From db142da571d99a3a44a0eed52a819bc7c4a85617 Mon Sep 17 00:00:00 2001 From: Garux Date: Thu, 29 Apr 2021 19:44:06 +0300 Subject: [PATCH 01/27] orient mdc correctly --- code/AssetLib/MDC/MDCLoader.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/code/AssetLib/MDC/MDCLoader.cpp b/code/AssetLib/MDC/MDCLoader.cpp index 17a349768..c53c31b77 100644 --- a/code/AssetLib/MDC/MDCLoader.cpp +++ b/code/AssetLib/MDC/MDCLoader.cpp @@ -465,6 +465,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 From 149224091f2967badf71d074b1839a45afa1695e Mon Sep 17 00:00:00 2001 From: Garux Date: Fri, 30 Apr 2021 10:37:06 +0300 Subject: [PATCH 02/27] support missing closing brace in material list after Ascii Scene Exporter v2.51 --- code/AssetLib/ASE/ASEParser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/AssetLib/ASE/ASEParser.cpp b/code/AssetLib/ASE/ASEParser.cpp index 21ec26593..958e3b9a8 100644 --- a/code/AssetLib/ASE/ASEParser.cpp +++ b/code/AssetLib/ASE/ASEParser.cpp @@ -498,6 +498,12 @@ void Parser::ParseLV1MaterialListBlock() { ParseLV2MaterialBlock(sMat); continue; } + if( iDepth == 1 ){ + // CRUDE HACK: support missing brace after "Ascii Scene Exporter v2.51" + LogWarning("Missing closing brace in material list"); + --filePtr; + return; + } } AI_ASE_HANDLE_TOP_LEVEL_SECTION(); } From c2d3d22271cb81aacce318df85a1cf8be1ad8122 Mon Sep 17 00:00:00 2001 From: Jason C Date: Sat, 1 May 2021 10:58:29 -0400 Subject: [PATCH 03/27] Fix crash in CanRead when file can not be opened. Addresses #3849 --- code/AssetLib/M3D/M3DImporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/M3D/M3DImporter.cpp b/code/AssetLib/M3D/M3DImporter.cpp index 8cbda23cb..91fa54b75 100644 --- a/code/AssetLib/M3D/M3DImporter.cpp +++ b/code/AssetLib/M3D/M3DImporter.cpp @@ -137,7 +137,7 @@ bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool c */ std::unique_ptr 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 */ From 2925592c640132e2b34d9aa52d7e36d675b18092 Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 04:55:08 -0400 Subject: [PATCH 04/27] [assimp] Make sure ctype calls use unsigned char. Cast to unsigned char as required by C++ (see C++ **[cctype.cyn]** -> ISO C99 section 7.4, [see also](https://en.cppreference.com/w/cpp/string/byte/isspace)). Addresses https://github.com/assimp/assimp/issues/3867 and then some. --- code/AssetLib/3DS/3DSConverter.cpp | 2 +- code/AssetLib/AMF/AMFImporter.cpp | 2 +- code/AssetLib/BVH/BVHLoader.cpp | 4 ++-- code/AssetLib/Blender/BlenderLoader.cpp | 6 +++--- code/AssetLib/Collada/ColladaParser.cpp | 2 +- code/AssetLib/FBX/FBXMaterial.cpp | 2 +- code/AssetLib/MD3/MD3Loader.cpp | 2 +- code/AssetLib/X/XFileImporter.cpp | 4 ++-- code/AssetLib/X/XFileParser.cpp | 4 ++-- code/Common/BaseImporter.cpp | 6 +++--- include/assimp/ParsingUtils.h | 2 +- include/assimp/StringComparison.h | 8 ++++---- include/assimp/StringUtils.h | 2 +- 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/code/AssetLib/3DS/3DSConverter.cpp b/code/AssetLib/3DS/3DSConverter.cpp index c977867c0..aca16b0d6 100644 --- a/code/AssetLib/3DS/3DSConverter.cpp +++ b/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(::tolower(*it)); + *it = static_cast(::tolower(static_cast(*it))); } if (std::string::npos == s.find("default")) continue; diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp index 1a3efba9a..e77b65f77 100644 --- a/code/AssetLib/AMF/AMFImporter.cpp +++ b/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 &pOutputData) const { diff --git a/code/AssetLib/BVH/BVHLoader.cpp b/code/AssetLib/BVH/BVHLoader.cpp index 8ae99033c..cf78fb6c6 100644 --- a/code/AssetLib/BVH/BVHLoader.cpp +++ b/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); diff --git a/code/AssetLib/Blender/BlenderLoader.cpp b/code/AssetLib/Blender/BlenderLoader.cpp index 3722b9c73..56f4e985f 100644 --- a/code/AssetLib/Blender/BlenderLoader.cpp +++ b/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; diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index 42166fdd4..1ef109f11 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/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); diff --git a/code/AssetLib/FBX/FBXMaterial.cpp b/code/AssetLib/FBX/FBXMaterial.cpp index 3af014bc3..409d7304a 100644 --- a/code/AssetLib/FBX/FBXMaterial.cpp +++ b/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(tolower(shading[i])); + shading[i] = static_cast(tolower(static_cast(shading[i]))); } std::string templateName; if(shading == "phong") { diff --git a/code/AssetLib/MD3/MD3Loader.cpp b/code/AssetLib/MD3/MD3Loader.cpp index e27079766..3002aff67 100644 --- a/code/AssetLib/MD3/MD3Loader.cpp +++ b/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(tolower(*it)); + *it = static_cast(tolower(static_cast(*it))); } // Load multi-part model file, if necessary diff --git a/code/AssetLib/X/XFileImporter.cpp b/code/AssetLib/X/XFileImporter.cpp index cb245ed74..1fcd6b3db 100644 --- a/code/AssetLib/X/XFileImporter.cpp +++ b/code/AssetLib/X/XFileImporter.cpp @@ -667,8 +667,8 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, std::vector &extensions) { } for (size_t i = 0; i < read; ++i) { - buffer[i] = static_cast(::tolower(buffer[i])); + buffer[i] = static_cast(::tolower((unsigned char)buffer[i])); } // It is not a proper handling of unicode files here ... @@ -214,7 +214,7 @@ void BaseImporter::GetExtensionList(std::set &extensions) { token.clear(); const char *ptr(tokens[i]); for (size_t tokIdx = 0; tokIdx < len; ++tokIdx) { - token.push_back(static_cast(tolower(*ptr))); + token.push_back(static_cast(tolower(static_cast(*ptr)))); ++ptr; } const char *r = strstr(buffer, token.c_str()); @@ -223,7 +223,7 @@ void BaseImporter::GetExtensionList(std::set &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(r[-1])))) { continue; } // We got a match, either we don't care where it is, or it happens to diff --git a/include/assimp/ParsingUtils.h b/include/assimp/ParsingUtils.h index b52b0610e..b5074869e 100644 --- a/include/assimp/ParsingUtils.h +++ b/include/assimp/ParsingUtils.h @@ -262,7 +262,7 @@ AI_FORCE_INLINE unsigned int tokenize(const string_type &str, std::vector= 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; diff --git a/include/assimp/StringUtils.h b/include/assimp/StringUtils.h index 4afd717cf..93b7c3f0b 100644 --- a/include/assimp/StringUtils.h +++ b/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; From 1ec8d4b6cf15c8a14e8cc33834b9164c85cd79d7 Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 17:22:44 -0400 Subject: [PATCH 05/27] [draco] Make sure ctype calls use unsigned char. Addresses https://github.com/assimp/assimp/issues/3867 and then some. --- contrib/draco/src/draco/io/parser_utils.cc | 2 +- contrib/draco/src/draco/io/ply_reader.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/draco/src/draco/io/parser_utils.cc b/contrib/draco/src/draco/io/parser_utils.cc index 753a1b314..4f95f6f84 100644 --- a/contrib/draco/src/draco/io/parser_utils.cc +++ b/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; } diff --git a/contrib/draco/src/draco/io/ply_reader.cc b/contrib/draco/src/draco/io/ply_reader.cc index ea7f2689a..cb32df225 100644 --- a/contrib/draco/src/draco/io/ply_reader.cc +++ b/contrib/draco/src/draco/io/ply_reader.cc @@ -268,14 +268,14 @@ std::vector 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; From 7dd7a053a91322fad88cdf958c6d0b3b7b91cb90 Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 17:25:45 -0400 Subject: [PATCH 06/27] [gtest] Fixed a rogue std::isalnum Use IsAlNum instead (gtest-port.h), which deals with char signedness correctly. This was the only spot in gtest where a cctype function was called instead of its gtest-port.h equivalent. Addresses https://github.com/assimp/assimp/issues/3867 and then some. --- contrib/gtest/include/gtest/internal/gtest-param-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/gtest/include/gtest/internal/gtest-param-util.h b/contrib/gtest/include/gtest/internal/gtest-param-util.h index 82cab9b02..9d725a433 100644 --- a/contrib/gtest/include/gtest/internal/gtest-param-util.h +++ b/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; } From 200086c4c5ea18593dace1f3800d1213b8b3588c Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 17:26:17 -0400 Subject: [PATCH 07/27] [assimp_view] Make sure ctype calls use unsigned char. Addresses https://github.com/assimp/assimp/issues/3867 and then some. --- tools/assimp_view/Material.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/assimp_view/Material.cpp b/tools/assimp_view/Material.cpp index 8141fb58c..bcc93011e 100644 --- a/tools/assimp_view/Material.cpp +++ b/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; From c8ad8c6017c78534d54a8478d3aa0b1203cc515b Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 04:15:17 -0400 Subject: [PATCH 08/27] [mmd] Remove stderr spam. Removed stderr spam and cleaned up exception text. Addresses #3865. --- code/AssetLib/MMD/MMDPmxParser.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/code/AssetLib/MMD/MMDPmxParser.cpp b/code/AssetLib/MMD/MMDPmxParser.cpp index cb4787efd..d57dc169a 100644 --- a/code/AssetLib/MMD/MMDPmxParser.cpp +++ b/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); From a9fb1e56ae1504001b3848c2019fb622fd6b72e3 Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 19:16:23 -0400 Subject: [PATCH 09/27] Add ai_str_toprintable; fixed garbage messages in HMP, MDL, Q3D loaders. - ai_str_toprintable: See docs in StringUtils.h. - HMP, MDL, Q3D: In particular, newlines in binary data were complicating logging. --- code/AssetLib/HMP/HMPLoader.cpp | 8 ++------ code/AssetLib/MDL/MDLLoader.cpp | 2 +- code/AssetLib/Q3D/Q3DLoader.cpp | 3 ++- include/assimp/StringUtils.h | 27 +++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/code/AssetLib/HMP/HMPLoader.cpp b/code/AssetLib/HMP/HMPLoader.cpp index 56401f5c9..cd14cb9c3 100644 --- a/code/AssetLib/HMP/HMPLoader.cpp +++ b/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 #include #include #include @@ -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; diff --git a/code/AssetLib/MDL/MDLLoader.cpp b/code/AssetLib/MDL/MDLLoader.cpp index a4286a716..4c0fcd339 100644 --- a/code/AssetLib/MDL/MDLLoader.cpp +++ b/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 diff --git a/code/AssetLib/Q3D/Q3DLoader.cpp b/code/AssetLib/Q3D/Q3DLoader.cpp index b52f86672..b6684d1b8 100644 --- a/code/AssetLib/Q3D/Q3DLoader.cpp +++ b/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 #include #include #include @@ -115,7 +116,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 diff --git a/include/assimp/StringUtils.h b/include/assimp/StringUtils.h index 4afd717cf..5ee1f48d8 100644 --- a/include/assimp/StringUtils.h +++ b/include/assimp/StringUtils.h @@ -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 From 9a04f5d4b0ea3cafba84dfcdc3f8746cc3eaac0a Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 21:24:44 -0400 Subject: [PATCH 10/27] Fix garbage messages in SIB, MD2, and MDC loaders. --- code/AssetLib/MD2/MD2Loader.cpp | 32 +++++++++++++------------------ code/AssetLib/MDC/MDCLoader.cpp | 13 +++---------- code/AssetLib/SIB/SIBImporter.cpp | 7 ++++--- 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/code/AssetLib/MD2/MD2Loader.cpp b/code/AssetLib/MD2/MD2Loader.cpp index 9ccbcdfca..5308ac89c 100644 --- a/code/AssetLib/MD2/MD2Loader.cpp +++ b/code/AssetLib/MD2/MD2Loader.cpp @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include @@ -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"); } // ------------------------------------------------------------------------------------------------ diff --git a/code/AssetLib/MDC/MDCLoader.cpp b/code/AssetLib/MDC/MDCLoader.cpp index 17a349768..ef5fdbfcd 100644 --- a/code/AssetLib/MDC/MDCLoader.cpp +++ b/code/AssetLib/MDC/MDCLoader.cpp @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include @@ -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) { diff --git a/code/AssetLib/SIB/SIBImporter.cpp b/code/AssetLib/SIB/SIBImporter.cpp index 6898fb65c..5c43c8587 100644 --- a/code/AssetLib/SIB/SIBImporter.cpp +++ b/code/AssetLib/SIB/SIBImporter.cpp @@ -68,6 +68,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include @@ -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((chunk.Tag >> 24) & 0xff), static_cast((chunk.Tag >> 16) & 0xff), static_cast((chunk.Tag >> 8) & 0xff), - static_cast(chunk.Tag & 0xff), '\0' + static_cast(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. From 558457e5bf2711ab845239fe4b98c872f4b05d33 Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 03:04:12 -0400 Subject: [PATCH 11/27] [openddlparser] Remove default log handler and unsolicited output. This addresses part of #3862. - Remove default log handler. - Log callback can now be set to nullptr, which just makes logging a no-op. - Initial log callback is nullptr. - Also tweaked format of token error log message and removed newline. Assimp code that uses this may regain logging output by installing a callback and directing the output through appropriate logging facilities. --- contrib/openddlparser/code/OpenDDLParser.cpp | 47 ++++++-------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/contrib/openddlparser/code/OpenDDLParser.cpp b/contrib/openddlparser/code/OpenDDLParser.cpp index 024c26f41..6a9f802ec 100644 --- a/contrib/openddlparser/code/OpenDDLParser.cpp +++ b/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 { From f8609c2c2dc65d40a13c6e542f0cf0058821444b Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 03:32:49 -0400 Subject: [PATCH 12/27] [opengex] Direct OpenDDLParser log messages to assimp logger Also filter unprintable characters. Addresses second part of #3862. --- code/AssetLib/OpenGEX/OpenGEXImporter.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/code/AssetLib/OpenGEX/OpenGEXImporter.cpp b/code/AssetLib/OpenGEX/OpenGEXImporter.cpp index b29aeeeb1..44b0bbf7b 100644 --- a/code/AssetLib/OpenGEX/OpenGEXImporter.cpp +++ b/code/AssetLib/OpenGEX/OpenGEXImporter.cpp @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include @@ -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) { From a03dc4edaa05731e81c5ac9edef78f9ac90097fa Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 20:45:08 -0400 Subject: [PATCH 13/27] [amf] Fix minor typo in error message. Added missing space to detail string on parse failure. --- code/AssetLib/AMF/AMFImporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp index 1a3efba9a..07b033b38 100644 --- a/code/AssetLib/AMF/AMFImporter.cpp +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -268,7 +268,7 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { mXmlParser = new XmlParser(); if (!mXmlParser->parse(file.get())) { delete mXmlParser; - throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); + throw DeadlyImportError("Failed to create XML reader for file ", pFile, "."); } // Start reading, search for root tag From ccd1a4455e3f5611e32cc5f933ec7f3f60316b70 Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 21:14:39 -0400 Subject: [PATCH 14/27] [ply] Fix minor typo in error message. --- code/AssetLib/Ply/PlyLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/Ply/PlyLoader.cpp b/code/AssetLib/Ply/PlyLoader.cpp index ce52636dd..93d48bcbf 100644 --- a/code/AssetLib/Ply/PlyLoader.cpp +++ b/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 mBuffer2; From 6e65115253dbb8806308c8efd399516fcfbd6ba9 Mon Sep 17 00:00:00 2001 From: Jason C Date: Tue, 4 May 2021 21:10:02 -0400 Subject: [PATCH 15/27] [assimp/xml] Improved XML parse error message. Fixed typo, added detail. --- include/assimp/XmlParser.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/assimp/XmlParser.h b/include/assimp/XmlParser.h index f525d3549..bd5281049 100644 --- a/include/assimp/XmlParser.h +++ b/include/assimp/XmlParser.h @@ -136,7 +136,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; } } From 785cca1bb43f9e6047cb566a910fcd0e3d49951f Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:13:10 -0400 Subject: [PATCH 16/27] [amf] Fix crash when file could not be parsed. Fix double free of mXmlParser (deleted but not reset in ParseFile, then deleted again in ~AMFImporter). Should probably use a smart pointer instead, though. Partially addresses https://github.com/assimp/assimp/issues/3888. --- code/AssetLib/AMF/AMFImporter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp index 1a3efba9a..add1cdb57 100644 --- a/code/AssetLib/AMF/AMFImporter.cpp +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -268,6 +268,7 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { mXmlParser = new XmlParser(); if (!mXmlParser->parse(file.get())) { delete mXmlParser; + mXmlParser = nullptr; throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); } From 116ebf6e10c39fdb2c88b31445b68d51fdfb5c5a Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:30:05 -0400 Subject: [PATCH 17/27] [3ds] Fix assertion failure when file could not be opened Check result of IOSystem::Open before constructing stream. Partially addresses #3888. --- code/AssetLib/3DS/3DSLoader.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/3DS/3DSLoader.cpp b/code/AssetLib/3DS/3DSLoader.cpp index a25355ccc..92fe72bbf 100644 --- a/code/AssetLib/3DS/3DSLoader.cpp +++ b/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) { From 7f13387487d9650f4212489b86e9a8be4beb2a0f Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:30:29 -0400 Subject: [PATCH 18/27] [cob] Fix assertion failure when file could not be opened. Check result of IOSystem::Open before constructing stream. Partially addresses #3888. --- code/AssetLib/COB/COBLoader.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/COB/COBLoader.cpp b/code/AssetLib/COB/COBLoader.cpp index efe7fc446..a6e9d4218 100644 --- a/code/AssetLib/COB/COBLoader.cpp +++ b/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 stream(new StreamReaderLE(pIOHandler->Open(pFile, "rb"))); + + auto file = pIOHandler->Open(pFile, "rb"); + if (!file) { + ThrowException("Could not open " + pFile); + } + + std::unique_ptr stream(new StreamReaderLE(file)); // check header char head[32]; From 1cd3752ec6b64d584ebce84c0a6d0ae437a6e5c4 Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:31:06 -0400 Subject: [PATCH 19/27] [ms3d] Fix assertion failure when file could not be opened. Check result of IOSystem::Open before constructing stream. Partially addresses #3888. --- code/AssetLib/MS3D/MS3DLoader.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/MS3D/MS3DLoader.cpp b/code/AssetLib/MS3D/MS3DLoader.cpp index 192bcbe41..31cbca83b 100644 --- a/code/AssetLib/MS3D/MS3DLoader.cpp +++ b/code/AssetLib/MS3D/MS3DLoader.cpp @@ -215,7 +215,12 @@ void MS3DImporter :: CollectChildJoints(const std::vector& 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]; From e52c2972841afc1806d0f0a7a528cbe4af4fbbf3 Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:31:24 -0400 Subject: [PATCH 20/27] [nendo] Fix assertion failure when file could not be opened. Check result of IOSystem::Open before constructing stream. Partially addresses #3888. --- code/AssetLib/NDO/NDOLoader.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/NDO/NDOLoader.cpp b/code/AssetLib/NDO/NDOLoader.cpp index 77fe3e36c..df3a9b15d 100644 --- a/code/AssetLib/NDO/NDOLoader.cpp +++ b/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(); From a80b3b25ebba38a04afc8a72ad46c66759b4a640 Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:31:50 -0400 Subject: [PATCH 21/27] [quick3d] Fix assertion failure when file could not be opened. Check result of IOSystem::Open before constructing stream. Partially addresses #3888. --- code/AssetLib/Q3D/Q3DLoader.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/Q3D/Q3DLoader.cpp b/code/AssetLib/Q3D/Q3DLoader.cpp index b52f86672..710dd52ac 100644 --- a/code/AssetLib/Q3D/Q3DLoader.cpp +++ b/code/AssetLib/Q3D/Q3DLoader.cpp @@ -106,7 +106,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) From 0d3e8b52be6f6c1465fc1ff885fa16f7b221b7d2 Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:32:10 -0400 Subject: [PATCH 22/27] [sib] Fix assertion failure when file could not be opened. Check result of IOSystem::Open before constructing stream. Partially addresses #3888. --- code/AssetLib/SIB/SIBImporter.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/SIB/SIBImporter.cpp b/code/AssetLib/SIB/SIBImporter.cpp index 6898fb65c..825f20ee2 100644 --- a/code/AssetLib/SIB/SIBImporter.cpp +++ b/code/AssetLib/SIB/SIBImporter.cpp @@ -804,7 +804,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) From 470913bf27e74a6fa6f6ef0f0d0fccd4ebd675de Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:46:24 -0400 Subject: [PATCH 23/27] [assbin] Fail if file could not be opened Fail instead of returning empty scene. Partially addresses #3888. --- code/AssetLib/Assbin/AssbinLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/Assbin/AssbinLoader.cpp b/code/AssetLib/Assbin/AssbinLoader.cpp index d94a9ed7d..d94407e03 100644 --- a/code/AssetLib/Assbin/AssbinLoader.cpp +++ b/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 From 98f586c8d443d46b14aa551baa00fbb03188903f Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:48:44 -0400 Subject: [PATCH 24/27] [irr] Fail if file could not be parsed. Fail instead of returning empty scene. Partially addresses #3888. TODO: Propagate XML error detail through exception (depends on #3881). --- code/AssetLib/Irr/IRRLoader.cpp | 4 ++-- code/AssetLib/Irr/IRRMeshLoader.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/AssetLib/Irr/IRRLoader.cpp b/code/AssetLib/Irr/IRRLoader.cpp index ed92c93bb..9ec0a9244 100644 --- a/code/AssetLib/Irr/IRRLoader.cpp +++ b/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(); diff --git a/code/AssetLib/Irr/IRRMeshLoader.cpp b/code/AssetLib/Irr/IRRMeshLoader.cpp index edcff6c83..9350e07b8 100644 --- a/code/AssetLib/Irr/IRRMeshLoader.cpp +++ b/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(); From de5c8ece6f53f5d22ac1c872780cd7518bbb2bb8 Mon Sep 17 00:00:00 2001 From: Jason C Date: Wed, 5 May 2021 17:49:10 -0400 Subject: [PATCH 25/27] [xgl] Fail if file could not be parsed. Fail instead of returning empty scene. Partially addresses #3888. TODO: Propagate XML error detail through exception (depends on #3881). --- code/AssetLib/XGL/XGLLoader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/XGL/XGLLoader.cpp b/code/AssetLib/XGL/XGLLoader.cpp index 00e8bafb2..3b84d7ba9 100644 --- a/code/AssetLib/XGL/XGLLoader.cpp +++ b/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; From e37e00c51fa48d459165ef57caf033e9fe73c3e6 Mon Sep 17 00:00:00 2001 From: Jason C Date: Fri, 7 May 2021 20:21:56 -0400 Subject: [PATCH 26/27] [assimp/fast_atof] Fixed garbage in exception messages. Also reduced 100 byte context output to 30 (which is still probably excessive, but not *as* excessive). --- include/assimp/fast_atof.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/assimp/fast_atof.h b/include/assimp/fast_atof.h index 9ea49c85c..441fe5652 100644 --- a/include/assimp/fast_atof.h +++ b/include/assimp/fast_atof.h @@ -29,6 +29,7 @@ #include "StringComparison.h" #include #include +#include #ifdef _MSC_VER # include @@ -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."); } From 00b625a2ae75f344bafc85baf03a1b2ea73f8462 Mon Sep 17 00:00:00 2001 From: Jason C Date: Mon, 10 May 2021 19:01:15 -0400 Subject: [PATCH 27/27] [amf] Fix crash when file could not be parsed. Fix double free of mXmlParser (deleted but not reset in ParseFile, then deleted again in ~AMFImporter). Should probably use a smart pointer instead, though. --- This change was previously made in 785cca1bb43f9e6047cb566a910fcd0e3d49951f, as part of PR #3890, but was lost in a merge. --- code/AssetLib/AMF/AMFImporter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/AMF/AMFImporter.cpp b/code/AssetLib/AMF/AMFImporter.cpp index e77b65f77..615882b6a 100644 --- a/code/AssetLib/AMF/AMFImporter.cpp +++ b/code/AssetLib/AMF/AMFImporter.cpp @@ -268,7 +268,8 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { mXmlParser = new XmlParser(); if (!mXmlParser->parse(file.get())) { delete mXmlParser; - throw DeadlyImportError("Failed to create XML reader for file" + pFile + "."); + mXmlParser = nullptr; + throw DeadlyImportError("Failed to create XML reader for file ", pFile, "."); } // Start reading, search for root tag