Browse Source

Merge branch 'master' into coverity_scan

Kim Kulling 8 years ago
parent
commit
e6cfe6b5c8
100 changed files with 6357 additions and 3294 deletions
  1. 2 1
      .travis.sh
  2. 38 9
      .travis.yml
  3. 13 2
      CMakeLists.txt
  4. 8 8
      Readme.md
  5. 1 1
      code/3DSExporter.cpp
  6. 1 1
      code/AMFImporter_Postprocess.cpp
  7. 12 19
      code/Assimp.cpp
  8. 2 1
      code/AssimpCExport.cpp
  9. 10 43
      code/BaseImporter.cpp
  10. 1 5
      code/BaseImporter.h
  11. 2 2
      code/BlenderModifier.cpp
  12. 3 7
      code/CMakeLists.txt
  13. 1 1
      code/ColladaExporter.cpp
  14. 12 4
      code/ColladaLoader.cpp
  15. 1 1
      code/Exporter.cpp
  16. 2 3
      code/HalfLifeFileData.h
  17. 40 17
      code/IFCLoader.cpp
  18. 90 5
      code/IOStreamBuffer.h
  19. 1 1
      code/IRRLoader.cpp
  20. 1 1
      code/IRRLoader.h
  21. 1 0
      code/LWOAnimation.cpp
  22. 3 4
      code/LWOAnimation.h
  23. 1 1
      code/LWSLoader.cpp
  24. 1 1
      code/LWSLoader.h
  25. 12 15
      code/MD3FileData.h
  26. 1 1
      code/MD3Loader.cpp
  27. 1 1
      code/MDCFileData.h
  28. 51 76
      code/MDLFileData.h
  29. 40 0
      code/MMDCpp14.h
  30. 40 0
      code/MMDPmdParser.h
  31. 42 10
      code/MMDPmxParser.cpp
  32. 40 0
      code/MMDPmxParser.h
  33. 40 0
      code/MMDVmdParser.h
  34. 32 43
      code/ObjFileParser.cpp
  35. 4 5
      code/ObjFileParser.h
  36. 5 3
      code/ObjTools.h
  37. 1 1
      code/OptimizeGraph.cpp
  38. 1 1
      code/OptimizeMeshes.cpp
  39. 2 4
      code/PlyExporter.h
  40. 855 911
      code/PlyLoader.cpp
  41. 14 47
      code/PlyLoader.h
  42. 930 754
      code/PlyParser.cpp
  43. 39 56
      code/PlyParser.h
  44. 1 1
      code/PretransformVertices.cpp
  45. 22 9
      code/SIBImporter.cpp
  46. 25 32
      code/STEPFileEncoding.cpp
  47. 3 3
      code/STLLoader.cpp
  48. 1 1
      code/SceneCombiner.cpp
  49. 2 3
      code/SpatialSort.cpp
  50. 2 1
      code/StepExporter.cpp
  51. 1 1
      code/Subdivision.cpp
  52. 2 1
      code/XFileExporter.cpp
  53. 10 3
      code/fast_atof.h
  54. 5 2
      code/glTFExporter.cpp
  55. 0 539
      contrib/ConvertUTF/ConvertUTF.c
  56. 0 151
      contrib/ConvertUTF/ConvertUTF.h
  57. 0 43
      contrib/ConvertUTF/readme.txt
  58. 114 8
      contrib/openddlparser/CMakeLists.txt
  59. 3 0
      contrib/openddlparser/CREDITS
  60. 2 2
      contrib/openddlparser/README.md
  61. 14 6
      contrib/openddlparser/code/DDLNode.cpp
  62. 35 9
      contrib/openddlparser/code/OpenDDLCommon.cpp
  63. 1 55
      contrib/openddlparser/code/OpenDDLExport.cpp
  64. 80 65
      contrib/openddlparser/code/OpenDDLParser.cpp
  65. 96 0
      contrib/openddlparser/code/OpenDDLStream.cpp
  66. 17 18
      contrib/openddlparser/code/Value.cpp
  67. 19 10
      contrib/openddlparser/include/openddlparser/DDLNode.h
  68. 3 4
      contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
  69. 3 27
      contrib/openddlparser/include/openddlparser/OpenDDLExport.h
  70. 11 1
      contrib/openddlparser/include/openddlparser/OpenDDLParser.h
  71. 36 8
      contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
  72. 89 0
      contrib/openddlparser/include/openddlparser/OpenDDLStream.h
  73. 7 3
      contrib/openddlparser/include/openddlparser/Value.h
  74. 23 31
      contrib/poly2tri/poly2tri/common/shapes.cc
  75. 29 31
      contrib/poly2tri/poly2tri/common/shapes.h
  76. 32 8
      contrib/poly2tri/poly2tri/common/utils.h
  77. 2 3
      contrib/poly2tri/poly2tri/poly2tri.h
  78. 3 4
      contrib/poly2tri/poly2tri/sweep/advancing_front.cc
  79. 3 3
      contrib/poly2tri/poly2tri/sweep/advancing_front.h
  80. 4 5
      contrib/poly2tri/poly2tri/sweep/cdt.cc
  81. 17 17
      contrib/poly2tri/poly2tri/sweep/cdt.h
  82. 91 42
      contrib/poly2tri/poly2tri/sweep/sweep.cc
  83. 28 21
      contrib/poly2tri/poly2tri/sweep/sweep.h
  84. 31 22
      contrib/poly2tri/poly2tri/sweep/sweep_context.cc
  85. 17 17
      contrib/poly2tri/poly2tri/sweep/sweep_context.h
  86. 12 0
      contrib/utf8cpp/doc/ReleaseNotes
  87. 1789 0
      contrib/utf8cpp/doc/utf8cpp.html
  88. 34 0
      contrib/utf8cpp/source/utf8.h
  89. 327 0
      contrib/utf8cpp/source/utf8/checked.h
  90. 329 0
      contrib/utf8cpp/source/utf8/core.h
  91. 228 0
      contrib/utf8cpp/source/utf8/unchecked.h
  92. 0 2
      include/assimp/SceneCombiner.h
  93. 0 2
      include/assimp/color4.inl
  94. 16 4
      include/assimp/material.inl
  95. 4 3
      include/assimp/matrix4x4.h
  96. 1 4
      port/PyAssimp/pyassimp/helper.py
  97. 1 3
      port/PyAssimp/setup.py
  98. 28 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln
  99. 102 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h
  100. 205 0
      samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp

+ 2 - 1
.travis.sh

@@ -5,7 +5,8 @@ function generate()
 
 if [ $ANDROID ]; then
     ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
-else
+fi
+if [ "$TRAVIS_OS_NAME" = "linux" ]; then
     generate \
     && make -j4 \
     && sudo make install \

+ 38 - 9
.travis.yml

@@ -1,23 +1,52 @@
-env:
-  global:
-    - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
+sudo: required
+language: cpp
 
 before_install:
-  - sudo apt-get update -qq
-  - sudo apt-get install cmake
-  - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; fi
+  - if [ "$TRAVIS_OS_NAME" =   "osx" ]; then brew install cmake python3 homebrew/x11/freeglut; fi
+  - echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
+  # install latest LCOV (1.9 was failing)
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz && tar xf lcov_1.11.orig.tar.gz && sudo make -C lcov-1.11/ install && gem install coveralls-lcov && lcov --version && g++ --version ; fi
 
-language: cpp
+branches:
+  only:
+    - master
+
+osx_image: xcode8.3
+
+env:
+  global:
+    - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
+    - PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
+  matrix:
+    - LINUX=1 TRAVIS_NO_EXPORT=YES ENABLE_COVERALLS=ON
+    - LINUX=1 TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
+    - LINUX=1 SHARED_BUILD=ON      ENABLE_COVERALLS=OFF
+    - LINUX=1 SHARED_BUILD=OFF     ENABLE_COVERALLS=OFF
+    #exclude:
+    #    - os: linux
+    #      compiler: clang
+    #    - os: osx
+    #      compiler: gcc  
 
 compiler:
   - gcc
   - clang
 
 before_script:
-  cmake .
+  # init coverage to 0 (optional)
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --zerocounters ; fi
 
 script:
-  make
+  - export COVERALLS_SERVICE_NAME=travis-ci
+  - export COVERALLS_REPO_TOKEN=abc12345
+  - . ./.travis.sh
+os:
+  - linux
+  - osx
+ 
+after_success:
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info && lcov --list coverage.info && coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info ; fi
 
 addons:
   coverity_scan:

+ 13 - 2
CMakeLists.txt

@@ -89,6 +89,10 @@ OPTION ( BUILD_DOCS
    OFF
 )
 
+if (WIN32)
+    add_definitions( -DWIN32_LEAN_AND_MEAN )
+endif()
+
 IF(MSVC)
   set (CMAKE_PREFIX_PATH "D:\\libs\\devil")
   OPTION( ASSIMP_INSTALL_PDB
@@ -141,6 +145,13 @@ IF(ASSIMP_DOUBLE_PRECISION)
   ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
 ENDIF(ASSIMP_DOUBLE_PRECISION)
 
+# Check for OpenMP support
+find_package(OpenMP)
+if (OPENMP_FOUND)
+    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+endif()
+
 configure_file(
   ${CMAKE_CURRENT_LIST_DIR}/revision.h.in
   ${CMAKE_CURRENT_BINARY_DIR}/revision.h
@@ -157,7 +168,7 @@ include_directories(
     ${CMAKE_CURRENT_BINARY_DIR}/include
 )
 
-SET(CMAKE_MODULE_PATH       "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
+LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
 SET(LIBASSIMP_COMPONENT     "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}" )
 SET(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}-dev" )
 SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev)
@@ -178,7 +189,7 @@ ENDIF( UNIX )
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
   # hide all not-exported symbols
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -std=c++0x")
-  SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -fPIC)
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
   SET(LIBSTDC++_LIBRARIES -lstdc++)
 ELSEIF(MSVC)
   # enable multi-core compilation with MSVC

+ 8 - 8
Readme.md

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

+ 1 - 1
code/3DSExporter.cpp

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

+ 1 - 1
code/AMFImporter_Postprocess.cpp

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

+ 12 - 19
code/Assimp.cpp

@@ -66,8 +66,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // ------------------------------------------------------------------------------------------------
 using namespace Assimp;
 
-namespace Assimp
-{
+namespace Assimp {
     // underlying structure for aiPropertyStore
     typedef BatchLoader::PropertyMap PropertyMap;
 
@@ -110,12 +109,11 @@ static std::mutex gLogStreamMutex;
 
 // ------------------------------------------------------------------------------------------------
 // Custom LogStream implementation for the C-API
-class LogToCallbackRedirector : public LogStream
-{
+class LogToCallbackRedirector : public LogStream {
 public:
     explicit LogToCallbackRedirector(const aiLogStream& s)
-        : stream (s)    {
-            ai_assert(NULL != s.callback);
+    : stream (s)    {
+        ai_assert(NULL != s.callback);
     }
 
     ~LogToCallbackRedirector()  {
@@ -146,8 +144,7 @@ private:
 };
 
 // ------------------------------------------------------------------------------------------------
-void ReportSceneNotFoundError()
-{
+void ReportSceneNotFoundError() {
     DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
         "The C-API does not accept scenes produced by the C++ API and vice versa");
 
@@ -156,22 +153,18 @@ void ReportSceneNotFoundError()
 
 // ------------------------------------------------------------------------------------------------
 // Reads the given file and returns its content.
-const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
-{
+const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) {
     return aiImportFileEx(pFile,pFlags,NULL);
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,  aiFileIO* pFS)
-{
+const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,  aiFileIO* pFS) {
     return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
-    aiFileIO* pFS,
-    const aiPropertyStore* props)
-{
+const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, 
+        aiFileIO* pFS, const aiPropertyStore* props) {
     ai_assert(NULL != pFile);
 
     const aiScene* scene = NULL;
@@ -190,7 +183,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl
         pimpl->mMatrixProperties = pp->matrices;
     }
     // setup a custom IO system if necessary
-    if (pFS)    {
+    if (pFS) {
         imp->SetIOHandler( new CIOSystemWrapper (pFS) );
     }
 
@@ -201,8 +194,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl
     if( scene)  {
         ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
         priv->mOrigImporter = imp;
-    }
-    else    {
+    } else {
         // if failed, extract error code and destroy the import
         gLastErrorString = imp->GetErrorString();
         delete imp;
@@ -210,6 +202,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl
 
     // return imported data. If the import failed the pointer is NULL anyways
     ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    
     return scene;
 }
 

+ 2 - 1
code/AssimpCExport.cpp

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

+ 10 - 43
code/BaseImporter.cpp

@@ -303,24 +303,13 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
     return false;
 }
 
-#include "../contrib/ConvertUTF/ConvertUTF.h"
-
-// ------------------------------------------------------------------------------------------------
-void ReportResult(ConversionResult res)
-{
-    if(res == sourceExhausted) {
-        DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails");
-    }
-    else if(res == sourceIllegal) {
-        DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails");
-    }
-}
+#include "../contrib/utf8cpp/source/utf8.h"
 
 // ------------------------------------------------------------------------------------------------
 // Convert to UTF8 data
 void BaseImporter::ConvertToUTF8(std::vector<char>& data)
 {
-    ConversionResult result;
+    //ConversionResult result;
     if(data.size() < 8) {
         throw DeadlyImportError("File is too small");
     }
@@ -333,7 +322,8 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
         data.resize(data.size()-3);
         return;
     }
-
+    
+    
     // UTF 32 BE with BOM
     if(*((uint32_t*)&data.front()) == 0xFFFE0000) {
 
@@ -347,21 +337,10 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
     if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
         DefaultLogger::get()->debug("Found UTF-32 BOM ...");
 
-        const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1;
-        char* dstart,*dend;
         std::vector<char> output;
-        do {
-            output.resize(output.size()?output.size()*3/2:data.size()/2);
-            dstart = &output.front(),dend = &output.back()+1;
-
-            result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
-        } while(result == targetExhausted);
-
-        ReportResult(result);
-
-        // copy to output buffer.
-        const size_t outlen = (size_t)(dstart-&output.front());
-        data.assign(output.begin(),output.begin()+outlen);
+        int *ptr = (int*)&data[ 0 ];
+        int *end = ptr + ( data.size() / sizeof(int) ) +1;
+        utf8::utf32to8( ptr, end, back_inserter(output));
         return;
     }
 
@@ -378,21 +357,9 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
     if(*((uint16_t*)&data.front()) == 0xFEFF) {
         DefaultLogger::get()->debug("Found UTF-16 BOM ...");
 
-        const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1);
-        char* dstart,*dend;
-        std::vector<char> output;
-        do {
-            output.resize(output.size()?output.size()*3/2:data.size()*3/4);
-            dstart = &output.front(),dend = &output.back()+1;
-
-            result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
-        } while(result == targetExhausted);
-
-        ReportResult(result);
-
-        // copy to output buffer.
-        const size_t outlen = (size_t)(dstart-&output.front());
-        data.assign(output.begin(),output.begin()+outlen);
+        std::vector<unsigned char> output;
+        int16_t *ptr = (int16_t*) &data[ 0 ];
+        utf8::utf16to8(data.begin(), data.end(), back_inserter(output));
         return;
     }
 }

+ 1 - 5
code/BaseImporter.h

@@ -61,7 +61,6 @@ class BaseProcess;
 class SharedPostProcessInfo;
 class IOStream;
 
-
 // utility to do char4 to uint32 in a portable manner
 #define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \
     (string[1] << 16) + (string[2] << 8) + string[3]))
@@ -194,14 +193,11 @@ public:
         const Importer* pImp
         );
 
-
     // -------------------------------------------------------------------
     /** Called by #Importer::GetImporterInfo to get a description of
      *  some loader features. Importers must provide this information. */
     virtual const aiImporterDesc* GetInfo() const = 0;
 
-
-
     // -------------------------------------------------------------------
     /** Called by #Importer::GetExtensionList for each loaded importer.
      *  Take the extension list contained in the structure returned by
@@ -317,7 +313,7 @@ public: // static utilities
      *  @param Size of one token, in bytes. Maximally 16 bytes.
      *  @return true if one of the given tokens was found
      *
-     *  @note For convinence, the check is also performed for the
+     *  @note For convenience, the check is also performed for the
      *  byte-swapped variant of all tokens (big endian). Only for
      *  tokens of size 2,4.
      */

+ 2 - 2
code/BlenderModifier.cpp

@@ -43,10 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of some blender modifiers (i.e subdivision, mirror).
  */
 
-
 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
+
 #include "BlenderModifier.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "Subdivision.h"
 #include <assimp/scene.h>
 #include <memory>

+ 3 - 7
code/CMakeLists.txt

@@ -96,6 +96,7 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/Exporter.hpp
   ${HEADER_PATH}/DefaultIOStream.h
   ${HEADER_PATH}/DefaultIOSystem.h
+  ${HEADER_PATH}/SceneCombiner.h
 )
 
 SET( Core_SRCS
@@ -148,7 +149,6 @@ SET( Common_SRCS
   SpatialSort.cpp
   SpatialSort.h
   SceneCombiner.cpp
-  SceneCombiner.h
   ScenePreprocessor.cpp
   ScenePreprocessor.h
   SkeletonMeshBuilder.cpp
@@ -695,11 +695,6 @@ SET( Extra_SRCS
 )
 SOURCE_GROUP( Extra FILES ${Extra_SRCS})
 
-SET( ConvertUTF_SRCS
-  ../contrib/ConvertUTF/ConvertUTF.h
-  ../contrib/ConvertUTF/ConvertUTF.c
-)
-SOURCE_GROUP( ConvertUTF FILES ${ConvertUTF_SRCS})
 
 SET( Clipper_SRCS
   ../contrib/clipper/clipper.hpp
@@ -737,10 +732,12 @@ SET ( openddl_parser_SRCS
   ../contrib/openddlparser/code/OpenDDLCommon.cpp
   ../contrib/openddlparser/code/OpenDDLExport.cpp
   ../contrib/openddlparser/code/Value.cpp
+  ../contrib/openddlparser/code/OpenDDLStream.cpp
   ../contrib/openddlparser/include/openddlparser/OpenDDLParser.h
   ../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
   ../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
   ../contrib/openddlparser/include/openddlparser/OpenDDLExport.h
+  ../contrib/openddlparser/include/openddlparser/OpenDDLStream.h
   ../contrib/openddlparser/include/openddlparser/DDLNode.h
   ../contrib/openddlparser/include/openddlparser/Value.h
 )
@@ -835,7 +832,6 @@ SET( assimp_src
 
   # Third-party libraries
   ${IrrXML_SRCS}
-  ${ConvertUTF_SRCS}
   ${unzip_compile_SRCS}
   ${Poly2Tri_SRCS}
   ${Clipper_SRCS}

+ 1 - 1
code/ColladaExporter.cpp

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

+ 12 - 4
code/ColladaLoader.cpp

@@ -1726,6 +1726,8 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/)
 aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser,
     const Collada::Effect& pEffect, const std::string& pName)
 {
+    aiString result;
+
     // recurse through the param references until we end up at an image
     std::string name = pName;
     while( 1)
@@ -1744,11 +1746,17 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
     ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name);
     if( imIt == pParser.mImageLibrary.end())
     {
-        throw DeadlyImportError( format() <<
-            "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." );
-    }
+        //missing texture should not stop the conversion
+        //throw DeadlyImportError( format() <<
+        //    "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." );
 
-    aiString result;
+        DefaultLogger::get()->warn("Collada: Unable to resolve effect texture entry \"" + pName + "\", ended up at ID \"" + name + "\".");
+
+        //set default texture file name
+        result.Set(name + ".jpg");
+        ConvertPath(result);
+        return result;
+    }
 
     // if this is an embedded texture image setup an aiTexture for it
     if (imIt->second.mFileName.empty())

+ 1 - 1
code/Exporter.cpp

@@ -54,7 +54,7 @@ Here we implement only the C++ interface (Assimp::Exporter).
 #ifndef ASSIMP_BUILD_NO_EXPORT
 
 #include "BlobIOSystem.h"
-#include "SceneCombiner.h"
+#include <assimp/SceneCombiner.h>
 #include "BaseProcess.h"
 #include "Importer.h" // need this for GetPostProcessingStepInstanceList()
 

+ 2 - 3
code/HalfLifeFileData.h

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

+ 40 - 17
code/IFCLoader.cpp

@@ -882,6 +882,7 @@ void ProcessSpatialStructures(ConversionData& conv)
         }
     }
 
+	std::vector<aiNode*> nodes;
 
     for(const STEP::LazyObject* lz : *range) {
         const IfcSpatialStructureElement* const prod = lz->ToPtr<IfcSpatialStructureElement>();
@@ -890,20 +891,19 @@ void ProcessSpatialStructures(ConversionData& conv)
         }
         IFCImporter::LogDebug("looking at spatial structure `" + (prod->Name ? prod->Name.Get() : "unnamed") + "`" + (prod->ObjectType? " which is of type " + prod->ObjectType.Get():""));
 
-        // the primary site is referenced by an IFCRELAGGREGATES element which assigns it to the IFCPRODUCT
+        // the primary sites are referenced by an IFCRELAGGREGATES element which assigns them to the IFCPRODUCT
         const STEP::DB::RefMap& refs = conv.db.GetRefs();
-        STEP::DB::RefMapRange range = refs.equal_range(conv.proj.GetID());
-        for(;range.first != range.second; ++range.first) {
-            if(const IfcRelAggregates* const aggr = conv.db.GetObject((*range.first).second)->ToPtr<IfcRelAggregates>()) {
+        STEP::DB::RefMapRange ref_range = refs.equal_range(conv.proj.GetID());
+        for(; ref_range.first != ref_range.second; ++ref_range.first) {
+            if(const IfcRelAggregates* const aggr = conv.db.GetObject((*ref_range.first).second)->ToPtr<IfcRelAggregates>()) {
 
                 for(const IfcObjectDefinition& def : aggr->RelatedObjects) {
                     // comparing pointer values is not sufficient, we would need to cast them to the same type first
                     // as there is multiple inheritance in the game.
                     if (def.GetID() == prod->GetID()) {
                         IFCImporter::LogDebug("selecting this spatial structure as root structure");
-                        // got it, this is the primary site.
-                        conv.out->mRootNode = ProcessSpatialStructure(NULL,*prod,conv,NULL);
-                        return;
+                        // got it, this is one primary site.
+						nodes.push_back(ProcessSpatialStructure(NULL, *prod, conv, NULL));
                     }
                 }
 
@@ -911,19 +911,42 @@ void ProcessSpatialStructures(ConversionData& conv)
         }
     }
 
+	size_t nb_nodes = nodes.size();
 
-    IFCImporter::LogWarn("failed to determine primary site element, taking the first IfcSite");
-    for(const STEP::LazyObject* lz : *range) {
-        const IfcSpatialStructureElement* const prod = lz->ToPtr<IfcSpatialStructureElement>();
-        if(!prod) {
-            continue;
-        }
+	if (nb_nodes == 0) {
+		IFCImporter::LogWarn("failed to determine primary site element, taking all the IfcSite");
+		for (const STEP::LazyObject* lz : *range) {
+			const IfcSpatialStructureElement* const prod = lz->ToPtr<IfcSpatialStructureElement>();
+			if (!prod) {
+				continue;
+			}
 
-        conv.out->mRootNode = ProcessSpatialStructure(NULL,*prod,conv,NULL);
-        return;
-    }
+			nodes.push_back(ProcessSpatialStructure(NULL, *prod, conv, NULL));
+		}
+
+		nb_nodes = nodes.size();
+	}
+
+	if (nb_nodes == 1) {
+		conv.out->mRootNode = nodes[0];
+	}
+	else if (nb_nodes > 1) {
+		conv.out->mRootNode = new aiNode("Root");
+		conv.out->mRootNode->mParent = NULL;
+		conv.out->mRootNode->mNumChildren = static_cast<unsigned int>(nb_nodes);
+		conv.out->mRootNode->mChildren = new aiNode*[conv.out->mRootNode->mNumChildren];
+		
+		for (size_t i = 0; i < nb_nodes; ++i) {
+			aiNode* node = nodes[i];
+
+			node->mParent = conv.out->mRootNode;
 
-    IFCImporter::ThrowException("failed to determine primary site element");
+			conv.out->mRootNode->mChildren[i] = node;
+		}
+	}
+	else {
+		IFCImporter::ThrowException("failed to determine primary site element");
+	}
 }
 
 // ------------------------------------------------------------------------------------------------

+ 90 - 5
code/IOStreamBuffer.h

@@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOStream.hpp>
 #include "ParsingUtils.h"
 
+#include <vector>
+
 namespace Assimp {
 
 // ---------------------------------------------------------------------------
@@ -69,8 +71,8 @@ public:
     /// @return true if successful.
     bool close();
 
-    /// @brief  Returns the filesize.
-    /// @return The filesize.
+    /// @brief  Returns the file-size.
+    /// @return The file-size.
     size_t size() const;
     
     /// @brief  Returns the cache size.
@@ -96,7 +98,17 @@ public:
     /// @brief  Will read the next line.
     /// @param  buffer      The buffer for the next line.
     /// @return true if successful.
-    bool getNextLine( std::vector<T> &buffer );
+    bool getNextDataLine( std::vector<T> &buffer, T continuationToken );
+
+    /// @brief  Will read the next line ascii or binary end line char.
+    /// @param  buffer      The buffer for the next line.
+    /// @return true if successful.
+    bool getNextLine(std::vector<T> &buffer);
+
+    /// @brief  Will read the next block.
+    /// @param  buffer      The buffer for the next block.
+    /// @return true if successful.
+    bool getNextBlock( std::vector<T> &buffer );
 
 private:
     IOStream *m_stream;
@@ -227,15 +239,35 @@ size_t IOStreamBuffer<T>::getFilePos() const {
 
 template<class T>
 inline
-bool IOStreamBuffer<T>::getNextLine( std::vector<T> &buffer ) {
+bool IOStreamBuffer<T>::getNextDataLine( std::vector<T> &buffer, T continuationToken ) {
     buffer.resize( m_cacheSize );
     if ( m_cachePos == m_cacheSize || 0 == m_filePos ) {
         if ( !readNextBlock() ) {
             return false;
         }
     }
+
+    bool continuationFound( false ), endOfDataLine( false );
     size_t i = 0;
-    while ( !IsLineEnd( m_cache[ m_cachePos ] ) ) {
+    while ( !endOfDataLine ) {
+        if ( continuationToken == m_cache[ m_cachePos ] ) {
+            continuationFound = true;
+            ++m_cachePos;
+        }
+        if ( IsLineEnd( m_cache[ m_cachePos ] ) ) {
+            if ( !continuationFound ) {
+                // the end of the data line
+                break;
+            } else {
+                // skip line end
+                while ( m_cache[m_cachePos] != '\n') {
+                    ++m_cachePos;
+                }
+                ++m_cachePos;
+                continuationFound = false;
+            }
+        }
+
         buffer[ i ] = m_cache[ m_cachePos ];
         m_cachePos++;
         i++;
@@ -245,10 +277,63 @@ bool IOStreamBuffer<T>::getNextLine( std::vector<T> &buffer ) {
             }
         }
     }
+    
     buffer[ i ] = '\n';
     m_cachePos++;
 
     return true;
 }
 
+template<class T>
+inline
+bool IOStreamBuffer<T>::getNextLine(std::vector<T> &buffer) {
+    buffer.resize(m_cacheSize);
+    if (m_cachePos == m_cacheSize || 0 == m_filePos) {
+       if (!readNextBlock()) {
+          return false;
+       }
+      }
+
+    if (IsLineEnd(m_cache[m_cachePos])) {
+        // skip line end
+        while (m_cache[m_cachePos] != '\n') {
+            ++m_cachePos;
+        }
+        ++m_cachePos;
+    }
+
+    size_t i = 0;
+    while (!IsLineEnd(m_cache[m_cachePos])) {
+        buffer[i] = m_cache[m_cachePos];
+        m_cachePos++;
+        i++;
+        if (m_cachePos >= m_cacheSize) {
+            if (!readNextBlock()) {
+                return false;
+            }
+        }
+    }
+    buffer[i] = '\n';
+    m_cachePos++;
+
+    return true;
+}
+
+template<class T>
+inline
+bool IOStreamBuffer<T>::getNextBlock( std::vector<T> &buffer) {
+  //just return the last blockvalue if getNextLine was used before
+  if ( m_cachePos !=  0) {      
+      buffer = std::vector<T>(m_cache.begin() + m_cachePos, m_cache.end());
+      m_cachePos = 0;
+  }
+  else {
+      if ( !readNextBlock() )
+          return false;
+
+      buffer = std::vector<T>(m_cache.begin(), m_cache.end());
+  }
+  return true;
+}
+
 } // !ns Assimp

+ 1 - 1
code/IRRLoader.cpp

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

+ 1 - 1
code/IRRLoader.h

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

+ 1 - 0
code/LWOAnimation.cpp

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "LWOFileData.h"
+#include <assimp/anim.h>
 
 using namespace Assimp;
 using namespace Assimp::LWO;

+ 3 - 4
code/LWOAnimation.h

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

+ 1 - 1
code/LWSLoader.cpp

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

+ 1 - 1
code/LWSLoader.h

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

+ 12 - 15
code/MD3FileData.h

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

+ 1 - 1
code/MD3Loader.cpp

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

+ 1 - 1
code/MDCFileData.h

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

+ 51 - 76
code/MDLFileData.h

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

+ 40 - 0
code/MMDCpp14.h

@@ -1,3 +1,43 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
 #pragma once
 
 #ifndef MMD_CPP14_H

+ 40 - 0
code/MMDPmdParser.h

@@ -1,3 +1,43 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
 #pragma once
 
 #include <vector>

+ 42 - 10
code/MMDPmxParser.cpp

@@ -1,7 +1,47 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
 #include <utility>
 #include "MMDPmxParser.h"
+#include "../contrib/utf8cpp/source/utf8.h"
 #include "Exceptional.h"
-#include "../contrib/ConvertUTF/ConvertUTF.h"
 
 namespace pmx
 {
@@ -60,15 +100,7 @@ namespace pmx
 			const unsigned int targetSize = size * 3; // enough to encode
 			char* targetStart = new char[targetSize]();
 			const char* targetReserved = targetStart;
-			ConversionFlags flags = ConversionFlags::lenientConversion;
-
-			ConversionResult conversionResult;
-			if( ( conversionResult = ConvertUTF16toUTF8(
-				(const UTF16**)&sourceStart, (const UTF16*)(sourceStart + size),
-				(UTF8**)&targetStart, (UTF8*)(targetStart + targetSize),
-				flags) ) != ConversionResult::conversionOK) {
-				throw DeadlyImportError( "Convert " + std::string(sourceStart) + " to UTF8 is not valid." );
-			}
+            utf8::utf16to8( sourceStart, sourceStart + size, targetStart );
 
 			result.assign(targetReserved, targetStart - targetReserved);
 			delete[] targetReserved;

+ 40 - 0
code/MMDPmxParser.h

@@ -1,3 +1,43 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
 #pragma once
 
 #include <vector>

+ 40 - 0
code/MMDVmdParser.h

@@ -1,3 +1,43 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
 #pragma once
 
 #include <vector>

+ 32 - 43
code/ObjFileParser.cpp

@@ -64,7 +64,7 @@ ObjFileParser::ObjFileParser()
 , m_uiLine( 0 )
 , m_pIO( nullptr )
 , m_progress( nullptr )
-, m_originalObjFileName( "" ) {
+, m_originalObjFileName() {
     // empty
 }
 
@@ -109,28 +109,6 @@ ObjFile::Model *ObjFileParser::GetModel() const {
     return m_pModel;
 }
 
-void ignoreNewLines(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer)
-{
-    auto curPosition = buffer.begin();
-    do
-    {
-        while (*curPosition!='\n'&&*curPosition!='\\')
-        {
-            ++curPosition;
-        }
-        if (*curPosition=='\\')
-        {
-            std::vector<char> tempBuf;
-            do
-            {
-                streamBuffer.getNextLine(tempBuf);
-            } while (tempBuf[0]=='\n');
-            *curPosition = ' ';
-            std::copy(tempBuf.cbegin(), tempBuf.cend(), ++curPosition);
-        }
-    } while (*curPosition!='\n');
-}
-
 void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
     // only update every 100KB or it'll be too slow
     //const unsigned int updateProgressEveryBytes = 100 * 1024;
@@ -142,7 +120,7 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
     size_t lastFilePos( 0 );
 
     std::vector<char> buffer;
-    while ( streamBuffer.getNextLine( buffer ) ) {
+    while ( streamBuffer.getNextDataLine( buffer, '\\' ) ) {
         m_DataIt = buffer.begin();
         m_DataItEnd = buffer.end();
 
@@ -154,14 +132,14 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
             progressCounter++;
             m_progress->UpdateFileRead( progressOffset + processed * 2, progressTotal );
         }
-		//ignoreNewLines(streamBuffer, buffer);
+
         // parse line
         switch (*m_DataIt) {
         case 'v': // Parse a vertex texture coordinate
             {
                 ++m_DataIt;
                 if (*m_DataIt == ' ' || *m_DataIt == '\t') {
-                    size_t numComponents = getNumComponentsInLine();
+                    size_t numComponents = getNumComponentsInDataDefinition();
                     if (numComponents == 3) {
                         // read in vertex definition
                         getVector3(m_pModel->m_Vertices);
@@ -245,7 +223,6 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
         default:
             {
 pf_skip_line:
-
                 m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
             }
             break;
@@ -274,21 +251,44 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
     pBuffer[index] = '\0';
 }
 
-size_t ObjFileParser::getNumComponentsInLine() {
+static bool isDataDefinitionEnd( const char *tmp ) {
+    if ( *tmp == '\\' ) {
+        tmp++;
+        if ( IsLineEnd( *tmp ) ) {
+            tmp++;
+            return true;
+        }
+    }
+    return false;
+}
+
+size_t ObjFileParser::getNumComponentsInDataDefinition() {
     size_t numComponents( 0 );
     const char* tmp( &m_DataIt[0] );
-    while( !IsLineEnd( *tmp ) ) {        
+    bool end_of_definition = false;
+    while ( !end_of_definition ) {
+        if ( isDataDefinitionEnd( tmp ) ) {
+            tmp += 2;
+        } else if ( IsLineEnd( *tmp ) ) {
+            end_of_definition = true;
+        }
         if ( !SkipSpaces( &tmp ) ) {
             break;
         }
+        const bool isNum( IsNumeric( *tmp ) );
         SkipToken( tmp );
-        ++numComponents;
+        if ( isNum ) {
+            ++numComponents;
+        }
+        if ( !SkipSpaces( &tmp ) ) {
+            break;
+        }
     }
     return numComponents;
 }
 
 void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
-    size_t numComponents = getNumComponentsInLine();
+    size_t numComponents = getNumComponentsInDataDefinition();
     ai_real x, y, z;
     if( 2 == numComponents ) {
         copyNextWord( m_buffer, Buffersize );
@@ -397,10 +397,6 @@ static const std::string DefaultObjName = "defaultobject";
 // -------------------------------------------------------------------
 //  Get values for a new face instance
 void ObjFileParser::getFace( aiPrimitiveType type ) {
-    //copyNextLine(m_buffer, Buffersize);
-    //char *pPtr = m_DataIt;
-    //char *pPtr = m_buffer;
-    //char *pEnd = &pPtr[Buffersize];
     m_DataIt = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
     if ( m_DataIt == m_DataItEnd || *m_DataIt == '\0' ) {
         return;
@@ -571,14 +567,7 @@ void ObjFileParser::getMaterialDesc() {
 // -------------------------------------------------------------------
 //  Get a comment, values will be skipped
 void ObjFileParser::getComment() {
-    while (m_DataIt != m_DataItEnd) {
-        if ( '\n' == (*m_DataIt)) {
-            ++m_DataIt;
-            break;
-        } else {
-            ++m_DataIt;
-        }
-    }
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 
 // -------------------------------------------------------------------

+ 4 - 5
code/ObjFileParser.h

@@ -91,6 +91,8 @@ protected:
     void copyNextWord(char *pBuffer, size_t length);
     /// Method to copy the new line.
 //    void copyNextLine(char *pBuffer, size_t length);
+    /// Get the number of components in a line.
+    size_t getNumComponentsInDataDefinition();
     /// Stores the vector
     void getVector( std::vector<aiVector3D> &point3d_array );
     /// Stores the following 3d vector.
@@ -129,8 +131,6 @@ protected:
     bool needsNewMesh( const std::string &rMaterialName );
     /// Error report in token
     void reportErrorTokenInFace();
-    /// Get the number of components in a line.
-    size_t getNumComponentsInLine();
 
 private:
     // Copy and assignment constructor should be private
@@ -154,9 +154,8 @@ private:
     IOSystem *m_pIO;
     //! Pointer to progress handler
     ProgressHandler* m_progress;
-    /// Path to the current model
-    // name of the obj file where the buffer comes from
-    const std::string& m_originalObjFileName;
+    /// Path to the current model, name of the obj file where the buffer comes from
+    const std::string m_originalObjFileName;
 };
 
 }   // Namespace Assimp

+ 5 - 3
code/ObjTools.h

@@ -116,14 +116,16 @@ inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) {
     while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) {
         ++it;
     }
-    if ( it != end )
-    {
+    
+    if ( it != end ) {
         ++it;
         ++uiLine;
     }
     // fix .. from time to time there are spaces at the beginning of a material line
-    while ( it != end && (*it == '\t' || *it == ' ') )
+    while ( it != end && ( *it == '\t' || *it == ' ' ) ) {
         ++it;
+    }
+
     return it;
 }
 

+ 1 - 1
code/OptimizeGraph.cpp

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

+ 1 - 1
code/OptimizeMeshes.cpp

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

+ 2 - 4
code/PlyExporter.h

@@ -51,14 +51,12 @@ struct aiScene;
 struct aiNode;
 struct aiMesh;
 
-namespace Assimp
-{
+namespace Assimp {
 
 // ------------------------------------------------------------------------------------------------
 /** Helper class to export a given scene to a Stanford Ply file. */
 // ------------------------------------------------------------------------------------------------
-class PlyExporter
-{
+class PlyExporter {
 public:
     /// The class constructor for a specific scene to export
     PlyExporter(const char* filename, const aiScene* pScene, bool binary = false);

+ 855 - 911
code/PlyLoader.cpp

@@ -5,7 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2017, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -13,18 +12,18 @@ 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.
+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.
+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.
+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
@@ -48,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "PlyLoader.h"
+#include "IOStreamBuffer.h"
 #include "Macros.h"
 #include <memory>
 #include <assimp/IOSystem.hpp>
@@ -57,16 +57,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 static const aiImporterDesc desc = {
-    "Stanford Polygon Library (PLY) Importer",
-    "",
-    "",
-    "",
-    aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour,
-    0,
-    0,
-    0,
-    0,
-    "ply"
+  "Stanford Polygon Library (PLY) Importer",
+  "",
+  "",
+  "",
+  aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour,
+  0,
+  0,
+  0,
+  0,
+  "ply"
 };
 
 
@@ -74,1040 +74,984 @@ static const aiImporterDesc desc = {
 // Internal stuff
 namespace
 {
-    // ------------------------------------------------------------------------------------------------
-    // Checks that property index is within range
-    template <class T>
-    const T &GetProperty(const std::vector<T> &props, int idx)
-    {
-        if( static_cast< size_t >( idx ) >= props.size() ) {
-            throw DeadlyImportError( "Invalid .ply file: Property index is out of range." );
-        }
-
-        return props[idx];
+  // ------------------------------------------------------------------------------------------------
+  // Checks that property index is within range
+  template <class T>
+  const T &GetProperty(const std::vector<T> &props, int idx)
+  {
+    if (static_cast<size_t>(idx) >= props.size()) {
+      throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
     }
+
+    return props[idx];
+  }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 PLYImporter::PLYImporter()
-: mBuffer()
-, pcDOM(){
-    // empty
+  : mBuffer()
+  , pcDOM()
+  , mGeneratedMesh(NULL){
+  // empty
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 PLYImporter::~PLYImporter() {
-    // empty
+  // empty
 }
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool PLYImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "ply")
-        return true;
-    else if (!extension.length() || checkSig)
-    {
-        if (!pIOHandler)return true;
-        const char* tokens[] = {"ply"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+  const std::string extension = GetExtension(pFile);
+
+  if (extension == "ply")
+    return true;
+  else if (!extension.length() || checkSig)
+  {
+    if (!pIOHandler)return true;
+    const char* tokens[] = { "ply" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+  }
+  return false;
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiImporterDesc* PLYImporter::GetInfo () const
+const aiImporterDesc* PLYImporter::GetInfo() const
 {
-    return &desc;
+  return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
-static bool isBigEndian( const char* szMe ) {
-    ai_assert( NULL != szMe );
+static bool isBigEndian(const char* szMe) {
+  ai_assert(NULL != szMe);
 
-    // binary_little_endian
-    // binary_big_endian
-    bool isBigEndian( false );
+  // binary_little_endian
+  // binary_big_endian
+  bool isBigEndian(false);
 #if (defined AI_BUILD_BIG_ENDIAN)
-    if ( 'l' == *szMe || 'L' == *szMe ) {
-        isBigEndian = true;
-}
+  if ( 'l' == *szMe || 'L' == *szMe ) {
+    isBigEndian = true;
+  }
 #else
-    if ( 'b' == *szMe || 'B' == *szMe ) {
-        isBigEndian = true;
-    }
+  if ('b' == *szMe || 'B' == *szMe) {
+    isBigEndian = true;
+  }
 #endif // ! AI_BUILD_BIG_ENDIAN
 
-    return isBigEndian;
+  return isBigEndian;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
-void PLYImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
+void PLYImporter::InternReadFile(const std::string& pFile,
+  aiScene* pScene, IOSystem* pIOHandler)
 {
-    std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
-
-    // Check whether we can read from the file
-    if( file.get() == NULL) {
-        throw DeadlyImportError( "Failed to open PLY file " + pFile + ".");
+  static const std::string mode = "rb";
+  std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
+  if (!fileStream.get()) {
+    throw DeadlyImportError("Failed to open file " + pFile + ".");
+  }
+
+  // Get the file-size
+  size_t fileSize = fileStream->FileSize();
+
+  IOStreamBuffer<char> streamedBuffer(1024 * 1024);
+  streamedBuffer.open(fileStream.get());
+
+  // the beginning of the file must be PLY - magic, magic
+  std::vector<char> headerCheck;
+  streamedBuffer.getNextLine(headerCheck);
+
+  if ((headerCheck.size() >= 3) && (headerCheck[0] != 'P' && headerCheck[0] != 'p') ||
+    (headerCheck[1] != 'L' && headerCheck[1] != 'l') ||
+    (headerCheck[2] != 'Y' && headerCheck[2] != 'y'))
+  {
+    streamedBuffer.close();
+    throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there");
+  }
+
+  std::vector<char> mBuffer2;
+  streamedBuffer.getNextLine(mBuffer2);
+  mBuffer = (unsigned char*)&mBuffer2[0];
+
+  char* szMe = (char*)&this->mBuffer[0];
+  SkipSpacesAndLineEnd(szMe, (const char**)&szMe);
+
+  // determine the format of the file data and construct the aimesh
+  PLY::DOM sPlyDom;
+  this->pcDOM = &sPlyDom;
+
+  if (TokenMatch(szMe, "format", 6)) {
+    if (TokenMatch(szMe, "ascii", 5)) {
+      SkipLine(szMe, (const char**)&szMe);
+      if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this))
+      {
+        if (mGeneratedMesh != NULL)
+          delete(mGeneratedMesh);
+
+        streamedBuffer.close();
+        throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)");
+      }
+    }
+    else if (!::strncmp(szMe, "binary_", 7))
+    {
+      szMe += 7;
+      const bool bIsBE(isBigEndian(szMe));
+
+      // skip the line, parse the rest of the header and build the DOM
+      if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE))
+      {
+        if (mGeneratedMesh != NULL)
+          delete(mGeneratedMesh);
+
+        streamedBuffer.close();
+        throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
+      }
     }
+    else
+    {
+      if (mGeneratedMesh != NULL)
+        delete(mGeneratedMesh);
 
-    // allocate storage and copy the contents of the file to a memory buffer
-    std::vector<char> mBuffer2;
-    TextFileToBuffer(file.get(),mBuffer2);
-    mBuffer = (unsigned char*)&mBuffer2[0];
+      streamedBuffer.close();
+      throw DeadlyImportError("Invalid .ply file: Unknown file format");
+    }
+  }
+  else
+  {
+    AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
+    if (mGeneratedMesh != NULL)
+      delete(mGeneratedMesh);
+
+    streamedBuffer.close();
+    throw DeadlyImportError("Invalid .ply file: Missing format specification");
+  }
+
+  //free the file buffer
+  streamedBuffer.close();
+
+  if (mGeneratedMesh == NULL)
+  {
+    throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
+  }
+
+  // if no face list is existing we assume that the vertex
+  // list is containing a list of points
+  bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false;
+  if (pointsOnly)
+  {
+    if (mGeneratedMesh->mNumVertices < 3)
+    {
+      if (mGeneratedMesh != NULL)
+        delete(mGeneratedMesh);
 
-    // the beginning of the file must be PLY - magic, magic
-    if ((mBuffer[0] != 'P' && mBuffer[0] != 'p') ||
-        (mBuffer[1] != 'L' && mBuffer[1] != 'l') ||
-        (mBuffer[2] != 'Y' && mBuffer[2] != 'y'))   {
-        throw DeadlyImportError( "Invalid .ply file: Magic number \'ply\' is no there");
+      streamedBuffer.close();
+      throw DeadlyImportError("Invalid .ply file: Not enough "
+        "vertices to build a proper face list. ");
     }
 
-    char* szMe = (char*)&this->mBuffer[3];
-    SkipSpacesAndLineEnd(szMe,(const char**)&szMe);
-
-    // determine the format of the file data
-    PLY::DOM sPlyDom;
-    if (TokenMatch(szMe,"format",6)) {
-        if (TokenMatch(szMe,"ascii",5)) {
-            SkipLine(szMe,(const char**)&szMe);
-            if(!PLY::DOM::ParseInstance(szMe,&sPlyDom))
-                throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#1)");
-        } else if (!::strncmp(szMe,"binary_",7))
-        {
-            szMe += 7;
-            const bool bIsBE( isBigEndian( szMe ) );
+    const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3;
+    mGeneratedMesh->mNumFaces = iNum;
+    mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
 
-            // skip the line, parse the rest of the header and build the DOM
-            SkipLine(szMe,(const char**)&szMe);
-            if ( !PLY::DOM::ParseInstanceBinary( szMe, &sPlyDom, bIsBE ) ) {
-                throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#2)" );
-            }
-        } else {
-            throw DeadlyImportError( "Invalid .ply file: Unknown file format" );
-        }
-    }
-    else
+    for (unsigned int i = 0; i < iNum; ++i)
     {
-        AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
-        throw DeadlyImportError( "Invalid .ply file: Missing format specification");
+      mGeneratedMesh->mFaces[i].mNumIndices = 3;
+      mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3];
+      mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3);
+      mGeneratedMesh->mFaces[i].mIndices[1] = (i * 3) + 1;
+      mGeneratedMesh->mFaces[i].mIndices[2] = (i * 3) + 2;
     }
-    this->pcDOM = &sPlyDom;
+  }
+
+  // now load a list of all materials
+  std::vector<aiMaterial*> avMaterials;
+  std::string defaultTexture;
+  LoadMaterial(&avMaterials, defaultTexture, pointsOnly);
+
+  // now generate the output scene object. Fill the material list
+  pScene->mNumMaterials = (unsigned int)avMaterials.size();
+  pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
+  for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
+    pScene->mMaterials[i] = avMaterials[i];
+  }
+
+  // fill the mesh list
+  pScene->mNumMeshes = 1;
+  pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
+  pScene->mMeshes[0] = mGeneratedMesh;
+
+  // generate a simple node structure
+  pScene->mRootNode = new aiNode();
+  pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
+  pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+
+  for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i) {
+    pScene->mRootNode->mMeshes[i] = i;
+  }
+}
 
-    // now load a list of vertices. This must be successfully in order to procedure
-    std::vector<aiVector3D> avPositions;
-    this->LoadVertices(&avPositions,false);
+void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos)
+{
+  ai_assert(NULL != pcElement);
+  ai_assert(NULL != instElement);
 
-    if ( avPositions.empty() ) {
-        throw DeadlyImportError( "Invalid .ply file: No vertices found. "
-            "Unable to parse the data format of the PLY file." );
-    }
+  ai_uint aiPositions[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  PLY::EDataType aiTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
+
+  ai_uint aiNormal[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  PLY::EDataType aiNormalTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
+
+  unsigned int aiColors[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+  PLY::EDataType aiColorsTypes[4] = { EDT_Char, EDT_Char, EDT_Char, EDT_Char };
+
+  unsigned int aiTexcoord[2] = { 0xFFFFFFFF, 0xFFFFFFFF };
+  PLY::EDataType aiTexcoordTypes[2] = { EDT_Char, EDT_Char };
 
-    // now load a list of normals.
-    std::vector<aiVector3D> avNormals;
-    LoadVertices(&avNormals,true);
+  unsigned int cnt = 0;
 
-    // load the face list
-    std::vector<PLY::Face> avFaces;
-    LoadFaces(&avFaces);
+  // now check whether which normal components are available
+  unsigned int _a = 0;
+  for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+    a != pcElement->alProperties.end(); ++a, ++_a)
+  {
+    if ((*a).bIsList)continue;
 
-    // if no face list is existing we assume that the vertex
-    // list is containing a list of triangles
-    if (avFaces.empty())
+    // Positions
+    if (PLY::EST_XCoord == (*a).Semantic)
     {
-        if (avPositions.size() < 3)
-        {
-            throw DeadlyImportError( "Invalid .ply file: Not enough "
-                "vertices to build a proper face list. ");
-        }
+      cnt++;
+      aiPositions[0] = _a;
+      aiTypes[0] = (*a).eType;
+    }
+    else if (PLY::EST_YCoord == (*a).Semantic)
+    {
+      cnt++;
+      aiPositions[1] = _a;
+      aiTypes[1] = (*a).eType;
+    }
+    else if (PLY::EST_ZCoord == (*a).Semantic)
+    {
+      cnt++;
+      aiPositions[2] = _a;
+      aiTypes[2] = (*a).eType;
+    }
 
-        const unsigned int iNum = (unsigned int)avPositions.size() / 3;
-        for (unsigned int i = 0; i< iNum;++i)
-        {
-            PLY::Face sFace;
-            sFace.mIndices.push_back((iNum*3));
-            sFace.mIndices.push_back((iNum*3)+1);
-            sFace.mIndices.push_back((iNum*3)+2);
-            avFaces.push_back(sFace);
-        }
+    // Normals
+    else if (PLY::EST_XNormal == (*a).Semantic)
+    {
+      cnt++;
+      aiNormal[0] = _a;
+      aiNormalTypes[0] = (*a).eType;
+    }
+    else if (PLY::EST_YNormal == (*a).Semantic)
+    {
+      cnt++;
+      aiNormal[1] = _a;
+      aiNormalTypes[1] = (*a).eType;
+    }
+    else if (PLY::EST_ZNormal == (*a).Semantic)
+    {
+      cnt++;
+      aiNormal[2] = _a;
+      aiNormalTypes[2] = (*a).eType;
+    }
+    // Colors
+    else if (PLY::EST_Red == (*a).Semantic)
+    {
+      cnt++;
+      aiColors[0] = _a;
+      aiColorsTypes[0] = (*a).eType;
+    }
+    else if (PLY::EST_Green == (*a).Semantic)
+    {
+      cnt++;
+      aiColors[1] = _a;
+      aiColorsTypes[1] = (*a).eType;
+    }
+    else if (PLY::EST_Blue == (*a).Semantic)
+    {
+      cnt++;
+      aiColors[2] = _a;
+      aiColorsTypes[2] = (*a).eType;
+    }
+    else if (PLY::EST_Alpha == (*a).Semantic)
+    {
+      cnt++;
+      aiColors[3] = _a;
+      aiColorsTypes[3] = (*a).eType;
+    }
+    // Texture coordinates
+    else if (PLY::EST_UTextureCoord == (*a).Semantic)
+    {
+      cnt++;
+      aiTexcoord[0] = _a;
+      aiTexcoordTypes[0] = (*a).eType;
+    }
+    else if (PLY::EST_VTextureCoord == (*a).Semantic)
+    {
+      cnt++;
+      aiTexcoord[1] = _a;
+      aiTexcoordTypes[1] = (*a).eType;
+    }
+  }
+
+  // check whether we have a valid source for the vertex data
+  if (0 != cnt)
+  {
+    // Position
+    aiVector3D vOut;
+    if (0xFFFFFFFF != aiPositions[0])
+    {
+      vOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]);
     }
 
-    // now load a list of all materials
-    std::vector<aiMaterial*> avMaterials;
-    LoadMaterial(&avMaterials);
+    if (0xFFFFFFFF != aiPositions[1])
+    {
+      vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]);
+    }
 
-    // now load a list of all vertex color channels
-    std::vector<aiColor4D> avColors;
-    avColors.reserve(avPositions.size());
-    LoadVertexColor(&avColors);
+    if (0xFFFFFFFF != aiPositions[2])
+    {
+      vOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]);
+    }
 
-    // now try to load texture coordinates
-    std::vector<aiVector2D> avTexCoords;
-    avTexCoords.reserve(avPositions.size());
-    LoadTextureCoordinates(&avTexCoords);
+    // Normals
+    aiVector3D nOut;
+    bool haveNormal = false;
+    if (0xFFFFFFFF != aiNormal[0])
+    {
+      nOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]);
+      haveNormal = true;
+    }
 
-    // now replace the default material in all faces and validate all material indices
-    ReplaceDefaultMaterial(&avFaces,&avMaterials);
+    if (0xFFFFFFFF != aiNormal[1])
+    {
+      nOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]);
+      haveNormal = true;
+    }
 
-    // now convert this to a list of aiMesh instances
-    std::vector<aiMesh*> avMeshes;
-    avMeshes.reserve(avMaterials.size()+1);
-    ConvertMeshes(&avFaces,&avPositions,&avNormals,
-        &avColors,&avTexCoords,&avMaterials,&avMeshes);
+    if (0xFFFFFFFF != aiNormal[2])
+    {
+      nOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]);
+      haveNormal = true;
+    }
 
-    if ( avMeshes.empty() ) {
-        throw DeadlyImportError( "Invalid .ply file: Unable to extract mesh data " );
+    //Colors
+    aiColor4D cOut;
+    bool haveColor = false;
+    if (0xFFFFFFFF != aiColors[0])
+    {
+      cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties,
+        aiColors[0]).avList.front(), aiColorsTypes[0]);
+      haveColor = true;
     }
 
-    // now generate the output scene object. Fill the material list
-    pScene->mNumMaterials = (unsigned int)avMaterials.size();
-    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
-    for ( unsigned int i = 0; i < pScene->mNumMaterials; ++i ) {
-        pScene->mMaterials[ i ] = avMaterials[ i ];
+    if (0xFFFFFFFF != aiColors[1])
+    {
+      cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties,
+        aiColors[1]).avList.front(), aiColorsTypes[1]);
+      haveColor = true;
     }
 
-    // fill the mesh list
-    pScene->mNumMeshes = (unsigned int)avMeshes.size();
-    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-    for ( unsigned int i = 0; i < pScene->mNumMeshes; ++i ) {
-        pScene->mMeshes[ i ] = avMeshes[ i ];
+    if (0xFFFFFFFF != aiColors[2])
+    {
+      cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties,
+        aiColors[2]).avList.front(), aiColorsTypes[2]);
+      haveColor = true;
     }
 
-    // generate a simple node structure
-    pScene->mRootNode = new aiNode();
-    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
-    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+    // assume 1.0 for the alpha channel ifit is not set
+    if (0xFFFFFFFF == aiColors[3])
+    {
+      cOut.a = 1.0;
+    }
+    else
+    {
+      cOut.a = NormalizeColorValue(GetProperty(instElement->alProperties,
+        aiColors[3]).avList.front(), aiColorsTypes[3]);
 
-    for ( unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i ) {
-        pScene->mRootNode->mMeshes[ i ] = i;
+      haveColor = true;
     }
-}
 
-// ------------------------------------------------------------------------------------------------
-// Split meshes by material IDs
-void PLYImporter::ConvertMeshes(std::vector<PLY::Face>* avFaces,
-    const std::vector<aiVector3D>*          avPositions,
-    const std::vector<aiVector3D>*          avNormals,
-    const std::vector<aiColor4D>*           avColors,
-    const std::vector<aiVector2D>*          avTexCoords,
-    const std::vector<aiMaterial*>*     avMaterials,
-    std::vector<aiMesh*>* avOut)
-{
-    ai_assert(NULL != avFaces);
-    ai_assert(NULL != avPositions);
-    ai_assert(NULL != avMaterials);
+    //Texture coordinates
+    aiVector3D tOut;
+    tOut.z = 0;
+    bool haveTextureCoords = false;
+    if (0xFFFFFFFF != aiTexcoord[0])
+    {
+      tOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]);
+      haveTextureCoords = true;
+    }
 
-    // split by materials
-    std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[avMaterials->size()];
+    if (0xFFFFFFFF != aiTexcoord[1])
+    {
+      tOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
+        GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]);
+      haveTextureCoords = true;
+    }
 
-    unsigned int iNum = 0;
-    for (std::vector<PLY::Face>::const_iterator i = avFaces->begin();i != avFaces->end();++i,++iNum)
-        aiSplit[(*i).iMaterialIndex].push_back(iNum);
+    //create aiMesh if needed
+    if (mGeneratedMesh == NULL)
+    {
+      mGeneratedMesh = new aiMesh();
+      mGeneratedMesh->mMaterialIndex = 0;
+    }
 
-    // now generate sub-meshes
-    for (unsigned int p = 0; p < avMaterials->size();++p)
+    if (mGeneratedMesh->mVertices == NULL)
     {
-        if (aiSplit[p].size() != 0)
-        {
-            // allocate the mesh object
-            aiMesh* p_pcOut = new aiMesh();
-            p_pcOut->mMaterialIndex = p;
+      mGeneratedMesh->mNumVertices = pcElement->NumOccur;
+      mGeneratedMesh->mVertices = new aiVector3D[mGeneratedMesh->mNumVertices];
+    }
 
-            p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size();
-            p_pcOut->mFaces = new aiFace[aiSplit[p].size()];
+    mGeneratedMesh->mVertices[pos] = vOut;
 
-            // at first we need to determine the size of the output vector array
-            unsigned int iNum = 0;
-            for (unsigned int i = 0; i < aiSplit[p].size();++i)
-            {
-                iNum += (unsigned int)(*avFaces)[aiSplit[p][i]].mIndices.size();
-            }
-            p_pcOut->mNumVertices = iNum;
-            if( 0 == iNum ) {     // nothing to do
-                delete[] aiSplit; // cleanup
-                delete p_pcOut;
-                return;
-            }
-            p_pcOut->mVertices = new aiVector3D[iNum];
+    if (haveNormal)
+    {
+      if (mGeneratedMesh->mNormals == NULL)
+        mGeneratedMesh->mNormals = new aiVector3D[mGeneratedMesh->mNumVertices];
+      mGeneratedMesh->mNormals[pos] = nOut;
+    }
 
-            if (!avColors->empty())
-                p_pcOut->mColors[0] = new aiColor4D[iNum];
-            if (!avTexCoords->empty())
-            {
-                p_pcOut->mNumUVComponents[0] = 2;
-                p_pcOut->mTextureCoords[0] = new aiVector3D[iNum];
-            }
-            if (!avNormals->empty())
-                p_pcOut->mNormals = new aiVector3D[iNum];
-
-            // add all faces
-            iNum = 0;
-            unsigned int iVertex = 0;
-            for (std::vector<unsigned int>::const_iterator i =  aiSplit[p].begin();
-                i != aiSplit[p].end();++i,++iNum)
-            {
-                p_pcOut->mFaces[iNum].mNumIndices = (unsigned int)(*avFaces)[*i].mIndices.size();
-                p_pcOut->mFaces[iNum].mIndices = new unsigned int[p_pcOut->mFaces[iNum].mNumIndices];
-
-                // build an unique set of vertices/colors for this face
-                for (unsigned int q = 0; q <  p_pcOut->mFaces[iNum].mNumIndices;++q)
-                {
-                    p_pcOut->mFaces[iNum].mIndices[q] = iVertex;
-                    const size_t idx = ( *avFaces )[ *i ].mIndices[ q ];
-                    if( idx >= ( *avPositions ).size() ) {
-                        // out of border
-                        continue;
-                    }
-                    p_pcOut->mVertices[ iVertex ] = ( *avPositions )[ idx ];
-
-                    if (!avColors->empty())
-                        p_pcOut->mColors[ 0 ][ iVertex ] = ( *avColors )[ idx ];
-
-                    if (!avTexCoords->empty())
-                    {
-                        const aiVector2D& vec = ( *avTexCoords )[ idx ];
-                        p_pcOut->mTextureCoords[0][iVertex].x = vec.x;
-                        p_pcOut->mTextureCoords[0][iVertex].y = vec.y;
-                    }
-
-                    if (!avNormals->empty())
-                        p_pcOut->mNormals[ iVertex ] = ( *avNormals )[ idx ];
-                    iVertex++;
-                }
+    if (haveColor)
+    {
+      if (mGeneratedMesh->mColors[0] == NULL)
+        mGeneratedMesh->mColors[0] = new aiColor4D[mGeneratedMesh->mNumVertices];
+      mGeneratedMesh->mColors[0][pos] = cOut;
+    }
 
-            }
-            // add the mesh to the output list
-            avOut->push_back(p_pcOut);
-        }
+    if (haveTextureCoords)
+    {
+      if (mGeneratedMesh->mTextureCoords[0] == NULL)
+      {
+        mGeneratedMesh->mNumUVComponents[0] = 2;
+        mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
+      }
+      mGeneratedMesh->mTextureCoords[0][pos] = tOut;
     }
-    delete[] aiSplit; // cleanup
+  }
 }
 
+
 // ------------------------------------------------------------------------------------------------
-// Generate a default material if none was specified and apply it to all vanilla faces
-void PLYImporter::ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
-    std::vector<aiMaterial*>* avMaterials)
+// Convert a color component to [0...1]
+ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val,
+  PLY::EDataType eType)
 {
-    bool bNeedDefaultMat = false;
+  switch (eType)
+  {
+  case EDT_Float:
+    return val.fFloat;
+  case EDT_Double:
+    return (ai_real)val.fDouble;
+
+  case EDT_UChar:
+    return (ai_real)val.iUInt / (ai_real)0xFF;
+  case EDT_Char:
+    return (ai_real)(val.iInt + (0xFF / 2)) / (ai_real)0xFF;
+  case EDT_UShort:
+    return (ai_real)val.iUInt / (ai_real)0xFFFF;
+  case EDT_Short:
+    return (ai_real)(val.iInt + (0xFFFF / 2)) / (ai_real)0xFFFF;
+  case EDT_UInt:
+    return (ai_real)val.iUInt / (ai_real)0xFFFF;
+  case EDT_Int:
+    return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f;
+  default:;
+  };
+  return 0.0f;
+}
 
-    for (std::vector<PLY::Face>::iterator i =  avFaces->begin();i != avFaces->end();++i)    {
-        if (0xFFFFFFFF == (*i).iMaterialIndex)  {
-            bNeedDefaultMat = true;
-            (*i).iMaterialIndex = (unsigned int)avMaterials->size();
-        }
-        else if ((*i).iMaterialIndex >= avMaterials->size() )   {
-            // clamp the index
-            (*i).iMaterialIndex = (unsigned int)avMaterials->size()-1;
-        }
-    }
+// ------------------------------------------------------------------------------------------------
+// Try to extract proper faces from the PLY DOM
+void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos)
+{
+  ai_assert(NULL != pcElement);
+  ai_assert(NULL != instElement);
 
-    if (bNeedDefaultMat)    {
-        // generate a default material
-        aiMaterial* pcHelper = new aiMaterial();
+  if (mGeneratedMesh == NULL)
+    throw DeadlyImportError("Invalid .ply file: Vertices shoud be declared before faces");
 
-        // fill in a default material
-        int iMode = (int)aiShadingMode_Gouraud;
-        pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+  bool bOne = false;
 
-        aiColor3D clr;
-        clr.b = clr.g = clr.r = 0.6f;
-        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_DIFFUSE);
-        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_SPECULAR);
+  // index of the vertex index list
+  unsigned int iProperty = 0xFFFFFFFF;
+  PLY::EDataType eType = EDT_Char;
+  bool bIsTriStrip = false;
 
-        clr.b = clr.g = clr.r = 0.05f;
-        pcHelper->AddProperty<aiColor3D>(&clr, 1,AI_MATKEY_COLOR_AMBIENT);
+  // index of the material index property
+  //unsigned int iMaterialIndex = 0xFFFFFFFF;
+  //PLY::EDataType eType2 = EDT_Char;
 
-        // The face order is absolutely undefined for PLY, so we have to
-        // use two-sided rendering to be sure it's ok.
-        const int two_sided = 1;
-        pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED);
+  // texture coordinates
+  unsigned int iTextureCoord = 0xFFFFFFFF;
+  PLY::EDataType eType3 = EDT_Char;
 
-        avMaterials->push_back(pcHelper);
+  // face = unique number of vertex indices
+  if (PLY::EEST_Face == pcElement->eSemantic)
+  {
+    unsigned int _a = 0;
+    for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+      a != pcElement->alProperties.end(); ++a, ++_a)
+    {
+      if (PLY::EST_VertexIndex == (*a).Semantic)
+      {
+        // must be a dynamic list!
+        if (!(*a).bIsList)
+          continue;
+
+        iProperty = _a;
+        bOne = true;
+        eType = (*a).eType;
+      }
+      /*else if (PLY::EST_MaterialIndex == (*a).Semantic)
+      {
+      if ((*a).bIsList)
+      continue;
+      iMaterialIndex = _a;
+      bOne = true;
+      eType2 = (*a).eType;
+      }*/
+      else if (PLY::EST_TextureCoordinates == (*a).Semantic)
+      {
+        // must be a dynamic list!
+        if (!(*a).bIsList)
+          continue;
+        iTextureCoord = _a;
+        bOne = true;
+        eType3 = (*a).eType;
+      }
     }
-}
-
-// ------------------------------------------------------------------------------------------------
-void PLYImporter::LoadTextureCoordinates(std::vector<aiVector2D>* pvOut)
-{
-    ai_assert(NULL != pvOut);
-
-    unsigned int aiPositions[2] = {0xFFFFFFFF,0xFFFFFFFF};
-    PLY::EDataType aiTypes[2] = {EDT_Char,EDT_Char};
-    PLY::ElementInstanceList* pcList = NULL;
-    unsigned int cnt = 0;
-
-    // search in the DOM for a vertex entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
-        i != pcDOM->alElements.end();++i,++_i)
+  }
+  // triangle strip
+  // TODO: triangle strip and material index support???
+  else if (PLY::EEST_TriStrip == pcElement->eSemantic)
+  {
+    unsigned int _a = 0;
+    for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+      a != pcElement->alProperties.end(); ++a, ++_a)
     {
-        if (PLY::EEST_Vertex == (*i).eSemantic)
-        {
-            pcList = &this->pcDOM->alElementData[_i];
+      // must be a dynamic list!
+      if (!(*a).bIsList)
+        continue;
+      iProperty = _a;
+      bOne = true;
+      bIsTriStrip = true;
+      eType = (*a).eType;
+      break;
+    }
+  }
 
-            // now check whether which normal components are available
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                if ((*a).bIsList)continue;
-                if (PLY::EST_UTextureCoord == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[0] = _a;
-                    aiTypes[0] = (*a).eType;
-                }
-                else if (PLY::EST_VTextureCoord == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[1] = _a;
-                    aiTypes[1] = (*a).eType;
-                }
-            }
-        }
+  // check whether we have at least one per-face information set
+  if (bOne)
+  {
+    if (mGeneratedMesh->mFaces == NULL)
+    {
+      mGeneratedMesh->mNumFaces = pcElement->NumOccur;
+      mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
     }
-    // check whether we have a valid source for the texture coordinates data
-    if (NULL != pcList && 0 != cnt)
+
+    if (!bIsTriStrip)
     {
-        pvOut->reserve(pcList->alInstances.size());
-        for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
-            i != pcList->alInstances.end();++i)
-        {
-            // convert the vertices to sp floats
-            aiVector2D vOut;
+      // parse the list of vertex indices
+      if (0xFFFFFFFF != iProperty)
+      {
+        const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iProperty).avList.size();
+        mGeneratedMesh->mFaces[pos].mNumIndices = iNum;
+        mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[iNum];
 
-            if (0xFFFFFFFF != aiPositions[0])
-            {
-                vOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]);
-            }
+        std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
+          GetProperty(instElement->alProperties, iProperty).avList.begin();
 
-            if (0xFFFFFFFF != aiPositions[1])
-            {
-                vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]);
-            }
-            // and add them to our nice list
-            pvOut->push_back(vOut);
+        for (unsigned int a = 0; a < iNum; ++a, ++p)
+        {
+          mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p, eType);
         }
-    }
-}
+      }
 
-// ------------------------------------------------------------------------------------------------
-// Try to extract vertices from the PLY DOM
-void PLYImporter::LoadVertices(std::vector<aiVector3D>* pvOut, bool p_bNormals)
-{
-    ai_assert(NULL != pvOut);
+      // parse the material index
+      // cannot be handled without processing the whole file first
+      /*if (0xFFFFFFFF != iMaterialIndex)
+      {
+      mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo<unsigned int>(
+      GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2);
+      }*/
 
-    ai_uint aiPositions[3] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
-    PLY::EDataType aiTypes[3] = {EDT_Char,EDT_Char,EDT_Char};
-    PLY::ElementInstanceList* pcList = NULL;
-    unsigned int cnt = 0;
+      if (0xFFFFFFFF != iTextureCoord)
+      {
+        const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iTextureCoord).avList.size();
 
-    // search in the DOM for a vertex entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i =  pcDOM->alElements.begin();
-        i != pcDOM->alElements.end();++i,++_i)
-    {
-        if (PLY::EEST_Vertex == (*i).eSemantic)
-        {
-            pcList = &pcDOM->alElementData[_i];
+        //should be 6 coords
+        std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
+          GetProperty(instElement->alProperties, iTextureCoord).avList.begin();
 
-            // load normal vectors?
-            if (p_bNormals)
-            {
-                // now check whether which normal components are available
-                unsigned int _a = 0;
-                for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
-                    a != (*i).alProperties.end();++a,++_a)
-                {
-                    if ((*a).bIsList)continue;
-                    if (PLY::EST_XNormal == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[0] = _a;
-                        aiTypes[0] = (*a).eType;
-                    }
-                    else if (PLY::EST_YNormal == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[1] = _a;
-                        aiTypes[1] = (*a).eType;
-                    }
-                    else if (PLY::EST_ZNormal == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[2] = _a;
-                        aiTypes[2] = (*a).eType;
-                    }
-                }
-            }
-            // load vertex coordinates
-            else
+        if ((iNum / 3) == 2) // X Y coord
+        {
+          for (unsigned int a = 0; a < iNum; ++a, ++p)
+          {
+            unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2];
+            if (vindex < mGeneratedMesh->mNumVertices)
             {
-                // now check whether which coordinate sets are available
-                unsigned int _a = 0;
-                for (std::vector<PLY::Property>::const_iterator a = (*i).alProperties.begin();
-                    a != (*i).alProperties.end();++a,++_a)
-                {
-                    if ((*a).bIsList)continue;
-                    if (PLY::EST_XCoord == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[0] = _a;
-                        aiTypes[0] = (*a).eType;
-                    }
-                    else if (PLY::EST_YCoord == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[1] = _a;
-                        aiTypes[1] = (*a).eType;
-                    }
-                    else if (PLY::EST_ZCoord == (*a).Semantic)
-                    {
-                        cnt++;
-                        aiPositions[2] = _a;
-                        aiTypes[2] = (*a).eType;
-                    }
-                    if (3 == cnt)break;
-                }
+              if (mGeneratedMesh->mTextureCoords[0] == NULL)
+              {
+                mGeneratedMesh->mNumUVComponents[0] = 2;
+                mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
+              }
+
+              if (a % 2 == 0)
+                mGeneratedMesh->mTextureCoords[0][vindex].x = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
+              else
+                mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
+
+              mGeneratedMesh->mTextureCoords[0][vindex].z = 0;
             }
-            break;
+          }
         }
+      }
     }
-    // check whether we have a valid source for the vertex data
-    if (NULL != pcList && 0 != cnt)
+    else // triangle strips
     {
-        pvOut->reserve(pcList->alInstances.size());
-        for (std::vector<ElementInstance>::const_iterator
-            i =  pcList->alInstances.begin();
-            i != pcList->alInstances.end();++i)
-        {
-            // convert the vertices to sp floats
-            aiVector3D vOut;
-
-            if (0xFFFFFFFF != aiPositions[0])
-            {
-                vOut.x = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]);
-            }
+      // normally we have only one triangle strip instance where
+      // a value of -1 indicates a restart of the strip
+      bool flip = false;
+      const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty(instElement->alProperties, iProperty).avList;
+      //pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); //Limits memory consumption
+
+      int aiTable[2] = { -1, -1 };
+      for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin(); a != quak.end(); ++a)  {
+        const int p = PLY::PropertyInstance::ConvertTo<int>(*a, eType);
+
+        if (-1 == p)    {
+          // restart the strip ...
+          aiTable[0] = aiTable[1] = -1;
+          flip = false;
+          continue;
+        }
+        if (-1 == aiTable[0]) {
+          aiTable[0] = p;
+          continue;
+        }
+        if (-1 == aiTable[1]) {
+          aiTable[1] = p;
+          continue;
+        }
 
-            if (0xFFFFFFFF != aiPositions[1])
-            {
-                vOut.y = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]);
-            }
+        if (mGeneratedMesh->mFaces == NULL)
+        {
+          mGeneratedMesh->mNumFaces = pcElement->NumOccur;
+          mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
+        }
 
-            if (0xFFFFFFFF != aiPositions[2])
-            {
-                vOut.z = PLY::PropertyInstance::ConvertTo<ai_real>(
-                    GetProperty((*i).alProperties, aiPositions[2]).avList.front(),aiTypes[2]);
-            }
+        mGeneratedMesh->mFaces[pos].mNumIndices = 3;
+        mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[3];
+        mGeneratedMesh->mFaces[pos].mIndices[0] = aiTable[0];
+        mGeneratedMesh->mFaces[pos].mIndices[1] = aiTable[1];
+        mGeneratedMesh->mFaces[pos].mIndices[2] = aiTable[2];
 
-            // and add them to our nice list
-            pvOut->push_back(vOut);
+        if ((flip = !flip)) {
+          std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]);
         }
+
+        aiTable[0] = aiTable[1];
+        aiTable[1] = p;
+      }
     }
+  }
 }
 
 // ------------------------------------------------------------------------------------------------
-// Convert a color component to [0...1]
-ai_real PLYImporter::NormalizeColorValue (PLY::PropertyInstance::ValueUnion val,
-    PLY::EDataType eType)
+// Get a RGBA color in [0...1] range
+void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
+  unsigned int aiPositions[4],
+  PLY::EDataType aiTypes[4],
+  aiColor4D* clrOut)
 {
-    switch (eType)
-    {
-    case EDT_Float:
-        return val.fFloat;
-    case EDT_Double:
-        return (ai_real)val.fDouble;
-
-    case EDT_UChar:
-        return (ai_real)val.iUInt / (ai_real)0xFF;
-    case EDT_Char:
-        return (ai_real)(val.iInt+(0xFF/2)) / (ai_real)0xFF;
-    case EDT_UShort:
-        return (ai_real)val.iUInt / (ai_real)0xFFFF;
-    case EDT_Short:
-        return (ai_real)(val.iInt+(0xFFFF/2)) / (ai_real)0xFFFF;
-    case EDT_UInt:
-        return (ai_real)val.iUInt / (ai_real)0xFFFF;
-    case EDT_Int:
-        return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f;
-    default: ;
-    };
-    return 0.0f;
+  ai_assert(NULL != clrOut);
+
+  if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
+  else
+  {
+    clrOut->r = NormalizeColorValue(GetProperty(avList,
+      aiPositions[0]).avList.front(), aiTypes[0]);
+  }
+
+  if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
+  else
+  {
+    clrOut->g = NormalizeColorValue(GetProperty(avList,
+      aiPositions[1]).avList.front(), aiTypes[1]);
+  }
+
+  if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
+  else
+  {
+    clrOut->b = NormalizeColorValue(GetProperty(avList,
+      aiPositions[2]).avList.front(), aiTypes[2]);
+  }
+
+  // assume 1.0 for the alpha channel ifit is not set
+  if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
+  else
+  {
+    clrOut->a = NormalizeColorValue(GetProperty(avList,
+      aiPositions[3]).avList.front(), aiTypes[3]);
+  }
 }
 
 // ------------------------------------------------------------------------------------------------
-// Try to extract proper vertex colors from the PLY DOM
-void PLYImporter::LoadVertexColor(std::vector<aiColor4D>* pvOut)
+// Extract a material from the PLY DOM
+void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &defaultTexture, const bool pointsOnly)
 {
-    ai_assert(NULL != pvOut);
-
-    unsigned int aiPositions[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
-    PLY::EDataType aiTypes[4] = {EDT_Char, EDT_Char, EDT_Char, EDT_Char}; // silencing gcc
-    unsigned int cnt = 0;
-    PLY::ElementInstanceList* pcList = NULL;
-
-    // search in the DOM for a vertex entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i = pcDOM->alElements.begin();
-        i != pcDOM->alElements.end();++i,++_i)
+  ai_assert(NULL != pvOut);
+
+  // diffuse[4], specular[4], ambient[4]
+  // rgba order
+  unsigned int aaiPositions[3][4] = {
+
+    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
+    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
+    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF },
+  };
+
+  PLY::EDataType aaiTypes[3][4] = {
+    { EDT_Char, EDT_Char, EDT_Char, EDT_Char },
+    { EDT_Char, EDT_Char, EDT_Char, EDT_Char },
+    { EDT_Char, EDT_Char, EDT_Char, EDT_Char }
+  };
+  PLY::ElementInstanceList* pcList = NULL;
+
+  unsigned int iPhong = 0xFFFFFFFF;
+  PLY::EDataType ePhong = EDT_Char;
+
+  unsigned int iOpacity = 0xFFFFFFFF;
+  PLY::EDataType eOpacity = EDT_Char;
+
+  // search in the DOM for a vertex entry
+  unsigned int _i = 0;
+  for (std::vector<PLY::Element>::const_iterator i = this->pcDOM->alElements.begin();
+    i != this->pcDOM->alElements.end(); ++i, ++_i)
+  {
+    if (PLY::EEST_Material == (*i).eSemantic)
     {
-        if (PLY::EEST_Vertex == (*i).eSemantic)
+      pcList = &this->pcDOM->alElementData[_i];
+
+      // now check whether which coordinate sets are available
+      unsigned int _a = 0;
+      for (std::vector<PLY::Property>::const_iterator
+        a = (*i).alProperties.begin();
+        a != (*i).alProperties.end(); ++a, ++_a)
+      {
+        if ((*a).bIsList)continue;
+
+        // pohng specularity      -----------------------------------
+        if (PLY::EST_PhongPower == (*a).Semantic)
         {
-            pcList = &this->pcDOM->alElementData[_i];
-
-            // now check whether which coordinate sets are available
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator
-                a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                if ((*a).bIsList)continue;
-                if (PLY::EST_Red == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[0] = _a;
-                    aiTypes[0] = (*a).eType;
-                }
-                else if (PLY::EST_Green == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[1] = _a;
-                    aiTypes[1] = (*a).eType;
-                }
-                else if (PLY::EST_Blue == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[2] = _a;
-                    aiTypes[2] = (*a).eType;
-                }
-                else if (PLY::EST_Alpha == (*a).Semantic)
-                {
-                    cnt++;
-                    aiPositions[3] = _a;
-                    aiTypes[3] = (*a).eType;
-                }
-                if (4 == cnt)break;
-            }
-            break;
+          iPhong = _a;
+          ePhong = (*a).eType;
         }
-    }
-    // check whether we have a valid source for the vertex data
-    if (NULL != pcList && 0 != cnt)
-    {
-        pvOut->reserve(pcList->alInstances.size());
-        for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();
-            i != pcList->alInstances.end();++i)
-        {
-            // convert the vertices to sp floats
-            aiColor4D vOut;
-
-            if (0xFFFFFFFF != aiPositions[0])
-            {
-                vOut.r = NormalizeColorValue(GetProperty((*i).alProperties,
-                    aiPositions[0]).avList.front(),aiTypes[0]);
-            }
-
-            if (0xFFFFFFFF != aiPositions[1])
-            {
-                vOut.g = NormalizeColorValue(GetProperty((*i).alProperties,
-                    aiPositions[1]).avList.front(),aiTypes[1]);
-            }
-
-            if (0xFFFFFFFF != aiPositions[2])
-            {
-                vOut.b = NormalizeColorValue(GetProperty((*i).alProperties,
-                    aiPositions[2]).avList.front(),aiTypes[2]);
-            }
-
-            // assume 1.0 for the alpha channel ifit is not set
-            if (0xFFFFFFFF == aiPositions[3])vOut.a = 1.0;
-            else
-            {
-                vOut.a = NormalizeColorValue(GetProperty((*i).alProperties,
-                    aiPositions[3]).avList.front(),aiTypes[3]);
-            }
 
-            // and add them to our nice list
-            pvOut->push_back(vOut);
+        // general opacity        -----------------------------------
+        if (PLY::EST_Opacity == (*a).Semantic)
+        {
+          iOpacity = _a;
+          eOpacity = (*a).eType;
         }
-    }
-}
-
-// ------------------------------------------------------------------------------------------------
-// Try to extract proper faces from the PLY DOM
-void PLYImporter::LoadFaces(std::vector<PLY::Face>* pvOut)
-{
-    ai_assert(NULL != pvOut);
 
-    PLY::ElementInstanceList* pcList = NULL;
-    bool bOne = false;
-
-    // index of the vertex index list
-    unsigned int iProperty = 0xFFFFFFFF;
-    PLY::EDataType eType = EDT_Char;
-    bool bIsTriStrip = false;
-
-    // index of the material index property
-    unsigned int iMaterialIndex = 0xFFFFFFFF;
-    PLY::EDataType eType2 = EDT_Char;
-
-    // search in the DOM for a face entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i =  pcDOM->alElements.begin();
-        i != pcDOM->alElements.end();++i,++_i)
-    {
-        // face = unique number of vertex indices
-        if (PLY::EEST_Face == (*i).eSemantic)
+        // diffuse color channels -----------------------------------
+        if (PLY::EST_DiffuseRed == (*a).Semantic)
         {
-            pcList = &pcDOM->alElementData[_i];
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                if (PLY::EST_VertexIndex == (*a).Semantic)
-                {
-                    // must be a dynamic list!
-                    if (!(*a).bIsList)continue;
-                    iProperty   = _a;
-                    bOne        = true;
-                    eType       = (*a).eType;
-                }
-                else if (PLY::EST_MaterialIndex == (*a).Semantic)
-                {
-                    if ((*a).bIsList)continue;
-                    iMaterialIndex  = _a;
-                    bOne            = true;
-                    eType2      = (*a).eType;
-                }
-            }
-            break;
+          aaiPositions[0][0] = _a;
+          aaiTypes[0][0] = (*a).eType;
         }
-        // triangle strip
-        // TODO: triangle strip and material index support???
-        else if (PLY::EEST_TriStrip == (*i).eSemantic)
+        else if (PLY::EST_DiffuseGreen == (*a).Semantic)
         {
-            // find a list property in this ...
-            pcList = &this->pcDOM->alElementData[_i];
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                // must be a dynamic list!
-                if (!(*a).bIsList)continue;
-                iProperty   = _a;
-                bOne        = true;
-                bIsTriStrip = true;
-                eType       = (*a).eType;
-                break;
-            }
-            break;
+          aaiPositions[0][1] = _a;
+          aaiTypes[0][1] = (*a).eType;
         }
-    }
-    // check whether we have at least one per-face information set
-    if (pcList && bOne)
-    {
-        if (!bIsTriStrip)
+        else if (PLY::EST_DiffuseBlue == (*a).Semantic)
         {
-            pvOut->reserve(pcList->alInstances.size());
-            for (std::vector<ElementInstance>::const_iterator i =  pcList->alInstances.begin();
-                i != pcList->alInstances.end();++i)
-            {
-                PLY::Face sFace;
-
-                // parse the list of vertex indices
-                if (0xFFFFFFFF != iProperty)
-                {
-                    const unsigned int iNum = (unsigned int)GetProperty((*i).alProperties, iProperty).avList.size();
-                    sFace.mIndices.resize(iNum);
-
-                    std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
-                        GetProperty((*i).alProperties, iProperty).avList.begin();
-
-                    for (unsigned int a = 0; a < iNum;++a,++p)
-                    {
-                        sFace.mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p,eType);
-                    }
-                }
-
-                // parse the material index
-                if (0xFFFFFFFF != iMaterialIndex)
-                {
-                    sFace.iMaterialIndex = PLY::PropertyInstance::ConvertTo<unsigned int>(
-                        GetProperty((*i).alProperties, iMaterialIndex).avList.front(),eType2);
-                }
-                pvOut->push_back(sFace);
-            }
+          aaiPositions[0][2] = _a;
+          aaiTypes[0][2] = (*a).eType;
         }
-        else // triangle strips
+        else if (PLY::EST_DiffuseAlpha == (*a).Semantic)
         {
-            // normally we have only one triangle strip instance where
-            // a value of -1 indicates a restart of the strip
-            bool flip = false;
-            for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) {
-                const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty((*i).alProperties, iProperty).avList;
-                pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u));
-
-                int aiTable[2] = {-1,-1};
-                for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a =  quak.begin();a != quak.end();++a)  {
-                    const int p = PLY::PropertyInstance::ConvertTo<int>(*a,eType);
-
-                    if (-1 == p)    {
-                        // restart the strip ...
-                        aiTable[0] = aiTable[1] = -1;
-                        flip = false;
-                        continue;
-                    }
-                    if (-1 == aiTable[0]) {
-                        aiTable[0] = p;
-                        continue;
-                    }
-                    if (-1 == aiTable[1]) {
-                        aiTable[1] = p;
-                        continue;
-                    }
-
-                    pvOut->push_back(PLY::Face());
-                    PLY::Face& sFace = pvOut->back();
-                    sFace.mIndices[0] = aiTable[0];
-                    sFace.mIndices[1] = aiTable[1];
-                    sFace.mIndices[2] = p;
-                    if ((flip = !flip)) {
-                        std::swap(sFace.mIndices[0],sFace.mIndices[1]);
-                    }
-
-                    aiTable[0] = aiTable[1];
-                    aiTable[1] = p;
-                }
-            }
+          aaiPositions[0][3] = _a;
+          aaiTypes[0][3] = (*a).eType;
+        }
+        // specular color channels -----------------------------------
+        else if (PLY::EST_SpecularRed == (*a).Semantic)
+        {
+          aaiPositions[1][0] = _a;
+          aaiTypes[1][0] = (*a).eType;
         }
+        else if (PLY::EST_SpecularGreen == (*a).Semantic)
+        {
+          aaiPositions[1][1] = _a;
+          aaiTypes[1][1] = (*a).eType;
+        }
+        else if (PLY::EST_SpecularBlue == (*a).Semantic)
+        {
+          aaiPositions[1][2] = _a;
+          aaiTypes[1][2] = (*a).eType;
+        }
+        else if (PLY::EST_SpecularAlpha == (*a).Semantic)
+        {
+          aaiPositions[1][3] = _a;
+          aaiTypes[1][3] = (*a).eType;
+        }
+        // ambient color channels -----------------------------------
+        else if (PLY::EST_AmbientRed == (*a).Semantic)
+        {
+          aaiPositions[2][0] = _a;
+          aaiTypes[2][0] = (*a).eType;
+        }
+        else if (PLY::EST_AmbientGreen == (*a).Semantic)
+        {
+          aaiPositions[2][1] = _a;
+          aaiTypes[2][1] = (*a).eType;
+        }
+        else if (PLY::EST_AmbientBlue == (*a).Semantic)
+        {
+          aaiPositions[2][2] = _a;
+          aaiTypes[2][2] = (*a).eType;
+        }
+        else if (PLY::EST_AmbientAlpha == (*a).Semantic)
+        {
+          aaiPositions[2][3] = _a;
+          aaiTypes[2][3] = (*a).eType;
+        }
+      }
+      break;
     }
-}
-
-// ------------------------------------------------------------------------------------------------
-// Get a RGBA color in [0...1] range
-void PLYImporter::GetMaterialColor(const std::vector<PLY::PropertyInstance>& avList,
-    unsigned int aiPositions[4],
-    PLY::EDataType aiTypes[4],
-     aiColor4D* clrOut)
-{
-    ai_assert(NULL != clrOut);
-
-    if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f;
-    else
+    else if (PLY::EEST_TextureFile == (*i).eSemantic)
     {
-        clrOut->r = NormalizeColorValue(GetProperty(avList,
-            aiPositions[0]).avList.front(),aiTypes[0]);
+      defaultTexture = (*i).szName;
     }
-
-    if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f;
-    else
-    {
-        clrOut->g = NormalizeColorValue(GetProperty(avList,
-            aiPositions[1]).avList.front(),aiTypes[1]);
+  }
+  // check whether we have a valid source for the material data
+  if (NULL != pcList) {
+    for (std::vector<ElementInstance>::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i)  {
+      aiColor4D clrOut;
+      aiMaterial* pcHelper = new aiMaterial();
+
+      // build the diffuse material color
+      GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut);
+      pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE);
+
+      // build the specular material color
+      GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut);
+      pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR);
+
+      // build the ambient material color
+      GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut);
+      pcHelper->AddProperty<aiColor4D>(&clrOut, 1, AI_MATKEY_COLOR_AMBIENT);
+
+      // handle phong power and shading mode
+      int iMode = (int)aiShadingMode_Gouraud;
+      if (0xFFFFFFFF != iPhong)   {
+        ai_real fSpec = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), ePhong);
+
+        // if shininess is 0 (and the pow() calculation would therefore always
+        // become 1, not depending on the angle), use gouraud lighting
+        if (fSpec)  {
+          // scale this with 15 ... hopefully this is correct
+          fSpec *= 15;
+          pcHelper->AddProperty<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
+
+          iMode = (int)aiShadingMode_Phong;
+        }
+      }
+      pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+
+      // handle opacity
+      if (0xFFFFFFFF != iOpacity) {
+        ai_real fOpacity = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity);
+        pcHelper->AddProperty<ai_real>(&fOpacity, 1, AI_MATKEY_OPACITY);
+      }
+
+      // The face order is absolutely undefined for PLY, so we have to
+      // use two-sided rendering to be sure it's ok.
+      const int two_sided = 1;
+      pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
+
+      //default texture
+      if (!defaultTexture.empty())
+      {
+        const aiString name(defaultTexture.c_str());
+        pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
+      }
+
+      if (!pointsOnly)
+      {
+        const int two_sided = 1;
+        pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
+      }
+
+      //set to wireframe, so when using this material info we can switch to points rendering
+      if (pointsOnly)
+      {
+        const int wireframe = 1;
+        pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
+      }
+
+      // add the newly created material instance to the list
+      pvOut->push_back(pcHelper);
     }
-
-    if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f;
-    else
+  }
+  else
+  {
+    // generate a default material
+    aiMaterial* pcHelper = new aiMaterial();
+
+    // fill in a default material
+    int iMode = (int)aiShadingMode_Gouraud;
+    pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
+
+    //generate white material most 3D engine just multiply ambient / diffuse color with actual ambient / light color
+    aiColor3D clr;
+    clr.b = clr.g = clr.r = 1.0f;
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
+
+    clr.b = clr.g = clr.r = 1.0f;
+    pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
+
+    // The face order is absolutely undefined for PLY, so we have to
+    // use two-sided rendering to be sure it's ok.
+    if (!pointsOnly)
     {
-        clrOut->b = NormalizeColorValue(GetProperty(avList,
-            aiPositions[2]).avList.front(),aiTypes[2]);
+      const int two_sided = 1;
+      pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED);
     }
 
-    // assume 1.0 for the alpha channel ifit is not set
-    if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f;
-    else
+    //default texture
+    if (!defaultTexture.empty())
     {
-        clrOut->a = NormalizeColorValue(GetProperty(avList,
-            aiPositions[3]).avList.front(),aiTypes[3]);
+      const aiString name(defaultTexture.c_str());
+      pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0);
     }
-}
 
-// ------------------------------------------------------------------------------------------------
-// Extract a material from the PLY DOM
-void PLYImporter::LoadMaterial(std::vector<aiMaterial*>* pvOut)
-{
-    ai_assert(NULL != pvOut);
-
-    // diffuse[4], specular[4], ambient[4]
-    // rgba order
-    unsigned int aaiPositions[3][4] = {
-
-        {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
-        {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
-        {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF},
-    };
-
-    PLY::EDataType aaiTypes[3][4] = {
-        {EDT_Char,EDT_Char,EDT_Char,EDT_Char},
-        {EDT_Char,EDT_Char,EDT_Char,EDT_Char},
-        {EDT_Char,EDT_Char,EDT_Char,EDT_Char}
-    };
-    PLY::ElementInstanceList* pcList = NULL;
-
-    unsigned int iPhong = 0xFFFFFFFF;
-    PLY::EDataType ePhong = EDT_Char;
-
-    unsigned int iOpacity = 0xFFFFFFFF;
-    PLY::EDataType eOpacity = EDT_Char;
-
-    // search in the DOM for a vertex entry
-    unsigned int _i = 0;
-    for (std::vector<PLY::Element>::const_iterator i =  this->pcDOM->alElements.begin();
-        i != this->pcDOM->alElements.end();++i,++_i)
+    //set to wireframe, so when using this material info we can switch to points rendering
+    if (pointsOnly)
     {
-        if (PLY::EEST_Material == (*i).eSemantic)
-        {
-            pcList = &this->pcDOM->alElementData[_i];
-
-            // now check whether which coordinate sets are available
-            unsigned int _a = 0;
-            for (std::vector<PLY::Property>::const_iterator
-                a =  (*i).alProperties.begin();
-                a != (*i).alProperties.end();++a,++_a)
-            {
-                if ((*a).bIsList)continue;
-
-                // pohng specularity      -----------------------------------
-                if (PLY::EST_PhongPower == (*a).Semantic)
-                {
-                    iPhong      = _a;
-                    ePhong      = (*a).eType;
-                }
-
-                // general opacity        -----------------------------------
-                if (PLY::EST_Opacity == (*a).Semantic)
-                {
-                    iOpacity        = _a;
-                    eOpacity        = (*a).eType;
-                }
-
-                // diffuse color channels -----------------------------------
-                if (PLY::EST_DiffuseRed == (*a).Semantic)
-                {
-                    aaiPositions[0][0]  = _a;
-                    aaiTypes[0][0]      = (*a).eType;
-                }
-                else if (PLY::EST_DiffuseGreen == (*a).Semantic)
-                {
-                    aaiPositions[0][1]  = _a;
-                    aaiTypes[0][1]      = (*a).eType;
-                }
-                else if (PLY::EST_DiffuseBlue == (*a).Semantic)
-                {
-                    aaiPositions[0][2]  = _a;
-                    aaiTypes[0][2]      = (*a).eType;
-                }
-                else if (PLY::EST_DiffuseAlpha == (*a).Semantic)
-                {
-                    aaiPositions[0][3]  = _a;
-                    aaiTypes[0][3]      = (*a).eType;
-                }
-                // specular color channels -----------------------------------
-                else if (PLY::EST_SpecularRed == (*a).Semantic)
-                {
-                    aaiPositions[1][0]  = _a;
-                    aaiTypes[1][0]      = (*a).eType;
-                }
-                else if (PLY::EST_SpecularGreen == (*a).Semantic)
-                {
-                    aaiPositions[1][1]  = _a;
-                    aaiTypes[1][1]      = (*a).eType;
-                }
-                else if (PLY::EST_SpecularBlue == (*a).Semantic)
-                {
-                    aaiPositions[1][2]  = _a;
-                    aaiTypes[1][2]      = (*a).eType;
-                }
-                else if (PLY::EST_SpecularAlpha == (*a).Semantic)
-                {
-                    aaiPositions[1][3]  = _a;
-                    aaiTypes[1][3]      = (*a).eType;
-                }
-                // ambient color channels -----------------------------------
-                else if (PLY::EST_AmbientRed == (*a).Semantic)
-                {
-                    aaiPositions[2][0]  = _a;
-                    aaiTypes[2][0]      = (*a).eType;
-                }
-                else if (PLY::EST_AmbientGreen == (*a).Semantic)
-                {
-                    aaiPositions[2][1]  = _a;
-                    aaiTypes[2][1]      = (*a).eType;
-                }
-                else if (PLY::EST_AmbientBlue == (*a).Semantic)
-                {
-                    aaiPositions[2][2]  = _a;
-                    aaiTypes[2][2]      = (*a).eType;
-                }
-                else if (PLY::EST_AmbientAlpha == (*a).Semantic)
-                {
-                    aaiPositions[2][3]  = _a;
-                    aaiTypes[2][3]      = (*a).eType;
-                }
-            }
-            break;
-        }
+      const int wireframe = 1;
+      pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME);
     }
-    // check whether we have a valid source for the material data
-    if (NULL != pcList) {
-        for (std::vector<ElementInstance>::const_iterator i =  pcList->alInstances.begin();i != pcList->alInstances.end();++i)  {
-            aiColor4D clrOut;
-            aiMaterial* pcHelper = new aiMaterial();
-
-            // build the diffuse material color
-            GetMaterialColor((*i).alProperties,aaiPositions[0],aaiTypes[0],&clrOut);
-            pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_DIFFUSE);
-
-            // build the specular material color
-            GetMaterialColor((*i).alProperties,aaiPositions[1],aaiTypes[1],&clrOut);
-            pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_SPECULAR);
-
-            // build the ambient material color
-            GetMaterialColor((*i).alProperties,aaiPositions[2],aaiTypes[2],&clrOut);
-            pcHelper->AddProperty<aiColor4D>(&clrOut,1,AI_MATKEY_COLOR_AMBIENT);
-
-            // handle phong power and shading mode
-            int iMode = (int)aiShadingMode_Gouraud;
-            if (0xFFFFFFFF != iPhong)   {
-                ai_real fSpec = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(),ePhong);
-
-                // if shininess is 0 (and the pow() calculation would therefore always
-                // become 1, not depending on the angle), use gouraud lighting
-                if (fSpec)  {
-                    // scale this with 15 ... hopefully this is correct
-                    fSpec *= 15;
-                    pcHelper->AddProperty<ai_real>(&fSpec, 1, AI_MATKEY_SHININESS);
-
-                    iMode = (int)aiShadingMode_Phong;
-                }
-            }
-            pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
-
-            // handle opacity
-            if (0xFFFFFFFF != iOpacity) {
-                ai_real fOpacity = PLY::PropertyInstance::ConvertTo<ai_real>(GetProperty((*i).alProperties, iPhong).avList.front(),eOpacity);
-                pcHelper->AddProperty<ai_real>(&fOpacity, 1, AI_MATKEY_OPACITY);
-            }
 
-            // The face order is absolutely undefined for PLY, so we have to
-            // use two-sided rendering to be sure it's ok.
-            const int two_sided = 1;
-            pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED);
-
-            // add the newly created material instance to the list
-            pvOut->push_back(pcHelper);
-        }
-    }
+    pvOut->push_back(pcHelper);
+  }
 }
 
 #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER

+ 14 - 47
code/PlyLoader.h

@@ -68,7 +68,6 @@ public:
     PLYImporter();
     ~PLYImporter();
 
-
 public:
 
     // -------------------------------------------------------------------
@@ -78,6 +77,16 @@ public:
     bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
         bool checkSig) const;
 
+    // -------------------------------------------------------------------
+    /** Extract a vertex from the DOM
+    */
+    void LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos);
+
+    // -------------------------------------------------------------------
+    /** Extract a face from the DOM
+    */
+    void LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos);
+
 protected:
 
     // -------------------------------------------------------------------
@@ -94,53 +103,10 @@ protected:
         IOSystem* pIOHandler);
 
 protected:
-
-
-    // -------------------------------------------------------------------
-    /** Extract vertices from the DOM
-    */
-    void LoadVertices(std::vector<aiVector3D>* pvOut,
-        bool p_bNormals = false);
-
-    // -------------------------------------------------------------------
-    /** Extract vertex color channels from the DOM
-    */
-    void LoadVertexColor(std::vector<aiColor4D>* pvOut);
-
-    // -------------------------------------------------------------------
-    /** Extract texture coordinate channels from the DOM
-    */
-    void LoadTextureCoordinates(std::vector<aiVector2D>* pvOut);
-
-    // -------------------------------------------------------------------
-    /** Extract a face list from the DOM
-    */
-    void LoadFaces(std::vector<PLY::Face>* pvOut);
-
     // -------------------------------------------------------------------
     /** Extract a material list from the DOM
     */
-    void LoadMaterial(std::vector<aiMaterial*>* pvOut);
-
-
-    // -------------------------------------------------------------------
-    /** Validate material indices, replace default material identifiers
-    */
-    void ReplaceDefaultMaterial(std::vector<PLY::Face>* avFaces,
-        std::vector<aiMaterial*>* avMaterials);
-
-
-    // -------------------------------------------------------------------
-    /** Convert all meshes into our ourer representation
-    */
-    void ConvertMeshes(std::vector<PLY::Face>* avFaces,
-        const std::vector<aiVector3D>* avPositions,
-        const std::vector<aiVector3D>* avNormals,
-        const std::vector<aiColor4D>* avColors,
-        const std::vector<aiVector2D>* avTexCoords,
-        const std::vector<aiMaterial*>* avMaterials,
-        std::vector<aiMesh*>* avOut);
-
+    void LoadMaterial(std::vector<aiMaterial*>* pvOut, std::string &defaultTexture, const bool pointsOnly);
 
     // -------------------------------------------------------------------
     /** Static helper to parse a color from four single channels in
@@ -151,7 +117,6 @@ protected:
         PLY::EDataType aiTypes[4],
         aiColor4D* clrOut);
 
-
     // -------------------------------------------------------------------
     /** Static helper to parse a color channel value. The input value
     *  is normalized to 0-1.
@@ -160,12 +125,14 @@ protected:
         PLY::PropertyInstance::ValueUnion val,
         PLY::EDataType eType);
 
-
     /** Buffer to hold the loaded file */
     unsigned char* mBuffer;
 
     /** Document object model representation extracted from the file */
     PLY::DOM* pcDOM;
+
+    /** Mesh generated by loader */
+    aiMesh* mGeneratedMesh;
 };
 
 } // end of namespace Assimp

+ 930 - 754
code/PlyParser.cpp

@@ -5,7 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2017, assimp team
 
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -13,18 +12,18 @@ 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.
+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.
+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.
+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
@@ -45,916 +44,1093 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_PLY_IMPORTER
 
-#include "PlyLoader.h"
 #include "fast_atof.h"
 #include <assimp/DefaultLogger.hpp>
 #include "ByteSwapper.h"
-
+#include "PlyLoader.h"
 
 using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
-PLY::EDataType PLY::Property::ParseDataType(const char* pCur,const char** pCurOut) {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-
-    PLY::EDataType eOut = PLY::EDT_INVALID;
-
-    if (TokenMatch(pCur,"char",4) ||
-        TokenMatch(pCur,"int8",4))
-    {
-        eOut = PLY::EDT_Char;
-    }
-    else if (TokenMatch(pCur,"uchar",5) ||
-             TokenMatch(pCur,"uint8",5))
-    {
-        eOut = PLY::EDT_UChar;
-    }
-    else if (TokenMatch(pCur,"short",5) ||
-             TokenMatch(pCur,"int16",5))
-    {
-        eOut = PLY::EDT_Short;
-    }
-    else if (TokenMatch(pCur,"ushort",6) ||
-             TokenMatch(pCur,"uint16",6))
-    {
-        eOut = PLY::EDT_UShort;
-    }
-    else if (TokenMatch(pCur,"int32",5) || TokenMatch(pCur,"int",3))
-    {
-        eOut = PLY::EDT_Int;
-    }
-    else if (TokenMatch(pCur,"uint32",6) || TokenMatch(pCur,"uint",4))
-    {
-        eOut = PLY::EDT_UInt;
-    }
-    else if (TokenMatch(pCur,"float",5) || TokenMatch(pCur,"float32",7))
-    {
-        eOut = PLY::EDT_Float;
-    }
-    else if (TokenMatch(pCur,"double64",8) || TokenMatch(pCur,"double",6) ||
-             TokenMatch(pCur,"float64",7))
-    {
-        eOut = PLY::EDT_Double;
-    }
-    if (PLY::EDT_INVALID == eOut)
-    {
-        DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK");
-    }
-    *pCurOut = pCur;
-
-    return eOut;
+PLY::EDataType PLY::Property::ParseDataType(std::vector<char> &buffer) {
+  ai_assert(!buffer.empty());
+
+  PLY::EDataType eOut = PLY::EDT_INVALID;
+
+  if (PLY::DOM::TokenMatch(buffer, "char", 4) ||
+    PLY::DOM::TokenMatch(buffer, "int8", 4))
+  {
+    eOut = PLY::EDT_Char;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "uchar", 5) ||
+    PLY::DOM::TokenMatch(buffer, "uint8", 5))
+  {
+    eOut = PLY::EDT_UChar;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "short", 5) ||
+    PLY::DOM::TokenMatch(buffer, "int16", 5))
+  {
+    eOut = PLY::EDT_Short;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ushort", 6) ||
+    PLY::DOM::TokenMatch(buffer, "uint16", 6))
+  {
+    eOut = PLY::EDT_UShort;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "int32", 5) || PLY::DOM::TokenMatch(buffer, "int", 3))
+  {
+    eOut = PLY::EDT_Int;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "uint32", 6) || PLY::DOM::TokenMatch(buffer, "uint", 4))
+  {
+    eOut = PLY::EDT_UInt;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "float", 5) || PLY::DOM::TokenMatch(buffer, "float32", 7))
+  {
+    eOut = PLY::EDT_Float;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "double64", 8) || PLY::DOM::TokenMatch(buffer, "double", 6) ||
+    PLY::DOM::TokenMatch(buffer, "float64", 7))
+  {
+    eOut = PLY::EDT_Double;
+  }
+  if (PLY::EDT_INVALID == eOut)
+  {
+    DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK");
+  }
+
+  return eOut;
 }
 
 // ------------------------------------------------------------------------------------------------
-PLY::ESemantic PLY::Property::ParseSemantic(const char* pCur,const char** pCurOut) {
-    ai_assert (NULL != pCur );
-    ai_assert( NULL != pCurOut );
-
-    PLY::ESemantic eOut = PLY::EST_INVALID;
-    if (TokenMatch(pCur,"red",3)) {
-        eOut = PLY::EST_Red;
-    } else if (TokenMatch(pCur,"green",5)) {
-        eOut = PLY::EST_Green;
-    } else if (TokenMatch(pCur,"blue",4)) {
-        eOut = PLY::EST_Blue;
-    } else if (TokenMatch(pCur,"alpha",5)) {
-        eOut = PLY::EST_Alpha;
-    } else if (TokenMatch(pCur,"vertex_index",12) || TokenMatch(pCur,"vertex_indices",14)) {
-        eOut = PLY::EST_VertexIndex;
-    }
-    else if (TokenMatch(pCur,"material_index",14))
-    {
-        eOut = PLY::EST_MaterialIndex;
-    }
-    else if (TokenMatch(pCur,"ambient_red",11))
-    {
-        eOut = PLY::EST_AmbientRed;
-    }
-    else if (TokenMatch(pCur,"ambient_green",13))
-    {
-        eOut = PLY::EST_AmbientGreen;
-    }
-    else if (TokenMatch(pCur,"ambient_blue",12))
-    {
-        eOut = PLY::EST_AmbientBlue;
-    }
-    else if (TokenMatch(pCur,"ambient_alpha",13))
-    {
-        eOut = PLY::EST_AmbientAlpha;
-    }
-    else if (TokenMatch(pCur,"diffuse_red",11))
-    {
-        eOut = PLY::EST_DiffuseRed;
-    }
-    else if (TokenMatch(pCur,"diffuse_green",13))
-    {
-        eOut = PLY::EST_DiffuseGreen;
-    }
-    else if (TokenMatch(pCur,"diffuse_blue",12))
-    {
-        eOut = PLY::EST_DiffuseBlue;
-    }
-    else if (TokenMatch(pCur,"diffuse_alpha",13))
-    {
-        eOut = PLY::EST_DiffuseAlpha;
-    }
-    else if (TokenMatch(pCur,"specular_red",12))
-    {
-        eOut = PLY::EST_SpecularRed;
-    }
-    else if (TokenMatch(pCur,"specular_green",14))
-    {
-        eOut = PLY::EST_SpecularGreen;
-    }
-    else if (TokenMatch(pCur,"specular_blue",13))
-    {
-        eOut = PLY::EST_SpecularBlue;
-    }
-    else if (TokenMatch(pCur,"specular_alpha",14))
-    {
-        eOut = PLY::EST_SpecularAlpha;
-    }
-    else if (TokenMatch(pCur,"opacity",7))
-    {
-        eOut = PLY::EST_Opacity;
-    }
-    else if (TokenMatch(pCur,"specular_power",14))
-    {
-        eOut = PLY::EST_PhongPower;
-    }
-    else if (TokenMatch(pCur,"r",1))
-    {
-        eOut = PLY::EST_Red;
-    }
-    else if (TokenMatch(pCur,"g",1))
-    {
-        eOut = PLY::EST_Green;
-    }
-    else if (TokenMatch(pCur,"b",1))
-    {
-        eOut = PLY::EST_Blue;
-    }
-    // NOTE: Blender3D exports texture coordinates as s,t tuples
-    else if (TokenMatch(pCur,"u",1) ||  TokenMatch(pCur,"s",1) || TokenMatch(pCur,"tx",2) || TokenMatch(pCur,"texture_u",9))
-    {
-        eOut = PLY::EST_UTextureCoord;
-    }
-    else if (TokenMatch(pCur,"v",1) ||  TokenMatch(pCur,"t",1) || TokenMatch(pCur,"ty",2) || TokenMatch(pCur,"texture_v",9))
-    {
-        eOut = PLY::EST_VTextureCoord;
-    }
-    else if (TokenMatch(pCur,"x",1))
-    {
-        eOut = PLY::EST_XCoord;
-    } else if (TokenMatch(pCur,"y",1)) {
-        eOut = PLY::EST_YCoord;
-    } else if (TokenMatch(pCur,"z",1)) {
-        eOut = PLY::EST_ZCoord;
-    } else if (TokenMatch(pCur,"nx",2)) {
-        eOut = PLY::EST_XNormal;
-    } else if (TokenMatch(pCur,"ny",2)) {
-        eOut = PLY::EST_YNormal;
-    } else if (TokenMatch(pCur,"nz",2)) {
-        eOut = PLY::EST_ZNormal;
-    } else {
-        DefaultLogger::get()->info("Found unknown property semantic in file. This is ok");
-        SkipLine(&pCur);
-    }
-    *pCurOut = pCur;
-    return eOut;
+PLY::ESemantic PLY::Property::ParseSemantic(std::vector<char> &buffer) {
+  ai_assert(!buffer.empty());
+
+  PLY::ESemantic eOut = PLY::EST_INVALID;
+  if (PLY::DOM::TokenMatch(buffer, "red", 3)) {
+    eOut = PLY::EST_Red;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "green", 5)) {
+    eOut = PLY::EST_Green;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "blue", 4)) {
+    eOut = PLY::EST_Blue;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "alpha", 5)) {
+    eOut = PLY::EST_Alpha;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "vertex_index", 12) || PLY::DOM::TokenMatch(buffer, "vertex_indices", 14)) {
+    eOut = PLY::EST_VertexIndex;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "texcoord", 8)) // Manage uv coords on faces
+  {
+    eOut = PLY::EST_TextureCoordinates;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "material_index", 14))
+  {
+    eOut = PLY::EST_MaterialIndex;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ambient_red", 11))
+  {
+    eOut = PLY::EST_AmbientRed;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ambient_green", 13))
+  {
+    eOut = PLY::EST_AmbientGreen;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ambient_blue", 12))
+  {
+    eOut = PLY::EST_AmbientBlue;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ambient_alpha", 13))
+  {
+    eOut = PLY::EST_AmbientAlpha;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "diffuse_red", 11))
+  {
+    eOut = PLY::EST_DiffuseRed;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "diffuse_green", 13))
+  {
+    eOut = PLY::EST_DiffuseGreen;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "diffuse_blue", 12))
+  {
+    eOut = PLY::EST_DiffuseBlue;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "diffuse_alpha", 13))
+  {
+    eOut = PLY::EST_DiffuseAlpha;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_red", 12))
+  {
+    eOut = PLY::EST_SpecularRed;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_green", 14))
+  {
+    eOut = PLY::EST_SpecularGreen;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_blue", 13))
+  {
+    eOut = PLY::EST_SpecularBlue;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_alpha", 14))
+  {
+    eOut = PLY::EST_SpecularAlpha;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "opacity", 7))
+  {
+    eOut = PLY::EST_Opacity;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "specular_power", 14))
+  {
+    eOut = PLY::EST_PhongPower;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "r", 1))
+  {
+    eOut = PLY::EST_Red;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "g", 1))
+  {
+    eOut = PLY::EST_Green;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "b", 1))
+  {
+    eOut = PLY::EST_Blue;
+  }
+
+  // NOTE: Blender3D exports texture coordinates as s,t tuples
+  else if (PLY::DOM::TokenMatch(buffer, "u", 1) || PLY::DOM::TokenMatch(buffer, "s", 1) || PLY::DOM::TokenMatch(buffer, "tx", 2) || PLY::DOM::TokenMatch(buffer, "texture_u", 9))
+  {
+    eOut = PLY::EST_UTextureCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "v", 1) || PLY::DOM::TokenMatch(buffer, "t", 1) || PLY::DOM::TokenMatch(buffer, "ty", 2) || PLY::DOM::TokenMatch(buffer, "texture_v", 9))
+  {
+    eOut = PLY::EST_VTextureCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "x", 1))
+  {
+    eOut = PLY::EST_XCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "y", 1)) {
+    eOut = PLY::EST_YCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "z", 1)) {
+    eOut = PLY::EST_ZCoord;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "nx", 2)) {
+    eOut = PLY::EST_XNormal;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "ny", 2)) {
+    eOut = PLY::EST_YNormal;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "nz", 2)) {
+    eOut = PLY::EST_ZNormal;
+  }
+  else {
+    DefaultLogger::get()->info("Found unknown property semantic in file. This is ok");
+    PLY::DOM::SkipLine(buffer);
+  }
+  return eOut;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::Property::ParseProperty (const char* pCur,
-    const char** pCurOut,
-    PLY::Property* pOut)
+bool PLY::Property::ParseProperty(std::vector<char> &buffer, PLY::Property* pOut)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
+  ai_assert(!buffer.empty());
 
-    // Forms supported:
-    // "property float x"
-    // "property list uchar int vertex_index"
-    *pCurOut = pCur;
+  // Forms supported:
+  // "property float x"
+  // "property list uchar int vertex_index"
 
-    // skip leading spaces
-    if (!SkipSpaces(pCur,&pCur)) {
-        return false;
-    }
+  // skip leading spaces
+  if (!PLY::DOM::SkipSpaces(buffer)) {
+    return false;
+  }
 
-    // skip the "property" string at the beginning
-    if (!TokenMatch(pCur,"property",8))
+  // skip the "property" string at the beginning
+  if (!PLY::DOM::TokenMatch(buffer, "property", 8))
+  {
+    // seems not to be a valid property entry
+    return false;
+  }
+  // get next word
+  if (!PLY::DOM::SkipSpaces(buffer)) {
+    return false;
+  }
+  if (PLY::DOM::TokenMatch(buffer, "list", 4))
+  {
+    pOut->bIsList = true;
+
+    // seems to be a list.
+    if (EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(buffer)))
     {
-        // seems not to be a valid property entry
-        return false;
+      // unable to parse list size data type
+      PLY::DOM::SkipLine(buffer);
+      return false;
     }
-    // get next word
-    if (!SkipSpaces(pCur,&pCur)) {
-        return false;
-    }
-    if (TokenMatch(pCur,"list",4))
+    if (!PLY::DOM::SkipSpaces(buffer))return false;
+    if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer)))
     {
-        pOut->bIsList = true;
-
-        // seems to be a list.
-        if(EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(pCur, &pCur)))
-        {
-            // unable to parse list size data type
-            SkipLine(pCur,&pCur);
-            *pCurOut = pCur;
-            return false;
-        }
-        if (!SkipSpaces(pCur,&pCur))return false;
-        if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur)))
-        {
-            // unable to parse list data type
-            SkipLine(pCur,&pCur);
-            *pCurOut = pCur;
-            return false;
-        }
-    }
-    else
+      // unable to parse list data type
+      PLY::DOM::SkipLine(buffer);
+      return false;
+    }
+  }
+  else
+  {
+    if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer)))
     {
-        if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur)))
-        {
-            // unable to parse data type. Skip the property
-            SkipLine(pCur,&pCur);
-            *pCurOut = pCur;
-            return false;
-        }
+      // unable to parse data type. Skip the property
+      PLY::DOM::SkipLine(buffer);
+      return false;
     }
+  }
 
-    if (!SkipSpaces(pCur,&pCur))return false;
-    const char* szCur = pCur;
-    pOut->Semantic = PLY::Property::ParseSemantic(pCur, &pCur);
-
-    if (PLY::EST_INVALID == pOut->Semantic)
-    {
-        // store the name of the semantic
-        uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+  if (!PLY::DOM::SkipSpaces(buffer))
+    return false;
 
-        DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK");
-        pOut->szName = std::string(szCur,iDiff);
-    }
+  pOut->Semantic = PLY::Property::ParseSemantic(buffer);
 
-    SkipSpacesAndLineEnd(pCur,&pCur);
-    *pCurOut = pCur;
+  if (PLY::EST_INVALID == pOut->Semantic)
+  {
+    DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK");
+    std::string(&buffer[0], &buffer[0] + strlen(&buffer[0]));
+  }
 
-    return true;
+  PLY::DOM::SkipSpacesAndLineEnd(buffer);
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-PLY::EElementSemantic PLY::Element::ParseSemantic(const char* pCur,
-    const char** pCurOut)
+PLY::EElementSemantic PLY::Element::ParseSemantic(std::vector<char> &buffer)
 {
-    ai_assert(NULL != pCur && NULL != pCurOut);
-    PLY::EElementSemantic eOut = PLY::EEST_INVALID;
-    if (TokenMatch(pCur,"vertex",6))
-    {
-        eOut = PLY::EEST_Vertex;
-    }
-    else if (TokenMatch(pCur,"face",4))
-    {
-        eOut = PLY::EEST_Face;
-    }
+  ai_assert(!buffer.empty());
+
+  PLY::EElementSemantic eOut = PLY::EEST_INVALID;
+  if (PLY::DOM::TokenMatch(buffer, "vertex", 6))
+  {
+    eOut = PLY::EEST_Vertex;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "face", 4))
+  {
+    eOut = PLY::EEST_Face;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "tristrips", 9))
+  {
+    eOut = PLY::EEST_TriStrip;
+  }
 #if 0
-    // TODO: maybe implement this?
-    else if (TokenMatch(pCur,"range_grid",10))
-    {
-        eOut = PLY::EEST_Face;
-    }
+  // TODO: maybe implement this?
+  else if (PLY::DOM::TokenMatch(buffer,"range_grid",10))
+  {
+    eOut = PLY::EEST_Face;
+  }
 #endif
-    else if (TokenMatch(pCur,"tristrips",9))
-    {
-        eOut = PLY::EEST_TriStrip;
-    }
-    else if (TokenMatch(pCur,"edge",4))
-    {
-        eOut = PLY::EEST_Edge;
-    }
-    else if (TokenMatch(pCur,"material",8))
-    {
-        eOut = PLY::EEST_Material;
-    }
-    *pCurOut = pCur;
-
-    return eOut;
+  else if (PLY::DOM::TokenMatch(buffer, "edge", 4))
+  {
+    eOut = PLY::EEST_Edge;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "material", 8))
+  {
+    eOut = PLY::EEST_Material;
+  }
+  else if (PLY::DOM::TokenMatch(buffer, "TextureFile", 11))
+  {
+    eOut = PLY::EEST_TextureFile;
+  }
+
+  return eOut;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::Element::ParseElement (const char* pCur,
-    const char** pCurOut,
-    PLY::Element* pOut)
+bool PLY::Element::ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLY::Element* pOut)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pOut );
+  ai_assert(NULL != pOut);
+  // Example format: "element vertex 8"
 
-    // Example format: "element vertex 8"
-    *pCurOut = pCur;
+  // skip leading spaces
+  if (!PLY::DOM::SkipSpaces(buffer))
+  {
+    return false;
+  }
 
-    // skip leading spaces
-    if (!SkipSpaces(&pCur)) {
-        return false;
-    }
+  // skip the "element" string at the beginning
+  if (!PLY::DOM::TokenMatch(buffer, "element", 7) && !PLY::DOM::TokenMatch(buffer, "comment", 7))
+  {
+    // seems not to be a valid property entry
+    return false;
+  }
+  // get next word
+  if (!PLY::DOM::SkipSpaces(buffer))
+    return false;
 
-    // skip the "element" string at the beginning
-    if (!TokenMatch(pCur,"element",7))
-    {
-        // seems not to be a valid property entry
-        return false;
-    }
-    // get next word
-    if (!SkipSpaces(&pCur))return false;
+  // parse the semantic of the element
+  pOut->eSemantic = PLY::Element::ParseSemantic(buffer);
+  if (PLY::EEST_INVALID == pOut->eSemantic)
+  {
+    // if the exact semantic can't be determined, just store
+    // the original string identifier
+    pOut->szName = std::string(&buffer[0], &buffer[0] + strlen(&buffer[0]));
+  }
 
-    // parse the semantic of the element
-    const char* szCur = pCur;
-    pOut->eSemantic = PLY::Element::ParseSemantic(pCur,&pCur);
-    if (PLY::EEST_INVALID == pOut->eSemantic)
-    {
-        // if the exact semantic can't be determined, just store
-        // the original string identifier
-        uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
-        pOut->szName = std::string(szCur,iDiff);
-    }
+  if (!PLY::DOM::SkipSpaces(buffer))
+    return false;
 
-    if (!SkipSpaces(&pCur))return false;
+  if (PLY::EEST_TextureFile == pOut->eSemantic)
+  {
+    char* endPos = &buffer[0] + (strlen(&buffer[0]) - 1);
+    pOut->szName = std::string(&buffer[0], endPos);
+  }
 
-    //parse the number of occurrences of this element
-    pOut->NumOccur = strtoul10(pCur,&pCur);
+  //parse the number of occurrences of this element
+  const char* pCur = (char*)&buffer[0];
+  pOut->NumOccur = strtoul10(pCur, &pCur);
 
-    // go to the next line
-    SkipSpacesAndLineEnd(pCur,&pCur);
+  // go to the next line
+  PLY::DOM::SkipSpacesAndLineEnd(buffer);
 
-    // now parse all properties of the element
-    while(true)
-    {
-        // skip all comments
-        PLY::DOM::SkipComments(pCur,&pCur);
+  // now parse all properties of the element
+  while (true)
+  {
+    streamBuffer.getNextLine(buffer);
+    pCur = (char*)&buffer[0];
 
-        PLY::Property prop;
-        if(!PLY::Property::ParseProperty(pCur,&pCur,&prop))break;
-        pOut->alProperties.push_back(prop);
-    }
-    *pCurOut = pCur;
+    // skip all comments
+    PLY::DOM::SkipComments(buffer);
 
-    return true;
-}
+    PLY::Property prop;
+    if (!PLY::Property::ParseProperty(buffer, &prop))
+      break;
 
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::SkipComments (const char* pCur,
-    const char** pCurOut)
-{
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    *pCurOut = pCur;
+    pOut->alProperties.push_back(prop);
+  }
 
-    // skip spaces
-    if (!SkipSpaces(pCur,&pCur)) {
-        return false;
-    }
-
-    if (TokenMatch(pCur,"comment",7))
-    {
-        if ( !IsLineEnd(pCur[-1]) )
-        {
-            SkipLine(pCur,&pCur);
-        }
-        SkipComments(pCur,&pCur);
-        *pCurOut = pCur;
-        return true;
-    }
-    *pCurOut = pCur;
-
-    return false;
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut,bool isBinary) {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
+bool PLY::DOM::SkipSpaces(std::vector<char> &buffer)
+{
+  const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+  bool ret = false;
+  if (pCur)
+  {
+    const char* szCur = pCur;
+    ret = Assimp::SkipSpaces(pCur, &pCur);
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin");
+    uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+    buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+    return ret;
+  }
 
-    // after ply and format line
-    *pCurOut = pCur;
+  return ret;
+}
 
-    // parse all elements
-    while ((*pCur) != '\0')
-    {
-        // skip all comments
-        PLY::DOM::SkipComments(pCur,&pCur);
+bool PLY::DOM::SkipLine(std::vector<char> &buffer)
+{
+  const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+  bool ret = false;
+  if (pCur)
+  {
+    const char* szCur = pCur;
+    ret = Assimp::SkipLine(pCur, &pCur);
 
-        PLY::Element out;
-        if(PLY::Element::ParseElement(pCur,&pCur,&out))
-        {
-            // add the element to the list of elements
-            alElements.push_back(out);
-        }
-        else if (TokenMatch(pCur,"end_header",10))
-        {
-            // we have reached the end of the header
-            break;
-        }
-        else
-        {
-            // ignore unknown header elements
-            SkipLine(&pCur);
-        }
-    }
-    if(!isBinary)
-    { // it would occur an error, if binary data start with values as space or line end.
-        SkipSpacesAndLineEnd(pCur,&pCur);
-    }
-    *pCurOut = pCur;
+    uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+    buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+    return ret;
+  }
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded");
-    return true;
+  return ret;
 }
 
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseElementInstanceLists (
-    const char* pCur,
-    const char** pCurOut)
+bool PLY::DOM::TokenMatch(std::vector<char> &buffer, const char* token, unsigned int len)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
+  const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+  bool ret = false;
+  if (pCur)
+  {
+    const char* szCur = pCur;
+    ret = Assimp::TokenMatch(pCur, token, len);
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin");
-    *pCurOut = pCur;
+    uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+    buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+    return ret;
+  }
 
-    alElementData.resize(alElements.size());
+  return ret;
+}
 
-    std::vector<PLY::Element>::const_iterator i = alElements.begin();
-    std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+bool PLY::DOM::SkipSpacesAndLineEnd(std::vector<char> &buffer)
+{
+  const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0];
+  bool ret = false;
+  if (pCur)
+  {
+    const char* szCur = pCur;
+    ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur);
 
-    // parse all element instances
-    for (;i != alElements.end();++i,++a)
-    {
-        (*a).alInstances.resize((*i).NumOccur);
-        PLY::ElementInstanceList::ParseInstanceList(pCur,&pCur,&(*i),&(*a));
-    }
+    uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur;
+    buffer.erase(buffer.begin(), buffer.begin() + iDiff);
+    return ret;
+  }
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded");
-    *pCurOut = pCur;
-    return true;
+  return ret;
 }
 
-// ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseElementInstanceListsBinary (
-    const char* pCur,
-    const char** pCurOut,
-    bool p_bBE)
+bool PLY::DOM::SkipComments(std::vector<char> &buffer)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut);
+  ai_assert(!buffer.empty());
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin");
-    *pCurOut = pCur;
-
-    alElementData.resize(alElements.size());
+  std::vector<char> nbuffer = buffer;
+  // skip spaces
+  if (!SkipSpaces(nbuffer)) {
+    return false;
+  }
 
-    std::vector<PLY::Element>::const_iterator i = alElements.begin();
-    std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+  if (TokenMatch(nbuffer, "comment", 7))
+  {
+    if (!SkipSpaces(nbuffer))
+      SkipLine(nbuffer);
 
-    // parse all element instances
-    for (;i != alElements.end();++i,++a)
+    if (!TokenMatch(nbuffer, "TextureFile", 11))
     {
-        (*a).alInstances.resize((*i).NumOccur);
-        PLY::ElementInstanceList::ParseInstanceListBinary(pCur,&pCur,&(*i),&(*a),p_bBE);
+      SkipLine(nbuffer);
+      buffer = nbuffer;
+      return true;
     }
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded");
-    *pCurOut = pCur;
     return true;
+  }
+
+  return false;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseInstanceBinary (const char* pCur,DOM* p_pcOut,bool p_bBE)
-{
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != p_pcOut );
+bool PLY::DOM::ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, bool isBinary) {
+  DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin");
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin");
+  // parse all elements
+  while (!buffer.empty())
+  {
+    // skip all comments
+    PLY::DOM::SkipComments(buffer);
 
-    if(!p_pcOut->ParseHeader(pCur,&pCur,true))
+    PLY::Element out;
+    if (PLY::Element::ParseElement(streamBuffer, buffer, &out))
     {
-        DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
-        return false;
+      // add the element to the list of elements
+      alElements.push_back(out);
     }
-    if(!p_pcOut->ParseElementInstanceListsBinary(pCur,&pCur,p_bBE))
+    else if (TokenMatch(buffer, "end_header", 10))
     {
-        DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
-        return false;
+      // we have reached the end of the header
+      break;
     }
-    DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded");
-    return true;
+    else
+    {
+      // ignore unknown header elements
+      streamBuffer.getNextLine(buffer);
+    }
+  }
+
+  if (!isBinary) // it would occur an error, if binary data start with values as space or line end.
+    SkipSpacesAndLineEnd(buffer);
+
+  DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseInstance (const char* pCur,DOM* p_pcOut)
+bool PLY::DOM::ParseElementInstanceLists(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLYImporter* loader)
 {
-    ai_assert(NULL != pCur);
-    ai_assert(NULL != p_pcOut);
+  DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin");
+  alElementData.resize(alElements.size());
 
-    DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin");
+  std::vector<PLY::Element>::const_iterator i = alElements.begin();
+  std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
 
-
-    if(!p_pcOut->ParseHeader(pCur,&pCur,false))
+  // parse all element instances
+  //construct vertices and faces
+  for (; i != alElements.end(); ++i, ++a)
+  {
+    if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip)
     {
-        DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
-        return false;
+      PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), NULL, loader);
     }
-    if(!p_pcOut->ParseElementInstanceLists(pCur,&pCur))
+    else
     {
-        DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
-        return false;
+      (*a).alInstances.resize((*i).NumOccur);
+      PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), &(*a), NULL);
     }
-    DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded");
-    return true;
+  }
+
+  DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstanceList::ParseInstanceList (
-    const char* pCur,
-    const char** pCurOut,
-    const PLY::Element* pcElement,
-    PLY::ElementInstanceList* p_pcOut)
+bool PLY::DOM::ParseElementInstanceListsBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+    const char* &pCur,
+    unsigned int &bufferSize,
+    PLYImporter* loader,
+    bool p_bBE)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pcElement );
-    ai_assert( NULL != p_pcOut );
+  DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin");
+  alElementData.resize(alElements.size());
 
-    if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty())
+  std::vector<PLY::Element>::const_iterator i = alElements.begin();
+  std::vector<PLY::ElementInstanceList>::iterator a = alElementData.begin();
+
+  // parse all element instances
+  for (; i != alElements.end(); ++i, ++a)
+  {
+    if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip)
     {
-        // if the element has an unknown semantic we can skip all lines
-        // However, there could be comments
-        for (unsigned int i = 0; i < pcElement->NumOccur;++i)
-        {
-            PLY::DOM::SkipComments(pCur,&pCur);
-            SkipLine(pCur,&pCur);
-        }
+      PLY::ElementInstanceList::ParseInstanceListBinary(streamBuffer, buffer, pCur, bufferSize, &(*i), NULL, loader, p_bBE);
     }
     else
     {
-        // be sure to have enough storage
-        for (unsigned int i = 0; i < pcElement->NumOccur;++i)
-        {
-            PLY::DOM::SkipComments(pCur,&pCur);
-            PLY::ElementInstance::ParseInstance(pCur, &pCur,pcElement,
-                &p_pcOut->alInstances[i]);
-        }
+      (*a).alInstances.resize((*i).NumOccur);
+      PLY::ElementInstanceList::ParseInstanceListBinary(streamBuffer, buffer, pCur, bufferSize, &(*i), &(*a), NULL, p_bBE);
     }
-    *pCurOut = pCur;
-    return true;
-}
+  }
 
-// ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstanceList::ParseInstanceListBinary (
-    const char* pCur,
-    const char** pCurOut,
-    const PLY::Element* pcElement,
-    PLY::ElementInstanceList* p_pcOut,
-    bool p_bBE /* = false */)
-{
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pcElement );
-    ai_assert( NULL != p_pcOut );
-
-    // we can add special handling code for unknown element semantics since
-    // we can't skip it as a whole block (we don't know its exact size
-    // due to the fact that lists could be contained in the property list
-    // of the unknown element)
-    for (unsigned int i = 0; i < pcElement->NumOccur;++i)
-    {
-        PLY::ElementInstance::ParseInstanceBinary(pCur, &pCur,pcElement,
-            &p_pcOut->alInstances[i], p_bBE);
-    }
-    *pCurOut = pCur;
-    return true;
+  DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstance::ParseInstance (
-    const char* pCur,
-    const char** pCurOut,
-    const PLY::Element* pcElement,
-    PLY::ElementInstance* p_pcOut)
+bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader, bool p_bBE)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pcElement );
-    ai_assert( NULL != p_pcOut );
+  ai_assert(NULL != p_pcOut);
+  ai_assert(NULL != loader);
 
-    if (!SkipSpaces(pCur, &pCur)) {
-        return false;
-    }
-
-    // allocate enough storage
-    p_pcOut->alProperties.resize(pcElement->alProperties.size());
-
-    std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
-    std::vector<PLY::Property>::const_iterator  a = pcElement->alProperties.begin();
-    for (;i != p_pcOut->alProperties.end();++i,++a)
-    {
-        if(!(PLY::PropertyInstance::ParseInstance(pCur, &pCur,&(*a),&(*i))))
-        {
-            DefaultLogger::get()->warn("Unable to parse property instance. "
-                "Skipping this element instance");
+  std::vector<char> buffer;
+  streamBuffer.getNextLine(buffer);
 
-            // skip the rest of the instance
-            SkipLine(pCur, &pCur);
+  DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin");
 
-            PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType);
-            (*i).avList.push_back(v);
-        }
-    }
-    *pCurOut = pCur;
-    return true;
+  if (!p_pcOut->ParseHeader(streamBuffer, buffer, true))
+  {
+    DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
+    return false;
+  }
+
+  streamBuffer.getNextBlock(buffer);
+  unsigned int bufferSize = buffer.size();
+  const char* pCur = (char*)&buffer[0];
+  if (!p_pcOut->ParseElementInstanceListsBinary(streamBuffer, buffer, pCur, bufferSize, loader, p_bBE))
+  {
+    DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
+    return false;
+  }
+  DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::ElementInstance::ParseInstanceBinary (
-    const char* pCur,
-    const char** pCurOut,
-    const PLY::Element* pcElement,
-    PLY::ElementInstance* p_pcOut,
-    bool p_bBE /* = false */)
+bool PLY::DOM::ParseInstance(IOStreamBuffer<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != pcElement );
-    ai_assert( NULL != p_pcOut );
+  ai_assert(NULL != p_pcOut);
+  ai_assert(NULL != loader);
 
-    // allocate enough storage
-    p_pcOut->alProperties.resize(pcElement->alProperties.size());
+  std::vector<char> buffer;
+  streamBuffer.getNextLine(buffer);
 
-    std::vector<PLY::PropertyInstance>::iterator i =  p_pcOut->alProperties.begin();
-    std::vector<PLY::Property>::const_iterator   a =  pcElement->alProperties.begin();
-    for (;i != p_pcOut->alProperties.end();++i,++a)
-    {
-        if(!(PLY::PropertyInstance::ParseInstanceBinary(pCur, &pCur,&(*a),&(*i),p_bBE)))
-        {
-            DefaultLogger::get()->warn("Unable to parse binary property instance. "
-                "Skipping this element instance");
+  DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin");
 
-            (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType));
-        }
-    }
-    *pCurOut = pCur;
-    return true;
+  if (!p_pcOut->ParseHeader(streamBuffer, buffer, false))
+  {
+    DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
+    return false;
+  }
+
+  //get next line after header
+  streamBuffer.getNextLine(buffer);
+  if (!p_pcOut->ParseElementInstanceLists(streamBuffer, buffer, loader))
+  {
+    DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
+    return false;
+  }
+  DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded");
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseInstance (const char* pCur,const char** pCurOut,
-    const PLY::Property* prop, PLY::PropertyInstance* p_pcOut)
+bool PLY::ElementInstanceList::ParseInstanceList(
+  IOStreamBuffer<char> &streamBuffer,
+  std::vector<char> &buffer,
+  const PLY::Element* pcElement,
+  PLY::ElementInstanceList* p_pcOut,
+  PLYImporter* loader)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != prop );
-    ai_assert( NULL != p_pcOut );
-
-    *pCurOut = pCur;
-
-    // skip spaces at the beginning
-    if (!SkipSpaces(pCur, &pCur)) {
-        return false;
-    }
-
-    if (prop->bIsList)
+  ai_assert(NULL != pcElement);
+  const char* pCur = (const char*)&buffer[0];
+
+  // parse all elements
+  if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty())
+  {
+    // if the element has an unknown semantic we can skip all lines
+    // However, there could be comments
+    for (unsigned int i = 0; i < pcElement->NumOccur; ++i)
     {
-        // parse the number of elements in the list
-        PLY::PropertyInstance::ValueUnion v;
-        PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eFirstType,&v);
-
-        // convert to unsigned int
-        unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v,prop->eFirstType);
-
-        // parse all list elements
-        p_pcOut->avList.resize(iNum);
-        for (unsigned int i = 0; i < iNum;++i)
+      PLY::DOM::SkipComments(buffer);
+      PLY::DOM::SkipLine(buffer);
+      streamBuffer.getNextLine(buffer);
+      pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0];
+    }
+  }
+  else
+  {
+    // be sure to have enough storage
+    for (unsigned int i = 0; i < pcElement->NumOccur; ++i)
+    {
+      if (p_pcOut)
+        PLY::ElementInstance::ParseInstance(pCur, pcElement, &p_pcOut->alInstances[i]);
+      else
+      {
+        ElementInstance elt;
+        PLY::ElementInstance::ParseInstance(pCur, pcElement, &elt);
+
+        // Create vertex or face
+        if (pcElement->eSemantic == EEST_Vertex)
         {
-            if (!SkipSpaces(pCur, &pCur))return false;
-            PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&p_pcOut->avList[i]);
+          //call loader instance from here
+          loader->LoadVertex(pcElement, &elt, i);
         }
-    }
-    else
-    {
-        // parse the property
-        PLY::PropertyInstance::ValueUnion v;
+        else if (pcElement->eSemantic == EEST_Face)
+        {
+          //call loader instance from here
+          loader->LoadFace(pcElement, &elt, i);
+        }
+        else if (pcElement->eSemantic == EEST_TriStrip)
+        {
+          //call loader instance from here
+          loader->LoadFace(pcElement, &elt, i);
+        }
+      }
 
-        PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&v);
-        p_pcOut->avList.push_back(v);
+      streamBuffer.getNextLine(buffer);
+      pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0];
     }
-    SkipSpacesAndLineEnd(pCur, &pCur);
-    *pCurOut = pCur;
-    return true;
+  }
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseInstanceBinary (
-    const char*  pCur,
-    const char** pCurOut,
-    const PLY::Property* prop,
-    PLY::PropertyInstance* p_pcOut,
-    bool p_bBE)
+bool PLY::ElementInstanceList::ParseInstanceListBinary(
+  IOStreamBuffer<char> &streamBuffer,
+  std::vector<char> &buffer,
+  const char* &pCur,
+  unsigned int &bufferSize,
+  const PLY::Element* pcElement,
+  PLY::ElementInstanceList* p_pcOut,
+  PLYImporter* loader,
+  bool p_bBE /* = false */)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != prop );
-    ai_assert( NULL != p_pcOut );
-
-    if (prop->bIsList)
-    {
-        // parse the number of elements in the list
-        PLY::PropertyInstance::ValueUnion v;
-        PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eFirstType,&v,p_bBE);
-
-        // convert to unsigned int
-        unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v,prop->eFirstType);
-
-        // parse all list elements
-        p_pcOut->avList.resize(iNum);
-        for (unsigned int i = 0; i < iNum;++i){
-            PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&p_pcOut->avList[i],p_bBE);
-        }
-    }
+  ai_assert(NULL != pcElement);
+
+  // we can add special handling code for unknown element semantics since
+  // we can't skip it as a whole block (we don't know its exact size
+  // due to the fact that lists could be contained in the property list
+  // of the unknown element)
+  for (unsigned int i = 0; i < pcElement->NumOccur; ++i)
+  {
+    if (p_pcOut)
+      PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &p_pcOut->alInstances[i], p_bBE);
     else
     {
-        // parse the property
-        PLY::PropertyInstance::ValueUnion v;
-        PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&v,p_bBE);
-        p_pcOut->avList.push_back(v);
-    }
-    *pCurOut = pCur;
-    return true;
+      ElementInstance elt;
+      PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &elt, p_bBE);
+
+      // Create vertex or face
+      if (pcElement->eSemantic == EEST_Vertex)
+      {
+        //call loader instance from here
+        loader->LoadVertex(pcElement, &elt, i);
+      }
+      else if (pcElement->eSemantic == EEST_Face)
+      {
+        //call loader instance from here
+        loader->LoadFace(pcElement, &elt, i);
+      }
+      else if (pcElement->eSemantic == EEST_TriStrip)
+      {
+        //call loader instance from here
+        loader->LoadFace(pcElement, &elt, i);
+      }
+    }
+  }
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue( PLY::EDataType eType )
+bool PLY::ElementInstance::ParseInstance(const char* &pCur,
+  const PLY::Element* pcElement,
+  PLY::ElementInstance* p_pcOut)
 {
-    PLY::PropertyInstance::ValueUnion out;
+  ai_assert(NULL != pcElement);
+  ai_assert(NULL != p_pcOut);
 
-    switch (eType)
-    {
-    case EDT_Float:
-        out.fFloat = 0.f;
-        return out;
+  // allocate enough storage
+  p_pcOut->alProperties.resize(pcElement->alProperties.size());
 
-    case EDT_Double:
-        out.fDouble = 0.;
-        return out;
+  std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
+  std::vector<PLY::Property>::const_iterator  a = pcElement->alProperties.begin();
+  for (; i != p_pcOut->alProperties.end(); ++i, ++a)
+  {
+    if (!(PLY::PropertyInstance::ParseInstance(pCur, &(*a), &(*i))))
+    {
+      DefaultLogger::get()->warn("Unable to parse property instance. "
+        "Skipping this element instance");
 
-    default: ;
-    };
-    out.iUInt = 0;
-    return out;
+      PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType);
+      (*i).avList.push_back(v);
+    }
+  }
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseValue(
-    const char* pCur,
-    const char** pCurOut,
-    PLY::EDataType eType,
-    PLY::PropertyInstance::ValueUnion* out)
+bool PLY::ElementInstance::ParseInstanceBinary(
+  IOStreamBuffer<char> &streamBuffer,
+  std::vector<char> &buffer,
+  const char* &pCur,
+  unsigned int &bufferSize,
+  const PLY::Element* pcElement,
+  PLY::ElementInstance* p_pcOut,
+  bool p_bBE /* = false */)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != out );
+  ai_assert(NULL != pcElement);
+  ai_assert(NULL != p_pcOut);
+
+  // allocate enough storage
+  p_pcOut->alProperties.resize(pcElement->alProperties.size());
 
-    bool ret = true;
-    *pCurOut = pCur;
-    switch (eType)
+  std::vector<PLY::PropertyInstance>::iterator i = p_pcOut->alProperties.begin();
+  std::vector<PLY::Property>::const_iterator   a = pcElement->alProperties.begin();
+  for (; i != p_pcOut->alProperties.end(); ++i, ++a)
+  {
+    if (!(PLY::PropertyInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, &(*a), &(*i), p_bBE)))
     {
-    case EDT_UInt:
-    case EDT_UShort:
-    case EDT_UChar:
-
-        out->iUInt = (uint32_t)strtoul10(pCur, &pCur);
-        break;
-
-    case EDT_Int:
-    case EDT_Short:
-    case EDT_Char:
-
-        out->iInt = (int32_t)strtol10(pCur, &pCur);
-        break;
-
-    case EDT_Float:
-        // technically this should cast to float, but people tend to use float descriptors for double data
-        // this is the best way to not risk losing precision on import and it doesn't hurt to do this
-        ai_real f;
-        pCur = fast_atoreal_move<ai_real>(pCur,f);
-        out->fFloat = (ai_real)f;
-        break;
-
-    case EDT_Double:
-        double d;
-        pCur = fast_atoreal_move<double>(pCur,d);
-        out->fDouble = (double)d;
-        break;
-
-    default:
-        ret = false;
-        break;
-    }
-    *pCurOut = pCur;
+      DefaultLogger::get()->warn("Unable to parse binary property instance. "
+        "Skipping this element instance");
 
-    return ret;
+      (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType));
+    }
+  }
+  return true;
 }
 
 // ------------------------------------------------------------------------------------------------
-bool PLY::PropertyInstance::ParseValueBinary(
-    const char* pCur,
-    const char** pCurOut,
-    PLY::EDataType eType,
-    PLY::PropertyInstance::ValueUnion* out,
-    bool p_bBE)
+bool PLY::PropertyInstance::ParseInstance(const char* &pCur,
+  const PLY::Property* prop, PLY::PropertyInstance* p_pcOut)
 {
-    ai_assert( NULL != pCur );
-    ai_assert( NULL != pCurOut );
-    ai_assert( NULL != out );
+  ai_assert(NULL != prop);
+  ai_assert(NULL != p_pcOut);
 
-    bool ret = true;
-    switch (eType)
-    {
-    case EDT_UInt:
-        out->iUInt = (uint32_t)*((uint32_t*)pCur);
-        pCur += 4;
+  // skip spaces at the beginning
+  if (!SkipSpaces(&pCur))
+  {
+    return false;
+  }
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt);
-        break;
+  if (prop->bIsList)
+  {
+    // parse the number of elements in the list
+    PLY::PropertyInstance::ValueUnion v;
+    PLY::PropertyInstance::ParseValue(pCur, prop->eFirstType, &v);
 
-    case EDT_UShort:
-        {
-        uint16_t i = *((uint16_t*)pCur);
+    // convert to unsigned int
+    unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v, prop->eFirstType);
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap(&i);
-        out->iUInt = (uint32_t)i;
-        pCur += 2;
-        break;
-        }
+    // parse all list elements
+    p_pcOut->avList.resize(iNum);
+    for (unsigned int i = 0; i < iNum; ++i)
+    {
+      if (!SkipSpaces(&pCur))
+        return false;
 
-    case EDT_UChar:
-        {
-        out->iUInt = (uint32_t)(*((uint8_t*)pCur));
-        pCur ++;
-        break;
-        }
+      PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]);
+    }
+  }
+  else
+  {
+    // parse the property
+    PLY::PropertyInstance::ValueUnion v;
 
-    case EDT_Int:
-        out->iInt = *((int32_t*)pCur);
-        pCur += 4;
+    PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v);
+    p_pcOut->avList.push_back(v);
+  }
+  SkipSpacesAndLineEnd(&pCur);
+  return true;
+}
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap(&out->iInt);
-        break;
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+  const char* &pCur,
+  unsigned int &bufferSize,
+  const PLY::Property* prop,
+  PLY::PropertyInstance* p_pcOut,
+  bool p_bBE)
+{
+  ai_assert(NULL != prop);
+  ai_assert(NULL != p_pcOut);
+
+  // parse all elements
+  if (prop->bIsList)
+  {
+    // parse the number of elements in the list
+    PLY::PropertyInstance::ValueUnion v;
+    PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eFirstType, &v, p_bBE);
+
+    // convert to unsigned int
+    unsigned int iNum = PLY::PropertyInstance::ConvertTo<unsigned int>(v, prop->eFirstType);
+
+    // parse all list elements
+    p_pcOut->avList.resize(iNum);
+    for (unsigned int i = 0; i < iNum; ++i)
+    {
+      PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eType, &p_pcOut->avList[i], p_bBE);
+    }
+  }
+  else
+  {
+    // parse the property
+    PLY::PropertyInstance::ValueUnion v;
+    PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eType, &v, p_bBE);
+    p_pcOut->avList.push_back(v);
+  }
+  return true;
+}
 
-    case EDT_Short:
-        {
-        int16_t i = *((int16_t*)pCur);
+// ------------------------------------------------------------------------------------------------
+PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue(PLY::EDataType eType)
+{
+  PLY::PropertyInstance::ValueUnion out;
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap(&i);
-        out->iInt = (int32_t)i;
-        pCur += 2;
-        break;
-        }
+  switch (eType)
+  {
+  case EDT_Float:
+    out.fFloat = 0.f;
+    return out;
 
-    case EDT_Char:
-        out->iInt = (int32_t)*((int8_t*)pCur);
-        pCur ++;
-        break;
+  case EDT_Double:
+    out.fDouble = 0.;
+    return out;
 
-    case EDT_Float:
-        {
-        out->fFloat = *((float*)pCur);
+  default:;
+  };
+  out.iUInt = 0;
+  return out;
+}
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat);
-        pCur += 4;
-        break;
-        }
-    case EDT_Double:
-        {
-        out->fDouble = *((double*)pCur);
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseValue(const char* &pCur,
+  PLY::EDataType eType,
+  PLY::PropertyInstance::ValueUnion* out)
+{
+  ai_assert(NULL != pCur);
+  ai_assert(NULL != out);
+  
+  //calc element size
+  unsigned int lsize = 0;
+  switch (eType)
+  {
+  case EDT_Char:
+  case EDT_UChar:
+    lsize = 1;
+    break;
+
+  case EDT_UShort:
+  case EDT_Short:
+    lsize = 2;
+    break;
+
+  case EDT_UInt:
+  case EDT_Int:
+  case EDT_Float:
+    lsize = 4;
+    break;
+
+  case EDT_Double:
+    lsize = 8;
+    break;
+  }
+
+  bool ret = true;
+  switch (eType)
+  {
+  case EDT_UInt:
+  case EDT_UShort:
+  case EDT_UChar:
+
+    out->iUInt = (uint32_t)strtoul10(pCur, &pCur);
+    break;
+
+  case EDT_Int:
+  case EDT_Short:
+  case EDT_Char:
+
+    out->iInt = (int32_t)strtol10(pCur, &pCur);
+    break;
+
+  case EDT_Float:
+    // technically this should cast to float, but people tend to use float descriptors for double data
+    // this is the best way to not risk losing precision on import and it doesn't hurt to do this
+    ai_real f;
+    pCur = fast_atoreal_move<ai_real>(pCur, f);
+    out->fFloat = (ai_real)f;
+    break;
+
+  case EDT_Double:
+    double d;
+    pCur = fast_atoreal_move<double>(pCur, d);
+    out->fDouble = (double)d;
+    break;
+
+  default:
+    ret = false;
+    break;
+  }
+
+  return ret;
+}
 
-        // Swap endianness
-        if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble);
-        pCur += 8;
-        break;
-        }
-    default:
-        ret = false;
+// ------------------------------------------------------------------------------------------------
+bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer<char> &streamBuffer,
+  std::vector<char> &buffer,
+  const char* &pCur,
+  unsigned int &bufferSize,
+  PLY::EDataType eType,
+  PLY::PropertyInstance::ValueUnion* out,
+  bool p_bBE)
+{
+  ai_assert(NULL != out);
+
+  //calc element size
+  unsigned int lsize = 0;
+  switch (eType)
+  {
+  case EDT_Char:
+  case EDT_UChar:
+    lsize = 1;
+    break;
+
+  case EDT_UShort:
+  case EDT_Short:
+    lsize = 2;
+    break;
+
+  case EDT_UInt:
+  case EDT_Int:
+  case EDT_Float:
+    lsize = 4;
+    break;
+
+  case EDT_Double:
+    lsize = 8;
+    break;
+  }
+
+  //read the next file block if needed
+  if (bufferSize < lsize)
+  {
+    std::vector<char> nbuffer;
+    if (streamBuffer.getNextBlock(nbuffer))
+    {
+      //concat buffer contents
+      buffer = std::vector<char>(buffer.end() - bufferSize, buffer.end());
+      buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end());
+      nbuffer.clear();
+      bufferSize = buffer.size();
+      pCur = (char*)&buffer[0];
     }
-    *pCurOut = pCur;
-
-    return ret;
+    else
+    {
+      throw DeadlyImportError("Invalid .ply file: File corrupted");
+    }
+  }
+
+  bool ret = true;
+  switch (eType)
+  {
+  case EDT_UInt:
+    out->iUInt = (uint32_t)*((uint32_t*)pCur);
+    pCur += 4;
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt);
+    break;
+
+  case EDT_UShort:
+  {
+    uint16_t i = *((uint16_t*)pCur);
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap(&i);
+    out->iUInt = (uint32_t)i;
+    pCur += 2;
+    break;
+  }
+
+  case EDT_UChar:
+  {
+    out->iUInt = (uint32_t)(*((uint8_t*)pCur));
+    pCur++;
+    break;
+  }
+
+  case EDT_Int:
+    out->iInt = *((int32_t*)pCur);
+    pCur += 4;
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap(&out->iInt);
+    break;
+
+  case EDT_Short:
+  {
+    int16_t i = *((int16_t*)pCur);
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap(&i);
+    out->iInt = (int32_t)i;
+    pCur += 2;
+    break;
+  }
+
+  case EDT_Char:
+    out->iInt = (int32_t)*((int8_t*)pCur);
+    pCur++;
+    break;
+
+  case EDT_Float:
+  {
+    out->fFloat = *((float*)pCur);
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat);
+    pCur += 4;
+    break;
+  }
+  case EDT_Double:
+  {
+    out->fDouble = *((double*)pCur);
+
+    // Swap endianness
+    if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble);
+    pCur += 8;
+    break;
+  }
+  default:
+    ret = false;
+  }
+
+  bufferSize -= lsize;
+
+  return ret;
 }
 
 #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER

+ 39 - 56
code/PlyParser.h

@@ -3,7 +3,6 @@ Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
 Copyright (c) 2006-2017, assimp team
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -46,19 +45,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "ParsingUtils.h"
+#include "IOStreamBuffer.h"
 #include <vector>
 
-
 namespace Assimp
 {
 
+//pre-declaration
+class PLYImporter;
+
 // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/
 // http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf
 // http://www.okino.com/conv/exp_ply.htm
 namespace PLY
 {
 
-
 // ---------------------------------------------------------------------------------
 /*
 name        type        number of bytes
@@ -197,6 +198,9 @@ enum EElementSemantic
     //! The element is a material description
     EEST_Material,
 
+    //! texture path
+    EEST_TextureFile,
+
     //! Marks invalid entries
     EEST_INVALID
 };
@@ -238,16 +242,15 @@ public:
     //! string is either '\n', '\r' or '\0'. Return value is false
     //! if the input string is NOT a valid property (E.g. does
     //! not start with the "property" keyword)
-    static bool ParseProperty (const char* pCur, const char** pCurOut,
-        Property* pOut);
+    static bool ParseProperty(std::vector<char> &buffer, Property* pOut);
 
     // -------------------------------------------------------------------
     //! Parse a data type from a string
-    static EDataType ParseDataType(const char* pCur,const char** pCurOut);
+    static EDataType ParseDataType(std::vector<char> &buffer);
 
     // -------------------------------------------------------------------
     //! Parse a semantic from a string
-    static ESemantic ParseSemantic(const char* pCur,const char** pCurOut);
+    static ESemantic ParseSemantic(std::vector<char> &buffer);
 };
 
 // ---------------------------------------------------------------------------------
@@ -285,13 +288,11 @@ public:
     //! Parse an element from a string.
     //! The function will parse all properties contained in the
     //! element, too.
-    static bool ParseElement (const char* pCur, const char** pCurOut,
-        Element* pOut);
+    static bool ParseElement(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, Element* pOut);
 
     // -------------------------------------------------------------------
     //! Parse a semantic from a string
-    static EElementSemantic ParseSemantic(const char* pCur,
-        const char** pCurOut);
+    static EElementSemantic ParseSemantic(std::vector<char> &buffer);
 };
 
 // ---------------------------------------------------------------------------------
@@ -331,13 +332,13 @@ public:
 
     // -------------------------------------------------------------------
     //! Parse a property instance
-    static bool ParseInstance (const char* pCur,const char** pCurOut,
+    static bool ParseInstance(const char* &pCur,
         const Property* prop, PropertyInstance* p_pcOut);
 
     // -------------------------------------------------------------------
     //! Parse a property instance in binary format
-    static bool ParseInstanceBinary (const char* pCur,const char** pCurOut,
-        const Property* prop, PropertyInstance* p_pcOut,bool p_bBE);
+    static bool ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const char* &pCur, unsigned int &bufferSize, const Property* prop, PropertyInstance* p_pcOut, bool p_bBE);
 
     // -------------------------------------------------------------------
     //! Get the default value for a given data type
@@ -345,13 +346,12 @@ public:
 
     // -------------------------------------------------------------------
     //! Parse a value
-    static bool ParseValue(const char* pCur,const char** pCurOut,
-        EDataType eType,ValueUnion* out);
+    static bool ParseValue(const char* &pCur, EDataType eType, ValueUnion* out);
 
     // -------------------------------------------------------------------
     //! Parse a binary value
-    static bool ParseValueBinary(const char* pCur,const char** pCurOut,
-        EDataType eType,ValueUnion* out,bool p_bBE);
+    static bool ParseValueBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const char* &pCur, unsigned int &bufferSize, EDataType eType, ValueUnion* out, bool p_bBE);
 
     // -------------------------------------------------------------------
     //! Convert a property value to a given type TYPE
@@ -375,13 +375,13 @@ public:
 
     // -------------------------------------------------------------------
     //! Parse an element instance
-    static bool ParseInstance (const char* pCur,const char** pCurOut,
+    static bool ParseInstance(const char* &pCur,
         const Element* pcElement, ElementInstance* p_pcOut);
 
     // -------------------------------------------------------------------
     //! Parse a binary element instance
-    static bool ParseInstanceBinary (const char* pCur,const char** pCurOut,
-        const Element* pcElement, ElementInstance* p_pcOut,bool p_bBE);
+    static bool ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstance* p_pcOut, bool p_bBE);
 };
 
 // ---------------------------------------------------------------------------------
@@ -400,13 +400,13 @@ public:
 
     // -------------------------------------------------------------------
     //! Parse an element instance list
-    static bool ParseInstanceList (const char* pCur,const char** pCurOut,
-        const Element* pcElement, ElementInstanceList* p_pcOut);
+    static bool ParseInstanceList(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader);
 
     // -------------------------------------------------------------------
     //! Parse a binary element instance list
-    static bool ParseInstanceListBinary (const char* pCur,const char** pCurOut,
-        const Element* pcElement, ElementInstanceList* p_pcOut,bool p_bBE);
+    static bool ParseInstanceListBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer,
+        const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader, bool p_bBE);
 };
 // ---------------------------------------------------------------------------------
 /** \brief Class to represent the document object model of an ASCII or binary
@@ -428,50 +428,33 @@ public:
 
     //! Parse the DOM for a PLY file. The input string is assumed
     //! to be terminated with zero
-    static bool ParseInstance (const char* pCur,DOM* p_pcOut);
-    static bool ParseInstanceBinary (const char* pCur,
-        DOM* p_pcOut,bool p_bBE);
+    static bool ParseInstance(IOStreamBuffer<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader);
+    static bool ParseInstanceBinary(IOStreamBuffer<char> &streamBuffer, DOM* p_pcOut, PLYImporter* loader, bool p_bBE);
 
     //! Skip all comment lines after this
-    static bool SkipComments (const char* pCur,const char** pCurOut);
+    static bool SkipComments(std::vector<char> &buffer);
+
+    static bool SkipSpaces(std::vector<char> &buffer);
+
+    static bool SkipLine(std::vector<char> &buffer);
+
+    static bool TokenMatch(std::vector<char> &buffer, const char* token, unsigned int len);
+
+    static bool SkipSpacesAndLineEnd(std::vector<char> &buffer);
 
 private:
 
     // -------------------------------------------------------------------
     //! Handle the file header and read all element descriptions
-    bool ParseHeader (const char* pCur,const char** pCurOut, bool p_bBE);
+    bool ParseHeader(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, bool p_bBE);
 
     // -------------------------------------------------------------------
     //! Read in all element instance lists
-    bool ParseElementInstanceLists (const char* pCur,const char** pCurOut);
+    bool ParseElementInstanceLists(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, PLYImporter* loader);
 
     // -------------------------------------------------------------------
     //! Read in all element instance lists for a binary file format
-    bool ParseElementInstanceListsBinary (const char* pCur,
-        const char** pCurOut,bool p_bBE);
-};
-
-// ---------------------------------------------------------------------------------
-/** \brief Helper class to represent a loaded PLY face
- */
-class Face
-{
-public:
-
-    Face()
-        : iMaterialIndex(0xFFFFFFFF)
-    {
-        // set all indices to zero by default
-        mIndices.resize(3,0);
-    }
-
-public:
-
-    //! List of vertex indices
-    std::vector<unsigned int> mIndices;
-
-    //! Material index
-    unsigned int iMaterialIndex;
+    bool ParseElementInstanceListsBinary(IOStreamBuffer<char> &streamBuffer, std::vector<char> &buffer, const char* &pCur, unsigned int &bufferSize, PLYImporter* loader, bool p_bBE);
 };
 
 // ---------------------------------------------------------------------------------

+ 1 - 1
code/PretransformVertices.cpp

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

+ 22 - 9
code/SIBImporter.cpp

@@ -58,7 +58,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ByteSwapper.h"
 #include "StreamReader.h"
 #include "TinyFormatter.h"
-#include "../contrib/ConvertUTF/ConvertUTF.h"
+//#include "../contrib/ConvertUTF/ConvertUTF.h"
+#include "../contrib/utf8cpp/source/utf8.h"
 #include <assimp/IOSystem.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/scene.h>
@@ -177,21 +178,33 @@ static void UnknownChunk(StreamReaderLE* stream, const SIBChunk& chunk)
 // Reads a UTF-16LE string and returns it at UTF-8.
 static aiString ReadString(StreamReaderLE* stream, uint32_t numWChars)
 {
+    if ( 0 == numWChars ) {
+        static const aiString empty;
+        return empty;
+    }
     // Allocate buffers (max expansion is 1 byte -> 4 bytes for UTF-8)
-    UTF16* temp = new UTF16[numWChars];
-    UTF8* str = new UTF8[numWChars * 4 + 1];
+    //UTF16* temp = new UTF16[numWChars];
+    std::vector<unsigned char> str;
+    str.reserve(numWChars * 4 + 1);
+    //unsigned char* str = new unsigned char[numWChars * 4 + 1];
+    uint16_t *temp = new uint16_t[numWChars];
     for (uint32_t n=0;n<numWChars;n++)
         temp[n] = stream->GetU2();
 
     // Convert it and NUL-terminate.
-    const UTF16 *start = temp, *end = temp + numWChars;
-    UTF8 *dest = str, *limit = str + numWChars*4;
-    ConvertUTF16toUTF8(&start, end, &dest, limit, lenientConversion);
-    *dest = '\0';
+    //const UTF16 *start = temp, *end = temp + numWChars;
+
+    const uint16_t *start = temp, *end = temp + numWChars;
+    utf8::utf16to8(start, end, back_inserter(str));
+
+    //UTF8 *dest = str, *limit = str + numWChars*4;
+    //ConvertUTF16toUTF8(&start, end, &dest, limit, lenientConversion);
+    //*dest = '\0';
 
+    str[str.size()-1] = '\0';
     // Return the final string.
-    aiString result = aiString((const char *)str);
-    delete[] str;
+    aiString result = aiString((const char *)&str[0]);
+    //delete[] str;
     delete[] temp;
     return result;
 }

+ 25 - 32
code/STEPFileEncoding.cpp

@@ -40,18 +40,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 /** @file  STEPFileEncoding.cpp
- *  @brief STEP character handling, string unescaping
+ *  @brief STEP character handling, string un-escaping
  */
 #include "STEPFileEncoding.h"
 #include "fast_atof.h"
+#include <contrib/utf8cpp/source/utf8.h>
 
-#include "../contrib/ConvertUTF/ConvertUTF.h"
 #include <memory>
 
 using namespace Assimp;
 
 // roman1 to utf16 table
-static const UTF16 mac_codetable[] = {
+static const uint16_t mac_codetable[] = {
     // 0x20 unassig./nonprint. slots
      0x0020 ,
      0x0021 ,
@@ -309,14 +309,12 @@ bool STEP::StringToUTF8(std::string& s)
 
                 ai_assert(sizeof(mac_codetable) / sizeof(mac_codetable[0]) == 0x100-0x20);
 
-                const UTF32 unival = mac_codetable[macval - 0x20], *univalp = &unival;
+                const uint32_t unival = mac_codetable[macval - 0x20], *univalp = &unival;
 
-                UTF8 temp[5], *tempp = temp;
-                ai_assert(sizeof(UTF8) == 1);
+                unsigned char temp[5], *tempp = temp;
+                ai_assert(sizeof( unsigned char ) == 1);
 
-                if(ConvertUTF32toUTF8(&univalp, univalp+1, &tempp, tempp+sizeof(temp), lenientConversion) != conversionOK) {
-                    return false;
-                }
+                utf8::utf32to8( univalp, univalp + 1, tempp );
 
                 const size_t outcount = static_cast<size_t>(tempp-temp);
 
@@ -355,28 +353,26 @@ bool STEP::StringToUTF8(std::string& s)
                             }
 
                             const size_t count = (j-basei)/4;
-                            std::unique_ptr<UTF16[]> src(new UTF16[count]);
+                            std::unique_ptr<uint16_t[]> src(new uint16_t[count]);
 
                             const char* cur = s.c_str() + basei;
                             for (size_t k = 0; k < count; ++k, cur += 4) {
-                                src[k] = (static_cast<UTF16>(HexOctetToDecimal(cur)) << 8u)  |
-                                     static_cast<UTF16>(HexOctetToDecimal(cur+2));
+                                src[k] = (static_cast<uint16_t>(HexOctetToDecimal(cur)) << 8u)  |
+                                     static_cast<uint16_t>(HexOctetToDecimal(cur+2));
                             }
 
                             const size_t dcount = count * 3; // this is enough to hold all possible outputs
-                            std::unique_ptr<UTF8[]> dest(new UTF8[dcount]);
+                            std::unique_ptr<unsigned char[]> dest(new unsigned char[dcount]);
 
-                            const UTF16* srct = src.get();
-                            UTF8* destt = dest.get();
-                            if(ConvertUTF16toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) {
-                                return false;
-                            }
+                            const uint16_t* srct = src.get();
+                            unsigned char* destt = dest.get();
+                            utf8::utf16to8( srct, srct + count, destt );
 
                             const size_t outcount = static_cast<size_t>(destt-dest.get());
 
                             s.erase(i,(j+4-i));
 
-                            ai_assert(sizeof(UTF8) == 1);
+                            ai_assert(sizeof(unsigned char) == 1);
                             s.insert(i, reinterpret_cast<char*>(dest.get()), outcount);
 
                             i += outcount;
@@ -388,37 +384,34 @@ bool STEP::StringToUTF8(std::string& s)
                             }
 
                             const size_t count = (j-basei)/8;
-                            std::unique_ptr<UTF32[]> src(new UTF32[count]);
+                            std::unique_ptr<uint32_t[]> src(new uint32_t[count]);
 
                             const char* cur = s.c_str() + basei;
                             for (size_t k = 0; k < count; ++k, cur += 8) {
-                                src[k] = (static_cast<UTF32>(HexOctetToDecimal(cur  )) << 24u) |
-                                         (static_cast<UTF32>(HexOctetToDecimal(cur+2)) << 16u) |
-                                         (static_cast<UTF32>(HexOctetToDecimal(cur+4)) << 8u)  |
-                                         (static_cast<UTF32>(HexOctetToDecimal(cur+6)));
+                                src[k] = (static_cast<uint32_t>(HexOctetToDecimal(cur  )) << 24u) |
+                                         (static_cast<uint32_t>(HexOctetToDecimal(cur+2)) << 16u) |
+                                         (static_cast<uint32_t>(HexOctetToDecimal(cur+4)) << 8u)  |
+                                         (static_cast<uint32_t>(HexOctetToDecimal(cur+6)));
                             }
 
                             const size_t dcount = count * 5; // this is enough to hold all possible outputs
-                            std::unique_ptr<UTF8[]> dest(new UTF8[dcount]);
+                            std::unique_ptr<unsigned char[]> dest(new unsigned char[dcount]);
 
-                            const UTF32* srct = src.get();
-                            UTF8* destt = dest.get();
-                            if(ConvertUTF32toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) {
-                                return false;
-                            }
+                            const uint32_t* srct = src.get();
+                            unsigned char* destt = dest.get();
+                            utf8::utf32to8( srct, srct + count, destt );
 
                             const size_t outcount = static_cast<size_t>(destt-dest.get());
 
                             s.erase(i,(j+4-i));
 
-                            ai_assert(sizeof(UTF8) == 1);
+                            ai_assert(sizeof(unsigned char) == 1);
                             s.insert(i, reinterpret_cast<char*>(dest.get()), outcount);
 
                             i += outcount;
                             continue;
                         }
                     }
-
                     break;
 
                     // TODO: other encoding patterns?

+ 3 - 3
code/STLLoader.cpp

@@ -211,20 +211,20 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
     for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
         pScene->mRootNode->mMeshes[i] = i;
 
-    // create a single default material, using a light gray diffuse color for consistency with
+    // create a single default material, using a white diffuse color for consistency with
     // other geometric types (e.g., PLY).
     aiMaterial* pcMat = new aiMaterial();
     aiString s;
     s.Set(AI_DEFAULT_MATERIAL_NAME);
     pcMat->AddProperty(&s, AI_MATKEY_NAME);
 
-    aiColor4D clrDiffuse(ai_real(0.6),ai_real(0.6),ai_real(0.6),ai_real(1.0));
+    aiColor4D clrDiffuse(ai_real(1.0),ai_real(1.0),ai_real(1.0),ai_real(1.0));
     if (bMatClr) {
         clrDiffuse = clrColorDefault;
     }
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
-    clrDiffuse = aiColor4D( ai_real( 0.05), ai_real( 0.05), ai_real( 0.05), ai_real( 1.0));
+    clrDiffuse = aiColor4D( ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0));
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
 
     pScene->mNumMaterials = 1;

+ 1 - 1
code/SceneCombiner.cpp

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

+ 2 - 3
code/SpatialSort.cpp

@@ -126,9 +126,8 @@ void SpatialSort::FindPositions( const aiVector3D& pPosition,
     const ai_real dist = pPosition * mPlaneNormal;
     const ai_real minDist = dist - pRadius, maxDist = dist + pRadius;
 
-    // clear the array in this strange fashion because a simple clear() would also deallocate
-    // the array which we want to avoid
-    poResults.erase( poResults.begin(), poResults.end());
+    // clear the array
+    poResults.clear();
 
     // quick check for positions outside the range
     if( mPositions.size() == 0)

+ 2 - 1
code/StepExporter.cpp

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

+ 1 - 1
code/Subdivision.cpp

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

+ 2 - 1
code/XFileExporter.cpp

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

+ 10 - 3
code/fast_atof.h

@@ -1,3 +1,5 @@
+#pragma once
+
 // Copyright (C) 2002-2007 Nikolaus Gebhardt
 // This file is part of the "Irrlicht Engine" and the "irrXML" project.
 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
@@ -22,6 +24,7 @@
 #include <assimp/defs.h>
 
 #include "StringComparison.h"
+#include <assimp/DefaultLogger.hpp>
 
 
 #ifdef _MSC_VER
@@ -192,7 +195,7 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
     uint64_t value = 0;
 
     if ( *in < '0' || *in > '9' )
-            throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value.");
+        throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value.");
 
     bool running = true;
     while ( running )
@@ -202,8 +205,12 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
 
         const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
 
-        if (new_value < value) /* numeric overflow, we rely on you */
-            throw std::overflow_error(std::string("Converting the string \"") + in + "\" into a value resulted in overflow.");
+        // numeric overflow, we rely on you
+        if ( new_value < value ) {
+            DefaultLogger::get()->warn( std::string( "Converting the string \"" ) + in + "\" into a value resulted in overflow." );
+            return 0;
+        }
+            //throw std::overflow_error();
 
         value = new_value;
 

+ 5 - 2
code/glTFExporter.cpp

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

+ 0 - 539
contrib/ConvertUTF/ConvertUTF.c

@@ -1,539 +0,0 @@
-/*
- * Copyright 2001-2004 Unicode, Inc.
- * 
- * Disclaimer
- * 
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- * 
- * Limitations on Rights to Redistribute This Code
- * 
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
- */
-
-/* ---------------------------------------------------------------------
-
-    Conversions between UTF32, UTF-16, and UTF-8. Source code file.
-    Author: Mark E. Davis, 1994.
-    Rev History: Rick McGowan, fixes & updates May 2001.
-    Sept 2001: fixed const & error conditions per
-	mods suggested by S. Parent & A. Lillich.
-    June 2002: Tim Dodd added detection and handling of incomplete
-	source sequences, enhanced error detection, added casts
-	to eliminate compiler warnings.
-    July 2003: slight mods to back out aggressive FFFE detection.
-    Jan 2004: updated switches in from-UTF8 conversions.
-    Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
-
-    See the header file "ConvertUTF.h" for complete documentation.
-
------------------------------------------------------------------------- */
-
-
-#include "ConvertUTF.h"
-#ifdef CVTUTF_DEBUG
-#include <stdio.h>
-#endif
-
-static const int halfShift  = 10; /* used for shifting by 10 bits */
-
-static const UTF32 halfBase = 0x0010000UL;
-static const UTF32 halfMask = 0x3FFUL;
-
-#define UNI_SUR_HIGH_START  (UTF32)0xD800
-#define UNI_SUR_HIGH_END    (UTF32)0xDBFF
-#define UNI_SUR_LOW_START   (UTF32)0xDC00
-#define UNI_SUR_LOW_END     (UTF32)0xDFFF
-#define false	   0
-#define true	    1
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF16 (
-	const UTF32** sourceStart, const UTF32* sourceEnd, 
-	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF32* source = *sourceStart;
-    UTF16* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch;
-	if (target >= targetEnd) {
-	    result = targetExhausted; break;
-	}
-	ch = *source++;
-	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
-	    /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = (UTF16)ch; /* normal case */
-	    }
-	} else if (ch > UNI_MAX_LEGAL_UTF32) {
-	    if (flags == strictConversion) {
-		result = sourceIllegal;
-	    } else {
-		*target++ = UNI_REPLACEMENT_CHAR;
-	    }
-	} else {
-	    /* target is a character in range 0xFFFF - 0x10FFFF. */
-	    if (target + 1 >= targetEnd) {
-		--source; /* Back up source pointer! */
-		result = targetExhausted; break;
-	    }
-	    ch -= halfBase;
-	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
-	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
-	}
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF16toUTF32 (
-	const UTF16** sourceStart, const UTF16* sourceEnd, 
-	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF16* source = *sourceStart;
-    UTF32* target = *targetStart;
-    UTF32 ch, ch2;
-    while (source < sourceEnd) {
-	const UTF16* oldSource = source; /*  In case we have to back up because of target overflow. */
-	ch = *source++;
-	/* If we have a surrogate pair, convert to UTF32 first. */
-	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
-	    /* If the 16 bits following the high surrogate are in the source buffer... */
-	    if (source < sourceEnd) {
-		ch2 = *source;
-		/* If it's a low surrogate, convert to UTF32. */
-		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
-		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
-			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
-		    ++source;
-		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		}
-	    } else { /* We don't have the 16 bits following the high surrogate. */
-		--source; /* return to the high surrogate */
-		result = sourceExhausted;
-		break;
-	    }
-	} else if (flags == strictConversion) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	if (target >= targetEnd) {
-	    source = oldSource; /* Back up source pointer! */
-	    result = targetExhausted; break;
-	}
-	*target++ = ch;
-    }
-    *sourceStart = source;
-    *targetStart = target;
-#ifdef CVTUTF_DEBUG
-if (result == sourceIllegal) {
-    fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
-    fflush(stderr);
-}
-#endif
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Index into the table below with the first byte of a UTF-8 sequence to
- * get the number of trailing bytes that are supposed to follow it.
- * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
- * left as-is for anyone who may want to do such conversion, which was
- * allowed in earlier algorithms.
- */
-static const char trailingBytesForUTF8[256] = {
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
-};
-
-/*
- * Magic values subtracted from a buffer value during UTF8 conversion.
- * This table contains as many values as there might be trailing bytes
- * in a UTF-8 sequence.
- */
-static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 
-		     0x03C82080UL, 0xFA082080UL, 0x82082080UL };
-
-/*
- * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
- * into the first byte, depending on how many bytes follow.  There are
- * as many entries in this table as there are UTF-8 sequence types.
- * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
- * for *legal* UTF-8 will be 4 or fewer bytes total.
- */
-static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
-/* --------------------------------------------------------------------- */
-
-/* The interface converts a whole buffer to avoid function-call overhead.
- * Constants have been gathered. Loops & conditionals have been removed as
- * much as possible for efficiency, in favor of drop-through switches.
- * (See "Note A" at the bottom of the file for equivalent code.)
- * If your compiler supports it, the "isLegalUTF8" call can be turned
- * into an inline function.
- */
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF16toUTF8 (
-	const UTF16** sourceStart, const UTF16* sourceEnd, 
-	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF16* source = *sourceStart;
-    UTF8* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch;
-	unsigned short bytesToWrite = 0;
-	const UTF32 byteMask = 0xBF;
-	const UTF32 byteMark = 0x80; 
-	const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
-	ch = *source++;
-	/* If we have a surrogate pair, convert to UTF32 first. */
-	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
-	    /* If the 16 bits following the high surrogate are in the source buffer... */
-	    if (source < sourceEnd) {
-		UTF32 ch2 = *source;
-		/* If it's a low surrogate, convert to UTF32. */
-		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
-		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
-			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
-		    ++source;
-		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		}
-	    } else { /* We don't have the 16 bits following the high surrogate. */
-		--source; /* return to the high surrogate */
-		result = sourceExhausted;
-		break;
-	    }
-	} else if (flags == strictConversion) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	/* Figure out how many bytes the result will require */
-	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
-	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
-	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
-	} else if (ch < (UTF32)0x110000) {  bytesToWrite = 4;
-	} else {			    bytesToWrite = 3;
-					    ch = UNI_REPLACEMENT_CHAR;
-	}
-
-	target += bytesToWrite;
-	if (target > targetEnd) {
-	    source = oldSource; /* Back up source pointer! */
-	    target -= bytesToWrite; result = targetExhausted; break;
-	}
-	switch (bytesToWrite) { /* note: everything falls through. */
-	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 1: *--target =  (UTF8)(ch | firstByteMark[bytesToWrite]);
-	}
-	target += bytesToWrite;
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Utility routine to tell whether a sequence of bytes is legal UTF-8.
- * This must be called with the length pre-determined by the first byte.
- * If not calling this from ConvertUTF8to*, then the length can be set by:
- *  length = trailingBytesForUTF8[*source]+1;
- * and the sequence is illegal right away if there aren't that many bytes
- * available.
- * If presented with a length > 4, this returns false.  The Unicode
- * definition of UTF-8 goes up to 4-byte sequences.
- */
-
-static Boolean isLegalUTF8(const UTF8 *source, int length) {
-    UTF8 a;
-    const UTF8 *srcptr = source+length;
-    switch (length) {
-    default: return false;
-	/* Everything else falls through when "true"... */
-    case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
-    case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
-    case 2: if ((a = (*--srcptr)) > 0xBF) return false;
-
-	switch (*source) {
-	    /* no fall-through in this inner switch */
-	    case 0xE0: if (a < 0xA0) return false; break;
-	    case 0xED: if (a > 0x9F) return false; break;
-	    case 0xF0: if (a < 0x90) return false; break;
-	    case 0xF4: if (a > 0x8F) return false; break;
-	    default:   if (a < 0x80) return false;
-	}
-
-    case 1: if (*source >= 0x80 && *source < 0xC2) return false;
-    }
-    if (*source > 0xF4) return false;
-    return true;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return whether a UTF-8 sequence is legal or not.
- * This is not used here; it's just exported.
- */
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
-    int length = trailingBytesForUTF8[*source]+1;
-    if (source+length > sourceEnd) {
-	return false;
-    }
-    return isLegalUTF8(source, length);
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF16 (
-	const UTF8** sourceStart, const UTF8* sourceEnd, 
-	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF8* source = *sourceStart;
-    UTF16* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch = 0;
-	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
-	if (source + extraBytesToRead >= sourceEnd) {
-	    result = sourceExhausted; break;
-	}
-	/* Do this check whether lenient or strict */
-	if (! isLegalUTF8(source, extraBytesToRead+1)) {
-	    result = sourceIllegal;
-	    break;
-	}
-	/*
-	 * The cases all fall through. See "Note A" below.
-	 */
-	switch (extraBytesToRead) {
-	    case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
-	    case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
-	    case 3: ch += *source++; ch <<= 6;
-	    case 2: ch += *source++; ch <<= 6;
-	    case 1: ch += *source++; ch <<= 6;
-	    case 0: ch += *source++;
-	}
-	ch -= offsetsFromUTF8[extraBytesToRead];
-
-	if (target >= targetEnd) {
-	    source -= (extraBytesToRead+1); /* Back up source pointer! */
-	    result = targetExhausted; break;
-	}
-	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = (UTF16)ch; /* normal case */
-	    }
-	} else if (ch > UNI_MAX_UTF16) {
-	    if (flags == strictConversion) {
-		result = sourceIllegal;
-		source -= (extraBytesToRead+1); /* return to the start */
-		break; /* Bail out; shouldn't continue */
-	    } else {
-		*target++ = UNI_REPLACEMENT_CHAR;
-	    }
-	} else {
-	    /* target is a character in range 0xFFFF - 0x10FFFF. */
-	    if (target + 1 >= targetEnd) {
-		source -= (extraBytesToRead+1); /* Back up source pointer! */
-		result = targetExhausted; break;
-	    }
-	    ch -= halfBase;
-	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
-	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
-	}
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF8 (
-	const UTF32** sourceStart, const UTF32* sourceEnd, 
-	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF32* source = *sourceStart;
-    UTF8* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch;
-	unsigned short bytesToWrite = 0;
-	const UTF32 byteMask = 0xBF;
-	const UTF32 byteMark = 0x80; 
-	ch = *source++;
-	if (flags == strictConversion ) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	/*
-	 * Figure out how many bytes the result will require. Turn any
-	 * illegally large UTF32 things (> Plane 17) into replacement chars.
-	 */
-	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
-	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
-	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
-	} else if (ch <= UNI_MAX_LEGAL_UTF32) {  bytesToWrite = 4;
-	} else {			    bytesToWrite = 3;
-					    ch = UNI_REPLACEMENT_CHAR;
-					    result = sourceIllegal;
-	}
-	
-	target += bytesToWrite;
-	if (target > targetEnd) {
-	    --source; /* Back up source pointer! */
-	    target -= bytesToWrite; result = targetExhausted; break;
-	}
-	switch (bytesToWrite) { /* note: everything falls through. */
-	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
-	}
-	target += bytesToWrite;
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF32 (
-	const UTF8** sourceStart, const UTF8* sourceEnd, 
-	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF8* source = *sourceStart;
-    UTF32* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch = 0;
-	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
-	if (source + extraBytesToRead >= sourceEnd) {
-	    result = sourceExhausted; break;
-	}
-	/* Do this check whether lenient or strict */
-	if (! isLegalUTF8(source, extraBytesToRead+1)) {
-	    result = sourceIllegal;
-	    break;
-	}
-	/*
-	 * The cases all fall through. See "Note A" below.
-	 */
-	switch (extraBytesToRead) {
-	    case 5: ch += *source++; ch <<= 6;
-	    case 4: ch += *source++; ch <<= 6;
-	    case 3: ch += *source++; ch <<= 6;
-	    case 2: ch += *source++; ch <<= 6;
-	    case 1: ch += *source++; ch <<= 6;
-	    case 0: ch += *source++;
-	}
-	ch -= offsetsFromUTF8[extraBytesToRead];
-
-	if (target >= targetEnd) {
-	    source -= (extraBytesToRead+1); /* Back up the source pointer! */
-	    result = targetExhausted; break;
-	}
-	if (ch <= UNI_MAX_LEGAL_UTF32) {
-	    /*
-	     * UTF-16 surrogate values are illegal in UTF-32, and anything
-	     * over Plane 17 (> 0x10FFFF) is illegal.
-	     */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = ch;
-	    }
-	} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
-	    result = sourceIllegal;
-	    *target++ = UNI_REPLACEMENT_CHAR;
-	}
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* ---------------------------------------------------------------------
-
-    Note A.
-    The fall-through switches in UTF-8 reading code save a
-    temp variable, some decrements & conditionals.  The switches
-    are equivalent to the following loop:
-	{
-	    int tmpBytesToRead = extraBytesToRead+1;
-	    do {
-		ch += *source++;
-		--tmpBytesToRead;
-		if (tmpBytesToRead) ch <<= 6;
-	    } while (tmpBytesToRead > 0);
-	}
-    In UTF-8 writing code, the switches on "bytesToWrite" are
-    similarly unrolled loops.
-
-   --------------------------------------------------------------------- */

+ 0 - 151
contrib/ConvertUTF/ConvertUTF.h

@@ -1,151 +0,0 @@
-/*
- * Copyright 2001-2004 Unicode, Inc.
- * 
- * Disclaimer
- * 
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- * 
- * Limitations on Rights to Redistribute This Code
- * 
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
- */
-#ifndef CONVERTUTF_H
-#define CONVERTUTF_H
-/* ---------------------------------------------------------------------
-
-    Conversions between UTF32, UTF-16, and UTF-8.  Header file.
-
-    Several funtions are included here, forming a complete set of
-    conversions between the three formats.  UTF-7 is not included
-    here, but is handled in a separate source file.
-
-    Each of these routines takes pointers to input buffers and output
-    buffers.  The input buffers are const.
-
-    Each routine converts the text between *sourceStart and sourceEnd,
-    putting the result into the buffer between *targetStart and
-    targetEnd. Note: the end pointers are *after* the last item: e.g. 
-    *(sourceEnd - 1) is the last item.
-
-    The return result indicates whether the conversion was successful,
-    and if not, whether the problem was in the source or target buffers.
-    (Only the first encountered problem is indicated.)
-
-    After the conversion, *sourceStart and *targetStart are both
-    updated to point to the end of last text successfully converted in
-    the respective buffers.
-
-    Input parameters:
-	sourceStart - pointer to a pointer to the source buffer.
-		The contents of this are modified on return so that
-		it points at the next thing to be converted.
-	targetStart - similarly, pointer to pointer to the target buffer.
-	sourceEnd, targetEnd - respectively pointers to the ends of the
-		two buffers, for overflow checking only.
-
-    These conversion functions take a ConversionFlags argument. When this
-    flag is set to strict, both irregular sequences and isolated surrogates
-    will cause an error.  When the flag is set to lenient, both irregular
-    sequences and isolated surrogates are converted.
-
-    Whether the flag is strict or lenient, all illegal sequences will cause
-    an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
-    or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
-    must check for illegal sequences.
-
-    When the flag is set to lenient, characters over 0x10FFFF are converted
-    to the replacement character; otherwise (when the flag is set to strict)
-    they constitute an error.
-
-    Output parameters:
-	The value "sourceIllegal" is returned from some routines if the input
-	sequence is malformed.  When "sourceIllegal" is returned, the source
-	value will point to the illegal value that caused the problem. E.g.,
-	in UTF-8 when a sequence is malformed, it points to the start of the
-	malformed sequence.  
-
-    Author: Mark E. Davis, 1994.
-    Rev History: Rick McGowan, fixes & updates May 2001.
-		 Fixes & updates, Sept 2001.
-
------------------------------------------------------------------------- */
-
-/* ---------------------------------------------------------------------
-    The following 4 definitions are compiler-specific.
-    The C standard does not guarantee that wchar_t has at least
-    16 bits, so wchar_t is no less portable than unsigned short!
-    All should be unsigned values to avoid sign extension during
-    bit mask & shift operations.
------------------------------------------------------------------------- */
-
-typedef unsigned long	UTF32;	/* at least 32 bits */
-typedef unsigned short	UTF16;	/* at least 16 bits */
-typedef unsigned char	UTF8;	/* typically 8 bits */
-typedef unsigned char	Boolean; /* 0 or 1 */
-
-/* Some fundamental constants */
-#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
-#define UNI_MAX_BMP (UTF32)0x0000FFFF
-#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
-#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
-#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
-
-typedef enum {
-	conversionOK, 		/* conversion successful */
-	sourceExhausted,	/* partial character in source, but hit end */
-	targetExhausted,	/* insuff. room in target for conversion */
-	sourceIllegal		/* source sequence is illegal/malformed */
-} ConversionResult;
-
-typedef enum {
-	strictConversion = 0,
-	lenientConversion
-} ConversionFlags;
-
-/* This is for C++ and does no harm in C */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-ConversionResult ConvertUTF8toUTF16 (
-		const UTF8** sourceStart, const UTF8* sourceEnd, 
-		UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF16toUTF8 (
-		const UTF16** sourceStart, const UTF16* sourceEnd, 
-		UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-		
-ConversionResult ConvertUTF8toUTF32 (
-		const UTF8** sourceStart, const UTF8* sourceEnd, 
-		UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF32toUTF8 (
-		const UTF32** sourceStart, const UTF32* sourceEnd, 
-		UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-		
-ConversionResult ConvertUTF16toUTF32 (
-		const UTF16** sourceStart, const UTF16* sourceEnd, 
-		UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF32toUTF16 (
-		const UTF32** sourceStart, const UTF32* sourceEnd, 
-		UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
-
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
-
-#ifdef __cplusplus
-}
-#endif
-
-/* --------------------------------------------------------------------- */
-#endif  // CONVERTUTF_H

+ 0 - 43
contrib/ConvertUTF/readme.txt

@@ -1,43 +0,0 @@
-
-The accompanying C source code file "ConvertUTF.c" and the associated header
-file "ConvertUTF.h" provide for conversion between various transformation
-formats of Unicode characters.  The following conversions are supported:
-
-	UTF-32 to UTF-16
-	UTF-32 to UTF-8
-	UTF-16 to UTF-32
-	UTF-16 to UTF-8
-	UTF-8 to UTF-16
-	UTF-8 to UTF-32
-
-In addition, there is a test harness which runs various tests.
-
-The files "CVTUTF7.C" and "CVTUTF7.H" are for archival and historical purposes
-only. They have not been updated to Unicode 3.0 or later and should be
-considered obsolescent. "CVTUTF7.C" contains two functions that can convert
-between UCS2 (i.e., the BMP characters only) and UTF-7. Surrogates are
-not supported, the code has not been tested, and should be considered
-unsuitable for general purpose use.
-
-Please submit any bug reports about these programs here:
-
-	http://www.unicode.org/unicode/reporting.html
-
-Version 1.0: initial version.
-
-Version 1.1: corrected some minor problems; added stricter checks.
-
-Version 1.2: corrected switch statements associated with "extraBytesToRead"
-	in 4 & 5 byte cases, in functions for conversion from UTF8.
-	Note: formally, the 4 & 5 byte cases are illegal in the latest
-	UTF8, but the table and this code has always catered for those,
-	cases since at one time they were legal.
-
-Version 1.3: Updated UTF-8 legality check;
-	updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions
-	Updated UTF-8 legality tests in harness.c
- 
-
-Last update: October 19, 2004
-
-

+ 114 - 8
contrib/openddlparser/CMakeLists.txt

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

+ 3 - 0
contrib/openddlparser/CREDITS

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

+ 2 - 2
contrib/openddlparser/README.md

@@ -11,7 +11,7 @@ Current coverity check status:
   <img alt="Coverity Scan Build Status"
        src="https://scan.coverity.com/projects/5606/badge.svg"/>
 </a>
-
+Current test coverage:[![Coverage Status](https://coveralls.io/repos/github/kimkulling/openddl-parser/badge.svg?branch=master)](https://coveralls.io/github/kimkulling/openddl-parser?branch=cpp_coveralls)
 Get the source code
 ===================
 You can get the code from our git repository, which is located at GitHub. You can clone the repository with the following command:
@@ -25,7 +25,7 @@ After installing it you can open a console and enter:
 
 > cmake CMakeLists.txt
 
-This command will generate a build environment for your installed build enrironment ( for Visual-Studio-users the project files will be generated, for gcc-users the makefiles will be generated ).
+This command will generate a build environment for your preferred build tool ( for Visual-Studio-users the project files will be generated, for gcc-users the makefiles will be generated ).
 When using an IDE open the IDE and run the build. When using GNU-make type in your console:
 
 > make

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

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

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

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

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

@@ -29,60 +29,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 BEGIN_ODDLPARSER_NS
 
-StreamFormatterBase::StreamFormatterBase() {
-
-}
-
-StreamFormatterBase::~StreamFormatterBase() {
-
-}
-
-std::string StreamFormatterBase::format( const std::string &statement ) {
-    std::string tmp( statement );
-    return tmp;
-}
-
-IOStreamBase::IOStreamBase( StreamFormatterBase *formatter )
-: m_formatter( formatter )
-, m_file( ddl_nullptr ) {
-    if (ddl_nullptr == m_formatter) {
-        m_formatter = new StreamFormatterBase;
-    }
-}
-
-IOStreamBase::~IOStreamBase() {
-    delete m_formatter;
-    m_formatter = ddl_nullptr;
-}
-
-bool IOStreamBase::open( const std::string &name ) {
-    m_file = ::fopen( name.c_str(), "a" );
-    if (m_file == ddl_nullptr) {
-        return false;
-    }
-    
-    return true;
-}
-
-bool IOStreamBase::close() {
-    if (ddl_nullptr == m_file) {
-        return false;
-    }
-
-    ::fclose( m_file );
-    m_file = ddl_nullptr;
-
-    return true;
-}
-
-size_t IOStreamBase::write( const std::string &statement ) {
-    if (ddl_nullptr == m_file) {
-        return 0;
-    }
-    std::string formatStatement = m_formatter->format( statement );
-    return ::fwrite( formatStatement.c_str(), sizeof( char ), formatStatement.size(), m_file );
-}
-
 struct DDLNodeIterator {
     const DDLNode::DllNodeList &m_childs;
     size_t m_idx;
@@ -280,7 +226,7 @@ bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std:
         statement += "[";
         char buffer[ 256 ];
         ::memset( buffer, '\0', 256 * sizeof( char ) );
-        sprintf( buffer, "%d", int(numItems) );
+        sprintf( buffer, "%d", static_cast<int>( numItems ) );
         statement += buffer;
         statement += "]";
     }

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

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

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

@@ -0,0 +1,96 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#include <openddlparser/OpenDDLStream.h>
+
+BEGIN_ODDLPARSER_NS
+
+StreamFormatterBase::StreamFormatterBase() {
+    // empty
+}
+
+StreamFormatterBase::~StreamFormatterBase() {
+    // empty
+}
+
+std::string StreamFormatterBase::format(const std::string &statement) {
+    std::string tmp(statement);
+    return tmp;
+}
+
+IOStreamBase::IOStreamBase(StreamFormatterBase *formatter)
+    : m_formatter(formatter)
+    , m_file(ddl_nullptr) {
+    if (ddl_nullptr == m_formatter) {
+        m_formatter = new StreamFormatterBase;
+    }
+}
+
+IOStreamBase::~IOStreamBase() {
+    delete m_formatter;
+    m_formatter = ddl_nullptr;
+}
+
+bool IOStreamBase::open(const std::string &name) {
+    m_file = ::fopen(name.c_str(), "a");
+    if (m_file == ddl_nullptr) {
+        return false;
+    }
+
+    return true;
+}
+
+bool IOStreamBase::close() {
+    if (ddl_nullptr == m_file) {
+        return false;
+    }
+
+    ::fclose(m_file);
+    m_file = ddl_nullptr;
+
+    return true;
+}
+
+bool IOStreamBase::isOpen() const {
+    return ( ddl_nullptr != m_file );
+}
+
+size_t IOStreamBase::read( size_t sizeToRead, std::string &statement ) {
+    if (ddl_nullptr == m_file) {
+        return 0;
+    }
+    
+    statement.resize(sizeToRead);
+    const size_t readBytes = ::fread( &statement[0], 1, sizeToRead, m_file );
+
+    return readBytes;
+}
+
+size_t IOStreamBase::write(const std::string &statement) {
+    if (ddl_nullptr == m_file) {
+        return 0;
+    }
+    std::string formatStatement = m_formatter->format(statement);
+    return ::fwrite(formatStatement.c_str(), sizeof(char), formatStatement.size(), m_file);
+}
+
+END_ODDLPARSER_NS

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

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

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

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

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

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

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

@@ -23,37 +23,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #pragma once
 
 #include <openddlparser/OpenDDLCommon.h>
+#include <openddlparser/OpenDDLStream.h>
 #include <openddlparser/Value.h>
 
 BEGIN_ODDLPARSER_NS
 
-//-------------------------------------------------------------------------------------------------
-/// @ingroup    IOStreamBase
-///	@brief      This class represents the stream to write out.
-//-------------------------------------------------------------------------------------------------
-class DLL_ODDLPARSER_EXPORT StreamFormatterBase {
-public:
-    StreamFormatterBase();
-    virtual ~StreamFormatterBase();
-    virtual std::string format( const std::string &statement );
-};
-
-//-------------------------------------------------------------------------------------------------
-/// @ingroup    IOStreamBase
-///	@brief      This class represents the stream to write out.
-//-------------------------------------------------------------------------------------------------
-class DLL_ODDLPARSER_EXPORT IOStreamBase {
-public:
-    IOStreamBase( StreamFormatterBase *formatter = ddl_nullptr );
-    virtual ~IOStreamBase();
-    virtual bool open( const std::string &anme );
-    virtual bool close();
-    virtual size_t write( const std::string &statement );
-
-private:
-    StreamFormatterBase *m_formatter;
-    FILE *m_file;
-};
+// Forward declarations
+class IOStreamBase;
 
 //-------------------------------------------------------------------------------------------------
 ///

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

@@ -39,6 +39,16 @@ struct Identifier;
 struct Reference;
 struct Property;
 
+template<class T>
+inline
+bool isEmbeddedCommentOpenTag( T *in, T *end ) {
+    if ( in == '/' && in+1 == '*' ) {
+        return true;
+    }
+
+    return false;
+}
+
 ///	@brief  Utility function to search for the next token or the end of the buffer.
 /// @param  in      [in] The start position in the buffer.
 /// @param  end     [in] The end position in the buffer.
@@ -47,7 +57,7 @@ struct Property;
 template<class T>
 inline
 T *lookForNextToken( T *in, T *end ) {
-    while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) {
+    while( ( in != end ) && ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) ) {
         in++;
     }
     return in;

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

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

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

@@ -0,0 +1,89 @@
+/*-----------------------------------------------------------------------------------------------
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Kim Kulling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-----------------------------------------------------------------------------------------------*/
+#pragma once
+
+#include <openddlparser/OpenDDLCommon.h>
+
+BEGIN_ODDLPARSER_NS
+
+//-------------------------------------------------------------------------------------------------
+/// @ingroup    IOStreamBase
+///	@brief      This class represents the stream to write out.
+//-------------------------------------------------------------------------------------------------
+class DLL_ODDLPARSER_EXPORT StreamFormatterBase {
+public:
+    /// @brief  The class constructor.
+    StreamFormatterBase();
+
+    /// @brief  The class destructor, virtual.
+    virtual ~StreamFormatterBase();
+
+    /// @brief  Will format the sring and return the new formatted result.
+    /// @param  statement   [in] The string to reformat.
+    /// @return The reformatted result.
+    virtual std::string format(const std::string &statement);
+};
+
+//-------------------------------------------------------------------------------------------------
+/// @ingroup    IOStreamBase
+///	@brief      This class represents the stream to write out.
+//-------------------------------------------------------------------------------------------------
+class DLL_ODDLPARSER_EXPORT IOStreamBase {
+public:
+    /// @brief  The class constructor with the formatter.
+    /// @param  formatter   [in] The formatter to use.
+    explicit IOStreamBase(StreamFormatterBase *formatter = ddl_nullptr);
+
+    /// @brief  The class destructor, virtual.
+    virtual ~IOStreamBase();
+
+    /// @brief  Will open the stream.
+    /// @param  name        [in] The name for the stream.
+    /// @return true, if the stream was opened successfully, false if not.
+    virtual bool open(const std::string &name);
+
+    /// @brief  Will close the stream.
+    /// @return true, if the stream was closed successfully, false if not.
+    virtual bool close();
+
+    /// @brief  Returns true, if the stream is open.
+    /// @return true, if the stream is open, false if not.
+    virtual bool isOpen() const;
+
+    /// @brief  Will read a string from the stream.
+    /// @param  sizeToRead  [in] The size to read in bytes.
+    /// @param  statement   [out] The read statements.
+    /// @return The bytes read from the stream.
+    virtual size_t read( size_t sizeToRead, std::string &statement );
+
+    /// @brief  Will write a string into the stream.
+    /// @param  statement  [in] The string to write.
+    /// @return The bytes written into the stream.
+    virtual size_t write(const std::string &statement);
+
+private:
+    StreamFormatterBase *m_formatter;
+    FILE *m_file;
+};
+
+END_ODDLPARSER_NS

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

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

+ 23 - 31
contrib/poly2tri/poly2tri/common/shapes.cc

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -88,7 +88,7 @@ void Triangle::Clear()
     points_[0]=points_[1]=points_[2] = NULL;
 }
 
-void Triangle::ClearNeighbor(Triangle *triangle )
+void Triangle::ClearNeighbor(const Triangle *triangle )
 {
     if( neighbors_[0] == triangle )
     {
@@ -96,14 +96,14 @@ void Triangle::ClearNeighbor(Triangle *triangle )
     }
     else if( neighbors_[1] == triangle )
     {
-        neighbors_[1] = NULL;            
+        neighbors_[1] = NULL;
     }
     else
     {
         neighbors_[2] = NULL;
     }
 }
-    
+
 void Triangle::ClearNeighbors()
 {
   neighbors_[0] = NULL;
@@ -116,13 +116,9 @@ void Triangle::ClearDelunayEdges()
   delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false;
 }
 
-Point* Triangle::OppositePoint(Triangle& t, Point& p)
+Point* Triangle::OppositePoint(Triangle& t, const Point& p)
 {
   Point *cw = t.PointCW(p);
-  //double x = cw->x;
-  //double y = cw->y;
-  //x = p.x;
-  //y = p.y;
   return PointCW(*cw);
 }
 
@@ -164,8 +160,7 @@ int Triangle::Index(const Point* p)
     return 2;
   }
   assert(0);
-
-  return 0;
+  return -1;
 }
 
 int Triangle::EdgeIndex(const Point* p1, const Point* p2)
@@ -192,7 +187,7 @@ int Triangle::EdgeIndex(const Point* p1, const Point* p2)
   return -1;
 }
 
-void Triangle::MarkConstrainedEdge(const int index)
+void Triangle::MarkConstrainedEdge(int index)
 {
   constrained_edge[index] = true;
 }
@@ -215,7 +210,7 @@ void Triangle::MarkConstrainedEdge(Point* p, Point* q)
 }
 
 // The point counter-clockwise to given point
-Point* Triangle::PointCW(Point& point)
+Point* Triangle::PointCW(const Point& point)
 {
   if (&point == points_[0]) {
     return points_[2];
@@ -225,12 +220,11 @@ Point* Triangle::PointCW(Point& point)
     return points_[1];
   }
   assert(0);
-
-  return 0;
+  return NULL;
 }
 
 // The point counter-clockwise to given point
-Point* Triangle::PointCCW(Point& point)
+Point* Triangle::PointCCW(const Point& point)
 {
   if (&point == points_[0]) {
     return points_[1];
@@ -240,12 +234,11 @@ Point* Triangle::PointCCW(Point& point)
     return points_[0];
   }
   assert(0);
-
-  return 0;
+  return NULL;
 }
 
 // The neighbor clockwise to given point
-Triangle* Triangle::NeighborCW(Point& point)
+Triangle* Triangle::NeighborCW(const Point& point)
 {
   if (&point == points_[0]) {
     return neighbors_[1];
@@ -256,7 +249,7 @@ Triangle* Triangle::NeighborCW(Point& point)
 }
 
 // The neighbor counter-clockwise to given point
-Triangle* Triangle::NeighborCCW(Point& point)
+Triangle* Triangle::NeighborCCW(const Point& point)
 {
   if (&point == points_[0]) {
     return neighbors_[2];
@@ -266,7 +259,7 @@ Triangle* Triangle::NeighborCCW(Point& point)
   return neighbors_[1];
 }
 
-bool Triangle::GetConstrainedEdgeCCW(Point& p)
+bool Triangle::GetConstrainedEdgeCCW(const Point& p)
 {
   if (&p == points_[0]) {
     return constrained_edge[2];
@@ -276,7 +269,7 @@ bool Triangle::GetConstrainedEdgeCCW(Point& p)
   return constrained_edge[1];
 }
 
-bool Triangle::GetConstrainedEdgeCW(Point& p)
+bool Triangle::GetConstrainedEdgeCW(const Point& p)
 {
   if (&p == points_[0]) {
     return constrained_edge[1];
@@ -286,7 +279,7 @@ bool Triangle::GetConstrainedEdgeCW(Point& p)
   return constrained_edge[0];
 }
 
-void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce)
+void Triangle::SetConstrainedEdgeCCW(const Point& p, bool ce)
 {
   if (&p == points_[0]) {
     constrained_edge[2] = ce;
@@ -297,7 +290,7 @@ void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce)
   }
 }
 
-void Triangle::SetConstrainedEdgeCW(Point& p, bool ce)
+void Triangle::SetConstrainedEdgeCW(const Point& p, bool ce)
 {
   if (&p == points_[0]) {
     constrained_edge[1] = ce;
@@ -308,7 +301,7 @@ void Triangle::SetConstrainedEdgeCW(Point& p, bool ce)
   }
 }
 
-bool Triangle::GetDelunayEdgeCCW(Point& p)
+bool Triangle::GetDelunayEdgeCCW(const Point& p)
 {
   if (&p == points_[0]) {
     return delaunay_edge[2];
@@ -318,7 +311,7 @@ bool Triangle::GetDelunayEdgeCCW(Point& p)
   return delaunay_edge[1];
 }
 
-bool Triangle::GetDelunayEdgeCW(Point& p)
+bool Triangle::GetDelunayEdgeCW(const Point& p)
 {
   if (&p == points_[0]) {
     return delaunay_edge[1];
@@ -328,7 +321,7 @@ bool Triangle::GetDelunayEdgeCW(Point& p)
   return delaunay_edge[0];
 }
 
-void Triangle::SetDelunayEdgeCCW(Point& p, bool e)
+void Triangle::SetDelunayEdgeCCW(const Point& p, bool e)
 {
   if (&p == points_[0]) {
     delaunay_edge[2] = e;
@@ -339,7 +332,7 @@ void Triangle::SetDelunayEdgeCCW(Point& p, bool e)
   }
 }
 
-void Triangle::SetDelunayEdgeCW(Point& p, bool e)
+void Triangle::SetDelunayEdgeCW(const Point& p, bool e)
 {
   if (&p == points_[0]) {
     delaunay_edge[1] = e;
@@ -351,7 +344,7 @@ void Triangle::SetDelunayEdgeCW(Point& p, bool e)
 }
 
 // The neighbor across to given point
-Triangle& Triangle::NeighborAcross(Point& opoint)
+Triangle& Triangle::NeighborAcross(const Point& opoint)
 {
   if (&opoint == points_[0]) {
     return *neighbors_[0];
@@ -369,5 +362,4 @@ void Triangle::DebugPrint()
   cout << points_[2]->x << "," << points_[2]->y << endl;
 }
 
-}
-
+}

+ 29 - 31
contrib/poly2tri/poly2tri/common/shapes.h

@@ -113,7 +113,7 @@ struct Point {
   /// Convert this point into a unit point. Returns the Length.
   double Normalize()
   {
-    double len = Length();
+    const double len = Length();
     x /= len;
     y /= len;
     return len;
@@ -162,50 +162,50 @@ bool constrained_edge[3];
 /// Flags to determine if an edge is a Delauney edge
 bool delaunay_edge[3];
 
-Point* GetPoint(const int& index);
-Point* PointCW(Point& point);
-Point* PointCCW(Point& point);
-Point* OppositePoint(Triangle& t, Point& p);
+Point* GetPoint(int index);
+Point* PointCW(const Point& point);
+Point* PointCCW(const Point& point);
+Point* OppositePoint(Triangle& t, const Point& p);
 
-Triangle* GetNeighbor(const int& index);
+Triangle* GetNeighbor(int index);
 void MarkNeighbor(Point* p1, Point* p2, Triangle* t);
 void MarkNeighbor(Triangle& t);
 
-void MarkConstrainedEdge(const int index);
+void MarkConstrainedEdge(int index);
 void MarkConstrainedEdge(Edge& edge);
 void MarkConstrainedEdge(Point* p, Point* q);
 
 int Index(const Point* p);
 int EdgeIndex(const Point* p1, const Point* p2);
 
-Triangle* NeighborCW(Point& point);
-Triangle* NeighborCCW(Point& point);
-bool GetConstrainedEdgeCCW(Point& p);
-bool GetConstrainedEdgeCW(Point& p);
-void SetConstrainedEdgeCCW(Point& p, bool ce);
-void SetConstrainedEdgeCW(Point& p, bool ce);
-bool GetDelunayEdgeCCW(Point& p);
-bool GetDelunayEdgeCW(Point& p);
-void SetDelunayEdgeCCW(Point& p, bool e);
-void SetDelunayEdgeCW(Point& p, bool e);
-
-bool Contains(Point* p);
+Triangle* NeighborCW(const Point& point);
+Triangle* NeighborCCW(const Point& point);
+bool GetConstrainedEdgeCCW(const Point& p);
+bool GetConstrainedEdgeCW(const Point& p);
+void SetConstrainedEdgeCCW(const Point& p, bool ce);
+void SetConstrainedEdgeCW(const Point& p, bool ce);
+bool GetDelunayEdgeCCW(const Point& p);
+bool GetDelunayEdgeCW(const Point& p);
+void SetDelunayEdgeCCW(const Point& p, bool e);
+void SetDelunayEdgeCW(const Point& p, bool e);
+
+bool Contains(const Point* p);
 bool Contains(const Edge& e);
-bool Contains(Point* p, Point* q);
+bool Contains(const Point* p, const Point* q);
 void Legalize(Point& point);
 void Legalize(Point& opoint, Point& npoint);
 /**
  * Clears all references to all other triangles and points
  */
 void Clear();
-void ClearNeighbor(Triangle *triangle );
+void ClearNeighbor(const Triangle *triangle);
 void ClearNeighbors();
 void ClearDelunayEdges();
 
 inline bool IsInterior();
 inline void IsInterior(bool b);
 
-Triangle& NeighborAcross(Point& opoint);
+Triangle& NeighborAcross(const Point& opoint);
 
 void DebugPrint();
 
@@ -258,7 +258,7 @@ inline bool operator ==(const Point& a, const Point& b)
 
 inline bool operator !=(const Point& a, const Point& b)
 {
-  return a.x != b.x || a.y != b.y;
+  return !(a.x == b.x) && !(a.y == b.y);
 }
 
 /// Peform the dot product on two vectors.
@@ -282,22 +282,22 @@ inline Point Cross(const Point& a, double s)
 
 /// Perform the cross product on a scalar and a point. In 2D this produces
 /// a point.
-inline Point Cross(const double s, const Point& a)
+inline Point Cross(double s, const Point& a)
 {
   return Point(-s * a.y, s * a.x);
 }
 
-inline Point* Triangle::GetPoint(const int& index)
+inline Point* Triangle::GetPoint(int index)
 {
   return points_[index];
 }
 
-inline Triangle* Triangle::GetNeighbor(const int& index)
+inline Triangle* Triangle::GetNeighbor(int index)
 {
   return neighbors_[index];
 }
 
-inline bool Triangle::Contains(Point* p)
+inline bool Triangle::Contains(const Point* p)
 {
   return p == points_[0] || p == points_[1] || p == points_[2];
 }
@@ -307,7 +307,7 @@ inline bool Triangle::Contains(const Edge& e)
   return Contains(e.p) && Contains(e.q);
 }
 
-inline bool Triangle::Contains(Point* p, Point* q)
+inline bool Triangle::Contains(const Point* p, const Point* q)
 {
   return Contains(p) && Contains(q);
 }
@@ -324,6 +324,4 @@ inline void Triangle::IsInterior(bool b)
 
 }
 
-#endif
-
-
+#endif

+ 32 - 8
contrib/poly2tri/poly2tri/common/utils.h

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -28,18 +28,26 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
 #ifndef UTILS_H
 #define UTILS_H
 
+// Otherwise #defines like M_PI are undeclared under Visual Studio
+#define _USE_MATH_DEFINES
+
 #include <exception>
+#include <math.h>
+
+// C99 removes M_PI from math.h
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338327
+#endif
 
 namespace p2t {
 
-const double PI = 3.1415926535897932384626433832795029;
-const double PI_2 = 2 * PI;
-const double PI_3div4 = 3 * PI / 4;
-const double EPSILON = 1e-15;
+const double PI_3div4 = 3 * M_PI / 4;
+const double PI_div2 = 1.57079632679489661923;
+const double EPSILON = 1e-12;
 
 enum Orientation { CW, CCW, COLLINEAR };
 
@@ -53,7 +61,7 @@ enum Orientation { CW, CCW, COLLINEAR };
  *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
  * </pre>
  */
-Orientation Orient2d(Point& pa, Point& pb, Point& pc)
+Orientation Orient2d(const Point& pa, const Point& pb, const Point& pc)
 {
   double detleft = (pa.x - pc.x) * (pb.y - pc.y);
   double detright = (pa.y - pc.y) * (pb.x - pc.x);
@@ -66,6 +74,7 @@ Orientation Orient2d(Point& pa, Point& pb, Point& pc)
   return CW;
 }
 
+/*
 bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd)
 {
   double pdx = pd.x;
@@ -97,7 +106,22 @@ bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd)
   return true;
 }
 
+*/
+
+bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point& pd)
+{
+  double oadb = (pa.x - pb.x)*(pd.y - pb.y) - (pd.x - pb.x)*(pa.y - pb.y);
+  if (oadb >= -EPSILON) {
+    return false;
+  }
+
+  double oadc = (pa.x - pc.x)*(pd.y - pc.y) - (pd.x - pc.x)*(pa.y - pc.y);
+  if (oadc <= EPSILON) {
+    return false;
+  }
+  return true;
 }
 
-#endif
+}
 
+#endif

+ 2 - 3
contrib/poly2tri/poly2tri/poly2tri.h

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -35,5 +35,4 @@
 #include "common/shapes.h"
 #include "sweep/cdt.h"
 
-#endif
-
+#endif

+ 3 - 4
contrib/poly2tri/poly2tri/sweep/advancing_front.cc

@@ -39,7 +39,7 @@ AdvancingFront::AdvancingFront(Node& head, Node& tail)
   search_node_ = &head;
 }
 
-Node* AdvancingFront::LocateNode(const double& x)
+Node* AdvancingFront::LocateNode(double x)
 {
   Node* node = search_node_;
 
@@ -61,7 +61,7 @@ Node* AdvancingFront::LocateNode(const double& x)
   return NULL;
 }
 
-Node* AdvancingFront::FindSearchNode(const double& x)
+Node* AdvancingFront::FindSearchNode(double x)
 {
   (void)x; // suppress compiler warnings "unused parameter 'x'"
   // TODO: implement BST index
@@ -105,5 +105,4 @@ AdvancingFront::~AdvancingFront()
 {
 }
 
-}
-
+}

+ 3 - 3
contrib/poly2tri/poly2tri/sweep/advancing_front.h

@@ -74,7 +74,7 @@ Node* search();
 void set_search(Node* node);
 
 /// Locate insertion point along advancing front
-Node* LocateNode(const double& x);
+Node* LocateNode(double x);
 
 Node* LocatePoint(const Point* point);
 
@@ -82,7 +82,7 @@ private:
 
 Node* head_, *tail_, *search_node_;
 
-Node* FindSearchNode(const double& x);
+Node* FindSearchNode(double x);
 };
 
 inline Node* AdvancingFront::head()
@@ -115,4 +115,4 @@ inline void AdvancingFront::set_search(Node* node)
 
 }
 
-#endif
+#endif

+ 4 - 5
contrib/poly2tri/poly2tri/sweep/cdt.cc

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -32,13 +32,13 @@
 
 namespace p2t {
 
-CDT::CDT(std::vector<Point*> polyline)
+CDT::CDT(const std::vector<Point*>& polyline)
 {
   sweep_context_ = new SweepContext(polyline);
   sweep_ = new Sweep;
 }
 
-void CDT::AddHole(std::vector<Point*> polyline)
+void CDT::AddHole(const std::vector<Point*>& polyline)
 {
   sweep_context_->AddHole(polyline);
 }
@@ -68,5 +68,4 @@ CDT::~CDT()
   delete sweep_;
 }
 
-}
-
+}

+ 17 - 17
contrib/poly2tri/poly2tri/sweep/cdt.h

@@ -1,4 +1,4 @@
-/* 
+/*
  * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors
  * http://code.google.com/p/poly2tri/
  *
@@ -28,7 +28,7 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
- 
+
 #ifndef CDT_H
 #define CDT_H
 
@@ -37,11 +37,11 @@
 #include "sweep.h"
 
 /**
- * 
+ *
  * @author Mason Green <[email protected]>
  *
  */
- 
+
 namespace p2t {
 
 class CDT
@@ -50,40 +50,40 @@ public:
 
   /**
    * Constructor - add polyline with non repeating points
-   * 
+   *
    * @param polyline
    */
-  CDT(std::vector<Point*> polyline);
-  
+  CDT(const std::vector<Point*>& polyline);
+
    /**
    * Destructor - clean up memory
    */
   ~CDT();
-  
+
   /**
    * Add a hole
-   * 
+   *
    * @param polyline
    */
-  void AddHole(std::vector<Point*> polyline);
-  
+  void AddHole(const std::vector<Point*>& polyline);
+
   /**
    * Add a steiner point
-   * 
+   *
    * @param point
    */
   void AddPoint(Point* point);
-  
+
   /**
    * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points
    */
   void Triangulate();
-  
+
   /**
    * Get CDT triangles
    */
   std::vector<Triangle*> GetTriangles();
-  
+
   /**
    * Get triangle map
    */
@@ -94,7 +94,7 @@ public:
   /**
    * Internals
    */
-   
+
   SweepContext* sweep_context_;
   Sweep* sweep_;
 
@@ -102,4 +102,4 @@ public:
 
 }
 
-#endif
+#endif

+ 91 - 42
contrib/poly2tri/poly2tri/sweep/sweep.cc

@@ -49,7 +49,7 @@ void Sweep::Triangulate(SweepContext& tcx)
 
 void Sweep::SweepPoints(SweepContext& tcx)
 {
-  for (int i = 1; i < tcx.point_count(); i++) {
+  for (size_t i = 1; i < tcx.point_count(); i++) {
     Point& point = *tcx.GetPoint(i);
     Node* node = &PointEvent(tcx, point);
     for (unsigned int i = 0; i < point.edge_list.size(); i++) {
@@ -117,7 +117,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
 	  throw std::runtime_error("EdgeEvent - collinear points not supported");
     if( triangle->Contains(&eq, p1)) {
       triangle->MarkConstrainedEdge(&eq, p1 );
-      // We are modifying the constraint maybe it would be better to 
+      // We are modifying the constraint maybe it would be better to
       // not change the given constraint and just keep a variable for the new constraint
       tcx.edge_event.constrained_edge->q = p1;
       triangle = &triangle->NeighborAcross(point);
@@ -137,7 +137,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
 
     if( triangle->Contains(&eq, p2)) {
       triangle->MarkConstrainedEdge(&eq, p2 );
-      // We are modifying the constraint maybe it would be better to 
+      // We are modifying the constraint maybe it would be better to
       // not change the given constraint and just keep a variable for the new constraint
       tcx.edge_event.constrained_edge->q = p2;
       triangle = &triangle->NeighborAcross(point);
@@ -166,7 +166,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
 
 bool Sweep::IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq)
 {
-  int index = triangle.EdgeIndex(&ep, &eq);
+  const int index = triangle.EdgeIndex(&ep, &eq);
 
   if (index != -1) {
     triangle.MarkConstrainedEdge(index);
@@ -230,8 +230,8 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
   Node* node = n.next;
 
   while (node->next) {
-    double angle = HoleAngle(*node);
-    if (angle > PI_2 || angle < -PI_2) break;
+    // if HoleAngle exceeds 90 degrees then break.
+    if (LargeHole_DontFill(node)) break;
     Fill(tcx, *node);
     node = node->next;
   }
@@ -240,29 +240,81 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
   node = n.prev;
 
   while (node->prev) {
-    double angle = HoleAngle(*node);
-    if (angle > PI_2 || angle < -PI_2) break;
+    // if HoleAngle exceeds 90 degrees then break.
+    if (LargeHole_DontFill(node)) break;
     Fill(tcx, *node);
     node = node->prev;
   }
 
   // Fill right basins
   if (n.next && n.next->next) {
-    double angle = BasinAngle(n);
+    const double angle = BasinAngle(n);
     if (angle < PI_3div4) {
       FillBasin(tcx, n);
     }
   }
 }
 
-double Sweep::BasinAngle(Node& node)
+// True if HoleAngle exceeds 90 degrees.
+bool Sweep::LargeHole_DontFill(const Node* node) const {
+
+  const Node* nextNode = node->next;
+  const Node* prevNode = node->prev;
+  if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point))
+          return false;
+
+  // Check additional points on front.
+  const Node* next2Node = nextNode->next;
+  // "..Plus.." because only want angles on same side as point being added.
+  if ((next2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point))
+          return false;
+
+  const Node* prev2Node = prevNode->prev;
+  // "..Plus.." because only want angles on same side as point being added.
+  if ((prev2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point))
+          return false;
+
+  return true;
+}
+
+bool Sweep::AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const {
+  const double angle = Angle(origin, pa, pb);
+  return ((angle > PI_div2) || (angle < -PI_div2));
+}
+
+bool Sweep::AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const {
+  const double angle = Angle(origin, pa, pb);
+  return (angle > PI_div2) || (angle < 0);
+}
+
+double Sweep::Angle(const Point* origin, const Point* pa, const Point* pb) const {
+  /* Complex plane
+   * ab = cosA +i*sinA
+   * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx)
+   * atan2(y,x) computes the principal value of the argument function
+   * applied to the complex number x+iy
+   * Where x = ax*bx + ay*by
+   *       y = ax*by - ay*bx
+   */
+  const double px = origin->x;
+  const double py = origin->y;
+  const double ax = pa->x- px;
+  const double ay = pa->y - py;
+  const double bx = pb->x - px;
+  const double by = pb->y - py;
+  const double x = ax * by - ay * bx;
+  const double y = ax * bx + ay * by;
+  return atan2(x, y);
+}
+
+double Sweep::BasinAngle(const Node& node) const
 {
-  double ax = node.point->x - node.next->next->point->x;
-  double ay = node.point->y - node.next->next->point->y;
+  const double ax = node.point->x - node.next->next->point->x;
+  const double ay = node.point->y - node.next->next->point->y;
   return atan2(ay, ax);
 }
 
-double Sweep::HoleAngle(Node& node)
+double Sweep::HoleAngle(const Node& node) const
 {
   /* Complex plane
    * ab = cosA +i*sinA
@@ -272,10 +324,10 @@ double Sweep::HoleAngle(Node& node)
    * Where x = ax*bx + ay*by
    *       y = ax*by - ay*bx
    */
-  double ax = node.next->point->x - node.point->x;
-  double ay = node.next->point->y - node.point->y;
-  double bx = node.prev->point->x - node.point->x;
-  double by = node.prev->point->y - node.point->y;
+  const double ax = node.next->point->x - node.point->x;
+  const double ay = node.next->point->y - node.point->y;
+  const double bx = node.prev->point->x - node.point->x;
+  const double by = node.prev->point->y - node.point->y;
   return atan2(ax * by - ay * bx, ax * bx + ay * by);
 }
 
@@ -340,43 +392,43 @@ bool Sweep::Legalize(SweepContext& tcx, Triangle& t)
   return false;
 }
 
-bool Sweep::Incircle(Point& pa, Point& pb, Point& pc, Point& pd)
+bool Sweep::Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const
 {
-  double adx = pa.x - pd.x;
-  double ady = pa.y - pd.y;
-  double bdx = pb.x - pd.x;
-  double bdy = pb.y - pd.y;
+  const double adx = pa.x - pd.x;
+  const double ady = pa.y - pd.y;
+  const double bdx = pb.x - pd.x;
+  const double bdy = pb.y - pd.y;
 
-  double adxbdy = adx * bdy;
-  double bdxady = bdx * ady;
-  double oabd = adxbdy - bdxady;
+  const double adxbdy = adx * bdy;
+  const double bdxady = bdx * ady;
+  const double oabd = adxbdy - bdxady;
 
   if (oabd <= 0)
     return false;
 
-  double cdx = pc.x - pd.x;
-  double cdy = pc.y - pd.y;
+  const double cdx = pc.x - pd.x;
+  const double cdy = pc.y - pd.y;
 
-  double cdxady = cdx * ady;
-  double adxcdy = adx * cdy;
-  double ocad = cdxady - adxcdy;
+  const double cdxady = cdx * ady;
+  const double adxcdy = adx * cdy;
+  const double ocad = cdxady - adxcdy;
 
   if (ocad <= 0)
     return false;
 
-  double bdxcdy = bdx * cdy;
-  double cdxbdy = cdx * bdy;
+  const double bdxcdy = bdx * cdy;
+  const double cdxbdy = cdx * bdy;
 
-  double alift = adx * adx + ady * ady;
-  double blift = bdx * bdx + bdy * bdy;
-  double clift = cdx * cdx + cdy * cdy;
+  const double alift = adx * adx + ady * ady;
+  const double blift = bdx * bdx + bdy * bdy;
+  const double clift = cdx * cdx + cdy * cdy;
 
-  double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;
+  const double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd;
 
   return det > 0;
 }
 
-void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op)
+void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const
 {
   Triangle* n1, *n2, *n3, *n4;
   n1 = t.NeighborCCW(p);
@@ -708,11 +760,8 @@ Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op)
   } else if (o2d == CCW) {
     // Left
     return *ot.PointCW(op);
-  } else{
-    //throw new RuntimeException("[Unsupported] Opposing point on constrained edge");
-	  // ASSIMP_CHANGE (aramis_acg)
-	  throw std::runtime_error("[Unsupported] Opposing point on constrained edge");
   }
+  throw std::runtime_error("[Unsupported] Opposing point on constrained edge");
 }
 
 void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle,
@@ -740,7 +789,7 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle&
 Sweep::~Sweep() {
 
     // Clean up memory
-    for(unsigned int i = 0; i < nodes_.size(); i++) {
+    for(size_t i = 0; i < nodes_.size(); i++) {
         delete nodes_[i];
     }
 

+ 28 - 21
contrib/poly2tri/poly2tri/sweep/sweep.h

@@ -33,7 +33,7 @@
  * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation',
  * International Journal of Geographical Information Science
  *
- * "FlipScan" Constrained Edge Algorithm invented by Thomas Åhlén, [email protected]
+ * "FlipScan" Constrained Edge Algorithm invented by Thomas ?hl?n, [email protected]
  */
 
 #ifndef SWEEP_H
@@ -49,17 +49,17 @@ struct Point;
 struct Edge;
 class Triangle;
 
-class Sweep 
+class Sweep
 {
 public:
 
   /**
    * Triangulate
-   * 
+   *
    * @param tcx
    */
   void Triangulate(SweepContext& tcx);
-  
+
   /**
    * Destructor - clean up memory
    */
@@ -69,7 +69,7 @@ private:
 
   /**
    * Start sweeping the Y-sorted point set from bottom to top
-   * 
+   *
    * @param tcx
    */
   void SweepPoints(SweepContext& tcx);
@@ -86,8 +86,8 @@ private:
   Node& PointEvent(SweepContext& tcx, Point& point);
 
    /**
-     * 
-     * 
+     *
+     *
      * @param tcx
      * @param edge
      * @param node
@@ -98,7 +98,7 @@ private:
 
   /**
    * Creates a new front triangle and legalize it
-   * 
+   *
    * @param tcx
    * @param point
    * @param node
@@ -142,7 +142,7 @@ private:
    * @param d - point opposite a
    * @return true if d is inside circle, false if on circle edge
    */
-  bool Incircle(Point& pa, Point& pb, Point& pc, Point& pd);
+  bool Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const;
 
   /**
    * Rotates a triangle pair one vertex CW
@@ -158,7 +158,7 @@ private:
    *       n4                    n4
    * </pre>
    */
-  void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op);
+  void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const;
 
   /**
    * Fills holes in the Advancing Front
@@ -169,17 +169,24 @@ private:
    */
   void FillAdvancingFront(SweepContext& tcx, Node& n);
 
+  // Decision-making about when to Fill hole.
+  // Contributed by ToolmakerSteve2
+  bool LargeHole_DontFill(const Node* node) const;
+  bool AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const;
+  bool AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const;
+  double Angle(const Point* origin, const Point* pa, const Point* pb) const;
+
   /**
    *
    * @param node - middle node
    * @return the angle between 3 front nodes
    */
-  double HoleAngle(Node& node);
+  double HoleAngle(const Node& node) const;
 
   /**
    * The basin angle is decided against the horizontal line [1,0]
    */
-  double BasinAngle(Node& node);
+  double BasinAngle(const Node& node) const;
 
   /**
    * Fills a basin that has formed on the Advancing Front to the right
@@ -228,22 +235,22 @@ private:
   /**
    * After a flip we have two triangles and know that only one will still be
    * intersecting the edge. So decide which to contiune with and legalize the other
-   * 
+   *
    * @param tcx
    * @param o - should be the result of an orient2d( eq, op, ep )
    * @param t - triangle 1
    * @param ot - triangle 2
-   * @param p - a point shared by both triangles 
+   * @param p - a point shared by both triangles
    * @param op - another point shared by both triangles
    * @return returns the triangle still intersecting the edge
    */
   Triangle& NextFlipTriangle(SweepContext& tcx, int o, Triangle&  t, Triangle& ot, Point& p, Point& op);
 
    /**
-     * When we need to traverse from one triangle to the next we need 
+     * When we need to traverse from one triangle to the next we need
      * the point in current triangle that is the opposite point to the next
-     * triangle. 
-     * 
+     * triangle.
+     *
      * @param ep
      * @param eq
      * @param ot
@@ -254,10 +261,10 @@ private:
 
    /**
      * Scan part of the FlipScan algorithm<br>
-     * When a triangle pair isn't flippable we will scan for the next 
-     * point that is inside the flip triangle scan area. When found 
+     * When a triangle pair isn't flippable we will scan for the next
+     * point that is inside the flip triangle scan area. When found
      * we generate a new flipEdgeEvent
-     * 
+     *
      * @param tcx
      * @param ep - last point on the edge we are traversing
      * @param eq - first point on the edge we are traversing
@@ -275,4 +282,4 @@ private:
 
 }
 
-#endif
+#endif

+ 31 - 22
contrib/poly2tri/poly2tri/sweep/sweep_context.cc

@@ -34,17 +34,18 @@
 
 namespace p2t {
 
-SweepContext::SweepContext(std::vector<Point*> polyline)
+SweepContext::SweepContext(const std::vector<Point*>& polyline) : points_(polyline),
+  front_(0),
+  head_(0),
+  tail_(0),
+  af_head_(0),
+  af_middle_(0),
+  af_tail_(0)
 {
-  basin = Basin();
-  edge_event = EdgeEvent();
-
-  points_ = polyline;
-
   InitEdges(points_);
 }
 
-void SweepContext::AddHole(std::vector<Point*> polyline)
+void SweepContext::AddHole(const std::vector<Point*>& polyline)
 {
   InitEdges(polyline);
   for(unsigned int i = 0; i < polyline.size(); i++) {
@@ -56,12 +57,12 @@ void SweepContext::AddPoint(Point* point) {
   points_.push_back(point);
 }
 
-std::vector<Triangle*> SweepContext::GetTriangles()
+std::vector<Triangle*> &SweepContext::GetTriangles()
 {
   return triangles_;
 }
 
-std::list<Triangle*> SweepContext::GetMap()
+std::list<Triangle*> &SweepContext::GetMap()
 {
   return map_;
 }
@@ -94,16 +95,16 @@ void SweepContext::InitTriangulation()
 
 }
 
-void SweepContext::InitEdges(std::vector<Point*> polyline)
+void SweepContext::InitEdges(const std::vector<Point*>& polyline)
 {
-  int num_points = static_cast<int>(polyline.size());
-  for (int i = 0; i < num_points; i++) {
-    int j = i < num_points - 1 ? i + 1 : 0;
+  size_t num_points = polyline.size();
+  for (size_t i = 0; i < num_points; i++) {
+    size_t j = i < num_points - 1 ? i + 1 : 0;
     edge_list.push_back(new Edge(*polyline[i], *polyline[j]));
   }
 }
 
-Point* SweepContext::GetPoint(const int& index)
+Point* SweepContext::GetPoint(size_t index)
 {
   return points_[index];
 }
@@ -113,13 +114,13 @@ void SweepContext::AddToMap(Triangle* triangle)
   map_.push_back(triangle);
 }
 
-Node& SweepContext::LocateNode(Point& point)
+Node& SweepContext::LocateNode(const Point& point)
 {
   // TODO implement search tree
   return *front_->LocateNode(point.x);
 }
 
-void SweepContext::CreateAdvancingFront(std::vector<Node*> nodes)
+void SweepContext::CreateAdvancingFront(const std::vector<Node*>& nodes)
 {
 
   (void) nodes;
@@ -164,12 +165,20 @@ void SweepContext::RemoveFromMap(Triangle* triangle)
 
 void SweepContext::MeshClean(Triangle& triangle)
 {
-  if (!triangle.IsInterior()) {
-    triangle.IsInterior(true);
-    triangles_.push_back(&triangle);
-    for (int i = 0; i < 3; i++) {
-      if (!triangle.constrained_edge[i])
-        MeshClean(*triangle.GetNeighbor(i));
+  std::vector<Triangle *> triangles;
+  triangles.push_back(&triangle);
+
+  while(!triangles.empty()){
+	Triangle *t = triangles.back();
+	triangles.pop_back();
+
+    if (t != NULL && !t->IsInterior()) {
+      t->IsInterior(true);
+      triangles_.push_back(t);
+      for (int i = 0; i < 3; i++) {
+        if (!t->constrained_edge[i])
+          triangles.push_back(t->GetNeighbor(i));
+      }
     }
   }
 }

+ 17 - 17
contrib/poly2tri/poly2tri/sweep/sweep_context.h

@@ -52,47 +52,47 @@ class SweepContext {
 public:
 
 /// Constructor
-SweepContext(std::vector<Point*> polyline);
+SweepContext(const std::vector<Point*>& polyline);
 /// Destructor
 ~SweepContext();
 
 void set_head(Point* p1);
 
-Point* head();
+Point* head() const;
 
 void set_tail(Point* p1);
 
-Point* tail();
+Point* tail() const;
 
-int point_count();
+size_t point_count() const;
 
-Node& LocateNode(Point& point);
+Node& LocateNode(const Point& point);
 
 void RemoveNode(Node* node);
 
-void CreateAdvancingFront(std::vector<Node*> nodes);
+void CreateAdvancingFront(const std::vector<Node*>& nodes);
 
 /// Try to map a node to all sides of this triangle that don't have a neighbor
 void MapTriangleToNodes(Triangle& t);
 
 void AddToMap(Triangle* triangle);
 
-Point* GetPoint(const int& index);
+Point* GetPoint(size_t index);
 
 Point* GetPoints();
 
 void RemoveFromMap(Triangle* triangle);
 
-void AddHole(std::vector<Point*> polyline);
+void AddHole(const std::vector<Point*>& polyline);
 
 void AddPoint(Point* point);
 
-AdvancingFront* front();
+AdvancingFront* front() const;
 
 void MeshClean(Triangle& triangle);
 
-std::vector<Triangle*> GetTriangles();
-std::list<Triangle*> GetMap();
+std::vector<Triangle*> &GetTriangles();
+std::list<Triangle*> &GetMap();
 
 std::vector<Edge*> edge_list;
 
@@ -147,18 +147,18 @@ Point* tail_;
 Node *af_head_, *af_middle_, *af_tail_;
 
 void InitTriangulation();
-void InitEdges(std::vector<Point*> polyline);
+void InitEdges(const std::vector<Point*>& polyline);
 
 };
 
-inline AdvancingFront* SweepContext::front()
+inline AdvancingFront* SweepContext::front() const
 {
   return front_;
 }
 
-inline int SweepContext::point_count()
+inline size_t SweepContext::point_count() const
 {
-  return static_cast<int>(points_.size());
+  return points_.size();
 }
 
 inline void SweepContext::set_head(Point* p1)
@@ -166,7 +166,7 @@ inline void SweepContext::set_head(Point* p1)
   head_ = p1;
 }
 
-inline Point* SweepContext::head()
+inline Point* SweepContext::head() const
 {
   return head_;
 }
@@ -176,7 +176,7 @@ inline void SweepContext::set_tail(Point* p1)
   tail_ = p1;
 }
 
-inline Point* SweepContext::tail()
+inline Point* SweepContext::tail() const
 {
   return tail_;
 }

+ 12 - 0
contrib/utf8cpp/doc/ReleaseNotes

@@ -0,0 +1,12 @@
+utf8 cpp library
+Release 2.3.4
+
+A minor bug fix release. Thanks to all who reported bugs. 
+
+Note: Version 2.3.3 contained a regression, and therefore was removed.
+
+Changes from version 2.3.2
+- Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';'
+- Bug fix [36]: replace_invalid() only works with back_inserter
+
+Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes

+ 1789 - 0
contrib/utf8cpp/doc/utf8cpp.html

@@ -0,0 +1,1789 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <meta name="generator" content=
+    "HTML Tidy for Linux/x86 (vers 1st November 2002), see www.w3.org">
+    <meta name="description" content=
+    "A simple, portable and lightweigt C++ library for easy handling of UTF-8 encoded strings">
+    <meta name="keywords" content="UTF-8 C++ portable utf8 unicode generic templates">
+    <meta name="author" content="Nemanja Trifunovic">
+    <title>
+      UTF8-CPP: UTF-8 with C++ in a Portable Way
+    </title>
+    <style type="text/css">
+    <!--
+    span.return_value {
+      color: brown;
+    }
+    span.keyword {
+      color: blue;
+    }
+    span.preprocessor {
+      color: navy;
+    }
+    span.literal {
+      color: olive;
+    }
+    span.comment {
+      color: green;
+    }
+    code {
+      font-weight: bold; 
+    }
+    ul.toc {
+      list-style-type: none;
+    }
+    p.version {
+      font-size: small;
+      font-style: italic;
+    }
+    -->
+        </style>
+  </head>
+  <body>
+    <h1>
+      UTF8-CPP: UTF-8 with C++ in a Portable Way
+    </h1>
+    <p>
+      <a href="https://sourceforge.net/projects/utfcpp">The Sourceforge project page</a>
+    </p>
+    <div id="toc">
+      <h2>
+        Table of Contents
+      </h2>
+      <ul class="toc">
+        <li>
+          <a href="#introduction">Introduction</a>
+        </li>
+        <li>
+          <a href="#examples">Examples of Use</a>
+          <ul class="toc">
+            <li>
+              <a href=#introsample>Introductionary Sample </a>
+            </li>
+            <li>
+              <a href=#validfile>Checking if a file contains valid UTF-8 text</a>
+            </li>
+            <li>
+              <a href=#fixinvalid>Ensure that a string contains valid UTF-8 text</a>
+            </li>
+          </ul>
+        <li>
+          <a href="#reference">Reference</a>
+          <ul class="toc">
+            <li>
+              <a href="#funutf8">Functions From utf8 Namespace </a>
+            </li>
+            <li>
+              <a href="#typesutf8">Types From utf8 Namespace </a>
+            </li>
+            <li>
+              <a href="#fununchecked">Functions From utf8::unchecked Namespace </a>
+            </li>
+            <li>
+              <a href="#typesunchecked">Types From utf8::unchecked Namespace </a>
+            </li>
+          </ul>
+        </li>
+        <li>
+          <a href="#points">Points of Interest</a>
+        </li>
+        <li>
+          <a href="#links">Links</a>
+        </li>
+      </ul>
+    </div>
+    <h2 id="introduction">
+      Introduction
+    </h2>
+    <p>
+      Many C++ developers miss an easy and portable way of handling Unicode encoded
+      strings. The original C++ Standard (known as C++98 or C++03) is Unicode agnostic.
+      C++11 provides some support for Unicode on core language and library level:
+      u8, u, and U character and string literals, char16_t and char32_t character types,
+      u16string and u32string library classes, and codecvt support for conversions 
+      between Unicode encoding forms.
+      In the meantime, developers use third party libraries like ICU, OS specific capabilities, or simply
+      roll out their own solutions.
+    </p>
+    <p>
+      In order to easily handle UTF-8 encoded Unicode strings, I came up with a small
+      generic library. For anybody used to work with STL algorithms and iterators, it should be
+      easy and natural to use. The code is freely available for any purpose - check out
+      the license at the beginning of the utf8.h file. If you run into
+      bugs or performance issues, please let me know and I'll do my best to address them.
+    </p>
+    <p>
+      The purpose of this article is not to offer an introduction to Unicode in general,
+      and UTF-8 in particular. If you are not familiar with Unicode, be sure to check out
+      <a href="http://www.unicode.org/">Unicode Home Page</a> or some other source of
+      information for Unicode. Also, it is not my aim to advocate the use of UTF-8
+      encoded strings in C++ programs; if you want to handle UTF-8 encoded strings from
+      C++, I am sure you have good reasons for it.
+    </p>
+    <h2 id="examples">
+      Examples of use
+    </h2>
+    <h3 id="introsample">
+      Introductionary Sample
+    </h3>
+    <p>
+      To illustrate the use of the library, let's start with a small but complete program 
+      that opens a file containing UTF-8 encoded text, reads it line by line, checks each line
+      for invalid UTF-8 byte sequences, and converts it to UTF-16 encoding and back to UTF-8:
+    </p>
+<pre>
+<span class="preprocessor">#include &lt;fstream&gt;</span>
+<span class="preprocessor">#include &lt;iostream&gt;</span>
+<span class="preprocessor">#include &lt;string&gt;</span>
+<span class="preprocessor">#include &lt;vector&gt;</span>
+<span class="preprocessor">#include "utf8.h"</span>
+<span class="keyword">using namespace</span> std;
+<span class="keyword">int</span> main(<span class="keyword">int</span> argc, <span class="keyword">char</span>** argv)
+{
+    <span class="keyword">if</span> (argc != <span class="literal">2</span>) {
+        cout &lt;&lt; <span class="literal">"\nUsage: docsample filename\n"</span>;
+        <span class="keyword">return</span> <span class="literal">0</span>;
+    }
+
+    <span class="keyword">const char</span>* test_file_path = argv[1];
+    <span class="comment">// Open the test file (contains UTF-8 encoded text)</span>
+    ifstream fs8(test_file_path);
+    <span class="keyword">if</span> (!fs8.is_open()) {
+    cout &lt;&lt; <span class=
+"literal">"Could not open "</span> &lt;&lt; test_file_path &lt;&lt; endl;
+    <span class="keyword">return</span> <span class="literal">0</span>;
+    }
+
+    <span class="keyword">unsigned</span> line_count = <span class="literal">1</span>;
+    string line;
+    <span class="comment">// Play with all the lines in the file</span>
+    <span class="keyword">while</span> (getline(fs8, line)) {
+       <span class="comment">// check for invalid utf-8 (for a simple yes/no check, there is also utf8::is_valid function)</span>
+        string::iterator end_it = utf8::find_invalid(line.begin(), line.end());
+        <span class="keyword">if</span> (end_it != line.end()) {
+            cout &lt;&lt; <span class=
+"literal">"Invalid UTF-8 encoding detected at line "</span> &lt;&lt; line_count &lt;&lt; <span
+ class="literal">"\n"</span>;
+            cout &lt;&lt; <span class=
+"literal">"This part is fine: "</span> &lt;&lt; string(line.begin(), end_it) &lt;&lt; <span
+ class="literal">"\n"</span>;
+        }
+
+        <span class="comment">// Get the line length (at least for the valid part)</span>
+        <span class="keyword">int</span> length = utf8::distance(line.begin(), end_it);
+        cout &lt;&lt; <span class=
+"literal">"Length of line "</span> &lt;&lt; line_count &lt;&lt; <span class=
+"literal">" is "</span> &lt;&lt; length &lt;&lt;  <span class="literal">"\n"</span>;
+
+        <span class="comment">// Convert it to utf-16</span>
+        vector&lt;unsigned short&gt; utf16line;
+        utf8::utf8to16(line.begin(), end_it, back_inserter(utf16line));
+
+        <span class="comment">// And back to utf-8</span>
+        string utf8line; 
+        utf8::utf16to8(utf16line.begin(), utf16line.end(), back_inserter(utf8line));
+
+        <span class="comment">// Confirm that the conversion went OK:</span>
+        <span class="keyword">if</span> (utf8line != string(line.begin(), end_it))
+            cout &lt;&lt; <span class=
+"literal">"Error in UTF-16 conversion at line: "</span> &lt;&lt; line_count &lt;&lt; <span
+ class="literal">"\n"</span>;        
+
+        line_count++;
+    }
+    <span class="keyword">return</span> <span class="literal">0</span>;
+}
+</pre>
+    <p>
+      In the previous code sample, for each line we performed
+      a detection of invalid UTF-8 sequences with <code>find_invalid</code>; the number
+      of characters (more precisely - the number of Unicode code points, including the end
+      of line and even BOM if there is one) in each line was
+      determined with a use of <code>utf8::distance</code>; finally, we have converted
+      each line to UTF-16 encoding with <code>utf8to16</code> and back to UTF-8 with
+      <code>utf16to8</code>.
+    </p>
+    <h3 id="validfile">Checking if a file contains valid UTF-8 text</h3>
+<p>
+Here is a function that checks whether the content of a file is valid UTF-8 encoded text without
+reading the content into the memory:
+</p>
+<pre>    
+<span class="keyword">bool</span> valid_utf8_file(i<span class="keyword">const char</span>* file_name)
+{
+    ifstream ifs(file_name);
+    <span class="keyword">if</span> (!ifs)
+        <span class="keyword">return false</span>; <span class="comment">// even better, throw here</span>
+
+    istreambuf_iterator&lt;<span class="keyword">char</span>&gt; it(ifs.rdbuf());
+    istreambuf_iterator&lt;<span class="keyword">char</span>&gt; eos;
+
+    <span class="keyword">return</span> utf8::is_valid(it, eos);
+}
+</pre>
+<p>
+Because the function <code>utf8::is_valid()</code> works with input iterators, we were able
+to pass an <code>istreambuf_iterator</code> to it and read the content of the file directly 
+without loading it to the memory first.</p>
+<p>
+Note that other functions that take input iterator arguments can be used in a similar way. For
+instance, to read the content of a UTF-8 encoded text file and convert the text to UTF-16, just 
+do something like:
+</p>
+<pre>
+    utf8::utf8to16(it, eos, back_inserter(u16string));
+</pre>
+    <h3 id="fixinvalid">Ensure that a string contains valid UTF-8 text</h3>
+<p>
+If we have some text that "probably" contains UTF-8 encoded text and we want to
+replace any invalid UTF-8 sequence with a replacement character, something like 
+the following function may be used:
+</p>
+<pre>
+<span class="keyword">void</span> fix_utf8_string(std::string&amp; str)
+{
+    std::string temp;
+    utf8::replace_invalid(str.begin(), str.end(), back_inserter(temp));
+    str = temp;
+}
+</pre>
+<p>The function will replace any invalid UTF-8 sequence with a Unicode replacement character. 
+There is an overloaded function that enables the caller to supply their own replacement character.
+</p>
+    <h2 id="reference">
+      Reference
+    </h2>
+    <h3 id="funutf8">
+      Functions From utf8 Namespace
+    </h3>
+    <h4>
+      utf8::append
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence
+      to a UTF-8 string.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt;
+octet_iterator append(uint32_t cp, octet_iterator result);
+   
+</pre>
+    <p>
+	  <code>octet_iterator</code>: an output iterator.<br>
+      <code>cp</code>: a 32 bit integer representing a code point to append to the
+      sequence.<br>
+       <code>result</code>: an output iterator to the place in the sequence where to
+      append the code point.<br>
+       <span class="return_value">Return value</span>: an iterator pointing to the place
+      after the newly appended sequence.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">unsigned char</span> u[<span class="literal">5</span>] = {<span
+class="literal">0</span>,<span class="literal">0</span>,<span class=
+"literal">0</span>,<span class="literal">0</span>,<span class="literal">0</span>};
+<span class="keyword">unsigned char</span>* end = append(<span class=
+"literal">0x0448</span>, u);
+assert (u[<span class="literal">0</span>] == <span class=
+"literal">0xd1</span> &amp;&amp; u[<span class="literal">1</span>] == <span class=
+"literal">0x88</span> &amp;&amp; u[<span class="literal">2</span>] == <span class=
+"literal">0</span> &amp;&amp; u[<span class="literal">3</span>] == <span class=
+"literal">0</span> &amp;&amp; u[<span class="literal">4</span>] == <span class=
+"literal">0</span>);
+</pre>
+    <p>
+      Note that <code>append</code> does not allocate any memory - it is the burden of
+      the caller to make sure there is enough memory allocated for the operation. To make
+      things more interesting, <code>append</code> can add anywhere between 1 and 4
+      octets to the sequence. In practice, you would most often want to use
+      <code>std::back_inserter</code> to ensure that the necessary memory is allocated.
+    </p>
+    <p>
+      In case of an invalid code point, a <code>utf8::invalid_code_point</code> exception
+      is thrown.
+    </p>
+    <h4>
+      utf8::next
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Given the iterator to the beginning of the UTF-8 sequence, it returns the code
+      point and moves the iterator to the next position.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+uint32_t next(octet_iterator&amp; it, octet_iterator end);
+   
+</pre>
+    <p>
+	  <code>octet_iterator</code>: an input iterator.<br>
+      <code>it</code>: a reference to an iterator pointing to the beginning of an UTF-8
+      encoded code point. After the function returns, it is incremented to point to the
+      beginning of the next code point.<br>
+       <code>end</code>: end of the UTF-8 sequence to be processed. If <code>it</code>
+      gets equal to <code>end</code> during the extraction of a code point, an
+      <code>utf8::not_enough_room</code> exception is thrown.<br>
+       <span class="return_value">Return value</span>: the 32 bit representation of the
+      processed UTF-8 code point.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">char</span>* w = twochars;
+<span class="keyword">int</span> cp = next(w, twochars + <span class="literal">6</span>);
+assert (cp == <span class="literal">0x65e5</span>);
+assert (w == twochars + <span class="literal">3</span>);
+</pre>
+    <p>
+      This function is typically used to iterate through a UTF-8 encoded string.
+    </p>
+    <p>
+      In case of an invalid UTF-8 seqence, a <code>utf8::invalid_utf8</code> exception is
+      thrown.
+    </p>
+    <h4>
+      utf8::peek_next
+    </h4>
+    <p class="version">
+    Available in version 2.1 and later.
+    </p>
+    <p>
+      Given the iterator to the beginning of the UTF-8 sequence, it returns the code
+      point for the following sequence without changing the value of the iterator. 
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+uint32_t peek_next(octet_iterator it, octet_iterator end);
+   
+</pre>
+    <p>
+	  <code>octet_iterator</code>: an input iterator.<br>
+      <code>it</code>: an iterator pointing to the beginning of an UTF-8
+      encoded code point.<br>
+       <code>end</code>: end of the UTF-8 sequence to be processed. If <code>it</code>
+      gets equal to <code>end</code> during the extraction of a code point, an
+      <code>utf8::not_enough_room</code> exception is thrown.<br>
+       <span class="return_value">Return value</span>: the 32 bit representation of the
+      processed UTF-8 code point.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">char</span>* w = twochars;
+<span class="keyword">int</span> cp = peek_next(w, twochars + <span class="literal">6</span>);
+assert (cp == <span class="literal">0x65e5</span>);
+assert (w == twochars);
+</pre>
+    <p>
+      In case of an invalid UTF-8 seqence, a <code>utf8::invalid_utf8</code> exception is
+      thrown.
+    </p>
+    <h4>
+      utf8::prior
+    </h4>
+    <p class="version">
+    Available in version 1.02 and later.
+    </p>
+    <p>
+      Given a reference to an iterator pointing to an octet in a UTF-8 sequence, it
+      decreases the iterator until it hits the beginning of the previous UTF-8 encoded
+      code point and returns the 32 bits representation of the code point.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+uint32_t prior(octet_iterator&amp; it, octet_iterator start);
+   
+</pre>
+    <p>
+	  <code>octet_iterator</code>: a bidirectional iterator.<br>
+      <code>it</code>: a reference pointing to an octet within a UTF-8 encoded string.
+      After the function returns, it is decremented to point to the beginning of the
+      previous code point.<br>
+       <code>start</code>: an iterator to the beginning of the sequence where the search
+      for the beginning of a code point is performed. It is a
+      safety measure to prevent passing the beginning of the string in the search for a
+      UTF-8 lead octet.<br>
+       <span class="return_value">Return value</span>: the 32 bit representation of the
+      previous code point.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">unsigned char</span>* w = twochars + <span class=
+"literal">3</span>;
+<span class="keyword">int</span> cp = prior (w, twochars);
+assert (cp == <span class="literal">0x65e5</span>);
+assert (w == twochars);
+</pre>
+    <p> 
+      This function has two purposes: one is two iterate backwards through a UTF-8
+      encoded string. Note that it is usually a better idea to iterate forward instead,
+      since <code>utf8::next</code> is faster. The second purpose is to find a beginning
+      of a UTF-8 sequence if we have a random position within a string. Note that in that
+      case <code>utf8::prior</code> may not detect an invalid UTF-8 sequence in some scenarios:
+      for instance if there are superfluous trail octets, it will just skip them.
+    </p> 
+    <p>
+      <code>it</code> will typically point to the beginning of
+      a code point, and <code>start</code> will point to the
+      beginning of the string to ensure we don't go backwards too far. <code>it</code> is
+      decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence
+      beginning with that octet is decoded to a 32 bit representation and returned.
+    </p>
+    <p>
+      In case <code>start</code> is reached before a UTF-8 lead octet is hit, or if an
+      invalid UTF-8 sequence is started by the lead octet, an <code>invalid_utf8</code>
+      exception is thrown.
+    </p>
+    <p>In case <code>start</code> equals <code>it</code>, a <code>not_enough_room</code>
+      exception is thrown.
+    <h4>
+      utf8::previous
+    </h4>
+    <p class="version">
+    Deprecated in version 1.02 and later.
+    </p>
+    <p>
+      Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it
+      decreases the iterator until it hits the beginning of the previous UTF-8 encoded
+      code point and returns the 32 bits representation of the code point.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+uint32_t previous(octet_iterator&amp; it, octet_iterator pass_start);
+   
+</pre>
+    <p>
+	  <code>octet_iterator</code>: a random access iterator.<br>
+      <code>it</code>: a reference pointing to an octet within a UTF-8 encoded string.
+      After the function returns, it is decremented to point to the beginning of the
+      previous code point.<br>
+       <code>pass_start</code>: an iterator to the point in the sequence where the search
+      for the beginning of a code point is aborted if no result was reached. It is a
+      safety measure to prevent passing the beginning of the string in the search for a
+      UTF-8 lead octet.<br>
+       <span class="return_value">Return value</span>: the 32 bit representation of the
+      previous code point.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">unsigned char</span>* w = twochars + <span class=
+"literal">3</span>;
+<span class="keyword">int</span> cp = previous (w, twochars - <span class=
+"literal">1</span>);
+assert (cp == <span class="literal">0x65e5</span>);
+assert (w == twochars);
+</pre>
+    <p>
+      <code>utf8::previous</code> is deprecated, and <code>utf8::prior</code> should
+      be used instead, although the existing code can continue using this function.
+      The problem is the parameter <code>pass_start</code> that points to the position
+      just before the beginning of the sequence. Standard containers don't have the 
+      concept of "pass start" and the function can not be used with their iterators.
+    </p>
+    <p>
+      <code>it</code> will typically point to the beginning of
+      a code point, and <code>pass_start</code> will point to the octet just before the
+      beginning of the string to ensure we don't go backwards too far. <code>it</code> is
+      decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence
+      beginning with that octet is decoded to a 32 bit representation and returned.
+    </p>
+    <p>
+      In case <code>pass_start</code> is reached before a UTF-8 lead octet is hit, or if an
+      invalid UTF-8 sequence is started by the lead octet, an <code>invalid_utf8</code>
+      exception is thrown
+    </p>
+    <h4>
+      utf8::advance
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Advances an iterator by the specified number of code points within an UTF-8
+      sequence.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator, typename distance_type&gt; 
+<span class=
+"keyword">void</span> advance (octet_iterator&amp; it, distance_type n, octet_iterator end);
+   
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>distance_type</code>: an integral type convertible to <code>octet_iterator</code>'s difference type.<br>
+      <code>it</code>: a reference to an iterator pointing to the beginning of an UTF-8
+      encoded code point. After the function returns, it is incremented to point to the
+      nth following code point.<br>
+       <code>n</code>: a positive integer that shows how many code points we want to
+      advance.<br>
+       <code>end</code>: end of the UTF-8 sequence to be processed. If <code>it</code>
+      gets equal to <code>end</code> during the extraction of a code point, an
+      <code>utf8::not_enough_room</code> exception is thrown.<br>
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">unsigned char</span>* w = twochars;
+advance (w, <span class="literal">2</span>, twochars + <span class="literal">6</span>);
+assert (w == twochars + <span class="literal">5</span>);
+</pre>
+    <p>
+      This function works only "forward". In case of a negative <code>n</code>, there is
+      no effect.
+    </p>
+    <p>
+      In case of an invalid code point, a <code>utf8::invalid_code_point</code> exception
+      is thrown.
+    </p>
+    <h4>
+      utf8::distance
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Given the iterators to two UTF-8 encoded code points in a seqence, returns the
+      number of code points between them.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+<span class=
+"keyword">typename</span> std::iterator_traits&lt;octet_iterator&gt;::difference_type distance (octet_iterator first, octet_iterator last);
+   
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>first</code>: an iterator to a beginning of a UTF-8 encoded code point.<br>
+      <code>last</code>: an iterator to a "post-end" of the last UTF-8 encoded code
+      point in the sequence we are trying to determine the length. It can be the
+      beginning of a new code point, or not.<br>
+       <span class="return_value">Return value</span> the distance between the iterators,
+      in code points.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+size_t dist = utf8::distance(twochars, twochars + <span class="literal">5</span>);
+assert (dist == <span class="literal">2</span>);
+</pre>
+    <p>
+      This function is used to find the length (in code points) of a UTF-8 encoded
+      string. The reason it is called <em>distance</em>, rather than, say,
+      <em>length</em> is mainly because developers are used that <em>length</em> is an
+      O(1) function. Computing the length of an UTF-8 string is a linear operation, and
+      it looked better to model it after <code>std::distance</code> algorithm.
+    </p>
+    <p>
+      In case of an invalid UTF-8 seqence, a <code>utf8::invalid_utf8</code> exception is
+      thrown. If <code>last</code> does not point to the past-of-end of a UTF-8 seqence,
+      a <code>utf8::not_enough_room</code> exception is thrown.
+    </p>
+    <h4>
+      utf8::utf16to8
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Converts a UTF-16 encoded string to UTF-8.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> u16bit_iterator, <span class=
+"keyword">typename</span> octet_iterator&gt;
+octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
+   
+</pre>
+    <p>
+      <code>u16bit_iterator</code>: an input iterator.<br>
+      <code>octet_iterator</code>: an output iterator.<br>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-16 encoded
+      string to convert.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-16 encoded
+      string to convert.<br>
+       <code>result</code>: an output iterator to the place in the UTF-8 string where to
+      append the result of conversion.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the appended UTF-8 string.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">unsigned short</span> utf16string[] = {<span class=
+"literal">0x41</span>, <span class="literal">0x0448</span>, <span class=
+"literal">0x65e5</span>, <span class="literal">0xd834</span>, <span class=
+"literal">0xdd1e</span>};
+vector&lt;<span class="keyword">unsigned char</span>&gt; utf8result;
+utf16to8(utf16string, utf16string + <span class=
+"literal">5</span>, back_inserter(utf8result));
+assert (utf8result.size() == <span class="literal">10</span>);    
+</pre>
+    <p>
+      In case of invalid UTF-16 sequence, a <code>utf8::invalid_utf16</code> exception is
+      thrown.
+    </p>
+    <h4>
+      utf8::utf8to16
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Converts an UTF-8 encoded string to UTF-16
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> u16bit_iterator, typename octet_iterator&gt;
+u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
+   
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>u16bit_iterator</code>: an output iterator.<br>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-8 encoded
+      string to convert. &lt; br /&gt; <code>end</code>: an iterator pointing to
+      pass-the-end of the UTF-8 encoded string to convert.<br>
+       <code>result</code>: an output iterator to the place in the UTF-16 string where to
+      append the result of conversion.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the appended UTF-16 string.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span> utf8_with_surrogates[] = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e"</span>;
+vector &lt;<span class="keyword">unsigned short</span>&gt; utf16result;
+utf8to16(utf8_with_surrogates, utf8_with_surrogates + <span class=
+"literal">9</span>, back_inserter(utf16result));
+assert (utf16result.size() == <span class="literal">4</span>);
+assert (utf16result[<span class="literal">2</span>] == <span class=
+"literal">0xd834</span>);
+assert (utf16result[<span class="literal">3</span>] == <span class=
+"literal">0xdd1e</span>);
+</pre>
+    <p>
+      In case of an invalid UTF-8 seqence, a <code>utf8::invalid_utf8</code> exception is
+      thrown. If <code>end</code> does not point to the past-of-end of a UTF-8 seqence, a
+      <code>utf8::not_enough_room</code> exception is thrown.
+    </p>
+    <h4>
+      utf8::utf32to8
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Converts a UTF-32 encoded string to UTF-8.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator, typename u32bit_iterator&gt;
+octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
+   
+</pre>
+    <p>
+      <code>octet_iterator</code>: an output iterator.<br>
+      <code>u32bit_iterator</code>: an input iterator.<br>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-32 encoded
+      string to convert.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-32 encoded
+      string to convert.<br>
+       <code>result</code>: an output iterator to the place in the UTF-8 string where to
+      append the result of conversion.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the appended UTF-8 string.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">int</span> utf32string[] = {<span class=
+"literal">0x448</span>, <span class="literal">0x65E5</span>, <span class=
+"literal">0x10346</span>, <span class="literal">0</span>};
+vector&lt;<span class="keyword">unsigned char</span>&gt; utf8result;
+utf32to8(utf32string, utf32string + <span class=
+"literal">3</span>, back_inserter(utf8result));
+assert (utf8result.size() == <span class="literal">9</span>);
+</pre>
+    <p>
+      In case of invalid UTF-32 string, a <code>utf8::invalid_code_point</code> exception
+      is thrown.
+    </p>
+    <h4>
+      utf8::utf8to32
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Converts a UTF-8 encoded string to UTF-32.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator, <span class=
+"keyword">typename</span> u32bit_iterator&gt;
+u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
+   
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>u32bit_iterator</code>: an output iterator.<br>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-8 encoded
+      string to convert.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-8 encoded string
+      to convert.<br>
+       <code>result</code>: an output iterator to the place in the UTF-32 string where to
+      append the result of conversion.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the appended UTF-32 string.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+vector&lt;<span class="keyword">int</span>&gt; utf32result;
+utf8to32(twochars, twochars + <span class=
+"literal">5</span>, back_inserter(utf32result));
+assert (utf32result.size() == <span class="literal">2</span>);
+</pre>
+    <p>
+      In case of an invalid UTF-8 seqence, a <code>utf8::invalid_utf8</code> exception is
+      thrown. If <code>end</code> does not point to the past-of-end of a UTF-8 seqence, a
+      <code>utf8::not_enough_room</code> exception is thrown.
+    </p>
+    <h4>
+      utf8::find_invalid
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Detects an invalid sequence within a UTF-8 string.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+octet_iterator find_invalid(octet_iterator start, octet_iterator end);
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-8 string to
+      test for validity.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-8 string to test
+      for validity.<br>
+       <span class="return_value">Return value</span>: an iterator pointing to the first
+      invalid octet in the UTF-8 string. In case none were found, equals
+      <code>end</code>.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span> utf_invalid[] = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88\xfa"</span>;
+<span class=
+"keyword">char</span>* invalid = find_invalid(utf_invalid, utf_invalid + <span class=
+"literal">6</span>);
+assert (invalid == utf_invalid + <span class="literal">5</span>);
+</pre>
+    <p>
+      This function is typically used to make sure a UTF-8 string is valid before
+      processing it with other functions. It is especially important to call it if before
+      doing any of the <em>unchecked</em> operations on it.
+    </p>
+    <h4>
+      utf8::is_valid
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Checks whether a sequence of octets is a valid UTF-8 string.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+<span class="keyword">bool</span> is_valid(octet_iterator start, octet_iterator end);
+   
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-8 string to
+      test for validity.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-8 string to test
+      for validity.<br>
+       <span class="return_value">Return value</span>: <code>true</code> if the sequence
+      is a valid UTF-8 string; <code>false</code> if not.
+    </p>
+    Example of use: 
+<pre>
+<span class="keyword">char</span> utf_invalid[] = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88\xfa"</span>;
+<span class="keyword">bool</span> bvalid = is_valid(utf_invalid, utf_invalid + <span
+class="literal">6</span>);
+assert (bvalid == false);
+</pre>
+    <p>
+      <code>is_valid</code> is a shorthand for <code>find_invalid(start, end) ==
+      end;</code>. You may want to use it to make sure that a byte seqence is a valid
+      UTF-8 string without the need to know where it fails if it is not valid.
+    </p>
+    <h4>
+      utf8::replace_invalid
+    </h4>
+    <p class="version">
+    Available in version 2.0 and later.
+    </p>
+    <p>
+      Replaces all invalid UTF-8 sequences within a string with a replacement marker.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator, <span class=
+"keyword">typename</span> output_iterator&gt;
+output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement);
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator, <span class=
+"keyword">typename</span> output_iterator&gt;
+output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out);
+   
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>output_iterator</code>: an output iterator.<br>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-8 string to
+      look for invalid UTF-8 sequences.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-8 string to look
+      for invalid UTF-8 sequences.<br>
+       <code>out</code>: An output iterator to the range where the result of replacement
+      is stored.<br>
+       <code>replacement</code>: A Unicode code point for the replacement marker. The
+      version without this parameter assumes the value <code>0xfffd</code><br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the UTF-8 string with replaced invalid sequences.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span> invalid_sequence[] = <span class=
+"literal">"a\x80\xe0\xa0\xc0\xaf\xed\xa0\x80z"</span>;
+vector&lt;<span class="keyword">char</span>&gt; replace_invalid_result;
+replace_invalid (invalid_sequence, invalid_sequence + sizeof(invalid_sequence), back_inserter(replace_invalid_result), <span
+ class="literal">'?'</span>);
+bvalid = is_valid(replace_invalid_result.begin(), replace_invalid_result.end());
+assert (bvalid);
+<span class="keyword">char</span>* fixed_invalid_sequence = <span class=
+"literal">"a????z"</span>;
+assert (std::equal(replace_invalid_result.begin(), replace_invalid_result.end(), fixed_invalid_sequence));
+</pre>
+    <p>
+      <code>replace_invalid</code> does not perform in-place replacement of invalid
+      sequences. Rather, it produces a copy of the original string with the invalid
+      sequences replaced with a replacement marker. Therefore, <code>out</code> must not
+      be in the <code>[start, end]</code> range.
+    </p>
+    <p>
+      If <code>end</code> does not point to the past-of-end of a UTF-8 sequence, a
+      <code>utf8::not_enough_room</code> exception is thrown.
+    </p>
+    <h4>
+      utf8::starts_with_bom
+    </h4>
+    <p class="version">
+    Available in version 2.3 and later. Relaces deprecated <code>is_bom()</code> function.
+    </p>
+    <p>
+      Checks whether an octet sequence starts with a UTF-8 byte order mark (BOM)
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+<span class="keyword">bool</span> starts_with_bom (octet_iterator it, octet_iterator end);
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>it</code>: beginning of the octet sequence to check<br>
+      <code>end</code>: pass-end of the sequence to check<br>
+       <span class="return_value">Return value</span>: <code>true</code> if the sequence
+      starts with a UTF-8 byte order mark; <code>false</code> if not.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">unsigned char</span> byte_order_mark[] = {<span class=
+"literal">0xef</span>, <span class="literal">0xbb</span>, <span class=
+"literal">0xbf</span>};
+<span class="keyword">bool</span> bbom = starts_with_bom(byte_order_mark, byte_order_mark + <span class="keyword">sizeof</span>(byte_order_mark));
+assert (bbom == <span class="literal">true</span>);
+</pre>
+    <p>
+      The typical use of this function is to check the first three bytes of a file. If
+      they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8
+      encoded text.
+    </p>
+    <h4>
+      utf8::is_bom
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later. Deprecated in version 2.3. <code>starts_with_bom()</code> should be used
+    instead.
+    </p>
+    <p>
+      Checks whether a sequence of three octets is a UTF-8 byte order mark (BOM)
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt; 
+<span class="keyword">bool</span> is_bom (octet_iterator it); <span class="comment"> // Deprecated</span>
+</pre>
+    <p>
+      <code>octet_iterator</code>: an input iterator.<br>
+      <code>it</code>: beginning of the 3-octet sequence to check<br>
+       <span class="return_value">Return value</span>: <code>true</code> if the sequence
+      is UTF-8 byte order mark; <code>false</code> if not.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">unsigned char</span> byte_order_mark[] = {<span class=
+"literal">0xef</span>, <span class="literal">0xbb</span>, <span class=
+"literal">0xbf</span>};
+<span class="keyword">bool</span> bbom = is_bom(byte_order_mark);
+assert (bbom == <span class="literal">true</span>);
+</pre>
+    <p>
+      The typical use of this function is to check the first three bytes of a file. If
+      they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8
+      encoded text.
+    </p>
+    <p>
+      If a sequence is 
+      shorter than three bytes, an invalid iterator will be dereferenced. Therefore, this function is deprecated
+      in favor of <code>starts_with_bom()</code>that takes the end of sequence as an argument.
+    </p>
+    <h3 id="typesutf8">
+      Types From utf8 Namespace
+    </h3>
+    <h4>utf8::exception
+    </h4>
+    <p class="version">
+    Available in version 2.3 and later.
+    </p>
+    <p>
+    Base class for the exceptions thrown by UTF CPP library functions.
+    </p>
+<pre>
+<span class="keyword">class</span> exception : <span class="keyword">public</span> std::exception {};
+</pre>
+    <p>
+    Example of use:
+    </p>
+<pre>
+<span class="keyword">try</span> {
+  code_that_uses_utf_cpp_library();
+}
+<span class="keyword">catch</span>(<span class="keyword">const</span> utf8::exception&amp; utfcpp_ex) {
+  cerr &lt;&lt; utfcpp_ex.what();
+}
+</pre>
+    
+    <h4>utf8::invalid_code_point
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+    Thrown by UTF8 CPP functions such as <code>advance</code> and <code>next</code> if an UTF-8 sequence represents and invalid code point.
+    </p>
+
+<pre>
+<span class="keyword">class</span> invalid_code_point : <span class="keyword">public</span> exception {
+<span class="keyword">public</span>: 
+    uint32_t code_point() <span class="keyword">const</span>;
+};
+
+</pre>
+    <p>
+    Member function <code>code_point()</code> can be used to determine the invalid code point that
+    caused the exception to be thrown.
+    </p>
+    <h4>utf8::invalid_utf8
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+    Thrown by UTF8 CPP functions such as <code>next</code> and <code>prior</code> if an invalid UTF-8 sequence
+    is detected during decoding.
+    </p>
+
+<pre>
+<span class="keyword">class</span> invalid_utf8 : <span class="keyword">public</span> exception {
+<span class="keyword">public</span>: 
+    uint8_t utf8_octet() <span class="keyword">const</span>;
+};
+</pre>
+
+    <p>
+    Member function <code>utf8_octet()</code> can be used to determine the beginning of the byte 
+    sequence that caused the exception to be thrown.
+    </p>
+</pre>
+    <h4>utf8::invalid_utf16
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+    Thrown by UTF8 CPP function <code>utf16to8</code> if an invalid UTF-16 sequence
+    is detected during decoding.
+    </p>
+
+<pre>
+<span class="keyword">class</span> invalid_utf16 : <span class="keyword">public</span> exception {
+<span class="keyword">public</span>: 
+    uint16_t utf16_word() <span class="keyword">const</span>;
+};
+</pre>
+
+    <p>
+    Member function <code>utf16_word()</code> can be used to determine the UTF-16 code unit 
+    that caused the exception to be thrown.
+    </p>
+    <h4>utf8::not_enough_room
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+    Thrown by UTF8 CPP functions such as <code>next</code> if the end of the decoded UTF-8 sequence
+    was reached before the code point was decoded.
+    </p>
+
+<pre>
+<span class="keyword">class</span> not_enough_room : <span class="keyword">public</span> exception {};
+</pre>
+    <h4>
+      utf8::iterator
+    </h4>
+    <p class="version">
+    Available in version 2.0 and later.
+    </p>
+    <p>
+      Adapts the underlying octet iterator to iterate over the sequence of code points,
+      rather than raw octets.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class="keyword">typename</span> octet_iterator&gt;
+<span class="keyword">class</span> iterator;
+</pre>
+    
+    <h5>Member functions</h5>
+      <dl>
+      <dt><code>iterator();</code> <dd> the deafult constructor; the underlying <code>octet_iterator</code> is
+      constructed with its default constructor.
+      <dt><code><span class="keyword">explicit</span> iterator (const octet_iterator&amp; octet_it, 
+                         const octet_iterator&amp; range_start,
+                         const octet_iterator&amp; range_end);</code> <dd> a constructor 
+      that initializes the underlying <code>octet_iterator</code> with <code>octet_it</code>
+      and sets the range in which the iterator is considered valid.
+      <dt><code>octet_iterator base () <span class="keyword">const</span>;</code> <dd> returns the 
+      underlying <code>octet_iterator</code>.
+      <dt><code>uint32_t operator * () <span class="keyword">const</span>;</code> <dd> decodes the utf-8 sequence
+      the underlying <code>octet_iterator</code> is pointing to and returns the code point.
+      <dt><code><span class="keyword">bool operator</span> == (const iterator&amp; rhs)
+      <span class="keyword">const</span>;</code> <dd> returns <span class="keyword">true</span>
+      if the two underlaying iterators are equal.
+      <dt><code><span class="keyword">bool operator</span> != (const iterator&amp; rhs)
+      <span class="keyword">const</span>;</code> <dd> returns <span class="keyword">true</span>
+      if the two underlaying iterators are not equal.
+      <dt><code>iterator&amp; <span class="keyword">operator</span> ++ (); </code> <dd> the prefix increment - moves
+      the iterator to the next UTF-8 encoded code point.
+      <dt><code>iterator <span class="keyword">operator</span> ++ (<span class="keyword">int</span>); </code> <dd>
+      the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one.
+      <dt><code>iterator&amp; <span class="keyword">operator</span> -- (); </code> <dd> the prefix decrement - moves
+      the iterator to the previous UTF-8 encoded code point.
+      <dt><code>iterator <span class="keyword">operator</span> -- (<span class="keyword">int</span>); </code> <dd>
+      the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one.
+      </dl>
+      <p>
+      Example of use:
+      </p>
+<pre>
+<span class="keyword">char</span>* threechars = <span class="literal">"\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88"</span>;
+utf8::iterator&lt;<span class="keyword">char</span>*&gt; it(threechars, threechars, threechars + <span class="literal">9</span>);
+utf8::iterator&lt;<span class="keyword">char</span>*&gt; it2 = it;
+assert (it2 == it);
+assert (*it == <span class="literal">0x10346</span>);
+assert (*(++it) == <span class="literal">0x65e5</span>);
+assert ((*it++) == <span class="literal">0x65e5</span>);
+assert (*it == <span class="literal">0x0448</span>);
+assert (it != it2);
+utf8::iterator&lt;<span class="keyword">char</span>*&gt; endit (threechars + <span class="literal">9</span>, threechars, threechars + <span class="literal">9</span>);  
+assert (++it == endit);
+assert (*(--it) == <span class="literal">0x0448</span>);
+assert ((*it--) == <span class="literal">0x0448</span>);
+assert (*it == <span class="literal">0x65e5</span>);
+assert (--it == utf8::iterator&lt;<span class="keyword">char</span>*&gt;(threechars, threechars, threechars + <span class="literal">9</span>));
+assert (*it == <span class="literal">0x10346</span>);
+</pre>
+      <p>
+      The purpose of <code>utf8::iterator</code> adapter is to enable easy iteration as well as the use of STL
+      algorithms with UTF-8 encoded strings. Increment and decrement operators are implemented in terms of 
+      <code>utf8::next()</code> and <code>utf8::prior()</code> functions. 
+      </p>
+      <p>
+      Note that <code>utf8::iterator</code> adapter is a checked iterator. It operates on the range specified in
+      the constructor; any attempt to go out of that range will result in an exception. Even the comparison operators
+      require both iterator object to be constructed against the same range - otherwise an exception is thrown. Typically,
+      the range will be determined by sequence container functions <code>begin</code> and <code>end</code>, i.e.:
+      </p>
+<pre>
+std::string s = <span class="literal">"example"</span>;
+utf8::iterator i (s.begin(), s.begin(), s.end());
+</pre>
+    <h3 id="fununchecked">
+      Functions From utf8::unchecked Namespace
+    </h3>
+    <h4>
+      utf8::unchecked::append
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence
+      to a UTF-8 string.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt;
+octet_iterator append(uint32_t cp, octet_iterator result);
+   
+</pre>
+    <p>
+      <code>cp</code>: A 32 bit integer representing a code point to append to the
+      sequence.<br>
+       <code>result</code>: An output iterator to the place in the sequence where to
+      append the code point.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the newly appended sequence.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">unsigned char</span> u[<span class="literal">5</span>] = {<span
+class="literal">0</span>,<span class="literal">0</span>,<span class=
+"literal">0</span>,<span class="literal">0</span>,<span class="literal">0</span>};
+<span class="keyword">unsigned char</span>* end = unchecked::append(<span class=
+"literal">0x0448</span>, u);
+assert (u[<span class="literal">0</span>] == <span class=
+"literal">0xd1</span> &amp;&amp; u[<span class="literal">1</span>] == <span class=
+"literal">0x88</span> &amp;&amp; u[<span class="literal">2</span>] == <span class=
+"literal">0</span> &amp;&amp; u[<span class="literal">3</span>] == <span class=
+"literal">0</span> &amp;&amp; u[<span class="literal">4</span>] == <span class=
+"literal">0</span>);
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::append</code>. It does not
+      check for validity of the supplied code point, and may produce an invalid UTF-8
+      sequence.
+    </p>
+    <h4>
+      utf8::unchecked::next
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Given the iterator to the beginning of a UTF-8 sequence, it returns the code point
+      and moves the iterator to the next position.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt;
+uint32_t next(octet_iterator&amp; it);
+   
+</pre>
+    <p>
+      <code>it</code>: a reference to an iterator pointing to the beginning of an UTF-8
+      encoded code point. After the function returns, it is incremented to point to the
+      beginning of the next code point.<br>
+       <span class="return_value">Return value</span>: the 32 bit representation of the
+      processed UTF-8 code point.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">char</span>* w = twochars;
+<span class="keyword">int</span> cp = unchecked::next(w);
+assert (cp == <span class="literal">0x65e5</span>);
+assert (w == twochars + <span class="literal">3</span>);
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::next</code>. It does not
+      check for validity of the supplied UTF-8 sequence.
+    </p>
+    <h4>
+      utf8::unchecked::peek_next
+    </h4>
+    <p class="version">
+    Available in version 2.1 and later.
+    </p>
+    <p>
+      Given the iterator to the beginning of a UTF-8 sequence, it returns the code point.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt;
+uint32_t peek_next(octet_iterator it);
+   
+</pre>
+    <p>
+      <code>it</code>: an iterator pointing to the beginning of an UTF-8
+      encoded code point.<br>
+       <span class="return_value">Return value</span>: the 32 bit representation of the
+      processed UTF-8 code point.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">char</span>* w = twochars;
+<span class="keyword">int</span> cp = unchecked::peek_next(w);
+assert (cp == <span class="literal">0x65e5</span>);
+assert (w == twochars);
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::peek_next</code>. It does not
+      check for validity of the supplied UTF-8 sequence.
+    </p>
+    <h4>
+      utf8::unchecked::prior
+    </h4>
+    <p class="version">
+    Available in version 1.02 and later.
+    </p>
+    <p>
+      Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it
+      decreases the iterator until it hits the beginning of the previous UTF-8 encoded
+      code point and returns the 32 bits representation of the code point.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt;
+uint32_t prior(octet_iterator&amp; it);
+   
+</pre>
+    <p>
+      <code>it</code>: a reference pointing to an octet within a UTF-8 encoded string.
+      After the function returns, it is decremented to point to the beginning of the
+      previous code point.<br>
+       <span class="return_value">Return value</span>: the 32 bit representation of the
+      previous code point.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">char</span>* w = twochars + <span class="literal">3</span>;
+<span class="keyword">int</span> cp = unchecked::prior (w);
+assert (cp == <span class="literal">0x65e5</span>);
+assert (w == twochars);
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::prior</code>. It does not
+      check for validity of the supplied UTF-8 sequence and offers no boundary checking.
+    </p>
+    <h4>
+      utf8::unchecked::previous (deprecated, see utf8::unchecked::prior)
+    </h4>
+    <p class="version">
+    Deprecated in version 1.02 and later.
+    </p>
+    <p>
+      Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it
+      decreases the iterator until it hits the beginning of the previous UTF-8 encoded
+      code point and returns the 32 bits representation of the code point.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt;
+uint32_t previous(octet_iterator&amp; it);
+   
+</pre>
+    <p>
+      <code>it</code>: a reference pointing to an octet within a UTF-8 encoded string.
+      After the function returns, it is decremented to point to the beginning of the
+      previous code point.<br>
+       <span class="return_value">Return value</span>: the 32 bit representation of the
+      previous code point.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">char</span>* w = twochars + <span class="literal">3</span>;
+<span class="keyword">int</span> cp = unchecked::previous (w);
+assert (cp == <span class="literal">0x65e5</span>);
+assert (w == twochars);
+</pre>
+    <p>
+     The reason this function is deprecated is just the consistency with the "checked"
+     versions, where <code>prior</code> should be used instead of <code>previous</code>.
+     In fact, <code>unchecked::previous</code> behaves exactly the same as <code>
+     unchecked::prior</code>
+    </p>
+    <p>
+      This is a faster but less safe version of <code>utf8::previous</code>. It does not
+      check for validity of the supplied UTF-8 sequence and offers no boundary checking.
+    </p>
+    <h4>
+      utf8::unchecked::advance
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Advances an iterator by the specified number of code points within an UTF-8
+      sequence.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator, typename distance_type&gt;
+<span class="keyword">void</span> advance (octet_iterator&amp; it, distance_type n);
+   
+</pre>
+    <p>
+      <code>it</code>: a reference to an iterator pointing to the beginning of an UTF-8
+      encoded code point. After the function returns, it is incremented to point to the
+      nth following code point.<br>
+       <code>n</code>: a positive integer that shows how many code points we want to
+      advance.<br>
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+<span class="keyword">char</span>* w = twochars;
+unchecked::advance (w, <span class="literal">2</span>);
+assert (w == twochars + <span class="literal">5</span>);
+</pre>
+    <p>
+      This function works only "forward". In case of a negative <code>n</code>, there is
+      no effect.
+    </p>
+    <p>
+      This is a faster but less safe version of <code>utf8::advance</code>. It does not
+      check for validity of the supplied UTF-8 sequence and offers no boundary checking.
+    </p>
+    <h4>
+      utf8::unchecked::distance
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Given the iterators to two UTF-8 encoded code points in a seqence, returns the
+      number of code points between them.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator&gt;
+<span class=
+"keyword">typename</span> std::iterator_traits&lt;octet_iterator&gt;::difference_type distance (octet_iterator first, octet_iterator last);
+</pre>
+    <p>
+      <code>first</code>: an iterator to a beginning of a UTF-8 encoded code point.<br>
+       <code>last</code>: an iterator to a "post-end" of the last UTF-8 encoded code
+      point in the sequence we are trying to determine the length. It can be the
+      beginning of a new code point, or not.<br>
+       <span class="return_value">Return value</span> the distance between the iterators,
+      in code points.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+size_t dist = utf8::unchecked::distance(twochars, twochars + <span class=
+"literal">5</span>);
+assert (dist == <span class="literal">2</span>);
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::distance</code>. It does not
+      check for validity of the supplied UTF-8 sequence.
+    </p>
+    <h4>
+      utf8::unchecked::utf16to8
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Converts a UTF-16 encoded string to UTF-8.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> u16bit_iterator, <span class=
+"keyword">typename</span> octet_iterator&gt;
+octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
+   
+</pre>
+    <p>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-16 encoded
+      string to convert.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-16 encoded
+      string to convert.<br>
+       <code>result</code>: an output iterator to the place in the UTF-8 string where to
+      append the result of conversion.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the appended UTF-8 string.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">unsigned short</span> utf16string[] = {<span class=
+"literal">0x41</span>, <span class="literal">0x0448</span>, <span class=
+"literal">0x65e5</span>, <span class="literal">0xd834</span>, <span class=
+"literal">0xdd1e</span>};
+vector&lt;<span class="keyword">unsigned char</span>&gt; utf8result;
+unchecked::utf16to8(utf16string, utf16string + <span class=
+"literal">5</span>, back_inserter(utf8result));
+assert (utf8result.size() == <span class="literal">10</span>);    
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::utf16to8</code>. It does not
+      check for validity of the supplied UTF-16 sequence.
+    </p>
+    <h4>
+      utf8::unchecked::utf8to16
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Converts an UTF-8 encoded string to UTF-16
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> u16bit_iterator, typename octet_iterator&gt;
+u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
+   
+</pre>
+    <p>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-8 encoded
+      string to convert. &lt; br /&gt; <code>end</code>: an iterator pointing to
+      pass-the-end of the UTF-8 encoded string to convert.<br>
+       <code>result</code>: an output iterator to the place in the UTF-16 string where to
+      append the result of conversion.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the appended UTF-16 string.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span> utf8_with_surrogates[] = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e"</span>;
+vector &lt;<span class="keyword">unsigned short</span>&gt; utf16result;
+unchecked::utf8to16(utf8_with_surrogates, utf8_with_surrogates + <span class=
+"literal">9</span>, back_inserter(utf16result));
+assert (utf16result.size() == <span class="literal">4</span>);
+assert (utf16result[<span class="literal">2</span>] == <span class=
+"literal">0xd834</span>);
+assert (utf16result[<span class="literal">3</span>] == <span class=
+"literal">0xdd1e</span>);
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::utf8to16</code>. It does not
+      check for validity of the supplied UTF-8 sequence.
+    </p>
+    <h4>
+      utf8::unchecked::utf32to8
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Converts a UTF-32 encoded string to UTF-8.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator, <span class=
+"keyword">typename</span> u32bit_iterator&gt;
+octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
+   
+</pre>
+    <p>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-32 encoded
+      string to convert.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-32 encoded
+      string to convert.<br>
+       <code>result</code>: an output iterator to the place in the UTF-8 string where to
+      append the result of conversion.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the appended UTF-8 string.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">int</span> utf32string[] = {<span class=
+"literal">0x448</span>, <span class="literal">0x65e5</span>, <span class=
+"literal">0x10346</span>, <span class="literal">0</span>};
+vector&lt;<span class="keyword">unsigned char</span>&gt; utf8result;
+utf32to8(utf32string, utf32string + <span class=
+"literal">3</span>, back_inserter(utf8result));
+assert (utf8result.size() == <span class="literal">9</span>);
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::utf32to8</code>. It does not
+      check for validity of the supplied UTF-32 sequence.
+    </p>
+    <h4>
+      utf8::unchecked::utf8to32
+    </h4>
+    <p class="version">
+    Available in version 1.0 and later.
+    </p>
+    <p>
+      Converts a UTF-8 encoded string to UTF-32.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class=
+"keyword">typename</span> octet_iterator, typename u32bit_iterator&gt;
+u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
+   
+</pre>
+    <p>
+      <code>start</code>: an iterator pointing to the beginning of the UTF-8 encoded
+      string to convert.<br>
+       <code>end</code>: an iterator pointing to pass-the-end of the UTF-8 encoded string
+      to convert.<br>
+       <code>result</code>: an output iterator to the place in the UTF-32 string where to
+      append the result of conversion.<br>
+       <span class="return_value">Return value</span>: An iterator pointing to the place
+      after the appended UTF-32 string.
+    </p>
+    <p>
+      Example of use:
+    </p>
+<pre>
+<span class="keyword">char</span>* twochars = <span class=
+"literal">"\xe6\x97\xa5\xd1\x88"</span>;
+vector&lt;<span class="keyword">int</span>&gt; utf32result;
+unchecked::utf8to32(twochars, twochars + <span class=
+"literal">5</span>, back_inserter(utf32result));
+assert (utf32result.size() == <span class="literal">2</span>);
+</pre>
+    <p>
+      This is a faster but less safe version of <code>utf8::utf8to32</code>. It does not
+      check for validity of the supplied UTF-8 sequence.
+    </p>
+    <h3 id="typesunchecked">
+      Types From utf8::unchecked Namespace
+    </h3>
+    <h4>
+      utf8::iterator
+    </h4>
+    <p class="version">
+    Available in version 2.0 and later.
+    </p>
+    <p>
+      Adapts the underlying octet iterator to iterate over the sequence of code points,
+      rather than raw octets.
+    </p>
+<pre>
+<span class="keyword">template</span> &lt;<span class="keyword">typename</span> octet_iterator&gt;
+<span class="keyword">class</span> iterator;
+</pre>
+    
+    <h5>Member functions</h5>
+      <dl>
+      <dt><code>iterator();</code> <dd> the deafult constructor; the underlying <code>octet_iterator</code> is
+      constructed with its default constructor.
+      <dt><code><span class="keyword">explicit</span> iterator (const octet_iterator&amp; octet_it); 
+                         </code> <dd> a constructor 
+      that initializes the underlying <code>octet_iterator</code> with <code>octet_it</code>
+      <dt><code>octet_iterator base () <span class="keyword">const</span>;</code> <dd> returns the 
+      underlying <code>octet_iterator</code>.
+      <dt><code>uint32_t operator * () <span class="keyword">const</span>;</code> <dd> decodes the utf-8 sequence
+      the underlying <code>octet_iterator</code> is pointing to and returns the code point.
+      <dt><code><span class="keyword">bool operator</span> == (const iterator&amp; rhs)
+      <span class="keyword">const</span>;</code> <dd> returns <span class="keyword">true</span>
+      if the two underlaying iterators are equal.
+      <dt><code><span class="keyword">bool operator</span> != (const iterator&amp; rhs)
+      <span class="keyword">const</span>;</code> <dd> returns <span class="keyword">true</span>
+      if the two underlaying iterators are not equal.
+      <dt><code>iterator&amp; <span class="keyword">operator</span> ++ (); </code> <dd> the prefix increment - moves
+      the iterator to the next UTF-8 encoded code point.
+      <dt><code>iterator <span class="keyword">operator</span> ++ (<span class="keyword">int</span>); </code> <dd>
+      the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one.
+      <dt><code>iterator&amp; <span class="keyword">operator</span> -- (); </code> <dd> the prefix decrement - moves
+      the iterator to the previous UTF-8 encoded code point.
+      <dt><code>iterator <span class="keyword">operator</span> -- (<span class="keyword">int</span>); </code> <dd>
+      the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one.
+      </dl>
+      <p>
+      Example of use:
+      </p>
+<pre>
+<span class="keyword">char</span>* threechars = <span class="literal">"\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88"</span>;
+utf8::unchecked::iterator&lt;<span class="keyword">char</span>*&gt; un_it(threechars);
+utf8::unchecked::iterator&lt;<span class="keyword">char</span>*&gt; un_it2 = un_it;
+assert (un_it2 == un_it);
+assert (*un_it == <span class="literal">0x10346</span>);
+assert (*(++un_it) == <span class="literal">0x65e5</span>);
+assert ((*un_it++) == <span class="literal">0x65e5</span>);
+assert (*un_it == <span class="literal">0x0448</span>);
+assert (un_it != un_it2);
+utf8::::unchecked::iterator&lt;<span class="keyword">char</span>*&gt; un_endit (threechars + <span class="literal">9</span>);  
+assert (++un_it == un_endit);
+assert (*(--un_it) == <span class="literal">0x0448</span>);
+assert ((*un_it--) == <span class="literal">0x0448</span>);
+assert (*un_it == <span class="literal">0x65e5</span>);
+assert (--un_it == utf8::unchecked::iterator&lt;<span class="keyword">char</span>*&gt;(threechars));
+assert (*un_it == <span class="literal">0x10346</span>);
+</pre>
+      <p>
+      This is an unchecked version of <code>utf8::iterator</code>. It is faster in many cases, but offers
+      no validity or range checks.
+      </p>
+    <h2 id="points">
+      Points of interest
+    </h2>
+    <h4>
+      Design goals and decisions
+    </h4>
+    <p>
+      The library was designed to be:
+    </p>
+    <ol>
+      <li>
+        Generic: for better or worse, there are many C++ string classes out there, and
+        the library should work with as many of them as possible.
+      </li>
+      <li>
+        Portable: the library should be portable both accross different platforms and
+        compilers. The only non-portable code is a small section that declares unsigned
+        integers of different sizes: three typedefs. They can be changed by the users of
+        the library if they don't match their platform. The default setting should work
+        for Windows (both 32 and 64 bit), and most 32 bit and 64 bit Unix derivatives.
+      </li>
+      <li>
+        Lightweight: follow the "pay only for what you use" guideline.
+      </li>
+      <li>
+        Unintrusive: avoid forcing any particular design or even programming style on the
+        user. This is a library, not a framework.
+      </li>
+    </ol>
+    <h4>
+      Alternatives
+    </h4>
+    <p>
+      In case you want to look into other means of working with UTF-8 strings from C++,
+      here is the list of solutions I am aware of:
+    </p>
+    <ol>
+      <li>
+        <a href="http://icu.sourceforge.net/">ICU Library</a>. It is very powerful,
+        complete, feature-rich, mature, and widely used. Also big, intrusive,
+        non-generic, and doesn't play well with the Standard Library. I definitelly
+        recommend looking at ICU even if you don't plan to use it.
+      </li>
+      <li>
+        C++11 language and library features. Still far from complete, and not widely
+        supported by compiler vendors. 
+      </li>
+      <li>
+        <a href=
+        "http://www.gtkmm.org/gtkmm2/docs/tutorial/html/ch03s04.html">Glib::ustring</a>.
+        A class specifically made to work with UTF-8 strings, and also feel like
+        <code>std::string</code>. If you prefer to have yet another string class in your
+        code, it may be worth a look. Be aware of the licensing issues, though.
+      </li>
+      <li>
+        Platform dependent solutions: Windows and POSIX have functions to convert strings
+        from one encoding to another. That is only a subset of what my library offers,
+        but if that is all you need it may be good enough.
+      </li>
+    </ol>
+    <h2 id="links">
+      Links
+    </h2>
+    <ol>
+      <li>
+        <a href="http://www.unicode.org/">The Unicode Consortium</a>.
+      </li>
+      <li>
+        <a href="http://icu.sourceforge.net/">ICU Library</a>.
+      </li>
+      <li>
+        <a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8 at Wikipedia</a>
+      </li>
+      <li>
+        <a href="http://www.cl.cam.ac.uk/~mgk25/unicode.html">UTF-8 and Unicode FAQ for
+        Unix/Linux</a>
+      </li>
+    </ol>
+  </body>
+</html>

+ 34 - 0
contrib/utf8cpp/source/utf8.h

@@ -0,0 +1,34 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "utf8/checked.h"
+#include "utf8/unchecked.h"
+
+#endif // header guard

+ 327 - 0
contrib/utf8cpp/source/utf8/checked.h

@@ -0,0 +1,327 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+#include <stdexcept>
+
+namespace utf8
+{
+    // Base for the exceptions that may be thrown from the library
+    class exception : public ::std::exception {
+    };
+
+    // Exceptions that may be thrown from the library functions.
+    class invalid_code_point : public exception {
+        uint32_t cp;
+    public:
+        invalid_code_point(uint32_t cp) : cp(cp) {}
+        virtual const char* what() const throw() { return "Invalid code point"; }
+        uint32_t code_point() const {return cp;}
+    };
+
+    class invalid_utf8 : public exception {
+        uint8_t u8;
+    public:
+        invalid_utf8 (uint8_t u) : u8(u) {}
+        virtual const char* what() const throw() { return "Invalid UTF-8"; }
+        uint8_t utf8_octet() const {return u8;}
+    };
+
+    class invalid_utf16 : public exception {
+        uint16_t u16;
+    public:
+        invalid_utf16 (uint16_t u) : u16(u) {}
+        virtual const char* what() const throw() { return "Invalid UTF-16"; }
+        uint16_t utf16_word() const {return u16;}
+    };
+
+    class not_enough_room : public exception {
+    public:
+        virtual const char* what() const throw() { return "Not enough space"; }
+    };
+
+    /// The library API - functions intended to be called by the users
+
+    template <typename octet_iterator>
+    octet_iterator append(uint32_t cp, octet_iterator result)
+    {
+        if (!utf8::internal::is_code_point_valid(cp))
+            throw invalid_code_point(cp);
+
+        if (cp < 0x80)                        // one octet
+            *(result++) = static_cast<uint8_t>(cp);
+        else if (cp < 0x800) {                // two octets
+            *(result++) = static_cast<uint8_t>((cp >> 6)            | 0xc0);
+            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
+        }
+        else if (cp < 0x10000) {              // three octets
+            *(result++) = static_cast<uint8_t>((cp >> 12)           | 0xe0);
+            *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80);
+            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
+        }
+        else {                                // four octets
+            *(result++) = static_cast<uint8_t>((cp >> 18)           | 0xf0);
+            *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)  | 0x80);
+            *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f)   | 0x80);
+            *(result++) = static_cast<uint8_t>((cp & 0x3f)          | 0x80);
+        }
+        return result;
+    }
+
+    template <typename octet_iterator, typename output_iterator>
+    output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
+    {
+        while (start != end) {
+            octet_iterator sequence_start = start;
+            internal::utf_error err_code = utf8::internal::validate_next(start, end);
+            switch (err_code) {
+                case internal::UTF8_OK :
+                    for (octet_iterator it = sequence_start; it != start; ++it)
+                        *out++ = *it;
+                    break;
+                case internal::NOT_ENOUGH_ROOM:
+                    throw not_enough_room();
+                case internal::INVALID_LEAD:
+                    out = utf8::append (replacement, out);
+                    ++start;
+                    break;
+                case internal::INCOMPLETE_SEQUENCE:
+                case internal::OVERLONG_SEQUENCE:
+                case internal::INVALID_CODE_POINT:
+                    out = utf8::append (replacement, out);
+                    ++start;
+                    // just one replacement mark for the sequence
+                    while (start != end && utf8::internal::is_trail(*start))
+                        ++start;
+                    break;
+            }
+        }
+        return out;
+    }
+
+    template <typename octet_iterator, typename output_iterator>
+    inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
+    {
+        static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
+        return utf8::replace_invalid(start, end, out, replacement_marker);
+    }
+
+    template <typename octet_iterator>
+    uint32_t next(octet_iterator& it, octet_iterator end)
+    {
+        uint32_t cp = 0;
+        internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
+        switch (err_code) {
+            case internal::UTF8_OK :
+                break;
+            case internal::NOT_ENOUGH_ROOM :
+                throw not_enough_room();
+            case internal::INVALID_LEAD :
+            case internal::INCOMPLETE_SEQUENCE :
+            case internal::OVERLONG_SEQUENCE :
+                throw invalid_utf8(*it);
+            case internal::INVALID_CODE_POINT :
+                throw invalid_code_point(cp);
+        }
+        return cp;
+    }
+
+    template <typename octet_iterator>
+    uint32_t peek_next(octet_iterator it, octet_iterator end)
+    {
+        return utf8::next(it, end);
+    }
+
+    template <typename octet_iterator>
+    uint32_t prior(octet_iterator& it, octet_iterator start)
+    {
+        // can't do much if it == start
+        if (it == start)
+            throw not_enough_room();
+
+        octet_iterator end = it;
+        // Go back until we hit either a lead octet or start
+        while (utf8::internal::is_trail(*(--it)))
+            if (it == start)
+                throw invalid_utf8(*it); // error - no lead byte in the sequence
+        return utf8::peek_next(it, end);
+    }
+
+    /// Deprecated in versions that include "prior"
+    template <typename octet_iterator>
+    uint32_t previous(octet_iterator& it, octet_iterator pass_start)
+    {
+        octet_iterator end = it;
+        while (utf8::internal::is_trail(*(--it)))
+            if (it == pass_start)
+                throw invalid_utf8(*it); // error - no lead byte in the sequence
+        octet_iterator temp = it;
+        return utf8::next(temp, end);
+    }
+
+    template <typename octet_iterator, typename distance_type>
+    void advance (octet_iterator& it, distance_type n, octet_iterator end)
+    {
+        for (distance_type i = 0; i < n; ++i)
+            utf8::next(it, end);
+    }
+
+    template <typename octet_iterator>
+    typename std::iterator_traits<octet_iterator>::difference_type
+    distance (octet_iterator first, octet_iterator last)
+    {
+        typename std::iterator_traits<octet_iterator>::difference_type dist;
+        for (dist = 0; first < last; ++dist)
+            utf8::next(first, last);
+        return dist;
+    }
+
+    template <typename u16bit_iterator, typename octet_iterator>
+    octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
+    {
+        while (start != end) {
+            uint32_t cp = utf8::internal::mask16(*start++);
+            // Take care of surrogate pairs first
+            if (utf8::internal::is_lead_surrogate(cp)) {
+                if (start != end) {
+                    uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+                    if (utf8::internal::is_trail_surrogate(trail_surrogate))
+                        cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+                    else
+                        throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
+                }
+                else
+                    throw invalid_utf16(static_cast<uint16_t>(cp));
+
+            }
+            // Lone trail surrogate
+            else if (utf8::internal::is_trail_surrogate(cp))
+                throw invalid_utf16(static_cast<uint16_t>(cp));
+
+            result = utf8::append(cp, result);
+        }
+        return result;
+    }
+
+    template <typename u16bit_iterator, typename octet_iterator>
+    u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+    {
+        while (start != end) {
+            uint32_t cp = utf8::next(start, end);
+            if (cp > 0xffff) { //make a surrogate pair
+                *result++ = static_cast<uint16_t>((cp >> 10)   + internal::LEAD_OFFSET);
+                *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+            }
+            else
+                *result++ = static_cast<uint16_t>(cp);
+        }
+        return result;
+    }
+
+    template <typename octet_iterator, typename u32bit_iterator>
+    octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+    {
+        while (start != end)
+            result = utf8::append(*(start++), result);
+
+        return result;
+    }
+
+    template <typename octet_iterator, typename u32bit_iterator>
+    u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+    {
+        while (start != end)
+            (*result++) = utf8::next(start, end);
+
+        return result;
+    }
+
+    // The iterator class
+    template <typename octet_iterator>
+    class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
+      octet_iterator it;
+      octet_iterator range_start;
+      octet_iterator range_end;
+      public:
+      iterator () {}
+      explicit iterator (const octet_iterator& octet_it,
+                         const octet_iterator& range_start,
+                         const octet_iterator& range_end) :
+               it(octet_it), range_start(range_start), range_end(range_end)
+      {
+          if (it < range_start || it > range_end)
+              throw std::out_of_range("Invalid utf-8 iterator position");
+      }
+      // the default "big three" are OK
+      octet_iterator base () const { return it; }
+      uint32_t operator * () const
+      {
+          octet_iterator temp = it;
+          return utf8::next(temp, range_end);
+      }
+      bool operator == (const iterator& rhs) const
+      {
+          if (range_start != rhs.range_start || range_end != rhs.range_end)
+              throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
+          return (it == rhs.it);
+      }
+      bool operator != (const iterator& rhs) const
+      {
+          return !(operator == (rhs));
+      }
+      iterator& operator ++ ()
+      {
+          utf8::next(it, range_end);
+          return *this;
+      }
+      iterator operator ++ (int)
+      {
+          iterator temp = *this;
+          utf8::next(it, range_end);
+          return temp;
+      }
+      iterator& operator -- ()
+      {
+          utf8::prior(it, range_start);
+          return *this;
+      }
+      iterator operator -- (int)
+      {
+          iterator temp = *this;
+          utf8::prior(it, range_start);
+          return temp;
+      }
+    }; // class iterator
+
+} // namespace utf8
+
+#endif //header guard
+
+

+ 329 - 0
contrib/utf8cpp/source/utf8/core.h

@@ -0,0 +1,329 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include <iterator>
+
+namespace utf8
+{
+    // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
+    // You may need to change them to match your system.
+    // These typedefs have the same names as ones from cstdint, or boost/cstdint
+    typedef unsigned char   uint8_t;
+    typedef unsigned short  uint16_t;
+    typedef unsigned int    uint32_t;
+
+// Helper code - not intended to be directly called by the library users. May be changed at any time
+namespace internal
+{
+    // Unicode constants
+    // Leading (high) surrogates: 0xd800 - 0xdbff
+    // Trailing (low) surrogates: 0xdc00 - 0xdfff
+    const uint16_t LEAD_SURROGATE_MIN  = 0xd800u;
+    const uint16_t LEAD_SURROGATE_MAX  = 0xdbffu;
+    const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
+    const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
+    const uint16_t LEAD_OFFSET         = LEAD_SURROGATE_MIN - (0x10000 >> 10);
+    const uint32_t SURROGATE_OFFSET    = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
+
+    // Maximum valid value for a Unicode code point
+    const uint32_t CODE_POINT_MAX      = 0x0010ffffu;
+
+    template<typename octet_type>
+    inline uint8_t mask8(octet_type oc)
+    {
+        return static_cast<uint8_t>(0xff & oc);
+    }
+    template<typename u16_type>
+    inline uint16_t mask16(u16_type oc)
+    {
+        return static_cast<uint16_t>(0xffff & oc);
+    }
+    template<typename octet_type>
+    inline bool is_trail(octet_type oc)
+    {
+        return ((utf8::internal::mask8(oc) >> 6) == 0x2);
+    }
+
+    template <typename u16>
+    inline bool is_lead_surrogate(u16 cp)
+    {
+        return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
+    }
+
+    template <typename u16>
+    inline bool is_trail_surrogate(u16 cp)
+    {
+        return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+    }
+
+    template <typename u16>
+    inline bool is_surrogate(u16 cp)
+    {
+        return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+    }
+
+    template <typename u32>
+    inline bool is_code_point_valid(u32 cp)
+    {
+        return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
+    }
+
+    template <typename octet_iterator>
+    inline typename std::iterator_traits<octet_iterator>::difference_type
+    sequence_length(octet_iterator lead_it)
+    {
+        uint8_t lead = utf8::internal::mask8(*lead_it);
+        if (lead < 0x80)
+            return 1;
+        else if ((lead >> 5) == 0x6)
+            return 2;
+        else if ((lead >> 4) == 0xe)
+            return 3;
+        else if ((lead >> 3) == 0x1e)
+            return 4;
+        else
+            return 0;
+    }
+
+    template <typename octet_difference_type>
+    inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
+    {
+        if (cp < 0x80) {
+            if (length != 1) 
+                return true;
+        }
+        else if (cp < 0x800) {
+            if (length != 2) 
+                return true;
+        }
+        else if (cp < 0x10000) {
+            if (length != 3) 
+                return true;
+        }
+
+        return false;
+    }
+
+    enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
+
+    /// Helper for get_sequence_x
+    template <typename octet_iterator>
+    utf_error increase_safely(octet_iterator& it, octet_iterator end)
+    {
+        if (++it == end)
+            return NOT_ENOUGH_ROOM;
+
+        if (!utf8::internal::is_trail(*it))
+            return INCOMPLETE_SEQUENCE;
+        
+        return UTF8_OK;
+    }
+
+    #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}    
+
+    /// get_sequence_x functions decode utf-8 sequences of the length x
+    template <typename octet_iterator>
+    utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        if (it == end)
+            return NOT_ENOUGH_ROOM;
+
+        code_point = utf8::internal::mask8(*it);
+
+        return UTF8_OK;
+    }
+
+    template <typename octet_iterator>
+    utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        if (it == end) 
+            return NOT_ENOUGH_ROOM;
+        
+        code_point = utf8::internal::mask8(*it);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
+
+        return UTF8_OK;
+    }
+
+    template <typename octet_iterator>
+    utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        if (it == end)
+            return NOT_ENOUGH_ROOM;
+            
+        code_point = utf8::internal::mask8(*it);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point += (*it) & 0x3f;
+
+        return UTF8_OK;
+    }
+
+    template <typename octet_iterator>
+    utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        if (it == end)
+           return NOT_ENOUGH_ROOM;
+
+        code_point = utf8::internal::mask8(*it);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
+
+        UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+        code_point += (*it) & 0x3f;
+
+        return UTF8_OK;
+    }
+
+    #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
+
+    template <typename octet_iterator>
+    utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+    {
+        // Save the original value of it so we can go back in case of failure
+        // Of course, it does not make much sense with i.e. stream iterators
+        octet_iterator original_it = it;
+
+        uint32_t cp = 0;
+        // Determine the sequence length based on the lead octet
+        typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
+        const octet_difference_type length = utf8::internal::sequence_length(it);
+
+        // Get trail octets and calculate the code point
+        utf_error err = UTF8_OK;
+        switch (length) {
+            case 0: 
+                return INVALID_LEAD;
+            case 1:
+                err = utf8::internal::get_sequence_1(it, end, cp);
+                break;
+            case 2:
+                err = utf8::internal::get_sequence_2(it, end, cp);
+            break;
+            case 3:
+                err = utf8::internal::get_sequence_3(it, end, cp);
+            break;
+            case 4:
+                err = utf8::internal::get_sequence_4(it, end, cp);
+            break;
+        }
+
+        if (err == UTF8_OK) {
+            // Decoding succeeded. Now, security checks...
+            if (utf8::internal::is_code_point_valid(cp)) {
+                if (!utf8::internal::is_overlong_sequence(cp, length)){
+                    // Passed! Return here.
+                    code_point = cp;
+                    ++it;
+                    return UTF8_OK;
+                }
+                else
+                    err = OVERLONG_SEQUENCE;
+            }
+            else 
+                err = INVALID_CODE_POINT;
+        }
+
+        // Failure branch - restore the original value of the iterator
+        it = original_it;
+        return err;
+    }
+
+    template <typename octet_iterator>
+    inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
+        uint32_t ignored;
+        return utf8::internal::validate_next(it, end, ignored);
+    }
+
+} // namespace internal
+
+    /// The library API - functions intended to be called by the users
+
+    // Byte order mark
+    const uint8_t bom[] = {0xef, 0xbb, 0xbf};
+
+    template <typename octet_iterator>
+    octet_iterator find_invalid(octet_iterator start, octet_iterator end)
+    {
+        octet_iterator result = start;
+        while (result != end) {
+            utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
+            if (err_code != internal::UTF8_OK)
+                return result;
+        }
+        return result;
+    }
+
+    template <typename octet_iterator>
+    inline bool is_valid(octet_iterator start, octet_iterator end)
+    {
+        return (utf8::find_invalid(start, end) == end);
+    }
+
+    template <typename octet_iterator>
+    inline bool starts_with_bom (octet_iterator it, octet_iterator end)
+    {
+        return (
+            ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
+            ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
+            ((it != end) && (utf8::internal::mask8(*it))   == bom[2])
+           );
+    }
+	
+    //Deprecated in release 2.3 
+    template <typename octet_iterator>
+    inline bool is_bom (octet_iterator it)
+    {
+        return (
+            (utf8::internal::mask8(*it++)) == bom[0] &&
+            (utf8::internal::mask8(*it++)) == bom[1] &&
+            (utf8::internal::mask8(*it))   == bom[2]
+           );
+    }
+} // namespace utf8
+
+#endif // header guard
+
+

+ 228 - 0
contrib/utf8cpp/source/utf8/unchecked.h

@@ -0,0 +1,228 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+
+namespace utf8
+{
+    namespace unchecked 
+    {
+        template <typename octet_iterator>
+        octet_iterator append(uint32_t cp, octet_iterator result)
+        {
+            if (cp < 0x80)                        // one octet
+                *(result++) = static_cast<uint8_t>(cp);  
+            else if (cp < 0x800) {                // two octets
+                *(result++) = static_cast<uint8_t>((cp >> 6)          | 0xc0);
+                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
+            }
+            else if (cp < 0x10000) {              // three octets
+                *(result++) = static_cast<uint8_t>((cp >> 12)         | 0xe0);
+                *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
+            }
+            else {                                // four octets
+                *(result++) = static_cast<uint8_t>((cp >> 18)         | 0xf0);
+                *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
+                *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+                *(result++) = static_cast<uint8_t>((cp & 0x3f)        | 0x80);
+            }
+            return result;
+        }
+
+        template <typename octet_iterator>
+        uint32_t next(octet_iterator& it)
+        {
+            uint32_t cp = utf8::internal::mask8(*it);
+            typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
+            switch (length) {
+                case 1:
+                    break;
+                case 2:
+                    it++;
+                    cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
+                    break;
+                case 3:
+                    ++it; 
+                    cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+                    ++it;
+                    cp += (*it) & 0x3f;
+                    break;
+                case 4:
+                    ++it;
+                    cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);                
+                    ++it;
+                    cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
+                    ++it;
+                    cp += (*it) & 0x3f; 
+                    break;
+            }
+            ++it;
+            return cp;        
+        }
+
+        template <typename octet_iterator>
+        uint32_t peek_next(octet_iterator it)
+        {
+            return utf8::unchecked::next(it);    
+        }
+
+        template <typename octet_iterator>
+        uint32_t prior(octet_iterator& it)
+        {
+            while (utf8::internal::is_trail(*(--it))) ;
+            octet_iterator temp = it;
+            return utf8::unchecked::next(temp);
+        }
+
+        // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
+        template <typename octet_iterator>
+        inline uint32_t previous(octet_iterator& it)
+        {
+            return utf8::unchecked::prior(it);
+        }
+
+        template <typename octet_iterator, typename distance_type>
+        void advance (octet_iterator& it, distance_type n)
+        {
+            for (distance_type i = 0; i < n; ++i)
+                utf8::unchecked::next(it);
+        }
+
+        template <typename octet_iterator>
+        typename std::iterator_traits<octet_iterator>::difference_type
+        distance (octet_iterator first, octet_iterator last)
+        {
+            typename std::iterator_traits<octet_iterator>::difference_type dist;
+            for (dist = 0; first < last; ++dist) 
+                utf8::unchecked::next(first);
+            return dist;
+        }
+
+        template <typename u16bit_iterator, typename octet_iterator>
+        octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
+        {       
+            while (start != end) {
+                uint32_t cp = utf8::internal::mask16(*start++);
+            // Take care of surrogate pairs first
+                if (utf8::internal::is_lead_surrogate(cp)) {
+                    uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+                    cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+                }
+                result = utf8::unchecked::append(cp, result);
+            }
+            return result;         
+        }
+
+        template <typename u16bit_iterator, typename octet_iterator>
+        u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+        {
+            while (start < end) {
+                uint32_t cp = utf8::unchecked::next(start);
+                if (cp > 0xffff) { //make a surrogate pair
+                    *result++ = static_cast<uint16_t>((cp >> 10)   + internal::LEAD_OFFSET);
+                    *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+                }
+                else
+                    *result++ = static_cast<uint16_t>(cp);
+            }
+            return result;
+        }
+
+        template <typename octet_iterator, typename u32bit_iterator>
+        octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+        {
+            while (start != end)
+                result = utf8::unchecked::append(*(start++), result);
+
+            return result;
+        }
+
+        template <typename octet_iterator, typename u32bit_iterator>
+        u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+        {
+            while (start < end)
+                (*result++) = utf8::unchecked::next(start);
+
+            return result;
+        }
+
+        // The iterator class
+        template <typename octet_iterator>
+          class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> { 
+            octet_iterator it;
+            public:
+            iterator () {}
+            explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
+            // the default "big three" are OK
+            octet_iterator base () const { return it; }
+            uint32_t operator * () const
+            {
+                octet_iterator temp = it;
+                return utf8::unchecked::next(temp);
+            }
+            bool operator == (const iterator& rhs) const 
+            { 
+                return (it == rhs.it);
+            }
+            bool operator != (const iterator& rhs) const
+            {
+                return !(operator == (rhs));
+            }
+            iterator& operator ++ () 
+            {
+                ::std::advance(it, utf8::internal::sequence_length(it));
+                return *this;
+            }
+            iterator operator ++ (int)
+            {
+                iterator temp = *this;
+                ::std::advance(it, utf8::internal::sequence_length(it));
+                return temp;
+            }  
+            iterator& operator -- ()
+            {
+                utf8::unchecked::prior(it);
+                return *this;
+            }
+            iterator operator -- (int)
+            {
+                iterator temp = *this;
+                utf8::unchecked::prior(it);
+                return temp;
+            }
+          }; // class iterator
+
+    } // namespace utf8::unchecked
+} // namespace utf8 
+
+
+#endif // header guard
+

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

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

+ 0 - 2
include/assimp/color4.inl

@@ -77,7 +77,6 @@ AI_FORCE_INLINE const aiColor4t<TReal>& aiColor4t<TReal>::operator /= (TReal f)
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 AI_FORCE_INLINE TReal aiColor4t<TReal>::operator[](unsigned int i) const {
-    //return *(&r + i);
     switch ( i ) {
         case 0:
             return r;
@@ -93,7 +92,6 @@ AI_FORCE_INLINE TReal aiColor4t<TReal>::operator[](unsigned int i) const {
 // ------------------------------------------------------------------------------------------------
 template <typename TReal>
 AI_FORCE_INLINE TReal& aiColor4t<TReal>::operator[](unsigned int i) {
-//    return *(&r + i);
     switch ( i ) {
         case 0:
             return r;

+ 16 - 4
include/assimp/material.inl

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

+ 4 - 3
include/assimp/matrix4x4.h

@@ -224,7 +224,7 @@ public:
      *  @return Reference to the output matrix
      */
     static aiMatrix4x4t& Rotation(TReal a, const aiVector3t<TReal>& axis,
-        aiMatrix4x4t& out);
+            aiMatrix4x4t& out);
 
     // -------------------------------------------------------------------
     /** @brief Returns a translation matrix
@@ -232,7 +232,8 @@ public:
      *  @param out Receives the output matrix
      *  @return Reference to the output matrix
      */
-    static aiMatrix4x4t& Translation( const aiVector3t<TReal>& v, aiMatrix4x4t& out);
+    static aiMatrix4x4t& Translation( const aiVector3t<TReal>& v, 
+            aiMatrix4x4t& out);
 
     // -------------------------------------------------------------------
     /** @brief Returns a scaling matrix
@@ -252,7 +253,7 @@ public:
      *          Journal of Graphics Tools, 4(4):1-4, 1999
      */
     static aiMatrix4x4t& FromToMatrix(const aiVector3t<TReal>& from,
-        const aiVector3t<TReal>& to, aiMatrix4x4t& out);
+            const aiVector3t<TReal>& to, aiMatrix4x4t& out);
 
 public:
     TReal a1, a2, a3, a4;

+ 1 - 4
port/PyAssimp/pyassimp/helper.py

@@ -8,7 +8,6 @@ import os
 import ctypes
 from ctypes import POINTER
 import operator
-import sys
 
 try: import numpy
 except: numpy = None
@@ -40,9 +39,7 @@ elif os.name=='nt':
     for dir_candidate in path_dirs:
         if 'assimp' in dir_candidate.lower():
             additional_dirs.append(dir_candidate)
-
-additional_dirs += sys.path
-
+            
 #print(additional_dirs)
 def vec2tuple(x):
     """ Converts a VECTOR3D to a Tuple """

+ 1 - 3
port/PyAssimp/setup.py

@@ -9,7 +9,5 @@ setup(name='pyassimp',
       url='https://github.com/assimp/assimp',
       packages=['pyassimp'],
       data_files=[('share/pyassimp', ['README.md']),
-                  ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')]),
-                  ('lib/', [f for f in os.listdir('../../lib') if os.path.isfile(f)])],
-      requires=['numpy']
+                  ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')])], requires=['numpy']
       )

+ 28 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln

@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26228.9
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleTexturedDirectx11", "SimpleTexturedDirectx11\SimpleTexturedDirectx11.vcxproj", "{E3B160B5-E71F-4F3F-9310-B8F156F736D8}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.ActiveCfg = Debug|x64
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.Build.0 = Debug|x64
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.ActiveCfg = Debug|Win32
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.Build.0 = Debug|Win32
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.ActiveCfg = Release|x64
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.Build.0 = Release|x64
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.ActiveCfg = Release|Win32
+		{E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 102 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h

@@ -0,0 +1,102 @@
+#ifndef MESH_H
+#define MESH_H
+
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <iostream>
+#include <vector>
+using namespace std;
+
+#include <vector>
+#include <d3d11_1.h>
+#include <DirectXMath.h>
+using namespace DirectX;
+
+struct VERTEX {
+	FLOAT X, Y, Z;
+	XMFLOAT2 texcoord;
+};
+
+struct Texture {
+	string type;
+	string path;
+	ID3D11ShaderResourceView *texture;
+};
+
+class Mesh {
+public:
+	vector<VERTEX> vertices;
+	vector<UINT> indices;
+	vector<Texture> textures;
+	ID3D11Device *dev;
+
+	Mesh(ID3D11Device *dev, vector<VERTEX> vertices, vector<UINT> indices, vector<Texture> textures)
+	{
+		this->vertices = vertices;
+		this->indices = indices;
+		this->textures = textures;
+
+		this->dev = dev;
+
+		this->setupMesh(dev);
+	}
+
+	void Draw(ID3D11DeviceContext *devcon)
+	{
+		UINT stride = sizeof(VERTEX);
+		UINT offset = 0;
+
+		devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
+		devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
+
+		devcon->PSSetShaderResources(0, 1, &textures[0].texture);
+
+		devcon->DrawIndexed(indices.size(), 0, 0);
+	}
+
+	void Close()
+	{
+		VertexBuffer->Release();
+		IndexBuffer->Release();
+	}
+private:
+	/*  Render data  */
+	ID3D11Buffer *VertexBuffer, *IndexBuffer;
+
+	/*  Functions    */
+	// Initializes all the buffer objects/arrays
+	bool setupMesh(ID3D11Device *dev)
+	{
+		HRESULT hr;
+
+		D3D11_BUFFER_DESC vbd;
+		vbd.Usage = D3D11_USAGE_IMMUTABLE;
+		vbd.ByteWidth = sizeof(VERTEX) * vertices.size();
+		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+		vbd.CPUAccessFlags = 0;
+		vbd.MiscFlags = 0;
+
+		D3D11_SUBRESOURCE_DATA initData;
+		initData.pSysMem = &vertices[0];
+
+		hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer);
+		if (FAILED(hr))
+			return false;
+
+		D3D11_BUFFER_DESC ibd;
+		ibd.Usage = D3D11_USAGE_IMMUTABLE;
+		ibd.ByteWidth = sizeof(UINT) * indices.size();
+		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
+		ibd.CPUAccessFlags = 0;
+		ibd.MiscFlags = 0;
+
+		initData.pSysMem = &indices[0];
+
+		hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer);
+		if (FAILED(hr))
+			return false;
+	}
+};
+
+#endif

+ 205 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp

@@ -0,0 +1,205 @@
+#include "ModelLoader.h"
+
+ModelLoader::ModelLoader()
+{
+}
+
+
+ModelLoader::~ModelLoader()
+{
+}
+
+bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename)
+{
+	Assimp::Importer importer;
+
+	const aiScene* pScene = importer.ReadFile(filename,
+		aiProcess_Triangulate |
+		aiProcess_ConvertToLeftHanded);
+
+	if (pScene == NULL)
+		return false;
+
+	this->directory = filename.substr(0, filename.find_last_of('/'));
+
+	this->dev = dev;
+	this->hwnd = hwnd;
+
+	processNode(pScene->mRootNode, pScene);
+
+	return true;
+}
+
+void ModelLoader::Draw(ID3D11DeviceContext * devcon)
+{
+	for (int i = 0; i < meshes.size(); i++)
+	{
+		meshes[i].Draw(devcon);
+	}
+}
+
+string textype;
+
+Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene)
+{
+	// Data to fill
+	vector<VERTEX> vertices;
+	vector<UINT> indices;
+	vector<Texture> textures;
+
+	if (mesh->mMaterialIndex >= 0)
+	{
+		aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex];
+
+		if (textype.empty()) textype = determineTextureType(scene, mat);
+	}
+
+	// Walk through each of the mesh's vertices
+	for (UINT i = 0; i < mesh->mNumVertices; i++)
+	{
+		VERTEX vertex;
+
+		vertex.X = mesh->mVertices[i].x;
+		vertex.Y = mesh->mVertices[i].y;
+		vertex.Z = mesh->mVertices[i].z;
+
+		if (mesh->mTextureCoords[0])
+		{
+			vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x;
+			vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y;
+		}
+
+		vertices.push_back(vertex);
+	}
+
+	for (UINT i = 0; i < mesh->mNumFaces; i++)
+	{
+		aiFace face = mesh->mFaces[i];
+
+		for (UINT j = 0; j < face.mNumIndices; j++)
+			indices.push_back(face.mIndices[j]);
+	}
+
+	if (mesh->mMaterialIndex >= 0)
+	{
+		aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
+
+		vector<Texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene);
+		textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
+	}
+
+	return Mesh(dev, vertices, indices, textures);
+}
+
+vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene)
+{
+	vector<Texture> textures;
+	for (UINT i = 0; i < mat->GetTextureCount(type); i++)
+	{
+		aiString str;
+		mat->GetTexture(type, i, &str);
+		// Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture
+		bool skip = false;
+		for (UINT j = 0; j < textures_loaded.size(); j++)
+		{
+			if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0)
+			{
+				textures.push_back(textures_loaded[j]);
+				skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization)
+				break;
+			}
+		}
+		if (!skip)
+		{   // If texture hasn't been loaded already, load it
+			HRESULT hr;
+			Texture texture;
+			if (textype == "embedded compressed texture")
+			{
+				int textureindex = getTextureIndex(&str);
+				texture.texture = getTextureFromModel(scene, textureindex);
+			}
+			else
+			{
+				string filename = string(str.C_Str());
+				filename = directory + '/' + filename;
+				wstring filenamews = wstring(filename.begin(), filename.end());
+				hr = CreateWICTextureFromFile(dev, devcon, filenamews.c_str(), nullptr, &texture.texture);
+				if (FAILED(hr))
+					MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK);
+			}
+			texture.type = typeName;
+			texture.path = str.C_Str();
+			textures.push_back(texture);
+			this->textures_loaded.push_back(texture);  // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures.
+		}
+	}
+	return textures;
+}
+
+void ModelLoader::Close()
+{
+	for (int i = 0; i < meshes.size(); i++)
+	{
+		meshes[i].Close();
+	}
+
+	dev->Release();
+}
+
+void ModelLoader::processNode(aiNode * node, const aiScene * scene)
+{
+	for (UINT i = 0; i < node->mNumMeshes; i++)
+	{
+		aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
+		meshes.push_back(this->processMesh(mesh, scene));
+	}
+
+	for (UINT i = 0; i < node->mNumChildren; i++)
+	{
+		this->processNode(node->mChildren[i], scene);
+	}
+}
+
+string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat)
+{
+	aiString textypeStr;
+	mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr);
+	string textypeteststr = textypeStr.C_Str();
+	if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5")
+	{
+		if (scene->mTextures[0]->mHeight == 0)
+		{
+			return "embedded compressed texture";
+		}
+		else
+		{
+			return "embedded non-compressed texture";
+		}
+	}
+	if (textypeteststr.find('.') != string::npos)
+	{
+		return "textures are on disk";
+	}
+}
+
+int ModelLoader::getTextureIndex(aiString * str)
+{
+	string tistr;
+	tistr = str->C_Str();
+	tistr = tistr.substr(1);
+	return stoi(tistr);
+}
+
+ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex)
+{
+	HRESULT hr;
+	ID3D11ShaderResourceView *texture;
+
+	int* size = reinterpret_cast<int*>(&scene->mTextures[textureindex]->mWidth);
+
+	hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast<unsigned char*>(scene->mTextures[textureindex]->pcData), *size, nullptr, &texture);
+	if (FAILED(hr))
+		MessageBox(hwnd, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK);
+
+	return texture;
+}

Some files were not shown because too many files changed in this diff