Sfoglia il codice sorgente

Merge branch 'master' into master

Carsten Rudolph 4 anni fa
parent
commit
a54cd432cd
38 ha cambiato i file con 172 aggiunte e 127 eliminazioni
  1. 1 1
      code/AssetLib/3DS/3DSConverter.cpp
  2. 7 1
      code/AssetLib/3DS/3DSLoader.cpp
  3. 1 1
      code/AssetLib/AMF/AMFImporter.cpp
  4. 1 1
      code/AssetLib/Assbin/AssbinLoader.cpp
  5. 2 2
      code/AssetLib/BVH/BVHLoader.cpp
  6. 3 3
      code/AssetLib/Blender/BlenderLoader.cpp
  7. 7 1
      code/AssetLib/COB/COBLoader.cpp
  8. 1 1
      code/AssetLib/Collada/ColladaParser.cpp
  9. 1 1
      code/AssetLib/FBX/FBXMaterial.cpp
  10. 2 6
      code/AssetLib/HMP/HMPLoader.cpp
  11. 2 2
      code/AssetLib/Irr/IRRLoader.cpp
  12. 2 2
      code/AssetLib/Irr/IRRMeshLoader.cpp
  13. 1 1
      code/AssetLib/M3D/M3DImporter.cpp
  14. 13 19
      code/AssetLib/MD2/MD2Loader.cpp
  15. 1 1
      code/AssetLib/MD3/MD3Loader.cpp
  16. 10 10
      code/AssetLib/MDC/MDCLoader.cpp
  17. 1 1
      code/AssetLib/MDL/MDLLoader.cpp
  18. 4 7
      code/AssetLib/MMD/MMDPmxParser.cpp
  19. 6 1
      code/AssetLib/MS3D/MS3DLoader.cpp
  20. 7 1
      code/AssetLib/NDO/NDOLoader.cpp
  21. 14 0
      code/AssetLib/OpenGEX/OpenGEXImporter.cpp
  22. 1 1
      code/AssetLib/Ply/PlyLoader.cpp
  23. 8 2
      code/AssetLib/Q3D/Q3DLoader.cpp
  24. 10 4
      code/AssetLib/SIB/SIBImporter.cpp
  25. 2 2
      code/AssetLib/X/XFileImporter.cpp
  26. 2 2
      code/AssetLib/X/XFileParser.cpp
  27. 1 1
      code/AssetLib/XGL/XGLLoader.cpp
  28. 3 3
      code/Common/BaseImporter.cpp
  29. 1 1
      contrib/draco/src/draco/io/parser_utils.cc
  30. 2 2
      contrib/draco/src/draco/io/ply_reader.cc
  31. 1 1
      contrib/gtest/include/gtest/internal/gtest-param-util.h
  32. 13 34
      contrib/openddlparser/code/OpenDDLParser.cpp
  33. 1 1
      include/assimp/ParsingUtils.h
  34. 4 4
      include/assimp/StringComparison.h
  35. 28 1
      include/assimp/StringUtils.h
  36. 3 1
      include/assimp/XmlParser.h
  37. 3 2
      include/assimp/fast_atof.h
  38. 2 2
      tools/assimp_view/Material.cpp

+ 1 - 1
code/AssetLib/3DS/3DSConverter.cpp

