Переглянути джерело

Merge remote-tracking branch 'official/master' into contrib

Léo Terziman 9 роки тому
батько
коміт
6eebf8455a
100 змінених файлів з 11605 додано та 399 видалено
  1. 10 4
      CMakeLists.txt
  2. 7 8
      INSTALL
  3. 25 17
      Readme.md
  4. 0 3
      appveyor.yml
  5. 1 0
      cmake-modules/FindDirectX.cmake
  6. 2 2
      code/ASEParser.h
  7. 1 1
      code/Assimp.cpp
  8. 28 3
      code/AssimpCExport.cpp
  9. 1 1
      code/BVHLoader.h
  10. 6 6
      code/BaseImporter.cpp
  11. 25 4
      code/BaseImporter.h
  12. 2 2
      code/BaseProcess.h
  13. 5 0
      code/Bitmap.cpp
  14. 2 2
      code/CInterfaceIOWrapper.h
  15. 19 1
      code/CMakeLists.txt
  16. 47 15
      code/ColladaParser.cpp
  17. 1 1
      code/ComputeUVMappingProcess.h
  18. 12 10
      code/DefaultIOSystem.cpp
  19. 3 3
      code/DefaultIOSystem.h
  20. 9 0
      code/Exporter.cpp
  21. 77 33
      code/FBXConverter.cpp
  22. 8 0
      code/FBXDocument.cpp
  23. 61 0
      code/FBXDocument.h
  24. 4 0
      code/FBXImportSettings.h
  25. 1 0
      code/FBXImporter.cpp
  26. 81 0
      code/FBXMaterial.cpp
  27. 1 1
      code/FBXProperties.h
  28. 2 2
      code/IRRLoader.h
  29. 3 2
      code/Importer.cpp
  30. 1 1
      code/Importer.h
  31. 7 3
      code/ImporterRegistry.cpp
  32. 2 2
      code/LWOFileData.h
  33. 0 6
      code/MD5Loader.cpp
  34. 6 3
      code/MD5Parser.h
  35. 29 11
      code/OFFLoader.cpp
  36. 9 1
      code/ObjFileData.h
  37. 17 1
      code/ObjFileImporter.cpp
  38. 52 5
      code/ObjFileMtlImporter.cpp
  39. 2 1
      code/ObjFileMtlImporter.h
  40. 5 2
      code/ObjFileParser.cpp
  41. 2 2
      code/OgreStructs.h
  42. 1 1
      code/OgreXmlSerializer.h
  43. 13 0
      code/OpenGEXImporter.cpp
  44. 1 1
      code/PlyParser.cpp
  45. 1 1
      code/Q3BSPFileImporter.cpp
  46. 1 1
      code/Q3BSPZipArchive.h
  47. 1 1
      code/Q3DLoader.h
  48. 2 2
      code/RawLoader.h
  49. 1 1
      code/SGSpatialSort.h
  50. 2 2
      code/STLLoader.cpp
  51. 1 1
      code/SceneCombiner.h
  52. 1 1
      code/StdOStreamLogStream.h
  53. 1 1
      code/TinyFormatter.h
  54. 1 1
      code/UnrealLoader.h
  55. 1 1
      code/Version.cpp
  56. 2 2
      code/XFileHelper.h
  57. 1 1
      code/XFileParser.h
  58. 945 0
      code/glTFAsset.h
  59. 1215 0
      code/glTFAsset.inl
  60. 89 0
      code/glTFAssetWriter.h
  61. 497 0
      code/glTFAssetWriter.inl
  62. 367 0
      code/glTFExporter.cpp
  63. 108 0
      code/glTFExporter.h
  64. 629 0
      code/glTFImporter.cpp
  65. 90 0
      code/glTFImporter.h
  66. 1 1
      code/irrXMLWrapper.h
  67. 1 1
      contrib/clipper/clipper.cpp
  68. 1 1
      contrib/clipper/clipper.hpp
  69. 6 6
      contrib/openddlparser/code/DDLNode.cpp
  70. 168 0
      contrib/openddlparser/code/OpenDDLCommon.cpp
  71. 412 0
      contrib/openddlparser/code/OpenDDLExport.cpp
  72. 77 45
      contrib/openddlparser/code/OpenDDLParser.cpp
  73. 74 14
      contrib/openddlparser/code/Value.cpp
  74. 4 0
      contrib/openddlparser/include/openddlparser/DDLNode.h
  75. 111 146
      contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
  76. 88 0
      contrib/openddlparser/include/openddlparser/OpenDDLExport.h
  77. 70 7
      contrib/openddlparser/include/openddlparser/OpenDDLParser.h
  78. 29 1
      contrib/openddlparser/include/openddlparser/Value.h
  79. 261 0
      contrib/rapidjson/include/rapidjson/allocators.h
  80. 2114 0
      contrib/rapidjson/include/rapidjson/document.h
  81. 261 0
      contrib/rapidjson/include/rapidjson/encodedstream.h
  82. 625 0
      contrib/rapidjson/include/rapidjson/encodings.h
  83. 65 0
      contrib/rapidjson/include/rapidjson/error/en.h
  84. 146 0
      contrib/rapidjson/include/rapidjson/error/error.h
  85. 88 0
      contrib/rapidjson/include/rapidjson/filereadstream.h
  86. 95 0
      contrib/rapidjson/include/rapidjson/filewritestream.h
  87. 290 0
      contrib/rapidjson/include/rapidjson/internal/biginteger.h
  88. 248 0
      contrib/rapidjson/include/rapidjson/internal/diyfp.h
  89. 217 0
      contrib/rapidjson/include/rapidjson/internal/dtoa.h
  90. 77 0
      contrib/rapidjson/include/rapidjson/internal/ieee754.h
  91. 304 0
      contrib/rapidjson/include/rapidjson/internal/itoa.h
  92. 181 0
      contrib/rapidjson/include/rapidjson/internal/meta.h
  93. 55 0
      contrib/rapidjson/include/rapidjson/internal/pow10.h
  94. 196 0
      contrib/rapidjson/include/rapidjson/internal/stack.h
  95. 39 0
      contrib/rapidjson/include/rapidjson/internal/strfunc.h
  96. 270 0
      contrib/rapidjson/include/rapidjson/internal/strtod.h
  97. 37 0
      contrib/rapidjson/include/rapidjson/internal/swap.h
  98. 70 0
      contrib/rapidjson/include/rapidjson/memorybuffer.h
  99. 61 0
      contrib/rapidjson/include/rapidjson/memorystream.h
  100. 316 0
      contrib/rapidjson/include/rapidjson/msinttypes/inttypes.h

+ 10 - 4
CMakeLists.txt

@@ -10,8 +10,8 @@ endif(NOT BUILD_SHARED_LIBS)
 
 # Define here the needed parameters
 set (ASSIMP_VERSION_MAJOR 3)
-set (ASSIMP_VERSION_MINOR 1)
-set (ASSIMP_VERSION_PATCH 1) # subversion revision?
+set (ASSIMP_VERSION_MINOR 2)
+set (ASSIMP_VERSION_PATCH 0) # subversion revision?
 set (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
 set (ASSIMP_SOVERSION 3)
 set (PROJECT_VERSION "${ASSIMP_VERSION}")
@@ -27,6 +27,7 @@ execute_process(
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
   OUTPUT_VARIABLE GIT_BRANCH
   OUTPUT_STRIP_TRAILING_WHITESPACE
+  ERROR_QUIET
 )
 
 # Get the latest abbreviated commit hash of the working branch
@@ -35,6 +36,7 @@ execute_process(
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
   OUTPUT_VARIABLE GIT_COMMIT_HASH
   OUTPUT_STRIP_TRAILING_WHITESPACE
+  ERROR_QUIET
 )
 
 if(NOT GIT_COMMIT_HASH)
@@ -63,7 +65,9 @@ if( CMAKE_COMPILER_IS_MINGW )
 endif()
 
 if((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW)
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # this is a very important switch and some libraries seem now to have it....
+  if (BUILD_SHARED_LIBS AND CMAKE_SIZEOF_VOID_P EQUAL 8) # -fPIC is only required for shared libs on 64 bit
+     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+  endif()
   # hide all not-exported symbols
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall" )
 elseif(MSVC)
@@ -119,7 +123,9 @@ IF ( ASSIMP_ENABLE_BOOST_WORKAROUND )
   MESSAGE( STATUS "Building a non-boost version of Assimp." )
 ELSE ( ASSIMP_ENABLE_BOOST_WORKAROUND )
   SET( Boost_DETAILED_FAILURE_MSG ON )
-  SET( Boost_ADDITIONAL_VERSIONS "1.47" "1.47.0" "1.48.0" "1.48" "1.49" "1.49.0" "1.50" "1.50.0" "1.51" "1.51.0" "1.52.0" "1.53.0" "1.54.0" "1.55" "1.55.0" "1.56" "1.56.0" "1.57" "1.57.0" "1.58" "1.58.0" )
+  IF ( NOT Boost_ADDITIONAL_VERSIONS )
+    SET( Boost_ADDITIONAL_VERSIONS "1.47" "1.47.0" "1.48.0" "1.48" "1.49" "1.49.0" "1.50" "1.50.0" "1.51" "1.51.0" "1.52.0" "1.53.0" "1.54.0" "1.55" "1.55.0" "1.56" "1.56.0" "1.57" "1.57.0" "1.58" "1.58.0" "1.59" "1.59.0")
+  ENDIF ( NOT Boost_ADDITIONAL_VERSIONS )
   FIND_PACKAGE( Boost )
   IF ( NOT Boost_FOUND )
     MESSAGE( FATAL_ERROR

+ 7 - 8
INSTALL

@@ -33,13 +33,12 @@ CMake is the preferred build system for Assimp. The minimum required version
 is 2.6. If you don't have it yet, downloads for CMake can be found on
 http://www.cmake.org/. 
 
-Building Assimp with CMake is 'business as usual' if you've used CMake
-before. All steps can be done either on the command line / shell or
-by using the CMake GUI tool, the choice is up to you. 
-
-First, invoke CMake to generate build files for a particular
-toolchain (for standard GNU makefiles: cmake -G 'Unix Makefiles').
-Afterwards, use the generated build files to perform the actual
-build. 
+For Unix:
 
+1. cmake CMakeLists.txt -G 'Unix Makefiles'
+2. make
 
+For Windows:
+1. Open a command prompt
+2. cmake CMakeLists.txt
+2. Open your default IDE and build it

+ 25 - 17
Readme.md

@@ -1,4 +1,4 @@
-Open Asset Import Library (assimp) 
+Open Asset Import Library (assimp)
 ========
 
 Open Asset Import Library is a library to load various 3d file formats into a shared, in-memory format. It supports more than __40 file formats__ for import and a growing selection of file formats for export.
@@ -28,28 +28,28 @@ __Importers__:
 - BLEND (Blender)
 - DAE/Collada
 - FBX
-- IFC-STEP 
+- IFC-STEP
 - ASE
 - DXF
 - HMP
 - MD2
-- MD3 
+- MD3
 - MD5
 - MDC
 - MDL
 - NFF
 - PLY
 - STL
-- X 
+- X
 - OBJ
 - OpenGEX
 - SMD
-- LWO 
-- LXO 
+- LWO
+- LXO
 - LWS  
-- TER 
-- AC3D 
-- MS3D 
+- TER
+- AC3D
+- MS3D
 - COB
 - Q3BSP
 - XGL
@@ -61,7 +61,8 @@ __Importers__:
 - Ogre XML
 - Q3D
 - ASSBIN (Assimp custom format)
- 
+- glTF
+
 Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
 
 - C4D (https://github.com/acgessler/assimp-cinema4d)
@@ -76,7 +77,8 @@ __Exporters__:
 - 3DS
 - JSON (for WebGl, via https://github.com/acgessler/assimp2json)
 - ASSBIN
-	
+- glTF
+
 ### Building ###
 
 
@@ -96,7 +98,7 @@ Open Asset Import Library is implemented in C++. The directory structure is:
 	/port		Ports to other languages and scripts to maintain those.
 	/test		Unit- and regression tests, test suite of models
 	/tools		Tools (old assimp viewer, command line `assimp`)
-	/samples	A small number of samples to illustrate possible 
+	/samples	A small number of samples to illustrate possible
                         use cases for Assimp
 	/workspaces	Build enviroments for vc,xcode,... (deprecated,
 			CMake has superseeded all legacy build options!)
@@ -111,18 +113,24 @@ For more information, visit [our website](http://assimp.sourceforge.net/). Or ch
 If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
 
 For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
-  [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) 
+  [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)
+
+And we also have an IRC-channel at freenode: #assetimporterlib . You can easily join us via: [KiwiIRC/freenote](https://kiwiirc.com/client/irc.freenode.net), choose your nickname and type
+> /join #assetimporterlib
 
 ### Contributing ###
 
-Contributions to assimp are highly appreciated. The easiest way to get involved is to submit 
+Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
 a pull request with your changes against the main repository's `master` branch.
 
 ### License ###
 
-Our license is based on the modified, __3-clause BSD__-License. 
+Our license is based on the modified, __3-clause BSD__-License.
 
-An _informal_ summary is: do whatever you want, but include Assimp's license text with your product - 
+An _informal_ summary is: do whatever you want, but include Assimp's license text with your product -
 and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you may link statically to Assimp.
-For the legal details, see the `LICENSE` file. 
+For the legal details, see the `LICENSE` file.
+
+### Why this name ###
 
+Sorry, we're germans :-), no english native speakers ...

+ 0 - 3
appveyor.yml

@@ -1,9 +1,6 @@
 # AppVeyor file
 # http://www.appveyor.com/docs/appveyor-yml
 
-# Operating system (build VM template)
-os: Previous Windows Server 2012 R2  # using previous worker images since default worker has problem installing DART-Prerequisites.msi
-
 # clone directory
 clone_folder: c:\projects\assimp
 

+ 1 - 0
cmake-modules/FindDirectX.cmake

@@ -35,6 +35,7 @@ if(WIN32) # The only platform it makes sense to check for DirectX SDK
     "C:/Program Files (x86)/Microsoft DirectX SDK*"
     "C:/apps/Microsoft DirectX SDK*"
     "C:/Program Files/Microsoft DirectX SDK*"
+    "C:/Program Files (x86)/Windows Kits/8.1"
     "$ENV{ProgramFiles}/Microsoft DirectX SDK*"
   )
   create_search_paths(DirectX)

+ 2 - 2
code/ASEParser.h

@@ -138,7 +138,7 @@ struct Bone
     }
 
     //! Construction from an existing name
-    Bone( const std::string& name)
+    explicit Bone( const std::string& name)
         :   mName   (name)
     {}
 
@@ -216,7 +216,7 @@ struct BaseNode
     enum Type {Light, Camera, Mesh, Dummy} mType;
 
     //! Constructor. Creates a default name for the node
-    BaseNode(Type _mType)
+    explicit BaseNode(Type _mType)
         : mType         (_mType)
         , mProcessed    (false)
     {

+ 1 - 1
code/Assimp.cpp

@@ -110,7 +110,7 @@ static boost::mutex gLogStreamMutex;
 class LogToCallbackRedirector : public LogStream
 {
 public:
-    LogToCallbackRedirector(const aiLogStream& s)
+    explicit LogToCallbackRedirector(const aiLogStream& s)
         : stream (s)    {
             ai_assert(NULL != s.callback);
     }

+ 28 - 3
code/AssimpCExport.cpp

@@ -59,13 +59,38 @@ ASSIMP_API size_t aiGetExportFormatCount(void)
 
 
 // ------------------------------------------------------------------------------------------------
-ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
+ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index)
 {
-    // Note: this is valid as the index always pertains to a builtin exporter,
+    // Note: this is valid as the index always pertains to a built-in exporter,
     // for which the returned structure is guaranteed to be of static storage duration.
-    return Exporter().GetExportFormatDescription(pIndex);
+    Exporter exporter;
+    const aiExportFormatDesc* orig( exporter.GetExportFormatDescription( index ) );
+    if (NULL == orig) {
+        return NULL;
+    }
+
+    aiExportFormatDesc *desc = new aiExportFormatDesc;
+    desc->description = new char[ strlen( orig->description ) + 1 ];
+    ::strncpy( (char*) desc->description, orig->description, strlen( orig->description ) );
+    desc->fileExtension = new char[ strlen( orig->fileExtension ) + 1 ];
+    ::strncpy( ( char* ) desc->fileExtension, orig->fileExtension, strlen( orig->fileExtension ) );
+    desc->id = new char[ strlen( orig->id ) + 1 ];
+    ::strncpy( ( char* ) desc->id, orig->id, strlen( orig->id ) );
+
+    return desc;
 }
 
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiReleaseExportFormatDescription( const aiExportFormatDesc *desc ) {
+    if (NULL == desc) {
+        return;
+    }
+
+    delete [] desc->description;
+    delete [] desc->fileExtension;
+    delete [] desc->id;
+    delete desc;
+}
 
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut)

+ 1 - 1
code/BVHLoader.h

@@ -83,7 +83,7 @@ class BVHLoader : public BaseImporter
         std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
 
         Node() { }
-        Node( const aiNode* pNode) : mNode( pNode) { }
+        explicit Node( const aiNode* pNode) : mNode( pNode) { }
     };
 
 public:

+ 6 - 6
code/BaseImporter.cpp

@@ -63,7 +63,7 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 BaseImporter::BaseImporter()
-: progress()
+: m_progress()
 {
     // nothing to do here
 }
@@ -79,8 +79,8 @@ BaseImporter::~BaseImporter()
 // Imports the given file and returns the imported data.
 aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler)
 {
-    progress = pImp->GetProgressHandler();
-    ai_assert(progress);
+    m_progress = pImp->GetProgressHandler();
+    ai_assert(m_progress);
 
     // Gather configuration properties for this run
     SetupProperties( pImp );
@@ -98,8 +98,8 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
 
     } catch( const std::exception& err )    {
         // extract error description
-        mErrorText = err.what();
-        DefaultLogger::get()->error(mErrorText);
+        m_ErrorText = err.what();
+        DefaultLogger::get()->error(m_ErrorText);
         return NULL;
     }
 
@@ -274,7 +274,7 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
 
         for (unsigned int i = 0; i < num; ++i) {
             // also check against big endian versions of tokens with size 2,4
-            // that's just for convinience, the chance that we cause conflicts
+            // that's just for convenience, the chance that we cause conflicts
             // is quite low and it can save some lines and prevent nasty bugs
             if (2 == size) {
                 uint16_t rev = *magic_u16;

+ 25 - 4
code/BaseImporter.h

@@ -70,7 +70,7 @@ class IOStream;
 template <typename T>
 struct ScopeGuard
 {
-    ScopeGuard(T* obj) : obj(obj), mdismiss() {}
+    explicit ScopeGuard(T* obj) : obj(obj), mdismiss() {}
     ~ScopeGuard () throw() {
         if (!mdismiss) {
             delete obj;
@@ -181,7 +181,7 @@ public:
      * string if there was no error.
      */
     const std::string& GetErrorText() const {
-        return mErrorText;
+        return m_ErrorText;
     }
 
     // -------------------------------------------------------------------
@@ -359,13 +359,34 @@ public: // static utilities
         IOStream* stream,
         std::vector<char>& data);
 
+    // -------------------------------------------------------------------
+    /** Utility function to move a std::vector into a aiScene array
+    *  @param vec The vector to be moved
+    *  @param out The output pointer to the allocated array.
+    *  @param numOut The output count of elements copied. */
+    template<typename T>
+    AI_FORCE_INLINE
+    static void CopyVector(
+        std::vector<T>& vec,
+        T*& out,
+        unsigned int& outLength)
+    {
+        outLength = vec.size();
+        if (outLength) {
+            out = new T[outLength];
+            std::swap_ranges(vec.begin(), vec.end(), out);
+        }
+    }
+
+    
+
 protected:
 
     /** Error description in case there was one. */
-    std::string mErrorText;
+    std::string m_ErrorText;
 
     /** Currently set progress handler */
-    ProgressHandler* progress;
+    ProgressHandler* m_progress;
 };
 
 

+ 2 - 2
code/BaseProcess.h

@@ -74,7 +74,7 @@ public:
     template <typename T>
     struct THeapData : public Base
     {
-        THeapData(T* in)
+        explicit THeapData(T* in)
             : data (in)
         {}
 
@@ -89,7 +89,7 @@ public:
     template <typename T>
     struct TStaticData : public Base
     {
-        TStaticData(T in)
+        explicit TStaticData(T in)
             : data (in)
         {}
 

+ 5 - 0
code/Bitmap.cpp

@@ -84,7 +84,12 @@ namespace Assimp {
 
     template<typename T>
     inline std::size_t Copy(uint8_t* data, T& field) {
+#ifdef AI_BUILD_BIG_ENDIAN
+        T field_swapped=AI_BE(field);
+        std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field);
+#else
         std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
+#endif
     }
 
     void Bitmap::WriteHeader(Header& header, IOStream* file) {

+ 2 - 2
code/CInterfaceIOWrapper.h

@@ -57,7 +57,7 @@ class CIOStreamWrapper : public IOStream
     friend class CIOSystemWrapper;
 public:
 
-    CIOStreamWrapper(aiFile* pFile)
+    explicit CIOStreamWrapper(aiFile* pFile)
         : mFile(pFile)
     {}
 
@@ -110,7 +110,7 @@ private:
 class CIOSystemWrapper : public IOSystem
 {
 public:
-    CIOSystemWrapper(aiFileIO* pFile)
+    explicit CIOSystemWrapper(aiFileIO* pFile)
         : mFileSystem(pFile)
     {}
 

+ 19 - 1
code/CMakeLists.txt

@@ -562,6 +562,19 @@ ADD_ASSIMP_IMPORTER(X
   XFileExporter.cpp
 )
 
+ADD_ASSIMP_IMPORTER(GLTF
+  glTFAsset.h
+  glTFAsset.inl
+  glTFAssetWriter.h
+  glTFAssetWriter.inl
+
+  glTFImporter.cpp
+  glTFImporter.h
+  
+  glTFExporter.h
+  glTFExporter.cpp
+)
+
 SET( Step_SRCS
   StepExporter.h
   StepExporter.cpp
@@ -632,15 +645,20 @@ SOURCE_GROUP( unzip FILES ${unzip_SRCS})
 SET ( openddl_parser_SRCS
   ../contrib/openddlparser/code/OpenDDLParser.cpp
   ../contrib/openddlparser/code/DDLNode.cpp
+  ../contrib/openddlparser/code/OpenDDLCommon.cpp
+  ../contrib/openddlparser/code/OpenDDLExport.cpp
   ../contrib/openddlparser/code/Value.cpp
   ../contrib/openddlparser/include/openddlparser/OpenDDLParser.h
   ../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
   ../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
+  ../contrib/openddlparser/include/openddlparser/OpenDDLExport.h
   ../contrib/openddlparser/include/openddlparser/DDLNode.h
   ../contrib/openddlparser/include/openddlparser/Value.h
 )
 SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
 
+INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" )
+
 # VC2010 fixes
 if(MSVC10)
   option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF )
@@ -766,7 +784,7 @@ INSTALL( TARGETS assimp
 INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)
 INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev)
 if (ASSIMP_ANDROID_JNIIOSYSTEM)
-  INSTALL(FILES ${HEADER_PATH}/../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
+  INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
     DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
     COMPONENT assimp-dev)
 endif(ASSIMP_ANDROID_JNIIOSYSTEM)

+ 47 - 15
code/ColladaParser.cpp

@@ -64,28 +64,47 @@ using namespace Assimp::Collada;
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
-    : mFileName( pFile)
+    : mFileName( pFile )
+    , mReader( NULL )
+    , mDataLibrary()
+    , mAccessorLibrary()
+    , mMeshLibrary()
+    , mNodeLibrary()
+    , mImageLibrary()
+    , mEffectLibrary()
+    , mMaterialLibrary()
+    , mLightLibrary()
+    , mCameraLibrary()
+    , mControllerLibrary()
+    , mRootNode( NULL )
+    , mAnims()
+    , mUnitSize( 1.0f )
+    , mUpDirection( UP_Y )
+    , mFormat(FV_1_5_n )    // We assume the newest file format by default
 {
-    mRootNode = NULL;
-    mUnitSize = 1.0f;
-    mUpDirection = UP_Y;
-
-    // We assume the newest file format by default
-    mFormat = FV_1_5_n;
+    // validate io-handler instance
+    if ( NULL == pIOHandler ) {
+        throw DeadlyImportError("IOSystem is NULL." );
+    }
 
-  // open the file
-  boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
-  if( file.get() == NULL)
-    throw DeadlyImportError( "Failed to open file " + pFile + ".");
+    // open the file
+    boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile ) );
+    if ( file.get() == NULL ) {
+        throw DeadlyImportError( "Failed to open file " + pFile + "." );
+    }
 
     // generate a XML reader for it
-  boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get()));
+    boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get()));
     mReader = irr::io::createIrrXMLReader( mIOWrapper.get());
-    if( !mReader)
-        ThrowException( "Collada: Unable to open file.");
+    if (!mReader) {
+        ThrowException("Collada: Unable to open file.");
+    }
 
     // start reading
     ReadContents();
+
+    // release file after import
+    //pIOHandler->Close( file.get() );
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -1514,7 +1533,7 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
                 // don't care for remaining stuff
                 SkipElement( "surface");
             }
-            else if( IsElement( "sampler2D"))
+            else if( IsElement( "sampler2D") && (FV_1_4_n == mFormat || FV_1_3_n == mFormat))
             {
                 // surface ID is given inside <source> tags
                 TestOpening( "source");
@@ -1525,6 +1544,19 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
 
                 // don't care for remaining stuff
                 SkipElement( "sampler2D");
+            }
+            else if( IsElement( "sampler2D"))
+            {
+                // surface ID is given inside <instance_image> tags
+                TestOpening( "instance_image");
+                int attrURL = GetAttribute("url");
+                const char* url = mReader->getAttributeValue( attrURL);
+                if( url[0] != '#')
+                    ThrowException( "Unsupported URL format in instance_image");
+                url++;
+                pParam.mType = Param_Sampler;
+                pParam.mReference = url;
+                SkipElement( "sampler2D");
             } else
             {
                 // ignore unknown element

+ 1 - 1
code/ComputeUVMappingProcess.h

@@ -125,7 +125,7 @@ private:
     // temporary structure to describe a mapping
     struct MappingInfo
     {
-        MappingInfo(aiTextureMapping _type)
+        explicit MappingInfo(aiTextureMapping _type)
             : type  (_type)
             , axis  (0.f,1.f,0.f)
             , uv    (0u)

+ 12 - 10
code/DefaultIOSystem.cpp

@@ -135,11 +135,11 @@ inline void MakeAbsolutePath (const char* in, char* _out)
 {
     ai_assert(in && _out);
     char* ret;
-#ifdef _WIN32
-    ret = ::_fullpath(_out, in,PATHLIMIT);
+#if defined( _MSC_VER ) || defined( __MINGW32__ )
+    ret = ::_fullpath( _out, in, PATHLIMIT );
 #else
-        // use realpath
-        ret = realpath(in, _out);
+    // use realpath
+    ret = realpath(in, _out);
 #endif
     if(!ret) {
         // preserve the input path, maybe someone else is able to fix
@@ -167,8 +167,8 @@ bool DefaultIOSystem::ComparePaths (const char* one, const char* second) const
     return !ASSIMP_stricmp(temp1,temp2);
 }
 
-
-std::string DefaultIOSystem::fileName(std::string path)
+// ------------------------------------------------------------------------------------------------
+std::string DefaultIOSystem::fileName( const std::string &path )
 {
     std::string ret = path;
     std::size_t last = ret.find_last_of("\\/");
@@ -176,8 +176,8 @@ std::string DefaultIOSystem::fileName(std::string path)
     return ret;
 }
 
-
-std::string DefaultIOSystem::completeBaseName(std::string path)
+// ------------------------------------------------------------------------------------------------
+std::string DefaultIOSystem::completeBaseName( const std::string &path )
 {
     std::string ret = fileName(path);
     std::size_t pos = ret.find_last_of('.');
@@ -185,8 +185,8 @@ std::string DefaultIOSystem::completeBaseName(std::string path)
     return ret;
 }
 
-
-std::string DefaultIOSystem::absolutePath(std::string path)
+// ------------------------------------------------------------------------------------------------
+std::string DefaultIOSystem::absolutePath( const std::string &path )
 {
     std::string ret = path;
     std::size_t last = ret.find_last_of("\\/");
@@ -194,4 +194,6 @@ std::string DefaultIOSystem::absolutePath(std::string path)
     return ret;
 }
 
+// ------------------------------------------------------------------------------------------------
+
 #undef PATHLIMIT

+ 3 - 3
code/DefaultIOSystem.h

@@ -80,17 +80,17 @@ public:
     /** @brief get the file name of a full filepath
      * example: /tmp/archive.tar.gz -> archive.tar.gz
      */
-    static std::string fileName(std::string path);
+    static std::string fileName( const std::string &path );
 
     /** @brief get the complete base name of a full filepath
      * example: /tmp/archive.tar.gz -> archive.tar
      */
-    static std::string completeBaseName(std::string path);
+    static std::string completeBaseName( const std::string &path);
 
     /** @brief get the path of a full filepath
      * example: /tmp/archive.tar.gz -> /tmp/
      */
-    static std::string absolutePath(std::string path);
+    static std::string absolutePath( const std::string &path);
 };
 
 } //!ns Assimp

+ 9 - 0
code/Exporter.cpp

@@ -87,6 +87,8 @@ void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportPro
 void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 
@@ -135,6 +137,13 @@ Exporter::ExportFormatEntry gExporters[] =
         aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
 #endif
 
+#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
+    Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
+        aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/),
+    Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
+        aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/),
+#endif
+
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
     Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
 #endif

+ 77 - 33
code/FBXConverter.cpp

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXUtil.h"
 #include "FBXProperties.h"
 #include "FBXImporter.h"
+#include "StringComparison.h"
 #include "../include/assimp/scene.h"
 #include <boost/foreach.hpp>
 #include <boost/scoped_array.hpp>
@@ -148,6 +149,7 @@ public:
         std::for_each(animations.begin(),animations.end(),Util::delete_fun<aiAnimation>());
         std::for_each(lights.begin(),lights.end(),Util::delete_fun<aiLight>());
         std::for_each(cameras.begin(),cameras.end(),Util::delete_fun<aiCamera>());
+        std::for_each(textures.begin(),textures.end(),Util::delete_fun<aiTexture>());
     }
 
 
@@ -1449,6 +1451,36 @@ private:
         return static_cast<unsigned int>(materials.size() - 1);
     }
 
+    // ------------------------------------------------------------------------------------------------
+    // Video -> aiTexture
+    unsigned int ConvertVideo(const Video& video)
+    {
+        // generate empty output texture
+        aiTexture* out_tex = new aiTexture();
+        textures.push_back(out_tex);
+
+        // assuming the texture is compressed
+        out_tex->mWidth = static_cast<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
+        out_tex->pcData = reinterpret_cast<aiTexel*>( const_cast<Video&>(video).RelinquishContent() );
+
+        // try to extract a hint from the file extension
+        const std::string& filename = video.FileName().empty() ? video.RelativeFilename() : video.FileName();
+        std::string ext = BaseImporter::GetExtension(filename);
+
+        if(ext == "jpeg") {
+            ext = "jpg";
+        }
+
+        if(ext.size() <= 3) {
+            memcpy(out_tex->achFormatHint, ext.c_str(), ext.size());
+        }
+
+        return static_cast<unsigned int>(textures.size() - 1);
+    }
+
 
     // ------------------------------------------------------------------------------------------------
     void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
@@ -1466,6 +1498,24 @@ private:
             aiString path;
             path.Set(tex->RelativeFilename());
 
+            const Video* media = tex->Media();
+            if(media != 0 && media->ContentLength() > 0) {
+                unsigned int index;
+
+                VideoMap::const_iterator it = textures_converted.find(media);
+                if(it != textures_converted.end()) {
+                    index = (*it).second;
+                }
+                else {
+                    index = ConvertVideo(*media);
+                    textures_converted[media] = index;
+                }
+
+                // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
+                path.data[0] = '*';
+                path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
+            }
+
             out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0);
 
             aiUVTransform uvTrafo;
@@ -2496,8 +2546,9 @@ private:
         // need to convert from TRS order to SRT?
         if(reverse_order) {
 
-            aiVector3D def_scale, def_translate;
-            aiQuaternion def_rot;
+            aiVector3D def_scale = PropertyGet(props,"Lcl Scaling",aiVector3D(1.f,1.f,1.f));
+            aiVector3D def_translate = PropertyGet(props,"Lcl Translation",aiVector3D(0.f,0.f,0.f));
+            aiVector3D def_rot = PropertyGet(props,"Lcl Rotation",aiVector3D(0.f,0.f,0.f));
 
             KeyFrameListList scaling;
             KeyFrameListList translation;
@@ -2506,24 +2557,14 @@ private:
             if(chain[TransformationComp_Scaling] != iter_end) {
                 scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop);
             }
-            else {
-                def_scale = PropertyGet(props,"Lcl Scaling",aiVector3D(1.f,1.f,1.f));
-            }
 
             if(chain[TransformationComp_Translation] != iter_end) {
                 translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop);
             }
-            else {
-                def_translate = PropertyGet(props,"Lcl Translation",aiVector3D(0.f,0.f,0.f));
-            }
 
             if(chain[TransformationComp_Rotation] != iter_end) {
                 rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop);
             }
-            else {
-                def_rot = EulerToQuaternion(PropertyGet(props,"Lcl Rotation",aiVector3D(0.f,0.f,0.f)),
-                    target.RotationOrder());
-            }
 
             KeyFrameListList joined;
             joined.insert(joined.end(), scaling.begin(), scaling.end());
@@ -2740,7 +2781,7 @@ private:
 
     // ------------------------------------------------------------------------------------------------
     void InterpolateKeys(aiVectorKey* valOut,const KeyTimeList& keys, const KeyFrameListList& inputs,
-        const bool geom,
+        const aiVector3D& def_value,
         double& max_time,
         double& min_time)
 
@@ -2754,10 +2795,7 @@ private:
         next_pos.resize(inputs.size(),0);
 
         BOOST_FOREACH(KeyTimeList::value_type time, keys) {
-            float result[3] = {0.0f, 0.0f, 0.0f};
-            if(geom) {
-                result[0] = result[1] = result[2] = 1.0f;
-            }
+            float result[3] = {def_value.x, def_value.y, def_value.z};
 
             for (size_t i = 0; i < count; ++i) {
                 const KeyFrameList& kfl = inputs[i];
@@ -2782,12 +2820,7 @@ private:
                 const double factor = timeB == timeA ? 0. : static_cast<double>((time - timeA) / (timeB - timeA));
                 const float interpValue = static_cast<float>(valueA + (valueB - valueA) * factor);
 
-                if(geom) {
-                    result[kfl.get<2>()] *= interpValue;
-                }
-                else {
-                    result[kfl.get<2>()] += interpValue;
-                }
+                result[kfl.get<2>()] = interpValue;
             }
 
             // magic value to convert fbx times to seconds
@@ -2807,7 +2840,7 @@ private:
 
     // ------------------------------------------------------------------------------------------------
     void InterpolateKeys(aiQuatKey* valOut,const KeyTimeList& keys, const KeyFrameListList& inputs,
-        const bool geom,
+        const aiVector3D& def_value,
         double& maxTime,
         double& minTime,
         Model::RotOrder order)
@@ -2816,7 +2849,7 @@ private:
         ai_assert(valOut);
 
         boost::scoped_array<aiVectorKey> temp(new aiVectorKey[keys.size()]);
-        InterpolateKeys(temp.get(),keys,inputs,geom,maxTime, minTime);
+        InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime);
 
         aiMatrix4x4 m;
 
@@ -2858,20 +2891,20 @@ private:
         Model::RotOrder order,
         const aiVector3D& def_scale,
         const aiVector3D& def_translate,
-        const aiQuaternion& def_rotation)
+        const aiVector3D& def_rotation)
     {
         if (rotation.size()) {
-            InterpolateKeys(out_quat, times, rotation, false, maxTime, minTime, order);
+            InterpolateKeys(out_quat, times, rotation, def_rotation, maxTime, minTime, order);
         }
         else {
             for (size_t i = 0; i < times.size(); ++i) {
                 out_quat[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps;
-                out_quat[i].mValue = def_rotation;
+                out_quat[i].mValue = EulerToQuaternion(def_rotation, order);
             }
         }
 
         if (scaling.size()) {
-            InterpolateKeys(out_scale, times, scaling, true, maxTime, minTime);
+            InterpolateKeys(out_scale, times, scaling, def_scale, maxTime, minTime);
         }
         else {
             for (size_t i = 0; i < times.size(); ++i) {
@@ -2881,7 +2914,7 @@ private:
         }
 
         if (translation.size()) {
-            InterpolateKeys(out_translation, times, translation, false, maxTime, minTime);
+            InterpolateKeys(out_translation, times, translation, def_translate, maxTime, minTime);
         }
         else {
             for (size_t i = 0; i < times.size(); ++i) {
@@ -2935,7 +2968,7 @@ private:
         na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
         na->mScalingKeys = new aiVectorKey[keys.size()];
         if (keys.size() > 0)
-            InterpolateKeys(na->mScalingKeys, keys, inputs, true, maxTime, minTime);
+            InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime);
     }
 
 
@@ -2955,7 +2988,7 @@ private:
         na->mNumPositionKeys = static_cast<unsigned int>(keys.size());
         na->mPositionKeys = new aiVectorKey[keys.size()];
         if (keys.size() > 0)
-            InterpolateKeys(na->mPositionKeys, keys, inputs, false, maxTime, minTime);
+            InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime);
     }
 
 
@@ -2976,7 +3009,7 @@ private:
         na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
         na->mRotationKeys = new aiQuatKey[keys.size()];
         if (keys.size() > 0)
-            InterpolateKeys(na->mRotationKeys, keys, inputs, false, maxTime, minTime, order);
+            InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order);
     }
 
 
@@ -3024,6 +3057,13 @@ private:
 
             std::swap_ranges(cameras.begin(),cameras.end(),out->mCameras);
         }
+
+        if(textures.size()) {
+            out->mTextures = new aiTexture*[textures.size()]();
+            out->mNumTextures = static_cast<unsigned int>(textures.size());
+
+            std::swap_ranges(textures.begin(),textures.end(),out->mTextures);
+        }
     }
 
 
@@ -3037,10 +3077,14 @@ private:
     std::vector<aiAnimation*> animations;
     std::vector<aiLight*> lights;
     std::vector<aiCamera*> cameras;
+    std::vector<aiTexture*> textures;
 
     typedef std::map<const Material*, unsigned int> MaterialMap;
     MaterialMap materials_converted;
 
+    typedef std::map<const Video*, unsigned int> VideoMap;
+    VideoMap textures_converted;
+
     typedef std::map<const Geometry*, std::vector<unsigned int> > MeshMap;
     MeshMap meshes_converted;
 

+ 8 - 0
code/FBXDocument.cpp

@@ -180,6 +180,9 @@ const Object* LazyObject::Get(bool dieOnError)
         else if (!strncmp(obtype,"LayeredTexture",length)) {
             object.reset(new LayeredTexture(id,element,doc,name));
         }
+        else if (!strncmp(obtype,"Video",length)) {
+            object.reset(new Video(id,element,doc,name));
+        }
         else if (!strncmp(obtype,"AnimationStack",length)) {
             object.reset(new AnimationStack(id,element,name,doc));
         }
@@ -483,6 +486,11 @@ void Document::ReadConnections()
     for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
         const Element& el = *(*it).second;
         const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
+
+        // PP = property-property connection, ignored for now
+        // (tokens: "PP", ID1, "Property1", ID2, "Property2")
+        if(type == "PP") continue;
+
         const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
         const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
 

+ 61 - 0
code/FBXDocument.h

@@ -73,6 +73,8 @@ namespace FBX {
     class Material;
     class Geometry;
 
+    class Video;
+
     class AnimationCurve;
     class AnimationCurveNode;
     class AnimationLayer;
@@ -571,6 +573,10 @@ public:
         return crop;
     }
 
+    const Video* Media() const {
+        return media;
+    }
+
 private:
 
     aiVector2D uvTrans;
@@ -583,6 +589,8 @@ private:
     boost::shared_ptr<const PropertyTable> props;
 
     unsigned int crop[4];
+
+    const Video* media;
 };
 
 /** DOM class for layered FBX textures */
@@ -654,6 +662,59 @@ typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap;
 typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap;
 
 
+/** DOM class for generic FBX videos */
+class Video : public Object
+{
+public:
+
+    Video(uint64_t id, const Element& element, const Document& doc, const std::string& name);
+    ~Video();
+
+public:
+
+    const std::string& Type() const {
+        return type;
+    }
+
+    const std::string& FileName() const {
+        return fileName;
+    }
+
+    const std::string& RelativeFilename() const {
+        return relativeFileName;
+    }
+
+    const PropertyTable& Props() const {
+        ai_assert(props.get());
+        return *props.get();
+    }
+
+    const uint8_t* Content() const {
+        ai_assert(content);
+        return content;
+    }
+
+    const uint32_t ContentLength() const {
+        return contentLength;
+    }
+
+    uint8_t* RelinquishContent() {
+        uint8_t* ptr = content;
+        content = 0;
+        return ptr;
+    }
+
+private:
+
+    std::string type;
+    std::string relativeFileName;
+    std::string fileName;
+    boost::shared_ptr<const PropertyTable> props;
+
+    uint32_t contentLength;
+    uint8_t* content;
+};
+
 /** DOM class for generic FBX materials */
 class Material : public Object
 {

+ 4 - 0
code/FBXImportSettings.h

@@ -55,6 +55,7 @@ struct ImportSettings
         , readAllLayers(true)
         , readAllMaterials(false)
         , readMaterials(true)
+        , readTextures(true)
         , readCameras(true)
         , readLights(true)
         , readAnimations(true)
@@ -92,6 +93,9 @@ struct ImportSettings
      *  material. The default value is true.*/
     bool readMaterials;
 
+    /** import embedded textures? Default value is true.*/
+    bool readTextures;
+
     /** import cameras? Default value is true.*/
     bool readCameras;
 

+ 1 - 0
code/FBXImporter.cpp

@@ -126,6 +126,7 @@ void FBXImporter::SetupProperties(const Importer* pImp)
     settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
     settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
     settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
+    settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
     settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
     settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
     settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);

+ 81 - 0
code/FBXMaterial.cpp

@@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXImportSettings.h"
 #include "FBXDocumentUtil.h"
 #include "FBXProperties.h"
+#include "ByteSwapper.h"
 #include <boost/foreach.hpp>
 
 namespace Assimp {
@@ -147,6 +148,7 @@ Material::~Material()
 Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
 : Object(id,element,name)
 , uvScaling(1.0f,1.0f)
+, media(0)
 {
     const Scope& sc = GetRequiredScope(element);
 
@@ -199,6 +201,23 @@ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const
     }
 
     props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
+
+    // resolve video links
+    if(doc.Settings().readTextures) {
+        const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
+        BOOST_FOREACH(const Connection* con, conns) {
+            const Object* const ob = con->SourceObject();
+            if(!ob) {
+                DOMWarning("failed to read source object for texture link, ignoring",&element);
+                continue;
+            }
+
+            const Video* const video = dynamic_cast<const Video*>(ob);
+            if(video) {
+                media = video;
+            }
+        }
+    }
 }
 
 
@@ -253,6 +272,68 @@ void LayeredTexture::fillTexture(const Document& doc)
     }
 }
 
+
+// ------------------------------------------------------------------------------------------------
+Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name)
+: Object(id,element,name)
+, contentLength(0)
+, content(0)
+{
+    const Scope& sc = GetRequiredScope(element);
+
+    const Element* const Type = sc["Type"];
+    const Element* const FileName = sc["FileName"];
+    const Element* const RelativeFilename = sc["RelativeFilename"];
+    const Element* const Content = sc["Content"];
+
+    if(Type) {
+        type = ParseTokenAsString(GetRequiredToken(*Type,0));
+    }
+
+    if(FileName) {
+        fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
+    }
+
+    if(RelativeFilename) {
+        relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
+    }
+
+    if(Content) {
+        const Token& token = GetRequiredToken(*Content, 0);
+        const char* data = token.begin();
+        if(!token.IsBinary()) {
+            DOMWarning("video content is not binary data, ignoring", &element);
+        }
+        else if(static_cast<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);
+        }
+    }
+
+    props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
+}
+
+
+Video::~Video()
+{
+    if(content) {
+        delete[] content;
+    }
+}
+
 } //!FBX
 } //!Assimp
 

+ 1 - 1
code/FBXProperties.h

@@ -87,7 +87,7 @@ class TypedProperty : public Property
 {
 public:
 
-    TypedProperty(const T& value)
+    explicit TypedProperty(const T& value)
         : value(value)
     {
     }

+ 2 - 2
code/IRRLoader.h

@@ -113,7 +113,7 @@ private:
 
         } type;
 
-        Animator(AT t = UNKNOWN)
+        explicit Animator(AT t = UNKNOWN)
             : type              (t)
             , speed             (0.001f)
             , direction         (0.f,1.f,0.f)
@@ -163,7 +163,7 @@ private:
             ANIMMESH
         } type;
 
-        Node(ET t)
+        explicit Node(ET t)
             :   type                (t)
             ,   scaling             (1.f,1.f,1.f) // assume uniform scaling by default
             ,   parent()

+ 3 - 2
code/Importer.cpp

@@ -491,7 +491,7 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
         pHint = "";
     }
 
-    if (!pBuffer || !pLength || strlen(pHint) > 100) {
+    if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
         pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
         return NULL;
     }
@@ -503,7 +503,8 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
     SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength));
 
     // read the file and recover the previous IOSystem
-    char fbuff[128];
+    static const size_t BufferSize(Importer::MaxLenHint + 28);
+    char fbuff[ BufferSize ];
     sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
 
     ReadFile(fbuff,pFlags);

+ 1 - 1
code/Importer.h

@@ -167,7 +167,7 @@ public:
     // -------------------------------------------------------------------
     /** Construct a batch loader from a given IO system to be used
      *  to acess external files */
-    BatchLoader(IOSystem* pIO);
+    explicit BatchLoader(IOSystem* pIO);
     ~BatchLoader();
 
 

+ 7 - 3
code/ImporterRegistry.cpp

@@ -170,7 +170,9 @@ corresponding preprocessor flag to selectively disable formats.
 #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
 #   include "AssbinLoader.h"
 #endif
-
+#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
+#   include "glTFImporter.h"
+#endif
 #ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
 #   include "C4DImporter.h"
 #endif
@@ -305,8 +307,10 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
 #if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER )
     out.push_back( new AssbinImporter() );
 #endif
-
-#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
+#if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER )
+    out.push_back( new glTFImporter() );
+#endif
+#if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER )
     out.push_back( new C4DImporter() );
 #endif
 }

+ 2 - 2
code/LWOFileData.h

@@ -269,7 +269,7 @@ struct Face : public aiFace
     {}
 
     //! Construction from given type
-    Face(uint32_t _type)
+    explicit Face(uint32_t _type)
         : surfaceIndex  (0)
         , smoothGroup   (0)
         , type          (_type)
@@ -305,7 +305,7 @@ struct Face : public aiFace
  */
 struct VMapEntry
 {
-    VMapEntry(unsigned int _dims)
+    explicit VMapEntry(unsigned int _dims)
         :  dims(_dims)
     {}
 

+ 0 - 6
code/MD5Loader.cpp

@@ -285,9 +285,6 @@ void MD5Importer::AttachChilds_Mesh(int iParentID,aiNode* piParent, BoneList& bo
                 aiQuaternion quat;
                 MD5::ConvertQuaternion ( bones[i].mRotationQuat, quat );
 
-                // FIX to get to Assimp's quaternion conventions
-                quat.w *= -1.f;
-
                 bones[i].mTransform = aiMatrix4x4 ( quat.GetMatrix());
                 bones[i].mTransform.a4 = bones[i].mPositionXYZ.x;
                 bones[i].mTransform.b4 = bones[i].mPositionXYZ.y;
@@ -656,9 +653,6 @@ void MD5Importer::LoadMD5AnimFile ()
 
                     MD5::ConvertQuaternion(vTemp, qKey->mValue);
                     qKey->mTime = vKey->mTime = dTime;
-
-                    // we need this to get to Assimp quaternion conventions
-                    qKey->mValue.w *= -1.f;
                 }
             }
 

+ 6 - 3
code/MD5Parser.h

@@ -262,6 +262,9 @@ inline void ConvertQuaternion (const aiVector3D& in, aiQuaternion& out) {
     if (t < 0.0f)
         out.w = 0.0f;
     else out.w = std::sqrt (t);
+
+    // Assimp convention.
+    out.w *= -1.f;
 }
 
 // ---------------------------------------------------------------------------
@@ -277,7 +280,7 @@ public:
      *
      *  @param mSections List of file sections (output of MD5Parser)
      */
-    MD5MeshParser(SectionList& mSections);
+    explicit MD5MeshParser(SectionList& mSections);
 
     //! List of all meshes
     MeshList mMeshes;
@@ -302,7 +305,7 @@ public:
      *
      *  @param mSections List of file sections (output of MD5Parser)
      */
-    MD5AnimParser(SectionList& mSections);
+    explicit MD5AnimParser(SectionList& mSections);
 
 
     //! Output frame rate
@@ -334,7 +337,7 @@ public:
      *
      *  @param mSections List of file sections (output of MD5Parser)
      */
-    MD5CameraParser(SectionList& mSections);
+    explicit MD5CameraParser(SectionList& mSections);
 
 
     //! Output frame rate

+ 29 - 11
code/OFFLoader.cpp

@@ -138,9 +138,15 @@ void OFFImporter::InternReadFile( const std::string& pFile,
         throw DeadlyImportError("OFF: There are no valid faces");
     }
 
-    pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = 1 ];
-    aiMesh* mesh = pScene->mMeshes[0] = new aiMesh();
-    aiFace* faces = mesh->mFaces = new aiFace [mesh->mNumFaces = numFaces];
+    pScene->mNumMeshes = 1;
+    pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
+
+    aiMesh* mesh = new aiMesh();
+    pScene->mMeshes[0] = mesh;
+
+    mesh->mNumFaces = numFaces;
+    aiFace* faces = new aiFace [mesh->mNumFaces];
+    mesh->mFaces = faces;
 
     std::vector<aiVector3D> tempPositions(numVertices);
 
@@ -171,7 +177,8 @@ void OFFImporter::InternReadFile( const std::string& pFile,
             break;
         }
         sz = line;SkipSpaces(&sz);
-        if(!(faces->mNumIndices = strtoul10(sz,&sz)) || faces->mNumIndices > 9)
+        faces->mNumIndices = strtoul10(sz,&sz);
+        if(!(faces->mNumIndices) || faces->mNumIndices > 9)
         {
             DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed");
             --mesh->mNumFaces;
@@ -185,43 +192,54 @@ void OFFImporter::InternReadFile( const std::string& pFile,
         throw DeadlyImportError("OFF: There are no valid faces");
 
     // allocate storage for the output vertices
-    aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
+    std::vector<aiVector3D> verts;
+    verts.reserve(mesh->mNumVertices);
 
     // second: now parse all face indices
-    buffer = old;faces = mesh->mFaces;
+    buffer = old;
+    faces = mesh->mFaces;
     for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;)
     {
         if(!GetNextLine(buffer,line))break;
 
         unsigned int idx;
         sz = line;SkipSpaces(&sz);
-        if(!(idx = strtoul10(sz,&sz)) || idx > 9)
+        idx = strtoul10(sz,&sz);
+        if(!(idx) || idx > 9)
             continue;
 
         faces->mIndices = new unsigned int [faces->mNumIndices];
         for (unsigned int m = 0; m < faces->mNumIndices;++m)
         {
             SkipSpaces(&sz);
-            if ((idx = strtoul10(sz,&sz)) >= numVertices)
+            idx = strtoul10(sz,&sz);
+            if ((idx) >= numVertices)
             {
                 DefaultLogger::get()->error("OFF: Vertex index is out of range");
                 idx = numVertices-1;
             }
             faces->mIndices[m] = p++;
-            *verts++ = tempPositions[idx];
+            verts.push_back(tempPositions[idx]);
         }
         ++i;
         ++faces;
     }
 
+    if (mesh->mNumVertices != verts.size()) {
+        throw DeadlyImportError("OFF: Vertex count mismatch");
+    }
+    mesh->mVertices = new aiVector3D[verts.size()];
+    memcpy(mesh->mVertices, &verts[0], verts.size() * sizeof(aiVector3D));
     // generate the output node graph
     pScene->mRootNode = new aiNode();
     pScene->mRootNode->mName.Set("<OFFRoot>");
-    pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes = 1];
+    pScene->mRootNode->mNumMeshes = 1;
+    pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes];
     pScene->mRootNode->mMeshes[0] = 0;
 
     // generate a default material
-    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = 1];
+    pScene->mNumMaterials = 1;
+    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
     aiMaterial* pcMat = new aiMaterial();
 
     aiColor4D clr(0.6f,0.6f,0.6f,1.0f);

+ 9 - 1
code/ObjFileData.h

@@ -156,6 +156,7 @@ struct Material
     aiString textureEmissive;
     aiString textureBump;
     aiString textureNormal;
+    aiString textureReflection[6];
     aiString textureSpecularity;
     aiString textureOpacity;
     aiString textureDisp;
@@ -167,6 +168,13 @@ struct Material
         TextureEmissiveType,
         TextureBumpType,
         TextureNormalType,
+        TextureReflectionSphereType,
+        TextureReflectionCubeTopType,
+        TextureReflectionCubeBottomType,
+        TextureReflectionCubeFrontType,
+        TextureReflectionCubeBackType,
+        TextureReflectionCubeLeftType,
+        TextureReflectionCubeRightType,
         TextureSpecularityType,
         TextureOpacityType,
         TextureDispType,
@@ -234,7 +242,7 @@ struct Mesh {
     bool m_hasNormals;
 
     /// Constructor
-    Mesh( const std::string &name ) 
+    explicit Mesh( const std::string &name ) 
     : m_name( name )
     , m_pMaterial(NULL)
     , m_uiNumIndices(0)

+ 17 - 1
code/ObjFileImporter.cpp

@@ -138,7 +138,7 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
     if ( pos != std::string::npos ) {
         modelName = pFile.substr(pos+1, pFile.size() - pos - 1);
         folderName = pFile.substr( 0, pos );
-        if ( folderName.empty() ) {
+        if ( !folderName.empty() ) {
             pIOHandler->PushDirectory( folderName );
         }
     } else {
@@ -636,6 +636,22 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc
             }
         }
 
+        if( 0 != pCurrentMaterial->textureReflection[0].length )
+        {
+            ObjFile::Material::TextureType type = 0 != pCurrentMaterial->textureReflection[1].length ?
+                ObjFile::Material::TextureReflectionCubeTopType :
+                ObjFile::Material::TextureReflectionSphereType;
+
+            unsigned count = type == ObjFile::Material::TextureReflectionSphereType ? 1 : 6;
+            for( unsigned i = 0; i < count; i++ )
+                mat->AddProperty(&pCurrentMaterial->textureReflection[i], AI_MATKEY_TEXTURE_REFLECTION(i));
+
+            if(pCurrentMaterial->clamp[type])
+                //TODO addTextureMappingModeProperty should accept an index to handle clamp option for each
+                //texture of a cubemap
+                addTextureMappingModeProperty(mat, aiTextureType_REFLECTION);
+        }
+
         if ( 0 != pCurrentMaterial->textureDisp.length )
         {
             mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) );

+ 52 - 5
code/ObjFileMtlImporter.cpp

@@ -64,6 +64,7 @@ static const std::string BumpTexture1        = "map_bump";
 static const std::string BumpTexture2        = "map_Bump";
 static const std::string BumpTexture3        = "bump";
 static const std::string NormalTexture       = "map_Kn";
+static const std::string ReflectionTexture   = "refl";
 static const std::string DisplacementTexture = "disp";
 static const std::string SpecularityTexture  = "map_ns";
 
@@ -200,6 +201,7 @@ void ObjFileMtlImporter::load()
 
         case 'm':   // Texture
         case 'b':   // quick'n'dirty - for 'bump' sections
+        case 'r':   // quick'n'dirty - for 'refl' sections
             {
                 getTexture();
                 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
@@ -332,6 +334,9 @@ void ObjFileMtlImporter::getTexture() {
         // Normal map
         out = & m_pModel->m_pCurrentMaterial->textureNormal;
         clampIndex = ObjFile::Material::TextureNormalType;
+    } else if(!ASSIMP_strincmp( pPtr, ReflectionTexture.c_str(), ReflectionTexture.size() ) ) {
+        // Reflection texture(s)
+        //Do nothing here
     } else if (!ASSIMP_strincmp( pPtr, DisplacementTexture.c_str(), DisplacementTexture.size() ) ) {
         // Displacement texture
         out = &m_pModel->m_pCurrentMaterial->textureDisp;
@@ -346,7 +351,7 @@ void ObjFileMtlImporter::getTexture() {
     }
 
     bool clamp = false;
-    getTextureOption(clamp);
+    getTextureOption(clamp, clampIndex, out);
     m_pModel->m_pCurrentMaterial->clamp[clampIndex] = clamp;
 
     std::string texture;
@@ -369,7 +374,7 @@ void ObjFileMtlImporter::getTexture() {
  * Because aiMaterial supports clamp option, so we also want to return it
  * /////////////////////////////////////////////////////////////////////////////
  */
-void ObjFileMtlImporter::getTextureOption(bool &clamp)
+void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out)
 {
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
 
@@ -392,13 +397,55 @@ void ObjFileMtlImporter::getTextureOption(bool &clamp)
 
             skipToken = 2;
         }
-        else if (  !ASSIMP_strincmp(pPtr, BlendUOption.c_str(), BlendUOption.size())
+        else if( !ASSIMP_strincmp( pPtr, TypeOption.c_str(), TypeOption.size() ) )
+        {
+            DataArrayIt it = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
+            char value[ 12 ];
+            CopyNextWord( it, m_DataItEnd, value, sizeof( value ) / sizeof( *value ) );
+            if( !ASSIMP_strincmp( value, "cube_top", 8 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_bottom", 11 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[1];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_front", 10 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[2];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_back", 9 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[3];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_left", 9 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[4];
+            }
+            else if( !ASSIMP_strincmp( value, "cube_right", 10 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[5];
+            }
+            else if( !ASSIMP_strincmp( value, "sphere", 6 ) )
+            {
+                clampIndex = ObjFile::Material::TextureReflectionSphereType;
+                out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
+            }
+
+            skipToken = 2;
+        }
+        else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), BlendUOption.size())
                 || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), BlendVOption.size())
                 || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), BoostOption.size())
                 || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), ResolutionOption.size())
                 || !ASSIMP_strincmp(pPtr, BumpOption.c_str(), BumpOption.size())
-                || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), ChannelOption.size())
-                || !ASSIMP_strincmp(pPtr, TypeOption.c_str(), TypeOption.size()) )
+                || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), ChannelOption.size()))
         {
             skipToken = 2;
         }

+ 2 - 1
code/ObjFileMtlImporter.h

@@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 
 struct aiColor3D;
+struct aiString;
 
 namespace Assimp {
 
@@ -89,7 +90,7 @@ private:
     void createMaterial();
     /// Get texture name from loaded data.
     void getTexture();
-    void getTextureOption(bool &clamp);
+    void getTextureOption(bool &clamp, int &clampIndex, aiString *&out);
 
 private:
     //! Absolute pathname

+ 5 - 2
code/ObjFileParser.cpp

@@ -414,7 +414,7 @@ void ObjFileParser::getFace(aiPrimitiveType type)
 
     if ( pIndices->empty() ) {
         DefaultLogger::get()->error("Obj: Ignoring empty face");
-        // skip line and clean up 
+        // skip line and clean up
         m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
         delete pNormalID;
         delete pTexID;
@@ -539,7 +539,10 @@ void ObjFileParser::getMaterialLib()
     const std::string strMatName(pStart, &(*m_DataIt));
     std::string absName;
     if ( m_pIO->StackSize() > 0 ) {
-        const std::string &path = m_pIO->CurrentDirectory();
+        std::string path = m_pIO->CurrentDirectory();
+        if ( '/' != *path.rbegin() ) {
+          path += '/';
+        }
         absName = path + strMatName;
     } else {
         absName = strMatName;

+ 2 - 2
code/OgreStructs.h

@@ -381,8 +381,8 @@ typedef std::vector<VertexAnimationTrack> VertexAnimationTrackList;
 class Animation
 {
 public:
-    Animation(Skeleton *parent);
-    Animation(Mesh *parent);
+    explicit Animation(Skeleton *parent);
+    explicit Animation(Mesh *parent);
 
     /// Returns the associated vertex data for a track in this animation.
     /** @note Only valid to call when parent Mesh is set. */

+ 1 - 1
code/OgreXmlSerializer.h

@@ -69,7 +69,7 @@ public:
     static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
 
 private:
-    OgreXmlSerializer(XmlReader *reader) :
+    explicit OgreXmlSerializer(XmlReader *reader) :
         m_reader(reader)
     {
     }

+ 13 - 0
code/OpenGEXImporter.cpp

@@ -801,6 +801,19 @@ void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene *pScen
     }
 }
 
+//------------------------------------------------------------------------------------------------
+bool isSpecialRootDir(aiString &texName) {
+    if (texName.length < 2) {
+        return false;
+    }
+
+    if (texName.data[0] = '/' || texName.data[1] == '/') {
+        return true;
+    }
+
+    return false;
+}
+
 //------------------------------------------------------------------------------------------------
 void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
     if( NULL == node ) {

+ 1 - 1
code/PlyParser.cpp

@@ -857,7 +857,7 @@ bool PLY::PropertyInstance::ParseValueBinary(
 
     case EDT_UShort:
         {
-        int16_t i = *((uint16_t*)pCur);
+        uint16_t i = *((uint16_t*)pCur);
 
         // Swap endianess
         if (p_bBE)ByteSwap::Swap(&i);

+ 1 - 1
code/Q3BSPFileImporter.cpp

@@ -325,7 +325,7 @@ void Q3BSPFileImporter::CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* p
         matIdx++;
     }
 
-    pScene->mNumMeshes = MeshArray.size();
+    pScene->mNumMeshes = static_cast<unsigned int>( MeshArray.size() );
     if ( pScene->mNumMeshes > 0 )
     {
         pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];

+ 1 - 1
code/Q3BSPZipArchive.h

@@ -90,7 +90,7 @@ class ZipFile : public IOStream {
 
     public:
 
-        ZipFile(size_t size);
+        explicit ZipFile(size_t size);
 
         ~ZipFile();
 

+ 1 - 1
code/Q3DLoader.h

@@ -103,7 +103,7 @@ private:
 
     struct Face
     {
-        Face(unsigned int s)
+        explicit Face(unsigned int s)
             :   indices   (s)
             ,   uvindices (s)
             ,   mat       (0)

+ 2 - 2
code/RawLoader.h

@@ -88,7 +88,7 @@ private:
 
     struct MeshInformation
     {
-        MeshInformation(const std::string& _name)
+        explicit MeshInformation(const std::string& _name)
             : name(_name)
         {
             vertices.reserve(100);
@@ -103,7 +103,7 @@ private:
 
     struct GroupInformation
     {
-        GroupInformation(const std::string& _name)
+        explicit GroupInformation(const std::string& _name)
             : name(_name)
         {
             meshes.reserve(10);

+ 1 - 1
code/SGSpatialSort.h

@@ -66,7 +66,7 @@ public:
     /** Construction from a given face array, handling smoothing groups
      *  properly
      */
-    SGSpatialSort(const std::vector<aiVector3D>& vPositions);
+    explicit SGSpatialSort(const std::vector<aiVector3D>& vPositions);
 
     // -------------------------------------------------------------------
     /** Add a vertex to the spatial sort

+ 2 - 2
code/STLLoader.cpp

@@ -74,7 +74,7 @@ static const aiImporterDesc desc = {
 // 1) 80 byte header
 // 2) 4 byte face count
 // 3) 50 bytes per face
-bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
+static bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
     if( fileSize < 84 ) {
         return false;
     }
@@ -88,7 +88,7 @@ bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
 // An ascii STL buffer will begin with "solid NAME", where NAME is optional.
 // Note: The "solid NAME" check is necessary, but not sufficient, to determine
 // if the buffer is ASCII; a binary header could also begin with "solid NAME".
-bool IsAsciiSTL(const char* buffer, unsigned int fileSize) {
+static bool IsAsciiSTL(const char* buffer, unsigned int fileSize) {
     if (IsBinarySTL(buffer, fileSize))
         return false;
 

+ 1 - 1
code/SceneCombiner.h

@@ -166,7 +166,7 @@ struct SceneHelper
         id[0] = 0;
     }
 
-    SceneHelper (aiScene* _scene)
+    explicit SceneHelper (aiScene* _scene)
         : scene     (_scene)
         , idlen     (0)
     {

+ 1 - 1
code/StdOStreamLogStream.h

@@ -16,7 +16,7 @@ public:
     /** @brief  Construction from an existing std::ostream
      *  @param _ostream Output stream to be used
     */
-    StdOStreamLogStream(std::ostream& _ostream);
+    explicit StdOStreamLogStream(std::ostream& _ostream);
 
     /** @brief  Destructor  */
     ~StdOStreamLogStream();

+ 1 - 1
code/TinyFormatter.h

@@ -97,7 +97,7 @@ public:
     // being bound to const ref& function parameters. Copying streams is not permitted, though.
     // This workaround avoids this by manually specifying a copy ctor.
 #if !defined(__GNUC__) || !defined(__APPLE__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
-    basic_formatter(const basic_formatter& other) {
+    explicit basic_formatter(const basic_formatter& other) {
         underlying << (string)other;
     }
 #endif

+ 1 - 1
code/UnrealLoader.h

@@ -87,7 +87,7 @@ struct TempMat  {
         ,   numFaces    (0)
     {}
 
-    TempMat(const Triangle& in)
+    explicit TempMat(const Triangle& in)
         :   type        ((Unreal::MeshFlags)in.mType)
         ,   tex         (in.mTextureNum)
         ,   numFaces    (0)

+ 1 - 1
code/Version.cpp

@@ -6,7 +6,7 @@
 #include "ScenePrivate.h"
 
 static const unsigned int MajorVersion = 3;
-static const unsigned int MinorVersion = 1;
+static const unsigned int MinorVersion = 2;
 
 // --------------------------------------------------------------------------------
 // Legal information string - dont't remove this.

+ 2 - 2
code/XFileHelper.h

@@ -129,7 +129,7 @@ struct Mesh
 
     std::vector<Bone> mBones;
 
-    Mesh(const std::string &pName = "") { mName = pName; mNumTextures = 0; mNumColorSets = 0; }
+    explicit Mesh(const std::string &pName = "") { mName = pName; mNumTextures = 0; mNumColorSets = 0; }
 };
 
 /** Helper structure to represent a XFile frame */
@@ -142,7 +142,7 @@ struct Node
     std::vector<Mesh*> mMeshes;
 
     Node() { mParent = NULL; }
-    Node( Node* pParent) { mParent = pParent; }
+    explicit Node( Node* pParent) { mParent = pParent; }
     ~Node()
     {
         for( unsigned int a = 0; a < mChildren.size(); a++)

+ 1 - 1
code/XFileParser.h

@@ -68,7 +68,7 @@ public:
     /** Constructor. Creates a data structure out of the XFile given in the memory block.
      * @param pBuffer Null-terminated memory buffer containing the XFile
      */
-    XFileParser( const std::vector<char>& pBuffer);
+    explicit XFileParser( const std::vector<char>& pBuffer);
 
     /** Destructor. Destroys all imported data along with it */
     ~XFileParser();

+ 945 - 0
code/glTFAsset.h

@@ -0,0 +1,945 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file glTFAsset.h
+ * Declares a glTF class to handle gltf/glb files
+ *
+ * glTF Extensions Support:
+ *   KHR_binary_glTF: full
+ *   KHR_materials_common: full
+ */
+#ifndef glTFAsset_H_INC
+#define glTFAsset_H_INC
+
+#include <map>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <stdexcept>
+
+#define RAPIDJSON_HAS_STDSTRING 1
+#include <rapidjson/rapidjson.h>
+#include <rapidjson/document.h>
+#include <rapidjson/error/en.h>
+
+#ifdef ASSIMP_API
+#   include "boost/shared_ptr.hpp"
+#   include "DefaultIOSystem.h"
+#   include "ByteSwapper.h"
+#else
+#   include <memory>
+#   define AI_SWAP4(p)
+#   define ai_assert
+#endif
+
+
+#if _MSC_VER > 1500 || (defined __GNUC___)
+#       define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP
+#   else
+#       define gltf_unordered_map map
+#endif
+
+#ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP
+#   include <unordered_map>
+#   if _MSC_VER > 1600
+#       define gltf_unordered_map unordered_map
+#   else
+#       define gltf_unordered_map tr1::unordered_map
+#   endif
+#endif
+
+namespace glTF
+{
+#ifdef ASSIMP_API
+    using Assimp::IOStream;
+    using Assimp::IOSystem;
+    using boost::shared_ptr;
+#else
+    using std::shared_ptr;
+
+    typedef std::runtime_error DeadlyImportError;
+    typedef std::runtime_error DeadlyExportError;
+
+    enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 };
+    class IOSystem;
+    class IOStream
+    {
+        FILE* f;
+    public:
+        IOStream(FILE* file) : f(file) {}
+        ~IOStream() { fclose(f); f = 0; }
+
+        size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); }
+        size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); }
+        int    Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); }
+        size_t Tell() const { return ftell(f); }
+
+        size_t FileSize() {
+            long p = Tell(), len = (Seek(0, aiOrigin_END), Tell());
+            return size_t((Seek(p, aiOrigin_SET), len));
+        }
+    };
+#endif
+
+    using rapidjson::Value;
+    using rapidjson::Document;
+
+    class Asset;
+    class AssetWriter;
+
+    struct BufferView; // here due to cross-reference
+    struct Texture;
+    struct Light;
+
+
+    // Vec/matrix types, as raw float arrays
+    typedef float (vec3)[3];
+    typedef float (vec4)[4];
+    typedef float (mat4)[16];
+
+
+    namespace Util
+    {
+        void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out);
+
+        size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
+
+        inline size_t DecodeBase64(const char* in, uint8_t*& out)
+        {
+            return DecodeBase64(in, strlen(in), out);
+        }
+
+        struct DataURI
+        {
+            const char* mediaType;
+            const char* charset;
+            bool base64;
+            const char* data;
+            size_t dataLength;
+        };
+
+        //! Check if a uri is a data URI
+        inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out);
+    }
+
+
+    //! Magic number for GLB files
+    #define AI_GLB_MAGIC_NUMBER "glTF"
+
+    #ifdef ASSIMP_API
+        #include "./../include/assimp/Compiler/pushpack1.h"
+    #endif
+
+    //! For the KHR_binary_glTF extension (binary .glb file)
+    //! 20-byte header (+ the JSON + a "body" data section)
+    struct GLB_Header
+    {
+        uint8_t magic[4];     //!< Magic number: "glTF"
+        uint32_t version;     //!< Version number (always 1 as of the last update)
+        uint32_t length;      //!< Total length of the Binary glTF, including header, scene, and body, in bytes
+        uint32_t sceneLength; //!< Length, in bytes, of the glTF scene
+        uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum)
+    } PACK_STRUCT;
+
+    #ifdef ASSIMP_API
+        #include "./../include/assimp/Compiler/poppack1.h"
+    #endif
+
+
+    //! Values for the GLB_Header::sceneFormat field
+    enum SceneFormat
+    {
+        SceneFormat_JSON = 0
+    };
+
+    //! Values for the mesh primitive modes
+    enum PrimitiveMode
+    {
+        PrimitiveMode_POINTS = 0,
+        PrimitiveMode_LINES = 1,
+        PrimitiveMode_LINE_LOOP = 2,
+        PrimitiveMode_LINE_STRIP = 3,
+        PrimitiveMode_TRIANGLES = 4,
+        PrimitiveMode_TRIANGLE_STRIP = 5,
+        PrimitiveMode_TRIANGLE_FAN = 6
+    };
+
+    //! Values for the Accessor::componentType field
+    enum ComponentType
+    {
+        ComponentType_BYTE = 5120,
+        ComponentType_UNSIGNED_BYTE = 5121,
+        ComponentType_SHORT = 5122,
+        ComponentType_UNSIGNED_SHORT = 5123,
+        ComponentType_FLOAT = 5126
+    };
+
+    inline size_t ComponentTypeSize(ComponentType t)
+    {
+        switch (t) {
+            case ComponentType_SHORT:
+            case ComponentType_UNSIGNED_SHORT:
+                return 2;
+
+            case ComponentType_FLOAT:
+                return 4;
+
+            //case Accessor::ComponentType_BYTE:
+            //case Accessor::ComponentType_UNSIGNED_BYTE:
+            default:
+                return 1;
+        }
+    }
+
+    //! Values for the BufferView::target field
+    enum BufferViewTarget
+    {
+        BufferViewTarget_ARRAY_BUFFER = 34962,
+        BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963
+    };
+
+    //! Values for the Texture::format and Texture::internalFormat fields
+    enum TextureFormat
+    {
+        TextureFormat_ALPHA = 6406,
+        TextureFormat_RGB = 6407,
+        TextureFormat_RGBA = 6408,
+        TextureFormat_LUMINANCE = 6409,
+        TextureFormat_LUMINANCE_ALPHA = 6410
+    };
+
+    //! Values for the Texture::target field
+    enum TextureTarget
+    {
+        TextureTarget_TEXTURE_2D = 3553
+    };
+
+    //! Values for the Texture::type field
+    enum TextureType
+    {
+        TextureType_UNSIGNED_BYTE = 5121,
+        TextureType_UNSIGNED_SHORT_5_6_5 = 33635,
+        TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819,
+        TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820
+    };
+
+
+    //! Values for the Accessor::type field (helper class)
+    class AttribType
+    {
+    public:
+        enum Value
+            { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4 };
+
+    private:
+        static const size_t NUM_VALUES = static_cast<size_t>(MAT4)+1;
+
+        struct Info
+            { const char* name; unsigned int numComponents; };
+
+        template<int N> struct data
+            { static const Info infos[NUM_VALUES]; };
+
+    public:
+        inline static Value FromString(const char* str)
+        {
+            for (size_t i = 0; i < NUM_VALUES; ++i) {
+                if (strcmp(data<0>::infos[i].name, str) == 0) {
+                    return static_cast<Value>(i);
+                }
+            }
+            return SCALAR;
+        }
+
+        inline static const char* ToString(Value type)
+        {
+            return data<0>::infos[static_cast<size_t>(type)].name;
+        }
+
+        inline static unsigned int GetNumComponents(Value type)
+        {
+            return data<0>::infos[static_cast<size_t>(type)].numComponents;
+        }
+    };
+
+    // must match the order of the AttribTypeTraits::Value enum!
+    template<int N> const AttribType::Info
+    AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
+        { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 }
+    };
+
+
+
+    //! A reference to one top-level object, which is valid
+    //! until the Asset instance is destroyed
+    template<class T>
+    class Ref
+    {
+        std::vector<T*>* vector;
+        int index;
+
+    public:
+        Ref() : vector(0), index(0) {}
+        Ref(std::vector<T*>& vec, int idx) : vector(&vec), index(idx) {}
+
+        inline size_t GetIndex() const
+            { return index; }
+
+        operator bool() const
+            { return vector != 0; }
+
+        T* operator->()
+            { return (*vector)[index]; }
+
+        T& operator*()
+            { return *((*vector)[index]); }
+    };
+
+    //! Helper struct to represent values that might not be present
+    template<class T>
+    struct Nullable
+    {
+        T value;
+        bool isPresent;
+
+        Nullable() : isPresent(false) {}
+        Nullable(T& val) : value(val), isPresent(true) {}
+    };
+
+
+    //! Base classe for all glTF top-level objects
+    struct Object
+    {
+        std::string id;   //!< The globally unique ID used to reference this object
+        std::string name; //!< The user-defined name of this object
+
+        //! Objects marked as special are not exported (used to emulate the binary body buffer)
+        virtual bool IsSpecial() const
+            { return false; }
+
+        virtual ~Object() {}
+    };
+
+
+
+    //
+    // Classes for each glTF top-level object type
+    //
+
+    //! A typed view into a BufferView. A BufferView contains raw binary data.
+    //! An accessor provides a typed view into a BufferView or a subset of a BufferView
+    // !similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer.
+    struct Accessor : public Object
+    {
+        Ref<BufferView> bufferView;  //!< The ID of the bufferView. (required)
+        unsigned int byteOffset;     //!< The offset relative to the start of the bufferView in bytes. (required)
+        unsigned int byteStride;     //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0)
+        ComponentType componentType; //!< The datatype of components in the attribute. (required)
+        unsigned int count;          //!< The number of attributes referenced by this accessor. (required)
+        AttribType::Value type;      //!< Specifies if the attribute is a scalar, vector, or matrix. (required)
+        //std::vector<float> max;    //!< Maximum value of each component in this attribute.
+        //std::vector<float> min;    //!< Minimum value of each component in this attribute.
+
+        unsigned int GetNumComponents();
+        unsigned int GetBytesPerComponent();
+        unsigned int GetElementSize();
+
+        inline uint8_t* GetPointer();
+
+        template<class T>
+        void ExtractData(T*& outData);
+
+        void WriteData(size_t count, const void* src_buffer, size_t src_stride);
+
+        //! Helper class to iterate the data
+        class Indexer
+        {
+            friend struct Accessor;
+
+            Accessor& accessor;
+            uint8_t* data;
+            size_t elemSize, stride;
+
+            Indexer(Accessor& acc);
+
+        public:
+
+            //! Accesses the i-th value as defined by the accessor
+            template<class T>
+            T GetValue(int i);
+
+            //! Accesses the i-th value as defined by the accessor
+            inline unsigned int GetUInt(int i)
+            {
+                return GetValue<unsigned int>(i);
+            }
+        };
+
+        inline Indexer GetIndexer()
+        {
+            return Indexer(*this);
+        }
+
+        Accessor() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+
+    struct Animation : public Object
+    {
+        struct Channel
+        {
+
+        };
+        
+        struct Target
+        {
+
+        };
+        
+        struct Sampler
+        {
+
+        };
+    };
+
+    //! A buffer points to binary geometry, animation, or skins.
+    struct Buffer : public Object
+    {
+    public:
+
+        enum Type
+        {
+            Type_arraybuffer,
+            Type_text
+        };
+
+        //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
+        size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
+        //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
+
+        Type type;
+
+    private:
+        shared_ptr<uint8_t> mData; //!< Pointer to the data
+        bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer)
+
+    public:
+        Buffer();
+
+        void Read(Value& obj, Asset& r);
+
+        void LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0);
+        
+        size_t AppendData(uint8_t* data, size_t length);
+        void Grow(size_t amount);
+
+        uint8_t* GetPointer()
+            { return mData.get(); }
+
+        void MarkAsSpecial()
+            { mIsSpecial = true; }
+        
+        bool IsSpecial() const
+            { return mIsSpecial; }
+    };
+
+
+    //! A view into a buffer generally representing a subset of the buffer.
+    struct BufferView : public Object
+    {
+        Ref<Buffer> buffer; //! The ID of the buffer. (required)
+        size_t byteOffset; //! The offset into the buffer in bytes. (required)
+        size_t byteLength; //! The length of the bufferView in bytes. (default: 0)
+
+        BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
+
+        BufferView() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+
+    struct Camera : public Object
+    {
+        enum Type
+        {
+            Perspective,
+            Orthographic
+        };
+
+        Type type;
+
+        union
+        {
+            struct {
+                float aspectRatio; //!<The floating - point aspect ratio of the field of view. (0 = undefined = use the canvas one)
+                float yfov;  //!<The floating - point vertical field of view in radians. (required)
+                float zfar;  //!<The floating - point distance to the far clipping plane. (required)
+                float znear; //!< The floating - point distance to the near clipping plane. (required)
+            } perspective;
+
+            struct {
+                float xmag;  //! The floating-point horizontal magnification of the view. (required)
+                float ymag;  //! The floating-point vertical magnification of the view. (required)
+                float zfar;  //! The floating-point distance to the far clipping plane. (required)
+                float znear; //! The floating-point distance to the near clipping plane. (required)
+            } ortographic;
+        };
+
+        Camera() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+
+    //! Image data used to create a texture.
+    struct Image : public Object
+    {
+        std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required)
+
+        Ref<BufferView> bufferView;
+
+        std::string mimeType;
+
+        int width, height;
+
+    private:
+        uint8_t* mData;
+        size_t mDataLength;
+
+    public:
+
+        Image();
+        void Read(Value& obj, Asset& r);
+
+        inline bool HasData() const
+            { return mDataLength > 0; }
+
+        inline size_t GetDataLength() const
+            { return mDataLength; }
+        
+        inline const uint8_t* GetData() const
+            { return mData; }
+
+        inline uint8_t* StealData();
+
+        inline void SetData(uint8_t* data, size_t length, Asset& r);
+    };
+
+    //! Holds a material property that can be a texture or a color
+    struct TexProperty
+    {
+        Ref<Texture> texture;
+        vec4 color;
+    };
+
+    //! The material appearance of a primitive.
+    struct Material : public Object
+    {
+        //Ref<Sampler> source; //!< The ID of the technique.
+        //std::gltf_unordered_map<std::string, std::string> values; //!< A dictionary object of parameter values.
+
+        //! Techniques defined by KHR_materials_common
+        enum Technique
+        {
+            Technique_undefined = 0,
+            Technique_BLINN,
+            Technique_PHONG,
+            Technique_LAMBERT,
+            Technique_CONSTANT
+        };
+
+        TexProperty ambient;
+        TexProperty diffuse;
+        TexProperty specular;
+        TexProperty emission;
+
+        bool doubleSided;
+        bool transparent;
+        float transparency;
+        float shininess;
+
+        Technique technique;
+
+        Material() { SetDefaults(); }
+        void Read(Value& obj, Asset& r);
+        void SetDefaults();
+    };
+
+    //! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene.
+    struct Mesh : public Object
+    {
+        typedef std::vector< Ref<Accessor> > AccessorList;
+
+        struct Primitive
+        {
+            PrimitiveMode mode;
+
+            struct Attributes {
+                AccessorList position, normal, texcoord, color, joint, jointmatrix, weight;
+            } attributes;
+
+            Ref<Accessor> indices;
+
+            Ref<Material> material;
+        };
+
+        std::vector<Primitive> primitives;
+
+        Mesh() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+    struct Node : public Object
+    {
+        std::vector< Ref<Node> > children;
+        std::vector< Ref<Mesh> > meshes;
+
+        Nullable<mat4> matrix;
+        Nullable<vec3> translation;
+        Nullable<vec4> rotation;
+        Nullable<vec3> scale;
+
+        Ref<Camera> camera;
+        Ref<Light>  light;
+
+        Node() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+    struct Program : public Object
+    {
+        Program() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+
+    struct Sampler : public Object
+    {
+        Sampler() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+    struct Scene : public Object
+    {
+        std::vector< Ref<Node> > nodes;
+
+        Scene() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+    struct Shader : public Object
+    {
+        Shader() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+    struct Skin : public Object
+    {
+        Skin() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+    struct Technique : public Object
+    {
+        struct Parameters
+        {
+
+        };
+
+        struct States
+        {
+
+        };
+
+        struct Functions
+        {
+
+        };
+
+        Technique() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+    //! A texture and its sampler.
+    struct Texture : public Object
+    {
+        //Ref<Sampler> source; //!< The ID of the sampler used by this texture. (required)
+        Ref<Image> source; //!< The ID of the image used by this texture. (required)
+
+        //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA)
+        //TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA)
+
+        //TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D)
+        //TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE)
+
+        Texture() {}
+        void Read(Value& obj, Asset& r);
+    };
+
+
+    //! A light (from KHR_materials_common extension)
+    struct Light : public Object
+    {
+        enum Type
+        {
+            Type_undefined,
+            Type_ambient,
+            Type_directional,
+            Type_point,
+            Type_spot
+        };
+
+        Type type;
+
+        vec4 color;
+        float distance;
+        float constantAttenuation;
+        float linearAttenuation;
+        float quadraticAttenuation;
+        float falloffAngle;
+        float falloffExponent;
+
+        Light() {}
+        void Read(Value& obj, Asset& r);
+
+        void SetDefaults();
+    };
+
+    //! Base class for LazyDict that acts as an interface
+    class LazyDictBase
+    {
+    public:
+        virtual ~LazyDictBase() {}
+
+        virtual void AttachToDocument(Document& doc) = 0;
+        virtual void DetachFromDocument() = 0;
+
+        virtual void WriteObjects(AssetWriter& writer) = 0;
+    };
+
+    //! (Stub class that is specialized in glTFAssetWriter.h)
+    template<class T>
+    struct LazyDictWriter
+    {
+        static void Write(T& d, AssetWriter& w) {}
+    };
+
+    //! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID
+    //! It is the owner the loaded objects, so when it is destroyed it also deletes them
+    template<class T>
+    class LazyDict : public LazyDictBase
+    {
+        friend class Asset;
+        friend class AssetWriter;
+
+        typedef typename std::gltf_unordered_map< std::string, size_t > Dict;
+
+        std::vector<T*>  mObjs;      //! The read objects
+        Dict             mObjsById;  //! The read objects accesible by id
+        const char*      mDictId;    //! ID of the dictionary object
+        const char*      mExtId;     //! ID of the extension defining the dictionary
+        Value*           mDict;      //! JSON dictionary object
+        Asset&           mAsset;     //! The asset instance
+
+        void AttachToDocument(Document& doc);
+        void DetachFromDocument();
+
+        void WriteObjects(AssetWriter& writer)
+            { LazyDictWriter< LazyDict >::Write(*this, writer); }
+
+        Ref<T> Add(T* obj);
+
+    public:
+        LazyDict(Asset& asset, const char* dictId, const char* extId = 0);
+        ~LazyDict();
+
+        Ref<T> Get(const char* id);
+        Ref<T> Get(size_t i);
+
+        Ref<T> Create(const char* id);
+        Ref<T> Create(const std::string& id)
+            { return Create(id.c_str()); }
+
+        inline size_t Size() const
+            { return mObjs.size(); }
+
+        inline T& operator[](size_t i)
+            { return *mObjs[i]; }
+
+    };
+
+
+    struct AssetMetadata
+    {
+        std::string copyright; //!< A copyright message suitable for display to credit the content creator.
+        std::string generator; //!< Tool that generated this glTF model.Useful for debugging.
+        bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false)
+
+        struct {
+            std::string api;     //!< Specifies the target rendering API (default: "WebGL")
+            std::string version; //!< Specifies the target rendering API (default: "1.0.3")
+        } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
+
+        int version; //!< The glTF format version (should be 1)
+
+        void Read(Document& doc);
+    };
+
+    //
+    // glTF Asset class
+    //
+
+    //! Root object for a glTF asset
+    class Asset
+    {
+        typedef std::gltf_unordered_map<std::string, int> IdMap;
+
+        template<class T>
+        friend class LazyDict;
+
+        friend struct Buffer; // To access OpenFile
+
+        friend class AssetWriter;
+
+    private:
+        IOSystem* mIOSystem;
+
+        std::string mCurrentAssetDir;
+
+        size_t mSceneLength;
+        size_t mBodyOffset, mBodyLength;
+
+        std::vector<LazyDictBase*> mDicts;
+
+        IdMap mUsedIds;
+
+        Ref<Buffer> mBodyBuffer;
+
+        Asset(Asset&);
+        Asset& operator=(const Asset&);
+
+    public:
+
+        //! Keeps info about the enabled extensions
+        struct Extensions
+        {
+            bool KHR_binary_glTF;
+            bool KHR_materials_common;
+
+        } extensionsUsed;
+
+        AssetMetadata asset;
+
+
+        // Dictionaries for each type of object
+
+        LazyDict<Accessor>    accessors;
+        LazyDict<Animation>   animations;
+        LazyDict<Buffer>      buffers;
+        LazyDict<BufferView>  bufferViews;
+        LazyDict<Camera>      cameras;
+        LazyDict<Image>       images;
+        LazyDict<Material>    materials;
+        LazyDict<Mesh>        meshes;
+        LazyDict<Node>        nodes;
+        //LazyDict<Program>   programs;
+        //LazyDict<Sampler>   samplers;
+        LazyDict<Scene>       scenes;
+        //LazyDict<Shader>    shaders;
+        //LazyDict<Skin>      skins;
+        //LazyDict<Technique> techniques;
+        LazyDict<Texture>     textures;
+
+        LazyDict<Light>       lights; // KHR_materials_common ext
+
+        Ref<Scene> scene;
+
+    public:
+        Asset(IOSystem* io = 0)
+            : mIOSystem(io)
+            , accessors     (*this, "accessors")
+            , animations    (*this, "animations")
+            , buffers       (*this, "buffers")
+            , bufferViews   (*this, "bufferViews")
+            , cameras       (*this, "cameras")
+            , images        (*this, "images")
+            , materials     (*this, "materials")
+            , meshes        (*this, "meshes")
+            , nodes         (*this, "nodes")
+            //, programs    (*this, "programs")
+            //, samplers    (*this, "samplers")
+            , scenes        (*this, "scenes")
+            //, shaders     (*this, "shaders")
+            //, skins       (*this, "skins")
+            //, techniques  (*this, "techniques")
+            , textures      (*this, "textures")
+            , lights        (*this, "lights", "KHR_materials_common")
+        {
+            memset(&extensionsUsed, 0, sizeof(extensionsUsed));
+            memset(&asset, 0, sizeof(asset));
+        }
+
+        //! Main function
+        void Load(const std::string& file, bool isBinary = false);
+
+        //! Enables the "KHR_binary_glTF" extension on the asset
+        void SetAsBinary();
+
+        //! Search for an available name, starting from the given strings
+        std::string FindUniqueID(const std::string& str, const char* suffix);
+
+        Ref<Buffer> GetBodyBuffer()
+            { return mBodyBuffer; }
+
+    private:
+        void ReadBinaryHeader(IOStream& stream);
+
+        void ReadExtensionsUsed(Document& doc);
+
+
+        IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);
+    };
+
+}
+
+// Include the implementation of the methods
+#include "glTFAsset.inl"
+
+#endif

+ 1215 - 0
code/glTFAsset.inl

@@ -0,0 +1,1215 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, 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.
+
+----------------------------------------------------------------------
+*/
+
+namespace glTF {
+
+namespace {
+    
+    //
+    // JSON Value reading helpers
+    //
+
+    template<class T>
+    struct ReadHelper { static bool Read(Value& val, T& out) {
+        return val.IsInt() ? out = static_cast<T>(val.GetInt()), true : false;
+    }};
+    
+    template<> struct ReadHelper<bool> { static bool Read(Value& val, bool& out) {
+        return val.IsBool() ? out = val.GetBool(), true : false;
+    }};
+
+    template<> struct ReadHelper<float> { static bool Read(Value& val, float& out) {
+        return val.IsNumber() ? out = static_cast<float>(val.GetDouble()), true : false;
+    }};
+    
+    template<size_t N> struct ReadHelper<float[N]> { static bool Read(Value& val, float (&out)[N]) {
+        if (!val.IsArray() || val.Size() != N) return false;
+        for (size_t i = 0; i < N; ++i) {
+            if (val[i].IsNumber())
+                out[i] = static_cast<float>(val[i].GetDouble());
+        }
+        return true;
+    }};
+
+    template<> struct ReadHelper<const char*> { static bool Read(Value& val, const char*& out) {
+        return val.IsString() ? out = val.GetString(), true : false;
+    }};
+
+    template<> struct ReadHelper<std::string> { static bool Read(Value& val, std::string& out) {
+        return val.IsString() ? out = val.GetString(), true : false;
+    }};
+
+    template<class T> struct ReadHelper< Nullable<T> > { static bool Read(Value& val, Nullable<T>& out) {
+        return out.isPresent = ReadHelper<T>::Read(val, out.value);
+    }};
+
+    template<class T>
+    inline static bool ReadValue(Value& val, T& out)
+    {
+        return ReadHelper<T>::Read(val, out);
+    }
+
+    template<class T>
+    inline static bool ReadMember(Value& obj, const char* id, T& out)
+    {
+        Value::MemberIterator it = obj.FindMember(id);
+        if (it != obj.MemberEnd()) {
+            return ReadHelper<T>::Read(it->value, out);
+        }
+        return false;
+    }
+
+    template<class T>
+    inline static T MemberOrDefault(Value& obj, const char* id, T defaultValue)
+    {
+        T out;
+        return ReadMember(obj, id, out) ? out : defaultValue;
+    }
+
+    inline Value* FindMember(Value& val, const char* id)
+    {
+        Value::MemberIterator it = val.FindMember(id);
+        return (it != val.MemberEnd()) ? &it->value : 0;
+    }
+
+    inline Value* FindString(Value& val, const char* id)
+    {
+        Value::MemberIterator it = val.FindMember(id);
+        return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0;
+    }
+
+    inline Value* FindArray(Value& val, const char* id)
+    {
+        Value::MemberIterator it = val.FindMember(id);
+        return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : 0;
+    }
+
+    inline Value* FindObject(Value& val, const char* id)
+    {
+        Value::MemberIterator it = val.FindMember(id);
+        return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : 0;
+    }
+}
+
+//
+// LazyDict methods
+//
+
+template<class T>
+inline LazyDict<T>::LazyDict(Asset& asset, const char* dictId, const char* extId)
+    : mDictId(dictId), mExtId(extId), mDict(0), mAsset(asset)
+{
+    asset.mDicts.push_back(this); // register to the list of dictionaries
+}
+
+template<class T>
+inline LazyDict<T>::~LazyDict()
+{
+    for (size_t i = 0; i < mObjs.size(); ++i) {
+        delete mObjs[i];
+    }
+}
+
+
+template<class T>
+inline void LazyDict<T>::AttachToDocument(Document& doc)
+{
+    Value* container = 0;
+
+    if (mExtId) {
+        if (Value* exts = FindObject(doc, "extensions")) {
+            container = FindObject(*exts, mExtId);
+        }
+    }
+    else {
+        container = &doc;
+    }
+
+    if (container) {
+        mDict = FindObject(*container, mDictId);
+    }
+}
+
+template<class T>
+inline void LazyDict<T>::DetachFromDocument()
+{
+    mDict = 0;
+}
+
+template<class T>
+Ref<T> LazyDict<T>::Get(size_t i)
+{
+    return Ref<T>(mObjs, i);
+}
+
+template<class T>
+Ref<T> LazyDict<T>::Get(const char* id)
+{
+    typename Dict::iterator it = mObjsById.find(id);
+    if (it != mObjsById.end()) { // already created?
+        return Ref<T>(mObjs, it->second);
+    }
+
+    // read it from the JSON object
+    if (!mDict) {
+        return Ref<T>(); // section is missing
+    }
+
+    Value::MemberIterator obj = mDict->FindMember(id);
+    if (obj == mDict->MemberEnd()) {
+        throw DeadlyImportError("Missing object with id \"" + std::string(id) + "\" in \"" + mDictId + "\"");
+    }
+    if (!obj->value.IsObject()) {
+        throw DeadlyImportError("Object with id \"" + std::string(id) + "\" is not a JSON object!");
+    }
+
+    // create an instance of the given type
+    T* inst = new T();
+    inst->id = id;
+    ReadMember(obj->value, "name", inst->name);
+    inst->Read(obj->value, mAsset);
+    return Add(inst);
+}
+
+template<class T>
+Ref<T> LazyDict<T>::Add(T* obj)
+{
+    size_t idx = mObjs.size();
+    mObjs.push_back(obj);
+    mObjsById[obj->id] = idx;
+    mAsset.mUsedIds[obj->id] = true;
+    return Ref<T>(mObjs, idx);
+}
+
+template<class T>
+Ref<T> LazyDict<T>::Create(const char* id)
+{
+    Asset::IdMap::iterator it = mAsset.mUsedIds.find(id);
+    if (it != mAsset.mUsedIds.end()) {
+        throw DeadlyImportError("Two objects with the same ID exist!");
+    }
+    T* inst = new T();
+    inst->id = id;
+    return Add(inst);
+}
+
+
+//
+// glTF dictionary objects methods
+//
+
+
+inline Buffer::Buffer()
+: byteLength(0), type(Type_arraybuffer), mIsSpecial(false)
+{ }
+
+
+inline void Buffer::Read(Value& obj, Asset& r)
+{
+    size_t statedLength = MemberOrDefault<size_t>(obj, "byteLength", 0);
+    byteLength = statedLength;
+
+    Value* it = FindString(obj, "uri");
+    if (!it) return;
+
+    const char* uri = it->GetString();
+
+    Util::DataURI dataURI;
+    if (ParseDataURI(uri, it->GetStringLength(), dataURI)) {
+        if (dataURI.base64) {
+            uint8_t* data = 0;
+            this->byteLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, data);
+            this->mData.reset(data);
+
+            if (statedLength > 0 && this->byteLength != statedLength) {
+                // error?
+            }
+        }
+    }
+    else { // Local file
+        if (byteLength > 0) {
+            IOStream* file = r.OpenFile(uri, "rb");
+            if (file) {
+                LoadFromStream(*file, byteLength);
+                delete file;
+            }
+        }
+    }
+}
+
+inline void Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseOffset)
+{
+    byteLength = length ? length : stream.FileSize();
+
+    if (baseOffset) {
+        stream.Seek(baseOffset, aiOrigin_SET);
+    }
+
+    mData.reset(new uint8_t[byteLength]);
+
+    if (stream.Read(mData.get(), byteLength, 1) != 1) {
+        throw DeadlyImportError("Unable to load buffer from file!");
+    }
+}
+
+inline size_t Buffer::AppendData(uint8_t* data, size_t length)
+{
+    size_t offset = this->byteLength;
+    Grow(length);
+    memcpy(mData.get() + offset, data, length);
+    return offset;
+}
+
+inline void Buffer::Grow(size_t amount)
+{
+    if (amount <= 0) return;
+    uint8_t* b = new uint8_t[byteLength + amount];
+    if (mData) memcpy(b, mData.get(), byteLength);
+    mData.reset(b);
+    byteLength += amount;
+}
+
+
+inline void BufferView::Read(Value& obj, Asset& r)
+{
+    const char* bufferId = MemberOrDefault<const char*>(obj, "buffer", 0);
+    if (bufferId) {
+        buffer = r.buffers.Get(bufferId);
+    }
+        
+    byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
+    byteLength = MemberOrDefault(obj, "byteLength", 0u);
+}
+
+
+
+inline void Accessor::Read(Value& obj, Asset& r)
+{
+    const char* bufferViewId = MemberOrDefault<const char*>(obj, "bufferView", 0);
+    if (bufferViewId) {
+        bufferView = r.bufferViews.Get(bufferViewId);
+    }
+
+    byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
+    byteStride = MemberOrDefault(obj, "byteStride", 0u);
+    componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE);
+    count = MemberOrDefault(obj, "count", 0u);
+
+    const char* typestr;
+    type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR;
+}
+
+inline unsigned int Accessor::GetNumComponents()
+{
+    return AttribType::GetNumComponents(type);
+}
+
+inline unsigned int Accessor::GetBytesPerComponent()
+{
+    return ComponentTypeSize(componentType);
+}
+
+inline unsigned int Accessor::GetElementSize()
+{
+    return GetNumComponents() * GetBytesPerComponent();
+}
+
+inline uint8_t* Accessor::GetPointer()
+{
+    if (!bufferView || !bufferView->buffer) return 0;
+
+    size_t offset = byteOffset + bufferView->byteOffset;
+    return bufferView->buffer->GetPointer() + offset;
+}
+
+namespace {
+    inline void CopyData(size_t count,
+            const uint8_t* src, size_t src_stride,
+                  uint8_t* dst, size_t dst_stride)
+    {
+        if (src_stride == dst_stride) {
+            memcpy(dst, src, count * src_stride);
+        }
+        else {
+            size_t sz = std::min(src_stride, dst_stride);
+            for (size_t i = 0; i < count; ++i) {
+                memcpy(dst, src, sz);
+                if (sz < dst_stride) {
+                    memset(dst + sz, 0, dst_stride - sz);
+                }
+                src += src_stride;
+                dst += dst_stride;
+            }
+        }
+    }
+}
+
+template<class T>
+void Accessor::ExtractData(T*& outData)
+{
+    uint8_t* data = GetPointer();
+    ai_assert(data);
+
+    const size_t elemSize = GetElementSize();
+    const size_t totalSize = elemSize * count;
+
+    const size_t stride = byteStride ? byteStride : elemSize;
+
+    const size_t targetElemSize = sizeof(T);
+    ai_assert(elemSize <= targetElemSize);
+
+    ai_assert(count*stride <= bufferView->byteLength);
+
+    outData = new T[count];
+    if (stride == elemSize && targetElemSize == elemSize) {
+        memcpy(outData, data, totalSize);
+    }
+    else {
+        for (size_t i = 0; i < count; ++i) {
+            memcpy(outData + i, data + i*stride, elemSize);
+        }
+    }
+}
+
+inline void Accessor::WriteData(size_t count, const void* src_buffer, size_t src_stride)
+{
+    uint8_t* buffer_ptr = bufferView->buffer->GetPointer();
+    size_t offset = byteOffset + bufferView->byteOffset;
+
+    size_t dst_stride = GetNumComponents() * GetBytesPerComponent();
+
+    const uint8_t* src = reinterpret_cast<const uint8_t*>(src_buffer);
+    uint8_t*       dst = reinterpret_cast<      uint8_t*>(buffer_ptr + offset);
+
+    ai_assert(dst + count*dst_stride <= buffer_ptr + bufferView->buffer->byteLength);
+    CopyData(count, src, src_stride, dst, dst_stride);
+}
+
+
+
+inline Accessor::Indexer::Indexer(Accessor& acc)
+    : accessor(acc)
+    , data(acc.GetPointer())
+    , elemSize(acc.GetElementSize())
+    , stride(acc.byteStride ? acc.byteStride : elemSize)
+{
+
+}
+
+//! Accesses the i-th value as defined by the accessor
+template<class T>
+T Accessor::Indexer::GetValue(int i)
+{
+    ai_assert(data);
+    ai_assert(i*stride < accessor.bufferView->byteLength);
+    T value = T();
+    memcpy(&value, data + i*stride, elemSize);
+    //value >>= 8 * (sizeof(T) - elemSize);
+    return value;
+}
+
+inline Image::Image()
+    : width(0)
+    , height(0)
+    , mData(0)
+    , mDataLength(0)
+{
+
+}
+
+inline void Image::Read(Value& obj, Asset& r)
+{
+    // Check for extensions first (to detect binary embedded data) 
+    if (Value* extensions = FindObject(obj, "extensions")) {
+        if (r.extensionsUsed.KHR_binary_glTF) {
+            if (Value* ext = FindObject(*extensions, "KHR_binary_glTF")) {
+
+                width  = MemberOrDefault(*ext, "width", 0);
+                height = MemberOrDefault(*ext, "height", 0);
+
+                ReadMember(*ext, "mimeType", mimeType);
+
+                const char* bufferViewId;
+                if (ReadMember(*ext, "bufferView", bufferViewId)) {
+                    Ref<BufferView> bv = r.bufferViews.Get(bufferViewId);
+                    if (bv) {
+                        mDataLength = bv->byteLength;
+                        mData = new uint8_t[mDataLength];
+                        memcpy(mData, bv->buffer->GetPointer() + bv->byteOffset, mDataLength);
+                    }
+                }
+            }
+        }
+    }
+
+    if (!mDataLength) {
+        if (Value* uri = FindString(obj, "uri")) {
+            const char* uristr = uri->GetString();
+
+            Util::DataURI dataURI;
+            if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) {
+                mimeType = dataURI.mediaType;
+                if (dataURI.base64) {
+                    mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, mData);
+                }
+            }
+            else {
+                this->uri = uristr;
+            }
+        }
+    }
+}
+
+inline uint8_t* Image::StealData()
+{
+    uint8_t* data = mData;
+    mDataLength = 0;
+    mData = 0;
+    return data;
+}
+
+inline void Image::SetData(uint8_t* data, size_t length, Asset& r)
+{
+    Ref<Buffer> b = r.GetBodyBuffer();
+    if (b) { // binary file: append to body
+        std::string bvId = r.FindUniqueID(this->id, "imgdata");
+        bufferView = r.bufferViews.Create(bvId);
+
+        bufferView->buffer = b;
+        bufferView->byteLength = length;
+        bufferView->byteOffset = b->AppendData(data, length);
+    }
+    else { // text file: will be stored as a data uri
+        this->mData = data;
+        this->mDataLength = length;
+    }
+}
+
+inline void Texture::Read(Value& obj, Asset& r)
+{
+    const char* sourcestr;
+    if (ReadMember(obj, "source", sourcestr)) {
+        source = r.images.Get(sourcestr);
+    }
+}
+
+namespace {
+    inline void ReadMaterialProperty(Asset& r, Value& vals, const char* propName, TexProperty& out)
+    {
+        if (Value* prop = FindMember(vals, propName)) {
+            if (prop->IsString()) {
+                out.texture = r.textures.Get(prop->GetString());
+            }
+            else {
+                ReadValue(*prop, out.color);
+            }
+        }
+    }
+}
+
+inline void Material::Read(Value& material, Asset& r)
+{
+    SetDefaults();
+
+    if (Value* values = FindObject(material, "values")) {
+        ReadMaterialProperty(r, *values, "ambient", this->ambient);
+        ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
+        ReadMaterialProperty(r, *values, "specular", this->specular);
+
+        ReadMember(*values, "shininess", shininess);
+    }
+
+    if (Value* extensions = FindObject(material, "extensions")) {
+        if (r.extensionsUsed.KHR_materials_common) {
+            if (Value* ext = FindObject(*extensions, "KHR_materials_common")) {
+                if (Value* tnq = FindString(*ext, "technique")) {
+                    const char* t = tnq->GetString();
+                    if      (strcmp(t, "BLINN") == 0)    technique = Technique_BLINN;
+                    else if (strcmp(t, "PHONG") == 0)    technique = Technique_PHONG;
+                    else if (strcmp(t, "LAMBERT") == 0)  technique = Technique_LAMBERT;
+                    else if (strcmp(t, "CONSTANT") == 0) technique = Technique_CONSTANT;
+                }
+
+                ReadMaterialProperty(r, *ext, "ambient", this->ambient);
+                ReadMaterialProperty(r, *ext, "diffuse", this->diffuse);
+                ReadMaterialProperty(r, *ext, "specular", this->specular);
+
+                ReadMember(*ext, "doubleSided", doubleSided);
+                ReadMember(*ext, "transparent", transparent);
+                ReadMember(*ext, "transparency", transparency);
+                ReadMember(*ext, "shininess", shininess);
+            }
+        }
+    }
+}
+
+namespace {
+    void SetVector(vec4& v, float x, float y, float z, float w)
+        { v[0] = x; v[1] = y; v[2] = z; v[3] = w; }
+}
+
+inline void Material::SetDefaults()
+{
+    SetVector(ambient.color, 0, 0, 0, 1);
+    SetVector(diffuse.color, 0, 0, 0, 1);
+    SetVector(specular.color, 0, 0, 0, 1);
+    SetVector(emission.color, 0, 0, 0, 1);
+
+    doubleSided = false;
+    transparent = false;
+    transparency = 1.0;
+    shininess = 0.0;
+
+    technique = Technique_undefined;
+}
+
+namespace {
+
+    template<int N>
+    inline int Compare(const char* attr, const char (&str)[N]) {
+        return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0;
+    }
+
+    inline bool GetAttribVector(Mesh::Primitive& p, const char* attr, Mesh::AccessorList*& v, int& pos)
+    {
+        if ((pos = Compare(attr, "POSITION"))) {
+            v = &(p.attributes.position);
+        }
+        else if ((pos = Compare(attr, "NORMAL"))) {
+            v = &(p.attributes.normal);
+        }
+        else if ((pos = Compare(attr, "TEXCOORD"))) {
+            v = &(p.attributes.texcoord);
+        }
+        else if ((pos = Compare(attr, "COLOR"))) {
+            v = &(p.attributes.color);
+        }
+        else if ((pos = Compare(attr, "JOINT"))) {
+            v = &(p.attributes.joint);
+        }
+        else if ((pos = Compare(attr, "JOINTMATRIX"))) {
+            v = &(p.attributes.jointmatrix);
+        }
+        else if ((pos = Compare(attr, "WEIGHT"))) {
+            v = &(p.attributes.weight);
+        }
+        else return false;
+        return true;
+    }
+}
+
+inline void Mesh::Read(Value& obj, Asset& r)
+{  
+    if (Value* primitives = FindArray(obj, "primitives")) {
+        this->primitives.resize(primitives->Size());
+        for (unsigned int i = 0; i < primitives->Size(); ++i) {
+            Value& primitive = (*primitives)[i];
+
+            Primitive& prim = this->primitives[i];
+            prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES);
+
+            if (Value* attrs = FindObject(primitive, "attributes")) {
+                for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
+                    if (!it->value.IsString()) continue;
+                    const char* attr = it->name.GetString();
+                    // Valid attribute semantics include POSITION, NORMAL, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
+                    // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
+
+                    int undPos = 0;
+                    Mesh::AccessorList* vec = 0;
+                    if (GetAttribVector(prim, attr, vec, undPos)) {
+                        size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
+                        if ((*vec).size() <= idx) (*vec).resize(idx + 1);
+                        (*vec)[idx] = r.accessors.Get(it->value.GetString());
+                    }
+                }
+            }
+
+            if (Value* indices = FindString(primitive, "indices")) {
+                prim.indices = r.accessors.Get(indices->GetString());
+            }
+
+            if (Value* material = FindString(primitive, "material")) {
+                prim.material = r.materials.Get(material->GetString());
+            }
+        }
+    }
+}
+
+
+inline void Camera::Read(Value& obj, Asset& r)
+{
+    type = MemberOrDefault(obj, "type", Camera::Perspective);
+
+    const char* subobjId = (type == Camera::Orthographic) ? "ortographic" : "perspective";
+
+    Value* it = FindObject(obj, subobjId);
+    if (!it) throw DeadlyImportError("Camera missing its parameters!");
+
+    if (type == Camera::Perspective) {
+        perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
+        perspective.yfov        = MemberOrDefault(*it, "yfov", 3.1415f/2.f);
+        perspective.zfar        = MemberOrDefault(*it, "zfar", 100.f);
+        perspective.znear       = MemberOrDefault(*it, "znear", 0.01f);
+    }
+    else {
+        ortographic.xmag  = MemberOrDefault(obj, "xmag", 1.f);
+        ortographic.ymag  = MemberOrDefault(obj, "ymag", 1.f);
+        ortographic.zfar  = MemberOrDefault(obj, "zfar", 100.f);
+        ortographic.znear = MemberOrDefault(obj, "znear", 0.01f);
+    }
+}
+
+inline void Light::Read(Value& obj, Asset& r)
+{
+    SetDefaults();
+
+    if (Value* type = FindString(obj, "type")) {
+        const char* t = type->GetString();
+        if      (strcmp(t, "ambient") == 0)     this->type = Type_ambient;
+        else if (strcmp(t, "directional") == 0) this->type = Type_directional;
+        else if (strcmp(t, "point") == 0)       this->type = Type_point;
+        else if (strcmp(t, "spot") == 0)        this->type = Type_spot;
+
+        if (this->type != Type_undefined) {
+            if (Value* vals = FindString(obj, t)) {
+                ReadMember(*vals, "color", color);
+
+                ReadMember(*vals, "constantAttenuation", constantAttenuation);
+                ReadMember(*vals, "linearAttenuation", linearAttenuation);
+                ReadMember(*vals, "quadraticAttenuation", quadraticAttenuation);
+                ReadMember(*vals, "distance", distance);
+
+                ReadMember(*vals, "falloffAngle", falloffAngle);
+                ReadMember(*vals, "falloffExponent", falloffExponent);
+            }
+        }
+    }
+}
+
+inline void Light::SetDefaults()
+{
+    #ifndef M_PI
+        const float M_PI = 3.14159265358979323846f;
+    #endif
+
+    type = Type_undefined;
+
+    SetVector(color, 0.f, 0.f, 0.f, 1.f);
+
+    constantAttenuation = 0.f;
+    linearAttenuation = 1.f;
+    quadraticAttenuation = 1.f;
+    distance = 0.f;
+
+    falloffAngle = static_cast<float>(M_PI / 2.f);
+    falloffExponent = 0.f;
+}
+
+inline void Node::Read(Value& obj, Asset& r)
+{
+    if (Value* children = FindArray(obj, "children")) {
+        this->children.reserve(children->Size());
+        for (unsigned int i = 0; i < children->Size(); ++i) {
+            Value& child = (*children)[i];
+            if (child.IsString()) {
+                // get/create the child node
+                Ref<Node> chn = r.nodes.Get(child.GetString());
+                if (chn) this->children.push_back(chn);
+            }
+        }
+    }
+
+    
+    if (Value* matrix = FindArray(obj, "matrix")) {
+        ReadValue(*matrix, this->matrix);
+    }
+    else {
+        ReadMember(obj, "translation", translation);
+        ReadMember(obj, "scale", scale);
+        ReadMember(obj, "rotation", rotation);
+    }
+
+    if (Value* meshes = FindArray(obj, "meshes")) {
+        size_t numMeshes = (size_t)meshes->Size();
+
+        std::vector<unsigned int> meshList;
+
+        this->meshes.reserve(numMeshes);
+        for (size_t i = 0; i < numMeshes; ++i) {
+            if ((*meshes)[i].IsString()) {
+                Ref<Mesh> mesh = r.meshes.Get((*meshes)[i].GetString());
+                if (mesh) this->meshes.push_back(mesh);
+            }
+        }
+    }
+
+    if (Value* camera = FindString(obj, "camera")) {
+        this->camera = r.cameras.Get(camera->GetString());
+        if (this->camera)
+            this->camera->id = this->id;
+    }
+
+    // TODO load "skeletons", "skin", "jointName"
+
+    if (Value* extensions = FindObject(obj, "extensions")) {
+        if (r.extensionsUsed.KHR_materials_common) {
+
+            if (Value* ext = FindObject(*extensions, "KHR_materials_common")) {
+                if (Value* light = FindString(*ext, "light")) {
+                    this->light = r.lights.Get(light->GetString());
+                }
+            }
+
+        }
+    }
+}
+
+inline void Scene::Read(Value& obj, Asset& r)
+{
+    if (Value* array = FindArray(obj, "nodes")) {
+        for (unsigned int i = 0; i < array->Size(); ++i) {
+            if (!(*array)[i].IsString()) continue;
+            Ref<Node> node = r.nodes.Get((*array)[i].GetString());
+            if (node)
+                this->nodes.push_back(node);
+        }
+    }
+}
+
+
+inline void AssetMetadata::Read(Document& doc)
+{
+    // read the version, etc.
+    int statedVersion = 0;
+    if (Value* obj = FindObject(doc, "asset")) {
+        ReadMember(*obj, "copyright", copyright);
+        ReadMember(*obj, "generator", generator);
+
+        premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false);
+        statedVersion = MemberOrDefault(*obj, "version", 0);
+
+        if (Value* profile = FindObject(*obj, "profile")) {
+            ReadMember(*profile, "api",     this->profile.api);
+            ReadMember(*profile, "version", this->profile.version);
+        }
+    }
+
+    version = std::max(statedVersion, version);
+    if (version == 0) {
+        // if missing version, we'll assume version 1...
+        version = 1;
+    }
+
+    if (version != 1) {
+        char msg[128];
+        sprintf(msg, "Unsupported glTF version: %d", version);
+        throw DeadlyImportError(msg);
+    }
+}
+
+
+
+//
+// Asset methods implementation
+//
+
+inline void Asset::ReadBinaryHeader(IOStream& stream)
+{
+    GLB_Header header;
+    if (stream.Read(&header, sizeof(header), 1) != 1) {
+        throw DeadlyImportError("Unable to read the file header");
+    }
+
+    if (strncmp((char*)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
+        throw DeadlyImportError("Invalid binary glTF file");
+    }
+
+    AI_SWAP4(header.version);
+    asset.version = header.version;
+    if (header.version != 1) {
+        throw DeadlyImportError("Unsupported binary glTF version");
+    }
+
+    AI_SWAP4(header.sceneFormat);
+    if (header.sceneFormat != SceneFormat_JSON) {
+        throw DeadlyImportError("Unsupported binary glTF scene format");
+    }
+
+    AI_SWAP4(header.length);
+    AI_SWAP4(header.sceneLength);
+
+    mSceneLength = static_cast<size_t>(header.sceneLength);
+
+    mBodyOffset = sizeof(header)+mSceneLength;
+    mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
+
+    mBodyLength = header.length - mBodyOffset;
+}
+
+inline void Asset::Load(const std::string& pFile, bool isBinary)
+{
+    mCurrentAssetDir.clear();
+    int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
+    if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1);
+
+    shared_ptr<IOStream> stream(OpenFile(pFile.c_str(), "rb", true));
+    if (!stream) {
+        throw DeadlyImportError("Could not open file for reading");
+    }
+
+    // is binary? then read the header
+    if (isBinary) {
+        SetAsBinary(); // also creates the body buffer
+        ReadBinaryHeader(*stream);
+    }
+    else {
+        mSceneLength = stream->FileSize();
+        mBodyLength = 0;
+    }
+
+
+    // read the scene data
+
+    std::vector<char> sceneData(mSceneLength + 1);
+    sceneData[mSceneLength] = '\0';
+
+    if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) {
+        throw DeadlyImportError("Could not read the file contents");
+    }
+
+
+    // parse the JSON document
+
+    Document doc;
+    doc.ParseInsitu(&sceneData[0]);
+
+    if (doc.HasParseError()) {
+        char buffer[32];
+        sprintf(buffer, "%d", static_cast<int>(doc.GetErrorOffset()));
+        throw DeadlyImportError(std::string("JSON parse error, offset ") + buffer + ": "
+            + GetParseError_En(doc.GetParseError()));
+    }
+
+    if (!doc.IsObject()) {
+        throw DeadlyImportError("gltf file must be a JSON object!");
+    }
+
+    // Fill the buffer instance for the current file embedded contents
+    if (mBodyLength > 0) {
+        mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset);
+    }
+
+
+    // Load the metadata
+    asset.Read(doc);
+    ReadExtensionsUsed(doc);
+
+    // Prepare the dictionaries
+    for (size_t i = 0; i < mDicts.size(); ++i) {
+        mDicts[i]->AttachToDocument(doc);
+    }
+
+
+
+    // Read the "scene" property, which specifies which scene to load
+    // and recursively load everything referenced by it
+    if (Value* scene = FindString(doc, "scene")) {
+        this->scene = scenes.Get(scene->GetString());
+    }
+
+    // Clean up
+    for (size_t i = 0; i < mDicts.size(); ++i) {
+        mDicts[i]->DetachFromDocument();
+    }
+}
+
+inline void Asset::SetAsBinary()
+{
+    if (!extensionsUsed.KHR_binary_glTF) {
+        extensionsUsed.KHR_binary_glTF = true;
+        mBodyBuffer = buffers.Create("KHR_binary_glTF");
+        mBodyBuffer->MarkAsSpecial();
+    }
+}
+
+
+inline void Asset::ReadExtensionsUsed(Document& doc)
+{
+    Value* extsUsed = FindArray(doc, "extensionsUsed");
+    if (!extsUsed) return;
+
+    std::gltf_unordered_map<std::string, bool> exts;
+
+    for (unsigned int i = 0; i < extsUsed->Size(); ++i) {
+        if ((*extsUsed)[i].IsString()) {
+            exts[(*extsUsed)[i].GetString()] = true;
+        }
+    }
+
+    #define CHECK_EXT(EXT) \
+        if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
+
+    CHECK_EXT(KHR_binary_glTF);
+    CHECK_EXT(KHR_materials_common);
+
+    #undef CHECK_EXT
+}
+
+inline IOStream* Asset::OpenFile(std::string path, const char* mode, bool absolute)
+{
+    #ifdef ASSIMP_API
+        return mIOSystem->Open(path, mode);
+    #else
+        if (path.size() < 2) return 0;
+        if (!absolute && path[1] != ':' && path[0] != '/') { // relative?
+            path = mCurrentAssetDir + path;
+        }
+        FILE* f = fopen(path.c_str(), mode);
+        return f ? new IOStream(f) : 0;
+    #endif
+}
+
+inline std::string Asset::FindUniqueID(const std::string& str, const char* suffix)
+{
+    std::string id = str;
+
+    Asset::IdMap::iterator it;
+
+    do {
+        if (!id.empty()) {
+            it = mUsedIds.find(id);
+            if (it == mUsedIds.end()) break;
+
+            id += "_";
+        }
+
+        id += suffix;
+
+        it = mUsedIds.find(id);
+        if (it == mUsedIds.end()) break;
+
+        char buffer[256];
+        int offset = sprintf(buffer, "%s_", id.c_str());
+        for (int i = 0; it != mUsedIds.end(); ++i) {
+            sprintf(buffer + offset, "%d", i);
+
+            id = buffer;
+            it = mUsedIds.find(id);
+        }
+    } while (false); // fake loop to allow using "break"
+    
+    return id;
+}
+
+namespace Util
+{
+
+    inline bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out)
+    {
+        if (const_uri[0] != 0x10) { // we already parsed this uri?
+            if (strncmp(const_uri, "data:", 5) != 0) // not a data uri?
+                return false;
+        }
+
+        // set defaults
+        out.mediaType = "text/plain";
+        out.charset = "US-ASCII";
+        out.base64 = false;
+
+        char* uri = const_cast<char*>(const_uri);
+        if (uri[0] != 0x10) {
+            uri[0] = 0x10;
+            uri[1] = uri[2] = uri[3] = uri[4] = 0;
+
+            size_t i = 5, j;
+            if (uri[i] != ';' && uri[i] != ',') { // has media type?
+                uri[1] = i;
+                for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) {}
+            }
+            while (uri[i] == ';' && i < uriLen) {
+                uri[i++] = '\0';
+                for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) {}
+
+                if (strncmp(uri + j, "charset=", 8) == 0) uri[2] = j + 8;
+                else if (strncmp(uri + j, "base64", 6) == 0) uri[3] = j;
+            }
+            if (i < uriLen) {
+                uri[i++] = '\0';
+                uri[4] = i;
+            }
+            else {
+                uri[1] = uri[2] = uri[3] = 0;
+                uri[4] = 5;
+            }
+        }
+
+        if (uri[1] != 0) out.mediaType = uri + uri[1];
+        if (uri[2] != 0) out.charset = uri + uri[2];
+        if (uri[3] != 0) out.base64 = true;
+        out.data = uri + uri[4];
+        out.dataLength = (uri + uriLen) - out.data;
+
+        return true;
+    }
+
+    template<bool B>
+    struct DATA
+    {
+        static const uint8_t tableDecodeBase64[128];
+    };
+
+    template<bool B>
+    const uint8_t DATA<B>::tableDecodeBase64[128] = {
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0, 63,
+        52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0, 64,  0,  0,
+         0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
+         0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  0,  0,  0,  0,  0
+    };
+
+    inline char EncodeCharBase64(uint8_t b)
+    {
+        return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)];
+    }
+
+    inline uint8_t DecodeCharBase64(char c)
+    {
+        return DATA<true>::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs?
+        /*if (c >= 'A' && c <= 'Z') return c - 'A';
+        if (c >= 'a' && c <= 'z') return c - 'a' + 26;
+        if (c >= '0' && c <= '9') return c - '0' + 52;
+        if (c == '+') return 62;
+        if (c == '/') return 63;
+        return 64; // '-' */
+    }
+
+    inline size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out)
+    {
+        ai_assert(inLength % 4 == 0);
+
+        if (inLength < 4) {
+            out = 0;
+            return 0;
+        }
+
+        int nEquals = int(in[inLength - 1] == '=') +
+                      int(in[inLength - 2] == '=');
+
+        size_t outLength = (inLength * 3) / 4 - nEquals;
+        out = new uint8_t[outLength];
+        memset(out, 0, outLength);
+
+        size_t i, j = 0;
+
+        for (i = 0; i + 4 < inLength; i += 4) {
+            uint8_t b0 = DecodeCharBase64(in[i]);
+            uint8_t b1 = DecodeCharBase64(in[i + 1]);
+            uint8_t b2 = DecodeCharBase64(in[i + 2]);
+            uint8_t b3 = DecodeCharBase64(in[i + 3]);
+
+            out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
+            out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
+            out[j++] = (uint8_t)((b2 << 6) | b3);
+        }
+
+        {
+            uint8_t b0 = DecodeCharBase64(in[i]);
+            uint8_t b1 = DecodeCharBase64(in[i + 1]);
+            uint8_t b2 = DecodeCharBase64(in[i + 2]);
+            uint8_t b3 = DecodeCharBase64(in[i + 3]);
+
+            out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
+            if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
+            if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3);
+        }
+
+        return outLength;
+    }
+
+
+
+    inline void EncodeBase64(
+        const uint8_t* in, size_t inLength,
+        std::string& out)
+    {
+        size_t outLength = ((inLength + 2) / 3) * 4;
+
+        size_t j = out.size();
+        out.resize(j + outLength);
+
+        for (size_t i = 0; i <  inLength; i += 3) {
+            uint8_t b = (in[i] & 0xFC) >> 2;
+            out[j++] = EncodeCharBase64(b);
+
+            b = (in[i] & 0x03) << 4;
+            if (i + 1 < inLength) {
+                b |= (in[i + 1] & 0xF0) >> 4;
+                out[j++] = EncodeCharBase64(b);
+
+                b = (in[i + 1] & 0x0F) << 2;
+                if (i + 2 < inLength) {
+                    b |= (in[i + 2] & 0xC0) >> 6;
+                    out[j++] = EncodeCharBase64(b);
+
+                    b = in[i + 2] & 0x3F;
+                    out[j++] = EncodeCharBase64(b);
+                }
+                else {
+                    out[j++] = EncodeCharBase64(b);
+                    out[j++] = '=';
+                }
+            }
+            else {
+                out[j++] = EncodeCharBase64(b);
+                out[j++] = '=';
+                out[j++] = '=';
+            }
+        }
+    }
+
+}
+
+}
+
+

+ 89 - 0
code/glTFAssetWriter.h

@@ -0,0 +1,89 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file glTFWriter.h
+ * Declares a class to write gltf/glb files
+ *
+ * glTF Extensions Support:
+ *   KHR_binary_glTF: full
+ *   KHR_materials_common: full
+ */
+#ifndef glTFAssetWriter_H_INC
+#define glTFAssetWriter_H_INC
+
+#include "glTFAsset.h"
+
+namespace glTF
+{
+
+using rapidjson::MemoryPoolAllocator;
+
+class AssetWriter
+{
+    template<class T>
+    friend struct LazyDictWriter;
+
+private:
+
+    void WriteBinaryData(IOStream* outfile, size_t sceneLength);
+
+    void WriteMetadata();
+    void WriteExtensionsUsed();
+
+    template<class T>
+    void WriteObjects(LazyDict<T>& d);
+
+public:
+    Document mDoc;
+    Asset& mAsset;
+
+    MemoryPoolAllocator<>& mAl;
+
+    AssetWriter(Asset& asset);
+
+    void WriteFile(const char* path);
+};
+
+}
+
+// Include the implementation of the methods
+#include "glTFAssetWriter.inl"
+
+#endif

+ 497 - 0
code/glTFAssetWriter.inl

@@ -0,0 +1,497 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#include <rapidjson/stringbuffer.h>
+#include <rapidjson/writer.h>
+#include <rapidjson/prettywriter.h>
+
+namespace glTF {
+
+    using rapidjson::StringBuffer;
+    using rapidjson::PrettyWriter;
+    using rapidjson::Writer;
+    using rapidjson::StringRef;
+    using rapidjson::StringRef;
+
+    namespace {
+
+        template<size_t N>
+        inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
+            val.SetArray();
+            val.Reserve(N, al);
+            for (int i = 0; i < N; ++i) {
+                val.PushBack(r[i], al);
+            }
+            return val;
+        };
+
+        template<class T>
+        inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
+            if (v.empty()) return;
+            Value lst;
+            lst.SetArray();
+            lst.Reserve(v.size(), al);
+            for (size_t i = 0; i < v.size(); ++i) {
+                lst.PushBack(StringRef(v[i]->id), al);
+            }
+            obj.AddMember(StringRef(fieldId), lst, al);
+        };
+
+
+    }
+
+    inline void Write(Value& obj, Accessor& a, AssetWriter& w)
+    {
+        obj.AddMember("bufferView", Value(a.bufferView->id, w.mAl).Move(), w.mAl);
+        obj.AddMember("byteOffset", a.byteOffset, w.mAl);
+        obj.AddMember("byteStride", a.byteStride, w.mAl);
+        obj.AddMember("componentType", int(a.componentType), w.mAl);
+        obj.AddMember("count", a.count, w.mAl);
+        obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
+    }
+
+    inline void Write(Value& obj, Animation& a, AssetWriter& w)
+    {
+
+    }
+
+    inline void Write(Value& obj, Buffer& b, AssetWriter& w)
+    {
+        std::string dataURI = "data:application/octet-stream;base64,";
+        Util::EncodeBase64(b.GetPointer(), b.byteLength, dataURI);
+
+        const char* type;
+        switch (b.type) {
+            case Buffer::Type_text:
+                type = "text"; break;
+            default:
+                type = "arraybuffer";
+        }
+
+        obj.AddMember("byteLength", b.byteLength, w.mAl);
+        obj.AddMember("type", StringRef(type), w.mAl);
+        obj.AddMember("uri", Value(dataURI, w.mAl).Move(), w.mAl);
+    }
+
+    inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
+    {
+        obj.AddMember("buffer", Value(bv.buffer->id, w.mAl).Move(), w.mAl);
+        obj.AddMember("byteOffset", bv.byteOffset, w.mAl);
+        obj.AddMember("byteLength", bv.byteLength, w.mAl);
+        obj.AddMember("target", int(bv.target), w.mAl);
+    }
+
+    inline void Write(Value& obj, Camera& c, AssetWriter& w)
+    {
+
+    }
+
+    inline void Write(Value& obj, Image& img, AssetWriter& w)
+    {
+        std::string uri;
+        if (w.mAsset.extensionsUsed.KHR_binary_glTF && img.bufferView) {
+            Value exts, ext;
+            exts.SetObject();
+            ext.SetObject();
+
+            ext.AddMember("bufferView", StringRef(img.bufferView->id), w.mAl);
+
+            if (!img.mimeType.empty())
+                ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl);
+
+            exts.AddMember("KHR_binary_glTF", ext, w.mAl);
+            obj.AddMember("extensions", exts, w.mAl);
+            return;
+        }
+        else if (img.HasData()) {
+            uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType);
+            uri += ";base64,";
+            Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri);
+        }
+        else {
+            uri = img.uri;
+        }
+
+        obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl);
+    }
+
+    namespace {
+        inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al)
+        {
+            if (prop.texture)
+                obj.AddMember(StringRef(propName), Value(prop.texture->id, al).Move(), al);
+            else {
+                Value col;
+                obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al);
+            }
+        }
+    }
+
+    inline void Write(Value& obj, Material& m, AssetWriter& w)
+    {
+        Value v;
+        v.SetObject();
+        {
+            WriteColorOrTex(v, m.ambient, "ambient", w.mAl);
+            WriteColorOrTex(v, m.diffuse, "diffuse", w.mAl);
+            WriteColorOrTex(v, m.specular, "specular", w.mAl);
+            WriteColorOrTex(v, m.emission, "emission", w.mAl);
+
+            v.AddMember("shininess", m.shininess, w.mAl);
+        }
+        obj.AddMember("values", v, w.mAl);
+    }
+
+    namespace {
+        inline void WriteAttrs(AssetWriter& w, Value& attrs, Mesh::AccessorList& lst,
+            const char* semantic, bool forceNumber = false)
+        {
+            if (lst.empty()) return;
+            if (lst.size() == 1 && !forceNumber) {
+                attrs.AddMember(StringRef(semantic), Value(lst[0]->id, w.mAl).Move(), w.mAl);
+            }
+            else {
+                for (size_t i = 0; i < lst.size(); ++i) {
+                    char buffer[32];
+                    sprintf(buffer, "%s_%d", semantic, int(i));
+                    attrs.AddMember(Value(buffer, w.mAl).Move(), Value(lst[i]->id, w.mAl).Move(), w.mAl);
+                }
+            }
+        }
+    }
+
+    inline void Write(Value& obj, Mesh& m, AssetWriter& w)
+    {
+        Value primitives;
+        primitives.SetArray();
+        primitives.Reserve(m.primitives.size(), w.mAl);
+
+        for (size_t i = 0; i < m.primitives.size(); ++i) {
+            Mesh::Primitive& p = m.primitives[i];
+            Value prim;
+            prim.SetObject();
+            {
+                prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl);
+
+                if (p.material)
+                    prim.AddMember("material", p.material->id, w.mAl);
+
+                if (p.indices)
+                    prim.AddMember("indices", Value(p.indices->id, w.mAl).Move(), w.mAl);
+
+                Value attrs;
+                attrs.SetObject();
+                {
+                    WriteAttrs(w, attrs, p.attributes.position, "POSITION");
+                    WriteAttrs(w, attrs, p.attributes.normal, "NORMAL");
+                    WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true);
+                    WriteAttrs(w, attrs, p.attributes.color, "COLOR");
+                    WriteAttrs(w, attrs, p.attributes.joint, "JOINT");
+                    WriteAttrs(w, attrs, p.attributes.jointmatrix, "JOINTMATRIX");
+                    WriteAttrs(w, attrs, p.attributes.weight, "WEIGHT");
+                }
+                prim.AddMember("attributes", attrs, w.mAl);
+            }
+            primitives.PushBack(prim, w.mAl);
+        }
+    
+        obj.AddMember("primitives", primitives, w.mAl);
+    }
+
+    inline void Write(Value& obj, Node& n, AssetWriter& w)
+    {
+
+        if (n.matrix.isPresent) {
+            Value val;
+            obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl);
+        }
+
+        if (n.translation.isPresent) {
+            Value val;
+            obj.AddMember("translation", MakeValue(val, n.translation.value, w.mAl).Move(), w.mAl);
+        }
+
+        if (n.scale.isPresent) {
+            Value val;
+            obj.AddMember("scale", MakeValue(val, n.scale.value, w.mAl).Move(), w.mAl);
+        }
+        if (n.rotation.isPresent) {
+            Value val;
+            obj.AddMember("rotation", MakeValue(val, n.rotation.value, w.mAl).Move(), w.mAl);
+        }
+
+        AddRefsVector(obj, "children", n.children, w.mAl);
+
+        AddRefsVector(obj, "meshes", n.meshes, w.mAl);
+    }
+
+    inline void Write(Value& obj, Program& b, AssetWriter& w)
+    {
+
+    }
+
+    inline void Write(Value& obj, Sampler& b, AssetWriter& w)
+    {
+
+    }
+
+    inline void Write(Value& scene, Scene& s, AssetWriter& w)
+    {
+        AddRefsVector(scene, "nodes", s.nodes, w.mAl);
+    }
+
+    inline void Write(Value& obj, Shader& b, AssetWriter& w)
+    {
+
+    }
+
+    inline void Write(Value& obj, Skin& b, AssetWriter& w)
+    {
+
+    }
+
+    inline void Write(Value& obj, Technique& b, AssetWriter& w)
+    {
+
+    }
+
+    inline void Write(Value& obj, Texture& tex, AssetWriter& w)
+    {
+        if (tex.source) {
+            obj.AddMember("source", Value(tex.source->id, w.mAl).Move(), w.mAl);
+        }
+    }
+
+    inline void Write(Value& obj, Light& b, AssetWriter& w)
+    {
+
+    }
+
+
+    AssetWriter::AssetWriter(Asset& a)
+        : mDoc()
+        , mAsset(a)
+        , mAl(mDoc.GetAllocator())
+    {
+        mDoc.SetObject();
+
+        WriteMetadata();
+        WriteExtensionsUsed();
+
+        // Dump the contents of the dictionaries
+        for (size_t i = 0; i < a.mDicts.size(); ++i) {
+            a.mDicts[i]->WriteObjects(*this);
+        }
+
+        // Add the target scene field
+        if (mAsset.scene) {
+            mDoc.AddMember("scene", StringRef(mAsset.scene->id), mAl);
+        }
+    }
+
+    void AssetWriter::WriteFile(const char* path)
+    {
+        bool isBinary = mAsset.extensionsUsed.KHR_binary_glTF;
+
+        boost::scoped_ptr<IOStream> outfile
+            (mAsset.OpenFile(path, isBinary ? "wb" : "wt", true));
+
+        if (outfile == 0) {
+            throw DeadlyExportError("Could not open output file: " + std::string(path));
+        }
+
+        if (isBinary) {
+            // we will write the header later, skip its size
+            outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
+        }
+
+        StringBuffer docBuffer;
+
+        bool pretty = true; 
+        if (!isBinary && pretty) {
+            PrettyWriter<StringBuffer> writer(docBuffer);
+            mDoc.Accept(writer);
+        }
+        else {
+            Writer<StringBuffer> writer(docBuffer);
+            mDoc.Accept(writer);
+        }
+
+        if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
+            throw DeadlyExportError("Failed to write scene data!"); 
+        }
+
+        if (isBinary) {
+            WriteBinaryData(outfile.get(), docBuffer.GetSize());
+        }
+    }
+
+    void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength)
+    {
+        //
+        // write the body data
+        //
+
+        size_t bodyLength = 0;
+        if (Ref<Buffer> b = mAsset.GetBodyBuffer()) {
+            bodyLength = b->byteLength;
+
+            if (bodyLength > 0) {
+                size_t bodyOffset = sizeof(GLB_Header) + sceneLength;
+                bodyOffset = (bodyOffset + 3) & ~3; // Round up to next multiple of 4
+
+                outfile->Seek(bodyOffset, aiOrigin_SET);
+
+                if (outfile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
+                    throw DeadlyExportError("Failed to write body data!");
+                }
+            }
+        }
+
+
+        //
+        // write the header
+        //
+
+        GLB_Header header;
+        memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic));
+
+        header.version = 1;
+        AI_SWAP4(header.version);
+
+        header.length = sizeof(header) + sceneLength + bodyLength;
+        AI_SWAP4(header.length);
+
+        header.sceneLength = sceneLength;
+        AI_SWAP4(header.sceneLength);
+
+        header.sceneFormat = SceneFormat_JSON;
+        AI_SWAP4(header.sceneFormat);
+
+        outfile->Seek(0, aiOrigin_SET);
+
+        if (outfile->Write(&header, 1, sizeof(header)) != sizeof(header)) {
+            throw DeadlyExportError("Failed to write the header!");
+        }
+    }
+
+    
+    void AssetWriter::WriteMetadata()
+    {
+        Value asset;
+        asset.SetObject();
+        {
+            asset.AddMember("version", mAsset.asset.version, mAl);
+
+            asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
+        }
+        mDoc.AddMember("asset", asset, mAl);
+    }
+
+    void AssetWriter::WriteExtensionsUsed()
+    {
+        Value exts;
+        exts.SetArray();
+        {
+            if (false)
+                exts.PushBack(StringRef("KHR_binary_glTF"), mAl);
+
+            if (false)
+                exts.PushBack(StringRef("KHR_materials_common"), mAl);
+        }
+
+        if (!exts.Empty())
+            mDoc.AddMember("extensionsUsed", exts, mAl);
+    }
+
+    template<class T>
+    void AssetWriter::WriteObjects(LazyDict<T>& d)
+    {
+        if (d.mObjs.empty()) return;
+
+        Value* container = &mDoc;
+
+        if (d.mExtId) {
+            Value* exts = FindObject(mDoc, "extensions");
+            if (!exts) {
+                mDoc.AddMember("extensions", Value().SetObject().Move(), mDoc.GetAllocator());
+                exts = FindObject(mDoc, "extensions");
+            }
+
+            if (!(container = FindObject(*exts, d.mExtId))) {
+                exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator());
+                container = FindObject(*exts, d.mExtId);
+            }
+        }
+
+        Value* dict;
+        if (!(dict = FindObject(*container, d.mDictId))) {
+            container->AddMember(StringRef(d.mDictId), Value().SetObject().Move(), mDoc.GetAllocator());
+            dict = FindObject(*container, d.mDictId);
+        }
+
+        for (size_t i = 0; i < d.mObjs.size(); ++i) {
+            if (d.mObjs[i]->IsSpecial()) continue;
+
+            Value obj;
+            obj.SetObject();
+
+            if (!d.mObjs[i]->name.empty()) {
+                obj.AddMember("name", StringRef(d.mObjs[i]->name.c_str()), mAl);
+            }
+
+            Write(obj, *d.mObjs[i], *this);
+
+            dict->AddMember(StringRef(d.mObjs[i]->id), obj, mAl);
+        }
+    }
+
+    template<class T>
+    struct LazyDictWriter< LazyDict<T> >
+    {
+        static void Write(LazyDict<T>& d, AssetWriter& w)
+        {
+            w.WriteObjects(d);
+        }
+    };
+
+}
+
+

+ 367 - 0
code/glTFExporter.cpp

@@ -0,0 +1,367 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
+
+#include "glTFExporter.h"
+#include "Exceptional.h"
+#include "StringComparison.h"
+#include "ByteSwapper.h"
+
+#include <assimp/version.h>
+#include <assimp/IOSystem.hpp>
+#include <assimp/Exporter.hpp>
+#include <assimp/material.h>
+#include <assimp/scene.h>
+
+#include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "glTFAssetWriter.h"
+
+using namespace rapidjson;
+
+using namespace Assimp;
+using namespace glTF;
+
+namespace Assimp {
+
+    // ------------------------------------------------------------------------------------------------
+    // Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp
+    void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
+    {
+        // invoke the exporter
+        glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false);
+    }
+
+    // ------------------------------------------------------------------------------------------------
+    // Worker function for exporting a scene to GLB. Prototyped and registered in Exporter.cpp
+    void ExportSceneGLB(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
+    {
+        // invoke the exporter
+        glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, true);
+    }
+
+} // end of namespace Assimp
+
+
+
+glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene,
+                           const ExportProperties* pProperties, bool isBinary)
+    : mFilename(filename)
+    , mIOSystem(pIOSystem)
+    , mScene(pScene)
+    , mProperties(pProperties)
+{
+    boost::scoped_ptr<Asset> asset(new glTF::Asset(pIOSystem));
+    mAsset = asset.get();
+
+    if (isBinary) {
+        asset->SetAsBinary();
+    }
+
+    ExportMetadata();
+
+    //for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {}
+
+    //for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {}
+
+    //for (unsigned int i = 0; i < pScene->mNumLights; ++i) {}
+
+
+    ExportMaterials();
+
+    ExportMeshes();
+
+    //for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {}
+
+
+    if (mScene->mRootNode) {
+        ExportNode(mScene->mRootNode);
+    }
+
+    ExportScene();
+
+
+    glTF::AssetWriter writer(*mAsset);
+    writer.WriteFile(filename);
+}
+
+
+static void CopyValue(const aiMatrix4x4& v, glTF::mat4& o)
+{ 
+    o[ 0] = v.a1; o[ 1] = v.b1; o[ 2] = v.c1; o[ 3] = v.d1;
+    o[ 4] = v.a2; o[ 5] = v.b2; o[ 6] = v.c2; o[ 7] = v.d2;
+    o[ 8] = v.a3; o[ 9] = v.b3; o[10] = v.c3; o[11] = v.d3;
+    o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4;
+}
+
+inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& buffer,
+    unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false)
+{
+    if (!count || !data) return Ref<Accessor>();
+
+    unsigned int numCompsIn = AttribType::GetNumComponents(typeIn);
+    unsigned int numCompsOut = AttribType::GetNumComponents(typeOut);
+    unsigned int bytesPerComp = ComponentTypeSize(compType);
+
+    size_t offset = buffer->byteLength;
+    size_t length = count * numCompsOut * bytesPerComp;
+    buffer->Grow(length);
+
+    // bufferView
+    Ref<BufferView> bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view"));
+    bv->buffer = buffer;
+    bv->byteOffset = 0;
+    bv->byteLength = length; //! The target that the WebGL buffer should be bound to.
+    bv->target = isIndices ? BufferViewTarget_ELEMENT_ARRAY_BUFFER : BufferViewTarget_ARRAY_BUFFER;
+
+    // accessor
+    Ref<Accessor> acc = a.accessors.Create(a.FindUniqueID(meshName, "accessor"));
+    acc->bufferView = bv;
+    acc->byteOffset = offset;
+    acc->byteStride = 0;
+    acc->componentType = compType;
+    acc->count = count;
+    acc->type = typeOut;
+
+    // copy the data
+    acc->WriteData(count, data, numCompsIn*bytesPerComp);
+
+    return acc;
+}
+
+namespace {
+    void GetMatScalar(const aiMaterial* mat, float& val, const char* propName, int type, int idx) {
+        if (mat->Get(propName, type, idx, val) == AI_SUCCESS) {}
+    }
+}
+
+void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt)
+{
+    aiString tex;
+    aiColor4D col;
+    if (mat->GetTextureCount(tt) > 0) {
+        if (mat->Get(AI_MATKEY_TEXTURE(tt, 0), tex) == AI_SUCCESS) {
+            std::string path = tex.C_Str();
+
+            if (path.size() > 0) {
+                if (path[0] != '*') {
+                    std::map<std::string, size_t>::iterator it = mTexturesByPath.find(path);
+                    if (it != mTexturesByPath.end()) {
+                        prop.texture = mAsset->textures.Get(it->second);
+                    }
+                }
+
+                if (!prop.texture) {
+                    std::string texId = mAsset->FindUniqueID("", "texture");
+                    prop.texture = mAsset->textures.Create(texId);
+                    mTexturesByPath[path] = prop.texture.GetIndex();
+
+                    std::string imgId = mAsset->FindUniqueID("", "image");
+                    prop.texture->source = mAsset->images.Create(imgId);
+
+                    if (path[0] == '*') { // embedded
+                        aiTexture* tex = mScene->mTextures[atoi(&path[1])];
+
+                        uint8_t* data = reinterpret_cast<uint8_t*>(tex->pcData);
+                        prop.texture->source->SetData(data, tex->mWidth, *mAsset);
+
+                        if (tex->achFormatHint[0]) {
+                            std::string mimeType = "image/";
+                            mimeType += (memcmp(tex->achFormatHint, "jpg", 3) == 0) ? "jpeg" : tex->achFormatHint;
+                            prop.texture->source->mimeType = mimeType;
+                        }
+                    }
+                    else {
+                        prop.texture->source->uri = path;
+                    }
+                }
+            }
+        }
+    }
+
+    if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
+        prop.color[0] = col.r; prop.color[1] = col.g; prop.color[2] = col.b; prop.color[3] = col.a;
+    }
+}
+
+void glTFExporter::ExportMaterials()
+{
+    aiString aiName;
+    for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
+        const aiMaterial* mat = mScene->mMaterials[i];
+
+        
+        std::string name;
+        if (mat->Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) {
+            name = aiName.C_Str();
+        }
+        name = mAsset->FindUniqueID(name, "material");
+
+        Ref<Material> m = mAsset->materials.Create(name);
+
+        GetMatColorOrTex(mat, m->ambient, AI_MATKEY_COLOR_AMBIENT, aiTextureType_AMBIENT);
+        GetMatColorOrTex(mat, m->diffuse, AI_MATKEY_COLOR_DIFFUSE, aiTextureType_DIFFUSE);
+        GetMatColorOrTex(mat, m->specular, AI_MATKEY_COLOR_SPECULAR, aiTextureType_SPECULAR);
+        GetMatColorOrTex(mat, m->emission, AI_MATKEY_COLOR_EMISSIVE, aiTextureType_EMISSIVE);
+
+        GetMatScalar(mat, m->shininess, AI_MATKEY_SHININESS);
+    }
+}
+
+void glTFExporter::ExportMeshes()
+{
+    for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
+        const aiMesh* aim = mScene->mMeshes[i];
+
+        std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh");
+        Ref<Mesh> m = mAsset->meshes.Create(meshId);
+        m->primitives.resize(1);
+        Mesh::Primitive& p = m->primitives.back();
+
+        p.material = mAsset->materials.Get(aim->mMaterialIndex);
+
+        std::string bufferId = mAsset->FindUniqueID(meshId, "buffer");
+
+        Ref<Buffer> b = mAsset->GetBodyBuffer();
+        if (!b) {
+            b = mAsset->buffers.Create(bufferId);
+        }
+
+        Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
+        if (v) p.attributes.position.push_back(v);
+
+        Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
+        if (n) p.attributes.normal.push_back(n);
+
+        for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+            if (aim->mNumUVComponents[i] > 0) {
+                AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
+                Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true);
+                if (tc) p.attributes.texcoord.push_back(tc);
+            }
+        }
+
+        if (aim->mNumFaces > 0) {
+            unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices;
+            std::vector<uint16_t> indices;
+            indices.resize(aim->mNumFaces * nIndicesPerFace);
+            for (size_t i = 0; i < aim->mNumFaces; ++i) {
+                for (size_t j = 0; j < nIndicesPerFace; ++j) {
+                    indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]);
+                }
+            }
+            p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT);
+        }
+
+        switch (aim->mPrimitiveTypes) {
+            case aiPrimitiveType_POLYGON:
+                p.mode = PrimitiveMode_TRIANGLES; break; // TODO implement this
+            case aiPrimitiveType_LINE:
+                p.mode = PrimitiveMode_LINES; break;
+            case aiPrimitiveType_POINT:
+                p.mode = PrimitiveMode_POINTS; break;
+            default: // aiPrimitiveType_TRIANGLE
+                p.mode = PrimitiveMode_TRIANGLES;
+        }
+    }
+}
+
+size_t glTFExporter::ExportNode(const aiNode* n)
+{
+    Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node"));
+
+    if (!n->mTransformation.IsIdentity()) {
+        node->matrix.isPresent = true;
+        CopyValue(n->mTransformation, node->matrix.value);
+    }
+
+    for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
+        node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
+    }
+
+    for (unsigned int i = 0; i < n->mNumChildren; ++i) {
+        size_t idx = ExportNode(n->mChildren[i]);
+        node->children.push_back(mAsset->nodes.Get(idx));
+    }
+
+    return node.GetIndex();
+}
+
+
+void glTFExporter::ExportScene()
+{
+    const char* sceneName = "defaultScene";
+    Ref<Scene> scene = mAsset->scenes.Create(sceneName);
+
+    // root node will be the first one exported (idx 0)
+    if (mAsset->nodes.Size() > 0) {
+        scene->nodes.push_back(mAsset->nodes.Get(size_t(0)));
+    }
+
+    // set as the default scene
+    mAsset->scene = scene;
+}
+
+void glTFExporter::ExportMetadata()
+{
+    glTF::AssetMetadata& asset = mAsset->asset;
+    asset.version = 1;
+
+    char buffer[256];
+    sprintf(buffer, "Open Asset Import Library (assimp v%d.%d.%d)",
+        aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision());
+
+    asset.generator = buffer;
+}
+
+
+
+
+
+
+
+#endif // ASSIMP_BUILD_NO_GLTF_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 108 - 0
code/glTFExporter.h

@@ -0,0 +1,108 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file GltfExporter.h
+* Declares the exporter class to write a scene to a gltf/glb file
+*/
+#ifndef AI_GLTFEXPORTER_H_INC
+#define AI_GLTFEXPORTER_H_INC
+
+#include <assimp/types.h>
+#include <assimp/material.h>
+#include <sstream>
+#include <vector>
+#include <map>
+
+#include "boost/scoped_ptr.hpp"
+
+
+struct aiScene;
+struct aiNode;
+struct aiMaterial;
+
+namespace glTF
+{
+    class Asset;
+
+    struct TexProperty;
+}
+
+namespace Assimp
+{
+    class IOSystem;
+    class IOStream;
+    class ExportProperties;
+
+    // ------------------------------------------------------------------------------------------------
+    /** Helper class to export a given scene to an glTF file. */
+    // ------------------------------------------------------------------------------------------------
+    class glTFExporter
+    {
+    public:
+        /// Constructor for a specific scene to export
+        glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene,
+            const ExportProperties* pProperties, bool binary);
+
+    private:
+
+        const char* mFilename;
+        IOSystem* mIOSystem;
+        const aiScene* mScene;
+        const ExportProperties* mProperties;
+
+        std::map<std::string, size_t> mTexturesByPath;
+
+        glTF::Asset* mAsset;
+
+        std::vector<unsigned char> mBodyData;
+
+        void WriteBinaryData(IOStream* outfile, std::size_t sceneLength);
+
+        void GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt);
+        void ExportMetadata();
+        void ExportMaterials();
+        void ExportMeshes();
+        size_t ExportNode(const aiNode* node);
+        void ExportScene();
+    };
+
+}
+
+#endif

+ 629 - 0
code/glTFImporter.cpp

@@ -0,0 +1,629 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
+
+#include "glTFImporter.h"
+
+#include "StringComparison.h"
+
+#include "boost/scoped_ptr.hpp"
+
+#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
+#include <assimp/ai_assert.h>
+#include <assimp/DefaultLogger.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "glTFAsset.h"
+
+using namespace Assimp;
+using namespace glTF;
+
+
+//
+// glTFImporter
+//
+
+static const aiImporterDesc desc = {
+    "glTF Importer",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour
+        | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
+    0,
+    0,
+    0,
+    0,
+    "gltf glb"
+};
+
+glTFImporter::glTFImporter() 
+: BaseImporter()
+{
+
+}
+
+glTFImporter::~glTFImporter()
+{
+
+}
+
+const aiImporterDesc* glTFImporter::GetInfo() const
+{
+    return &desc;
+}
+
+bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+{
+    const std::string& extension = GetExtension(pFile);
+
+    if (extension == "gltf" || extension == "glb")
+        return true;
+
+    if ((checkSig || !extension.length()) && pIOHandler) {
+        char buffer[4];
+
+        boost::scoped_ptr<IOStream> pStream(pIOHandler->Open(pFile));
+        if (pStream && pStream->Read(buffer, sizeof(buffer), 1) == 1) {
+            if (memcmp(buffer, AI_GLB_MAGIC_NUMBER, sizeof(buffer)) == 0) {
+                return true; // Has GLB header
+            }
+            else if (memcmp(buffer, "{\r\n ", sizeof(buffer)) == 0
+                    || memcmp(buffer, "{\n  ", sizeof(buffer)) == 0) {
+                // seems a JSON file, and we're the only format that can read them
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+
+
+//static void CopyValue(const glTF::vec3& v, aiColor3D& out)
+//{
+//    out.r = v[0]; out.g = v[1]; out.b = v[2];
+//}
+
+static void CopyValue(const glTF::vec4& v, aiColor4D& out)
+{
+    out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3];
+}
+
+static void CopyValue(const glTF::vec4& v, aiColor3D& out)
+{
+    out.r = v[0]; out.g = v[1]; out.b = v[2];
+}
+
+static void CopyValue(const glTF::vec3& v, aiVector3D& out)
+{
+    out.x = v[0]; out.y = v[1]; out.z = v[2];
+}
+
+static void CopyValue(const glTF::vec4& v, aiQuaternion& out)
+{
+    out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3];
+}
+
+static void CopyValue(const glTF::mat4& v, aiMatrix4x4& o)
+{
+    o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3];
+    o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7];
+    o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11];
+    o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15];
+}
+
+inline void SetMaterialColorProperty(std::vector<int>& embeddedTexIdxs, Asset& r, glTF::TexProperty prop, aiMaterial* mat,
+    aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx)
+{
+    if (prop.texture) {
+        if (prop.texture->source) {
+            aiString uri(prop.texture->source->uri);
+
+            int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()];
+            if (texIdx != -1) { // embedded
+                // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
+                uri.data[0] = '*';
+                uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
+            }
+
+            mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0);
+        }
+    }
+    else {
+        aiColor4D col;
+        CopyValue(prop.color, col);
+        if (col.r != 1.f || col.g != 1.f || col.b != 1.f || col.a != 1.f) {
+            mat->AddProperty(&col, 1, pKey, type, idx);
+        }
+    }
+}
+
+void glTFImporter::ImportMaterials(glTF::Asset& r)
+{
+    mScene->mNumMaterials = r.materials.Size();
+    mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials];
+
+    for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
+        aiMaterial* aimat = mScene->mMaterials[i] = new aiMaterial();
+
+        Material& mat = r.materials[i];
+
+        /*if (!mat.name.empty())*/ {
+            aiString str(mat.id /*mat.name*/);
+            aimat->AddProperty(&str, AI_MATKEY_NAME);
+        }
+
+        SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
+        SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
+        SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
+
+        if (mat.shininess > 0.f) {
+            aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);
+        }
+    }
+
+    if (mScene->mNumMaterials == 0) {
+        mScene->mNumMaterials = 1;
+        mScene->mMaterials = new aiMaterial*[1];
+        mScene->mMaterials[0] = new aiMaterial();
+    }
+}
+
+
+inline void SetFace(aiFace& face, int a)
+{
+    face.mNumIndices = 1;
+    face.mIndices = new unsigned int[1];
+    face.mIndices[0] = a;
+}
+
+inline void SetFace(aiFace& face, int a, int b)
+{
+    face.mNumIndices = 2;
+    face.mIndices = new unsigned int[2];
+    face.mIndices[0] = a;
+    face.mIndices[1] = b;
+}
+
+inline void SetFace(aiFace& face, int a, int b, int c)
+{
+    face.mNumIndices = 3;
+    face.mIndices = new unsigned int[3];
+    face.mIndices[0] = a;
+    face.mIndices[1] = b;
+    face.mIndices[2] = c;
+}
+
+void glTFImporter::ImportMeshes(glTF::Asset& r)
+{
+    std::vector<aiMesh*> meshes;
+
+    unsigned int k = 0;
+
+    for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
+        Mesh& mesh = r.meshes[m];
+
+        meshOffsets.push_back(k);
+        k += mesh.primitives.size();
+
+        for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
+            Mesh::Primitive& prim = mesh.primitives[p];
+
+            aiMesh* aim = new aiMesh();
+            meshes.push_back(aim);
+
+            aim->mName = mesh.id;
+            if (mesh.primitives.size() > 1) {
+                size_t& len = aim->mName.length;
+                aim->mName.data[len] = '-';
+                len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, MAXLEN - len - 1, p);
+            }
+
+            switch (prim.mode) {
+                case PrimitiveMode_POINTS:
+                    aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
+                    break;
+
+                case PrimitiveMode_LINES:
+                case PrimitiveMode_LINE_LOOP:
+                case PrimitiveMode_LINE_STRIP:
+                    aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
+                    break;
+
+                case PrimitiveMode_TRIANGLES:
+                case PrimitiveMode_TRIANGLE_STRIP:
+                case PrimitiveMode_TRIANGLE_FAN:
+                    aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
+                    break;
+            }
+
+            Mesh::Primitive::Attributes& attr = prim.attributes;
+            if (attr.position.size() > 0 && attr.position[0]) {
+                aim->mNumVertices = attr.position[0]->count;
+                attr.position[0]->ExtractData(aim->mVertices);
+            }
+
+            if (attr.normal.size() > 0 && attr.normal[0]) {
+                attr.normal[0]->ExtractData(aim->mNormals);
+            }
+
+            for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
+                attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
+                aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
+            }
+
+
+            if (prim.indices) {
+                aiFace* faces = 0;
+                size_t nFaces = 0;
+
+                unsigned int count = prim.indices->count;
+
+                Accessor::Indexer data = prim.indices->GetIndexer();
+
+                switch (prim.mode) {
+                    case PrimitiveMode_POINTS: {
+                        nFaces = count;
+                        faces = new aiFace[nFaces];
+                        for (unsigned int i = 0; i < count; ++i) {
+                            SetFace(faces[i], data.GetUInt(i));
+                        }
+                        break;
+                    }
+
+                    case PrimitiveMode_LINES: {
+                        nFaces = count / 2;
+                        faces = new aiFace[nFaces];
+                        for (unsigned int i = 0; i < count; i += 2) {
+                            SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
+                        }
+                        break;
+                    }
+
+                    case PrimitiveMode_LINE_LOOP:
+                    case PrimitiveMode_LINE_STRIP: {
+                        nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
+                        faces = new aiFace[nFaces];
+                        SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
+                        for (unsigned int i = 2; i < count; ++i) {
+                            SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
+                        }
+                        if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
+                            SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
+                        }
+                        break;
+                    }
+
+                    case PrimitiveMode_TRIANGLES: {
+                        nFaces = count / 3;
+                        faces = new aiFace[nFaces];
+                        for (unsigned int i = 0; i < count; i += 3) {
+                            SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
+                        }
+                        break;
+                    }
+                    case PrimitiveMode_TRIANGLE_STRIP: {
+                        nFaces = count - 2;
+                        faces = new aiFace[nFaces];
+                        SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
+                        for (unsigned int i = 3; i < count; ++i) {
+                            SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i));
+                        }
+                        break;
+                    }
+                    case PrimitiveMode_TRIANGLE_FAN:
+                        nFaces = count - 2;
+                        faces = new aiFace[nFaces];
+                        SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
+                        for (unsigned int i = 3; i < count; ++i) {
+                            SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i));
+                        }
+                        break;
+                }
+
+                if (faces) {
+                    aim->mFaces = faces;
+                    aim->mNumFaces = nFaces;
+                }
+            }
+
+
+            if (prim.material) {
+                aim->mMaterialIndex = prim.material.GetIndex();
+            }
+        }
+    }
+
+    meshOffsets.push_back(k);
+    
+    CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
+}
+
+void glTFImporter::ImportCameras(glTF::Asset& r)
+{
+    if (!r.cameras.Size()) return;
+
+    mScene->mNumCameras = r.cameras.Size();
+    mScene->mCameras = new aiCamera*[r.cameras.Size()];
+
+    for (size_t i = 0; i < r.cameras.Size(); ++i) {
+        Camera& cam = r.cameras[i];
+
+        aiCamera* aicam = mScene->mCameras[i] = new aiCamera();
+
+        if (cam.type == Camera::Perspective) {
+            
+            aicam->mAspect        = cam.perspective.aspectRatio;
+            aicam->mHorizontalFOV = cam.perspective.yfov * aicam->mAspect;
+            aicam->mClipPlaneFar  = cam.perspective.zfar;
+            aicam->mClipPlaneNear = cam.perspective.znear;
+        }
+        else {
+            // assimp does not support orthographic cameras
+        }
+    }
+}
+
+void glTFImporter::ImportLights(glTF::Asset& r)
+{
+    if (!r.lights.Size()) return;
+
+    mScene->mNumLights = r.lights.Size();
+    mScene->mLights = new aiLight*[r.lights.Size()];
+
+    for (size_t i = 0; i < r.lights.Size(); ++i) {
+        Light& l = r.lights[i];
+
+        aiLight* ail = mScene->mLights[i] = new aiLight();
+
+        switch (l.type) {
+            case Light::Type_directional:
+                ail->mType = aiLightSource_DIRECTIONAL; break;
+
+            case Light::Type_spot:
+                ail->mType = aiLightSource_SPOT; break;
+
+            case Light::Type_ambient:
+                ail->mType = aiLightSource_AMBIENT; break;
+
+            default: // Light::Type_point
+                ail->mType = aiLightSource_POINT; break;
+        }
+
+        CopyValue(l.color, ail->mColorAmbient);
+        CopyValue(l.color, ail->mColorDiffuse);
+        CopyValue(l.color, ail->mColorSpecular);
+        
+        ail->mAngleOuterCone = l.falloffAngle;
+        ail->mAngleInnerCone = l.falloffExponent; // TODO fix this, it does not look right at all
+
+        ail->mAttenuationConstant  = l.constantAttenuation;
+        ail->mAttenuationLinear    = l.linearAttenuation;
+        ail->mAttenuationQuadratic = l.quadraticAttenuation;
+    }
+}
+
+
+aiNode* ImportNode(aiScene* pScene, glTF::Asset& r, std::vector<unsigned int>& meshOffsets, glTF::Ref<glTF::Node>& ptr)
+{
+    Node& node = *ptr;
+
+    aiNode* ainode = new aiNode(node.id);
+
+    if (!node.children.empty()) {
+        ainode->mNumChildren = node.children.size();
+        ainode->mChildren = new aiNode*[ainode->mNumChildren];
+
+        for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
+            aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]);
+            child->mParent = ainode;
+            ainode->mChildren[i] = child;
+        }
+    }
+
+    aiMatrix4x4 matrix = ainode->mTransformation;
+    if (node.matrix.isPresent) {
+        CopyValue(node.matrix.value, matrix);
+    }
+    else {
+        if (node.translation.isPresent) {
+            aiVector3D trans;
+            CopyValue(node.translation.value, trans);
+            aiMatrix4x4 t;
+            aiMatrix4x4::Translation(trans, t);
+            matrix = t * matrix;
+        }
+
+        if (node.scale.isPresent) {
+            aiVector3D scal(1.f);
+            CopyValue(node.scale.value, scal);
+            aiMatrix4x4 s;
+            aiMatrix4x4::Scaling(scal, s);
+            matrix = s * matrix;
+        }
+
+
+        if (node.rotation.isPresent) {
+            aiQuaternion rot;
+            CopyValue(node.rotation.value, rot);
+            matrix = aiMatrix4x4(rot.GetMatrix()) * matrix;
+        }
+    }
+
+    if (!node.meshes.empty()) {
+        int count = 0;
+        for (size_t i = 0; i < node.meshes.size(); ++i) {
+            int idx = node.meshes[i].GetIndex();
+            count += meshOffsets[idx + 1] - meshOffsets[idx];
+        }
+
+        ainode->mNumMeshes = count;
+        ainode->mMeshes = new unsigned int[count];
+
+        int k = 0;
+        for (size_t i = 0; i < node.meshes.size(); ++i) {
+            int idx = node.meshes[i].GetIndex();
+            for (size_t j = meshOffsets[idx]; j < meshOffsets[idx + 1]; ++j, ++k) {
+                ainode->mMeshes[k] = j;
+            }
+        }
+    }
+
+    if (node.camera) {
+        pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
+    }
+
+    if (node.light) {
+        pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
+    }
+
+    return ainode;
+}
+
+void glTFImporter::ImportNodes(glTF::Asset& r)
+{
+    if (!r.scene) return;
+
+    std::vector< Ref<Node> > rootNodes = r.scene->nodes;
+
+    // The root nodes
+    unsigned int numRootNodes = rootNodes.size();
+    if (numRootNodes == 1) { // a single root node: use it
+        mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
+    }
+    else if (numRootNodes > 1) { // more than one root node: create a fake root
+        aiNode* root = new aiNode("ROOT");
+        root->mChildren = new aiNode*[numRootNodes];
+        for (unsigned int i = 0; i < numRootNodes; ++i) {
+            aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
+            node->mParent = root;
+            root->mChildren[root->mNumChildren++] = node;
+        }
+        mScene->mRootNode = root;
+    }
+
+    //if (!mScene->mRootNode) {
+    //  mScene->mRootNode = new aiNode("EMPTY");
+    //}
+}
+
+void glTFImporter::ImportEmbeddedTextures(glTF::Asset& r)
+{
+    embeddedTexIdxs.resize(r.images.Size(), -1);
+
+    int numEmbeddedTexs = 0;
+    for (size_t i = 0; i < r.images.Size(); ++i) {
+        if (r.images[i].HasData())
+            numEmbeddedTexs += 1;
+    }
+
+    if (numEmbeddedTexs == 0)
+        return;
+
+    mScene->mTextures = new aiTexture*[numEmbeddedTexs];
+
+    // Add the embedded textures
+    for (size_t i = 0; i < r.images.Size(); ++i) {
+        Image img = r.images[i];
+        if (!img.HasData()) continue;
+
+        int idx = mScene->mNumTextures++;
+        embeddedTexIdxs[i] = idx;
+
+        aiTexture* tex = mScene->mTextures[idx] = new aiTexture();
+
+        size_t length = img.GetDataLength();
+        void* data = img.StealData();
+
+        tex->mWidth = static_cast<unsigned int>(length);
+        tex->mHeight = 0;
+        tex->pcData = reinterpret_cast<aiTexel*>(data);
+
+        if (!img.mimeType.empty()) {
+            const char* ext = strchr(img.mimeType.c_str(), '/') + 1;
+            if (ext) {
+                if (strcmp(ext, "jpeg") == 0) ext = "jpg";
+
+                size_t len = strlen(ext);
+                if (len <= 3) {
+                    strcpy(tex->achFormatHint, ext);
+                }
+            }
+        }
+    }
+}
+
+void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
+
+    this->mScene = pScene;
+    
+    // read the asset file
+    glTF::Asset asset(pIOHandler);
+    asset.Load(pFile, GetExtension(pFile) == "glb");
+
+
+    //
+    // Copy the data out
+    //
+
+    ImportEmbeddedTextures(asset);
+    ImportMaterials(asset);
+
+    ImportMeshes(asset);
+
+    ImportCameras(asset);
+    ImportLights(asset);
+
+    ImportNodes(asset);
+
+    // TODO: it does not split the loaded vertices, should it?
+    pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
+
+    if (pScene->mNumMeshes == 0) {
+        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
+    }
+}
+
+#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
+

+ 90 - 0
code/glTFImporter.h

@@ -0,0 +1,90 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2015, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef AI_GLTFIMPORTER_H_INC
+#define AI_GLTFIMPORTER_H_INC
+
+#include "BaseImporter.h"
+#include "DefaultIOSystem.h"
+
+struct aiNode;
+
+
+namespace glTF
+{
+    class Asset;
+}
+
+namespace Assimp {
+
+/**
+ * Load the glTF format.
+ * https://github.com/KhronosGroup/glTF/tree/master/specification
+ */
+class glTFImporter : public BaseImporter{
+public:
+    glTFImporter();
+    virtual ~glTFImporter();
+    virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const;
+
+protected:
+    virtual const aiImporterDesc* GetInfo() const;
+    virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler );
+
+private:
+
+    std::vector<unsigned int> meshOffsets;
+
+    std::vector<int> embeddedTexIdxs;
+
+    aiScene* mScene;
+
+    void ImportEmbeddedTextures(glTF::Asset& a);
+    void ImportMaterials(glTF::Asset& a);
+    void ImportMeshes(glTF::Asset& a);
+    void ImportCameras(glTF::Asset& a);
+    void ImportLights(glTF::Asset& a);
+    void ImportNodes(glTF::Asset& a);
+
+};
+
+} // Namespace assimp
+
+#endif // AI_GLTFIMPORTER_H_INC
+

+ 1 - 1
code/irrXMLWrapper.h

@@ -76,7 +76,7 @@ public:
 
     // ----------------------------------------------------------------------------------
     //! Construction from an existing IOStream
-    CIrrXML_IOStreamReader(IOStream* _stream)
+    explicit CIrrXML_IOStreamReader(IOStream* _stream)
         : stream (_stream)
         , t (0)
     {

+ 1 - 1
contrib/clipper/clipper.cpp

@@ -26,7 +26,7 @@
 * Paper no. DETC2005-85513 pp. 565-575                                         *
 * ASME 2005 International Design Engineering Technical Conferences             *
 * and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
-* September 2428, 2005 , Long Beach, California, USA                          *
+* September 24–28, 2005 , Long Beach, California, USA                          *
 * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
 *                                                                              *
 *******************************************************************************/

+ 1 - 1
contrib/clipper/clipper.hpp

@@ -26,7 +26,7 @@
 * Paper no. DETC2005-85513 pp. 565-575                                         *
 * ASME 2005 International Design Engineering Technical Conferences             *
 * and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
-* September 2428, 2005 , Long Beach, California, USA                          *
+* September 24–28, 2005 , Long Beach, California, USA                          *
 * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
 *                                                                              *
 *******************************************************************************/

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

@@ -49,11 +49,7 @@ static void releaseReferencedNames( Reference *ref ) {
         return;
     }
 
-    if( ref->m_referencedName ) {
-        for( size_t i = 0; i < ref->m_numRefs; i++ ) {
-            delete ref->m_referencedName;
-        }
-    }
+    delete ref;
 }
 
 DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent )
@@ -121,7 +117,6 @@ const std::string &DDLNode::getType() const {
     return m_type;
 }
 
-
 void DDLNode::setName( const std::string &name ) {
     m_name = name;
 }
@@ -143,6 +138,10 @@ bool DDLNode::hasProperty( const std::string &name ) {
     return ( ddl_nullptr != prop );
 }
 
+bool DDLNode::hasProperties() const {
+    return( ddl_nullptr != m_properties );
+}
+
 Property *DDLNode::findPropertyByName( const std::string &name ) {
     if( name.empty() ) {
         return ddl_nullptr;
@@ -151,6 +150,7 @@ Property *DDLNode::findPropertyByName( const std::string &name ) {
     if( ddl_nullptr == m_properties ) {
         return ddl_nullptr;
     }
+
     Property *current( m_properties );
     while( ddl_nullptr != current ) {
         int res = strncmp( current->m_key->m_text.m_buffer, name.c_str(), name.size() );

+ 168 - 0
contrib/openddlparser/code/OpenDDLCommon.cpp

@@ -0,0 +1,168 @@
+/*-----------------------------------------------------------------------------------------------
+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/OpenDDLCommon.h>
+#include <openddlparser/DDLNode.h>
+
+BEGIN_ODDLPARSER_NS
+
+Text::Text( const char *buffer, size_t numChars )
+: m_capacity( 0 )
+, m_len( 0 )
+, m_buffer( ddl_nullptr ) {
+    set( buffer, numChars );
+}
+
+Text::~Text() {
+    clear();
+}
+
+void Text::clear() {
+    delete[] m_buffer;
+    m_buffer = ddl_nullptr;
+    m_capacity = 0;
+    m_len = 0;
+}
+
+void Text::set( const char *buffer, size_t numChars ) {
+    clear();
+    if( numChars > 0 ) {
+        m_len = numChars;
+        m_capacity = m_len + 1;
+        m_buffer = new char[ m_capacity ];
+        strncpy( m_buffer, buffer, numChars );
+        m_buffer[ numChars ] = '\0';
+    }
+}
+
+bool Text::operator == ( const std::string &name ) const {
+    if( m_len != name.size() ) {
+        return false;
+    }
+    const int res( strncmp( m_buffer, name.c_str(), name.size() ) );
+
+    return ( 0 == res );
+}
+
+bool Text::operator == ( const Text &rhs ) const {
+    if( m_len != rhs.m_len ) {
+        return false;
+    }
+
+    const int res( strncmp( m_buffer, rhs.m_buffer, m_len ) );
+
+    return ( 0 == res );
+}
+
+Identifier::Identifier( const char buffer[], size_t len )
+: m_text( buffer, len ) {
+    // empty
+}
+
+Identifier::Identifier( const char buffer[] )
+: m_text( buffer, strlen( buffer ) ) {
+    // empty
+}
+
+Identifier::~Identifier() {
+    // empty
+}
+
+bool Identifier::operator == ( const Identifier &rhs ) const {
+    return m_text == rhs.m_text;
+}
+
+Name::Name( NameType type, Identifier *id )
+: m_type( type )
+, m_id( id ) {
+    // empty
+}
+
+Name::~Name() {
+    m_id = ddl_nullptr;
+}
+
+Reference::Reference()
+: m_numRefs( 0 )
+, m_referencedName( ddl_nullptr ) {
+    // empty
+}
+
+Reference::Reference( size_t numrefs, Name **names )
+: m_numRefs( numrefs )
+, m_referencedName( ddl_nullptr ) {
+    m_referencedName = new Name *[ numrefs ];
+    for( size_t i = 0; i < numrefs; i++ ) {
+        Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id );
+        m_referencedName[ i ] = name;
+    }
+}
+
+Reference::~Reference() {
+    for( size_t i = 0; i < m_numRefs; i++ ) {
+        delete m_referencedName[ i ];
+    }
+    m_numRefs = 0;
+    m_referencedName = ddl_nullptr;
+}
+
+Property::Property( Identifier *id )
+: m_key( id )
+, m_value( ddl_nullptr )
+, m_ref( ddl_nullptr )
+, m_next( ddl_nullptr ) {
+    // empty
+}
+
+Property::~Property() {
+    m_key = ddl_nullptr;
+    m_value = ddl_nullptr;
+    m_ref = ddl_nullptr;;
+    m_next = ddl_nullptr;;
+}
+
+DataArrayList::DataArrayList()
+: m_numItems( 0 )
+, m_dataList( ddl_nullptr )
+, m_next( ddl_nullptr ) {
+    // empty
+}
+
+DataArrayList::~DataArrayList() {
+    // empty
+}
+
+Context::Context()
+: m_root( ddl_nullptr ) {
+    // empty
+}
+
+Context::~Context() {
+    m_root = ddl_nullptr;
+}
+
+void Context::clear() {
+    delete m_root;
+    m_root = ddl_nullptr;
+}
+
+END_ODDLPARSER_NS

+ 412 - 0
contrib/openddlparser/code/OpenDDLExport.cpp

@@ -0,0 +1,412 @@
+/*-----------------------------------------------------------------------------------------------
+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/OpenDDLExport.h>
+#include <openddlparser/DDLNode.h>
+#include <openddlparser/Value.h>
+#include <openddlparser/OpenDDLParser.h>
+
+#include <sstream>
+
+BEGIN_ODDLPARSER_NS
+
+IOStreamBase::IOStreamBase()
+: m_file( ddl_nullptr ) {
+    // empty
+}
+IOStreamBase::~IOStreamBase() {
+    // empty
+}
+
+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;
+}
+
+void IOStreamBase::write( const std::string &statement ) {
+    if (ddl_nullptr == m_file) {
+        return;
+    }
+
+    ::fwrite( statement.c_str(), sizeof( char ), statement.size(), m_file );
+}
+
+struct DDLNodeIterator {
+    const DDLNode::DllNodeList &m_childs;
+    size_t m_idx;
+
+    DDLNodeIterator( const DDLNode::DllNodeList &childs ) 
+    : m_childs( childs )
+    , m_idx( 0 ) {
+        // empty
+    }
+
+    ~DDLNodeIterator() {
+        // empty
+    }
+
+    bool getNext( DDLNode **node ) {
+        if( m_childs.size() > (m_idx+1) ) {
+            m_idx++;
+            *node = m_childs[ m_idx ];
+            return true;
+        }
+
+        return false;
+    }
+};
+
+static void writeLineEnd( std::string &statement ) {
+    statement += "\n";
+}
+
+OpenDDLExport::OpenDDLExport( IOStreamBase *stream )
+: m_stream( stream ) {
+    if (ddl_nullptr == m_stream) {
+        m_stream = new IOStreamBase();
+    }
+}
+
+OpenDDLExport::~OpenDDLExport() {
+    if (ddl_nullptr != m_stream) {
+        m_stream->close();
+    }
+    delete m_stream;
+}
+
+bool OpenDDLExport::exportContext( Context *ctx, const std::string &filename ) {
+    if( ddl_nullptr == ctx ) {
+        return false;
+    }
+
+    DDLNode *root( ctx->m_root );
+    if ( ddl_nullptr == root ) {
+        return true;
+    }
+
+    if (!filename.empty()) {
+        if (!m_stream->open( filename )) {
+            return false;
+        }
+    }
+
+    const bool retValue( handleNode( root ) );
+    
+    return retValue;
+}
+
+bool OpenDDLExport::handleNode( DDLNode *node ) {
+    if( ddl_nullptr == node ) {
+        return true;
+    }
+
+    const DDLNode::DllNodeList &childs = node->getChildNodeList();
+    if( childs.empty() ) {
+        return true;
+    }
+    DDLNode *current( ddl_nullptr );
+    DDLNodeIterator it( childs );
+    std::string statement;
+    bool success( true );
+    while( it.getNext( &current ) ) {
+        if( ddl_nullptr != current ) {
+            success |= writeNode( current, statement );
+            if( !handleNode( current ) ) {
+                success = false;
+            }
+        }
+    }
+
+    return success;
+}
+
+bool OpenDDLExport::writeToStream( const std::string &statement ) {
+    if (ddl_nullptr == m_stream ) {
+        return false;
+    }
+
+    if ( !statement.empty()) {
+        m_stream->write( statement );
+    }
+
+    return true;
+}
+
+bool OpenDDLExport::writeNode( DDLNode *node, std::string &statement ) {
+    bool success( true );
+    writeNodeHeader( node, statement );
+    if (node->hasProperties()) {
+        success |= writeProperties( node, statement );
+    }
+    writeLineEnd( statement );
+
+    statement = "}";
+    DataArrayList *al( node->getDataArrayList() );
+    if ( ddl_nullptr != al ) {
+        writeValueType( al->m_dataList->m_type, al->m_numItems, statement );
+        writeValueArray( al, statement );
+    }
+    Value *v( node->getValue() );
+    if (ddl_nullptr != v ) {
+        writeValueType( v->m_type, 1, statement );
+        statement = "{";
+        writeLineEnd( statement );
+        writeValue( v, statement );
+        statement = "}";
+        writeLineEnd( statement );
+    }
+    statement = "}";
+    writeLineEnd( statement );
+
+    writeToStream( statement );
+
+    return true;
+}
+
+bool OpenDDLExport::writeNodeHeader( DDLNode *node, std::string &statement ) {
+    if (ddl_nullptr == node) {
+        return false;
+    }
+
+    statement += node->getType();
+    const std::string &name( node->getName() );
+    if ( !name.empty() ) {
+        statement += " ";
+        statement += "$";
+        statement += name;
+    }
+
+    return true;
+}
+
+bool OpenDDLExport::writeProperties( DDLNode *node, std::string &statement ) {
+    if ( ddl_nullptr == node ) {
+        return false;
+    }
+
+    Property *prop( node->getProperties() );
+    // if no properties are there, return
+    if ( ddl_nullptr == prop ) {
+        return true;
+    }
+
+    if ( ddl_nullptr != prop ) {
+        // for instance (attrib = "position", bla=2)
+        statement += "(";
+        bool first( true );
+        while ( ddl_nullptr != prop ) {
+            if (!first) {
+                statement += ", ";
+            } else {
+                first = false;
+            }
+            statement += std::string( prop->m_key->m_text.m_buffer );
+            statement += " = ";
+            writeValue( prop->m_value, statement );
+            prop = prop->m_next;
+        }
+
+        statement += ")";
+    }
+
+    return true;
+}
+
+bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std::string &statement ) {
+    if ( Value::ddl_types_max == type) {
+        return false;
+    }
+
+    const std::string typeStr( getTypeToken( type ) );
+    statement += typeStr;
+    // if we have an array to write
+    if ( numItems > 1 ) {
+        statement += "[";
+        char buffer[ 256 ];
+        ::memset( buffer, '\0', 256 * sizeof( char ) );
+        sprintf( buffer, "%d", numItems );
+        statement += buffer;
+        statement += "]";
+    }
+
+    return true;
+}
+
+bool OpenDDLExport::writeValue( Value *val, std::string &statement ) {
+    if (ddl_nullptr == val) {
+        return false;
+    }
+
+    switch ( val->m_type ) {
+        case Value::ddl_bool:
+            if ( true == val->getBool() ) {
+                statement += "true";
+            } else {
+                statement += "false";
+            }
+            break;
+        case Value::ddl_int8: 
+            {
+                std::stringstream stream;
+                const int i = static_cast<int>( val->getInt8() );
+                stream << i;
+                statement += stream.str();
+            }
+            break;
+        case Value::ddl_int16:
+            {
+                std::stringstream stream;
+                char buffer[ 256 ];
+                ::memset( buffer, '\0', 256 * sizeof( char ) );
+                sprintf( buffer, "%d", val->getInt16() );
+                statement += buffer;
+        }
+            break;
+        case Value::ddl_int32:
+            {
+                std::stringstream stream;
+                char buffer[ 256 ];
+                ::memset( buffer, '\0', 256 * sizeof( char ) );
+                const int i = static_cast< int >( val->getInt32() );
+                sprintf( buffer, "%d", i );
+                statement += buffer;
+            }
+            break;
+        case Value::ddl_int64:
+            {
+                std::stringstream stream;
+                const int i = static_cast< int >( val->getInt64() );
+                stream << i;
+                statement += stream.str();
+        }
+            break;
+        case Value::ddl_unsigned_int8:
+            {
+                std::stringstream stream;
+                const int i = static_cast< unsigned int >( val->getUnsignedInt8() );
+                stream << i;
+                statement += stream.str();
+            }
+            break;
+        case Value::ddl_unsigned_int16:
+            {
+                std::stringstream stream;
+                const int i = static_cast< unsigned int >( val->getUnsignedInt16() );
+                stream << i;
+                statement += stream.str();
+            }
+            break;
+        case Value::ddl_unsigned_int32:
+            {
+                std::stringstream stream;
+                const int i = static_cast< unsigned int >( val->getUnsignedInt32() );
+                stream << i;
+                statement += stream.str();
+            }
+            break;
+        case Value::ddl_unsigned_int64:
+            {
+                std::stringstream stream;
+                const int i = static_cast< unsigned int >( val->getUnsignedInt64() );
+                stream << i;
+                statement += stream.str();
+            }
+            break;
+        case Value::ddl_half:
+            break;
+        case Value::ddl_float:
+            {
+                std::stringstream stream;
+                stream << val->getFloat();
+                statement += stream.str();
+            }
+            break;
+        case Value::ddl_double:
+            break;
+        case Value::ddl_string:
+            {
+                std::stringstream stream;
+                stream << val->getString();
+                statement += "\"";
+                statement += stream.str();
+                statement += "\"";
+             }
+            break;
+        case Value::ddl_ref:
+            break;
+        case Value::ddl_none:
+        case Value::ddl_types_max:
+        default:
+            break;
+    }
+
+    return true;
+}
+
+bool OpenDDLExport::writeValueArray( DataArrayList *al, std::string &statement ) {
+    if (ddl_nullptr == al) {
+        return false;
+    }
+
+    if (0 == al->m_numItems) {
+        return true;
+    }
+
+    DataArrayList *nextDataArrayList = al ;
+    Value *nextValue( nextDataArrayList->m_dataList );
+    while (ddl_nullptr != nextDataArrayList) {
+        if (ddl_nullptr != nextDataArrayList) {
+            statement += "{ ";
+            nextValue = nextDataArrayList->m_dataList;
+            size_t idx( 0 );
+            while (ddl_nullptr != nextValue) {
+                if (idx > 0) {
+                    statement += ", ";
+                }
+                writeValue( nextValue, statement );
+                nextValue = nextValue->m_next;
+                idx++;
+            }
+            statement += " }";
+        }
+        nextDataArrayList = nextDataArrayList->m_next;
+    }
+
+    return true;
+}
+
+END_ODDLPARSER_NS

+ 77 - 45
contrib/openddlparser/code/OpenDDLParser.cpp

@@ -21,6 +21,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 -----------------------------------------------------------------------------------------------*/
 #include <openddlparser/OpenDDLParser.h>
+#include <openddlparser/OpenDDLExport.h>
 
 #include <cassert>
 #include <iostream>
@@ -36,17 +37,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 BEGIN_ODDLPARSER_NS
 
-static const char *Version = "0.1.0";
+static const char *Version = "0.3.0";
 
 namespace Grammar {
-    static const char * const OpenBracketToken   = "{";
-    static const char * const CloseBracketToken  = "}";
-    static const char * const OpenPropertyToken  = "(";
-    static const char * const ClosePropertyToken = ")";
-    static const char * const BoolTrue           = "true";
-    static const char * const BoolFalse          = "false";
-    static const char * const RefToken           = "ref";
-    static const char * const CommaSeparator     = ",";
+    static const char *OpenBracketToken   = "{";
+    static const char *CloseBracketToken  = "}";
+    static const char *OpenPropertyToken  = "(";
+    static const char *ClosePropertyToken = ")";
+    static const char *OpenArrayToken     = "[";
+    static const char *CloseArrayToken    = "]";
+    static const char *BoolTrue           = "true";
+    static const char *BoolFalse          = "false";
+    static const char *CommaSeparator     = ",";
 
     static const char* PrimitiveTypeToken[ Value::ddl_types_max ] = {
         "bool",
@@ -66,6 +68,9 @@ namespace Grammar {
     };
 } // Namespace Grammar
 
+const char *getTypeToken( Value::ValueType  type ) {
+    return Grammar::PrimitiveTypeToken[ type ];
+}
 
 static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) {
     std::stringstream stream;
@@ -206,6 +211,17 @@ bool OpenDDLParser::parse() {
     return true;
 }
 
+bool OpenDDLParser::exportContext( Context *ctx, const std::string &filename ) {
+    if( ddl_nullptr == ctx ) {
+        return false;
+    }
+    
+    OpenDDLExport myExporter;
+    return myExporter.exportContext( ctx, filename );
+
+    return false;
+}
+
 char *OpenDDLParser::parseNextNode( char *in, char *end ) {
     in = parseHeader( in, end );
     in = parseStructure( in, end );
@@ -215,7 +231,8 @@ char *OpenDDLParser::parseNextNode( char *in, char *end ) {
 
 static void dumpId( Identifier *id ) {
     if( ddl_nullptr != id ) {
-        std::cout << id->m_text.m_buffer << std::endl;
+        if ( ddl_nullptr != id->m_text.m_buffer ) { }
+            std::cout << id->m_text.m_buffer << std::endl;
     }
 }
 
@@ -234,19 +251,19 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) {
     in = lookForNextToken( in, end );
     Property *first( ddl_nullptr );
     if( ddl_nullptr != id ) {
-        if( *in == '(' ) {
+        if( *in == Grammar::OpenPropertyToken[ 0 ] ) {
             in++;
             Property *prop( ddl_nullptr ), *prev( ddl_nullptr );
-            while( *in != ')' && in != end ) {
+            while( *in != Grammar::ClosePropertyToken[ 0 ] && in != end ) {
                 in = OpenDDLParser::parseProperty( in, end, &prop );
                 in = lookForNextToken( in, end );
 
-                if( *in != ',' && *in != ')' ) {
-                    logInvalidTokenError( in, ")", m_logCallback );
+                if( *in != Grammar::CommaSeparator[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] ) {
+                    logInvalidTokenError( in, Grammar::ClosePropertyToken, m_logCallback );
                     return in;
                 }
                 
-                if( ddl_nullptr != prop && *in != ',' ) {
+                if( ddl_nullptr != prop && *in != Grammar::CommaSeparator[ 0 ] ) {
                     if( ddl_nullptr == first ) {
                         first = prop;
                     }
@@ -348,13 +365,13 @@ char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) {
     if( Value::ddl_none != type ) {
         // parse a primitive data type
         in = lookForNextToken( in, end );
-        if( *in == '{' ) {
+        if( *in == Grammar::OpenBracketToken[ 0 ] ) {
             Reference *refs( ddl_nullptr );
             DataArrayList *dtArrayList( ddl_nullptr );
             Value *values( ddl_nullptr );
             if( 1 == arrayLen ) {
                 size_t numRefs( 0 ), numValues( 0 );
-                in = parseDataList( in, end, &values, numValues, &refs, numRefs );
+                in = parseDataList( in, end, type, &values, numValues, &refs, numRefs );
                 setNodeValues( top(), values );
                 setNodeReferences( top(), refs );
             } else if( arrayLen > 1 ) {
@@ -435,10 +452,10 @@ void OpenDDLParser::normalizeBuffer( std::vector<char> &buffer) {
             newBuffer.push_back( buffer[ readIdx ] );
         } else {
             if( isComment<char>( c, end ) ) {
-                readIdx++;
+                ++readIdx;
                 // skip the comment and the rest of the line
                 while( !isEndofLine( buffer[ readIdx ] ) ) {
-                    readIdx++;
+                    ++readIdx;
                 }
             }
         }
@@ -493,9 +510,9 @@ char *OpenDDLParser::parseIdentifier( char *in, char *end, Identifier **id ) {
     // get size of id
     size_t idLen( 0 );
     char *start( in );
-    while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != '(' && *in != ')' ) {
-        in++;
-        idLen++;
+    while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != Grammar::OpenPropertyToken[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] ) {
+        ++in;
+        ++idLen;
     }
     
     const size_t len( idLen );
@@ -529,14 +546,14 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy
     }
 
     bool ok( true );
-    if( *in == '[' ) {
+    if( *in == Grammar::OpenArrayToken[ 0 ] ) {
         ok = false;
         in++;
         char *start( in );
         while ( in != end ) {
             in++;
-            if( *in == ']' ) {
-                len = atoi( start );
+            if( *in == Grammar::CloseArrayToken[ 0 ] ) {
+                len = ::atoi( start );
                 ok = true;
                 in++;
                 break;
@@ -562,9 +579,9 @@ char *OpenDDLParser::parseReference( char *in, char *end, std::vector<Name*> &na
     if( nextName ) {
         names.push_back( nextName );
     }
-    while( ',' == *in ) {
+    while( Grammar::CommaSeparator[ 0 ] == *in ) {
         in = getNextSeparator( in, end );
-        if( ',' == *in ) {
+        if( Grammar::CommaSeparator[ 0 ] == *in ) {
             in = parseName( in, end, &nextName );
             if( nextName ) {
                 names.push_back( nextName );
@@ -802,7 +819,7 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) {
     return in;
 }
 
-char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ) {
+char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ) {
     *data = ddl_nullptr;
     numValues = numRefs = 0;
     if( ddl_nullptr == in || in == end ) {
@@ -816,21 +833,35 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &n
         while( '}' != *in ) {
             current = ddl_nullptr;
             in = lookForNextToken( in, end );
-            if( isInteger( in, end ) ) {
-                in = parseIntegerLiteral( in, end, &current );
-            } else if( isFloat( in, end ) ) {
-                in = parseFloatingLiteral( in, end, &current );
-            } else if( isStringLiteral( *in ) ) {
-                in = parseStringLiteral( in, end, &current );
-            } else if( isHexLiteral( in, end ) ) {
-                in = parseHexaLiteral( in, end, &current );
-            } else {                          // reference data
-                std::vector<Name*> names;
-                in = parseReference( in, end, names );
-                if( !names.empty() ) {
-                    Reference *ref = new Reference( names.size(), &names[ 0 ] );
-                    *refs = ref;
-                    numRefs = names.size();
+            if (Value::ddl_none == type) {
+                if (isInteger( in, end )) {
+                    in = parseIntegerLiteral( in, end, &current );
+                }
+                else if (isFloat( in, end )) {
+                    in = parseFloatingLiteral( in, end, &current );
+                }
+                else if (isStringLiteral( *in )) {
+                    in = parseStringLiteral( in, end, &current );
+                }
+                else if (isHexLiteral( in, end )) {
+                    in = parseHexaLiteral( in, end, &current );
+                }
+                else {                          // reference data
+                    std::vector<Name*> names;
+                    in = parseReference( in, end, names );
+                    if (!names.empty()) {
+                        Reference *ref = new Reference( names.size(), &names[ 0 ] );
+                        *refs = ref;
+                        numRefs = names.size();
+                    }
+                }
+            } else {
+                if (Value::ddl_int32 == type) {
+                    in = parseIntegerLiteral( in, end, &current );
+                } else if (Value::ddl_float == type) {
+                    in = parseFloatingLiteral( in, end, &current );
+                } else if (Value::ddl_string == type) {
+                    in = parseStringLiteral( in, end, &current );
                 }
             }
 
@@ -846,7 +877,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &n
             }
 
             in = getNextSeparator( in, end );
-            if( ',' != *in && '}' != *in && !isSpace( *in ) ) {
+            if( ',' != *in && Grammar::CloseBracketToken[ 0 ] != *in && !isSpace( *in ) ) {
                 break;
             }
         }
@@ -879,7 +910,8 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end, DataArrayList **da
         do {
             size_t numRefs( 0 ), numValues( 0 );
             currentValue = ddl_nullptr;
-            in = parseDataList( in, end, &currentValue, numValues, &refs, numRefs );
+            Value::ValueType type( Value::ddl_none );
+            in = parseDataList( in, end, type, &currentValue, numValues, &refs, numRefs );
             if( ddl_nullptr != currentValue ) {
                 if( ddl_nullptr == prev ) {
                     *dataList = createDataArrayList( currentValue, numValues );

+ 74 - 14
contrib/openddlparser/code/Value.cpp

@@ -27,6 +27,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 BEGIN_ODDLPARSER_NS
 
+static Value::Iterator end( ddl_nullptr );
+
 Value::Iterator::Iterator()
 : m_start( ddl_nullptr )
 , m_current( ddl_nullptr ) {
@@ -39,6 +41,12 @@ Value::Iterator::Iterator( Value *start )
     // empty
 }
 
+Value::Iterator::Iterator( const Iterator &rhs )
+: m_start( rhs.m_start )
+, m_current( rhs.m_current ) {
+    // empty
+}
+
 Value::Iterator::~Iterator() {
     // empty
 }
@@ -61,6 +69,38 @@ Value *Value::Iterator::getNext() {
     return v;
 }
 
+const Value::Iterator Value::Iterator::operator++( int ) {
+    if( ddl_nullptr == m_current ) {
+        return end;
+    }
+
+    m_current = m_current->getNext();
+    Iterator inst( m_current );
+
+    return inst;
+}
+
+Value::Iterator &Value::Iterator::operator++( ) {
+    if( ddl_nullptr == m_current ) {
+        return end;
+    }
+
+    m_current = m_current->getNext();
+
+    return *this;
+}
+
+bool Value::Iterator::operator == ( const Iterator &rhs ) const {
+    return ( m_current == rhs.m_current );
+}
+
+Value *Value::Iterator::operator->( ) const {
+    if(ddl_nullptr == m_current ) {
+        return ddl_nullptr;
+    }
+    return m_current;
+}
+
 Value::Value( ValueType type )
 : m_type( type )
 , m_size( 0 )
@@ -80,7 +120,7 @@ void Value::setBool( bool value ) {
 
 bool Value::getBool() {
     assert( ddl_bool == m_type );
-    return ( *m_data ) ? true : false;
+    return ( *m_data == 1 );
 }
 
 void Value::setInt8( int8 value ) {
@@ -100,7 +140,9 @@ void Value::setInt16( int16 value ) {
 
 int16 Value::getInt16() {
     assert( ddl_int16 == m_type );
-    return ( int16 ) ( *m_data );
+    int16 i;
+    ::memcpy( &i, m_data, m_size );
+    return i;
 }
 
 void Value::setInt32( int32 value ) {
@@ -110,16 +152,21 @@ void Value::setInt32( int32 value ) {
 
 int32 Value::getInt32() {
     assert( ddl_int32 == m_type );
-    return ( int32 ) ( *m_data );
+    int32 i;
+    ::memcpy( &i, m_data, m_size );
+    return i;
 }
 
 void Value::setInt64( int64 value ) {
-    assert( ddl_int32 == m_type );
+    assert( ddl_int64 == m_type );
     ::memcpy( m_data, &value, m_size );
 }
 
 int64 Value::getInt64() {
-    return ( int64 ) ( *m_data );
+    assert( ddl_int64 == m_type );
+    int64 i;
+    ::memcpy( &i, m_data, m_size );
+    return i;
 }
 
 void Value::setUnsignedInt8( uint8 value ) {
@@ -129,7 +176,9 @@ void Value::setUnsignedInt8( uint8 value ) {
 
 uint8 Value::getUnsignedInt8() const {
     assert( ddl_unsigned_int8 == m_type );
-    return ( uint8 ) ( *m_data );
+    uint8 i;
+    ::memcpy( &i, m_data, m_size );
+    return i;
 }
 
 void Value::setUnsignedInt16( uint16 value ) {
@@ -139,7 +188,9 @@ void Value::setUnsignedInt16( uint16 value ) {
 
 uint16 Value::getUnsignedInt16() const {
     assert( ddl_unsigned_int16 == m_type );
-    return ( uint8 ) ( *m_data );
+    uint16 i;
+    ::memcpy( &i, m_data, m_size );
+    return i;
 }
 
 void Value::setUnsignedInt32( uint32 value ) {
@@ -149,7 +200,9 @@ void Value::setUnsignedInt32( uint32 value ) {
 
 uint32 Value::getUnsignedInt32() const {
     assert( ddl_unsigned_int32 == m_type );
-    return ( uint8 ) ( *m_data );
+    uint32 i;
+    ::memcpy( &i, m_data, m_size );
+    return i;
 }
 
 void Value::setUnsignedInt64( uint64 value ) {
@@ -159,7 +212,9 @@ void Value::setUnsignedInt64( uint64 value ) {
 
 uint64 Value::getUnsignedInt64() const {
     assert( ddl_unsigned_int64 == m_type );
-    return ( uint64 ) ( *m_data );
+    uint64 i;
+    ::memcpy( &i, m_data, m_size );
+    return i;
 }
 
 void Value::setFloat( float value ) {
@@ -185,6 +240,7 @@ void Value::setDouble( double value ) {
 }
 
 double Value::getDouble() const {
+    assert( ddl_double == m_type );
     double v;
     ::memcpy( &v, m_data, m_size );
     return v;
@@ -196,6 +252,7 @@ void Value::setString( const std::string &str ) {
     m_data[ str.size() ] = '\0';
 }
 const char *Value::getString() const {
+    assert( ddl_string == m_type );
     return (const char*) m_data;
 }
 
@@ -271,22 +328,25 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) {
             data->m_size = sizeof( bool );
             break;
         case Value::ddl_int8:
-            data->m_size = sizeof( char );
+            data->m_size = sizeof( int8 );
             break;
         case Value::ddl_int16:
-            data->m_size = sizeof( short );
+            data->m_size = sizeof( int16 );
             break;
         case Value::ddl_int32:
-            data->m_size = sizeof( int );
+            data->m_size = sizeof( int32 );
             break;
         case Value::ddl_int64:
             data->m_size = sizeof( int64 );
             break;
         case Value::ddl_unsigned_int8:
-            data->m_size = sizeof( unsigned char );
+            data->m_size = sizeof( uint8 );
+            break;
+        case Value::ddl_unsigned_int16:
+            data->m_size = sizeof( uint16 );
             break;
         case Value::ddl_unsigned_int32:
-            data->m_size = sizeof( unsigned int );
+            data->m_size = sizeof( uint32 );
             break;
         case Value::ddl_unsigned_int64:
             data->m_size = sizeof( uint64 );

+ 4 - 0
contrib/openddlparser/include/openddlparser/DDLNode.h

@@ -101,6 +101,10 @@ public:
     /// @return true, if a corresponding property is assigned to the node, false if not.
     bool hasProperty( const std::string &name );
 
+    ///	@brief  Will return true, if any properties are assigned to the node instance.
+    ///	@return True, if properties are assigned.
+    bool hasProperties() const;
+
     ///	@brief  Search for a given property and returns it. Will return ddl_nullptr if no property was found.
     /// @param  name    [in] The name for the property to look for.
     /// @return The property or ddl_nullptr if no property was found.

+ 111 - 146
contrib/openddlparser/include/openddlparser/OpenDDLCommon.h

@@ -26,6 +26,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <vector>
 #include <string>
 
+#include <stdio.h>
 #include <string.h>
 #ifndef _WIN32
 #  include <inttypes.h>
@@ -56,10 +57,11 @@ BEGIN_ODDLPARSER_NS
     // All C++11 constructs
 #   define ddl_nullptr nullptr
 #else
-    // Fallback for older compilers
+    // Fall-back for older compilers
 #   define ddl_nullptr NULL
 #endif // OPENDDL_NO_USE_CPP11
 
+// Forward declarations
 class DDLNode;
 class Value;
 
@@ -69,6 +71,7 @@ struct Reference;
 struct Property;
 struct DataArrayList;
 
+// Platform-specific typedefs
 #ifdef _WIN32
 typedef signed __int64    int64_impl;
 typedef unsigned __int64  uint64_impl;
@@ -87,65 +90,36 @@ typedef unsigned short    uint16;  ///< Unsigned integer, 2 byte
 typedef unsigned int      uint32;  ///< Unsigned integer, 4 byte
 typedef uint64_impl       uint64;  ///< Unsigned integer, 8 byte
 
-///	@brief  Description of the type of a name.
-enum NameType {
-    GlobalName, ///< Name is global.
-    LocalName   ///< Name is local.
-};
+///	@brief  Stores a text.
+///
+/// A text is stored in a simple character buffer. Texts buffer can be 
+/// greater than the number of stored characters in them.
+struct DLL_ODDLPARSER_EXPORT Text {
+    size_t m_capacity;  ///< The capacity of the text.
+    size_t m_len;       ///< The length of the text.
+    char *m_buffer;     ///< The buffer with the text.
+
+    ///	@brief  The constructor with a given text buffer.
+    /// @param  buffer      [in] The buffer.
+    /// @param  numChars    [in] The number of characters in the buffer.
+    Text( const char *buffer, size_t numChars );
+
+    ///	@brief  The destructor.
+    ~Text();
 
-///	@brief  Stores a text
-struct Text {
-    size_t m_capacity;
-    size_t m_len;
-    char *m_buffer;
-
-    Text( const char *buffer, size_t numChars )
-    : m_capacity( 0 )
-    , m_len( 0 )
-    , m_buffer( ddl_nullptr ) {
-        set( buffer, numChars );
-    }
-
-    ~Text() {
-        clear();
-    }
-
-    void clear() {
-        delete[] m_buffer;
-        m_buffer = ddl_nullptr;
-        m_capacity = 0;
-        m_len = 0;
-    }
-
-    void set( const char *buffer, size_t numChars ) {
-        clear();
-        if( numChars > 0 ) {
-            m_len = numChars;
-            m_capacity = m_len + 1;
-            m_buffer = new char[ m_capacity ];
-            strncpy( m_buffer, buffer, numChars );
-            m_buffer[ numChars ] = '\0';
-        }
-    }
-
-    bool operator == ( const std::string &name ) const {
-        if( m_len != name.size() ) {
-            return false;
-        }
-        const int res( strncmp( m_buffer, name.c_str(), name.size() ) );
-        
-        return ( 0 == res );
-    }
-
-    bool operator == ( const Text &rhs ) const {
-        if( m_len != rhs.m_len ) {
-            return false;
-        }
-
-        const int res( strncmp( m_buffer, rhs.m_buffer, m_len ) );
-        
-        return ( 0 == res );
-    }
+    ///	@brief  Clears the text.
+    void clear();
+
+    ///	@brief  Set a new text.
+    /// @param  buffer      [in] The buffer.
+    /// @param  numChars    [in] The number of characters in the buffer.
+    void set( const char *buffer, size_t numChars );
+
+    ///	@brief  The compare operator for std::strings.
+    bool operator == ( const std::string &name ) const;
+
+    ///	@brief  The compare operator for Texts.
+    bool operator == ( const Text &rhs ) const;
 
 private:
     Text( const Text & );
@@ -153,38 +127,48 @@ private:
 };
 
 ///	@brief  Stores an OpenDDL-specific identifier type.
-struct Identifier {
-    Text m_text;
+struct DLL_ODDLPARSER_EXPORT Identifier {
+    Text m_text;    ///< The text element.
 
-    Identifier( char buffer[], size_t len )
-        : m_text( buffer, len ) {
-        // empty
-    }
+    ///	@brief  The constructor with a sized buffer full of characters.
+    ///	@param  buffer  [in] The identifier buffer.
+    ///	@param  len     [in] The length of the buffer
+    Identifier( const char buffer[], size_t len );
 
-    Identifier( char buffer[] )
-    : m_text( buffer, strlen( buffer ) ) {
-        // empty
-    }
+    ///	@brief  The constructor with a buffer full of characters.
+    ///	@param  buffer  [in] The identifier buffer.
+    /// @remark Buffer must be null-terminated.
+    Identifier( const char buffer[] );
 
-    bool operator == ( const Identifier &rhs ) const {
-        return m_text == rhs.m_text;
-    }
+    ///	@brief  The destructor.
+    ~Identifier();
+    
+    ///	@brief  The compare operator.
+    bool operator == ( const Identifier &rhs ) const;
 
 private:
     Identifier( const Identifier & );
     Identifier &operator = ( const Identifier & );
 };
 
+///	@brief  Description of the type of a name.
+enum NameType {
+    GlobalName, ///< Name is global.
+    LocalName   ///< Name is local.
+};
+
 ///	@brief  Stores an OpenDDL-specific name
-struct Name {
-    NameType    m_type;
-    Identifier *m_id;
+struct DLL_ODDLPARSER_EXPORT Name {
+    NameType    m_type; ///< The type of the name ( @see NameType ).
+    Identifier *m_id;   ///< The id.
 
-    Name( NameType type, Identifier *id )
-        : m_type( type )
-        , m_id( id ) {
-        // empty
-    }
+    ///	@brief  The constructor with the type and the id.
+    ///	@param  type    [in] The name type.
+    ///	@param  id      [in] The id.
+    Name( NameType type, Identifier *id );
+
+    ///	@brief  The destructor.
+    ~Name();
 
 private:
     Name( const Name & );
@@ -192,33 +176,20 @@ private:
 };
 
 ///	@brief  Stores a bundle of references.
-struct Reference {
-    size_t   m_numRefs;
-    Name   **m_referencedName;
-
-    Reference()
-    : m_numRefs( 0 )
-    , m_referencedName( ddl_nullptr ) {
-        // empty
-    }
+struct DLL_ODDLPARSER_EXPORT Reference {
+    size_t   m_numRefs;         ///< The number of stored references.
+    Name   **m_referencedName;  ///< The reference names.
+
+    ///	@brief  The default constructor.
+    Reference();
      
-    Reference( size_t numrefs, Name **names )
-    : m_numRefs( numrefs )
-    , m_referencedName( ddl_nullptr ) {
-        m_referencedName = new Name *[ numrefs ];
-        for( size_t i = 0; i < numrefs; i++ ) {
-            Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id );
-            m_referencedName[ i ] = name;
-        }
-    }
-
-    ~Reference() {
-        for( size_t i = 0; i < m_numRefs; i++ ) {
-            delete m_referencedName[ i ];
-        }
-        m_numRefs = 0;
-        m_referencedName = ddl_nullptr;
-    }
+    ///	@brief  The constructor with an array of ref names.
+    /// @param  numrefs     [in] The number of ref names.
+    /// @param  names       [in] The ref names.
+    Reference( size_t numrefs, Name **names );
+
+    ///	@brief  The destructor.
+    ~Reference();
 
 private:
     Reference( const Reference & );
@@ -226,26 +197,21 @@ private:
 };
 
 ///	@brief  Stores a property list.
-struct Property {
-    Identifier *m_key;
-    Value *m_value;
-    Reference *m_ref;
-    Property *m_next;
-
-    Property( Identifier *id )
-    : m_key( id )
-    , m_value( ddl_nullptr )
-    , m_ref( ddl_nullptr )
-    , m_next( ddl_nullptr ) {
-        // empty
-    }
-
-    ~Property() {
-        m_key = ddl_nullptr;
-        m_value = ddl_nullptr;
-        m_ref = ddl_nullptr;;
-        m_next = ddl_nullptr;;
-    }
+struct DLL_ODDLPARSER_EXPORT Property {
+    Identifier *m_key;      ///< The identifier / key of the property.
+    Value      *m_value;    ///< The value assigned to its key / id ( ddl_nullptr if none ).
+    Reference  *m_ref;      ///< References assigned to its key / id ( ddl_nullptr if none ).
+    Property   *m_next;     ///< The next property ( ddl_nullptr if none ).
+
+    ///	@brief  The default constructor.
+    Property();
+
+    ///	@brief  The constructor for initialization.
+    /// @param  id      [in] The identifier
+    Property( Identifier *id );
+
+    ///	@brief  The destructor.
+    ~Property();
 
 private:
     Property( const Property & );
@@ -253,17 +219,16 @@ private:
 };
 
 ///	@brief  Stores a data array list.
-struct DataArrayList {
-    size_t m_numItems;
-    Value *m_dataList;
-    DataArrayList *m_next;
-
-    DataArrayList()
-        : m_numItems( 0 )
-        , m_dataList( ddl_nullptr )
-        , m_next( ddl_nullptr ) {
-        // empty
-    }
+struct DLL_ODDLPARSER_EXPORT DataArrayList {
+    size_t         m_numItems;  ///< The number of items in the list.
+    Value         *m_dataList;  ///< The data list ( ee Value ).
+    DataArrayList *m_next;      ///< The next data array list ( ddl_nullptr if last ).
+
+    ///	@brief  The default constructor for initialization.
+    DataArrayList();
+
+    ///	@brief  The destructor.
+    ~DataArrayList();
 
 private:
     DataArrayList( const DataArrayList & ); 
@@ -271,17 +236,17 @@ private:
 };
 
 ///	@brief  Stores the context of a parsed OpenDDL declaration.
-struct Context {
-    DDLNode *m_root;
+struct DLL_ODDLPARSER_EXPORT Context {
+    DDLNode *m_root;    ///< The root node of the OpenDDL node tree.
+
+    ///	@brief  Constructor for initialization.
+    Context();
 
-    Context()
-        : m_root( ddl_nullptr ) {
-        // empty
-    }
+    ///	@brief  Destructor.
+    ~Context();
 
-    ~Context() {
-        m_root = ddl_nullptr;
-    }
+    ///	@brief  Clears the whole node tree.
+    void clear();
 
 private:
     Context( const Context & );

+ 88 - 0
contrib/openddlparser/include/openddlparser/OpenDDLExport.h

@@ -0,0 +1,88 @@
+/*-----------------------------------------------------------------------------------------------
+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>
+#include <openddlparser/Value.h>
+
+BEGIN_ODDLPARSER_NS
+
+//-------------------------------------------------------------------------------------------------
+/// @ingroup    IOStreamBase
+///	@brief      This class represents the stream to write out.
+//-------------------------------------------------------------------------------------------------
+class DLL_ODDLPARSER_EXPORT IOStreamBase {
+public:
+    IOStreamBase();
+    virtual ~IOStreamBase();
+    virtual bool open( const std::string &anme );
+    virtual bool close();
+    virtual void write( const std::string &statement );
+
+private:
+    FILE *m_file;
+};
+
+//-------------------------------------------------------------------------------------------------
+///
+/// @ingroup    OpenDDLParser
+///	@brief      This class represents the OpenDDLExporter.
+///
+//-------------------------------------------------------------------------------------------------
+class DLL_ODDLPARSER_EXPORT OpenDDLExport {
+public:
+    ///	@brief  The class constructor
+    OpenDDLExport( IOStreamBase *stream = ddl_nullptr );
+
+    ///	@brief  The class destructor.
+    ~OpenDDLExport();
+
+    ///	@brief  Export the data of a parser context.
+    /// @param  ctx         [in] Pointer to the context.
+    /// @param  filename    [in] The filename for the export.
+    /// @return True in case of success, false in case of an error.
+    bool exportContext( Context *ctx, const std::string &filename );
+
+    ///	@brief  Handles a node export.
+    /// @param  node        [in] The node to handle with.
+    /// @return True in case of success, false in case of an error.
+    bool handleNode( DDLNode *node );
+
+    ///	@brief  Writes the statement to the stream.
+    /// @param  statement   [in]  The content to write.
+    /// @return True in case of success, false in case of an error.
+    bool writeToStream( const std::string &statement );
+
+protected:
+    bool writeNode( DDLNode *node, std::string &statement );
+    bool writeNodeHeader( DDLNode *node, std::string &statement );
+    bool writeProperties( DDLNode *node, std::string &statement );
+    bool writeValueType( Value::ValueType type, size_t numItems, std::string &statement );
+    bool writeValue( Value *val, std::string &statement );
+    bool writeValueArray( DataArrayList *al, std::string &statement );
+
+private:
+    IOStreamBase *m_stream;
+};
+
+END_ODDLPARSER_NS

+ 70 - 7
contrib/openddlparser/include/openddlparser/OpenDDLParser.h

@@ -39,6 +39,11 @@ struct Identifier;
 struct Reference;
 struct Property;
 
+///	@brief  Utility function to search for the next token or the end of the buffer.
+/// @param  in      [in] The start position in the buffer.
+/// @param  end     [in] The end position in the buffer.
+///	@return Pointer showing to the next token or the end of the buffer.
+///	@detail Will not increase buffer when already a valid buffer was found.
 template<class T>
 inline
 T *lookForNextToken( T *in, T *end ) {
@@ -48,13 +53,19 @@ T *lookForNextToken( T *in, T *end ) {
     return in;
 }
 
+///	@brief  Utility function to go for the next token or the end of the buffer.
+/// @param  in      [in] The start position in the buffer.
+/// @param  end     [in] The end position in the buffer.
+///	@return Pointer showing to the next token or the end of the buffer.
+///	@detail Will  increase buffer by a minimum of one.
 template<class T>
 inline
 T *getNextToken( T *in, T *end ) {
     T *tmp( in );
-    while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) {
+    in = lookForNextToken( in, end );
+    /*while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) {
         in++;
-    }
+    }*/
     if( tmp == in ) {
         in++;
     }
@@ -69,22 +80,78 @@ enum LogSeverity {
     ddl_error_msg       ///< Parser errors
 };
 
+DLL_ODDLPARSER_EXPORT const char *getTypeToken( Value::ValueType  type );
+
+//-------------------------------------------------------------------------------------------------
+///	@class		OpenDDLParser
+///	@ingroup	OpenDDLParser
+
+///
+///	@brief  This is the main API for the OpenDDL-parser.
+///
+/// Use instances of this class to manage the parsing and handling of your parser contexts.
+//-------------------------------------------------------------------------------------------------
 class DLL_ODDLPARSER_EXPORT OpenDDLParser {
 public:
+    ///	@brief  The log callback function pointer.
     typedef void( *logCallback )( LogSeverity severity, const std::string &msg );
 
 public:
+    ///	@brief  The default class constructor.
     OpenDDLParser();
+
+    ///	@brief  The class constructor.
+    ///	@param  buffer      [in] The buffer
+    ///	@param  len         [in] Size of the buffer
     OpenDDLParser( char *buffer, size_t len );
+
+    ///	@brief  The class destructor.
     ~OpenDDLParser();
+
+    ///	@brief  Setter for an own log callback function.
+    /// @param  callback    [in] The own callback.
     void setLogCallback( logCallback callback );
+
+    ///	@brief  Getter for the log callback.
+    /// @return The current log callback.
     logCallback getLogCallback() const;
+
+    ///	@brief  Assigns a new buffer to parse.
+    ///	@param  buffer      [in] The buffer
+    ///	@param  len         [in] Size of the buffer
     void setBuffer( char *buffer, size_t len );
+
+    ///	@brief  Assigns a new buffer to parse.
+    /// @param  buffer      [in] The buffer as a std::vector.
     void setBuffer( const std::vector<char> &buffer );
+
+    ///	@brief  Returns the buffer pointer.
+    /// @return The buffer pointer.
     const char *getBuffer() const;
+    
+    /// @brief  Returns the size of the buffer.
+    /// @return The buffer size.
     size_t getBufferSize() const;
+    
+    ///	@brief  Clears all parser data, including buffer and active context.
     void clear();
+
+    ///	@brief  Starts the parsing of the OpenDDL-file.
+    /// @return True in case of success, false in case of an error.
+    /// @remark In case of errors check log.
     bool parse();
+
+    bool exportContext( Context *ctx, const std::string &filename );
+
+    ///	@brief  Returns the root node.
+    /// @return The root node.
+    DDLNode *getRoot() const;
+
+    ///	@brief  Returns the parser context, only available in case of a succeeded parsing.
+    /// @return Pointer to the active context or ddl_nullptr.
+    Context *getContext() const;
+
+public: // parser helpers
     char *parseNextNode( char *current, char *end );
     char *parseHeader( char *in, char *end );
     char *parseStructure( char *in, char *end );
@@ -92,10 +159,6 @@ public:
     void pushNode( DDLNode *node );
     DDLNode *popNode();
     DDLNode *top();
-    DDLNode *getRoot() const;
-    Context *getContext() const;
-
-public: // static parser helpers
     static void normalizeBuffer( std::vector<char> &buffer );
     static char *parseName( char *in, char *end, Name **name );
     static char *parseIdentifier( char *in, char *end, Identifier **id );
@@ -107,7 +170,7 @@ public: // static parser helpers
     static char *parseStringLiteral( char *in, char *end, Value **stringData );
     static char *parseHexaLiteral( char *in, char *end, Value **data );
     static char *parseProperty( char *in, char *end, Property **prop );
-    static char *parseDataList( char *in, char *end, Value **data, size_t &numValues, Reference **refs, size_t &numRefs );
+    static char *parseDataList( char *in, char *end, Value::ValueType type, Value **data, size_t &numValues, Reference **refs, size_t &numRefs );
     static char *parseDataArrayList( char *in, char *end, DataArrayList **dataList );
     static const char *getVersion();
 

+ 29 - 1
contrib/openddlparser/include/openddlparser/Value.h

@@ -61,6 +61,8 @@ public:
         /// @param  start   [in] The first value for iteration,
         Iterator( Value *start );
 
+        Iterator( const Iterator &rhs );
+
         ///	@brief  The class destructor.
         ~Iterator();
 
@@ -71,13 +73,27 @@ public:
         ///	@brief  Returns the next item and moves the iterator to it.
         ///	@return The next value, is ddl_nullptr in case of being the last item.
         Value *getNext();
+        
+        ///	@brief  The post-increment operator.
+        const Iterator operator++( int );
+        
+        ///	@brief  The pre-increment operator.
+        Iterator &operator++( );
+
+        ///	@brief  The compare operator.
+        /// @param  rhs [in] The instance to compare.
+        /// @return true if equal.
+        bool operator == ( const Iterator &rhs ) const;
+
+        /// @brief  The * operator.
+        /// @return The instance or ddl_nullptr if end of list is reached.
+        Value *operator->( ) const;
 
     private:
         Value *m_start;
         Value *m_current;
 
     private:
-        Iterator( const Iterator & );
         Iterator &operator = ( const Iterator & );
     };
 
@@ -135,11 +151,23 @@ public:
     size_t m_size;
     unsigned char *m_data;
     Value *m_next;
+
+private:
+    Value &operator =( const Value & );
+    Value( const Value  & );
 };
 
+///------------------------------------------------------------------------------------------------
+///	@brief  This class implements the value allocator.
+///------------------------------------------------------------------------------------------------
 struct DLL_ODDLPARSER_EXPORT ValueAllocator {
     static Value *allocPrimData( Value::ValueType type, size_t len = 1 );
     static void releasePrimData( Value **data );
+
+private:
+    ValueAllocator();
+    ValueAllocator( const ValueAllocator  & );
+    ValueAllocator &operator = ( const ValueAllocator & );
 };
 
 END_ODDLPARSER_NS

+ 261 - 0
contrib/rapidjson/include/rapidjson/allocators.h

@@ -0,0 +1,261 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ALLOCATORS_H_
+#define RAPIDJSON_ALLOCATORS_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+    \brief Concept for allocating, resizing and freeing memory block.
+    
+    Note that Malloc() and Realloc() are non-static but Free() is static.
+    
+    So if an allocator need to support Free(), it needs to put its pointer in 
+    the header of memory block.
+
+\code
+concept Allocator {
+    static const bool kNeedFree;    //!< Whether this allocator needs to call Free().
+
+    // Allocate a memory block.
+    // \param size of the memory block in bytes.
+    // \returns pointer to the memory block.
+    void* Malloc(size_t size);
+
+    // Resize a memory block.
+    // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+    // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+    // \param newSize the new size in bytes.
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+    // Free a memory block.
+    // \param pointer to the memory block. Null pointer is permitted.
+    static void Free(void *ptr);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+    \note implements Allocator concept
+*/
+class CrtAllocator {
+public:
+    static const bool kNeedFree = true;
+    void* Malloc(size_t size) { 
+        if (size) //  behavior of malloc(0) is implementation defined.
+            return std::malloc(size);
+        else
+            return NULL; // standardize to returning NULL.
+    }
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+        (void)originalSize;
+        if (newSize == 0) {
+            std::free(originalPtr);
+            return NULL;
+        }
+        return std::realloc(originalPtr, newSize);
+    }
+    static void Free(void *ptr) { std::free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks. 
+
+    It does not free memory blocks. And Realloc() only allocate new memory.
+
+    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+    User may also supply a buffer as the first chunk.
+
+    If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+    The user-buffer is not deallocated by this allocator.
+
+    \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+    \note implements Allocator concept
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+    static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+    //! Constructor with chunkSize.
+    /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+        \param baseAllocator The allocator for allocating memory chunks.
+    */
+    MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 
+        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+    {
+    }
+
+    //! Constructor with user-supplied buffer.
+    /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+        The user buffer will not be deallocated when this allocator is destructed.
+
+        \param buffer User supplied buffer.
+        \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+        \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+        \param baseAllocator The allocator for allocating memory chunks.
+    */
+    MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+    {
+        RAPIDJSON_ASSERT(buffer != 0);
+        RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+        chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
+        chunkHead_->capacity = size - sizeof(ChunkHeader);
+        chunkHead_->size = 0;
+        chunkHead_->next = 0;
+    }
+
+    //! Destructor.
+    /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+    */
+    ~MemoryPoolAllocator() {
+        Clear();
+        RAPIDJSON_DELETE(ownBaseAllocator_);
+    }
+
+    //! Deallocates all memory chunks, excluding the user-supplied buffer.
+    void Clear() {
+        while (chunkHead_ && chunkHead_ != userBuffer_) {
+            ChunkHeader* next = chunkHead_->next;
+            baseAllocator_->Free(chunkHead_);
+            chunkHead_ = next;
+        }
+        if (chunkHead_ && chunkHead_ == userBuffer_)
+            chunkHead_->size = 0; // Clear user buffer
+    }
+
+    //! Computes the total capacity of allocated memory chunks.
+    /*! \return total capacity in bytes.
+    */
+    size_t Capacity() const {
+        size_t capacity = 0;
+        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+            capacity += c->capacity;
+        return capacity;
+    }
+
+    //! Computes the memory blocks allocated.
+    /*! \return total used bytes.
+    */
+    size_t Size() const {
+        size_t size = 0;
+        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+            size += c->size;
+        return size;
+    }
+
+    //! Allocates a memory block. (concept Allocator)
+    void* Malloc(size_t size) {
+        if (!size)
+            return NULL;
+
+        size = RAPIDJSON_ALIGN(size);
+        if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+            AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
+
+        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
+        chunkHead_->size += size;
+        return buffer;
+    }
+
+    //! Resizes a memory block (concept Allocator)
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+        if (originalPtr == 0)
+            return Malloc(newSize);
+
+        if (newSize == 0)
+            return NULL;
+
+        // Do not shrink if new size is smaller than original
+        if (originalSize >= newSize)
+            return originalPtr;
+
+        // Simply expand it if it is the last allocation and there is sufficient space
+        if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+            size_t increment = static_cast<size_t>(newSize - originalSize);
+            increment = RAPIDJSON_ALIGN(increment);
+            if (chunkHead_->size + increment <= chunkHead_->capacity) {
+                chunkHead_->size += increment;
+                return originalPtr;
+            }
+        }
+
+        // Realloc process: allocate and copy memory, do not free original buffer.
+        void* newBuffer = Malloc(newSize);
+        RAPIDJSON_ASSERT(newBuffer != 0);   // Do not handle out-of-memory explicitly.
+        if (originalSize)
+            std::memcpy(newBuffer, originalPtr, originalSize);
+        return newBuffer;
+    }
+
+    //! Frees a memory block (concept Allocator)
+    static void Free(void *ptr) { (void)ptr; } // Do nothing
+
+private:
+    //! Copy constructor is not permitted.
+    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
+    //! Copy assignment operator is not permitted.
+    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+
+    //! Creates a new chunk.
+    /*! \param capacity Capacity of the chunk in bytes.
+    */
+    void AddChunk(size_t capacity) {
+        if (!baseAllocator_)
+            ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
+        ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
+        chunk->capacity = capacity;
+        chunk->size = 0;
+        chunk->next = chunkHead_;
+        chunkHead_ =  chunk;
+    }
+
+    static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+
+    //! Chunk header for perpending to each chunk.
+    /*! Chunks are stored as a singly linked list.
+    */
+    struct ChunkHeader {
+        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).
+        size_t size;        //!< Current size of allocated memory in bytes.
+        ChunkHeader *next;  //!< Next chunk in the linked list.
+    };
+
+    ChunkHeader *chunkHead_;    //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.
+    void *userBuffer_;          //!< User supplied buffer.
+    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.
+    BaseAllocator* ownBaseAllocator_;   //!< base allocator created by this object.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ENCODINGS_H_

+ 2114 - 0
contrib/rapidjson/include/rapidjson/document.h

@@ -0,0 +1,2114 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+/*! \file document.h */
+
+#include "reader.h"
+#include "internal/meta.h"
+#include "internal/strfunc.h"
+#include <new>      // placement new
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#elif defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_HAS_STDSTRING
+
+#ifndef RAPIDJSON_HAS_STDSTRING
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
+#else
+#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
+#endif
+/*! \def RAPIDJSON_HAS_STDSTRING
+    \ingroup RAPIDJSON_CONFIG
+    \brief Enable RapidJSON support for \c std::string
+
+    By defining this preprocessor symbol to \c 1, several convenience functions for using
+    \ref rapidjson::GenericValue with \c std::string are enabled, especially
+    for construction and comparison.
+
+    \hideinitializer
+*/
+#endif // !defined(RAPIDJSON_HAS_STDSTRING)
+
+#if RAPIDJSON_HAS_STDSTRING
+#include <string>
+#endif // RAPIDJSON_HAS_STDSTRING
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+#include <iterator> // std::iterator, std::random_access_iterator_tag
+#endif
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// Forward declaration.
+template <typename Encoding, typename Allocator>
+class GenericValue;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+//! Name-value pair in a JSON object value.
+/*!
+    This class was internal to GenericValue. It used to be a inner struct.
+    But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
+    https://code.google.com/p/rapidjson/issues/detail?id=64
+*/
+template <typename Encoding, typename Allocator> 
+struct GenericMember { 
+    GenericValue<Encoding, Allocator> name;     //!< name of member (must be a string)
+    GenericValue<Encoding, Allocator> value;    //!< value of member.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericMemberIterator
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+
+//! (Constant) member iterator for a JSON object value
+/*!
+    \tparam Const Is this a constant iterator?
+    \tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)
+    \tparam Allocator   Allocator type for allocating memory of object, array and string.
+
+    This class implements a Random Access Iterator for GenericMember elements
+    of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
+
+    \note This iterator implementation is mainly intended to avoid implicit
+        conversions from iterator values to \c NULL,
+        e.g. from GenericValue::FindMember.
+
+    \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
+        pointer-based implementation, if your platform doesn't provide
+        the C++ <iterator> header.
+
+    \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
+ */
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator
+    : public std::iterator<std::random_access_iterator_tag
+        , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
+
+    friend class GenericValue<Encoding,Allocator>;
+    template <bool, typename, typename> friend class GenericMemberIterator;
+
+    typedef GenericMember<Encoding,Allocator> PlainType;
+    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+    typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
+
+public:
+    //! Iterator type itself
+    typedef GenericMemberIterator Iterator;
+    //! Constant iterator type
+    typedef GenericMemberIterator<true,Encoding,Allocator>  ConstIterator;
+    //! Non-constant iterator type
+    typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
+
+    //! Pointer to (const) GenericMember
+    typedef typename BaseType::pointer         Pointer;
+    //! Reference to (const) GenericMember
+    typedef typename BaseType::reference       Reference;
+    //! Signed integer type (e.g. \c ptrdiff_t)
+    typedef typename BaseType::difference_type DifferenceType;
+
+    //! Default constructor (singular value)
+    /*! Creates an iterator pointing to no element.
+        \note All operations, except for comparisons, are undefined on such values.
+     */
+    GenericMemberIterator() : ptr_() {}
+
+    //! Iterator conversions to more const
+    /*!
+        \param it (Non-const) iterator to copy from
+
+        Allows the creation of an iterator from another GenericMemberIterator
+        that is "less const".  Especially, creating a non-constant iterator
+        from a constant iterator are disabled:
+        \li const -> non-const (not ok)
+        \li const -> const (ok)
+        \li non-const -> const (ok)
+        \li non-const -> non-const (ok)
+
+        \note If the \c Const template parameter is already \c false, this
+            constructor effectively defines a regular copy-constructor.
+            Otherwise, the copy constructor is implicitly defined.
+    */
+    GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
+
+    //! @name stepping
+    //@{
+    Iterator& operator++(){ ++ptr_; return *this; }
+    Iterator& operator--(){ --ptr_; return *this; }
+    Iterator  operator++(int){ Iterator old(*this); ++ptr_; return old; }
+    Iterator  operator--(int){ Iterator old(*this); --ptr_; return old; }
+    //@}
+
+    //! @name increment/decrement
+    //@{
+    Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
+    Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
+
+    Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
+    Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
+    //@}
+
+    //! @name relations
+    //@{
+    bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
+    bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
+    bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
+    bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
+    bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
+    bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
+    //@}
+
+    //! @name dereference
+    //@{
+    Reference operator*() const { return *ptr_; }
+    Pointer   operator->() const { return ptr_; }
+    Reference operator[](DifferenceType n) const { return ptr_[n]; }
+    //@}
+
+    //! Distance
+    DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
+
+private:
+    //! Internal constructor from plain pointer
+    explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
+
+    Pointer ptr_; //!< raw pointer
+};
+
+#else // RAPIDJSON_NOMEMBERITERATORCLASS
+
+// class-based member iterator implementation disabled, use plain pointers
+
+template <bool Const, typename Encoding, typename Allocator>
+struct GenericMemberIterator;
+
+//! non-const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<false,Encoding,Allocator> {
+    //! use plain pointer as iterator type
+    typedef GenericMember<Encoding,Allocator>* Iterator;
+};
+//! const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<true,Encoding,Allocator> {
+    //! use plain const pointer as iterator type
+    typedef const GenericMember<Encoding,Allocator>* Iterator;
+};
+
+#endif // RAPIDJSON_NOMEMBERITERATORCLASS
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericStringRef
+
+//! Reference to a constant string (not taking a copy)
+/*!
+    \tparam CharType character type of the string
+
+    This helper class is used to automatically infer constant string
+    references for string literals, especially from \c const \b (!)
+    character arrays.
+
+    The main use is for creating JSON string values without copying the
+    source string via an \ref Allocator.  This requires that the referenced
+    string pointers have a sufficient lifetime, which exceeds the lifetime
+    of the associated GenericValue.
+
+    \b Example
+    \code
+    Value v("foo");   // ok, no need to copy & calculate length
+    const char foo[] = "foo";
+    v.SetString(foo); // ok
+
+    const char* bar = foo;
+    // Value x(bar); // not ok, can't rely on bar's lifetime
+    Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
+    Value y(StringRef(bar, 3));  // ok, explicitly pass length
+    \endcode
+
+    \see StringRef, GenericValue::SetString
+*/
+template<typename CharType>
+struct GenericStringRef {
+    typedef CharType Ch; //!< character type of the string
+
+    //! Create string reference from \c const character array
+    /*!
+        This constructor implicitly creates a constant string reference from
+        a \c const character array.  It has better performance than
+        \ref StringRef(const CharType*) by inferring the string \ref length
+        from the array length, and also supports strings containing null
+        characters.
+
+        \tparam N length of the string, automatically inferred
+
+        \param str Constant character array, lifetime assumed to be longer
+            than the use of the string in e.g. a GenericValue
+
+        \post \ref s == str
+
+        \note Constant complexity.
+        \note There is a hidden, private overload to disallow references to
+            non-const character arrays to be created via this constructor.
+            By this, e.g. function-scope arrays used to be filled via
+            \c snprintf are excluded from consideration.
+            In such cases, the referenced string should be \b copied to the
+            GenericValue instead.
+     */
+    template<SizeType N>
+    GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
+        : s(str), length(N-1) {}
+
+    //! Explicitly create string reference from \c const character pointer
+    /*!
+        This constructor can be used to \b explicitly  create a reference to
+        a constant string pointer.
+
+        \see StringRef(const CharType*)
+
+        \param str Constant character pointer, lifetime assumed to be longer
+            than the use of the string in e.g. a GenericValue
+
+        \post \ref s == str
+
+        \note There is a hidden, private overload to disallow references to
+            non-const character arrays to be created via this constructor.
+            By this, e.g. function-scope arrays used to be filled via
+            \c snprintf are excluded from consideration.
+            In such cases, the referenced string should be \b copied to the
+            GenericValue instead.
+     */
+    explicit GenericStringRef(const CharType* str)
+        : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
+
+    //! Create constant string reference from pointer and length
+    /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+        \param len length of the string, excluding the trailing NULL terminator
+
+        \post \ref s == str && \ref length == len
+        \note Constant complexity.
+     */
+    GenericStringRef(const CharType* str, SizeType len)
+        : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
+
+    //! implicit conversion to plain CharType pointer
+    operator const Ch *() const { return s; }
+
+    const Ch* const s; //!< plain CharType pointer
+    const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
+
+private:
+    //! Disallow copy-assignment
+    GenericStringRef operator=(const GenericStringRef&);
+    //! Disallow construction from non-const array
+    template<SizeType N>
+    GenericStringRef(CharType (&str)[N]) /* = delete */;
+};
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal".  This function
+    can be used to avoid copying a character string to be referenced as a
+    value in a JSON GenericValue object, if the string's lifetime is known
+    to be valid long enough.
+    \tparam CharType Character type of the string
+    \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+    \return GenericStringRef string reference object
+    \relatesalso GenericStringRef
+
+    \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str) {
+    return GenericStringRef<CharType>(str, internal::StrLen(str));
+}
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal".  This function
+    can be used to avoid copying a character string to be referenced as a
+    value in a JSON GenericValue object, if the string's lifetime is known
+    to be valid long enough.
+
+    This version has better performance with supplied length, and also
+    supports string containing null characters.
+
+    \tparam CharType character type of the string
+    \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+    \param length The length of source string.
+    \return GenericStringRef string reference object
+    \relatesalso GenericStringRef
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
+    return GenericStringRef<CharType>(str, SizeType(length));
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+//! Mark a string object as constant string
+/*! Mark a string object (e.g. \c std::string) as a "string literal".
+    This function can be used to avoid copying a string to be referenced as a
+    value in a JSON GenericValue object, if the string's lifetime is known
+    to be valid long enough.
+
+    \tparam CharType character type of the string
+    \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+    \return GenericStringRef string reference object
+    \relatesalso GenericStringRef
+    \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {
+    return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue type traits
+namespace internal {
+
+template <typename T, typename Encoding = void, typename Allocator = void>
+struct IsGenericValueImpl : FalseType {};
+
+// select candidates according to nested encoding and allocator types
+template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
+    : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
+
+// helper to match arbitrary GenericValue instantiations, including derived classes
+template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+    A JSON value can be one of 7 types. This class is a variant type supporting
+    these types.
+
+    Use the Value if UTF8 and default allocator
+
+    \tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)
+    \tparam Allocator   Allocator type for allocating memory of object, array and string.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> > 
+class GenericValue {
+public:
+    //! Name-value pair in an object.
+    typedef GenericMember<Encoding, Allocator> Member;
+    typedef Encoding EncodingType;                  //!< Encoding type from template parameter.
+    typedef Allocator AllocatorType;                //!< Allocator type from template parameter.
+    typedef typename Encoding::Ch Ch;               //!< Character type derived from Encoding.
+    typedef GenericStringRef<Ch> StringRefType;     //!< Reference to a constant string
+    typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator;  //!< Member iterator for iterating in object.
+    typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator;  //!< Constant member iterator for iterating in object.
+    typedef GenericValue* ValueIterator;            //!< Value iterator for iterating in array.
+    typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of itself.
+
+    //!@name Constructors and destructor.
+    //@{
+
+    //! Default constructor creates a null value.
+    GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move constructor in C++11
+    GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) {
+        rhs.flags_ = kNullFlag; // give up contents
+    }
+#endif
+
+private:
+    //! Copy constructor is not permitted.
+    GenericValue(const GenericValue& rhs);
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Moving from a GenericDocument is not permitted.
+    template <typename StackAllocator>
+    GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
+
+    //! Move assignment from a GenericDocument is not permitted.
+    template <typename StackAllocator>
+    GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
+#endif
+
+public:
+
+    //! Constructor with JSON value type.
+    /*! This creates a Value of specified type with default content.
+        \param type Type of the value.
+        \note Default content for number is zero.
+    */
+    explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
+        static const unsigned defaultFlags[7] = {
+            kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
+            kNumberAnyFlag
+        };
+        RAPIDJSON_ASSERT(type <= kNumberType);
+        flags_ = defaultFlags[type];
+
+        // Use ShortString to store empty string.
+        if (type == kStringType)
+            data_.ss.SetLength(0);
+    }
+
+    //! Explicit copy constructor (with allocator)
+    /*! Creates a copy of a Value by using the given Allocator
+        \tparam SourceAllocator allocator of \c rhs
+        \param rhs Value to copy from (read-only)
+        \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
+        \see CopyFrom()
+    */
+    template< typename SourceAllocator >
+    GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
+
+    //! Constructor for boolean value.
+    /*! \param b Boolean value
+        \note This constructor is limited to \em real boolean values and rejects
+            implicitly converted types like arbitrary pointers.  Use an explicit cast
+            to \c bool, if you want to construct a boolean JSON value in such cases.
+     */
+#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
+    template <typename T>
+    explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>))) RAPIDJSON_NOEXCEPT
+#else
+    explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
+#endif
+        : data_(), flags_(b ? kTrueFlag : kFalseFlag) {
+            // safe-guard against failing SFINAE
+            RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
+    }
+
+    //! Constructor for int value.
+    explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {
+        data_.n.i64 = i;
+        if (i >= 0)
+            flags_ |= kUintFlag | kUint64Flag;
+    }
+
+    //! Constructor for unsigned value.
+    explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) {
+        data_.n.u64 = u; 
+        if (!(u & 0x80000000))
+            flags_ |= kIntFlag | kInt64Flag;
+    }
+
+    //! Constructor for int64_t value.
+    explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) {
+        data_.n.i64 = i64;
+        if (i64 >= 0) {
+            flags_ |= kNumberUint64Flag;
+            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+                flags_ |= kUintFlag;
+            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+                flags_ |= kIntFlag;
+        }
+        else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+            flags_ |= kIntFlag;
+    }
+
+    //! Constructor for uint64_t value.
+    explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
+        data_.n.u64 = u64;
+        if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
+            flags_ |= kInt64Flag;
+        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+            flags_ |= kUintFlag;
+        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+            flags_ |= kIntFlag;
+    }
+
+    //! Constructor for double value.
+    explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
+
+    //! Constructor for constant string (i.e. do not make a copy of string)
+    GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); }
+
+    //! Constructor for constant string (i.e. do not make a copy of string)
+    explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); }
+
+    //! Constructor for copy-string (i.e. do make a copy of string)
+    GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }
+
+    //! Constructor for copy-string (i.e. do make a copy of string)
+    GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Constructor for copy-string from a string object (i.e. do make a copy of string)
+    /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+     */
+    GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
+#endif
+
+    //! Destructor.
+    /*! Need to destruct elements of array, members of object, or copy-string.
+    */
+    ~GenericValue() {
+        if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+            switch(flags_) {
+            case kArrayFlag:
+                for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+                    v->~GenericValue();
+                Allocator::Free(data_.a.elements);
+                break;
+
+            case kObjectFlag:
+                for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+                    m->~Member();
+                Allocator::Free(data_.o.members);
+                break;
+
+            case kCopyStringFlag:
+                Allocator::Free(const_cast<Ch*>(data_.s.str));
+                break;
+
+            default:
+                break;  // Do nothing for other types.
+            }
+        }
+    }
+
+    //@}
+
+    //!@name Assignment operators
+    //@{
+
+    //! Assignment with move semantics.
+    /*! \param rhs Source of the assignment. It will become a null value after assignment.
+    */
+    GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+        RAPIDJSON_ASSERT(this != &rhs);
+        this->~GenericValue();
+        RawAssign(rhs);
+        return *this;
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move assignment in C++11
+    GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
+        return *this = rhs.Move();
+    }
+#endif
+
+    //! Assignment of constant string reference (no copy)
+    /*! \param str Constant string reference to be assigned
+        \note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
+        \see GenericStringRef, operator=(T)
+    */
+    GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
+        GenericValue s(str);
+        return *this = s;
+    }
+
+    //! Assignment with primitive types.
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+        \param value The value to be assigned.
+
+        \note The source type \c T explicitly disallows all pointer types,
+            especially (\c const) \ref Ch*.  This helps avoiding implicitly
+            referencing character strings with insufficient lifetime, use
+            \ref SetString(const Ch*, Allocator&) (for copying) or
+            \ref StringRef() (to explicitly mark the pointer as constant) instead.
+            All other pointer types would implicitly convert to \c bool,
+            use \ref SetBool() instead.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
+    operator=(T value) {
+        GenericValue v(value);
+        return *this = v;
+    }
+
+    //! Deep-copy assignment from Value
+    /*! Assigns a \b copy of the Value to the current Value object
+        \tparam SourceAllocator Allocator type of \c rhs
+        \param rhs Value to copy from (read-only)
+        \param allocator Allocator to use for copying
+     */
+    template <typename SourceAllocator>
+    GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
+        RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
+        this->~GenericValue();
+        new (this) GenericValue(rhs, allocator);
+        return *this;
+    }
+
+    //! Exchange the contents of this value with those of other.
+    /*!
+        \param other Another value.
+        \note Constant complexity.
+    */
+    GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
+        GenericValue temp;
+        temp.RawAssign(*this);
+        RawAssign(other);
+        other.RawAssign(temp);
+        return *this;
+    }
+
+    //! free-standing swap function helper
+    /*!
+        Helper function to enable support for common swap implementation pattern based on \c std::swap:
+        \code
+        void swap(MyClass& a, MyClass& b) {
+            using std::swap;
+            swap(a.value, b.value);
+            // ...
+        }
+        \endcode
+        \see Swap()
+     */
+    friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+    //! Prepare Value for move semantics
+    /*! \return *this */
+    GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
+    //@}
+
+    //!@name Equal-to and not-equal-to operators
+    //@{
+    //! Equal-to operator
+    /*!
+        \note If an object contains duplicated named member, comparing equality with any object is always \c false.
+        \note Linear time complexity (number of all values in the subtree and total lengths of all strings).
+    */
+    template <typename SourceAllocator>
+    bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+        typedef GenericValue<Encoding, SourceAllocator> RhsType;
+        if (GetType() != rhs.GetType())
+            return false;
+
+        switch (GetType()) {
+        case kObjectType: // Warning: O(n^2) inner-loop
+            if (data_.o.size != rhs.data_.o.size)
+                return false;           
+            for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
+                typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
+                if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
+                    return false;
+            }
+            return true;
+            
+        case kArrayType:
+            if (data_.a.size != rhs.data_.a.size)
+                return false;
+            for (SizeType i = 0; i < data_.a.size; i++)
+                if ((*this)[i] != rhs[i])
+                    return false;
+            return true;
+
+        case kStringType:
+            return StringEqual(rhs);
+
+        case kNumberType:
+            if (IsDouble() || rhs.IsDouble()) {
+                double a = GetDouble();     // May convert from integer to double.
+                double b = rhs.GetDouble(); // Ditto
+                return a >= b && a <= b;    // Prevent -Wfloat-equal
+            }
+            else
+                return data_.n.u64 == rhs.data_.n.u64;
+
+        default: // kTrueType, kFalseType, kNullType
+            return true;
+        }
+    }
+
+    //! Equal-to operator with const C-string pointer
+    bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Equal-to operator with string object
+    /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+     */
+    bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }
+#endif
+
+    //! Equal-to operator with primitive types
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
+    */
+    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
+
+    //! Not-equal-to operator
+    /*! \return !(*this == rhs)
+     */
+    template <typename SourceAllocator>
+    bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
+
+    //! Not-equal-to operator with const C-string pointer
+    bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
+
+    //! Not-equal-to operator with arbitrary types
+    /*! \return !(*this == rhs)
+     */
+    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
+
+    //! Equal-to operator with arbitrary types (symmetric version)
+    /*! \return (rhs == lhs)
+     */
+    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
+
+    //! Not-Equal-to operator with arbitrary types (symmetric version)
+    /*! \return !(rhs == lhs)
+     */
+    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
+    //@}
+
+    //!@name Type
+    //@{
+
+    Type GetType()  const { return static_cast<Type>(flags_ & kTypeMask); }
+    bool IsNull()   const { return flags_ == kNullFlag; }
+    bool IsFalse()  const { return flags_ == kFalseFlag; }
+    bool IsTrue()   const { return flags_ == kTrueFlag; }
+    bool IsBool()   const { return (flags_ & kBoolFlag) != 0; }
+    bool IsObject() const { return flags_ == kObjectFlag; }
+    bool IsArray()  const { return flags_ == kArrayFlag; }
+    bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
+    bool IsInt()    const { return (flags_ & kIntFlag) != 0; }
+    bool IsUint()   const { return (flags_ & kUintFlag) != 0; }
+    bool IsInt64()  const { return (flags_ & kInt64Flag) != 0; }
+    bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
+    bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
+    bool IsString() const { return (flags_ & kStringFlag) != 0; }
+
+    //@}
+
+    //!@name Null
+    //@{
+
+    GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+    //@}
+
+    //!@name Bool
+    //@{
+
+    bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
+    //!< Set boolean value
+    /*! \post IsBool() == true */
+    GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+    //@}
+
+    //!@name Object
+    //@{
+
+    //! Set this value as an empty object.
+    /*! \post IsObject() == true */
+    GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+    //! Get the number of members in the object.
+    SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
+
+    //! Check whether the object is empty.
+    bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
+
+    //! Get a value from an object associated with the name.
+    /*! \pre IsObject() == true
+        \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
+        \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
+        Since 0.2, if the name is not correct, it will assert.
+        If user is unsure whether a member exists, user should use HasMember() first.
+        A better approach is to use FindMember().
+        \note Linear time complexity.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
+        GenericValue n(StringRef(name));
+        return (*this)[n];
+    }
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+    //! Get a value from an object associated with the name.
+    /*! \pre IsObject() == true
+        \tparam SourceAllocator Allocator of the \c name value
+
+        \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
+        And it can also handle strings with embedded null characters.
+
+        \note Linear time complexity.
+    */
+    template <typename SourceAllocator>
+    GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
+        MemberIterator member = FindMember(name);
+        if (member != MemberEnd())
+            return member->value;
+        else {
+            RAPIDJSON_ASSERT(false);    // see above note
+            static GenericValue NullValue;
+            return NullValue;
+        }
+    }
+    template <typename SourceAllocator>
+    const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Get a value from an object associated with name (string object).
+    GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
+    const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
+#endif
+
+    //! Const member iterator
+    /*! \pre IsObject() == true */
+    ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
+    //! Const \em past-the-end member iterator
+    /*! \pre IsObject() == true */
+    ConstMemberIterator MemberEnd() const   { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); }
+    //! Member iterator
+    /*! \pre IsObject() == true */
+    MemberIterator MemberBegin()            { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); }
+    //! \em Past-the-end member iterator
+    /*! \pre IsObject() == true */
+    MemberIterator MemberEnd()              { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); }
+
+    //! Check whether a member exists in the object.
+    /*!
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Whether a member with that name exists.
+        \note It is better to use FindMember() directly if you need the obtain the value as well.
+        \note Linear time complexity.
+    */
+    bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Check whether a member exists in the object with string object.
+    /*!
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Whether a member with that name exists.
+        \note It is better to use FindMember() directly if you need the obtain the value as well.
+        \note Linear time complexity.
+    */
+    bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
+#endif
+
+    //! Check whether a member exists in the object with GenericValue name.
+    /*!
+        This version is faster because it does not need a StrLen(). It can also handle string with null character.
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Whether a member with that name exists.
+        \note It is better to use FindMember() directly if you need the obtain the value as well.
+        \note Linear time complexity.
+    */
+    template <typename SourceAllocator>
+    bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
+
+    //! Find member by name.
+    /*!
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Iterator to member, if it exists.
+            Otherwise returns \ref MemberEnd().
+
+        \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+            the requested member doesn't exist. For consistency with e.g.
+            \c std::map, this has been changed to MemberEnd() now.
+        \note Linear time complexity.
+    */
+    MemberIterator FindMember(const Ch* name) {
+        GenericValue n(StringRef(name));
+        return FindMember(n);
+    }
+
+    ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+    //! Find member by name.
+    /*!
+        This version is faster because it does not need a StrLen(). It can also handle string with null character.
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Iterator to member, if it exists.
+            Otherwise returns \ref MemberEnd().
+
+        \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+            the requested member doesn't exist. For consistency with e.g.
+            \c std::map, this has been changed to MemberEnd() now.
+        \note Linear time complexity.
+    */
+    template <typename SourceAllocator>
+    MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+        RAPIDJSON_ASSERT(IsObject());
+        RAPIDJSON_ASSERT(name.IsString());
+        MemberIterator member = MemberBegin();
+        for ( ; member != MemberEnd(); ++member)
+            if (name.StringEqual(member->name))
+                break;
+        return member;
+    }
+    template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Find member by string object name.
+    /*!
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Iterator to member, if it exists.
+            Otherwise returns \ref MemberEnd().
+    */
+    MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(StringRef(name)); }
+    ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(StringRef(name)); }
+#endif
+
+    //! Add a member (name-value pair) to the object.
+    /*! \param name A string value as name of member.
+        \param value Value of any type.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \note The ownership of \c name and \c value will be transferred to this object on success.
+        \pre  IsObject() && name.IsString()
+        \post name.IsNull() && value.IsNull()
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+        RAPIDJSON_ASSERT(IsObject());
+        RAPIDJSON_ASSERT(name.IsString());
+
+        Object& o = data_.o;
+        if (o.size >= o.capacity) {
+            if (o.capacity == 0) {
+                o.capacity = kDefaultObjectCapacity;
+                o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
+            }
+            else {
+                SizeType oldCapacity = o.capacity;
+                o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
+                o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));
+            }
+        }
+        o.members[o.size].name.RawAssign(name);
+        o.members[o.size].value.RawAssign(value);
+        o.size++;
+        return *this;
+    }
+
+    //! Add a constant string value as member (name-value pair) to the object.
+    /*! \param name A string value as name of member.
+        \param value constant string reference as value of member.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+        \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
+        GenericValue v(value);
+        return AddMember(name, v, allocator);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Add a string object as member (name-value pair) to the object.
+    /*! \param name A string value as name of member.
+        \param value constant string reference as value of member.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+        \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
+        GenericValue v(value, allocator);
+        return AddMember(name, v, allocator);
+    }
+#endif
+
+    //! Add any primitive value as member (name-value pair) to the object.
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+        \param name A string value as name of member.
+        \param value Value of primitive type \c T as value of member
+        \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+
+        \note The source type \c T explicitly disallows all pointer types,
+            especially (\c const) \ref Ch*.  This helps avoiding implicitly
+            referencing character strings with insufficient lifetime, use
+            \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+            AddMember(StringRefType, StringRefType, Allocator&).
+            All other pointer types would implicitly convert to \c bool,
+            use an explicit cast instead, if needed.
+        \note Amortized Constant time complexity.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+    AddMember(GenericValue& name, T value, Allocator& allocator) {
+        GenericValue v(value);
+        return AddMember(name, v, allocator);
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
+        return AddMember(name, value, allocator);
+    }
+    GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
+        return AddMember(name, value, allocator);
+    }
+    GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
+        return AddMember(name, value, allocator);
+    }
+    GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
+        GenericValue n(name);
+        return AddMember(n, value, allocator);
+    }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+
+    //! Add a member (name-value pair) to the object.
+    /*! \param name A constant string reference as name of member.
+        \param value Value of any type.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \note The ownership of \c value will be transferred to this object on success.
+        \pre  IsObject()
+        \post value.IsNull()
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
+        GenericValue n(name);
+        return AddMember(n, value, allocator);
+    }
+
+    //! Add a constant string value as member (name-value pair) to the object.
+    /*! \param name A constant string reference as name of member.
+        \param value constant string reference as value of member.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+        \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
+        GenericValue v(value);
+        return AddMember(name, v, allocator);
+    }
+
+    //! Add any primitive value as member (name-value pair) to the object.
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+        \param name A constant string reference as name of member.
+        \param value Value of primitive type \c T as value of member
+        \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+
+        \note The source type \c T explicitly disallows all pointer types,
+            especially (\c const) \ref Ch*.  This helps avoiding implicitly
+            referencing character strings with insufficient lifetime, use
+            \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+            AddMember(StringRefType, StringRefType, Allocator&).
+            All other pointer types would implicitly convert to \c bool,
+            use an explicit cast instead, if needed.
+        \note Amortized Constant time complexity.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+    AddMember(StringRefType name, T value, Allocator& allocator) {
+        GenericValue n(name);
+        return AddMember(n, value, allocator);
+    }
+
+    //! Remove all members in the object.
+    /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.
+        \note Linear time complexity.
+    */
+    void RemoveAllMembers() {
+        RAPIDJSON_ASSERT(IsObject()); 
+        for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+            m->~Member();
+        data_.o.size = 0;
+    }
+
+    //! Remove a member in object by its name.
+    /*! \param name Name of member to be removed.
+        \return Whether the member existed.
+        \note This function may reorder the object members. Use \ref
+            EraseMember(ConstMemberIterator) if you need to preserve the
+            relative order of the remaining members.
+        \note Linear time complexity.
+    */
+    bool RemoveMember(const Ch* name) {
+        GenericValue n(StringRef(name));
+        return RemoveMember(n);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
+#endif
+
+    template <typename SourceAllocator>
+    bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
+        MemberIterator m = FindMember(name);
+        if (m != MemberEnd()) {
+            RemoveMember(m);
+            return true;
+        }
+        else
+            return false;
+    }
+
+    //! Remove a member in object by iterator.
+    /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
+        \return the new iterator after removal.
+        \note This function may reorder the object members. Use \ref
+            EraseMember(ConstMemberIterator) if you need to preserve the
+            relative order of the remaining members.
+        \note Constant time complexity.
+    */
+    MemberIterator RemoveMember(MemberIterator m) {
+        RAPIDJSON_ASSERT(IsObject());
+        RAPIDJSON_ASSERT(data_.o.size > 0);
+        RAPIDJSON_ASSERT(data_.o.members != 0);
+        RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
+
+        MemberIterator last(data_.o.members + (data_.o.size - 1));
+        if (data_.o.size > 1 && m != last) {
+            // Move the last one to this place
+            *m = *last;
+        }
+        else {
+            // Only one left, just destroy
+            m->~Member();
+        }
+        --data_.o.size;
+        return m;
+    }
+
+    //! Remove a member from an object by iterator.
+    /*! \param pos iterator to the member to remove
+        \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
+        \return Iterator following the removed element.
+            If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
+        \note This function preserves the relative order of the remaining object
+            members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
+        \note Linear time complexity.
+    */
+    MemberIterator EraseMember(ConstMemberIterator pos) {
+        return EraseMember(pos, pos +1);
+    }
+
+    //! Remove members in the range [first, last) from an object.
+    /*! \param first iterator to the first member to remove
+        \param last  iterator following the last member to remove
+        \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
+        \return Iterator following the last removed element.
+        \note This function preserves the relative order of the remaining object
+            members.
+        \note Linear time complexity.
+    */
+    MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
+        RAPIDJSON_ASSERT(IsObject());
+        RAPIDJSON_ASSERT(data_.o.size > 0);
+        RAPIDJSON_ASSERT(data_.o.members != 0);
+        RAPIDJSON_ASSERT(first >= MemberBegin());
+        RAPIDJSON_ASSERT(first <= last);
+        RAPIDJSON_ASSERT(last <= MemberEnd());
+
+        MemberIterator pos = MemberBegin() + (first - MemberBegin());
+        for (MemberIterator itr = pos; itr != last; ++itr)
+            itr->~Member();
+        std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member));
+        data_.o.size -= (last - first);
+        return pos;
+    }
+
+    //! Erase a member in object by its name.
+    /*! \param name Name of member to be removed.
+        \return Whether the member existed.
+        \note Linear time complexity.
+    */
+    bool EraseMember(const Ch* name) {
+        GenericValue n(StringRef(name));
+        return EraseMember(n);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
+#endif
+
+    template <typename SourceAllocator>
+    bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
+        MemberIterator m = FindMember(name);
+        if (m != MemberEnd()) {
+            EraseMember(m);
+            return true;
+        }
+        else
+            return false;
+    }
+
+    //@}
+
+    //!@name Array
+    //@{
+
+    //! Set this value as an empty array.
+    /*! \post IsArray == true */
+    GenericValue& SetArray() {  this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+    //! Get the number of elements in array.
+    SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+    //! Get the capacity of array.
+    SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+    //! Check whether the array is empty.
+    bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+    //! Remove all elements in the array.
+    /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+        \note Linear time complexity.
+    */
+    void Clear() {
+        RAPIDJSON_ASSERT(IsArray()); 
+        for (SizeType i = 0; i < data_.a.size; ++i)
+            data_.a.elements[i].~GenericValue();
+        data_.a.size = 0;
+    }
+
+    //! Get an element from array by index.
+    /*! \pre IsArray() == true
+        \param index Zero-based index of element.
+        \see operator[](T*)
+    */
+    GenericValue& operator[](SizeType index) {
+        RAPIDJSON_ASSERT(IsArray());
+        RAPIDJSON_ASSERT(index < data_.a.size);
+        return data_.a.elements[index];
+    }
+    const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
+
+    //! Element iterator
+    /*! \pre IsArray() == true */
+    ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
+    //! \em Past-the-end element iterator
+    /*! \pre IsArray() == true */
+    ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
+    //! Constant element iterator
+    /*! \pre IsArray() == true */
+    ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
+    //! Constant \em past-the-end element iterator
+    /*! \pre IsArray() == true */
+    ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
+
+    //! Request the array to have enough capacity to store elements.
+    /*! \param newCapacity  The capacity that the array at least need to have.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \note Linear time complexity.
+    */
+    GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+        RAPIDJSON_ASSERT(IsArray());
+        if (newCapacity > data_.a.capacity) {
+            data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue));
+            data_.a.capacity = newCapacity;
+        }
+        return *this;
+    }
+
+    //! Append a GenericValue at the end of the array.
+    /*! \param value        Value to be appended.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \pre IsArray() == true
+        \post value.IsNull() == true
+        \return The value itself for fluent API.
+        \note The ownership of \c value will be transferred to this array on success.
+        \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+        \note Amortized constant time complexity.
+    */
+    GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+        RAPIDJSON_ASSERT(IsArray());
+        if (data_.a.size >= data_.a.capacity)
+            Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
+        data_.a.elements[data_.a.size++].RawAssign(value);
+        return *this;
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
+        return PushBack(value, allocator);
+    }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+    //! Append a constant string reference at the end of the array.
+    /*! \param value        Constant string reference to be appended.
+        \param allocator    Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
+        \pre IsArray() == true
+        \return The value itself for fluent API.
+        \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+        \note Amortized constant time complexity.
+        \see GenericStringRef
+    */
+    GenericValue& PushBack(StringRefType value, Allocator& allocator) {
+        return (*this).template PushBack<StringRefType>(value, allocator);
+    }
+
+    //! Append a primitive value at the end of the array.
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+        \param value Value of primitive type T to be appended.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \pre IsArray() == true
+        \return The value itself for fluent API.
+        \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+
+        \note The source type \c T explicitly disallows all pointer types,
+            especially (\c const) \ref Ch*.  This helps avoiding implicitly
+            referencing character strings with insufficient lifetime, use
+            \ref PushBack(GenericValue&, Allocator&) or \ref
+            PushBack(StringRefType, Allocator&).
+            All other pointer types would implicitly convert to \c bool,
+            use an explicit cast instead, if needed.
+        \note Amortized constant time complexity.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+    PushBack(T value, Allocator& allocator) {
+        GenericValue v(value);
+        return PushBack(v, allocator);
+    }
+
+    //! Remove the last element in the array.
+    /*!
+        \note Constant time complexity.
+    */
+    GenericValue& PopBack() {
+        RAPIDJSON_ASSERT(IsArray());
+        RAPIDJSON_ASSERT(!Empty());
+        data_.a.elements[--data_.a.size].~GenericValue();
+        return *this;
+    }
+
+    //! Remove an element of array by iterator.
+    /*!
+        \param pos iterator to the element to remove
+        \pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
+        \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
+        \note Linear time complexity.
+    */
+    ValueIterator Erase(ConstValueIterator pos) {
+        return Erase(pos, pos + 1);
+    }
+
+    //! Remove elements in the range [first, last) of the array.
+    /*!
+        \param first iterator to the first element to remove
+        \param last  iterator following the last element to remove
+        \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
+        \return Iterator following the last removed element.
+        \note Linear time complexity.
+    */
+    ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
+        RAPIDJSON_ASSERT(IsArray());
+        RAPIDJSON_ASSERT(data_.a.size > 0);
+        RAPIDJSON_ASSERT(data_.a.elements != 0);
+        RAPIDJSON_ASSERT(first >= Begin());
+        RAPIDJSON_ASSERT(first <= last);
+        RAPIDJSON_ASSERT(last <= End());
+        ValueIterator pos = Begin() + (first - Begin());
+        for (ValueIterator itr = pos; itr != last; ++itr)
+            itr->~GenericValue();       
+        std::memmove(pos, last, (End() - last) * sizeof(GenericValue));
+        data_.a.size -= (last - first);
+        return pos;
+    }
+
+    //@}
+
+    //!@name Number
+    //@{
+
+    int GetInt() const          { RAPIDJSON_ASSERT(flags_ & kIntFlag);   return data_.n.i.i;   }
+    unsigned GetUint() const    { RAPIDJSON_ASSERT(flags_ & kUintFlag);  return data_.n.u.u;   }
+    int64_t GetInt64() const    { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
+    uint64_t GetUint64() const  { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
+
+    double GetDouble() const {
+        RAPIDJSON_ASSERT(IsNumber());
+        if ((flags_ & kDoubleFlag) != 0)                return data_.n.d;   // exact type, no conversion.
+        if ((flags_ & kIntFlag) != 0)                   return data_.n.i.i; // int -> double
+        if ((flags_ & kUintFlag) != 0)                  return data_.n.u.u; // unsigned -> double
+        if ((flags_ & kInt64Flag) != 0)                 return (double)data_.n.i64; // int64_t -> double (may lose precision)
+        RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0);  return (double)data_.n.u64; // uint64_t -> double (may lose precision)
+    }
+
+    GenericValue& SetInt(int i)             { this->~GenericValue(); new (this) GenericValue(i);    return *this; }
+    GenericValue& SetUint(unsigned u)       { this->~GenericValue(); new (this) GenericValue(u);    return *this; }
+    GenericValue& SetInt64(int64_t i64)     { this->~GenericValue(); new (this) GenericValue(i64);  return *this; }
+    GenericValue& SetUint64(uint64_t u64)   { this->~GenericValue(); new (this) GenericValue(u64);  return *this; }
+    GenericValue& SetDouble(double d)       { this->~GenericValue(); new (this) GenericValue(d);    return *this; }
+
+    //@}
+
+    //!@name String
+    //@{
+
+    const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); }
+
+    //! Get the length of string.
+    /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+    */
+    SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
+
+    //! Set this value as a string without copying source string.
+    /*! This version has better performance with supplied length, and also support string containing null character.
+        \param s source string pointer. 
+        \param length The length of source string, excluding the trailing null terminator.
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() == s && GetStringLength() == length
+        \see SetString(StringRefType)
+    */
+    GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
+
+    //! Set this value as a string without copying source string.
+    /*! \param s source string reference
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() == s && GetStringLength() == s.length
+    */
+    GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
+
+    //! Set this value as a string by copying from source string.
+    /*! This version has better performance with supplied length, and also support string containing null character.
+        \param s source string. 
+        \param length The length of source string, excluding the trailing null terminator.
+        \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+    */
+    GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
+
+    //! Set this value as a string by copying from source string.
+    /*! \param s source string. 
+        \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+    */
+    GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Set this value as a string by copying from source string.
+    /*! \param s source string.
+        \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
+        \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+    */
+    GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
+#endif
+
+    //@}
+
+    //! Generate events of this value to a Handler.
+    /*! This function adopts the GoF visitor pattern.
+        Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+        It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+        \tparam Handler type of handler.
+        \param handler An object implementing concept Handler.
+    */
+    template <typename Handler>
+    bool Accept(Handler& handler) const {
+        switch(GetType()) {
+        case kNullType:     return handler.Null();
+        case kFalseType:    return handler.Bool(false);
+        case kTrueType:     return handler.Bool(true);
+
+        case kObjectType:
+            if (!handler.StartObject())
+                return false;
+            for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
+                RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
+                if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0))
+                    return false;
+                if (!m->value.Accept(handler))
+                    return false;
+            }
+            return handler.EndObject(data_.o.size);
+
+        case kArrayType:
+            if (!handler.StartArray())
+                return false;
+            for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+                if (!v->Accept(handler))
+                    return false;
+            return handler.EndArray(data_.a.size);
+    
+        case kStringType:
+            return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
+    
+        default:
+            RAPIDJSON_ASSERT(GetType() == kNumberType);
+            if (IsInt())            return handler.Int(data_.n.i.i);
+            else if (IsUint())      return handler.Uint(data_.n.u.u);
+            else if (IsInt64())     return handler.Int64(data_.n.i64);
+            else if (IsUint64())    return handler.Uint64(data_.n.u64);
+            else                    return handler.Double(data_.n.d);
+        }
+    }
+
+private:
+    template <typename, typename> friend class GenericValue;
+    template <typename, typename, typename> friend class GenericDocument;
+
+    enum {
+        kBoolFlag = 0x100,
+        kNumberFlag = 0x200,
+        kIntFlag = 0x400,
+        kUintFlag = 0x800,
+        kInt64Flag = 0x1000,
+        kUint64Flag = 0x2000,
+        kDoubleFlag = 0x4000,
+        kStringFlag = 0x100000,
+        kCopyFlag = 0x200000,
+        kInlineStrFlag = 0x400000,
+
+        // Initial flags of different types.
+        kNullFlag = kNullType,
+        kTrueFlag = kTrueType | kBoolFlag,
+        kFalseFlag = kFalseType | kBoolFlag,
+        kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+        kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+        kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+        kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+        kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+        kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
+        kConstStringFlag = kStringType | kStringFlag,
+        kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+        kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+        kObjectFlag = kObjectType,
+        kArrayFlag = kArrayType,
+
+        kTypeMask = 0xFF    // bitwise-and with mask of 0xFF can be optimized by compiler
+    };
+
+    static const SizeType kDefaultArrayCapacity = 16;
+    static const SizeType kDefaultObjectCapacity = 16;
+
+    struct String {
+        const Ch* str;
+        SizeType length;
+        unsigned hashcode;  //!< reserved
+    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
+    // (excluding the terminating zero) and store a value to determine the length of the contained
+    // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
+    // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
+    // the string terminator as well. For getting the string length back from that value just use
+    // "MaxSize - str[LenPos]".
+    // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode
+    // inline (for `UTF8`-encoded strings).
+    struct ShortString {
+        enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
+        Ch str[MaxChars];
+
+        inline static bool Usable(SizeType len) { return            (MaxSize >= len); }
+        inline void     SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize -  len); }
+        inline SizeType GetLength() const       { return  (SizeType)(MaxSize -  str[LenPos]); }
+    };  // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    // By using proper binary layout, retrieval of different integer types do not need conversions.
+    union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+        struct I {
+            int i;
+            char padding[4];
+        }i;
+        struct U {
+            unsigned u;
+            char padding2[4];
+        }u;
+#else
+        struct I {
+            char padding[4];
+            int i;
+        }i;
+        struct U {
+            char padding2[4];
+            unsigned u;
+        }u;
+#endif
+        int64_t i64;
+        uint64_t u64;
+        double d;
+    };  // 8 bytes
+
+    struct Object {
+        Member* members;
+        SizeType size;
+        SizeType capacity;
+    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    struct Array {
+        GenericValue* elements;
+        SizeType size;
+        SizeType capacity;
+    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    union Data {
+        String s;
+        ShortString ss;
+        Number n;
+        Object o;
+        Array a;
+    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    // Initialize this value as array with initial data, without calling destructor.
+    void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
+        flags_ = kArrayFlag;
+        if (count) {
+            data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue));
+            std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
+        }
+        else
+            data_.a.elements = NULL;
+        data_.a.size = data_.a.capacity = count;
+    }
+
+    //! Initialize this value as object with initial data, without calling destructor.
+    void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
+        flags_ = kObjectFlag;
+        if (count) {
+            data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member));
+            std::memcpy(data_.o.members, members, count * sizeof(Member));
+        }
+        else
+            data_.o.members = NULL;
+        data_.o.size = data_.o.capacity = count;
+    }
+
+    //! Initialize this value as constant string, without calling destructor.
+    void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
+        flags_ = kConstStringFlag;
+        data_.s.str = s;
+        data_.s.length = s.length;
+    }
+
+    //! Initialize this value as copy string with initial data, without calling destructor.
+    void SetStringRaw(StringRefType s, Allocator& allocator) {
+        Ch* str = NULL;
+        if(ShortString::Usable(s.length)) {
+            flags_ = kShortStringFlag;
+            data_.ss.SetLength(s.length);
+            str = data_.ss.str;
+        } else {
+            flags_ = kCopyStringFlag;
+            data_.s.length = s.length;
+            str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch));
+            data_.s.str = str;
+        }
+        std::memcpy(str, s, s.length * sizeof(Ch));
+        str[s.length] = '\0';
+    }
+
+    //! Assignment without calling destructor
+    void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+        data_ = rhs.data_;
+        flags_ = rhs.flags_;
+        rhs.flags_ = kNullFlag;
+    }
+
+    template <typename SourceAllocator>
+    bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+        RAPIDJSON_ASSERT(IsString());
+        RAPIDJSON_ASSERT(rhs.IsString());
+
+        const SizeType len1 = GetStringLength();
+        const SizeType len2 = rhs.GetStringLength();
+        if(len1 != len2) { return false; }
+
+        const Ch* const str1 = GetString();
+        const Ch* const str2 = rhs.GetString();
+        if(str1 == str2) { return true; } // fast path for constant string
+
+        return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
+    }
+
+    Data data_;
+    unsigned flags_;
+};
+
+//! GenericValue with UTF8 encoding
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument 
+
+//! A document for parsing JSON text as DOM.
+/*!
+    \note implements Handler concept
+    \tparam Encoding Encoding for both parsing and string storage.
+    \tparam Allocator Allocator for allocating memory for the DOM
+    \tparam StackAllocator Allocator for allocating memory for stack during parsing.
+    \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor.  To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+public:
+    typedef typename Encoding::Ch Ch;                       //!< Character type derived from Encoding.
+    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of the document.
+    typedef Allocator AllocatorType;                        //!< Allocator type from template parameter.
+
+    //! Constructor
+    /*! Creates an empty document of specified type.
+        \param type             Mandatory type of object to create.
+        \param allocator        Optional allocator for allocating memory.
+        \param stackCapacity    Optional initial capacity of stack in bytes.
+        \param stackAllocator   Optional allocator for allocating memory for stack.
+    */
+    explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
+        GenericValue<Encoding, Allocator>(type),  allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+    {
+        if (!allocator_)
+            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+    }
+
+    //! Constructor
+    /*! Creates an empty document which type is Null. 
+        \param allocator        Optional allocator for allocating memory.
+        \param stackCapacity    Optional initial capacity of stack in bytes.
+        \param stackAllocator   Optional allocator for allocating memory for stack.
+    */
+    GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : 
+        allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+    {
+        if (!allocator_)
+            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move constructor in C++11
+    GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+        : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
+          allocator_(rhs.allocator_),
+          ownAllocator_(rhs.ownAllocator_),
+          stack_(std::move(rhs.stack_)),
+          parseResult_(rhs.parseResult_)
+    {
+        rhs.allocator_ = 0;
+        rhs.ownAllocator_ = 0;
+        rhs.parseResult_ = ParseResult();
+    }
+#endif
+
+    ~GenericDocument() {
+        Destroy();
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move assignment in C++11
+    GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+    {
+        // The cast to ValueType is necessary here, because otherwise it would
+        // attempt to call GenericValue's templated assignment operator.
+        ValueType::operator=(std::forward<ValueType>(rhs));
+
+        // Calling the destructor here would prematurely call stack_'s destructor
+        Destroy();
+
+        allocator_ = rhs.allocator_;
+        ownAllocator_ = rhs.ownAllocator_;
+        stack_ = std::move(rhs.stack_);
+        parseResult_ = rhs.parseResult_;
+
+        rhs.allocator_ = 0;
+        rhs.ownAllocator_ = 0;
+        rhs.parseResult_ = ParseResult();
+
+        return *this;
+    }
+#endif
+
+    //! Exchange the contents of this document with those of another.
+    /*!
+        \param other Another document.
+        \note Constant complexity.
+        \see GenericValue::Swap
+    */
+    GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
+        ValueType::Swap(rhs);
+        stack_.Swap(rhs.stack_);
+        internal::Swap(allocator_, rhs.allocator_);
+        internal::Swap(ownAllocator_, rhs.ownAllocator_);
+        internal::Swap(parseResult_, rhs.parseResult_);
+        return *this;
+    }
+
+    //! free-standing swap function helper
+    /*!
+        Helper function to enable support for common swap implementation pattern based on \c std::swap:
+        \code
+        void swap(MyClass& a, MyClass& b) {
+            using std::swap;
+            swap(a.doc, b.doc);
+            // ...
+        }
+        \endcode
+        \see Swap()
+     */
+    friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+    //!@name Parse from stream
+    //!@{
+
+    //! Parse JSON text from an input stream (with Encoding conversion)
+    /*! \tparam parseFlags Combination of \ref ParseFlag.
+        \tparam SourceEncoding Encoding of input stream
+        \tparam InputStream Type of input stream, implementing Stream concept
+        \param is Input stream to be parsed.
+        \return The document itself for fluent API.
+    */
+    template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+    GenericDocument& ParseStream(InputStream& is) {
+        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
+            stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
+        ClearStackOnExit scope(*this);
+        parseResult_ = reader.template Parse<parseFlags>(is, *this);
+        if (parseResult_) {
+            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
+        }
+        return *this;
+    }
+
+    //! Parse JSON text from an input stream
+    /*! \tparam parseFlags Combination of \ref ParseFlag.
+        \tparam InputStream Type of input stream, implementing Stream concept
+        \param is Input stream to be parsed.
+        \return The document itself for fluent API.
+    */
+    template <unsigned parseFlags, typename InputStream>
+    GenericDocument& ParseStream(InputStream& is) {
+        return ParseStream<parseFlags, Encoding, InputStream>(is);
+    }
+
+    //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
+    /*! \tparam InputStream Type of input stream, implementing Stream concept
+        \param is Input stream to be parsed.
+        \return The document itself for fluent API.
+    */
+    template <typename InputStream>
+    GenericDocument& ParseStream(InputStream& is) {
+        return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
+    }
+    //!@}
+
+    //!@name Parse in-place from mutable string
+    //!@{
+
+    //! Parse JSON text from a mutable string
+    /*! \tparam parseFlags Combination of \ref ParseFlag.
+        \param str Mutable zero-terminated string to be parsed.
+        \return The document itself for fluent API.
+    */
+    template <unsigned parseFlags>
+    GenericDocument& ParseInsitu(Ch* str) {
+        GenericInsituStringStream<Encoding> s(str);
+        return ParseStream<parseFlags | kParseInsituFlag>(s);
+    }
+
+    //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
+    /*! \param str Mutable zero-terminated string to be parsed.
+        \return The document itself for fluent API.
+    */
+    GenericDocument& ParseInsitu(Ch* str) {
+        return ParseInsitu<kParseDefaultFlags>(str);
+    }
+    //!@}
+
+    //!@name Parse from read-only string
+    //!@{
+
+    //! Parse JSON text from a read-only string (with Encoding conversion)
+    /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+        \tparam SourceEncoding Transcoding from input Encoding
+        \param str Read-only zero-terminated string to be parsed.
+    */
+    template <unsigned parseFlags, typename SourceEncoding>
+    GenericDocument& Parse(const Ch* str) {
+        RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+        GenericStringStream<SourceEncoding> s(str);
+        return ParseStream<parseFlags, SourceEncoding>(s);
+    }
+
+    //! Parse JSON text from a read-only string
+    /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+        \param str Read-only zero-terminated string to be parsed.
+    */
+    template <unsigned parseFlags>
+    GenericDocument& Parse(const Ch* str) {
+        return Parse<parseFlags, Encoding>(str);
+    }
+
+    //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
+    /*! \param str Read-only zero-terminated string to be parsed.
+    */
+    GenericDocument& Parse(const Ch* str) {
+        return Parse<kParseDefaultFlags>(str);
+    }
+    //!@}
+
+    //!@name Handling parse errors
+    //!@{
+
+    //! Whether a parse error has occured in the last parsing.
+    bool HasParseError() const { return parseResult_.IsError(); }
+
+    //! Get the \ref ParseErrorCode of last parsing.
+    ParseErrorCode GetParseError() const { return parseResult_.Code(); }
+
+    //! Get the position of last parsing error in input, 0 otherwise.
+    size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+    //!@}
+
+    //! Get the allocator of this document.
+    Allocator& GetAllocator() {
+        RAPIDJSON_ASSERT(allocator_);
+        return *allocator_;
+    }
+
+    //! Get the capacity of stack in bytes.
+    size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+private:
+    // clear stack on any exit from ParseStream, e.g. due to exception
+    struct ClearStackOnExit {
+        explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
+        ~ClearStackOnExit() { d_.ClearStack(); }
+    private:
+        ClearStackOnExit(const ClearStackOnExit&);
+        ClearStackOnExit& operator=(const ClearStackOnExit&);
+        GenericDocument& d_;
+    };
+
+    // callers of the following private Handler functions
+    template <typename,typename,typename> friend class GenericReader; // for parsing
+    template <typename, typename> friend class GenericValue; // for deep copying
+
+    // Implementation of Handler
+    bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
+    bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
+    bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+    bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+    bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+    bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+    bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
+
+    bool String(const Ch* str, SizeType length, bool copy) { 
+        if (copy) 
+            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+        else
+            new (stack_.template Push<ValueType>()) ValueType(str, length);
+        return true;
+    }
+
+    bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
+    
+    bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
+
+    bool EndObject(SizeType memberCount) {
+        typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+        stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
+        return true;
+    }
+
+    bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
+    
+    bool EndArray(SizeType elementCount) {
+        ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+        stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+        return true;
+    }
+
+private:
+    //! Prohibit copying
+    GenericDocument(const GenericDocument&);
+    //! Prohibit assignment
+    GenericDocument& operator=(const GenericDocument&);
+
+    void ClearStack() {
+        if (Allocator::kNeedFree)
+            while (stack_.GetSize() > 0)    // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
+                (stack_.template Pop<ValueType>(1))->~ValueType();
+        else
+            stack_.Clear();
+        stack_.ShrinkToFit();
+    }
+
+    void Destroy() {
+        RAPIDJSON_DELETE(ownAllocator_);
+    }
+
+    static const size_t kDefaultStackCapacity = 1024;
+    Allocator* allocator_;
+    Allocator* ownAllocator_;
+    internal::Stack<StackAllocator> stack_;
+    ParseResult parseResult_;
+};
+
+//! GenericDocument with UTF8 encoding
+typedef GenericDocument<UTF8<> > Document;
+
+// defined here due to the dependency on GenericDocument
+template <typename Encoding, typename Allocator>
+template <typename SourceAllocator>
+inline
+GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
+{
+    switch (rhs.GetType()) {
+    case kObjectType:
+    case kArrayType: { // perform deep copy via SAX Handler
+            GenericDocument<Encoding,Allocator> d(&allocator);
+            rhs.Accept(d);
+            RawAssign(*d.stack_.template Pop<GenericValue>(1));
+        }
+        break;
+    case kStringType:
+        if (rhs.flags_ == kConstStringFlag) {
+            flags_ = rhs.flags_;
+            data_  = *reinterpret_cast<const Data*>(&rhs.data_);
+        } else {
+            SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
+        }
+        break;
+    default: // kNumberType, kTrueType, kFalseType, kNullType
+        flags_ = rhs.flags_;
+        data_  = *reinterpret_cast<const Data*>(&rhs.data_);
+        break;
+    }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(_MSC_VER) || defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_DOCUMENT_H_

+ 261 - 0
contrib/rapidjson/include/rapidjson/encodedstream.h

@@ -0,0 +1,261 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODEDSTREAM_H_
+#define RAPIDJSON_ENCODEDSTREAM_H_
+
+#include "rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Input byte stream wrapper with a statically bound encoding.
+/*!
+    \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+    \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
+*/
+template <typename Encoding, typename InputByteStream>
+class EncodedInputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+    typedef typename Encoding::Ch Ch;
+
+    EncodedInputStream(InputByteStream& is) : is_(is) { 
+        current_ = Encoding::TakeBOM(is_);
+    }
+
+    Ch Peek() const { return current_; }
+    Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
+    size_t Tell() const { return is_.Tell(); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    EncodedInputStream(const EncodedInputStream&);
+    EncodedInputStream& operator=(const EncodedInputStream&);
+
+    InputByteStream& is_;
+    Ch current_;
+};
+
+//! Output byte stream wrapper with statically bound encoding.
+/*!
+    \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+    \tparam InputByteStream Type of input byte stream. For example, FileWriteStream.
+*/
+template <typename Encoding, typename OutputByteStream>
+class EncodedOutputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+    typedef typename Encoding::Ch Ch;
+
+    EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { 
+        if (putBOM)
+            Encoding::PutBOM(os_);
+    }
+
+    void Put(Ch c) { Encoding::Put(os_, c);  }
+    void Flush() { os_.Flush(); }
+
+    // Not implemented
+    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+    size_t Tell() const { RAPIDJSON_ASSERT(false);  return 0; }
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    EncodedOutputStream(const EncodedOutputStream&);
+    EncodedOutputStream& operator=(const EncodedOutputStream&);
+
+    OutputByteStream& os_;
+};
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+    \tparam CharType Type of character for reading.
+    \tparam InputByteStream type of input byte stream to be wrapped.
+*/
+template <typename CharType, typename InputByteStream>
+class AutoUTFInputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+    typedef CharType Ch;
+
+    //! Constructor.
+    /*!
+        \param is input stream to be wrapped.
+        \param type UTF encoding type if it is not detected from the stream.
+    */
+    AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
+        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);        
+        DetectType();
+        static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
+        takeFunc_ = f[type_];
+        current_ = takeFunc_(*is_);
+    }
+
+    UTFType GetType() const { return type_; }
+    bool HasBOM() const { return hasBOM_; }
+
+    Ch Peek() const { return current_; }
+    Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
+    size_t Tell() const { return is_->Tell(); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    AutoUTFInputStream(const AutoUTFInputStream&);
+    AutoUTFInputStream& operator=(const AutoUTFInputStream&);
+
+    // Detect encoding type with BOM or RFC 4627
+    void DetectType() {
+        // BOM (Byte Order Mark):
+        // 00 00 FE FF  UTF-32BE
+        // FF FE 00 00  UTF-32LE
+        // FE FF        UTF-16BE
+        // FF FE        UTF-16LE
+        // EF BB BF     UTF-8
+
+        const unsigned char* c = (const unsigned char *)is_->Peek4();
+        if (!c)
+            return;
+
+        unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
+        hasBOM_ = false;
+        if (bom == 0xFFFE0000)                  { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+        else if (bom == 0x0000FEFF)             { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+        else if ((bom & 0xFFFF) == 0xFFFE)      { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take();                           }
+        else if ((bom & 0xFFFF) == 0xFEFF)      { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take();                           }
+        else if ((bom & 0xFFFFFF) == 0xBFBBEF)  { type_ = kUTF8;    hasBOM_ = true; is_->Take(); is_->Take(); is_->Take();              }
+
+        // RFC 4627: Section 3
+        // "Since the first two characters of a JSON text will always be ASCII
+        // characters [RFC0020], it is possible to determine whether an octet
+        // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
+        // at the pattern of nulls in the first four octets."
+        // 00 00 00 xx  UTF-32BE
+        // 00 xx 00 xx  UTF-16BE
+        // xx 00 00 00  UTF-32LE
+        // xx 00 xx 00  UTF-16LE
+        // xx xx xx xx  UTF-8
+
+        if (!hasBOM_) {
+            unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
+            switch (pattern) {
+            case 0x08: type_ = kUTF32BE; break;
+            case 0x0A: type_ = kUTF16BE; break;
+            case 0x01: type_ = kUTF32LE; break;
+            case 0x05: type_ = kUTF16LE; break;
+            case 0x0F: type_ = kUTF8;    break;
+            default: break; // Use type defined by user.
+            }
+        }
+
+        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+    }
+
+    typedef Ch (*TakeFunc)(InputByteStream& is);
+    InputByteStream* is_;
+    UTFType type_;
+    Ch current_;
+    TakeFunc takeFunc_;
+    bool hasBOM_;
+};
+
+//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+    \tparam CharType Type of character for writing.
+    \tparam InputByteStream type of output byte stream to be wrapped.
+*/
+template <typename CharType, typename OutputByteStream>
+class AutoUTFOutputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+    typedef CharType Ch;
+
+    //! Constructor.
+    /*!
+        \param os output stream to be wrapped.
+        \param type UTF encoding type.
+        \param putBOM Whether to write BOM at the beginning of the stream.
+    */
+    AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
+        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+
+        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+
+        static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
+        putFunc_ = f[type_];
+
+        if (putBOM)
+            PutBOM();
+    }
+
+    UTFType GetType() const { return type_; }
+
+    void Put(Ch c) { putFunc_(*os_, c); }
+    void Flush() { os_->Flush(); } 
+
+    // Not implemented
+    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    AutoUTFOutputStream(const AutoUTFOutputStream&);
+    AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
+
+    void PutBOM() { 
+        typedef void (*PutBOMFunc)(OutputByteStream&);
+        static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
+        f[type_](*os_);
+    }
+
+    typedef void (*PutFunc)(OutputByteStream&, Ch);
+
+    OutputByteStream* os_;
+    UTFType type_;
+    PutFunc putFunc_;
+};
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_

+ 625 - 0
contrib/rapidjson/include/rapidjson/encodings.h

@@ -0,0 +1,625 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODINGS_H_
+#define RAPIDJSON_ENCODINGS_H_
+
+#include "rapidjson.h"
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
+RAPIDJSON_DIAG_OFF(4702)  // unreachable code
+#elif defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(overflow)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+    \brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+    typename Ch;    //! Type of character. A "character" is actually a code unit in unicode's definition.
+
+    enum { supportUnicode = 1 }; // or 0 if not supporting unicode
+
+    //! \brief Encode a Unicode codepoint to an output stream.
+    //! \param os Output stream.
+    //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint);
+
+    //! \brief Decode a Unicode codepoint from an input stream.
+    //! \param is Input stream.
+    //! \param codepoint Output of the unicode codepoint.
+    //! \return true if a valid codepoint can be decoded from the stream.
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint);
+
+    //! \brief Validate one Unicode codepoint from an encoded stream.
+    //! \param is Input stream to obtain codepoint.
+    //! \param os Output for copying one codepoint.
+    //! \return true if it is valid.
+    //! \note This function just validating and copying the codepoint without actually decode it.
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os);
+
+    // The following functions are deal with byte streams.
+
+    //! Take a character from input byte stream, skip BOM if exist.
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is);
+
+    //! Take a character from input byte stream.
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is);
+
+    //! Put BOM to output byte stream.
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os);
+
+    //! Put a character to output byte stream.
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+    http://tools.ietf.org/html/rfc3629
+    \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
+    \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct UTF8 {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        if (codepoint <= 0x7F) 
+            os.Put(static_cast<Ch>(codepoint & 0xFF));
+        else if (codepoint <= 0x7FF) {
+            os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+        }
+        else if (codepoint <= 0xFFFF) {
+            os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
+#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+        Ch c = is.Take();
+        if (!(c & 0x80)) {
+            *codepoint = (unsigned char)c;
+            return true;
+        }
+
+        unsigned char type = GetRange((unsigned char)c);
+        *codepoint = (0xFF >> type) & (unsigned char)c;
+        bool result = true;
+        switch (type) {
+        case 2: TAIL(); return result;
+        case 3: TAIL(); TAIL(); return result;
+        case 4: COPY(); TRANS(0x50); TAIL(); return result;
+        case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+        case 6: TAIL(); TAIL(); TAIL(); return result;
+        case 10: COPY(); TRANS(0x20); TAIL(); return result;
+        case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+        default: return false;
+        }
+#undef COPY
+#undef TRANS
+#undef TAIL
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+#define COPY() os.Put(c = is.Take())
+#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+        Ch c;
+        COPY();
+        if (!(c & 0x80))
+            return true;
+
+        bool result = true;
+        switch (GetRange((unsigned char)c)) {
+        case 2: TAIL(); return result;
+        case 3: TAIL(); TAIL(); return result;
+        case 4: COPY(); TRANS(0x50); TAIL(); return result;
+        case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+        case 6: TAIL(); TAIL(); TAIL(); return result;
+        case 10: COPY(); TRANS(0x20); TAIL(); return result;
+        case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+        default: return false;
+        }
+#undef COPY
+#undef TRANS
+#undef TAIL
+    }
+
+    static unsigned char GetRange(unsigned char c) {
+        // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+        // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
+        static const unsigned char type[] = {
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+            0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+            8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+            10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+        };
+        return type[c];
+    }
+
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        Ch c = Take(is);
+        if ((unsigned char)c != 0xEFu) return c;
+        c = is.Take();
+        if ((unsigned char)c != 0xBBu) return c;
+        c = is.Take();
+        if ((unsigned char)c != 0xBFu) return c;
+        c = is.Take();
+        return c;
+    }
+
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        return is.Take();
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(c));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+    http://tools.ietf.org/html/rfc2781
+    \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+    \note implements Encoding concept
+
+    \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+    For streaming, use UTF16LE and UTF16BE, which handle endianness.
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+    typedef CharType Ch;
+    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+        if (codepoint <= 0xFFFF) {
+            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair 
+            os.Put(static_cast<typename OutputStream::Ch>(codepoint));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            unsigned v = codepoint - 0x10000;
+            os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+            os.Put((v & 0x3FF) | 0xDC00);
+        }
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+        Ch c = is.Take();
+        if (c < 0xD800 || c > 0xDFFF) {
+            *codepoint = c;
+            return true;
+        }
+        else if (c <= 0xDBFF) {
+            *codepoint = (c & 0x3FF) << 10;
+            c = is.Take();
+            *codepoint |= (c & 0x3FF);
+            *codepoint += 0x10000;
+            return c >= 0xDC00 && c <= 0xDFFF;
+        }
+        return false;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+        Ch c;
+        os.Put(c = is.Take());
+        if (c < 0xD800 || c > 0xDFFF)
+            return true;
+        else if (c <= 0xDBFF) {
+            os.Put(c = is.Take());
+            return c >= 0xDC00 && c <= 0xDFFF;
+        }
+        return false;
+    }
+};
+
+//! UTF-16 little endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16LE : UTF16<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return (unsigned short)c == 0xFEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = (unsigned char)is.Take();
+        c |= (unsigned char)is.Take() << 8;
+        return c;
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(0xFFu); os.Put(0xFEu);
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(c & 0xFFu);
+        os.Put((c >> 8) & 0xFFu);
+    }
+};
+
+//! UTF-16 big endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16BE : UTF16<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return (unsigned short)c == 0xFEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = (unsigned char)is.Take() << 8;
+        c |= (unsigned char)is.Take();
+        return c;
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(0xFEu); os.Put(0xFFu);
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put((c >> 8) & 0xFFu);
+        os.Put(c & 0xFFu);
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding. 
+/*! http://en.wikipedia.org/wiki/UTF-32
+    \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+    \note implements Encoding concept
+
+    \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+    For streaming, use UTF32LE and UTF32BE, which handle endianness.
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+    typedef CharType Ch;
+    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+        os.Put(codepoint);
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+        Ch c = is.Take();
+        *codepoint = c;
+        return c <= 0x10FFFF;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+        Ch c;
+        os.Put(c = is.Take());
+        return c <= 0x10FFFF;
+    }
+};
+
+//! UTF-32 little endian enocoding.
+template<typename CharType = unsigned>
+struct UTF32LE : UTF32<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = (unsigned char)is.Take();
+        c |= (unsigned char)is.Take() << 8;
+        c |= (unsigned char)is.Take() << 16;
+        c |= (unsigned char)is.Take() << 24;
+        return c;
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(c & 0xFFu);
+        os.Put((c >> 8) & 0xFFu);
+        os.Put((c >> 16) & 0xFFu);
+        os.Put((c >> 24) & 0xFFu);
+    }
+};
+
+//! UTF-32 big endian encoding.
+template<typename CharType = unsigned>
+struct UTF32BE : UTF32<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return (unsigned)c == 0x0000FEFFu ? Take(is) : c; 
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = (unsigned char)is.Take() << 24;
+        c |= (unsigned char)is.Take() << 16;
+        c |= (unsigned char)is.Take() << 8;
+        c |= (unsigned char)is.Take();
+        return c;
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put((c >> 24) & 0xFFu);
+        os.Put((c >> 16) & 0xFFu);
+        os.Put((c >> 8) & 0xFFu);
+        os.Put(c & 0xFFu);
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ASCII
+
+//! ASCII encoding.
+/*! http://en.wikipedia.org/wiki/ASCII
+    \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
+    \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct ASCII {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 0 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_ASSERT(codepoint <= 0x7F);
+        os.Put(static_cast<Ch>(codepoint & 0xFF));
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        unsigned char c = static_cast<unsigned char>(is.Take());
+        *codepoint = c;
+        return c <= 0X7F;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        unsigned char c = is.Take();
+        os.Put(c);
+        return c <= 0x7F;
+    }
+
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        Ch c = Take(is);
+        return c;
+    }
+
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        return is.Take();
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        (void)os;
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(c));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// AutoUTF
+
+//! Runtime-specified UTF encoding type of a stream.
+enum UTFType {
+    kUTF8 = 0,      //!< UTF-8.
+    kUTF16LE = 1,   //!< UTF-16 little endian.
+    kUTF16BE = 2,   //!< UTF-16 big endian.
+    kUTF32LE = 3,   //!< UTF-32 little endian.
+    kUTF32BE = 4    //!< UTF-32 big endian.
+};
+
+//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
+/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
+*/
+template<typename CharType>
+struct AutoUTF {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 1 };
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+    template<typename OutputStream>
+    RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
+        typedef void (*EncodeFunc)(OutputStream&, unsigned);
+        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
+        (*f[os.GetType()])(os, codepoint);
+    }
+
+    template <typename InputStream>
+    RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
+        typedef bool (*DecodeFunc)(InputStream&, unsigned*);
+        static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
+        return (*f[is.GetType()])(is, codepoint);
+    }
+
+    template <typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+        typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
+        static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
+        return (*f[is.GetType()])(is, os);
+    }
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Transcoder
+
+//! Encoding conversion.
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder {
+    //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+        unsigned codepoint;
+        if (!SourceEncoding::Decode(is, &codepoint))
+            return false;
+        TargetEncoding::Encode(os, codepoint);
+        return true;
+    }
+
+    //! Validate one Unicode codepoint from an encoded stream.
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+        return Transcode(is, os);   // Since source/target encoding is different, must transcode.
+    }
+};
+
+//! Specialization of Transcoder with same source and target encoding.
+template<typename Encoding>
+struct Transcoder<Encoding, Encoding> {
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+        os.Put(is.Take());  // Just copy one code unit. This semantic is different from primary template class.
+        return true;
+    }
+    
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+        return Encoding::Validate(is, os);  // source/target encoding are the same
+    }
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__GNUC__) || defined(_MSV_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ENCODINGS_H_

+ 65 - 0
contrib/rapidjson/include/rapidjson/error/en.h

@@ -0,0 +1,65 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_EN_H__
+#define RAPIDJSON_ERROR_EN_H__
+
+#include "error.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Maps error code of parsing into error message.
+/*!
+    \ingroup RAPIDJSON_ERRORS
+    \param parseErrorCode Error code obtained in parsing.
+    \return the error message.
+    \note User can make a copy of this function for localization.
+        Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
+    switch (parseErrorCode) {
+        case kParseErrorNone:                           return RAPIDJSON_ERROR_STRING("No error.");
+
+        case kParseErrorDocumentEmpty:                  return RAPIDJSON_ERROR_STRING("The document is empty.");
+        case kParseErrorDocumentRootNotSingular:        return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
+    
+        case kParseErrorValueInvalid:                   return RAPIDJSON_ERROR_STRING("Invalid value.");
+    
+        case kParseErrorObjectMissName:                 return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
+        case kParseErrorObjectMissColon:                return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
+        case kParseErrorObjectMissCommaOrCurlyBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
+    
+        case kParseErrorArrayMissCommaOrSquareBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
+
+        case kParseErrorStringUnicodeEscapeInvalidHex:  return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
+        case kParseErrorStringUnicodeSurrogateInvalid:  return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
+        case kParseErrorStringEscapeInvalid:            return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
+        case kParseErrorStringMissQuotationMark:        return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
+        case kParseErrorStringInvalidEncoding:          return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
+
+        case kParseErrorNumberTooBig:                   return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
+        case kParseErrorNumberMissFraction:             return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
+        case kParseErrorNumberMissExponent:             return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
+
+        case kParseErrorTermination:                    return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
+        case kParseErrorUnspecificSyntaxError:          return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
+
+        default:
+            return RAPIDJSON_ERROR_STRING("Unknown error.");
+    }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ERROR_EN_H__

+ 146 - 0
contrib/rapidjson/include/rapidjson/error/error.h

@@ -0,0 +1,146 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_ERROR_H__
+#define RAPIDJSON_ERROR_ERROR_H__
+
+#include "../rapidjson.h"
+
+/*! \file error.h */
+
+/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_CHARTYPE
+
+//! Character type of error messages.
+/*! \ingroup RAPIDJSON_ERRORS
+    The default character type is \c char.
+    On Windows, user can define this macro as \c TCHAR for supporting both
+    unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_CHARTYPE
+#define RAPIDJSON_ERROR_CHARTYPE char
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_STRING
+
+//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+/*! \ingroup RAPIDJSON_ERRORS
+    By default this conversion macro does nothing.
+    On Windows, user can define this macro as \c _T(x) for supporting both
+    unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_STRING
+#define RAPIDJSON_ERROR_STRING(x) x
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseErrorCode
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+    \see GenericReader::Parse, GenericReader::GetParseErrorCode
+*/
+enum ParseErrorCode {
+    kParseErrorNone = 0,                        //!< No error.
+
+    kParseErrorDocumentEmpty,                   //!< The document is empty.
+    kParseErrorDocumentRootNotSingular,         //!< The document root must not follow by other values.
+
+    kParseErrorValueInvalid,                    //!< Invalid value.
+
+    kParseErrorObjectMissName,                  //!< Missing a name for object member.
+    kParseErrorObjectMissColon,                 //!< Missing a colon after a name of object member.
+    kParseErrorObjectMissCommaOrCurlyBracket,   //!< Missing a comma or '}' after an object member.
+
+    kParseErrorArrayMissCommaOrSquareBracket,   //!< Missing a comma or ']' after an array element.
+
+    kParseErrorStringUnicodeEscapeInvalidHex,   //!< Incorrect hex digit after \\u escape in string.
+    kParseErrorStringUnicodeSurrogateInvalid,   //!< The surrogate pair in string is invalid.
+    kParseErrorStringEscapeInvalid,             //!< Invalid escape character in string.
+    kParseErrorStringMissQuotationMark,         //!< Missing a closing quotation mark in string.
+    kParseErrorStringInvalidEncoding,           //!< Invalid encoding in string.
+
+    kParseErrorNumberTooBig,                    //!< Number too big to be stored in double.
+    kParseErrorNumberMissFraction,              //!< Miss fraction part in number.
+    kParseErrorNumberMissExponent,              //!< Miss exponent in number.
+
+    kParseErrorTermination,                     //!< Parsing was terminated.
+    kParseErrorUnspecificSyntaxError            //!< Unspecific syntax error.
+};
+
+//! Result of parsing (wraps ParseErrorCode)
+/*!
+    \ingroup RAPIDJSON_ERRORS
+    \code
+        Document doc;
+        ParseResult ok = doc.Parse("[42]");
+        if (!ok) {
+            fprintf(stderr, "JSON parse error: %s (%u)",
+                    GetParseError_En(ok.Code()), ok.Offset());
+            exit(EXIT_FAILURE);
+        }
+    \endcode
+    \see GenericReader::Parse, GenericDocument::Parse
+*/
+struct ParseResult {
+
+    //! Default constructor, no error.
+    ParseResult() : code_(kParseErrorNone), offset_(0) {}
+    //! Constructor to set an error.
+    ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
+
+    //! Get the error code.
+    ParseErrorCode Code() const { return code_; }
+    //! Get the error offset, if \ref IsError(), 0 otherwise.
+    size_t Offset() const { return offset_; }
+
+    //! Conversion to \c bool, returns \c true, iff !\ref IsError().
+    operator bool() const { return !IsError(); }
+    //! Whether the result is an error.
+    bool IsError() const { return code_ != kParseErrorNone; }
+
+    bool operator==(const ParseResult& that) const { return code_ == that.code_; }
+    bool operator==(ParseErrorCode code) const { return code_ == code; }
+    friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+
+    //! Reset error code.
+    void Clear() { Set(kParseErrorNone); }
+    //! Update error code and offset.
+    void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
+
+private:
+    ParseErrorCode code_;
+    size_t offset_;
+};
+
+//! Function pointer type of GetParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+    This is the prototype for \c GetParseError_X(), where \c X is a locale.
+    User can dynamically change locale in runtime, e.g.:
+\code
+    GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
+    const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ERROR_ERROR_H__

+ 88 - 0
contrib/rapidjson/include/rapidjson/filereadstream.h

@@ -0,0 +1,88 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEREADSTREAM_H_
+#define RAPIDJSON_FILEREADSTREAM_H_
+
+#include "rapidjson.h"
+#include <cstdio>
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! File byte stream for input using fread().
+/*!
+    \note implements Stream concept
+*/
+class FileReadStream {
+public:
+    typedef char Ch;    //!< Character type (byte).
+
+    //! Constructor.
+    /*!
+        \param fp File pointer opened for read.
+        \param buffer user-supplied buffer.
+        \param bufferSize size of buffer in bytes. Must >=4 bytes.
+    */
+    FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 
+        RAPIDJSON_ASSERT(fp_ != 0);
+        RAPIDJSON_ASSERT(bufferSize >= 4);
+        Read();
+    }
+
+    Ch Peek() const { return *current_; }
+    Ch Take() { Ch c = *current_; Read(); return c; }
+    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    // For encoding detection only.
+    const Ch* Peek4() const {
+        return (current_ + 4 <= bufferLast_) ? current_ : 0;
+    }
+
+private:
+    void Read() {
+        if (current_ < bufferLast_)
+            ++current_;
+        else if (!eof_) {
+            count_ += readCount_;
+            readCount_ = fread(buffer_, 1, bufferSize_, fp_);
+            bufferLast_ = buffer_ + readCount_ - 1;
+            current_ = buffer_;
+
+            if (readCount_ < bufferSize_) {
+                buffer_[readCount_] = '\0';
+                ++bufferLast_;
+                eof_ = true;
+            }
+        }
+    }
+
+    std::FILE* fp_;
+    Ch *buffer_;
+    size_t bufferSize_;
+    Ch *bufferLast_;
+    Ch *current_;
+    size_t readCount_;
+    size_t count_;  //!< Number of characters read
+    bool eof_;
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_FILESTREAM_H_

+ 95 - 0
contrib/rapidjson/include/rapidjson/filewritestream.h

@@ -0,0 +1,95 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEWRITESTREAM_H_
+#define RAPIDJSON_FILEWRITESTREAM_H_
+
+#include "rapidjson.h"
+#include <cstdio>
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of C file stream for input using fread().
+/*!
+    \note implements Stream concept
+*/
+class FileWriteStream {
+public:
+    typedef char Ch;    //!< Character type. Only support char.
+
+    FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 
+        RAPIDJSON_ASSERT(fp_ != 0);
+    }
+
+    void Put(char c) { 
+        if (current_ >= bufferEnd_)
+            Flush();
+
+        *current_++ = c;
+    }
+
+    void PutN(char c, size_t n) {
+        size_t avail = static_cast<size_t>(bufferEnd_ - current_);
+        while (n > avail) {
+            std::memset(current_, c, avail);
+            current_ += avail;
+            Flush();
+            n -= avail;
+            avail = static_cast<size_t>(bufferEnd_ - current_);
+        }
+
+        if (n > 0) {
+            std::memset(current_, c, n);
+            current_ += n;
+        }
+    }
+
+    void Flush() {
+        if (current_ != buffer_) {
+            size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
+            if (result < static_cast<size_t>(current_ - buffer_)) {
+                // failure deliberately ignored at this time
+                // added to avoid warn_unused_result build errors
+            }
+            current_ = buffer_;
+        }
+    }
+
+    // Not implemented
+    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+    char Take() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    FileWriteStream(const FileWriteStream&);
+    FileWriteStream& operator=(const FileWriteStream&);
+
+    std::FILE* fp_;
+    char *buffer_;
+    char *bufferEnd_;
+    char *current_;
+};
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(FileWriteStream& stream, char c, size_t n) {
+    stream.PutN(c, n);
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_FILESTREAM_H_

+ 290 - 0
contrib/rapidjson/include/rapidjson/internal/biginteger.h

@@ -0,0 +1,290 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_BIGINTEGER_H_
+#define RAPIDJSON_BIGINTEGER_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h> // for _umul128
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class BigInteger {
+public:
+    typedef uint64_t Type;
+
+    BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
+        std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+    }
+
+    explicit BigInteger(uint64_t u) : count_(1) {
+        digits_[0] = u;
+    }
+
+    BigInteger(const char* decimals, size_t length) : count_(1) {
+        RAPIDJSON_ASSERT(length > 0);
+        digits_[0] = 0;
+        size_t i = 0;
+        const size_t kMaxDigitPerIteration = 19;  // 2^64 = 18446744073709551616 > 10^19
+        while (length >= kMaxDigitPerIteration) {
+            AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
+            length -= kMaxDigitPerIteration;
+            i += kMaxDigitPerIteration;
+        }
+
+        if (length > 0)
+            AppendDecimal64(decimals + i, decimals + i + length);
+    }
+    
+    BigInteger& operator=(const BigInteger &rhs)
+    {
+        if (this != &rhs) {
+            count_ = rhs.count_;
+            std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+        }
+        return *this;
+    }
+    
+    BigInteger& operator=(uint64_t u) {
+        digits_[0] = u;            
+        count_ = 1;
+        return *this;
+    }
+
+    BigInteger& operator+=(uint64_t u) {
+        Type backup = digits_[0];
+        digits_[0] += u;
+        for (size_t i = 0; i < count_ - 1; i++) {
+            if (digits_[i] >= backup)
+                return *this; // no carry
+            backup = digits_[i + 1];
+            digits_[i + 1] += 1;
+        }
+
+        // Last carry
+        if (digits_[count_ - 1] < backup)
+            PushBack(1);
+
+        return *this;
+    }
+
+    BigInteger& operator*=(uint64_t u) {
+        if (u == 0) return *this = 0;
+        if (u == 1) return *this;
+        if (*this == 1) return *this = u;
+
+        uint64_t k = 0;
+        for (size_t i = 0; i < count_; i++) {
+            uint64_t hi;
+            digits_[i] = MulAdd64(digits_[i], u, k, &hi);
+            k = hi;
+        }
+        
+        if (k > 0)
+            PushBack(k);
+
+        return *this;
+    }
+
+    BigInteger& operator*=(uint32_t u) {
+        if (u == 0) return *this = 0;
+        if (u == 1) return *this;
+        if (*this == 1) return *this = u;
+
+        uint64_t k = 0;
+        for (size_t i = 0; i < count_; i++) {
+            const uint64_t c = digits_[i] >> 32;
+            const uint64_t d = digits_[i] & 0xFFFFFFFF;
+            const uint64_t uc = u * c;
+            const uint64_t ud = u * d;
+            const uint64_t p0 = ud + k;
+            const uint64_t p1 = uc + (p0 >> 32);
+            digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
+            k = p1 >> 32;
+        }
+        
+        if (k > 0)
+            PushBack(k);
+
+        return *this;
+    }
+
+    BigInteger& operator<<=(size_t shift) {
+        if (IsZero() || shift == 0) return *this;
+
+        size_t offset = shift / kTypeBit;
+        size_t interShift = shift % kTypeBit;
+        RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
+
+        if (interShift == 0) {
+            std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
+            count_ += offset;
+        }
+        else {
+            digits_[count_] = 0;
+            for (size_t i = count_; i > 0; i--)
+                digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
+            digits_[offset] = digits_[0] << interShift;
+            count_ += offset;
+            if (digits_[count_])
+                count_++;
+        }
+
+        std::memset(digits_, 0, offset * sizeof(Type));
+
+        return *this;
+    }
+
+    bool operator==(const BigInteger& rhs) const {
+        return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
+    }
+
+    bool operator==(const Type rhs) const {
+        return count_ == 1 && digits_[0] == rhs;
+    }
+
+    BigInteger& MultiplyPow5(unsigned exp) {
+        static const uint32_t kPow5[12] = {
+            5,
+            5 * 5,
+            5 * 5 * 5,
+            5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+        };
+        if (exp == 0) return *this;
+        for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
+        for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
+        if (exp > 0)                 *this *= kPow5[exp - 1];
+        return *this;
+    }
+
+    // Compute absolute difference of this and rhs.
+    // Assume this != rhs
+    bool Difference(const BigInteger& rhs, BigInteger* out) const {
+        int cmp = Compare(rhs);
+        RAPIDJSON_ASSERT(cmp != 0);
+        const BigInteger *a, *b;  // Makes a > b
+        bool ret;
+        if (cmp < 0) { a = &rhs; b = this; ret = true; }
+        else         { a = this; b = &rhs; ret = false; }
+
+        Type borrow = 0;
+        for (size_t i = 0; i < a->count_; i++) {
+            Type d = a->digits_[i] - borrow;
+            if (i < b->count_)
+                d -= b->digits_[i];
+            borrow = (d > a->digits_[i]) ? 1 : 0;
+            out->digits_[i] = d;
+            if (d != 0)
+                out->count_ = i + 1;
+        }
+
+        return ret;
+    }
+
+    int Compare(const BigInteger& rhs) const {
+        if (count_ != rhs.count_)
+            return count_ < rhs.count_ ? -1 : 1;
+
+        for (size_t i = count_; i-- > 0;)
+            if (digits_[i] != rhs.digits_[i])
+                return digits_[i] < rhs.digits_[i] ? -1 : 1;
+
+        return 0;
+    }
+
+    size_t GetCount() const { return count_; }
+    Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
+    bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
+
+private:
+    void AppendDecimal64(const char* begin, const char* end) {
+        uint64_t u = ParseUint64(begin, end);
+        if (IsZero())
+            *this = u;
+        else {
+            unsigned exp = static_cast<unsigned>(end - begin);
+            (MultiplyPow5(exp) <<= exp) += u;   // *this = *this * 10^exp + u
+        }
+    }
+
+    void PushBack(Type digit) {
+        RAPIDJSON_ASSERT(count_ < kCapacity);
+        digits_[count_++] = digit;
+    }
+
+    static uint64_t ParseUint64(const char* begin, const char* end) {
+        uint64_t r = 0;
+        for (const char* p = begin; p != end; ++p) {
+            RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
+            r = r * 10u + (unsigned)(*p - '0');
+        }
+        return r;
+    }
+
+    // Assume a * b + k < 2^128
+    static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        uint64_t low = _umul128(a, b, outHigh) + k;
+        if (low < k)
+            (*outHigh)++;
+        return low;
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+        __extension__ typedef unsigned __int128 uint128;
+        uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
+        p += k;
+        *outHigh = static_cast<uint64_t>(p >> 64);
+        return static_cast<uint64_t>(p);
+#else
+        const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
+        uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
+        x1 += (x0 >> 32); // can't give carry
+        x1 += x2;
+        if (x1 < x2)
+            x3 += (static_cast<uint64_t>(1) << 32);
+        uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
+        uint64_t hi = x3 + (x1 >> 32);
+
+        lo += k;
+        if (lo < k)
+            hi++;
+        *outHigh = hi;
+        return lo;
+#endif
+    }
+
+    static const size_t kBitCount = 3328;  // 64bit * 54 > 10^1000
+    static const size_t kCapacity = kBitCount / sizeof(Type);
+    static const size_t kTypeBit = sizeof(Type) * 8;
+
+    Type digits_[kCapacity];
+    size_t count_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_BIGINTEGER_H_

+ 248 - 0
contrib/rapidjson/include/rapidjson/internal/diyfp.h

@@ -0,0 +1,248 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DIYFP_H_
+#define RAPIDJSON_DIYFP_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+struct DiyFp {
+    DiyFp() {}
+
+    DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
+
+    explicit DiyFp(double d) {
+        union {
+            double d;
+            uint64_t u64;
+        } u = { d };
+
+        int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
+        uint64_t significand = (u.u64 & kDpSignificandMask);
+        if (biased_e != 0) {
+            f = significand + kDpHiddenBit;
+            e = biased_e - kDpExponentBias;
+        } 
+        else {
+            f = significand;
+            e = kDpMinExponent + 1;
+        }
+    }
+
+    DiyFp operator-(const DiyFp& rhs) const {
+        return DiyFp(f - rhs.f, e);
+    }
+
+    DiyFp operator*(const DiyFp& rhs) const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        uint64_t h;
+        uint64_t l = _umul128(f, rhs.f, &h);
+        if (l & (uint64_t(1) << 63)) // rounding
+            h++;
+        return DiyFp(h, e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+        __extension__ typedef unsigned __int128 uint128;
+        uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
+        uint64_t h = static_cast<uint64_t>(p >> 64);
+        uint64_t l = static_cast<uint64_t>(p);
+        if (l & (uint64_t(1) << 63)) // rounding
+            h++;
+        return DiyFp(h, e + rhs.e + 64);
+#else
+        const uint64_t M32 = 0xFFFFFFFF;
+        const uint64_t a = f >> 32;
+        const uint64_t b = f & M32;
+        const uint64_t c = rhs.f >> 32;
+        const uint64_t d = rhs.f & M32;
+        const uint64_t ac = a * c;
+        const uint64_t bc = b * c;
+        const uint64_t ad = a * d;
+        const uint64_t bd = b * d;
+        uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+        tmp += 1U << 31;  /// mult_round
+        return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
+#endif
+    }
+
+    DiyFp Normalize() const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        unsigned long index;
+        _BitScanReverse64(&index, f);
+        return DiyFp(f << (63 - index), e - (63 - index));
+#elif defined(__GNUC__) && __GNUC__ >= 4
+        int s = __builtin_clzll(f);
+        return DiyFp(f << s, e - s);
+#else
+        DiyFp res = *this;
+        while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
+            res.f <<= 1;
+            res.e--;
+        }
+        return res;
+#endif
+    }
+
+    DiyFp NormalizeBoundary() const {
+        DiyFp res = *this;
+        while (!(res.f & (kDpHiddenBit << 1))) {
+            res.f <<= 1;
+            res.e--;
+        }
+        res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+        res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+        return res;
+    }
+
+    void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
+        DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
+        DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
+        mi.f <<= mi.e - pl.e;
+        mi.e = pl.e;
+        *plus = pl;
+        *minus = mi;
+    }
+
+    double ToDouble() const {
+        union {
+            double d;
+            uint64_t u64;
+        }u;
+        const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : 
+            static_cast<uint64_t>(e + kDpExponentBias);
+        u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
+        return u.d;
+    }
+
+    static const int kDiySignificandSize = 64;
+    static const int kDpSignificandSize = 52;
+    static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
+    static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
+    static const int kDpMinExponent = -kDpExponentBias;
+    static const int kDpDenormalExponent = -kDpExponentBias + 1;
+    static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+    static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+    static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+    uint64_t f;
+    int e;
+};
+
+inline DiyFp GetCachedPowerByIndex(size_t index) {
+    // 10^-348, 10^-340, ..., 10^340
+    static const uint64_t kCachedPowers_F[] = {
+        RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
+        RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
+        RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
+        RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
+        RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
+        RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+        RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
+        RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
+        RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
+        RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
+        RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
+        RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
+        RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
+        RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
+        RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
+        RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
+        RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
+        RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+        RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
+        RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
+        RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
+        RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
+        RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
+        RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
+        RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
+        RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
+        RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
+        RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
+        RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
+        RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
+        RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
+        RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
+        RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
+        RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
+        RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
+        RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
+        RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
+        RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
+        RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
+        RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
+        RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
+        RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
+        RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
+        RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
+    };
+    static const int16_t kCachedPowers_E[] = {
+        -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,
+        -954,  -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,
+        -688,  -661,  -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,
+        -422,  -396,  -369,  -343,  -316,  -289,  -263,  -236,  -210,  -183,
+        -157,  -130,  -103,   -77,   -50,   -24,     3,    30,    56,    83,
+        109,   136,   162,   189,   216,   242,   269,   295,   322,   348,
+        375,   402,   428,   455,   481,   508,   534,   561,   588,   614,
+        641,   667,   694,   720,   747,   774,   800,   827,   853,   880,
+        907,   933,   960,   986,  1013,  1039,  1066
+    };
+    return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+    
+inline DiyFp GetCachedPower(int e, int* K) {
+
+    //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
+    double dk = (-61 - e) * 0.30102999566398114 + 347;  // dk must be positive, so can do ceiling in positive
+    int k = static_cast<int>(dk);
+    if (dk - k > 0.0)
+        k++;
+
+    unsigned index = static_cast<unsigned>((k >> 3) + 1);
+    *K = -(-348 + static_cast<int>(index << 3));    // decimal exponent no need lookup table
+
+    return GetCachedPowerByIndex(index);
+}
+
+inline DiyFp GetCachedPower10(int exp, int *outExp) {
+     unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
+     *outExp = -348 + static_cast<int>(index) * 8;
+     return GetCachedPowerByIndex(index);
+ }
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DIYFP_H_

+ 217 - 0
contrib/rapidjson/include/rapidjson/internal/dtoa.h

@@ -0,0 +1,217 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DTOA_
+#define RAPIDJSON_DTOA_
+
+#include "itoa.h" // GetDigitsLut()
+#include "diyfp.h"
+#include "ieee754.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
+    while (rest < wp_w && delta - rest >= ten_kappa &&
+           (rest + ten_kappa < wp_w ||  /// closer
+            wp_w - rest > rest + ten_kappa - wp_w)) {
+        buffer[len - 1]--;
+        rest += ten_kappa;
+    }
+}
+
+inline unsigned CountDecimalDigit32(uint32_t n) {
+    // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
+    if (n < 10) return 1;
+    if (n < 100) return 2;
+    if (n < 1000) return 3;
+    if (n < 10000) return 4;
+    if (n < 100000) return 5;
+    if (n < 1000000) return 6;
+    if (n < 10000000) return 7;
+    if (n < 100000000) return 8;
+    // Will not reach 10 digits in DigitGen()
+    //if (n < 1000000000) return 9;
+    //return 10;
+    return 9;
+}
+
+inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
+    static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+    const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
+    const DiyFp wp_w = Mp - W;
+    uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
+    uint64_t p2 = Mp.f & (one.f - 1);
+    unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
+    *len = 0;
+
+    while (kappa > 0) {
+        uint32_t d = 0;
+        switch (kappa) {
+            case  9: d = p1 /  100000000; p1 %=  100000000; break;
+            case  8: d = p1 /   10000000; p1 %=   10000000; break;
+            case  7: d = p1 /    1000000; p1 %=    1000000; break;
+            case  6: d = p1 /     100000; p1 %=     100000; break;
+            case  5: d = p1 /      10000; p1 %=      10000; break;
+            case  4: d = p1 /       1000; p1 %=       1000; break;
+            case  3: d = p1 /        100; p1 %=        100; break;
+            case  2: d = p1 /         10; p1 %=         10; break;
+            case  1: d = p1;              p1 =           0; break;
+            default:;
+        }
+        if (d || *len)
+            buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
+        kappa--;
+        uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
+        if (tmp <= delta) {
+            *K += kappa;
+            GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+            return;
+        }
+    }
+
+    // kappa = 0
+    for (;;) {
+        p2 *= 10;
+        delta *= 10;
+        char d = static_cast<char>(p2 >> -one.e);
+        if (d || *len)
+            buffer[(*len)++] = static_cast<char>('0' + d);
+        p2 &= one.f - 1;
+        kappa--;
+        if (p2 < delta) {
+            *K += kappa;
+            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]);
+            return;
+        }
+    }
+}
+
+inline void Grisu2(double value, char* buffer, int* length, int* K) {
+    const DiyFp v(value);
+    DiyFp w_m, w_p;
+    v.NormalizedBoundaries(&w_m, &w_p);
+
+    const DiyFp c_mk = GetCachedPower(w_p.e, K);
+    const DiyFp W = v.Normalize() * c_mk;
+    DiyFp Wp = w_p * c_mk;
+    DiyFp Wm = w_m * c_mk;
+    Wm.f++;
+    Wp.f--;
+    DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
+}
+
+inline char* WriteExponent(int K, char* buffer) {
+    if (K < 0) {
+        *buffer++ = '-';
+        K = -K;
+    }
+
+    if (K >= 100) {
+        *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
+        K %= 100;
+        const char* d = GetDigitsLut() + K * 2;
+        *buffer++ = d[0];
+        *buffer++ = d[1];
+    }
+    else if (K >= 10) {
+        const char* d = GetDigitsLut() + K * 2;
+        *buffer++ = d[0];
+        *buffer++ = d[1];
+    }
+    else
+        *buffer++ = static_cast<char>('0' + static_cast<char>(K));
+
+    return buffer;
+}
+
+inline char* Prettify(char* buffer, int length, int k) {
+    const int kk = length + k;  // 10^(kk-1) <= v < 10^kk
+
+    if (length <= kk && kk <= 21) {
+        // 1234e7 -> 12340000000
+        for (int i = length; i < kk; i++)
+            buffer[i] = '0';
+        buffer[kk] = '.';
+        buffer[kk + 1] = '0';
+        return &buffer[kk + 2];
+    }
+    else if (0 < kk && kk <= 21) {
+        // 1234e-2 -> 12.34
+        std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
+        buffer[kk] = '.';
+        return &buffer[length + 1];
+    }
+    else if (-6 < kk && kk <= 0) {
+        // 1234e-6 -> 0.001234
+        const int offset = 2 - kk;
+        std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
+        buffer[0] = '0';
+        buffer[1] = '.';
+        for (int i = 2; i < offset; i++)
+            buffer[i] = '0';
+        return &buffer[length + offset];
+    }
+    else if (length == 1) {
+        // 1e30
+        buffer[1] = 'e';
+        return WriteExponent(kk - 1, &buffer[2]);
+    }
+    else {
+        // 1234e30 -> 1.234e33
+        std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
+        buffer[1] = '.';
+        buffer[length + 1] = 'e';
+        return WriteExponent(kk - 1, &buffer[0 + length + 2]);
+    }
+}
+
+inline char* dtoa(double value, char* buffer) {
+    Double d(value);
+    if (d.IsZero()) {
+        if (d.Sign())
+            *buffer++ = '-';     // -0.0, Issue #289
+        buffer[0] = '0';
+        buffer[1] = '.';
+        buffer[2] = '0';
+        return &buffer[3];
+    }
+    else {
+        if (value < 0) {
+            *buffer++ = '-';
+            value = -value;
+        }
+        int length, K;
+        Grisu2(value, buffer, &length, &K);
+        return Prettify(buffer, length, K);
+    }
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DTOA_

+ 77 - 0
contrib/rapidjson/include/rapidjson/internal/ieee754.h

@@ -0,0 +1,77 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_IEEE754_
+#define RAPIDJSON_IEEE754_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class Double {
+public:
+    Double() {}
+    Double(double d) : d_(d) {}
+    Double(uint64_t u) : u_(u) {}
+
+    double Value() const { return d_; }
+    uint64_t Uint64Value() const { return u_; }
+
+    double NextPositiveDouble() const {
+        RAPIDJSON_ASSERT(!Sign());
+        return Double(u_ + 1).Value();
+    }
+
+    bool Sign() const { return (u_ & kSignMask) != 0; }
+    uint64_t Significand() const { return u_ & kSignificandMask; }
+    int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
+
+    bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
+    bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
+    bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
+    bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
+
+    uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
+    int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
+    uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
+
+    static unsigned EffectiveSignificandSize(int order) {
+        if (order >= -1021)
+            return 53;
+        else if (order <= -1074)
+            return 0;
+        else
+            return (unsigned)order + 1074;
+    }
+
+private:
+    static const int kSignificandSize = 52;
+    static const int kExponentBias = 0x3FF;
+    static const int kDenormalExponent = 1 - kExponentBias;
+    static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
+    static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+    static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+    static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+    union {
+        double d_;
+        uint64_t u_;
+    };
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_IEEE754_

+ 304 - 0
contrib/rapidjson/include/rapidjson/internal/itoa.h

@@ -0,0 +1,304 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ITOA_
+#define RAPIDJSON_ITOA_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline const char* GetDigitsLut() {
+    static const char cDigitsLut[200] = {
+        '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
+        '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
+        '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
+        '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
+        '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
+        '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
+        '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
+        '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
+        '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
+        '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
+    };
+    return cDigitsLut;
+}
+
+inline char* u32toa(uint32_t value, char* buffer) {
+    const char* cDigitsLut = GetDigitsLut();
+
+    if (value < 10000) {
+        const uint32_t d1 = (value / 100) << 1;
+        const uint32_t d2 = (value % 100) << 1;
+        
+        if (value >= 1000)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= 100)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= 10)
+            *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+    }
+    else if (value < 100000000) {
+        // value = bbbbcccc
+        const uint32_t b = value / 10000;
+        const uint32_t c = value % 10000;
+        
+        const uint32_t d1 = (b / 100) << 1;
+        const uint32_t d2 = (b % 100) << 1;
+        
+        const uint32_t d3 = (c / 100) << 1;
+        const uint32_t d4 = (c % 100) << 1;
+        
+        if (value >= 10000000)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= 1000000)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= 100000)
+            *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+    }
+    else {
+        // value = aabbbbcccc in decimal
+        
+        const uint32_t a = value / 100000000; // 1 to 42
+        value %= 100000000;
+        
+        if (a >= 10) {
+            const unsigned i = a << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+
+        const uint32_t b = value / 10000; // 0 to 9999
+        const uint32_t c = value % 10000; // 0 to 9999
+        
+        const uint32_t d1 = (b / 100) << 1;
+        const uint32_t d2 = (b % 100) << 1;
+        
+        const uint32_t d3 = (c / 100) << 1;
+        const uint32_t d4 = (c % 100) << 1;
+        
+        *buffer++ = cDigitsLut[d1];
+        *buffer++ = cDigitsLut[d1 + 1];
+        *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+    }
+    return buffer;
+}
+
+inline char* i32toa(int32_t value, char* buffer) {
+    uint32_t u = static_cast<uint32_t>(value);
+    if (value < 0) {
+        *buffer++ = '-';
+        u = ~u + 1;
+    }
+
+    return u32toa(u, buffer);
+}
+
+inline char* u64toa(uint64_t value, char* buffer) {
+    const char* cDigitsLut = GetDigitsLut();
+    const uint64_t  kTen8 = 100000000;
+    const uint64_t  kTen9 = kTen8 * 10;
+    const uint64_t kTen10 = kTen8 * 100;
+    const uint64_t kTen11 = kTen8 * 1000;
+    const uint64_t kTen12 = kTen8 * 10000;
+    const uint64_t kTen13 = kTen8 * 100000;
+    const uint64_t kTen14 = kTen8 * 1000000;
+    const uint64_t kTen15 = kTen8 * 10000000;
+    const uint64_t kTen16 = kTen8 * kTen8;
+    
+    if (value < kTen8) {
+        uint32_t v = static_cast<uint32_t>(value);
+        if (v < 10000) {
+            const uint32_t d1 = (v / 100) << 1;
+            const uint32_t d2 = (v % 100) << 1;
+            
+            if (v >= 1000)
+                *buffer++ = cDigitsLut[d1];
+            if (v >= 100)
+                *buffer++ = cDigitsLut[d1 + 1];
+            if (v >= 10)
+                *buffer++ = cDigitsLut[d2];
+            *buffer++ = cDigitsLut[d2 + 1];
+        }
+        else {
+            // value = bbbbcccc
+            const uint32_t b = v / 10000;
+            const uint32_t c = v % 10000;
+            
+            const uint32_t d1 = (b / 100) << 1;
+            const uint32_t d2 = (b % 100) << 1;
+            
+            const uint32_t d3 = (c / 100) << 1;
+            const uint32_t d4 = (c % 100) << 1;
+            
+            if (value >= 10000000)
+                *buffer++ = cDigitsLut[d1];
+            if (value >= 1000000)
+                *buffer++ = cDigitsLut[d1 + 1];
+            if (value >= 100000)
+                *buffer++ = cDigitsLut[d2];
+            *buffer++ = cDigitsLut[d2 + 1];
+            
+            *buffer++ = cDigitsLut[d3];
+            *buffer++ = cDigitsLut[d3 + 1];
+            *buffer++ = cDigitsLut[d4];
+            *buffer++ = cDigitsLut[d4 + 1];
+        }
+    }
+    else if (value < kTen16) {
+        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+        
+        const uint32_t b0 = v0 / 10000;
+        const uint32_t c0 = v0 % 10000;
+        
+        const uint32_t d1 = (b0 / 100) << 1;
+        const uint32_t d2 = (b0 % 100) << 1;
+        
+        const uint32_t d3 = (c0 / 100) << 1;
+        const uint32_t d4 = (c0 % 100) << 1;
+
+        const uint32_t b1 = v1 / 10000;
+        const uint32_t c1 = v1 % 10000;
+        
+        const uint32_t d5 = (b1 / 100) << 1;
+        const uint32_t d6 = (b1 % 100) << 1;
+        
+        const uint32_t d7 = (c1 / 100) << 1;
+        const uint32_t d8 = (c1 % 100) << 1;
+
+        if (value >= kTen15)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= kTen14)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= kTen13)
+            *buffer++ = cDigitsLut[d2];
+        if (value >= kTen12)
+            *buffer++ = cDigitsLut[d2 + 1];
+        if (value >= kTen11)
+            *buffer++ = cDigitsLut[d3];
+        if (value >= kTen10)
+            *buffer++ = cDigitsLut[d3 + 1];
+        if (value >= kTen9)
+            *buffer++ = cDigitsLut[d4];
+        if (value >= kTen8)
+            *buffer++ = cDigitsLut[d4 + 1];
+        
+        *buffer++ = cDigitsLut[d5];
+        *buffer++ = cDigitsLut[d5 + 1];
+        *buffer++ = cDigitsLut[d6];
+        *buffer++ = cDigitsLut[d6 + 1];
+        *buffer++ = cDigitsLut[d7];
+        *buffer++ = cDigitsLut[d7 + 1];
+        *buffer++ = cDigitsLut[d8];
+        *buffer++ = cDigitsLut[d8 + 1];
+    }
+    else {
+        const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
+        value %= kTen16;
+        
+        if (a < 10)
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+        else if (a < 100) {
+            const uint32_t i = a << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else if (a < 1000) {
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
+            
+            const uint32_t i = (a % 100) << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else {
+            const uint32_t i = (a / 100) << 1;
+            const uint32_t j = (a % 100) << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+            *buffer++ = cDigitsLut[j];
+            *buffer++ = cDigitsLut[j + 1];
+        }
+        
+        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+        
+        const uint32_t b0 = v0 / 10000;
+        const uint32_t c0 = v0 % 10000;
+        
+        const uint32_t d1 = (b0 / 100) << 1;
+        const uint32_t d2 = (b0 % 100) << 1;
+        
+        const uint32_t d3 = (c0 / 100) << 1;
+        const uint32_t d4 = (c0 % 100) << 1;
+        
+        const uint32_t b1 = v1 / 10000;
+        const uint32_t c1 = v1 % 10000;
+        
+        const uint32_t d5 = (b1 / 100) << 1;
+        const uint32_t d6 = (b1 % 100) << 1;
+        
+        const uint32_t d7 = (c1 / 100) << 1;
+        const uint32_t d8 = (c1 % 100) << 1;
+        
+        *buffer++ = cDigitsLut[d1];
+        *buffer++ = cDigitsLut[d1 + 1];
+        *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+        *buffer++ = cDigitsLut[d5];
+        *buffer++ = cDigitsLut[d5 + 1];
+        *buffer++ = cDigitsLut[d6];
+        *buffer++ = cDigitsLut[d6 + 1];
+        *buffer++ = cDigitsLut[d7];
+        *buffer++ = cDigitsLut[d7 + 1];
+        *buffer++ = cDigitsLut[d8];
+        *buffer++ = cDigitsLut[d8 + 1];
+    }
+    
+    return buffer;
+}
+
+inline char* i64toa(int64_t value, char* buffer) {
+    uint64_t u = static_cast<uint64_t>(value);
+    if (value < 0) {
+        *buffer++ = '-';
+        u = ~u + 1;
+    }
+
+    return u64toa(u, buffer);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ITOA_

+ 181 - 0
contrib/rapidjson/include/rapidjson/internal/meta.h

@@ -0,0 +1,181 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_META_H_
+#define RAPIDJSON_INTERNAL_META_H_
+
+#include "../rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+#if defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(6334)
+#endif
+
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+#include <type_traits>
+#endif
+
+//@cond RAPIDJSON_INTERNAL
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
+template <typename T> struct Void { typedef void Type; };
+
+///////////////////////////////////////////////////////////////////////////////
+// BoolType, TrueType, FalseType
+//
+template <bool Cond> struct BoolType {
+    static const bool Value = Cond;
+    typedef BoolType Type;
+};
+typedef BoolType<true> TrueType;
+typedef BoolType<false> FalseType;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
+//
+
+template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
+template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
+template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
+template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
+
+template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
+template <> struct AndExprCond<true, true> : TrueType {};
+template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
+template <> struct OrExprCond<false, false> : FalseType {};
+
+template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
+template <typename C> struct NotExpr  : SelectIf<C,FalseType,TrueType>::Type {};
+template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
+template <typename C1, typename C2> struct OrExpr  : OrExprCond<C1::Value, C2::Value>::Type {};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// AddConst, MaybeAddConst, RemoveConst
+template <typename T> struct AddConst { typedef const T Type; };
+template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
+template <typename T> struct RemoveConst { typedef T Type; };
+template <typename T> struct RemoveConst<const T> { typedef T Type; };
+
+
+///////////////////////////////////////////////////////////////////////////////
+// IsSame, IsConst, IsMoreConst, IsPointer
+//
+template <typename T, typename U> struct IsSame : FalseType {};
+template <typename T> struct IsSame<T, T> : TrueType {};
+
+template <typename T> struct IsConst : FalseType {};
+template <typename T> struct IsConst<const T> : TrueType {};
+
+template <typename CT, typename T>
+struct IsMoreConst
+    : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
+              BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
+
+template <typename T> struct IsPointer : FalseType {};
+template <typename T> struct IsPointer<T*> : TrueType {};
+
+///////////////////////////////////////////////////////////////////////////////
+// IsBaseOf
+//
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+template <typename B, typename D> struct IsBaseOf
+    : BoolType< ::std::is_base_of<B,D>::value> {};
+
+#else // simplified version adopted from Boost
+
+template<typename B, typename D> struct IsBaseOfImpl {
+    RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
+    RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
+
+    typedef char (&Yes)[1];
+    typedef char (&No) [2];
+
+    template <typename T>
+    static Yes Check(const D*, T);
+    static No  Check(const B*, int);
+
+    struct Host {
+        operator const B*() const;
+        operator const D*();
+    };
+
+    enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
+};
+
+template <typename B, typename D> struct IsBaseOf
+    : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
+
+#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+
+//////////////////////////////////////////////////////////////////////////
+// EnableIf / DisableIf
+//
+template <bool Condition, typename T = void> struct EnableIfCond  { typedef T Type; };
+template <typename T> struct EnableIfCond<false, T> { /* empty */ };
+
+template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
+template <typename T> struct DisableIfCond<true, T> { /* empty */ };
+
+template <typename Condition, typename T = void>
+struct EnableIf : EnableIfCond<Condition::Value, T> {};
+
+template <typename Condition, typename T = void>
+struct DisableIf : DisableIfCond<Condition::Value, T> {};
+
+// SFINAE helpers
+struct SfinaeTag {};
+template <typename T> struct RemoveSfinaeTag;
+template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
+
+#define RAPIDJSON_REMOVEFPTR_(type) \
+    typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
+        < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
+
+#define RAPIDJSON_ENABLEIF(cond) \
+    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_DISABLEIF(cond) \
+    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
+    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond), \
+         RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
+    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond), \
+         RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+//@endcond
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_META_H_

+ 55 - 0
contrib/rapidjson/include/rapidjson/internal/pow10.h

@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+    \param n non-negative exponent. Must <= 308.
+    \return 10.0^n
+*/
+inline double Pow10(int n) {
+    static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
+        1e+0,  
+        1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 
+        1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+        1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+        1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+        1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+        1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+        1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+        1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+        1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+        1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+        1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+        1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+        1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+        1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+        1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+        1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+    };
+    RAPIDJSON_ASSERT(n >= 0 && n <= 308);
+    return e[n];
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_POW10_

+ 196 - 0
contrib/rapidjson/include/rapidjson/internal/stack.h

@@ -0,0 +1,196 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+#include "../rapidjson.h"
+#include "swap.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+    // Optimization note: Do not allocate memory for stack_ in constructor.
+    // Do it lazily when first Push() -> Expand() -> Resize().
+    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
+        RAPIDJSON_ASSERT(stackCapacity > 0);
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    Stack(Stack&& rhs)
+        : allocator_(rhs.allocator_),
+          ownAllocator_(rhs.ownAllocator_),
+          stack_(rhs.stack_),
+          stackTop_(rhs.stackTop_),
+          stackEnd_(rhs.stackEnd_),
+          initialCapacity_(rhs.initialCapacity_)
+    {
+        rhs.allocator_ = 0;
+        rhs.ownAllocator_ = 0;
+        rhs.stack_ = 0;
+        rhs.stackTop_ = 0;
+        rhs.stackEnd_ = 0;
+        rhs.initialCapacity_ = 0;
+    }
+#endif
+
+    ~Stack() {
+        Destroy();
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    Stack& operator=(Stack&& rhs) {
+        if (&rhs != this)
+        {
+            Destroy();
+
+            allocator_ = rhs.allocator_;
+            ownAllocator_ = rhs.ownAllocator_;
+            stack_ = rhs.stack_;
+            stackTop_ = rhs.stackTop_;
+            stackEnd_ = rhs.stackEnd_;
+            initialCapacity_ = rhs.initialCapacity_;
+
+            rhs.allocator_ = 0;
+            rhs.ownAllocator_ = 0;
+            rhs.stack_ = 0;
+            rhs.stackTop_ = 0;
+            rhs.stackEnd_ = 0;
+            rhs.initialCapacity_ = 0;
+        }
+        return *this;
+    }
+#endif
+
+    void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
+        internal::Swap(allocator_, rhs.allocator_);
+        internal::Swap(ownAllocator_, rhs.ownAllocator_);
+        internal::Swap(stack_, rhs.stack_);
+        internal::Swap(stackTop_, rhs.stackTop_);
+        internal::Swap(stackEnd_, rhs.stackEnd_);
+        internal::Swap(initialCapacity_, rhs.initialCapacity_);
+    }
+
+    void Clear() { stackTop_ = stack_; }
+
+    void ShrinkToFit() { 
+        if (Empty()) {
+            // If the stack is empty, completely deallocate the memory.
+            Allocator::Free(stack_);
+            stack_ = 0;
+            stackTop_ = 0;
+            stackEnd_ = 0;
+        }
+        else
+            Resize(GetSize());
+    }
+
+    // Optimization note: try to minimize the size of this function for force inline.
+    // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
+    template<typename T>
+    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
+         // Expand the stack if needed
+        if (stackTop_ + sizeof(T) * count >= stackEnd_)
+            Expand<T>(count);
+
+        T* ret = reinterpret_cast<T*>(stackTop_);
+        stackTop_ += sizeof(T) * count;
+        return ret;
+    }
+
+    template<typename T>
+    T* Pop(size_t count) {
+        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+        stackTop_ -= count * sizeof(T);
+        return reinterpret_cast<T*>(stackTop_);
+    }
+
+    template<typename T>
+    T* Top() { 
+        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+    }
+
+    template<typename T>
+    T* Bottom() { return (T*)stack_; }
+
+    bool HasAllocator() const {
+        return allocator_ != 0;
+    }
+
+    Allocator& GetAllocator() {
+        RAPIDJSON_ASSERT(allocator_);
+        return *allocator_;
+    }
+    bool Empty() const { return stackTop_ == stack_; }
+    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
+    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
+
+private:
+    template<typename T>
+    void Expand(size_t count) {
+        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
+        size_t newCapacity;
+        if (stack_ == 0) {
+            if (!allocator_)
+                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+            newCapacity = initialCapacity_;
+        } else {
+            newCapacity = GetCapacity();
+            newCapacity += (newCapacity + 1) / 2;
+        }
+        size_t newSize = GetSize() + sizeof(T) * count;
+        if (newCapacity < newSize)
+            newCapacity = newSize;
+
+        Resize(newCapacity);
+    }
+
+    void Resize(size_t newCapacity) {
+        const size_t size = GetSize();  // Backup the current size
+        stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
+        stackTop_ = stack_ + size;
+        stackEnd_ = stack_ + newCapacity;
+    }
+
+    void Destroy() {
+        Allocator::Free(stack_);
+        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
+    }
+
+    // Prohibit copy constructor & assignment operator.
+    Stack(const Stack&);
+    Stack& operator=(const Stack&);
+
+    Allocator* allocator_;
+    Allocator* ownAllocator_;
+    char *stack_;
+    char *stackTop_;
+    char *stackEnd_;
+    size_t initialCapacity_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STACK_H_

+ 39 - 0
contrib/rapidjson/include/rapidjson/internal/strfunc.h

@@ -0,0 +1,39 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+    \param s Null-terminated input string.
+    \return Number of characters in the string. 
+    \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+    const Ch* p = s;
+    while (*p) ++p;
+    return SizeType(p - s);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_

+ 270 - 0
contrib/rapidjson/include/rapidjson/internal/strtod.h

@@ -0,0 +1,270 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRTOD_
+#define RAPIDJSON_STRTOD_
+
+#include "../rapidjson.h"
+#include "ieee754.h"
+#include "biginteger.h"
+#include "diyfp.h"
+#include "pow10.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline double FastPath(double significand, int exp) {
+    if (exp < -308)
+        return 0.0;
+    else if (exp >= 0)
+        return significand * internal::Pow10(exp);
+    else
+        return significand / internal::Pow10(-exp);
+}
+
+inline double StrtodNormalPrecision(double d, int p) {
+    if (p < -308) {
+        // Prevent expSum < -308, making Pow10(p) = 0
+        d = FastPath(d, -308);
+        d = FastPath(d, p + 308);
+    }
+    else
+        d = FastPath(d, p);
+    return d;
+}
+
+template <typename T>
+inline T Min3(T a, T b, T c) {
+    T m = a;
+    if (m > b) m = b;
+    if (m > c) m = c;
+    return m;
+}
+
+inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
+    const Double db(b);
+    const uint64_t bInt = db.IntegerSignificand();
+    const int bExp = db.IntegerExponent();
+    const int hExp = bExp - 1;
+
+    int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
+
+    // Adjust for decimal exponent
+    if (dExp >= 0) {
+        dS_Exp2 += dExp;
+        dS_Exp5 += dExp;
+    }
+    else {
+        bS_Exp2 -= dExp;
+        bS_Exp5 -= dExp;
+        hS_Exp2 -= dExp;
+        hS_Exp5 -= dExp;
+    }
+
+    // Adjust for binary exponent
+    if (bExp >= 0)
+        bS_Exp2 += bExp;
+    else {
+        dS_Exp2 -= bExp;
+        hS_Exp2 -= bExp;
+    }
+
+    // Adjust for half ulp exponent
+    if (hExp >= 0)
+        hS_Exp2 += hExp;
+    else {
+        dS_Exp2 -= hExp;
+        bS_Exp2 -= hExp;
+    }
+
+    // Remove common power of two factor from all three scaled values
+    int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
+    dS_Exp2 -= common_Exp2;
+    bS_Exp2 -= common_Exp2;
+    hS_Exp2 -= common_Exp2;
+
+    BigInteger dS = d;
+    dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
+
+    BigInteger bS(bInt);
+    bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
+
+    BigInteger hS(1);
+    hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
+
+    BigInteger delta(0);
+    dS.Difference(bS, &delta);
+
+    return delta.Compare(hS);
+}
+
+inline bool StrtodFast(double d, int p, double* result) {
+    // Use fast path for string-to-double conversion if possible
+    // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
+    if (p > 22  && p < 22 + 16) {
+        // Fast Path Cases In Disguise
+        d *= internal::Pow10(p - 22);
+        p = 22;
+    }
+
+    if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
+        *result = FastPath(d, p);
+        return true;
+    }
+    else
+        return false;
+}
+
+// Compute an approximation and see if it is within 1/2 ULP
+inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
+    uint64_t significand = 0;
+    size_t i = 0;   // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999    
+    for (; i < length; i++) {
+        if (significand  >  RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
+            (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
+            break;
+        significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
+    }
+    
+    if (i < length && decimals[i] >= '5') // Rounding
+        significand++;
+
+    size_t remaining = length - i;
+    const unsigned kUlpShift = 3;
+    const unsigned kUlp = 1 << kUlpShift;
+    int error = (remaining == 0) ? 0 : kUlp / 2;
+
+    DiyFp v(significand, 0);
+    v = v.Normalize();
+    error <<= -v.e;
+
+    const int dExp = (int)decimalPosition - (int)i + exp;
+
+    int actualExp;
+    DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
+    if (actualExp != dExp) {
+        static const DiyFp kPow10[] = {
+            DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60),  // 10^1
+            DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57),  // 10^2
+            DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54),  // 10^3
+            DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50),  // 10^4
+            DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47),  // 10^5
+            DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44),  // 10^6
+            DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40)   // 10^7
+        };
+        int  adjustment = dExp - actualExp - 1;
+        RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
+        v = v * kPow10[adjustment];
+        if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
+            error += kUlp / 2;
+    }
+
+    v = v * cachedPower;
+
+    error += kUlp + (error == 0 ? 0 : 1);
+
+    const int oldExp = v.e;
+    v = v.Normalize();
+    error <<= oldExp - v.e;
+
+    const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
+    unsigned precisionSize = 64 - effectiveSignificandSize;
+    if (precisionSize + kUlpShift >= 64) {
+        unsigned scaleExp = (precisionSize + kUlpShift) - 63;
+        v.f >>= scaleExp;
+        v.e += scaleExp; 
+        error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
+        precisionSize -= scaleExp;
+    }
+
+    DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
+    const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
+    const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
+    if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
+        rounded.f++;
+        if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
+            rounded.f >>= 1;
+            rounded.e++;
+        }
+    }
+
+    *result = rounded.ToDouble();
+
+    return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
+}
+
+inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+    const BigInteger dInt(decimals, length);
+    const int dExp = (int)decimalPosition - (int)length + exp;
+    Double a(approx);
+    int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
+    if (cmp < 0)
+        return a.Value();  // within half ULP
+    else if (cmp == 0) {
+        // Round towards even
+        if (a.Significand() & 1)
+            return a.NextPositiveDouble();
+        else
+            return a.Value();
+    }
+    else // adjustment
+        return a.NextPositiveDouble();
+}
+
+inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+    RAPIDJSON_ASSERT(d >= 0.0);
+    RAPIDJSON_ASSERT(length >= 1);
+
+    double result;
+    if (StrtodFast(d, p, &result))
+        return result;
+
+    // Trim leading zeros
+    while (*decimals == '0' && length > 1) {
+        length--;
+        decimals++;
+        decimalPosition--;
+    }
+
+    // Trim trailing zeros
+    while (decimals[length - 1] == '0' && length > 1) {
+        length--;
+        decimalPosition--;
+        exp++;
+    }
+
+    // Trim right-most digits
+    const int kMaxDecimalDigit = 780;
+    if ((int)length > kMaxDecimalDigit) {
+        int delta = (int(length) - kMaxDecimalDigit);
+        exp += delta;
+        decimalPosition -= static_cast<unsigned>(delta);
+        length = kMaxDecimalDigit;
+    }
+
+    // If too small, underflow to zero
+    if (int(length) + exp < -324)
+        return 0.0;
+
+    if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
+        return result;
+
+    // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
+    return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STRTOD_

+ 37 - 0
contrib/rapidjson/include/rapidjson/internal/swap.h

@@ -0,0 +1,37 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_SWAP_H_
+#define RAPIDJSON_INTERNAL_SWAP_H_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom swap() to avoid dependency on C++ <algorithm> header
+/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
+    \note This has the same semantics as std::swap().
+*/
+template <typename T>
+inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
+    T tmp = a;
+        a = b;
+        b = tmp;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_INTERNAL_SWAP_H_

+ 70 - 0
contrib/rapidjson/include/rapidjson/memorybuffer.h

@@ -0,0 +1,70 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYBUFFER_H_
+#define RAPIDJSON_MEMORYBUFFER_H_
+
+#include "rapidjson.h"
+#include "internal/stack.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output byte stream.
+/*!
+    This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
+
+    It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
+
+    Differences between MemoryBuffer and StringBuffer:
+    1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 
+    2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
+
+    \tparam Allocator type for allocating memory buffer.
+    \note implements Stream concept
+*/
+template <typename Allocator = CrtAllocator>
+struct GenericMemoryBuffer {
+    typedef char Ch; // byte
+
+    GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+    void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+    void Flush() {}
+
+    void Clear() { stack_.Clear(); }
+    void ShrinkToFit() { stack_.ShrinkToFit(); }
+    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+    void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+    const Ch* GetBuffer() const {
+        return stack_.template Bottom<Ch>();
+    }
+
+    size_t GetSize() const { return stack_.GetSize(); }
+
+    static const size_t kDefaultCapacity = 256;
+    mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericMemoryBuffer<> MemoryBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
+    std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_

+ 61 - 0
contrib/rapidjson/include/rapidjson/memorystream.h

@@ -0,0 +1,61 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYSTREAM_H_
+#define RAPIDJSON_MEMORYSTREAM_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory input byte stream.
+/*!
+    This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
+
+    It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
+
+    Differences between MemoryStream and StringStream:
+    1. StringStream has encoding but MemoryStream is a byte stream.
+    2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
+    3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
+    \note implements Stream concept
+*/
+struct MemoryStream {
+    typedef char Ch; // byte
+
+    MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
+
+    Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
+    Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
+    size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
+
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    // For encoding detection only.
+    const Ch* Peek4() const {
+        return Tell() + 4 <= size_ ? src_ : 0;
+    }
+
+    const Ch* src_;     //!< Current read position.
+    const Ch* begin_;   //!< Original head of the string.
+    const Ch* end_;     //!< End of stream.
+    size_t size_;       //!< Size of the stream.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_

+ 316 - 0
contrib/rapidjson/include/rapidjson/msinttypes/inttypes.h

@@ -0,0 +1,316 @@
+// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006-2013 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+// 
+//   3. Neither the name of the product nor the names of its contributors may
+//      be used to endorse or promote products derived from this software
+//      without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by 
+// THL A29 Limited ("Tencent Modifications"). 
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// miloyip: VC supports inttypes.h since VC2013
+#if _MSC_VER >= 1800
+#include <inttypes.h>
+#else
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+   intmax_t quot;
+   intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8       "d"
+#define PRIi8       "i"
+#define PRIdLEAST8  "d"
+#define PRIiLEAST8  "i"
+#define PRIdFAST8   "d"
+#define PRIiFAST8   "i"
+
+#define PRId16       "hd"
+#define PRIi16       "hi"
+#define PRIdLEAST16  "hd"
+#define PRIiLEAST16  "hi"
+#define PRIdFAST16   "hd"
+#define PRIiFAST16   "hi"
+
+#define PRId32       "I32d"
+#define PRIi32       "I32i"
+#define PRIdLEAST32  "I32d"
+#define PRIiLEAST32  "I32i"
+#define PRIdFAST32   "I32d"
+#define PRIiFAST32   "I32i"
+
+#define PRId64       "I64d"
+#define PRIi64       "I64i"
+#define PRIdLEAST64  "I64d"
+#define PRIiLEAST64  "I64i"
+#define PRIdFAST64   "I64d"
+#define PRIiFAST64   "I64i"
+
+#define PRIdMAX     "I64d"
+#define PRIiMAX     "I64i"
+
+#define PRIdPTR     "Id"
+#define PRIiPTR     "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8       "o"
+#define PRIu8       "u"
+#define PRIx8       "x"
+#define PRIX8       "X"
+#define PRIoLEAST8  "o"
+#define PRIuLEAST8  "u"
+#define PRIxLEAST8  "x"
+#define PRIXLEAST8  "X"
+#define PRIoFAST8   "o"
+#define PRIuFAST8   "u"
+#define PRIxFAST8   "x"
+#define PRIXFAST8   "X"
+
+#define PRIo16       "ho"
+#define PRIu16       "hu"
+#define PRIx16       "hx"
+#define PRIX16       "hX"
+#define PRIoLEAST16  "ho"
+#define PRIuLEAST16  "hu"
+#define PRIxLEAST16  "hx"
+#define PRIXLEAST16  "hX"
+#define PRIoFAST16   "ho"
+#define PRIuFAST16   "hu"
+#define PRIxFAST16   "hx"
+#define PRIXFAST16   "hX"
+
+#define PRIo32       "I32o"
+#define PRIu32       "I32u"
+#define PRIx32       "I32x"
+#define PRIX32       "I32X"
+#define PRIoLEAST32  "I32o"
+#define PRIuLEAST32  "I32u"
+#define PRIxLEAST32  "I32x"
+#define PRIXLEAST32  "I32X"
+#define PRIoFAST32   "I32o"
+#define PRIuFAST32   "I32u"
+#define PRIxFAST32   "I32x"
+#define PRIXFAST32   "I32X"
+
+#define PRIo64       "I64o"
+#define PRIu64       "I64u"
+#define PRIx64       "I64x"
+#define PRIX64       "I64X"
+#define PRIoLEAST64  "I64o"
+#define PRIuLEAST64  "I64u"
+#define PRIxLEAST64  "I64x"
+#define PRIXLEAST64  "I64X"
+#define PRIoFAST64   "I64o"
+#define PRIuFAST64   "I64u"
+#define PRIxFAST64   "I64x"
+#define PRIXFAST64   "I64X"
+
+#define PRIoMAX     "I64o"
+#define PRIuMAX     "I64u"
+#define PRIxMAX     "I64x"
+#define PRIXMAX     "I64X"
+
+#define PRIoPTR     "Io"
+#define PRIuPTR     "Iu"
+#define PRIxPTR     "Ix"
+#define PRIXPTR     "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8       "d"
+#define SCNi8       "i"
+#define SCNdLEAST8  "d"
+#define SCNiLEAST8  "i"
+#define SCNdFAST8   "d"
+#define SCNiFAST8   "i"
+
+#define SCNd16       "hd"
+#define SCNi16       "hi"
+#define SCNdLEAST16  "hd"
+#define SCNiLEAST16  "hi"
+#define SCNdFAST16   "hd"
+#define SCNiFAST16   "hi"
+
+#define SCNd32       "ld"
+#define SCNi32       "li"
+#define SCNdLEAST32  "ld"
+#define SCNiLEAST32  "li"
+#define SCNdFAST32   "ld"
+#define SCNiFAST32   "li"
+
+#define SCNd64       "I64d"
+#define SCNi64       "I64i"
+#define SCNdLEAST64  "I64d"
+#define SCNiLEAST64  "I64i"
+#define SCNdFAST64   "I64d"
+#define SCNiFAST64   "I64i"
+
+#define SCNdMAX     "I64d"
+#define SCNiMAX     "I64i"
+
+#ifdef _WIN64 // [
+#  define SCNdPTR     "I64d"
+#  define SCNiPTR     "I64i"
+#else  // _WIN64 ][
+#  define SCNdPTR     "ld"
+#  define SCNiPTR     "li"
+#endif  // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8       "o"
+#define SCNu8       "u"
+#define SCNx8       "x"
+#define SCNX8       "X"
+#define SCNoLEAST8  "o"
+#define SCNuLEAST8  "u"
+#define SCNxLEAST8  "x"
+#define SCNXLEAST8  "X"
+#define SCNoFAST8   "o"
+#define SCNuFAST8   "u"
+#define SCNxFAST8   "x"
+#define SCNXFAST8   "X"
+
+#define SCNo16       "ho"
+#define SCNu16       "hu"
+#define SCNx16       "hx"
+#define SCNX16       "hX"
+#define SCNoLEAST16  "ho"
+#define SCNuLEAST16  "hu"
+#define SCNxLEAST16  "hx"
+#define SCNXLEAST16  "hX"
+#define SCNoFAST16   "ho"
+#define SCNuFAST16   "hu"
+#define SCNxFAST16   "hx"
+#define SCNXFAST16   "hX"
+
+#define SCNo32       "lo"
+#define SCNu32       "lu"
+#define SCNx32       "lx"
+#define SCNX32       "lX"
+#define SCNoLEAST32  "lo"
+#define SCNuLEAST32  "lu"
+#define SCNxLEAST32  "lx"
+#define SCNXLEAST32  "lX"
+#define SCNoFAST32   "lo"
+#define SCNuFAST32   "lu"
+#define SCNxFAST32   "lx"
+#define SCNXFAST32   "lX"
+
+#define SCNo64       "I64o"
+#define SCNu64       "I64u"
+#define SCNx64       "I64x"
+#define SCNX64       "I64X"
+#define SCNoLEAST64  "I64o"
+#define SCNuLEAST64  "I64u"
+#define SCNxLEAST64  "I64x"
+#define SCNXLEAST64  "I64X"
+#define SCNoFAST64   "I64o"
+#define SCNuFAST64   "I64u"
+#define SCNxFAST64   "I64x"
+#define SCNXFAST64   "I64X"
+
+#define SCNoMAX     "I64o"
+#define SCNuMAX     "I64u"
+#define SCNxMAX     "I64x"
+#define SCNXMAX     "I64X"
+
+#ifdef _WIN64 // [
+#  define SCNoPTR     "I64o"
+#  define SCNuPTR     "I64u"
+#  define SCNxPTR     "I64x"
+#  define SCNXPTR     "I64X"
+#else  // _WIN64 ][
+#  define SCNoPTR     "lo"
+#  define SCNuPTR     "lu"
+#  define SCNxPTR     "lx"
+#  define SCNXPTR     "lX"
+#endif  // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+   imaxdiv_t result;
+
+   result.quot = numer / denom;
+   result.rem = numer % denom;
+
+   if (numer < 0 && result.rem > 0) {
+      // did division wrong; must fix up
+      ++result.quot;
+      result.rem -= denom;
+   }
+
+   return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+#endif // _MSC_VER >= 1800
+
+#endif // _MSC_INTTYPES_H_ ]

Деякі файли не було показано, через те що забагато файлів було змінено