diff --git a/Readme.md b/Readme.md index 9fecfedf5b..81fd9fd9dc 100644 --- a/Readme.md +++ b/Readme.md @@ -8,10 +8,10 @@ A library to import and export various 3d-model-formats including scene-post-pro Coverity Scan Build Status +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9973693b7bdd4543b07084d5d9cf4745)](https://www.codacy.com/gh/assimp/assimp/dashboard?utm_source=github.com&utm_medium=referral&utm_content=assimp/assimp&utm_campaign=Badge_Grade) [![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) [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue") -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5be56faac64f46fc941ac890fb4febef)](https://www.codacy.com/app/kimkulling/assimp?utm_source=github.com&utm_medium=referral&utm_content=assimp/assimp&utm_campaign=Badge_Grade) [![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
diff --git a/code/AssetLib/3MF/D3MFOpcPackage.cpp b/code/AssetLib/3MF/D3MFOpcPackage.cpp index ec0861fc1a..c46b83b030 100644 --- a/code/AssetLib/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -156,7 +156,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) : mRootStream = mZipArchive->Open(rootFile.c_str()); ai_assert(mRootStream != nullptr); if (nullptr == mRootStream) { - throw DeadlyExportError("Cannot open root-file in archive : " + rootFile); + throw DeadlyImportError("Cannot open root-file in archive : " + rootFile); } } else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { diff --git a/code/AssetLib/Blender/BlenderLoader.cpp b/code/AssetLib/Blender/BlenderLoader.cpp index 989e9d59a9..71ab67721a 100644 --- a/code/AssetLib/Blender/BlenderLoader.cpp +++ b/code/AssetLib/Blender/BlenderLoader.cpp @@ -88,7 +88,7 @@ using namespace Assimp::Blender; using namespace Assimp::Formatter; static const aiImporterDesc blenderDesc = { - "Blender 3D Importer \nhttp://www.blender3d.org", + "Blender 3D Importer (http://www.blender3d.org)", "", "", "No animation support yet", diff --git a/code/AssetLib/Ogre/OgreBinarySerializer.cpp b/code/AssetLib/Ogre/OgreBinarySerializer.cpp index 13bf54e9f7..0fc18feb98 100644 --- a/code/AssetLib/Ogre/OgreBinarySerializer.cpp +++ b/code/AssetLib/Ogre/OgreBinarySerializer.cpp @@ -181,13 +181,13 @@ Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream) { uint16_t id = serializer.ReadHeader(false); if (id != HEADER_CHUNK_ID) { - throw DeadlyExportError("Invalid Ogre Mesh file header."); + throw DeadlyImportError("Invalid Ogre Mesh file header."); } /// @todo Check what we can actually support. std::string version = serializer.ReadLine(); if (version != MESH_VERSION_1_8) { - throw DeadlyExportError("Mesh version ", version, " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.", + throw DeadlyImportError("Mesh version ", version, " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.", " Supported versions: ", MESH_VERSION_1_8); } @@ -797,13 +797,13 @@ MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHand void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton) { uint16_t id = ReadHeader(false); if (id != HEADER_CHUNK_ID) { - throw DeadlyExportError("Invalid Ogre Skeleton file header."); + throw DeadlyImportError("Invalid Ogre Skeleton file header."); } // This deserialization supports both versions of the skeleton spec std::string version = ReadLine(); if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1) { - throw DeadlyExportError("Skeleton version ", version, " not supported by this importer.", + throw DeadlyImportError("Skeleton version ", version, " not supported by this importer.", " Supported versions: ", SKELETON_VERSION_1_8, " and ", SKELETON_VERSION_1_1); } diff --git a/code/AssetLib/glTF/glTFAsset.h b/code/AssetLib/glTF/glTFAsset.h index 8e4f1ff8fa..da49a17374 100644 --- a/code/AssetLib/glTF/glTFAsset.h +++ b/code/AssetLib/glTF/glTFAsset.h @@ -954,7 +954,9 @@ namespace glTF virtual void AttachToDocument(Document& doc) = 0; virtual void DetachFromDocument() = 0; +#if !defined(ASSIMP_BUILD_NO_EXPORT) virtual void WriteObjects(AssetWriter& writer) = 0; +#endif }; @@ -986,8 +988,10 @@ namespace glTF void AttachToDocument(Document& doc); void DetachFromDocument(); +#if !defined(ASSIMP_BUILD_NO_EXPORT) void WriteObjects(AssetWriter& writer) { WriteLazyDict(*this, writer); } +#endif Ref Add(T* obj); diff --git a/code/AssetLib/glTF/glTFImporter.cpp b/code/AssetLib/glTF/glTFImporter.cpp index 3335fc109e..5e072dd2a0 100644 --- a/code/AssetLib/glTF/glTFImporter.cpp +++ b/code/AssetLib/glTF/glTFImporter.cpp @@ -43,7 +43,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssetLib/glTF/glTFImporter.h" #include "AssetLib/glTF/glTFAsset.h" +#if !defined(ASSIMP_BUILD_NO_EXPORT) #include "AssetLib/glTF/glTFAssetWriter.h" +#endif #include "PostProcessing/MakeVerboseFormat.h" #include diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index af48aa01b9..26a2f64c3e 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -997,7 +997,9 @@ class LazyDictBase { virtual void AttachToDocument(Document &doc) = 0; virtual void DetachFromDocument() = 0; +#if !defined(ASSIMP_BUILD_NO_EXPORT) virtual void WriteObjects(AssetWriter &writer) = 0; +#endif }; template @@ -1030,7 +1032,9 @@ class LazyDict : public LazyDictBase { void AttachToDocument(Document &doc); void DetachFromDocument(); +#if !defined(ASSIMP_BUILD_NO_EXPORT) void WriteObjects(AssetWriter &writer) { WriteLazyDict(*this, writer); } +#endif Ref Add(T *obj); diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 77537028fb..8a793c144f 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -162,6 +162,9 @@ inline static bool ReadValue(Value &val, T &out) { template inline static bool ReadMember(Value &obj, const char *id, T &out) { + if (!obj.IsObject()) { + return false; + } Value::MemberIterator it = obj.FindMember(id); if (it != obj.MemberEnd()) { return ReadHelper::Read(it->value, out); @@ -176,6 +179,9 @@ inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) { } inline Value *FindMember(Value &val, const char *id) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(id); return (it != val.MemberEnd()) ? &it->value : nullptr; } @@ -193,6 +199,9 @@ inline void throwUnexpectedTypeError(const char (&expectedTypeName)[N], const ch // Look-up functions with type checks. Context and extra context help the user identify the problem if there's an error. inline Value *FindStringInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -204,6 +213,9 @@ inline Value *FindStringInContext(Value &val, const char *memberId, const char* } inline Value *FindNumberInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -215,6 +227,9 @@ inline Value *FindNumberInContext(Value &val, const char *memberId, const char* } inline Value *FindUIntInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -226,6 +241,9 @@ inline Value *FindUIntInContext(Value &val, const char *memberId, const char* co } inline Value *FindArrayInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -237,6 +255,9 @@ inline Value *FindArrayInContext(Value &val, const char *memberId, const char* c } inline Value *FindObjectInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } Value::MemberIterator it = val.FindMember(memberId); if (it == val.MemberEnd()) { return nullptr; @@ -886,7 +907,7 @@ inline void Accessor::Read(Value &obj, Asset &r) { componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); { const Value* countValue = FindUInt(obj, "count"); - if (!countValue || countValue->GetInt() < 1) + if (!countValue || countValue->GetUint() < 1) { throw DeadlyImportError("A strictly positive count value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")"); } @@ -1105,7 +1126,9 @@ inline Accessor::Indexer::Indexer(Accessor &acc) : template T Accessor::Indexer::GetValue(int i) { ai_assert(data); - ai_assert(i * stride < accessor.GetMaxByteSize()); + if (i * stride >= accessor.GetMaxByteSize()) { + throw DeadlyImportError("GLTF: Invalid index ", i, ", count out of range for buffer with stride ", stride, " and size ", accessor.GetMaxByteSize(), "."); + } // Ensure that the memcpy doesn't overwrite the local. const size_t sizeToCopy = std::min(elemSize, sizeof(T)); T value = T(); diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index dca6fcb2dc..f34b1b4518 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -44,7 +44,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssetLib/glTF2/glTF2Importer.h" #include "PostProcessing/MakeVerboseFormat.h" #include "AssetLib/glTF2/glTF2Asset.h" +#if !defined(ASSIMP_BUILD_NO_EXPORT) #include "AssetLib/glTF2/glTF2AssetWriter.h" +#endif #include #include @@ -1170,7 +1172,7 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler static const float kMillisecondsFromSeconds = 1000.f; - if (samplers.translation) { + if (samplers.translation && samplers.translation->input && samplers.translation->output) { float *times = nullptr; samplers.translation->input->ExtractData(times); aiVector3D *values = nullptr; @@ -1194,7 +1196,7 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler anim->mPositionKeys->mValue.z = node.translation.value[2]; } - if (samplers.rotation) { + if (samplers.rotation && samplers.rotation->input && samplers.rotation->output) { float *times = nullptr; samplers.rotation->input->ExtractData(times); aiQuaternion *values = nullptr; @@ -1222,7 +1224,7 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler anim->mRotationKeys->mValue.w = node.rotation.value[3]; } - if (samplers.scale) { + if (samplers.scale && samplers.scale->input && samplers.scale->output) { float *times = nullptr; samplers.scale->input->ExtractData(times); aiVector3D *values = nullptr; diff --git a/code/Common/DefaultIOStream.cpp b/code/Common/DefaultIOStream.cpp index 115fea63c2..ba9b9d625c 100644 --- a/code/Common/DefaultIOStream.cpp +++ b/code/Common/DefaultIOStream.cpp @@ -90,10 +90,12 @@ DefaultIOStream::~DefaultIOStream() { size_t DefaultIOStream::Read(void *pvBuffer, size_t pSize, size_t pCount) { + if (0 == pCount) { + return 0; + } ai_assert(nullptr != pvBuffer); ai_assert(0 != pSize); - ai_assert(0 != pCount); - + return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0); } diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp index baa83940ea..205dde52bd 100644 --- a/code/Common/Version.cpp +++ b/code/Common/Version.cpp @@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static const char *LEGAL_INFORMATION = "Open Asset Import Library (Assimp).\n" "A free C/C++ library to import various 3D file formats into applications\n\n" - "(c) 2006-2020, assimp team\n" + "(c) 2006-2021, Assimp team\n" "License under the terms and conditions of the 3-clause BSD license\n" "https://www.assimp.org\n"; diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index dd69026925..20ab63249b 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -135,7 +135,9 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { std::vector::iterator meshIdx = replaceMeshIndex.begin(); for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { aiMesh *const mesh = pScene->mMeshes[i]; - ai_assert(0 != mesh->mPrimitiveTypes); + if (mesh->mPrimitiveTypes == 0) { + throw DeadlyImportError("Mesh with invalid primitive type: ", mesh->mName.C_Str()); + } // if there's just one primitive type in the mesh there's nothing to do for us unsigned int num = 0; diff --git a/include/assimp/postprocess.h b/include/assimp/postprocess.h index 01eabaef98..ca2c2c22d3 100644 --- a/include/assimp/postprocess.h +++ b/include/assimp/postprocess.h @@ -209,9 +209,14 @@ enum aiPostProcessSteps /**
Removes the node graph and pre-transforms all vertices with * the local transformation matrices of their nodes. * - * The output scene still contains nodes, however there is only a - * root node with children, each one referencing only one mesh, - * and each mesh referencing one material. For rendering, you can + * If the resulting scene can be reduced to a single mesh, with a single + * material, no lights, and no cameras, then the output scene will contain + * only a root node (with no children) that references the single mesh. + * Otherwise, the output scene will be reduced to a root node with a single + * level of child nodes, each one referencing one mesh, and each mesh + * referencing one material. + * + * In either case, for rendering, you can * simply render all meshes in order - you don't need to pay * attention to local transformations and the node hierarchy. * Animations are removed during this step. diff --git a/test/unit/utVersion.cpp b/test/unit/utVersion.cpp index 15d3366fa2..0189cd2a91 100644 --- a/test/unit/utVersion.cpp +++ b/test/unit/utVersion.cpp @@ -48,7 +48,7 @@ TEST_F( utVersion, aiGetLegalStringTest ) { EXPECT_NE( lv, nullptr ); std::string text( lv ); - size_t pos( text.find( std::string( "2020" ) ) ); + size_t pos( text.find( std::string( "2021" ) ) ); EXPECT_NE( pos, std::string::npos ); }