@@ -69,7 +69,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() {
     for (unsigned int i = 0; i < mScene->mMaterials.size(); ++i) {
         std::string s = mScene->mMaterials[i].mName;
         for (std::string::iterator it = s.begin(); it != s.end(); ++it) {
-            *it = static_cast<char>(::tolower(*it));
+            *it = static_cast<char>(::tolower(static_cast<unsigned char>(*it)));
         }
 
         if (std::string::npos == s.find("default")) continue;

+ 7 - 1
code/AssetLib/3DS/3DSLoader.cpp

@@ -143,7 +143,13 @@ void Discreet3DSImporter::SetupProperties(const Importer * /*pImp*/) {
 // Imports the given file into the given scene structure.
 void Discreet3DSImporter::InternReadFile(const std::string &pFile,
         aiScene *pScene, IOSystem *pIOHandler) {
-    StreamReaderLE theStream(pIOHandler->Open(pFile, "rb"));
+
+    auto theFile = pIOHandler->Open(pFile, "rb");
+    if (!theFile) {
+        throw DeadlyImportError("3DS: Could not open ", pFile);
+    }
+
+    StreamReaderLE theStream(theFile);
 
     // We should have at least one chunk
     if (theStream.GetRemainingSize() < 16) {

+ 1 - 1
code/AssetLib/AMF/AMFImporter.cpp

@@ -205,7 +205,7 @@ void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::s
 }
 
 static bool ParseHelper_Decode_Base64_IsBase64(const char pChar) {
-    return (isalnum(pChar) || (pChar == '+') || (pChar == '/'));
+    return (isalnum((unsigned char)pChar) || (pChar == '+') || (pChar == '/'));
 }
 
 void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<uint8_t> &pOutputData) const {

+ 1 - 1
code/AssetLib/Assbin/AssbinLoader.cpp

@@ -671,7 +671,7 @@ void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
 void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
     IOStream *stream = pIOHandler->Open(pFile, "rb");
     if (nullptr == stream) {
-        return;
+        throw DeadlyImportError("ASSBIN: Could not open ", pFile);
     }
 
     // signature

+ 2 - 2
code/AssetLib/BVH/BVHLoader.cpp

@@ -359,7 +359,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
 std::string BVHLoader::GetNextToken() {
     // skip any preceding whitespace
     while (mReader != mBuffer.end()) {
-        if (!isspace(*mReader))
+        if (!isspace((unsigned char)*mReader))
             break;
 
         // count lines
@@ -372,7 +372,7 @@ std::string BVHLoader::GetNextToken() {
     // collect all chars till the next whitespace. BVH is easy in respect to that.
     std::string token;
     while (mReader != mBuffer.end()) {
-        if (isspace(*mReader))
+        if (isspace((unsigned char)*mReader))
             break;
 
         token.push_back(*mReader);

+ 3 - 3
code/AssetLib/Blender/BlenderLoader.cpp

@@ -420,9 +420,9 @@ void BlenderImporter::ResolveImage(aiMaterial *out, const Material *mat, const M
             --s;
         }
 
-        curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower(s[1]);
-        curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower(s[2]);
-        curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower(s[3]);
+        curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower((unsigned char)s[1]);
+        curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower((unsigned char)s[2]);
+        curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower((unsigned char)s[3]);
         curTex->achFormatHint[3] = '\0';
 
         // tex->mHeight = 0;

+ 7 - 1
code/AssetLib/COB/COBLoader.cpp

@@ -137,7 +137,13 @@ void COBImporter::SetupProperties(const Importer * /*pImp*/) {
 // Imports the given file into the given scene structure.
 void COBImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
     COB::Scene scene;
-    std::unique_ptr<StreamReaderLE> stream(new StreamReaderLE(pIOHandler->Open(pFile, "rb")));
+
+    auto file = pIOHandler->Open(pFile, "rb");
+    if (!file) {
+        ThrowException("Could not open " + pFile);
+    }
+
+    std::unique_ptr<StreamReaderLE> stream(new StreamReaderLE(file));
 
     // check header
     char head[32];

+ 1 - 1
code/AssetLib/Collada/ColladaParser.cpp

@@ -234,7 +234,7 @@ void ColladaParser::UriDecodePath(aiString &ss) {
 #if defined(_MSC_VER)
     if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
 #else
-    if (ss.data[0] == '/' && isalpha(ss.data[1]) && ss.data[2] == ':') {
+    if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
 #endif
         --ss.length;
         ::memmove(ss.data, ss.data + 1, ss.length);

+ 1 - 1
code/AssetLib/FBX/FBXMaterial.cpp

@@ -82,7 +82,7 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
 
     // lower-case shading because Blender (for example) writes "Phong"
     for (size_t i = 0; i < shading.length(); ++i) {
-        shading[i] = static_cast<char>(tolower(shading[i]));
+        shading[i] = static_cast<char>(tolower(static_cast<unsigned char>(shading[i])));
     }
     std::string templateName;
     if(shading == "phong") {

+ 2 - 6
code/AssetLib/HMP/HMPLoader.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AssetLib/HMP/HMPLoader.h"
 #include "AssetLib/MD2/MD2FileData.h"
 
+#include <assimp/StringUtils.h>
 #include <assimp/importerdesc.h>
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
@@ -151,12 +152,7 @@ void HMPImporter::InternReadFile(const std::string &pFile,
         InternReadFile_HMP7();
     } else {
         // Print the magic word to the logger
-        char szBuffer[5];
-        szBuffer[0] = ((char *)&iMagic)[0];
-        szBuffer[1] = ((char *)&iMagic)[1];
-        szBuffer[2] = ((char *)&iMagic)[2];
-        szBuffer[3] = ((char *)&iMagic)[3];
-        szBuffer[4] = '\0';
+        std::string szBuffer = ai_str_toprintable((const char *)&iMagic, sizeof(iMagic));
     
         delete[] mBuffer;
         mBuffer = nullptr;

+ 2 - 2
code/AssetLib/Irr/IRRLoader.cpp

@@ -859,13 +859,13 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 
 	// Check whether we can read from the file
 	if (file.get() == nullptr) {
-		throw DeadlyImportError("Failed to open IRR file " + pFile);
+        throw DeadlyImportError("Failed to open IRR file ", pFile);
 	}
 
 	// Construct the irrXML parser
 	XmlParser st;
     if (!st.parse( file.get() )) {
-        return;
+        throw DeadlyImportError("XML parse error while loading IRR file ", pFile);
     }
     pugi::xml_node rootElement = st.getRootNode();
 

+ 2 - 2
code/AssetLib/Irr/IRRMeshLoader.cpp

@@ -135,12 +135,12 @@ void IRRMeshImporter::InternReadFile(const std::string &pFile,
 
 	// Check whether we can read from the file
 	if (file.get() == NULL)
-		throw DeadlyImportError("Failed to open IRRMESH file " + pFile);
+        throw DeadlyImportError("Failed to open IRRMESH file ", pFile);
 
 	// Construct the irrXML parser
 	XmlParser parser;
     if (!parser.parse( file.get() )) {
-        return;
+        throw DeadlyImportError("XML parse error while loading IRRMESH file ", pFile);
     }
     XmlNode root = parser.getRootNode();
 

+ 1 - 1
code/AssetLib/M3D/M3DImporter.cpp

@@ -136,7 +136,7 @@ bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool c
         */
         std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
         unsigned char data[4];
-        if (4 != pStream->Read(data, 1, 4)) {
+        if (!pStream || 4 != pStream->Read(data, 1, 4)) {
             return false;
         }
         return !memcmp(data, "3DMO", 4) /* bin */

+ 13 - 19
code/AssetLib/MD2/MD2Loader.cpp

@@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOSystem.hpp>
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
+#include <assimp/StringUtils.h>
 
 #include <memory>
 
@@ -148,46 +149,39 @@ void MD2Importer::ValidateHeader( )
     if (m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_BE &&
         m_pcHeader->magic != AI_MD2_MAGIC_NUMBER_LE)
     {
-        char szBuffer[5];
-        szBuffer[0] = ((char*)&m_pcHeader->magic)[0];
-        szBuffer[1] = ((char*)&m_pcHeader->magic)[1];
-        szBuffer[2] = ((char*)&m_pcHeader->magic)[2];
-        szBuffer[3] = ((char*)&m_pcHeader->magic)[3];
-        szBuffer[4] = '\0';
-
-        throw DeadlyImportError("Invalid MD2 magic word: should be IDP2, the "
-            "magic word found is " + std::string(szBuffer));
+        throw DeadlyImportError("Invalid MD2 magic word: expected IDP2, found ",
+                                ai_str_toprintable((char *)&m_pcHeader->magic, 4));
     }
 
     // check file format version
     if (m_pcHeader->version != 8)
-        ASSIMP_LOG_WARN( "Unsupported md2 file version. Continuing happily ...");
+        ASSIMP_LOG_WARN( "Unsupported MD2 file version. Continuing happily ...");
 
     // check some values whether they are valid
     if (0 == m_pcHeader->numFrames)
-        throw DeadlyImportError( "Invalid md2 file: NUM_FRAMES is 0");
+        throw DeadlyImportError( "Invalid MD2 file: NUM_FRAMES is 0");
 
     if (m_pcHeader->offsetEnd > (uint32_t)fileSize)
-        throw DeadlyImportError( "Invalid md2 file: File is too small");
+        throw DeadlyImportError( "Invalid MD2 file: File is too small");
 
     if (m_pcHeader->numSkins > AI_MAX_ALLOC(MD2::Skin)) {
-        throw DeadlyImportError("Invalid MD2 header: too many skins, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many skins, would overflow");
     }
 
     if (m_pcHeader->numVertices > AI_MAX_ALLOC(MD2::Vertex)) {
-        throw DeadlyImportError("Invalid MD2 header: too many vertices, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many vertices, would overflow");
     }
 
     if (m_pcHeader->numTexCoords > AI_MAX_ALLOC(MD2::TexCoord)) {
-        throw DeadlyImportError("Invalid MD2 header: too many texcoords, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many texcoords, would overflow");
     }
 
     if (m_pcHeader->numTriangles > AI_MAX_ALLOC(MD2::Triangle)) {
-        throw DeadlyImportError("Invalid MD2 header: too many triangles, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many triangles, would overflow");
     }
 
     if (m_pcHeader->numFrames > AI_MAX_ALLOC(MD2::Frame)) {
-        throw DeadlyImportError("Invalid MD2 header: too many frames, would overflow");
+        throw DeadlyImportError("Invalid MD2 header: Too many frames, would overflow");
     }
 
     // -1 because Frame already contains one
@@ -199,7 +193,7 @@ void MD2Importer::ValidateHeader( )
         m_pcHeader->offsetFrames    + m_pcHeader->numFrames * frameSize                 >= fileSize ||
         m_pcHeader->offsetEnd           > fileSize)
     {
-        throw DeadlyImportError("Invalid MD2 header: some offsets are outside the file");
+        throw DeadlyImportError("Invalid MD2 header: Some offsets are outside the file");
     }
 
     if (m_pcHeader->numSkins > AI_MD2_MAX_SKINS)
@@ -210,7 +204,7 @@ void MD2Importer::ValidateHeader( )
         ASSIMP_LOG_WARN("The model contains more vertices than Quake 2 supports");
 
     if (m_pcHeader->numFrames <= configFrameID )
-        throw DeadlyImportError("The requested frame is not existing the file");
+        throw DeadlyImportError("MD2: The requested frame (", configFrameID, ") does not exist in the file");
 }
 
 // ------------------------------------------------------------------------------------------------

+ 1 - 1
code/AssetLib/MD3/MD3Loader.cpp

@@ -702,7 +702,7 @@ void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
     }
     filename = mFile.substr(s), path = mFile.substr(0, s);
     for (std::string::iterator it = filename.begin(); it != filename.end(); ++it) {
-        *it = static_cast<char>(tolower(*it));
+        *it = static_cast<char>(tolower(static_cast<unsigned char>(*it)));
     }
 
     // Load multi-part model file, if necessary

+ 10 - 10
code/AssetLib/MDC/MDCLoader.cpp

@@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Importer.hpp>
+#include <assimp/StringUtils.h>
 
 #include <memory>
 
@@ -143,16 +144,8 @@ void MDCImporter::ValidateHeader() {
 
     if (pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_BE &&
             pcHeader->ulIdent != AI_MDC_MAGIC_NUMBER_LE) {
-        char szBuffer[5];
-        szBuffer[0] = ((char *)&pcHeader->ulIdent)[0];
-        szBuffer[1] = ((char *)&pcHeader->ulIdent)[1];
-        szBuffer[2] = ((char *)&pcHeader->ulIdent)[2];
-        szBuffer[3] = ((char *)&pcHeader->ulIdent)[3];
-        szBuffer[4] = '\0';
-
-        throw DeadlyImportError("Invalid MDC magic word: should be IDPC, the "
-                                "magic word found is " +
-                                std::string(szBuffer));
+        throw DeadlyImportError("Invalid MDC magic word: expected IDPC, found ",
+                                ai_str_toprintable((char *)&pcHeader->ulIdent, 4));
     }
 
     if (pcHeader->ulVersion != AI_MDC_VERSION) {
@@ -465,6 +458,13 @@ void MDCImporter::InternReadFile(
             pcMat->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
         }
     }
+
+    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
+    pScene->mRootNode->mTransformation = aiMatrix4x4(
+            1.f, 0.f, 0.f, 0.f,
+            0.f, 0.f, 1.f, 0.f,
+            0.f, -1.f, 0.f, 0.f,
+            0.f, 0.f, 0.f, 1.f);
 }
 
 #endif // !! ASSIMP_BUILD_NO_MDC_IMPORTER

+ 1 - 1
code/AssetLib/MDL/MDLLoader.cpp

@@ -252,7 +252,7 @@ void MDLImporter::InternReadFile(const std::string &pFile,
         } else {
             // print the magic word to the log file
             throw DeadlyImportError("Unknown MDL subformat ", pFile,
-                                    ". Magic word (", std::string((char *)&iMagicWord, 4), ") is not known");
+                                    ". Magic word (", ai_str_toprintable((const char *)&iMagicWord, sizeof(iMagicWord)), ") is not known");
         }
 
         // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system

+ 4 - 7
code/AssetLib/MMD/MMDPmxParser.cpp

@@ -478,8 +478,7 @@ namespace pmx
 
     void PmxSoftBody::Read(std::istream * /*stream*/, PmxSetting * /*setting*/)
 	{
-		std::cerr << "Not Implemented Exception" << std::endl;
-        throw DeadlyImportError("MMD: Not Implemented Exception");
+        throw DeadlyImportError("MMD: Soft Body support is not implemented.");
     }
 
 	void PmxModel::Init()
@@ -516,15 +515,13 @@ namespace pmx
 		char magic[4];
 		stream->read((char*) magic, sizeof(char) * 4);
 		if (magic[0] != 0x50 || magic[1] != 0x4d || magic[2] != 0x58 || magic[3] != 0x20)
-		{
-			std::cerr << "invalid magic number." << std::endl;
-      throw DeadlyImportError("MMD: invalid magic number.");
+        {
+      throw DeadlyImportError("MMD: Invalid magic number.");
     }
 		stream->read((char*) &version, sizeof(float));
 		if (version != 2.0f && version != 2.1f)
 		{
-			std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl;
-            throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but ", ai_to_string(version));
+            throw DeadlyImportError("MMD: Unsupported version (must be 2.0 or 2.1): ", ai_to_string(version));
     }
 		this->setting.Read(stream);
 

+ 6 - 1
code/AssetLib/MS3D/MS3DLoader.cpp

@@ -215,7 +215,12 @@ void MS3DImporter :: CollectChildJoints(const std::vector<TempJoint>& joints, ai
 void MS3DImporter::InternReadFile( const std::string& pFile,
     aiScene* pScene, IOSystem* pIOHandler)
 {
-    StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
+
+    auto file = pIOHandler->Open(pFile, "rb");
+    if (!file)
+        throw DeadlyImportError("MS3D: Could not open ", pFile);
+
+    StreamReaderLE stream(file);
 
     // CanRead() should have done this already
     char head[10];

+ 7 - 1
code/AssetLib/NDO/NDOLoader.cpp

@@ -116,7 +116,13 @@ void NDOImporter::SetupProperties(const Importer* /*pImp*/)
 void NDOImporter::InternReadFile( const std::string& pFile,
     aiScene* pScene, IOSystem* pIOHandler)
 {
-    StreamReaderBE reader(pIOHandler->Open( pFile, "rb"));
+
+    auto file = pIOHandler->Open( pFile, "rb");
+    if (!file) {
+        throw DeadlyImportError("Nendo: Could not open ", pFile);
+    }
+
+    StreamReaderBE reader(file);
 
     // first 9 bytes are nendo file format ("nendo 1.n")
     const char* head = (const char*)reader.GetPtr();

+ 14 - 0
code/AssetLib/OpenGEX/OpenGEXImporter.cpp

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <assimp/DefaultIOSystem.h>
 #include <assimp/StringComparison.h>
+#include <assimp/StringUtils.h>
 #include <assimp/DefaultLogger.hpp>
 
 #include <assimp/ai_assert.h>
@@ -223,6 +224,18 @@ static void propId2StdString(Property *prop, std::string &name, std::string &key
     }
 }
 
+//------------------------------------------------------------------------------------------------
+static void logDDLParserMessage (LogSeverity severity, const std::string &rawmsg) {
+    std::string msg = ai_str_toprintable(rawmsg);
+    switch (severity) {
+    case ddl_debug_msg: ASSIMP_LOG_DEBUG(msg);         break;
+    case ddl_info_msg:  ASSIMP_LOG_INFO(msg);          break;
+    case ddl_warn_msg:  ASSIMP_LOG_WARN(msg);          break;
+    case ddl_error_msg: ASSIMP_LOG_ERROR(msg);         break;
+    default:            ASSIMP_LOG_VERBOSE_DEBUG(msg); break;
+    }
+}
+
 //------------------------------------------------------------------------------------------------
 OpenGEXImporter::VertexContainer::VertexContainer() :
         m_numColors(0), m_colors(nullptr), m_numUVComps(), m_textureCoords() {
@@ -306,6 +319,7 @@ void OpenGEXImporter::InternReadFile(const std::string &filename, aiScene *pScen
     pIOHandler->Close(file);
 
     OpenDDLParser myParser;
+    myParser.setLogCallback(&logDDLParserMessage);
     myParser.setBuffer(&buffer[0], buffer.size());
     bool success(myParser.parse());
     if (success) {

+ 1 - 1
code/AssetLib/Ply/PlyLoader.cpp

@@ -172,7 +172,7 @@ void PLYImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
             (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");
+        throw DeadlyImportError("Invalid .ply file: Incorrect magic number (expected 'ply' or 'PLY').");
     }
 
     std::vector<char> mBuffer2;

+ 8 - 2
code/AssetLib/Q3D/Q3DLoader.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "Q3DLoader.h"
+#include <assimp/StringUtils.h>
 #include <assimp/StreamReader.h>
 #include <assimp/fast_atof.h>
 #include <assimp/importerdesc.h>
@@ -106,7 +107,12 @@ const aiImporterDesc *Q3DImporter::GetInfo() const {
 // Imports the given file into the given scene structure.
 void Q3DImporter::InternReadFile(const std::string &pFile,
         aiScene *pScene, IOSystem *pIOHandler) {
-    StreamReaderLE stream(pIOHandler->Open(pFile, "rb"));
+
+    auto file = pIOHandler->Open(pFile, "rb");
+    if (!file)
+        throw DeadlyImportError("Quick3D: Could not open ", pFile);
+
+    StreamReaderLE stream(file);
 
     // The header is 22 bytes large
     if (stream.GetRemainingSize() < 22)
@@ -115,7 +121,7 @@ void Q3DImporter::InternReadFile(const std::string &pFile,
     // Check the file's signature
     if (ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Do", 8) &&
             ASSIMP_strincmp((const char *)stream.GetPtr(), "quick3Ds", 8)) {
-        throw DeadlyImportError("Not a Quick3D file. Signature string is: ", std::string((const char *)stream.GetPtr(), 8));
+        throw DeadlyImportError("Not a Quick3D file. Signature string is: ", ai_str_toprintable((const char *)stream.GetPtr(), 8));
     }
 
     // Print the file format version

+ 10 - 4
code/AssetLib/SIB/SIBImporter.cpp

@@ -68,6 +68,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/IOSystem.hpp>
+#include <assimp/StringUtils.h>
 
 #include <map>
 
@@ -166,14 +167,14 @@ static aiColor3D ReadColor(StreamReaderLE *stream) {
 }
 
 static void UnknownChunk(StreamReaderLE * /*stream*/, const SIBChunk &chunk) {
-    char temp[5] = {
+    char temp[4] = {
         static_cast<char>((chunk.Tag >> 24) & 0xff),
         static_cast<char>((chunk.Tag >> 16) & 0xff),
         static_cast<char>((chunk.Tag >> 8) & 0xff),
-        static_cast<char>(chunk.Tag & 0xff), '\0'
+        static_cast<char>(chunk.Tag & 0xff)
     };
 
-    ASSIMP_LOG_WARN((Formatter::format(), "SIB: Skipping unknown '", temp, "' chunk."));
+    ASSIMP_LOG_WARN((Formatter::format(), "SIB: Skipping unknown '", ai_str_toprintable(temp, 4), "' chunk."));
 }
 
 // Reads a UTF-16LE string and returns it at UTF-8.
@@ -804,7 +805,12 @@ static void ReadScene(SIB *sib, StreamReaderLE *stream) {
 // Imports the given file into the given scene structure.
 void SIBImporter::InternReadFile(const std::string &pFile,
         aiScene *pScene, IOSystem *pIOHandler) {
-    StreamReaderLE stream(pIOHandler->Open(pFile, "rb"));
+
+    auto file = pIOHandler->Open(pFile, "rb");
+    if (!file)
+        throw DeadlyImportError("SIB: Could not open ", pFile);
+
+    StreamReaderLE stream(file);
 
     // We should have at least one chunk
     if (stream.GetRemainingSize() < 16)

+ 2 - 2
code/AssetLib/X/XFileImporter.cpp

@@ -667,8 +667,8 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector<XFile::Materi
 
                 // convert to lower case for easier comparison
                 for ( unsigned int c = 0; c < sz.length(); ++c ) {
-                    if ( isalpha( sz[ c ] ) ) {
-                        sz[ c ] = (char) tolower( sz[ c ] );
+                    if ( isalpha( (unsigned char) sz[ c ] ) ) {
+                        sz[ c ] = (char) tolower( (unsigned char) sz[ c ] );
                     }
                 }
 

+ 2 - 2
code/AssetLib/X/XFileParser.cpp

@@ -1245,13 +1245,13 @@ unsigned int XFileParser::ReadInt() {
         }
 
         // at least one digit expected
-        if (!isdigit(*mP))
+        if (!isdigit((unsigned char)*mP))
             ThrowException("Number expected.");
 
         // read digits
         unsigned int number = 0;
         while (mP < mEnd) {
-            if (!isdigit(*mP))
+            if (!isdigit((unsigned char)*mP))
                 break;
             number = number * 10 + (*mP - 48);
             mP++;

+ 1 - 1
code/AssetLib/XGL/XGLLoader.cpp

@@ -200,7 +200,7 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 	// parse the XML file
     mXmlParser = new XmlParser;
     if (!mXmlParser->parse(stream.get())) {
-		return;
+        throw DeadlyImportError("XML parse error while loading XGL file ", pFile);
 	}
 
 	TempScope scope;

+ 3 - 3
code/Common/BaseImporter.cpp

@@ -179,7 +179,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
         }
 
         for (size_t i = 0; i < read; ++i) {
-            buffer[i] = static_cast<char>(::tolower(buffer[i]));
+            buffer[i] = static_cast<char>(::tolower((unsigned char)buffer[i]));
         }
 
         // It is not a proper handling of unicode files here ...
@@ -200,7 +200,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
             token.clear();
             const char *ptr(tokens[i]);
             for (size_t tokIdx = 0; tokIdx < len; ++tokIdx) {
-                token.push_back(static_cast<char>(tolower(*ptr)));
+                token.push_back(static_cast<char>(tolower(static_cast<unsigned char>(*ptr))));
                 ++ptr;
             }
             const char *r = strstr(buffer, token.c_str());
@@ -209,7 +209,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
             }
             // We need to make sure that we didn't accidentially identify the end of another token as our token,
             // e.g. in a previous version the "gltf " present in some gltf files was detected as "f "
-            if (noAlphaBeforeTokens && (r != buffer && isalpha(r[-1]))) {
+            if (noAlphaBeforeTokens && (r != buffer && isalpha(static_cast<unsigned char>(r[-1])))) {
                 continue;
             }
             // We got a match, either we don't care where it is, or it happens to

+ 1 - 1
contrib/draco/src/draco/io/parser_utils.cc

@@ -252,7 +252,7 @@ DecoderBuffer ParseLineIntoDecoderBuffer(DecoderBuffer *buffer) {
 
 std::string ToLower(const std::string &str) {
   std::string out;
-  std::transform(str.begin(), str.end(), std::back_inserter(out), tolower);
+  std::transform(str.begin(), str.end(), std::back_inserter(out), [](unsigned char c){return tolower(c);});
   return out;
 }
 

+ 2 - 2
contrib/draco/src/draco/io/ply_reader.cc

@@ -268,14 +268,14 @@ std::vector<std::string> PlyReader::SplitWords(const std::string &line) {
   while ((end = line.find_first_of(" \t\n\v\f\r", start)) !=
          std::string::npos) {
     const std::string word(line.substr(start, end - start));
-    if (!std::all_of(word.begin(), word.end(), isspace)) {
+    if (!std::all_of(word.begin(), word.end(), [](unsigned char c){return isspace(c);})) {
       output.push_back(word);
     }
     start = end + 1;
   }
 
   const std::string last_word(line.substr(start));
-  if (!std::all_of(last_word.begin(), last_word.end(), isspace)) {
+  if (!std::all_of(last_word.begin(), last_word.end(), [](unsigned char c){return isspace(c);})) {
     output.push_back(last_word);
   }
   return output;

+ 1 - 1
contrib/gtest/include/gtest/internal/gtest-param-util.h

@@ -644,7 +644,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
 
     // Check for invalid characters
     for (std::string::size_type index = 0; index < name.size(); ++index) {
-      if (!isalnum(name[index]) && name[index] != '_')
+      if (!IsAlNum(name[index]) && name[index] != '_')
         return false;
     }
 

+ 13 - 34
contrib/openddlparser/code/OpenDDLParser.cpp

@@ -72,13 +72,15 @@ 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));
-    stream << part;
-    callback(ddl_error_msg, stream.str());
+    if (callback) {
+        std::string full(in);
+        std::string part(full.substr(0, 50));
+        std::stringstream stream;
+        stream << "Invalid token \"" << *in << "\" "
+               << "(expected \"" << exp << "\") "
+               << "in: \"" << part << "\"";
+        callback(ddl_error_msg, stream.str());
+    }
 }
 
 static bool isIntegerType(Value::ValueType integerType) {
@@ -111,26 +113,8 @@ static DDLNode *createDDLNode(Text *id, OpenDDLParser *parser) {
     return node;
 }
 
-static void logMessage(LogSeverity severity, const std::string &msg) {
-    std::string log;
-    if (ddl_debug_msg == severity) {
-        log += "Debug:";
-    } else if (ddl_info_msg == severity) {
-        log += "Info :";
-    } else if (ddl_warn_msg == severity) {
-        log += "Warn :";
-    } else if (ddl_error_msg == severity) {
-        log += "Error:";
-    } else {
-        log += "None :";
-    }
-
-    log += msg;
-    std::cout << log;
-}
-
 OpenDDLParser::OpenDDLParser() :
-        m_logCallback(logMessage),
+        m_logCallback(nullptr),
         m_buffer(),
         m_stack(),
         m_context(nullptr) {
@@ -138,7 +122,7 @@ OpenDDLParser::OpenDDLParser() :
 }
 
 OpenDDLParser::OpenDDLParser(const char *buffer, size_t len) :
-        m_logCallback(&logMessage), m_buffer(), m_context(nullptr) {
+        m_logCallback(nullptr), m_buffer(), m_context(nullptr) {
     if (0 != len) {
         setBuffer(buffer, len);
     }
@@ -149,13 +133,8 @@ OpenDDLParser::~OpenDDLParser() {
 }
 
 void OpenDDLParser::setLogCallback(logCallback callback) {
-    if (nullptr != callback) {
-        // install user-specific log callback
-        m_logCallback = callback;
-    } else {
-        // install default log callback
-        m_logCallback = &logMessage;
-    }
+    // install user-specific log callback; null = no log callback
+    m_logCallback = callback;
 }
 
 OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const {

+ 1 - 1
include/assimp/ParsingUtils.h

@@ -262,7 +262,7 @@ AI_FORCE_INLINE unsigned int tokenize(const string_type &str, std::vector<string
 inline std::string ai_stdStrToLower(const std::string &str) {
     std::string out(str);
     for (size_t i = 0; i < str.size(); ++i) {
-        out[i] = (char) tolower(out[i]);
+        out[i] = (char) tolower((unsigned char)out[i]);
     }
     return out;
 }

+ 4 - 4
include/assimp/StringComparison.h

@@ -146,8 +146,8 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2) {
 #else
     char c1, c2;
     do {
-        c1 = tolower(*s1++);
-        c2 = tolower(*s2++);
+        c1 = tolower((unsigned char)*(s1++));
+        c2 = tolower((unsigned char)*(s2++));
     } while (c1 && (c1 == c2));
     return c1 - c2;
 #endif
@@ -197,8 +197,8 @@ inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n) {
     unsigned int p = 0;
     do {
         if (p++ >= n) return 0;
-        c1 = tolower(*s1++);
-        c2 = tolower(*s2++);
+        c1 = tolower((unsigned char)*(s1++));
+        c2 = tolower((unsigned char)*(s2++));
     } while (c1 && (c1 == c2));
 
     return c1 - c2;

+ 28 - 1
include/assimp/StringUtils.h

@@ -157,7 +157,7 @@ AI_FORCE_INLINE std::string ai_decimal_to_hexa(T toConvert) {
     ss >> result;
 
     for (size_t i = 0; i < result.size(); ++i) {
-        result[i] = (char)toupper(result[i]);
+        result[i] = (char)toupper((unsigned char)result[i]);
     }
 
     return result;
@@ -249,4 +249,31 @@ AI_FORCE_INLINE std::string ai_str_toupper(const std::string &in) {
     return out;
 }
 
+// ---------------------------------------------------------------------------------
+/// @brief  Make a string printable by replacing all non-printable characters with
+///         the specified placeholder character.
+/// @param  in  The incoming string.
+/// @param  placeholder  Placeholder character, default is a question mark.
+/// @return The string, with all non-printable characters replaced.
+AI_FORCE_INLINE std::string ai_str_toprintable(const std::string &in, char placeholder = '?') {
+    std::string out(in);
+    std::transform(out.begin(), out.end(), out.begin(), [placeholder] (unsigned char c) {
+        return isprint(c) ? (char)c :  placeholder;
+    });
+    return out;
+}
+
+// ---------------------------------------------------------------------------------
+/// @brief  Make a string printable by replacing all non-printable characters with
+///         the specified placeholder character.
+/// @param  in  The incoming string.
+/// @param  len The length of the incoming string.
+/// @param  placeholder  Placeholder character, default is a question mark.
+/// @return The string, with all non-printable characters replaced. Will return an
+///         empty string if in is null or len is <= 0.
+AI_FORCE_INLINE std::string ai_str_toprintable(const char *in, int len, char placeholder = '?') {
+    return (in && len > 0) ? ai_str_toprintable(std::string(in, len), placeholder) : std::string();
+}
+
+
 #endif // INCLUDED_AI_STRINGUTILS_H

+ 3 - 1
include/assimp/XmlParser.h

@@ -139,7 +139,9 @@ public:
         if (parse_result.status == pugi::status_ok) {
             return true;
         } else {
-            ASSIMP_LOG_DEBUG("Error while parse xml.");
+            std::ostringstream oss;
+            oss << "Error while parsing XML: " << parse_result.description() << " @ " << parse_result.offset;
+            ASSIMP_LOG_DEBUG(oss.str());
             return false;
         }
     }

+ 3 - 2
include/assimp/fast_atof.h

@@ -29,6 +29,7 @@
 #include "StringComparison.h"
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Exceptional.h>
+#include <assimp/StringUtils.h>
 
 #ifdef _MSC_VER
 #  include <stdint.h>
@@ -193,7 +194,7 @@ uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_ino
 
     if ( *in < '0' || *in > '9' ) {
         // The string is known to be bad, so don't risk printing the whole thing.
-        throw ExceptionType("The string \"", std::string(in).substr(0, 100), "\" cannot be converted into a value." );
+        throw ExceptionType("The string \"", ai_str_toprintable(in, 30), "\" cannot be converted into a value." );
     }
 
     for ( ;; ) {
@@ -293,7 +294,7 @@ const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
     if (!(c[0] >= '0' && c[0] <= '9') &&
             !((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')) {
         // The string is known to be bad, so don't risk printing the whole thing.
-        throw ExceptionType("Cannot parse string \"", std::string(c).substr(0, 100), 
+        throw ExceptionType("Cannot parse string \"", ai_str_toprintable(c, 30),
                                     "\" as a real number: does not start with digit "
                                     "or decimal point followed by digit.");
     }

+ 2 - 2
tools/assimp_view/Material.cpp

@@ -272,7 +272,7 @@ bool CMaterialManager::TryLongerPath(char* szTemp,aiString* p_szString)
                             szExtFound - 1 - info.cFileName);
 
                         for (unsigned int i = 0; i < iSizeFound;++i)
-                            info.cFileName[i] = (CHAR)tolower(info.cFileName[i]);
+                            info.cFileName[i] = (CHAR)tolower((unsigned char)info.cFileName[i]);
 
                         if (0 == memcmp(info.cFileName,szFile2, std::min(iSizeFound,iSize)))
                         {
@@ -354,7 +354,7 @@ int CMaterialManager::FindValidPath(aiString* p_szString)
             for (unsigned int i = 0;;++i)
             {
                 if ('\0' == szTemp[i])break;
-                szTemp[i] = (char)tolower(szTemp[i]);
+                szTemp[i] = (char)tolower((unsigned char)szTemp[i]);
             }
 
             if(TryLongerPath(szTemp,p_szString))return 1;