diff --git a/Dependencies/assimp/LICENSE b/Dependencies/assimp/LICENSE index acaaf016e..f7ff71e8c 100644 --- a/Dependencies/assimp/LICENSE +++ b/Dependencies/assimp/LICENSE @@ -1,6 +1,6 @@ Open Asset Import Library (assimp) -Copyright (c) 2006-2021, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXAnimation.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXAnimation.cpp index fdde37f24..1feedc575 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXAnimation.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -143,31 +143,33 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, cons // ------------------------------------------------------------------------------------------------ const AnimationCurveMap &AnimationCurveNode::Curves() const { - if (curves.empty()) { - // resolve attached animation curves - const std::vector &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve"); + if (!curves.empty()) { + return curves; + } - for (const Connection *con : conns) { + // resolve attached animation curves + const std::vector &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve"); - // link should go for a property - if (!con->PropertyName().length()) { - continue; - } + for (const Connection *con : conns) { - const Object *const ob = con->SourceObject(); - if (nullptr == ob) { - DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring", &element); - continue; - } + // link should go for a property + if (!con->PropertyName().length()) { + continue; + } - const AnimationCurve *const anim = dynamic_cast(ob); - if (nullptr == anim) { - DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element); - continue; - } + const Object *const ob = con->SourceObject(); + if (nullptr == ob) { + DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring", &element); + continue; + } - curves[con->PropertyName()] = anim; + const AnimationCurve *const anim = dynamic_cast(ob); + if (nullptr == anim) { + DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element); + continue; } + + curves[con->PropertyName()] = anim; } return curves; diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXBinaryTokenizer.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXBinaryTokenizer.cpp index b828090e5..be4ed7fac 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXBinaryTokenizer.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXBinaryTokenizer.cpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -60,58 +59,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace FBX { -//enum Flag -//{ -// e_unknown_0 = 1 << 0, -// e_unknown_1 = 1 << 1, -// e_unknown_2 = 1 << 2, -// e_unknown_3 = 1 << 3, -// e_unknown_4 = 1 << 4, -// e_unknown_5 = 1 << 5, -// e_unknown_6 = 1 << 6, -// e_unknown_7 = 1 << 7, -// e_unknown_8 = 1 << 8, -// e_unknown_9 = 1 << 9, -// e_unknown_10 = 1 << 10, -// e_unknown_11 = 1 << 11, -// e_unknown_12 = 1 << 12, -// e_unknown_13 = 1 << 13, -// e_unknown_14 = 1 << 14, -// e_unknown_15 = 1 << 15, -// e_unknown_16 = 1 << 16, -// e_unknown_17 = 1 << 17, -// e_unknown_18 = 1 << 18, -// e_unknown_19 = 1 << 19, -// e_unknown_20 = 1 << 20, -// e_unknown_21 = 1 << 21, -// e_unknown_22 = 1 << 22, -// e_unknown_23 = 1 << 23, -// e_flag_field_size_64_bit = 1 << 24, // Not sure what is -// e_unknown_25 = 1 << 25, -// e_unknown_26 = 1 << 26, -// e_unknown_27 = 1 << 27, -// e_unknown_28 = 1 << 28, -// e_unknown_29 = 1 << 29, -// e_unknown_30 = 1 << 30, -// e_unknown_31 = 1 << 31 -//}; -// -//bool check_flag(uint32_t flags, Flag to_check) -//{ -// return (flags & to_check) != 0; -//} // ------------------------------------------------------------------------------------------------ -Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset) - : - #ifdef DEBUG - contents(sbegin, static_cast(send-sbegin)), - #endif - sbegin(sbegin) - , send(send) - , type(type) - , line(offset) - , column(BINARY_MARKER) -{ +Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset) : + #ifdef DEBUG + contents(sbegin, static_cast(send-sbegin)), + #endif + sbegin(sbegin), + send(send), + type(type), + line(offset), + column(BINARY_MARKER) { ai_assert(sbegin); ai_assert(send); @@ -134,7 +91,9 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) // ------------------------------------------------------------------------------------------------ size_t Offset(const char* begin, const char* cursor) { - ai_assert(begin <= cursor); + if (begin > cursor) { + return 0; + } return cursor - begin; } diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXCommon.h b/Dependencies/assimp/code/AssetLib/FBX/FBXCommon.h index 7e0fb2553..9ce2226c1 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXCommon.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXCommon.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -47,11 +47,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER -namespace Assimp { -namespace FBX { +namespace Assimp::FBX { static constexpr size_t NumNullRecords = 25; -const char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit + +constexpr char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?) @@ -83,8 +83,7 @@ enum TransformInheritance { TransformInheritance_MAX // end-of-enum sentinel }; -} // namespace FBX -} // namespace Assimp +} // namespace Assimp::FBX #endif // ASSIMP_BUILD_NO_FBX_EXPORTER diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXCompileConfig.h b/Dependencies/assimp/code/AssetLib/FBX/FBXCompileConfig.h index 9885ca346..c6e956ec6 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXCompileConfig.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXCompileConfig.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // -#if _MSC_VER > 1500 || (defined __GNUC___) +#if _MSC_VER > 1500 || (defined __GNUC__) # define ASSIMP_FBX_USE_UNORDERED_MULTIMAP # else # define fbx_unordered_map map diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXConverter.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXConverter.cpp index fd54c63f4..f190d600a 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXConverter.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXConverter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -181,7 +181,9 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo if (out->mNumMeshes == 0) { out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; } else { - correctRootTransform(mSceneOut); + // Apply the FBX axis metadata unless requested not to + if (!doc.Settings().ignoreUpDirection) + correctRootTransform(mSceneOut); } } @@ -235,7 +237,7 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN /// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released. struct FBXConverter::PotentialNode { PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {} - PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {} + explicit PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {} aiNode* operator->() { return mNode; } std::unique_ptr mOwnership; aiNode* mNode; @@ -245,7 +247,7 @@ struct FBXConverter::PotentialNode { /// todo: get bone from stack /// todo: make map of aiBone* to aiNode* /// then update convert clusters to the new format -void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) { +void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node, const aiMatrix4x4& parent_transform) { const std::vector &conns = doc.GetConnectionsByDestinationSequenced(id, "Model"); std::vector nodes; @@ -276,7 +278,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) if (nullptr != model) { nodes_chain.clear(); post_nodes_chain.clear(); - aiMatrix4x4 new_abs_transform = parent->mTransformation; + aiMatrix4x4 new_abs_transform = parent_transform; std::string node_name = FixNodeName(model->Name()); // even though there is only a single input node, the design of // assimp (or rather: the complicated transformation chain that @@ -310,6 +312,8 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) child->mParent = last_parent; last_parent = child.mNode; + + new_abs_transform *= child->mTransformation; } // attach geometry @@ -332,6 +336,8 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) postnode->mParent = last_parent; last_parent = postnode.mNode; + + new_abs_transform *= postnode->mTransformation; } } else { // free the nodes we allocated as we don't need them @@ -339,7 +345,7 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) } // recursion call - child nodes - ConvertNodes(model->ID(), last_parent, root_node); + ConvertNodes(model->ID(), last_parent, root_node, new_abs_transform); if (doc.Settings().readLights) { ConvertLights(*model, node_name); @@ -357,12 +363,12 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) if (nodes.empty()) { parent->mNumChildren = 0; parent->mChildren = nullptr; - } - - parent->mChildren = new aiNode *[nodes.size()](); - parent->mNumChildren = static_cast(nodes.size()); - for (unsigned int i = 0; i < nodes.size(); ++i) { - parent->mChildren[i] = nodes[i].mOwnership.release(); + } else { + parent->mChildren = new aiNode *[nodes.size()](); + parent->mNumChildren = static_cast(nodes.size()); + for (unsigned int i = 0; i < nodes.size(); ++i) { + parent->mChildren[i] = nodes[i].mOwnership.release(); + } } } @@ -432,7 +438,8 @@ void FBXConverter::ConvertLight(const Light &light, const std::string &orig_name out_light->mType = aiLightSource_UNDEFINED; break; default: - ai_assert(false); + FBXImporter::LogError("Not handled light type: ", light.LightType()); + break; } float decay = light.DecayStart(); @@ -457,7 +464,7 @@ void FBXConverter::ConvertLight(const Light &light, const std::string &orig_name out_light->mAttenuationQuadratic = 1.0f; break; default: - ai_assert(false); + FBXImporter::LogError("Not handled light decay type: ", light.DecayType()); break; } } @@ -595,7 +602,7 @@ const char *FBXConverter::NameTransformationCompProperty(TransformationComp comp return "GeometricRotationInverse"; case TransformationComp_GeometricTranslationInverse: return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings + case TransformationComp_MAXIMUM: break; } @@ -711,8 +718,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { const TransformationComp comp = static_cast(i); - if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation || - comp == TransformationComp_PreRotation || comp == TransformationComp_PostRotation) { + if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) { continue; } @@ -1248,9 +1254,9 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries(); for (const ShapeGeometry *shapeGeometry : shapeGeometries) { - aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); - const auto &curVertices = shapeGeometry->GetVertices(); const auto &curNormals = shapeGeometry->GetNormals(); + aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh, true, !curNormals.empty()); + const auto &curVertices = shapeGeometry->GetVertices(); const auto &curIndices = shapeGeometry->GetIndices(); //losing channel name if using shapeGeometry->Name() // if blendShapeChannel Name is empty or doesn't have a ".", add geoMetryName; @@ -1266,7 +1272,7 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c for (size_t j = 0; j < curIndices.size(); j++) { const unsigned int curIndex = curIndices.at(j); aiVector3D vertex = curVertices.at(j); - aiVector3D normal = curNormals.at(j); + aiVector3D normal = curNormals.empty() ? aiVector3D() : curNormals.at(j); unsigned int count = 0; const unsigned int *outIndices = mesh.ToOutputVertexIndex(curIndex, count); for (unsigned int k = 0; k < count; k++) { @@ -1486,15 +1492,15 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries(); for (const ShapeGeometry *shapeGeometry : shapeGeometries) { - aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); - const auto& curVertices = shapeGeometry->GetVertices(); const auto& curNormals = shapeGeometry->GetNormals(); + aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh, true, !curNormals.empty()); + const auto& curVertices = shapeGeometry->GetVertices(); const auto& curIndices = shapeGeometry->GetIndices(); animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); for (size_t j = 0; j < curIndices.size(); j++) { unsigned int curIndex = curIndices.at(j); aiVector3D vertex = curVertices.at(j); - aiVector3D normal = curNormals.at(j); + aiVector3D normal = curNormals.empty() ? aiVector3D() : curNormals.at(j); unsigned int count = 0; const unsigned int *outIndices = mesh.ToOutputVertexIndex(curIndex, count); for (unsigned int k = 0; k < count; k++) { @@ -1670,14 +1676,14 @@ void FBXConverter::ConvertCluster(std::vector &local_mesh_bones, const //bone->mOffsetMatrix = cluster->Transform(); // store local transform link for post processing - + bone->mOffsetMatrix = cluster->TransformLink(); bone->mOffsetMatrix.Inverse(); const aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform; bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset - + // // Now calculate the aiVertexWeights // @@ -2952,7 +2958,7 @@ void FBXConverter::GenerateNodeAnimations(std::vector &node_anims, // be invoked _later_ (animations come first). If this node has only rotation, // scaling and translation _and_ there are no animated other components either, // we can use a single node and also a single node animation channel. - if( !has_complex && !NeedsComplexTransformationChain(target)) { + if (!doc.Settings().preservePivots || (!has_complex && !NeedsComplexTransformationChain(target))) { aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain, node_property_map.end(), start, stop, @@ -3410,7 +3416,7 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std:: KeyFrameListList inputs; inputs.reserve(nodes.size() * 3); - //give some breathing room for rounding errors + // give some breathing room for rounding errors const int64_t adj_start = start - 10000; const int64_t adj_stop = stop + 10000; @@ -3436,7 +3442,7 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std:: ai_assert(curve->GetKeys().size() == curve->GetValues().size()); ai_assert(curve->GetKeys().size()); - //get values within the start/stop time window + // get values within the start/stop time window std::shared_ptr Keys(new KeyTimeList()); std::shared_ptr Values(new KeyValueList()); const size_t count = curve->GetKeys().size(); @@ -3456,8 +3462,7 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std:: if (tnew >= adj_start && tnew <= adj_stop) { Keys->push_back(tnew); Values->push_back(vnew); - } - else { + } else { // Something broke break; } diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXConverter.h b/Dependencies/assimp/code/AssetLib/FBX/FBXConverter.h index 73dc9e5a7..f33b26ee1 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXConverter.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXConverter.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -70,7 +69,7 @@ struct morphKeyData { std::vector values; std::vector weights; }; -typedef std::map morphAnimData; +using morphAnimData = std::map ; namespace Assimp { namespace FBX { @@ -134,7 +133,7 @@ class FBXConverter { // ------------------------------------------------------------------------------------------------ // collect and assign child nodes - void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node); + void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node, const aiMatrix4x4& parent_transform = aiMatrix4x4()); // ------------------------------------------------------------------------------------------------ void ConvertLights(const Model& model, const std::string &orig_name ); diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXDeformer.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXDeformer.cpp index 582042360..ee3751350 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXDeformer.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXDeformer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -65,9 +65,6 @@ Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, con props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true); } -// ------------------------------------------------------------------------------------------------ -Deformer::~Deformer() = default; - // ------------------------------------------------------------------------------------------------ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Deformer(id,element,doc,name) @@ -113,10 +110,6 @@ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const } } - -// ------------------------------------------------------------------------------------------------ -Cluster::~Cluster() = default; - // ------------------------------------------------------------------------------------------------ Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Deformer(id,element,doc,name) @@ -142,9 +135,6 @@ Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std:: } } - -// ------------------------------------------------------------------------------------------------ -Skin::~Skin() = default; // ------------------------------------------------------------------------------------------------ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Deformer(id, element, doc, name) @@ -161,8 +151,7 @@ BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, } } } -// ------------------------------------------------------------------------------------------------ -BlendShape::~BlendShape() = default; + // ------------------------------------------------------------------------------------------------ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Deformer(id, element, doc, name) @@ -188,10 +177,8 @@ BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const } } } -// ------------------------------------------------------------------------------------------------ -BlendShapeChannel::~BlendShapeChannel() = default; -// ------------------------------------------------------------------------------------------------ -} -} -#endif +} // namespace FBX +} // Namespace Assimp + +#endif // ASSIMP_BUILD_NO_FBX_IMPORTER diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXDocument.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXDocument.cpp index 3fb0964c4..2bf7b6cc7 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXDocument.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXDocument.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -269,7 +269,7 @@ Document::~Document() { // The document does not own the memory for the following objects, but we need to call their d'tor // so they can properly free memory like string members: - + for (ObjectMap::value_type &v : objects) { delete_LazyObject(v.second); } @@ -663,6 +663,10 @@ LazyObject& Connection::LazyDestinationObject() const { const Object* Connection::SourceObject() const { LazyObject* const lazy = doc.GetObject(src); ai_assert(lazy); + if (lazy == nullptr) { + return nullptr; + } + return lazy->Get(); } @@ -670,6 +674,10 @@ const Object* Connection::SourceObject() const { const Object* Connection::DestinationObject() const { LazyObject* const lazy = doc.GetObject(dest); ai_assert(lazy); + if (lazy == nullptr) { + return nullptr; + } + return lazy->Get(); } diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXDocument.h b/Dependencies/assimp/code/AssetLib/FBX/FBXDocument.h index a103321c0..b0f7da248 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXDocument.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXDocument.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -174,7 +174,7 @@ class NodeAttribute : public Object { public: NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~NodeAttribute() = default; + ~NodeAttribute() override = default; const PropertyTable& Props() const { ai_assert(props.get()); @@ -186,11 +186,11 @@ class NodeAttribute : public Object { }; /** DOM base class for FBX camera settings attached to a node */ -class CameraSwitcher : public NodeAttribute { +class CameraSwitcher final : public NodeAttribute { public: CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~CameraSwitcher() = default; + ~CameraSwitcher() override= default; int CameraID() const { return cameraId; @@ -231,11 +231,11 @@ class CameraSwitcher : public NodeAttribute { /** DOM base class for FBX cameras attached to a node */ -class Camera : public NodeAttribute { +class Camera final : public NodeAttribute { public: Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Camera() = default; + ~Camera() override = default; fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0)) fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0)) @@ -257,24 +257,24 @@ class Camera : public NodeAttribute { }; /** DOM base class for FBX null markers attached to a node */ -class Null : public NodeAttribute { +class Null final : public NodeAttribute { public: Null(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Null() = default; + ~Null() override = default; }; /** DOM base class for FBX limb node markers attached to a node */ -class LimbNode : public NodeAttribute { +class LimbNode final : public NodeAttribute { public: LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~LimbNode() = default; + ~LimbNode() override = default; }; /** DOM base class for FBX lights attached to a node */ -class Light : public NodeAttribute { +class Light final : public NodeAttribute { public: Light(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Light() = default; + ~Light() override = default; enum Type { Type_Point, @@ -329,7 +329,7 @@ class Light : public NodeAttribute { }; /** DOM base class for FBX models (even though its semantics are more "node" than "model" */ -class Model : public Object { +class Model final : public Object { public: enum RotOrder { RotOrder_EulerXYZ = 0, @@ -354,7 +354,7 @@ class Model : public Object { Model(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Model() = default; + ~Model() override = default; fbx_simple_property(QuaternionInterpolate, int, 0) @@ -477,11 +477,11 @@ class Model : public Object { }; /** DOM class for generic FBX textures */ -class Texture : public Object { +class Texture final : public Object { public: Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Texture(); + ~Texture() override; const std::string& Type() const { return type; @@ -542,10 +542,10 @@ class Texture : public Object { }; /** DOM class for layered FBX textures */ -class LayeredTexture : public Object { +class LayeredTexture final : public Object { public: LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~LayeredTexture(); + ~LayeredTexture() override; // Can only be called after construction of the layered texture object due to construction flag. void fillTexture(const Document& doc); @@ -608,11 +608,11 @@ using TextureMap = std::fbx_unordered_map; using LayeredTextureMap = std::fbx_unordered_map; /** DOM class for generic FBX videos */ -class Video : public Object { +class Video final : public Object { public: Video(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Video(); + ~Video() override; const std::string& Type() const { return type; @@ -657,11 +657,11 @@ class Video : public Object { }; /** DOM class for generic FBX materials */ -class Material : public Object { +class Material final : public Object { public: Material(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Material(); + ~Material() override = default; const std::string& GetShadingModel() const { return shading; @@ -697,10 +697,10 @@ using KeyTimeList = std::vector; using KeyValueList = std::vector; /** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefore) */ -class AnimationCurve : public Object { +class AnimationCurve final : public Object { public: AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc); - virtual ~AnimationCurve() = default; + ~AnimationCurve() override = default; /** get list of keyframe positions (time). * Invariant: |GetKeys()| > 0 */ @@ -733,7 +733,7 @@ class AnimationCurve : public Object { using AnimationCurveMap = std::map; /** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */ -class AnimationCurveNode : public Object { +class AnimationCurveNode final : public Object { public: /* the optional white list specifies a list of property names for which the caller wants animations for. If the curve node does not match one of these, std::range_error @@ -741,7 +741,7 @@ class AnimationCurveNode : public Object { AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc, const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0); - virtual ~AnimationCurveNode() = default; + ~AnimationCurveNode() override = default; const PropertyTable& Props() const { ai_assert(props.get()); @@ -783,7 +783,7 @@ class AnimationCurveNode : public Object { using AnimationCurveNodeList = std::vector; /** Represents a FBX animation layer (i.e. a list of node animations) */ -class AnimationLayer : public Object { +class AnimationLayer final : public Object { public: AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc); virtual ~AnimationLayer() = default; @@ -806,7 +806,7 @@ class AnimationLayer : public Object { using AnimationLayerList = std::vector; /** Represents a FBX animation stack (i.e. a list of animation layers) */ -class AnimationStack : public Object { +class AnimationStack final : public Object { public: AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc); virtual ~AnimationStack() = default; @@ -835,7 +835,7 @@ class AnimationStack : public Object { class Deformer : public Object { public: Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Deformer(); + virtual ~Deformer() = default; const PropertyTable& Props() const { ai_assert(props.get()); @@ -851,11 +851,11 @@ using WeightIndexArray = std::vector; /** DOM class for BlendShapeChannel deformers */ -class BlendShapeChannel : public Deformer { +class BlendShapeChannel final : public Deformer { public: BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~BlendShapeChannel(); + virtual ~BlendShapeChannel() = default; float DeformPercent() const { return percent; @@ -876,11 +876,11 @@ class BlendShapeChannel : public Deformer { }; /** DOM class for BlendShape deformers */ -class BlendShape : public Deformer { +class BlendShape final : public Deformer { public: BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~BlendShape(); + virtual ~BlendShape() = default; const std::unordered_set& BlendShapeChannels() const { return blendShapeChannels; @@ -891,11 +891,11 @@ class BlendShape : public Deformer { }; /** DOM class for skin deformer clusters (aka sub-deformers) */ -class Cluster : public Deformer { +class Cluster final : public Deformer { public: Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Cluster(); + virtual ~Cluster() = default; /** get the list of deformer weights associated with this cluster. * Use #GetIndices() to get the associated vertices. Both arrays @@ -935,11 +935,11 @@ class Cluster : public Deformer { }; /** DOM class for skin deformers */ -class Skin : public Deformer { +class Skin final : public Deformer { public: Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Skin(); + virtual ~Skin() = default; float DeformAccuracy() const { return accuracy; diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXDocumentUtil.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXDocumentUtil.cpp index 64105f351..59645c9bf 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXDocumentUtil.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXDocumentUtil.cpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -36,7 +35,6 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---------------------------------------------------------------------- */ @@ -81,8 +79,7 @@ void DOMWarning(const std::string& message, const Token& token) { } // ------------------------------------------------------------------------------------------------ -void DOMWarning(const std::string& message, const Element* element /*= nullptr*/) -{ +void DOMWarning(const std::string& message, const Element* element /*= nullptr*/) { if(element) { DOMWarning(message,element->KeyToken()); return; @@ -92,41 +89,39 @@ void DOMWarning(const std::string& message, const Element* element /*= nullptr*/ } } - // ------------------------------------------------------------------------------------------------ // fetch a property table and the corresponding property template std::shared_ptr GetPropertyTable(const Document& doc, - const std::string& templateName, - const Element &element, - const Scope& sc, - bool no_warn /*= false*/) -{ + const std::string& templateName, + const Element &element, + const Scope& sc, + bool no_warn /*= false*/) { const Element* const Properties70 = sc["Properties70"]; std::shared_ptr templateProps = std::shared_ptr( static_cast(nullptr)); - if(templateName.length()) { + if (templateName.length()) { PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName); if(it != doc.Templates().end()) { templateProps = (*it).second; } } - if(!Properties70 || !Properties70->Compound()) { + if (!Properties70 || !Properties70->Compound()) { if(!no_warn) { DOMWarning("property table (Properties70) not found",&element); } if(templateProps) { return templateProps; - } - else { + } else { return std::make_shared(); } } return std::make_shared(*Properties70,templateProps); } + } // !Util } // !FBX } // !Assimp -#endif +#endif // ASSIMP_BUILD_NO_FBX_IMPORTER diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXDocumentUtil.h b/Dependencies/assimp/code/AssetLib/FBX/FBXDocumentUtil.h index 1e4653201..d770ecd6f 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXDocumentUtil.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXDocumentUtil.h @@ -114,4 +114,4 @@ inline const T* ProcessSimpleConnection(const Connection& con, } //!FBX } //!Assimp -#endif +#endif // ASSIMP_BUILD_NO_FBX_IMPORTER diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXExportNode.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXExportNode.cpp index ae9586968..08f35d023 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXExportNode.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXExportNode.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -35,7 +35,6 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---------------------------------------------------------------------- */ #ifndef ASSIMP_BUILD_NO_EXPORT @@ -55,37 +54,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // shared_ptr namespace Assimp { + // AddP70 helpers... there's no usable pattern here, // so all are defined as separate functions. // Even "animatable" properties are often completely different // from the standard (nonanimated) property definition, // so they are specified with an 'A' suffix. -void FBX::Node::AddP70int( - const std::string& cur_name, int32_t value -) { +void FBX::Node::AddP70int(const std::string& cur_name, int32_t value) { FBX::Node n("P"); n.AddProperties(cur_name, "int", "Integer", "", value); AddChild(n); } -void FBX::Node::AddP70bool( - const std::string& cur_name, bool value -) { +void FBX::Node::AddP70bool(const std::string& cur_name, bool value) { FBX::Node n("P"); n.AddProperties(cur_name, "bool", "", "", int32_t(value)); AddChild(n); } -void FBX::Node::AddP70double( - const std::string &cur_name, double value) { - FBX::Node n("P"); +void FBX::Node::AddP70double(const std::string &cur_name, double value) { FBX::Node n("P"); n.AddProperties(cur_name, "double", "Number", "", value); AddChild(n); } -void FBX::Node::AddP70numberA( - const std::string &cur_name, double value) { +void FBX::Node::AddP70numberA(const std::string &cur_name, double value) { FBX::Node n("P"); n.AddProperties(cur_name, "Number", "", "A", value); AddChild(n); @@ -405,8 +398,7 @@ void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent) } } -void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children) -{ +void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children) { if (!has_children) { return; } // nothing to do s << '\n'; for (int i = 0; i < indent; ++i) { s << '\t'; } @@ -417,11 +409,10 @@ void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children) // ascii property node from vector of doubles void FBX::Node::WritePropertyNodeAscii( - const std::string& name, - const std::vector& v, - Assimp::StreamWriterLE& s, - int indent -){ + const std::string& name, + const std::vector& v, + Assimp::StreamWriterLE& s, + int indent){ char buffer[32]; FBX::Node node(name); node.Begin(s, false, indent); @@ -556,6 +547,8 @@ void FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNodeAscii(name, v, s, indent); } } -} + +} // namespace Assimp + #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXExportNode.h b/Dependencies/assimp/code/AssetLib/FBX/FBXExportNode.h index 7661ab1be..ae99ef43c 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXExportNode.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXExportNode.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -35,7 +35,6 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---------------------------------------------------------------------- */ @@ -70,7 +69,6 @@ class FBX::Node { // some nodes always pretend they have children... bool force_has_children = false; -public: // constructors /// The default class constructor. Node() = default; @@ -89,7 +87,6 @@ class FBX::Node { AddProperties(std::forward(more)...); } -public: // functions to add properties or children // add a single property to the node template void AddProperty(T&& value) { @@ -118,8 +115,6 @@ class FBX::Node { children.push_back(std::move(c)); } -public: // support specifically for dealing with Properties70 nodes - // it really is simpler to make these all separate functions. // the versions with 'A' suffixes are for animatable properties. // those often follow a completely different format internally in FBX. @@ -150,8 +145,6 @@ class FBX::Node { AddChild(n); } -public: // member functions for writing data to a file or stream - // write the full node to the given file or stream void Dump( const std::shared_ptr &outfile, @@ -175,31 +168,6 @@ class FBX::Node { bool has_children ); -private: // internal functions used for writing - - void DumpBinary(Assimp::StreamWriterLE &s); - void DumpAscii(Assimp::StreamWriterLE &s, int indent); - void DumpAscii(std::ostream &s, int indent); - - void BeginBinary(Assimp::StreamWriterLE &s); - void DumpPropertiesBinary(Assimp::StreamWriterLE& s); - void EndPropertiesBinary(Assimp::StreamWriterLE &s); - void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties); - void DumpChildrenBinary(Assimp::StreamWriterLE& s); - void EndBinary(Assimp::StreamWriterLE &s, bool has_children); - - void BeginAscii(std::ostream &s, int indent); - void DumpPropertiesAscii(std::ostream &s, int indent); - void BeginChildrenAscii(std::ostream &s, int indent); - void DumpChildrenAscii(std::ostream &s, int indent); - void EndAscii(std::ostream &s, int indent, bool has_children); - -private: // data used for binary dumps - size_t start_pos; // starting position in stream - size_t end_pos; // ending position in stream - size_t property_start; // starting position of property section - -public: // static member functions // convenience function to create a node with a single property, // and write it to the stream. @@ -235,7 +203,26 @@ class FBX::Node { bool binary, int indent ); -private: // static helper functions +private: // internal functions used for writing + + void DumpBinary(Assimp::StreamWriterLE &s); + void DumpAscii(Assimp::StreamWriterLE &s, int indent); + void DumpAscii(std::ostream &s, int indent); + + void BeginBinary(Assimp::StreamWriterLE &s); + void DumpPropertiesBinary(Assimp::StreamWriterLE& s); + void EndPropertiesBinary(Assimp::StreamWriterLE &s); + void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties); + void DumpChildrenBinary(Assimp::StreamWriterLE& s); + void EndBinary(Assimp::StreamWriterLE &s, bool has_children); + + void BeginAscii(std::ostream &s, int indent); + void DumpPropertiesAscii(std::ostream &s, int indent); + void BeginChildrenAscii(std::ostream &s, int indent); + void DumpChildrenAscii(std::ostream &s, int indent); + void EndAscii(std::ostream &s, int indent, bool has_children); + + // static helper functions static void WritePropertyNodeAscii( const std::string& name, const std::vector& v, @@ -259,9 +246,13 @@ class FBX::Node { Assimp::StreamWriterLE& s ); +private: // data used for binary dumps + size_t start_pos; // starting position in stream + size_t end_pos; // ending position in stream + size_t property_start; // starting position of property section }; -} -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER +} // Namespace Assimp +#endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // AI_FBXEXPORTNODE_H_INC diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXExportProperty.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXExportProperty.cpp index 5fbe84fa7..94ed69b92 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXExportProperty.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXExportProperty.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -286,6 +286,8 @@ void FBXExportProperty::DumpAscii(std::ostream& s, int indent) { break; } } + // assimp issue #6112; fallthrough confirmed by @mesilliac + [[fallthrough]]; case 'R': s << '"'; // we might as well check this now, diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXExportProperty.h b/Dependencies/assimp/code/AssetLib/FBX/FBXExportProperty.h index 93f8cfbe0..8ec37a679 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXExportProperty.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXExportProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXExporter.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXExporter.cpp index 79fa572af..edb78a764 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXExporter.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include // StreamWriterLE #include // DeadlyExportError #include // aiTextureType @@ -370,12 +371,6 @@ void FBXExporter::WriteHeaderExtension () "Creator", creator.str(), outstream, binary, indent ); - //FBX::Node sceneinfo("SceneInfo"); - //sceneinfo.AddProperty("GlobalInfo" + FBX::SEPARATOR + "SceneInfo"); - // not sure if any of this is actually needed, - // so just write an empty node for now. - //sceneinfo.Dump(outstream, binary, indent); - indent = 0; // finish node @@ -459,11 +454,7 @@ void WritePropString(const aiScene* scene, FBX::Node& p, const std::string& key, } } -void FBXExporter::WriteGlobalSettings () -{ - if (!binary) { - // no title, follows directly from the header extension - } +void FBXExporter::WriteGlobalSettings () { FBX::Node gs("GlobalSettings"); gs.AddChild("Version", int32_t(1000)); @@ -493,8 +484,7 @@ void FBXExporter::WriteGlobalSettings () gs.Dump(outfile, binary, 0); } -void FBXExporter::WriteDocuments () -{ +void FBXExporter::WriteDocuments() { if (!binary) { WriteAsciiSectionHeader("Documents Description"); } @@ -523,8 +513,7 @@ void FBXExporter::WriteDocuments () docs.Dump(outfile, binary, 0); } -void FBXExporter::WriteReferences () -{ +void FBXExporter::WriteReferences() { if (!binary) { WriteAsciiSectionHeader("Document References"); } @@ -540,7 +529,6 @@ void FBXExporter::WriteReferences () // some internal helper functions used for writing the definitions // (before any actual data is written) // --------------------------------------------------------------- - size_t count_nodes(const aiNode* n, const aiNode* root) { size_t count; if (n == root) { @@ -556,8 +544,7 @@ size_t count_nodes(const aiNode* n, const aiNode* root) { return count; } -bool has_phong_mat(const aiScene* scene) -{ +static bool has_phong_mat(const aiScene* scene) { // just search for any material with a shininess exponent for (size_t i = 0; i < scene->mNumMaterials; ++i) { aiMaterial* mat = scene->mMaterials[i]; @@ -570,16 +557,12 @@ bool has_phong_mat(const aiScene* scene) return false; } -size_t count_images(const aiScene* scene) { +static size_t count_images(const aiScene* scene) { std::unordered_set images; aiString texpath; for (size_t i = 0; i < scene->mNumMaterials; ++i) { - aiMaterial* mat = scene->mMaterials[i]; - for ( - size_t tt = aiTextureType_DIFFUSE; - tt < aiTextureType_UNKNOWN; - ++tt - ){ + aiMaterial *mat = scene->mMaterials[i]; + for (size_t tt = aiTextureType_DIFFUSE; tt < aiTextureType_UNKNOWN; ++tt) { const aiTextureType textype = static_cast(tt); const size_t texcount = mat->GetTextureCount(textype); for (unsigned int j = 0; j < texcount; ++j) { @@ -588,10 +571,11 @@ size_t count_images(const aiScene* scene) { } } } + return images.size(); } -size_t count_textures(const aiScene* scene) { +static size_t count_textures(const aiScene* scene) { size_t count = 0; for (size_t i = 0; i < scene->mNumMaterials; ++i) { aiMaterial* mat = scene->mMaterials[i]; @@ -609,7 +593,7 @@ size_t count_textures(const aiScene* scene) { return count; } -size_t count_deformers(const aiScene* scene) { +static size_t count_deformers(const aiScene* scene) { size_t count = 0; for (size_t i = 0; i < scene->mNumMeshes; ++i) { const size_t n = scene->mMeshes[i]->mNumBones; @@ -621,8 +605,7 @@ size_t count_deformers(const aiScene* scene) { return count; } -void FBXExporter::WriteDefinitions () -{ +void FBXExporter::WriteDefinitions () { // basically this is just bookkeeping: // determining how many of each type of object there are // and specifying the base properties to use when otherwise unspecified. @@ -1033,9 +1016,7 @@ void FBXExporter::WriteDefinitions () // some internal helper functions used for writing the objects section // (which holds the actual data) // ------------------------------------------------------------------- - -aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node) -{ +static aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node) { for (size_t i = 0; i < node->mNumMeshes; ++i) { if (node->mMeshes[i] == meshIndex) { return node; @@ -1048,8 +1029,7 @@ aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node) return nullptr; } -aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) -{ +aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) { std::vector node_chain; while (node != scene->mRootNode && node != nullptr) { node_chain.push_back(node); @@ -1063,18 +1043,47 @@ aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) } inline int64_t to_ktime(double ticks, const aiAnimation* anim) { - if (FP_ZERO == std::fpclassify(anim->mTicksPerSecond)) { - return static_cast(ticks) * FBX::SECOND; + if (FP_ZERO == std::fpclassify(anim->mTicksPerSecond)) { + return static_cast(ticks * FBX::SECOND); } - return (static_cast(ticks / anim->mTicksPerSecond)) * FBX::SECOND; + + // Defensive: handle zero or near-zero mTicksPerSecond + double tps = anim->mTicksPerSecond; + double timeVal; + if (FP_ZERO == std::fpclassify(tps)) { + timeVal = ticks; + } else { + timeVal = ticks / tps; + } + + // Clamp to prevent overflow + const double kMax = static_cast(INT64_MAX) / static_cast(FBX::SECOND); + const double kMin = static_cast(INT64_MIN) / static_cast(FBX::SECOND); + + if (timeVal > kMax) { + return INT64_MAX; + } + if (timeVal < kMin) { + return INT64_MIN; + } + return static_cast((ticks / anim->mTicksPerSecond) * FBX::SECOND); } inline int64_t to_ktime(double time) { - return (static_cast(time * FBX::SECOND)); + // Clamp to prevent overflow + const double kMax = static_cast(INT64_MAX) / static_cast(FBX::SECOND); + const double kMin = static_cast(INT64_MIN) / static_cast(FBX::SECOND); + + if (time > kMax) { + return INT64_MAX; + } + if (time < kMin) { + return INT64_MIN; + } + return static_cast(time * FBX::SECOND); } -void FBXExporter::WriteObjects () -{ +void FBXExporter::WriteObjects () { if (!binary) { WriteAsciiSectionHeader("Object properties"); } @@ -1087,21 +1096,27 @@ void FBXExporter::WriteObjects () object_node.BeginChildren(outstream, binary, indent); bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true); - std::vector> vVertexIndice;//save vertex_indices as it is needed later + // save vertex_indices as it is needed later + std::vector> vVertexIndice(mScene->mNumMeshes); + std::vector uniq_v_before_mi; const auto bTransparencyFactorReferencedToOpacity = mProperties->GetPropertyBool(AI_CONFIG_EXPORT_FBX_TRANSPARENCY_FACTOR_REFER_TO_OPACITY, false); // geometry (aiMesh) mesh_uids.clear(); indent = 1; - for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - // it's all about this mesh - aiMesh* m = mScene->mMeshes[mi]; + std::function visit_node_geo = [&](const aiNode *node) { + if (node->mNumMeshes == 0) { + for (uint32_t ni = 0; ni < node->mNumChildren; ni++) { + visit_node_geo(node->mChildren[ni]); + } + return; + } // start the node record FBX::Node n("Geometry"); int64_t uid = generate_uid(); - mesh_uids.push_back(uid); + mesh_uids[node] = uid; n.AddProperty(uid); n.AddProperty(FBX::SEPARATOR + "Geometry"); n.AddProperty("Mesh"); @@ -1109,159 +1124,113 @@ void FBXExporter::WriteObjects () n.DumpProperties(outstream, binary, indent); n.EndProperties(outstream, binary, indent); n.BeginChildren(outstream, binary, indent); - indent = 2; // output vertex data - each vertex should be unique (probably) std::vector flattened_vertices; // index of original vertex in vertex data vector std::vector vertex_indices; - // map of vertex value to its index in the data vector - std::map index_by_vertex_value; - if(bJoinIdenticalVertices){ - int32_t index = 0; - for (size_t vi = 0; vi < m->mNumVertices; ++vi) { - aiVector3D vtx = m->mVertices[vi]; - auto elem = index_by_vertex_value.find(vtx); - if (elem == index_by_vertex_value.end()) { - vertex_indices.push_back(index); - index_by_vertex_value[vtx] = index; - flattened_vertices.push_back(vtx[0]); - flattened_vertices.push_back(vtx[1]); - flattened_vertices.push_back(vtx[2]); - ++index; - } else { - vertex_indices.push_back(int32_t(elem->second)); - } - } - } - else { // do not join vertex, respect the export flag - vertex_indices.resize(m->mNumVertices); - std::iota(vertex_indices.begin(), vertex_indices.end(), 0); - for(unsigned int v = 0; v < m->mNumVertices; ++ v) { - aiVector3D vtx = m->mVertices[v]; - flattened_vertices.push_back(vtx.x); - flattened_vertices.push_back(vtx.y); - flattened_vertices.push_back(vtx.z); - } - } - vVertexIndice.push_back(vertex_indices); - FBX::Node::WritePropertyNode( - "Vertices", flattened_vertices, outstream, binary, indent - ); + std::vector normal_data; + std::vector color_data; + + std::vector polygon_data; + + std::vector> uv_data; + std::vector> uv_indices; + + indent = 2; + + for (uint32_t n_mi = 0; n_mi < node->mNumMeshes; n_mi++) { + const auto mi = node->mMeshes[n_mi]; + const aiMesh *m = mScene->mMeshes[mi]; + + size_t v_offset = vertex_indices.size(); + size_t uniq_v_before = flattened_vertices.size() / 3; + + // map of vertex value to its index in the data vector + std::map index_by_vertex_value; + if (bJoinIdenticalVertices) { + int32_t index = 0; + for (size_t vi = 0; vi < m->mNumVertices; ++vi) { + aiVector3D vtx = m->mVertices[vi]; + auto elem = index_by_vertex_value.find(vtx); + if (elem == index_by_vertex_value.end()) { + vertex_indices.push_back(index); + index_by_vertex_value[vtx] = index; + flattened_vertices.insert(flattened_vertices.end(), { vtx.x, vtx.y, vtx.z }); + ++index; + } else { + vertex_indices.push_back(int32_t(elem->second)); + } + } + } else { // do not join vertex, respect the export flag + vertex_indices.resize(v_offset + m->mNumVertices); + std::iota(vertex_indices.begin() + v_offset, vertex_indices.end(), 0); + for(unsigned int v = 0; v < m->mNumVertices; ++ v) { + aiVector3D vtx = m->mVertices[v]; + flattened_vertices.insert(flattened_vertices.end(), {vtx.x, vtx.y, vtx.z}); + } + } + vVertexIndice[mi].insert( + // TODO test whether this can be end or not + vVertexIndice[mi].end(), + vertex_indices.begin() + v_offset, + vertex_indices.end() + ); + + // here could be edges but they're insane. + // it's optional anyway, so let's ignore it. // output polygon data as a flattened array of vertex indices. // the last vertex index of each polygon is negated and - 1 - std::vector polygon_data; - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { + for (size_t fi = 0; fi < m->mNumFaces; fi++) { const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices - 1; ++pvi) { - polygon_data.push_back(vertex_indices[f.mIndices[pvi]]); + if (f.mNumIndices == 0) continue; + size_t pvi = 0; + for (; pvi < f.mNumIndices - 1; pvi++) { + polygon_data.push_back( + static_cast(uniq_v_before + vertex_indices[v_offset + f.mIndices[pvi]]) + ); } polygon_data.push_back( - -1 - vertex_indices[f.mIndices[f.mNumIndices-1]] + static_cast(-1 ^ (uniq_v_before + vertex_indices[v_offset+f.mIndices[pvi]])) ); - } - FBX::Node::WritePropertyNode( - "PolygonVertexIndex", polygon_data, outstream, binary, indent - ); - - // here could be edges but they're insane. - // it's optional anyway, so let's ignore it. + } - FBX::Node::WritePropertyNode( - "GeometryVersion", int32_t(124), outstream, binary, indent - ); + uniq_v_before_mi.push_back(static_cast(uniq_v_before)); - // normals, if any - if (m->HasNormals()) { - FBX::Node normals("LayerElementNormal", int32_t(0)); - normals.Begin(outstream, binary, indent); - normals.DumpProperties(outstream, binary, indent); - normals.EndProperties(outstream, binary, indent); - normals.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "Name", "", outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - // TODO: vertex-normals or indexed normals when appropriate - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "Direct", - outstream, binary, indent - ); - std::vector normal_data; + if (m->HasNormals()) { normal_data.reserve(3 * polygon_data.size()); - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiVector3D &curN = m->mNormals[f.mIndices[pvi]]; - normal_data.push_back(curN.x); - normal_data.push_back(curN.y); - normal_data.push_back(curN.z); - } + for (size_t fi = 0; fi < m->mNumFaces; fi++) { + const aiFace & f = m->mFaces[fi]; + for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) { + const aiVector3D &curN = m->mNormals[f.mIndices[pvi]]; + normal_data.insert(normal_data.end(), { curN.x, curN.y, curN.z }); + } } - FBX::Node::WritePropertyNode( - "Normals", normal_data, outstream, binary, indent - ); - // note: version 102 has a NormalsW also... not sure what it is, - // so we can stick with version 101 for now. - indent = 2; - normals.End(outstream, binary, indent, true); - } + } - // colors, if any - for (size_t ci = 0; ci < m->GetNumColorChannels(); ++ci) { - FBX::Node vertexcolors("LayerElementColor", int32_t(ci)); - vertexcolors.Begin(outstream, binary, indent); - vertexcolors.DumpProperties(outstream, binary, indent); - vertexcolors.EndProperties(outstream, binary, indent); - vertexcolors.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - char layerName[8]; - snprintf(layerName, sizeof(layerName), "COLOR_%d", int32_t(ci)); - FBX::Node::WritePropertyNode( - "Name", (const char*)layerName, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "Direct", - outstream, binary, indent - ); - std::vector color_data; + const int32_t colorChannelIndex = 0; + if (m->HasVertexColors(colorChannelIndex)) { color_data.reserve(4 * polygon_data.size()); - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiColor4D &c = m->mColors[ci][f.mIndices[pvi]]; - color_data.push_back(c.r); - color_data.push_back(c.g); - color_data.push_back(c.b); - color_data.push_back(c.a); - } + for (size_t fi = 0; fi < m->mNumFaces; fi++) { + const aiFace &f = m->mFaces[fi]; + for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) { + const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]]; + color_data.insert(color_data.end(), { c.r, c.g, c.b, c.a }); + } } - FBX::Node::WritePropertyNode( - "Colors", color_data, outstream, binary, indent - ); - indent = 2; - vertexcolors.End(outstream, binary, indent, true); - } + } - // uvs, if any - for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) { - if (m->mNumUVComponents[uvi] > 2) { + const auto num_uv = static_cast(m->GetNumUVChannels()); + uv_indices.resize(std::max(num_uv, uv_indices.size())); + uv_data.resize(std::max(num_uv, uv_data.size())); + std::map index_by_uv; + + // uvs, if any + for (size_t uvi = 0; uvi < m->GetNumUVChannels(); uvi++) { + const auto nc = m->mNumUVComponents[uvi]; + if (nc > 2) { // FBX only supports 2-channel UV maps... // or at least i'm not sure how to indicate a different number std::stringstream err; @@ -1276,71 +1245,112 @@ void FBXExporter::WriteObjects () err << " but may be incorrectly interpreted on load."; ASSIMP_LOG_WARN(err.str()); } - FBX::Node uv("LayerElementUV", int32_t(uvi)); - uv.Begin(outstream, binary, indent); - uv.DumpProperties(outstream, binary, indent); - uv.EndProperties(outstream, binary, indent); - uv.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - // it doesn't seem like assimp keeps the uv map name, - // so just leave it blank. - FBX::Node::WritePropertyNode( - "Name", "", outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "IndexToDirect", - outstream, binary, indent - ); - std::vector uv_data; - std::vector uv_indices; - std::map index_by_uv; - int32_t index = 0; - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiVector3D &curUv = - m->mTextureCoords[uvi][f.mIndices[pvi]]; - auto elem = index_by_uv.find(curUv); - if (elem == index_by_uv.end()) { - index_by_uv[curUv] = index; - uv_indices.push_back(index); - for (unsigned int x = 0; x < m->mNumUVComponents[uvi]; ++x) { - uv_data.push_back(curUv[x]); - } - ++index; - } else { - uv_indices.push_back(elem->second); - } + int32_t index = static_cast(uv_data[uvi].size()) / nc; + for (size_t fi = 0; fi < m->mNumFaces; fi++) { + const aiFace &f = m->mFaces[fi]; + for (size_t pvi = 0; pvi < f.mNumIndices; pvi++) { + const aiVector3D &curUv = m->mTextureCoords[uvi][f.mIndices[pvi]]; + auto elem = index_by_uv.find(curUv); + if (elem == index_by_uv.end()) { + index_by_uv[curUv] = index; + uv_indices[uvi].push_back(index); + for (uint32_t x = 0; x < nc; ++x) { + uv_data[uvi].push_back(curUv[x]); + } + ++index; + } else { + uv_indices[uvi].push_back(elem->second); } + } } - FBX::Node::WritePropertyNode( - "UV", uv_data, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "UVIndex", uv_indices, outstream, binary, indent - ); - indent = 2; - uv.End(outstream, binary, indent, true); + } + } + + + FBX::Node::WritePropertyNode("Vertices", flattened_vertices, outstream, binary, indent); + FBX::Node::WritePropertyNode("PolygonVertexIndex", polygon_data, outstream, binary, indent); + FBX::Node::WritePropertyNode("GeometryVersion", int32_t(124), outstream, binary, indent); + + if (!normal_data.empty()) { + FBX::Node normals("LayerElementNormal", int32_t(0)); + normals.Begin(outstream, binary, indent); + normals.DumpProperties(outstream, binary, indent); + normals.EndProperties(outstream, binary, indent); + normals.BeginChildren(outstream, binary, indent); + indent = 3; + FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent); + FBX::Node::WritePropertyNode("Name", "", outstream, binary, indent); + FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent); + FBX::Node::WritePropertyNode("ReferenceInformationType", "Direct", outstream, binary, indent); + FBX::Node::WritePropertyNode("Normals", normal_data, outstream, binary, indent); + // note: version 102 has a NormalsW also... not sure what it is, + // so stick with version 101 for now. + indent = 2; + normals.End(outstream, binary, indent, true); + } + + if (!color_data.empty()) { + const auto colorChannelIndex = 0; + FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex)); + vertexcolors.Begin(outstream, binary, indent); + vertexcolors.DumpProperties(outstream, binary, indent); + vertexcolors.EndProperties(outstream, binary, indent); + vertexcolors.BeginChildren(outstream, binary, indent); + indent = 3; + FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent); + char layerName[8]; + snprintf(layerName, sizeof(layerName), "COLOR_%d", colorChannelIndex); + FBX::Node::WritePropertyNode("Name", (const char *)layerName, outstream, binary, indent); + FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent); + FBX::Node::WritePropertyNode("ReferenceInformationType", "Direct", outstream, binary, indent); + FBX::Node::WritePropertyNode("Colors", color_data, outstream, binary, indent); + indent = 2; + vertexcolors.End(outstream, binary, indent, true); } - // i'm not really sure why this material section exists, - // as the material is linked via "Connections". - // it seems to always have the same "0" value. + for (uint32_t uvi = 0; uvi < uv_data.size(); uvi++) { + FBX::Node uv("LayerElementUV", int32_t(uvi)); + uv.Begin(outstream, binary, indent); + uv.DumpProperties(outstream, binary, indent); + uv.EndProperties(outstream, binary, indent); + uv.BeginChildren(outstream, binary, indent); + indent = 3; + FBX::Node::WritePropertyNode("Version", int32_t(101), outstream, binary, indent); + FBX::Node::WritePropertyNode("Name", "", outstream, binary, indent); + FBX::Node::WritePropertyNode("MappingInformationType", "ByPolygonVertex", outstream, binary, indent); + FBX::Node::WritePropertyNode("ReferenceInformationType", "IndexToDirect", outstream, binary, indent); + FBX::Node::WritePropertyNode("UV", uv_data[uvi], outstream, binary, indent); + FBX::Node::WritePropertyNode("UVIndex", uv_indices[uvi], outstream, binary, indent); + indent = 2; + uv.End(outstream, binary, indent, true); + } + + + // When merging multiple meshes, we instead use by polygon so the correct material is + // assigned to each face. Previously, this LayerElementMaterial always had 0 since it + // assumed there was 1 material for each node for all meshes. FBX::Node mat("LayerElementMaterial", int32_t(0)); mat.AddChild("Version", int32_t(101)); mat.AddChild("Name", ""); - mat.AddChild("MappingInformationType", "AllSame"); - mat.AddChild("ReferenceInformationType", "IndexToDirect"); - std::vector mat_indices = {0}; - mat.AddChild("Materials", mat_indices); + if (node->mNumMeshes == 1) { + mat.AddChild("MappingInformationType", "AllSame"); + mat.AddChild("ReferenceInformationType", "IndexToDirect"); + std::vector mat_indices = {0}; + mat.AddChild("Materials", mat_indices); + } else { + mat.AddChild("MappingInformationType", "ByPolygon"); + mat.AddChild("ReferenceInformationType", "IndexToDirect"); + std::vector mat_indices; + for (uint32_t n_mi = 0; n_mi < node->mNumMeshes; n_mi++) { + const auto mi = node->mMeshes[n_mi]; + const auto *const m = mScene->mMeshes[mi]; + for (size_t fi = 0; fi < m->mNumFaces; fi++) { + mat_indices.push_back(n_mi); + } + } + mat.AddChild("Materials", mat_indices); + } mat.Dump(outstream, binary, indent); // finally we have the layer specifications, @@ -1348,16 +1358,20 @@ void FBXExporter::WriteObjects () // TODO: handle multiple uv sets correctly? FBX::Node layer("Layer", int32_t(0)); layer.AddChild("Version", int32_t(100)); - FBX::Node le("LayerElement"); - le.AddChild("Type", "LayerElementNormal"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); + FBX::Node le; - for (size_t ci = 0; ci < m->GetNumColorChannels(); ++ci) { - le = FBX::Node("LayerElement"); - le.AddChild("Type", "LayerElementColor"); - le.AddChild("TypedIndex", int32_t(ci)); - layer.AddChild(le); + if (!normal_data.empty()) { + le = FBX::Node("LayerElement"); + le.AddChild("Type", "LayerElementNormal"); + le.AddChild("TypedIndex", int32_t(0)); + layer.AddChild(le); + } + + if (!color_data.empty()) { + le = FBX::Node("LayerElement"); + le.AddChild("Type", "LayerElementColor"); + le.AddChild("TypedIndex", int32_t(0)); + layer.AddChild(le); } le = FBX::Node("LayerElement"); @@ -1370,8 +1384,7 @@ void FBXExporter::WriteObjects () layer.AddChild(le); layer.Dump(outstream, binary, indent); - for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr) - { + for(unsigned int lr = 1; lr < uv_data.size(); ++ lr) { FBX::Node layerExtra("Layer", int32_t(lr)); layerExtra.AddChild("Version", int32_t(100)); FBX::Node leExtra("LayerElement"); @@ -1383,7 +1396,14 @@ void FBXExporter::WriteObjects () // finish the node record indent = 1; n.End(outstream, binary, indent, true); - } + + for (uint32_t ni = 0; ni < node->mNumChildren; ni++) { + visit_node_geo(node->mChildren[ni]); + } + return; + }; + + visit_node_geo(mScene->mRootNode); // aiMaterial @@ -1562,6 +1582,7 @@ void FBXExporter::WriteObjects () } } + std::map tpath_by_image; // FbxVideo - stores images used by textures. for (const auto &it : uid_by_image) { FBX::Node n("Video"); @@ -1581,10 +1602,21 @@ void FBXExporter::WriteObjects () std::stringstream newPath; if (embedded_texture->mFilename.length > 0) { newPath << embedded_texture->mFilename.C_Str(); + // If newPath doesn't end in an extension, add extension from embedded_texture->achFormatHint + std::string np = newPath.str(); + size_t dot_pos = np.find_last_of('.'); + if (dot_pos == std::string::npos || dot_pos < np.find_last_of("/\\")) { + // No extension found, add one + newPath << "." << embedded_texture->achFormatHint; + } } else if (embedded_texture->achFormatHint[0]) { int texture_index = std::stoi(path.substr(1, path.size() - 1)); newPath << texture_index << "." << embedded_texture->achFormatHint; } + auto elem = tpath_by_image.find(path); + if (elem == tpath_by_image.end()) { + tpath_by_image[path] = newPath.str(); + } path = newPath.str(); // embed the texture size_t texture_size = static_cast(embedded_texture->mWidth * std::max(embedded_texture->mHeight, 1u)); @@ -1703,6 +1735,17 @@ void FBXExporter::WriteObjects () unsigned int max = sizeof(aiUVTransform); aiGetMaterialFloatArray(mat, AI_MATKEY_UVTRANSFORM(aiTextureType_DIFFUSE, 0), (ai_real *)&trafo, &max); + auto tp_elem = tpath_by_image.find(texture_path); + std::string tfile_path = texture_path; + if (tp_elem != tpath_by_image.end()) { + tfile_path = tp_elem->second; + } else { + std::stringstream err; + err << "Texture path not found for texure " << texture_path; + err << " on material " << i; + ASSIMP_LOG_WARN(err.str()); + } + // now write the actual texture node FBX::Node tnode("Texture"); // TODO: some way to determine texture name? @@ -1723,8 +1766,8 @@ void FBXExporter::WriteObjects () // can't easily determine which texture path will be correct, // so just store what we have in every field. // these being incorrect is a common problem with FBX anyway. - tnode.AddChild("FileName", texture_path); - tnode.AddChild("RelativeFilename", texture_path); + tnode.AddChild("FileName", tp_elem->second); + tnode.AddChild("RelativeFilename", tp_elem->second); tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0)); tnode.AddChild("ModelUVScaling", double(1.0), double(1.0)); tnode.AddChild("Texture_Alpha_Source", "None"); @@ -1748,7 +1791,8 @@ void FBXExporter::WriteObjects () dnode.AddChild("Version", int32_t(101)); dnode.Dump(outstream, binary, indent); // connect it - connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]); + const auto node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode); + connections.emplace_back("C", "OO", deformer_uid, mesh_uids[node]); std::vector vertex_indices = vVertexIndice[mi]; for (unsigned int am = 0; am < m->mNumAnimMeshes; ++am) { @@ -1758,7 +1802,7 @@ void FBXExporter::WriteObjects () // start the node record FBX::Node bsnode("Geometry"); int64_t blendshape_uid = generate_uid(); - mesh_uids.push_back(blendshape_uid); + blendshape_uids.push_back(blendshape_uid); bsnode.AddProperty(blendshape_uid); bsnode.AddProperty(blendshape_name + FBX::SEPARATOR + "Geometry"); bsnode.AddProperty("Shape"); @@ -1770,23 +1814,25 @@ void FBXExporter::WriteObjects () indent++; if (pAnimMesh->HasPositions()) { std::vectorshape_indices; - std::vectorpPositionDiff; - std::vectorpNormalDiff; + std::vectorpPositionDiff; + std::vectorpNormalDiff; for (unsigned int vt = 0; vt < vertex_indices.size(); ++vt) { aiVector3D pDiff = (pAnimMesh->mVertices[vertex_indices[vt]] - m->mVertices[vertex_indices[vt]]); - if(pDiff.Length()>1e-8){ - shape_indices.push_back(vertex_indices[vt]); - pPositionDiff.push_back(pDiff[0]); - pPositionDiff.push_back(pDiff[1]); - pPositionDiff.push_back(pDiff[2]); - - if (pAnimMesh->HasNormals()) { - aiVector3D nDiff = (pAnimMesh->mNormals[vertex_indices[vt]] - m->mNormals[vertex_indices[vt]]); - pNormalDiff.push_back(nDiff[0]); - pNormalDiff.push_back(nDiff[1]); - pNormalDiff.push_back(nDiff[2]); - } + shape_indices.push_back(vertex_indices[vt]); + pPositionDiff.push_back(pDiff[0]); + pPositionDiff.push_back(pDiff[1]); + pPositionDiff.push_back(pDiff[2]); + + if (pAnimMesh->HasNormals()) { + aiVector3D nDiff = (pAnimMesh->mNormals[vertex_indices[vt]] - m->mNormals[vertex_indices[vt]]); + pNormalDiff.push_back(nDiff[0]); + pNormalDiff.push_back(nDiff[1]); + pNormalDiff.push_back(nDiff[2]); + } else { + pNormalDiff.push_back(0.0); + pNormalDiff.push_back(0.0); + pNormalDiff.push_back(0.0); } } @@ -1943,22 +1989,15 @@ void FBXExporter::WriteObjects () // otherwise check if this is the root of the skeleton bool end = false; // is the mesh part of this node? - for (size_t i = 0; i < parent->mNumMeshes; ++i) { - if (parent->mMeshes[i] == mi) { - end = true; - break; - } + for (size_t i = 0; i < parent->mNumMeshes && !end; ++i) { + end |= parent->mMeshes[i] == mi; } // is the mesh in one of the children of this node? - for (size_t j = 0; j < parent->mNumChildren; ++j) { + for (size_t j = 0; j < parent->mNumChildren && !end; ++j) { aiNode* child = parent->mChildren[j]; - for (size_t i = 0; i < child->mNumMeshes; ++i) { - if (child->mMeshes[i] == mi) { - end = true; - break; - } + for (size_t i = 0; i < child->mNumMeshes && !end; ++i) { + end |= child->mMeshes[i] == mi; } - if (end) { break; } } // if it was the skeleton root we can finish here @@ -1972,8 +2011,7 @@ void FBXExporter::WriteObjects () for (size_t i = 0; i < mScene->mNumMeshes; ++i) { auto &s = skeleton_by_mesh[i]; for (const aiNode* n : s) { - auto elem = node_uids.find(n); - if (elem == node_uids.end()) { + if (node_uids.find(n) == node_uids.end()) { node_uids[n] = generate_uid(); } } @@ -1989,6 +2027,8 @@ void FBXExporter::WriteObjects () if (!m->HasBones()) { continue; } + + const aiNode *mesh_node = get_node_for_mesh((uint32_t)mi, mScene->mRootNode); // make a deformer for this mesh int64_t deformer_uid = generate_uid(); FBX::Node dnode("Deformer"); @@ -2000,10 +2040,7 @@ void FBXExporter::WriteObjects () dnode.Dump(outstream, binary, indent); // connect it - connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]); - - //computed before - std::vector& vertex_indices = vVertexIndice[mi]; + connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mesh_node]); // TODO, FIXME: this won't work if anything is not in the bind pose. // for now if such a situation is detected, we throw an exception. @@ -2017,7 +2054,6 @@ void FBXExporter::WriteObjects () // as it can be instanced to many nodes. // All we can do is assume no instancing, // and take the first node we find that contains the mesh. - aiNode* mesh_node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode); aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene); // now make a subdeformer for each bone in the skeleton @@ -2046,14 +2082,19 @@ void FBXExporter::WriteObjects () sdnode.AddChild("Version", int32_t(100)); sdnode.AddChild("UserData", "", ""); - std::set setWeightedVertex; // add indices and weights, if any if (b) { + std::set setWeightedVertex; std::vector subdef_indices; std::vector subdef_weights; int32_t last_index = -1; for (size_t wi = 0; wi < b->mNumWeights; ++wi) { - int32_t vi = vertex_indices[b->mWeights[wi].mVertexId]; + if (b->mWeights[wi].mVertexId >= vVertexIndice[mi].size()) { + ASSIMP_LOG_ERROR("UNREAL: Skipping vertex index to prevent buffer overflow."); + continue; + } + int32_t vi = vVertexIndice[mi][b->mWeights[wi].mVertexId] + + uniq_v_before_mi[mi]; bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end()); if (vi == last_index || bIsWeightedAlready) { // only for vertices we exported to fbx @@ -2533,9 +2574,9 @@ void add_meta(FBX::Node& fbx_node, const aiNode* node){ default: break; } - + } - + } // write a single model node to the stream @@ -2700,9 +2741,8 @@ void FBXExporter::WriteModelNodes( // handled later } else if (node->mNumMeshes == 1) { // connect to child mesh, which should have been written previously - connections.emplace_back( - "C", "OO", mesh_uids[node->mMeshes[0]], node_uid - ); + // TODO double check this line + connections.emplace_back("C", "OO", mesh_uids[node], node_uid); // also connect to the material for the child mesh connections.emplace_back( "C", "OO", @@ -2727,6 +2767,16 @@ void FBXExporter::WriteModelNodes( na.Dump(outstream, binary, 1); // and connect them connections.emplace_back("C", "OO", node_attribute_uid, node_uid); + } else if (node->mNumMeshes >= 1) { + connections.emplace_back("C", "OO", mesh_uids[node], node_uid); + for (size_t i = 0; i < node->mNumMeshes; i++) { + connections.emplace_back( + "C", "OO", + material_uids[mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex], + node_uid + ); + } + WriteModelNode(outstream, binary, node, node_uid, "Mesh", transform_chain); } else { const auto& lightIt = lights_uids.find(node->mName.C_Str()); if(lightIt != lights_uids.end()) { @@ -2743,34 +2793,20 @@ void FBXExporter::WriteModelNodes( } } - // if more than one child mesh, make nodes for each mesh - if (node->mNumMeshes > 1 || node == mScene->mRootNode) { - for (size_t i = 0; i < node->mNumMeshes; ++i) { - // make a new model node - int64_t new_node_uid = generate_uid(); - // connect to parent node - connections.emplace_back("C", "OO", new_node_uid, node_uid); - // connect to child mesh, which should have been written previously - connections.emplace_back( - "C", "OO", mesh_uids[node->mMeshes[i]], new_node_uid - ); - // also connect to the material for the child mesh - connections.emplace_back( - "C", "OO", - material_uids[ - mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex - ], - new_node_uid - ); - - aiNode new_node; - // take name from mesh name, if it exists - new_node.mName = mScene->mMeshes[node->mMeshes[i]]->mName; - // write model node - WriteModelNode( - outstream, binary, &new_node, new_node_uid, "Mesh", std::vector>() - ); - } + if (node == mScene->mRootNode && node->mNumMeshes > 0) { + int64_t new_node_uid = generate_uid(); + connections.emplace_back("C", "OO", new_node_uid, node_uid); + connections.emplace_back("C", "OO", mesh_uids[node], new_node_uid); + for (size_t i = 0; i < node->mNumMeshes; ++i) { + connections.emplace_back( + "C", "OO", + material_uids[mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex], + new_node_uid + ); + } + aiNode new_node; + new_node.mName = mScene->mMeshes[0]->mName; + WriteModelNode(outstream, binary, &new_node, new_node_uid, "Mesh", {}); } // now recurse into children diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXExporter.h b/Dependencies/assimp/code/AssetLib/FBX/FBXExporter.h index df9029196..61c20b5dc 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXExporter.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXCommon.h" // FBX::TransformInheritance #include -//#include #include // StreamWriterLE #include // DeadlyExportError @@ -91,7 +90,8 @@ namespace Assimp { std::vector connections; // connection storage - std::vector mesh_uids; + std::map mesh_uids; + std::vector blendshape_uids; std::vector material_uids; std::map node_uids; std::map lights_uids; diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXImportSettings.h b/Dependencies/assimp/code/AssetLib/FBX/FBXImportSettings.h index 74290f7e0..c38a563b2 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXImportSettings.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXImportSettings.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -156,6 +156,9 @@ struct ImportSettings { /** Set to true to perform a conversion from cm to meter after the import */ bool convertToMeters; + + // Set to true to ignore the axis configuration in the file + bool ignoreUpDirection = false; }; } // namespace FBX diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXImporter.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXImporter.cpp index 3a8fb8b8a..13e6f4c31 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXImporter.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -117,6 +117,7 @@ void FBXImporter::SetupProperties(const Importer *pImp) { mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false); mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true); mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false); + mSettings.ignoreUpDirection = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_IGNORE_UP_DIRECTION, false); mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false); } diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXImporter.h b/Dependencies/assimp/code/AssetLib/FBX/FBXImporter.h index 8e8a7db78..0e4cad476 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXImporter.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -67,7 +67,7 @@ typedef class basic_formatter, std::allocator /// /// See http://en.wikipedia.org/wiki/FBX // ------------------------------------------------------------------------------------------- -class FBXImporter : public BaseImporter, public LogFunctions { +class FBXImporter final : public BaseImporter, public LogFunctions { public: /// @brief The class constructor. FBXImporter() = default; diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXMaterial.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXMaterial.cpp index 3872a4b38..d79a0e8ab 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXMaterial.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -134,10 +134,6 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con } } - -// ------------------------------------------------------------------------------------------------ -Material::~Material() = default; - // ------------------------------------------------------------------------------------------------ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) : Object(id,element,name), diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXMeshGeometry.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXMeshGeometry.cpp index 67488f53a..dc8303db7 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXMeshGeometry.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXMeshGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -685,11 +685,14 @@ ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::str DOMError("failed to read Geometry object (class: Shape), no data scope found"); } const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element); - const Element& Normals = GetRequiredElement(*sc, "Normals", &element); const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element); ParseVectorDataArray(m_indices, Indexes); ParseVectorDataArray(m_vertices, Vertices); - ParseVectorDataArray(m_normals, Normals); + + if ((*sc)["Normals"]) { + const Element& Normals = GetRequiredElement(*sc, "Normals", &element); + ParseVectorDataArray(m_normals, Normals); + } } // ------------------------------------------------------------------------------------------------ diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXMeshGeometry.h b/Dependencies/assimp/code/AssetLib/FBX/FBXMeshGeometry.h index 980d1a334..c7817b8d6 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXMeshGeometry.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXMeshGeometry.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXModel.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXModel.cpp index c108dd78b..131a1f630 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXModel.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXModel.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXNodeAttribute.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXNodeAttribute.cpp index 1e7dfa8c0..0195fb745 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXNodeAttribute.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXNodeAttribute.cpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXParser.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXParser.cpp index d0482e067..98583cfe9 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXParser.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -365,10 +365,14 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out) } if (data[0] == 'F') { - return SafeParse(data+1, t.end()); + BE_NCONST float id = SafeParse(data+1, t.end()); + AI_SWAP4(id); + return id; } else { - return static_cast( SafeParse(data+1, t.end()) ); + BE_NCONST double id = SafeParse(data+1, t.end()); + AI_SWAP8(id); + return static_cast(id); } } @@ -637,9 +641,15 @@ void ParseVectorDataArray(std::vector& out, const Element& el) if (type == 'd') { const double* d = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count3; ++i, d += 3) { - out.emplace_back(static_cast(d[0]), - static_cast(d[1]), - static_cast(d[2])); + BE_NCONST double val1 = d[0]; + BE_NCONST double val2 = d[1]; + BE_NCONST double val3 = d[2]; + AI_SWAP8(val1); + AI_SWAP8(val2); + AI_SWAP8(val3); + out.emplace_back(static_cast(val1), + static_cast(val2), + static_cast(val3)); } // for debugging /*for ( size_t i = 0; i < out.size(); i++ ) { @@ -652,7 +662,13 @@ void ParseVectorDataArray(std::vector& out, const Element& el) else if (type == 'f') { const float* f = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count3; ++i, f += 3) { - out.emplace_back(f[0],f[1],f[2]); + BE_NCONST float val1 = f[0]; + BE_NCONST float val2 = f[1]; + BE_NCONST float val3 = f[2]; + AI_SWAP4(val1); + AI_SWAP4(val2); + AI_SWAP4(val3); + out.emplace_back(val1,val2,val3); } } @@ -726,16 +742,32 @@ void ParseVectorDataArray(std::vector& out, const Element& el) if (type == 'd') { const double* d = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count4; ++i, d += 4) { - out.emplace_back(static_cast(d[0]), - static_cast(d[1]), - static_cast(d[2]), - static_cast(d[3])); + BE_NCONST double val1 = d[0]; + BE_NCONST double val2 = d[1]; + BE_NCONST double val3 = d[2]; + BE_NCONST double val4 = d[3]; + AI_SWAP8(val1); + AI_SWAP8(val2); + AI_SWAP8(val3); + AI_SWAP8(val4); + out.emplace_back(static_cast(val1), + static_cast(val2), + static_cast(val3), + static_cast(val4)); } } else if (type == 'f') { const float* f = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count4; ++i, f += 4) { - out.emplace_back(f[0],f[1],f[2],f[3]); + BE_NCONST float val1 = f[0]; + BE_NCONST float val2 = f[1]; + BE_NCONST float val3 = f[2]; + BE_NCONST float val4 = f[3]; + AI_SWAP4(val1); + AI_SWAP4(val2); + AI_SWAP4(val3); + AI_SWAP4(val4); + out.emplace_back(val1,val2,val3,val4); } } return; @@ -807,13 +839,21 @@ void ParseVectorDataArray(std::vector& out, const Element& el) { if (type == 'd') { const double* d = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count2; ++i, d += 2) { - out.emplace_back(static_cast(d[0]), - static_cast(d[1])); + BE_NCONST double val1 = d[0]; + BE_NCONST double val2 = d[1]; + AI_SWAP8(val1); + AI_SWAP8(val2); + out.emplace_back(static_cast(val1), + static_cast(val2)); } } else if (type == 'f') { const float* f = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count2; ++i, f += 2) { - out.emplace_back(f[0],f[1]); + BE_NCONST float val1 = f[0]; + BE_NCONST float val2 = f[1]; + AI_SWAP4(val1); + AI_SWAP4(val2); + out.emplace_back(val1,val2); } } @@ -938,13 +978,17 @@ void ParseVectorDataArray(std::vector& out, const Element& el) if (type == 'd') { const double* d = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count; ++i, ++d) { - out.push_back(static_cast(*d)); + BE_NCONST double val = *d; + AI_SWAP8(val); + out.push_back(static_cast(val)); } } else if (type == 'f') { const float* f = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count; ++i, ++f) { - out.push_back(*f); + BE_NCONST float val = *f; + AI_SWAP4(val); + out.push_back(val); } } diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXParser.h b/Dependencies/assimp/code/AssetLib/FBX/FBXParser.h index 2ca216d8c..72911e5ca 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXParser.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -64,7 +64,7 @@ class Parser; class Element; using ScopeList = std::vector; -using ElementMap = std::fbx_unordered_multimap< std::string, Element*>; +using ElementMap = std::multimap< std::string, Element*>; using ElementCollection = std::pair; #define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope @@ -82,10 +82,9 @@ using ElementCollection = std::pair= 2); @@ -146,9 +141,9 @@ Property* ReadTypedProperty(const Element& element) // ------------------------------------------------------------------------------------------------ // peek into an element and check if it contains a FBX property, if so return its name. -std::string PeekPropertyName(const Element& element) -{ +std::string PeekPropertyName(const Element& element) { ai_assert(element.KeyToken().StringContents() == "P"); + const TokenList& tok = element.Tokens(); if(tok.size() < 4) { return std::string(); @@ -160,13 +155,6 @@ std::string PeekPropertyName(const Element& element) } //! anon -// ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable() -: templateProps() -, element() -{ -} - // ------------------------------------------------------------------------------------------------ PropertyTable::PropertyTable(const Element &element, std::shared_ptr templateProps) : templateProps(std::move(templateProps)), element(&element) { diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXProperties.h b/Dependencies/assimp/code/AssetLib/FBX/FBXProperties.h index 4799b8056..1621c4015 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXProperties.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXProperties.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -56,34 +55,33 @@ namespace FBX { // Forward declarations class Element; -/** Represents a dynamic property. Type info added by deriving classes, - * see #TypedProperty. - Example: - @verbatim - P: "ShininessExponent", "double", "Number", "",0.5 - @endvebatim -*/ +/** + * Represents a dynamic property. Type info added by deriving classes, + * see #TypedProperty. + * Example: + * + * @verbatim + * P: "ShininessExponent", "double", "Number", "",0.5 + * @endvebatim + */ class Property { -protected: - Property(); public: - virtual ~Property(); + virtual ~Property() = default; -public: template const T* As() const { return dynamic_cast(this); } + +protected: + Property() = default; }; template class TypedProperty : public Property { public: - explicit TypedProperty(const T& value) - : value(value) { - // empty - } + explicit TypedProperty(const T& value) : value(value) {} const T& Value() const { return value; @@ -93,10 +91,9 @@ class TypedProperty : public Property { T value; }; - -typedef std::fbx_unordered_map > DirectPropertyMap; -typedef std::fbx_unordered_map PropertyMap; -typedef std::fbx_unordered_map LazyPropertyMap; +using DirectPropertyMap = std::fbx_unordered_map >; +using PropertyMap = std::fbx_unordered_map; +using LazyPropertyMap = std::fbx_unordered_map; /** * Represents a property table as can be found in the newer FBX files (Properties60, Properties70) @@ -104,7 +101,7 @@ typedef std::fbx_unordered_map LazyPrope class PropertyTable { public: // in-memory property table with no source element - PropertyTable(); + PropertyTable() : element() {} PropertyTable(const Element& element, std::shared_ptr templateProps); ~PropertyTable(); @@ -130,8 +127,7 @@ class PropertyTable { // ------------------------------------------------------------------------------------------------ template -inline -T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) { +inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) { const Property* const prop = in.Get(name); if( nullptr == prop) { return defaultValue; @@ -148,8 +144,7 @@ T PropertyGet(const PropertyTable& in, const std::string& name, const T& default // ------------------------------------------------------------------------------------------------ template -inline -T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) { +inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) { const Property* prop = in.Get(name); if( nullptr == prop) { if ( ! useTemplate ) { diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXTokenizer.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXTokenizer.cpp index 007e08d46..0a53051d2 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXTokenizer.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXTokenizer.cpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXTokenizer.h b/Dependencies/assimp/code/AssetLib/FBX/FBXTokenizer.h index dedfab66a..962d5d9db 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXTokenizer.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXTokenizer.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXUtil.cpp b/Dependencies/assimp/code/AssetLib/FBX/FBXUtil.cpp index a787a9f1d..3089e8564 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXUtil.cpp +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXUtil.cpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,11 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -namespace Assimp { -namespace FBX { -namespace Util { +namespace Assimp::FBX::Util { // ------------------------------------------------------------------------------------------------ const char* TokenTypeString(TokenType t) @@ -234,8 +229,5 @@ std::string EncodeBase64(const char* data, size_t length) return encoded_string; } -} // !Util -} // !FBX -} // !Assimp +} // namespace Assimp::FBX::Util -#endif diff --git a/Dependencies/assimp/code/AssetLib/FBX/FBXUtil.h b/Dependencies/assimp/code/AssetLib/FBX/FBXUtil.h index eb9ae14ed..191cb8075 100644 --- a/Dependencies/assimp/code/AssetLib/FBX/FBXUtil.h +++ b/Dependencies/assimp/code/AssetLib/FBX/FBXUtil.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -50,12 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXTokenizer.h" #include -namespace Assimp { -namespace FBX { - - -namespace Util { - +namespace Assimp::FBX::Util { /** helper for std::for_each to delete all heap-allocated items in a container */ template @@ -76,19 +70,15 @@ struct destructor_fun { } }; - /** Get a string representation for a #TokenType. */ const char* TokenTypeString(TokenType t); - - /** Format log/error messages using a given offset in the source binary file * * @param offset offset within the file * @return A string of the following format: " (offset 0x{offset}) "*/ std::string GetOffsetText(size_t offset); - /** Format log/error messages using a given line location in the source file. * * @param line Line index, 1-based @@ -96,7 +86,6 @@ std::string GetOffsetText(size_t offset); * @return A string of the following format: " (line {line}, col {column}) "*/ std::string GetLineAndColumnText(unsigned int line, unsigned int column); - /** Format log/error messages using a given cursor token. * * @param tok Token where parsing/processing stopped @@ -134,8 +123,6 @@ char EncodeBase64(char byte); * @return base64-encoded string*/ std::string EncodeBase64(const char* data, size_t length); -} -} } #endif // ! INCLUDED_AI_FBX_UTIL_H diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjExporter.cpp b/Dependencies/assimp/code/AssetLib/Obj/ObjExporter.cpp index 7c5c051f3..dc83c5b78 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjExporter.cpp +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjExporter.cpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2020, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -174,9 +173,12 @@ void ObjExporter::WriteHeader(std::ostringstream& out) { // ------------------------------------------------------------------------------------------------ std::string ObjExporter::GetMaterialName(unsigned int index) { + static const std::string EmptyStr; + if ( nullptr == pScene->mMaterials ) { + return EmptyStr; + } const aiMaterial* const mat = pScene->mMaterials[index]; if ( nullptr == mat ) { - static const std::string EmptyStr; return EmptyStr; } @@ -393,9 +395,12 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4 // ------------------------------------------------------------------------------------------------ void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent, bool merge_identical_vertices) { + if (nd == nullptr) { + return; + } + const aiMatrix4x4& mAbs = mParent * nd->mTransformation; - - aiMesh *cm( nullptr ); + aiMesh *cm{nullptr}; for(unsigned int i = 0; i < nd->mNumMeshes; ++i) { cm = pScene->mMeshes[nd->mMeshes[i]]; if (nullptr != cm) { diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjExporter.h b/Dependencies/assimp/code/AssetLib/Obj/ObjExporter.h index 4c92aa16f..993a9ac12 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjExporter.h +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2020, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -62,7 +62,7 @@ namespace Assimp { // ------------------------------------------------------------------------------------------------ /** Helper class to export a given scene to an OBJ file. */ // ------------------------------------------------------------------------------------------------ -class ObjExporter { +class ObjExporter final { public: /// Constructor for a specific scene to export ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false, const ExportProperties* props = nullptr); diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjFileData.h b/Dependencies/assimp/code/AssetLib/Obj/ObjFileData.h index 205c855e5..9cfd3de38 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjFileData.h +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -165,21 +165,23 @@ struct Material { //! Ambient color aiColor3D ambient; //! Diffuse color - aiColor3D diffuse; + aiColor3D diffuse = aiColor3D(0.6f, 0.6f, 0.6f); //! Specular color aiColor3D specular; //! Emissive color aiColor3D emissive; //! Alpha value - ai_real alpha; + ai_real alpha = ai_real(1.0); //! Shineness factor - ai_real shineness; + ai_real shineness = ai_real(0.0); //! Illumination model - int illumination_model; + int illumination_model = 1; //! Index of refraction - ai_real ior; + ai_real ior = ai_real(1.0); //! Transparency color - aiColor3D transparent; + aiColor3D transparent = aiColor3D(1.0f, 1.0f, 1.0f); + //! Ambient occlusion + Maybe ambient_occlusion; //! PBR Roughness Maybe roughness; @@ -187,31 +189,33 @@ struct Material { Maybe metallic; //! PBR Metallic Maybe sheen; + //! PBR Sheen: an additional grazing component, primarily intended for cloth. + Maybe sheen_grazing; + //! PBR Sheen Tint: amount to tint sheen towards base color. + Maybe sheen_tint; + //! PBR Clearcoat + Maybe clearcoat; //! PBR Clearcoat Thickness Maybe clearcoat_thickness; //! PBR Clearcoat Rougness Maybe clearcoat_roughness; + //! PBR clearcoatGloss: controls clearcoat glossiness (0 = a “satin” appearance, 1 = a “gloss” appearance). + Maybe clearcoat_gloss; //! PBR Anisotropy - ai_real anisotropy; - - //! bump map multipler (normal map scalar)(-bm) - ai_real bump_multiplier; + ai_real anisotropy = ai_real(0.0); + //! PBR Anisotropy Rotation + Maybe anisotropy_rotation; + //! PBR Subsurface Scattering + Maybe subsurface_scattering; + //! PBR Specular Tint: a concession for artistic control that tints incident specular towards the base color. + Maybe specular_tint; + // See: https://disneyanimation.com/publications/physically-based-shading-at-disney/ + + //! bump map multiplier (normal map scalar)(-bm) + ai_real bump_multiplier = ai_real(1.0); //! Constructor - Material() : - diffuse(0.6f, 0.6f, 0.6f), - alpha(ai_real(1.0)), - shineness(ai_real(0.0)), - illumination_model(1), - ior(ai_real(1.0)), - transparent(1.0f, 1.0, 1.0), - roughness(), - metallic(), - sheen(), - clearcoat_thickness(), - clearcoat_roughness(), - anisotropy(ai_real(0.0)), - bump_multiplier(ai_real(1.0)) { + Material() { std::fill_n(clamp, static_cast(TextureTypeCount), false); } diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjFileImporter.cpp b/Dependencies/assimp/code/AssetLib/Obj/ObjFileImporter.cpp index 09aa84c22..76af1b34b 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjFileImporter.cpp +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -67,7 +67,7 @@ static constexpr aiImporterDesc desc = { "obj" }; -static const unsigned int ObjMinSize = 16; +static constexpr unsigned int ObjMinSize = 16u; namespace Assimp { @@ -163,7 +163,7 @@ void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, I // ------------------------------------------------------------------------------------------------ // Create the data from parsed obj-file void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene *pScene) { - if (nullptr == pModel) { + if (pModel == nullptr) { return; } @@ -178,7 +178,6 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene } if (!pModel->mObjects.empty()) { - unsigned int meshCount = 0; unsigned int childCount = 0; @@ -258,8 +257,7 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile::Object *pObject, aiNode *pParent, aiScene *pScene, std::vector> &MeshArray) { - ai_assert(nullptr != pModel); - if (nullptr == pObject) { + if (nullptr == pObject || pModel == nullptr) { return nullptr; } @@ -311,16 +309,13 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model *pModel, const ObjFile // ------------------------------------------------------------------------------------------------ // Create topology data std::unique_ptr ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, unsigned int meshIndex) { - // Checking preconditions - ai_assert(nullptr != pModel); - - if (nullptr == pData) { + if (nullptr == pData || pModel == nullptr) { return nullptr; } // Create faces ObjFile::Mesh *pObjMesh = pModel->mMeshes[meshIndex]; - if (!pObjMesh) { + if (pObjMesh == nullptr) { return nullptr; } @@ -335,6 +330,9 @@ std::unique_ptr ObjFileImporter::createTopology(const ObjFile::Model *pM for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) { const ObjFile::Face *inp = pObjMesh->m_Faces[index]; + if (inp == nullptr) { + continue; + } if (inp->mPrimitiveType == aiPrimitiveType_LINE) { pMesh->mNumFaces += static_cast(inp->m_vertices.size() - 1); @@ -352,14 +350,14 @@ std::unique_ptr ObjFileImporter::createTopology(const ObjFile::Model *pM } } - unsigned int uiIdxCount(0u); + unsigned int uiIdxCount = 0u; if (pMesh->mNumFaces > 0) { pMesh->mFaces = new aiFace[pMesh->mNumFaces]; if (pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial) { pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex; } - unsigned int outIndex(0); + unsigned int outIndex = 0u; // Copy all data from all stored meshes for (auto &face : pObjMesh->m_Faces) { @@ -403,11 +401,14 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel, aiMesh *pMesh, unsigned int numIndices) { // Checking preconditions - ai_assert(nullptr != pCurrentObject); + if (pCurrentObject == nullptr || pModel == nullptr || pMesh == nullptr) { + return; + } // Break, if no faces are stored in object - if (pCurrentObject->m_Meshes.empty()) + if (pCurrentObject->m_Meshes.empty()) { return; + } // Get current mesh ObjFile::Mesh *pObjMesh = pModel->mMeshes[uiMeshIndex]; @@ -586,11 +587,12 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc it = pModel->mMaterialMap.find(pModel->mMaterialLib[matIndex]); // No material found, use the default material - if (pModel->mMaterialMap.end() == it) + if (pModel->mMaterialMap.end() == it) { continue; + } aiMaterial *mat = new aiMaterial; - ObjFile::Material *pCurrentMaterial = (*it).second; + ObjFile::Material *pCurrentMaterial = it->second; mat->AddProperty(&pCurrentMaterial->MaterialName, AI_MATKEY_NAME); // convert illumination model @@ -777,8 +779,11 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc // Appends this node to the parent node void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild) { // Checking preconditions - ai_assert(nullptr != pParent); - ai_assert(nullptr != pChild); + if (pParent == nullptr || pChild == nullptr) { + ai_assert(nullptr != pParent); + ai_assert(nullptr != pChild); + return; + } // Assign parent to child pChild->mParent = pParent; diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjFileImporter.h b/Dependencies/assimp/code/AssetLib/Obj/ObjFileImporter.h index 6768013e4..6923984e9 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjFileImporter.h +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjFileImporter.h @@ -61,7 +61,7 @@ struct Model; /// \class ObjFileImporter /// \brief Imports a waveform obj file // ------------------------------------------------------------------------------------------------ -class ObjFileImporter : public BaseImporter { +class ObjFileImporter final : public BaseImporter { public: /// \brief Default constructor ObjFileImporter(); diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjFileMtlImporter.cpp b/Dependencies/assimp/code/AssetLib/Obj/ObjFileMtlImporter.cpp index effdf627f..8e864f510 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjFileMtlImporter.cpp +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjFileMtlImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2020, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ObjFileMtlImporter.h" #include "ObjFileData.h" #include "ObjTools.h" +#include #include #include #include @@ -89,8 +90,9 @@ static constexpr char TypeOption[] = "-type"; // ------------------------------------------------------------------- // Constructor ObjFileMtlImporter::ObjFileMtlImporter(std::vector &buffer, - const std::string &, + const std::string &strAbsPath, ObjFile::Model *pModel) : + m_strAbsPath(strAbsPath), m_DataIt(buffer.begin()), m_DataItEnd(buffer.end()), m_pModel(pModel), @@ -103,13 +105,23 @@ ObjFileMtlImporter::ObjFileMtlImporter(std::vector &buffer, m_pModel->mDefaultMaterial = new ObjFile::Material; m_pModel->mDefaultMaterial->MaterialName.Set("default"); } + + // Try with OS folder separator first + char folderSeparator = DefaultIOSystem().getOsSeparator(); + std::size_t found = m_strAbsPath.find_last_of(folderSeparator); + if (found == std::string::npos) { + // Not found, try alternative folder separator + folderSeparator = (folderSeparator == '/' ? '\\' : '/'); + found = m_strAbsPath.find_last_of(folderSeparator); + } + if (found != std::string::npos) { + m_strAbsPath = m_strAbsPath.substr(0, found + 1); + } else { + m_strAbsPath = ""; + } load(); } -// ------------------------------------------------------------------- -// Destructor -ObjFileMtlImporter::~ObjFileMtlImporter() = default; - // ------------------------------------------------------------------- // Loads the material description void ObjFileMtlImporter::load() { @@ -223,24 +235,64 @@ void ObjFileMtlImporter::load() { ++m_DataIt; if (m_pModel->mCurrentMaterial != nullptr) getFloatValue(m_pModel->mCurrentMaterial->clearcoat_roughness); - } else { + } else if (*m_DataIt == 't') { + ++m_DataIt; if (m_pModel->mCurrentMaterial != nullptr) getFloatValue(m_pModel->mCurrentMaterial->clearcoat_thickness); + } else { + if (m_pModel->mCurrentMaterial != nullptr) + getFloatValue(m_pModel->mCurrentMaterial->clearcoat); } break; } m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); } break; + + case 'm': // Texture or metallic + { + // Save start of token (after 'm') + auto tokenStart = m_DataIt; // points to 'm' + auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd); // move iterator to end of token + + std::string keyword(tokenStart, tokenEnd); + m_DataIt = getNextWord(tokenEnd, m_DataItEnd); // advance iterator + + if (keyword.compare(0, 3, "map") == 0) { + // starts with "map", treat as texture map + m_DataIt = tokenStart; + getTexture(); + } else if (keyword == "metallic" || keyword == "metal" || keyword == "metalness") { + // parse metallic float value instead of texture + getFloatIfMaterialValid(&ObjFile::Material::metallic); + } + + m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); + } break; - case 'm': // Texture case 'b': // quick'n'dirty - for 'bump' sections - case 'r': // quick'n'dirty - for 'refl' sections { getTexture(); m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); } break; + case 'r': // refl (map) or roughness (float) + { + auto tokenStart = m_DataIt; // points to 'r' + auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd); + std::string keyword(tokenStart, tokenEnd); + m_DataIt = getNextWord(tokenEnd, m_DataItEnd); + + if (keyword == "roughness" || keyword == "rough") { + getFloatIfMaterialValid(&ObjFile::Material::roughness); + } else if (keyword == "refl" || keyword == "reflection") { + m_DataIt = tokenStart; + getTexture(); + } + + m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); + } break; + case 'i': // Illumination model { m_DataIt = getNextToken(m_DataIt, m_DataItEnd); @@ -249,11 +301,60 @@ void ObjFileMtlImporter::load() { m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); } break; - case 'a': // Anisotropy - { - ++m_DataIt; - if (m_pModel->mCurrentMaterial != nullptr) - getFloatValue(m_pModel->mCurrentMaterial->anisotropy); + case 'a': { + auto tokenStart = m_DataIt; + auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd); + std::string keyword(tokenStart, tokenEnd); + m_DataIt = getNextWord(tokenEnd, m_DataItEnd); + + if (keyword == "aniso" || keyword == "anisotropy") { + getFloatIfMaterialValid(&ObjFile::Material::anisotropy); + } else if (keyword == "ao") { + getFloatIfMaterialValid(&ObjFile::Material::ambient_occlusion); + } else if (keyword == "anisor" || ai_stdStrToLower(keyword) == "anisotropicrotation") { + getFloatIfMaterialValid(&ObjFile::Material::anisotropy_rotation); + } else { + ASSIMP_LOG_WARN("Unhandled keyword: ", keyword ); + } + + m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); + } break; + + case 's': { + auto tokenStart = m_DataIt; + auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd); + std::string keyword(tokenStart, tokenEnd); + m_DataIt = getNextWord(tokenEnd,m_DataItEnd); + + if (keyword == "subsurface" || keyword == "scattering") { + getFloatIfMaterialValid(&ObjFile::Material::subsurface_scattering); + } else if (ai_stdStrToLower(keyword) == "speculartint") { + getFloatIfMaterialValid(&ObjFile::Material::specular_tint); + } else if (keyword == "sheen") { + getFloatIfMaterialValid(&ObjFile::Material::sheen_grazing); + } else if (ai_stdStrToLower(keyword) == "sheentint") { + getFloatIfMaterialValid(&ObjFile::Material::sheen_tint); + } else { + ASSIMP_LOG_WARN("Unhandled keyword: ", keyword ); + } + + m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); + } break; + + case 'c': { + auto tokenStart = m_DataIt; + auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd); + std::string keyword(tokenStart, tokenEnd); + m_DataIt = getNextWord(tokenEnd, m_DataItEnd); + + if (ai_stdStrToLower(keyword) == "clearcoat") { + getFloatIfMaterialValid(&ObjFile::Material::clearcoat); + } else if (ai_stdStrToLower(keyword) == "clearcoatgloss") { + getFloatIfMaterialValid(&ObjFile::Material::clearcoat_gloss); + } else { + ASSIMP_LOG_WARN("Unhandled keyword: ", keyword ); + } + m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); } break; @@ -320,6 +421,23 @@ void ObjFileMtlImporter::getFloatValue(Maybe &value) { value = Maybe(); } +// ------------------------------------------------------------------- +// Writes a loaded single float value if material not null +void ObjFileMtlImporter::getFloatIfMaterialValid(ai_real ObjFile::Material::*member) { + if (m_pModel != nullptr && m_pModel->mCurrentMaterial != nullptr) { + // This will call getFloatValue(ai_real&) + getFloatValue(m_pModel->mCurrentMaterial->*member); + } +} + +// ------------------------------------------------------------------- +void ObjFileMtlImporter::getFloatIfMaterialValid(Maybe ObjFile::Material::*member) { + // It can directly access `m_pModel` because it's part of the class + if (m_pModel != nullptr && m_pModel->mCurrentMaterial != nullptr) { + getFloatValue(m_pModel->mCurrentMaterial->*member); + } +} + // ------------------------------------------------------------------- // Creates a material from loaded data. void ObjFileMtlImporter::createMaterial() { @@ -446,7 +564,7 @@ void ObjFileMtlImporter::getTexture() { std::string texture; m_DataIt = getName(m_DataIt, m_DataItEnd, texture); if (nullptr != out) { - out->Set(texture); + out->Set(m_strAbsPath + texture); } } diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjFileMtlImporter.h b/Dependencies/assimp/code/AssetLib/Obj/ObjFileMtlImporter.h index 6e73cf45c..bc44b4546 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjFileMtlImporter.h +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjFileMtlImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2020, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -71,13 +71,12 @@ class ObjFileMtlImporter { ObjFile::Model *pModel); //! \brief The class destructor - ~ObjFileMtlImporter(); + ~ObjFileMtlImporter() = default; ObjFileMtlImporter(const ObjFileMtlImporter &rOther) = delete; ObjFileMtlImporter &operator=(const ObjFileMtlImporter &rOther) = delete; private: - /// Copy constructor, empty. /// Load the whole material description void load(); /// Get color data. @@ -88,6 +87,8 @@ class ObjFileMtlImporter { /// Gets a float value from data. void getFloatValue(ai_real &value); void getFloatValue(Maybe &value); + void getFloatIfMaterialValid(ai_real ObjFile::Material::*member); + void getFloatIfMaterialValid(Maybe ObjFile::Material::*member); /// Creates a new material from loaded data. void createMaterial(); /// Get texture name from loaded data. @@ -109,8 +110,6 @@ class ObjFileMtlImporter { std::vector m_buffer; }; -// ------------------------------------------------------------------------------------------------ - } // Namespace Assimp #endif // OBJFILEMTLIMPORTER_H_INC diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjFileParser.cpp b/Dependencies/assimp/code/AssetLib/Obj/ObjFileParser.cpp index fec1fe87b..921ae6c3d 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjFileParser.cpp +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjFileParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -80,7 +80,7 @@ ObjFileParser::ObjFileParser(IOStreamBuffer &streamBuffer, const std::stri m_buffer(), m_pIO(io), m_progress(progress), - m_originalObjFileName(originalObjFileName) { + m_originalObjFileName(originalObjFileName) { std::fill_n(m_buffer, Buffersize, '\0'); // Create the model instance to store all the data @@ -111,8 +111,8 @@ void ObjFileParser::parseFile(IOStreamBuffer &streamBuffer) { //const unsigned int updateProgressEveryBytes = 100 * 1024; const unsigned int bytesToProcess = static_cast(streamBuffer.size()); const unsigned int progressTotal = bytesToProcess; - unsigned int processed = 0; - size_t lastFilePos(0); + unsigned int processed = 0u; + size_t lastFilePos = 0u; bool insideCstype = false; std::vector buffer; @@ -121,6 +121,13 @@ void ObjFileParser::parseFile(IOStreamBuffer &streamBuffer) { m_DataItEnd = buffer.end(); mEnd = &buffer[buffer.size() - 1] + 1; + if (processed == 0 && std::distance(m_DataIt, m_DataItEnd) >= 3 && + static_cast(*m_DataIt) == 0xEF && + static_cast(*(m_DataIt + 1)) == 0xBB && + static_cast(*(m_DataIt + 2)) == 0xBF) { + m_DataIt += 3; // skip BOM + } + // Handle progress reporting const size_t filePos(streamBuffer.getFilePos()); if (lastFilePos < filePos) { @@ -300,7 +307,7 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() { } else if (IsLineEnd(*tmp)) { end_of_definition = true; } - if (!SkipSpaces(&tmp, mEnd)) { + if (!SkipSpaces(&tmp, mEnd) || *tmp == '#') { break; } const bool isNum(IsNumeric(*tmp) || isNanOrInf(tmp)); @@ -308,11 +315,11 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() { if (isNum) { ++numComponents; } - if (!SkipSpaces(&tmp, mEnd)) { + if (!SkipSpaces(&tmp, mEnd) || *tmp == '#') { break; } } - + return numComponents; } @@ -451,7 +458,7 @@ void ObjFileParser::getFace(aiPrimitiveType type) { while (m_DataIt < m_DataItEnd) { int iStep = 1; - if (IsLineEnd(*m_DataIt)) { + if (IsLineEnd(*m_DataIt) || *m_DataIt == '#') { break; } @@ -464,19 +471,7 @@ void ObjFileParser::getFace(aiPrimitiveType type) { iPos = 0; } else { //OBJ USES 1 Base ARRAYS!!!! - int iVal; - auto end = m_DataIt; - // find either the buffer end or the '\0' - while (end < m_DataItEnd && *end != '\0') - ++end; - // avoid temporary string allocation if there is a zero - if (end != m_DataItEnd) { - iVal = ::atoi(&(*m_DataIt)); - } else { - // otherwise make a zero terminated copy, which is safe to pass to atoi - std::string number(&(*m_DataIt), m_DataItEnd - m_DataIt); - iVal = ::atoi(number.c_str()); - } + const int iVal = ::atoi(&(*m_DataIt)); // increment iStep position based off of the sign and # of digits int tmp = iVal; @@ -660,13 +655,13 @@ void ObjFileParser::getMaterialLib() { } else { absName = strMatName; } - - IOStream *pFile = m_pIO->Open(absName); + + std::unique_ptr pFile(m_pIO->Open(absName)); if (nullptr == pFile) { ASSIMP_LOG_ERROR("OBJ: Unable to locate material file ", strMatName); std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl"; ASSIMP_LOG_INFO("OBJ: Opening fallback material file ", strMatFallbackName); - pFile = m_pIO->Open(strMatFallbackName); + pFile.reset(m_pIO->Open(strMatFallbackName)); if (!pFile) { ASSIMP_LOG_ERROR("OBJ: Unable to locate fallback material file ", strMatFallbackName); m_DataIt = skipLine(m_DataIt, m_DataItEnd, m_uiLine); @@ -679,8 +674,8 @@ void ObjFileParser::getMaterialLib() { // material files if the model doesn't use any materials, so we // allow that. std::vector buffer; - BaseImporter::TextFileToBuffer(pFile, buffer, BaseImporter::ALLOW_EMPTY); - m_pIO->Close(pFile); + BaseImporter::TextFileToBuffer(pFile.get(), buffer, BaseImporter::ALLOW_EMPTY); + //m_pIO->Close(pFile); // Importing the material library ObjFileMtlImporter mtlImporter(buffer, strMatName, m_pModel.get()); diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjFileParser.h b/Dependencies/assimp/code/AssetLib/Obj/ObjFileParser.h index f3e149838..7a0779bf2 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjFileParser.h +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjFileParser.h @@ -55,18 +55,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { +// Forward declarations class ObjFileImporter; class IOSystem; class ProgressHandler; +// ------------------------------------------------------------------------------------------------ /// \class ObjFileParser /// \brief Parser for a obj waveform file +// ------------------------------------------------------------------------------------------------ class ASSIMP_API ObjFileParser { public: - static const size_t Buffersize = 4096; - typedef std::vector DataArray; - typedef std::vector::iterator DataArrayIt; - typedef std::vector::const_iterator ConstDataArrayIt; + static constexpr size_t Buffersize = 4096; + using DataArray = std::vector; + using DataArrayIt = std::vector::iterator; + using ConstDataArrayIt = std::vector::const_iterator; /// @brief The default constructor. ObjFileParser(); @@ -87,8 +90,6 @@ class ASSIMP_API ObjFileParser { void parseFile(IOStreamBuffer &streamBuffer); /// Method to copy the new delimited word in the current line. void copyNextWord(char *pBuffer, size_t length); - /// Method to copy the new line. - // void copyNextLine(char *pBuffer, size_t length); /// Get the number of components in a line. size_t getNumComponentsInDataDefinition(); /// Stores the vector @@ -143,7 +144,8 @@ class ASSIMP_API ObjFileParser { unsigned int m_uiLine; //! Helper buffer char m_buffer[Buffersize]; - const char *mEnd; + /// End of buffer + const char *mEnd; /// Pointer to IO system instance. IOSystem *m_pIO; //! Pointer to progress handler diff --git a/Dependencies/assimp/code/AssetLib/Obj/ObjTools.h b/Dependencies/assimp/code/AssetLib/Obj/ObjTools.h index ac5e119f2..cd75333d6 100644 --- a/Dependencies/assimp/code/AssetLib/Obj/ObjTools.h +++ b/Dependencies/assimp/code/AssetLib/Obj/ObjTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -86,19 +86,31 @@ inline Char_T getNextWord(Char_T pBuffer, Char_T pEnd) { } /** - * @brief Returns pointer a next token + * @brief Returns next space * @param[in] pBuffer Pointer to data buffer * @param[in] pEnd Pointer to end of buffer - * @return Pointer to next token + * @return Pointer to next space */ template -inline Char_T getNextToken(Char_T pBuffer, Char_T pEnd) { +inline Char_T getNextDelimiter(Char_T pBuffer, Char_T pEnd) { while (!isEndOfBuffer(pBuffer, pEnd)) { if (IsSpaceOrNewLine(*pBuffer)) { break; } ++pBuffer; } + return pBuffer; +} + +/** + * @brief Returns pointer a next token + * @param[in] pBuffer Pointer to data buffer + * @param[in] pEnd Pointer to end of buffer + * @return Pointer to next token + */ +template +inline Char_T getNextToken(Char_T pBuffer, Char_T pEnd) { + pBuffer = getNextDelimiter(pBuffer, pEnd); return getNextWord(pBuffer, pEnd); } diff --git a/Dependencies/assimp/code/CApi/AssimpCExport.cpp b/Dependencies/assimp/code/CApi/AssimpCExport.cpp index 99ad41ab7..b147e659b 100644 --- a/Dependencies/assimp/code/CApi/AssimpCExport.cpp +++ b/Dependencies/assimp/code/CApi/AssimpCExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/CApi/CInterfaceIOWrapper.cpp b/Dependencies/assimp/code/CApi/CInterfaceIOWrapper.cpp index 84648482b..75e6df877 100644 --- a/Dependencies/assimp/code/CApi/CInterfaceIOWrapper.cpp +++ b/Dependencies/assimp/code/CApi/CInterfaceIOWrapper.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -49,7 +49,6 @@ namespace Assimp { CIOStreamWrapper::~CIOStreamWrapper() { // Various places depend on this destructor to close the file if (mFile != nullptr) { - mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile); } } diff --git a/Dependencies/assimp/code/CApi/CInterfaceIOWrapper.h b/Dependencies/assimp/code/CApi/CInterfaceIOWrapper.h index 34c4a7311..f41a95d38 100644 --- a/Dependencies/assimp/code/CApi/CInterfaceIOWrapper.h +++ b/Dependencies/assimp/code/CApi/CInterfaceIOWrapper.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/AssertHandler.cpp b/Dependencies/assimp/code/Common/AssertHandler.cpp index ee2d2b95c..0fc2f3f5f 100644 --- a/Dependencies/assimp/code/Common/AssertHandler.cpp +++ b/Dependencies/assimp/code/Common/AssertHandler.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/Assimp.cpp b/Dependencies/assimp/code/Common/Assimp.cpp index ef3ee7b5d..7ae58f985 100644 --- a/Dependencies/assimp/code/Common/Assimp.cpp +++ b/Dependencies/assimp/code/Common/Assimp.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -67,13 +67,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; namespace Assimp { + // underlying structure for aiPropertyStore -typedef BatchLoader::PropertyMap PropertyMap; +using PropertyMap = BatchLoader::PropertyMap ; #if defined(__has_warning) -#if __has_warning("-Wordered-compare-function-pointers") -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wordered-compare-function-pointers" +# if __has_warning("-Wordered-compare-function-pointers") +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wordered-compare-function-pointers" #endif #endif @@ -111,6 +112,7 @@ void GetImporterInstanceList(std::vector &out); /** will delete all registered importers. */ void DeleteImporterInstanceList(std::vector &out); + } // namespace Assimp #ifndef ASSIMP_BUILD_SINGLETHREADED @@ -120,14 +122,14 @@ static std::mutex gLogStreamMutex; // ------------------------------------------------------------------------------------------------ // Custom LogStream implementation for the C-API -class LogToCallbackRedirector : public LogStream { +class LogToCallbackRedirector final : public LogStream { public: explicit LogToCallbackRedirector(const aiLogStream &s) : - stream(s) { + mStream(s) { ai_assert(nullptr != s.callback); } - ~LogToCallbackRedirector() { + ~LogToCallbackRedirector() override { #ifndef ASSIMP_BUILD_SINGLETHREADED std::lock_guard lock(gLogStreamMutex); #endif @@ -137,7 +139,7 @@ class LogToCallbackRedirector : public LogStream { // might cause strange problems, but the chance is quite low. PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(), - gPredefinedStreams.end(), (Assimp::LogStream *)stream.user); + gPredefinedStreams.end(), (Assimp::LogStream *)mStream.user); if (it != gPredefinedStreams.end()) { delete *it; @@ -146,12 +148,12 @@ class LogToCallbackRedirector : public LogStream { } /** @copydoc LogStream::write */ - void write(const char *message) { - stream.callback(message, stream.user); + void write(const char *message) override { + mStream.callback(message, mStream.user); } private: - aiLogStream stream; + const aiLogStream &mStream; }; // ------------------------------------------------------------------------------------------------ @@ -354,25 +356,31 @@ ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing(const aiScene *scene, void CallbackToLogRedirector(const char *msg, char *dt) { ai_assert(nullptr != msg); ai_assert(nullptr != dt); - LogStream *s = (LogStream *)dt; - - s->write(msg); + LogStream *stream = (LogStream *)dt; + if (stream != nullptr) { + stream->write(msg); + } } +static LogStream *DefaultStream = nullptr; + // ------------------------------------------------------------------------------------------------ ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream, const char *file) { aiLogStream sout; ASSIMP_BEGIN_EXCEPTION_REGION(); - LogStream *stream = LogStream::createDefaultStream(pStream, file); - if (!stream) { + if (DefaultStream == nullptr) { + DefaultStream = LogStream::createDefaultStream(pStream, file); + } + + if (!DefaultStream) { sout.callback = nullptr; sout.user = nullptr; } else { sout.callback = &CallbackToLogRedirector; - sout.user = (char *)stream; + sout.user = (char *)DefaultStream; } - gPredefinedStreams.push_back(stream); + gPredefinedStreams.push_back(DefaultStream); ASSIMP_END_EXCEPTION_REGION(aiLogStream); return sout; } @@ -411,6 +419,10 @@ ASSIMP_API aiReturn aiDetachLogStream(const aiLogStream *stream) { DefaultLogger::get()->detachStream(it->second); delete it->second; + if ((Assimp::LogStream *)stream->user == DefaultStream) { + DefaultStream = nullptr; + } + gActiveLogStreams.erase(it); if (gActiveLogStreams.empty()) { diff --git a/Dependencies/assimp/code/Common/Base64.cpp b/Dependencies/assimp/code/Common/Base64.cpp index 76f9b120e..aecfec2c5 100644 --- a/Dependencies/assimp/code/Common/Base64.cpp +++ b/Dependencies/assimp/code/Common/Base64.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/BaseImporter.cpp b/Dependencies/assimp/code/Common/BaseImporter.cpp index 5c70cc27e..fab094dab 100644 --- a/Dependencies/assimp/code/Common/BaseImporter.cpp +++ b/Dependencies/assimp/code/Common/BaseImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -375,6 +375,9 @@ void BaseImporter::ConvertToUTF8(std::vector &data) { // UTF 32 BE with BOM if (*((uint32_t *)&data.front()) == 0xFFFE0000) { + if (data.size() % sizeof(uint32_t) != 0) { + throw DeadlyImportError("Not valid UTF-32 BE"); + } // swap the endianness .. for (uint32_t *p = (uint32_t *)&data.front(), *end = (uint32_t *)&data.back(); p <= end; ++p) { @@ -384,11 +387,14 @@ void BaseImporter::ConvertToUTF8(std::vector &data) { // UTF 32 LE with BOM if (*((uint32_t *)&data.front()) == 0x0000FFFE) { + if (data.size() % sizeof(uint32_t) != 0) { + throw DeadlyImportError("Not valid UTF-32 LE"); + } ASSIMP_LOG_DEBUG("Found UTF-32 BOM ..."); std::vector output; - int *ptr = (int *)&data[0]; - int *end = ptr + (data.size() / sizeof(int)) + 1; + auto *ptr = (uint32_t *)&data[0]; + uint32_t *end = ptr + (data.size() / sizeof(uint32_t)) + 1; utf8::utf32to8(ptr, end, back_inserter(output)); return; } @@ -396,8 +402,8 @@ void BaseImporter::ConvertToUTF8(std::vector &data) { // UTF 16 BE with BOM if (*((uint16_t *)&data.front()) == 0xFFFE) { // Check to ensure no overflow can happen - if(data.size() % 2 != 0) { - return; + if (data.size() % sizeof(uint16_t) != 0) { + throw DeadlyImportError("Not valid UTF-16 BE"); } // swap the endianness .. for (uint16_t *p = (uint16_t *)&data.front(), *end = (uint16_t *)&data.back(); p <= end; ++p) { @@ -407,6 +413,9 @@ void BaseImporter::ConvertToUTF8(std::vector &data) { // UTF 16 LE with BOM if (*((uint16_t *)&data.front()) == 0xFEFF) { + if (data.size() % sizeof(uint16_t) != 0) { + throw DeadlyImportError("Not valid UTF-16 LE"); + } ASSIMP_LOG_DEBUG("Found UTF-16 BOM ..."); std::vector output; diff --git a/Dependencies/assimp/code/Common/BaseProcess.cpp b/Dependencies/assimp/code/Common/BaseProcess.cpp index 560ee7b94..4d315a033 100644 --- a/Dependencies/assimp/code/Common/BaseProcess.cpp +++ b/Dependencies/assimp/code/Common/BaseProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/BaseProcess.h b/Dependencies/assimp/code/Common/BaseProcess.h index a945ad542..a601a8693 100644 --- a/Dependencies/assimp/code/Common/BaseProcess.h +++ b/Dependencies/assimp/code/Common/BaseProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -68,11 +68,11 @@ class SharedPostProcessInfo { //! Represents data that is allocated on the heap, thus needs to be deleted template - struct THeapData : public Base { + struct THeapData final : Base { explicit THeapData(T *in) : data(in) {} - ~THeapData() { + ~THeapData() override { delete data; } T *data; @@ -80,11 +80,11 @@ class SharedPostProcessInfo { //! Represents static, by-value data not allocated on the heap template - struct TStaticData : public Base { + struct TStaticData final : Base { explicit TStaticData(T in) : data(in) {} - ~TStaticData() = default; + ~TStaticData() override= default; T data; }; diff --git a/Dependencies/assimp/code/Common/Bitmap.cpp b/Dependencies/assimp/code/Common/Bitmap.cpp index e6732c528..7563ff197 100644 --- a/Dependencies/assimp/code/Common/Bitmap.cpp +++ b/Dependencies/assimp/code/Common/Bitmap.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/Compression.cpp b/Dependencies/assimp/code/Common/Compression.cpp index 091171771..4aaf9a3a3 100644 --- a/Dependencies/assimp/code/Common/Compression.cpp +++ b/Dependencies/assimp/code/Common/Compression.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/Compression.h b/Dependencies/assimp/code/Common/Compression.h index 0bec91bba..bd73aee54 100644 --- a/Dependencies/assimp/code/Common/Compression.h +++ b/Dependencies/assimp/code/Common/Compression.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/CreateAnimMesh.cpp b/Dependencies/assimp/code/Common/CreateAnimMesh.cpp index 467651587..3299589c3 100644 --- a/Dependencies/assimp/code/Common/CreateAnimMesh.cpp +++ b/Dependencies/assimp/code/Common/CreateAnimMesh.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- Copyright (C) 2016 The Qt Company Ltd. -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace Assimp { +namespace Assimp { aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh, bool needPositions, bool needNormals, bool needTangents, bool needColors, bool needTexCoords) { diff --git a/Dependencies/assimp/code/Common/DefaultIOStream.cpp b/Dependencies/assimp/code/Common/DefaultIOStream.cpp index e423eae4f..d1962cee2 100644 --- a/Dependencies/assimp/code/Common/DefaultIOStream.cpp +++ b/Dependencies/assimp/code/Common/DefaultIOStream.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -157,9 +157,9 @@ size_t DefaultIOStream::FileSize() const { return 0; mCachedSize = (size_t)(fileStat.st_size); #elif defined _WIN32 - struct _stat32 fileStat; + struct _stat fileStat; //using fileno + fstat avoids having to handle the filename - int err = _fstat32(_fileno(mFile), &fileStat); + int err = _fstat(_fileno(mFile), &fileStat); if (0 != err) return 0; mCachedSize = (size_t)(fileStat.st_size); diff --git a/Dependencies/assimp/code/Common/DefaultIOSystem.cpp b/Dependencies/assimp/code/Common/DefaultIOSystem.cpp index ddb5b3b60..e49f03396 100644 --- a/Dependencies/assimp/code/Common/DefaultIOSystem.cpp +++ b/Dependencies/assimp/code/Common/DefaultIOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -96,7 +96,7 @@ bool DefaultIOSystem::Exists(const char *pFile) const { if (pFile == nullptr) { return false; } - + #ifdef _WIN32 struct __stat64 filestat; if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) { @@ -104,7 +104,9 @@ bool DefaultIOSystem::Exists(const char *pFile) const { } #else struct stat statbuf; - stat(pFile, &statbuf); + if (stat(pFile, &statbuf) != 0) { + return false; + } // test for a regular file if (!S_ISREG(statbuf.st_mode)) { return false; @@ -120,7 +122,7 @@ IOStream *DefaultIOSystem::Open(const char *strFile, const char *strMode) { ai_assert(strFile != nullptr); ai_assert(strMode != nullptr); FILE *file; - + #ifdef _WIN32 std::wstring name = Utf8ToWide(strFile); if (name.empty()) { @@ -131,7 +133,7 @@ IOStream *DefaultIOSystem::Open(const char *strFile, const char *strMode) { #else file = ::fopen(strFile, strMode); #endif - + if (!file) { return nullptr; } diff --git a/Dependencies/assimp/code/Common/DefaultLogger.cpp b/Dependencies/assimp/code/Common/DefaultLogger.cpp index 828e326e2..5d69bebe8 100644 --- a/Dependencies/assimp/code/Common/DefaultLogger.cpp +++ b/Dependencies/assimp/code/Common/DefaultLogger.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team @@ -221,13 +221,11 @@ void DefaultLogger::set(Logger *logger) { #endif if (nullptr == logger) { - logger = &s_pNullLogger; + m_pLogger = &s_pNullLogger; } - if (nullptr != m_pLogger && !isNullLogger()) { - delete m_pLogger; + else { + m_pLogger = logger; } - - DefaultLogger::m_pLogger = logger; } // ---------------------------------------------------------------------------------- @@ -320,9 +318,13 @@ bool DefaultLogger::attachStream(LogStream *pStream, unsigned int severity) { } if (0 == severity) { - severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging; + severity = SeverityAll; } +#ifndef ASSIMP_BUILD_SINGLETHREADED + std::lock_guard lock(m_arrayMutex); +#endif + for (StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it) { @@ -332,8 +334,8 @@ bool DefaultLogger::attachStream(LogStream *pStream, unsigned int severity) { } } - LogStreamInfo *pInfo = new LogStreamInfo(severity, pStream); - m_StreamArray.push_back(pInfo); + m_StreamArray.push_back(new LogStreamInfo(severity, pStream)); + return true; } @@ -348,6 +350,10 @@ bool DefaultLogger::detachStream(LogStream *pStream, unsigned int severity) { severity = SeverityAll; } +#ifndef ASSIMP_BUILD_SINGLETHREADED + std::lock_guard lock(m_arrayMutex); +#endif + bool res(false); for (StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it) { if ((*it)->m_pStream == pStream) { @@ -387,6 +393,10 @@ DefaultLogger::~DefaultLogger() { void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev) { ai_assert(nullptr != message); +#ifndef ASSIMP_BUILD_SINGLETHREADED + std::lock_guard lock(m_arrayMutex); +#endif + // Check whether this is a repeated message auto thisLen = ::strlen(message); if (thisLen == lastLen - 1 && !::strncmp(message, lastMsg, lastLen - 1)) { diff --git a/Dependencies/assimp/code/Common/DefaultProgressHandler.h b/Dependencies/assimp/code/Common/DefaultProgressHandler.h index 2ace9e02a..65680c23e 100644 --- a/Dependencies/assimp/code/Common/DefaultProgressHandler.h +++ b/Dependencies/assimp/code/Common/DefaultProgressHandler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -53,7 +53,7 @@ namespace Assimp { /** * @brief Internal default implementation of the #ProgressHandler interface. */ -class DefaultProgressHandler : public ProgressHandler { +class DefaultProgressHandler final : public ProgressHandler { public: /// @brief Ignores the update callback. bool Update(float) override { diff --git a/Dependencies/assimp/code/Common/Exceptional.cpp b/Dependencies/assimp/code/Common/Exceptional.cpp index 0629f716e..1bd2ed77a 100644 --- a/Dependencies/assimp/code/Common/Exceptional.cpp +++ b/Dependencies/assimp/code/Common/Exceptional.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/Exporter.cpp b/Dependencies/assimp/code/Common/Exporter.cpp index 4da055064..7b71ce2a2 100644 --- a/Dependencies/assimp/code/Common/Exporter.cpp +++ b/Dependencies/assimp/code/Common/Exporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -159,10 +159,8 @@ static void setupExporterArray(std::vector &exporte #endif #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER - exporters.emplace_back("obj", "Wavefront OBJ format", "obj", &ExportSceneObj, - aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */); - exporters.emplace_back("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl, - aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */); + exporters.emplace_back("obj", "Wavefront OBJ format", "obj", &ExportSceneObj); + exporters.emplace_back("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl); #endif #ifndef ASSIMP_BUILD_NO_STL_EXPORTER diff --git a/Dependencies/assimp/code/Common/FileLogStream.h b/Dependencies/assimp/code/Common/FileLogStream.h index f64f88f48..1e152a49b 100644 --- a/Dependencies/assimp/code/Common/FileLogStream.h +++ b/Dependencies/assimp/code/Common/FileLogStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/FileSystemFilter.h b/Dependencies/assimp/code/Common/FileSystemFilter.h index c530153d4..62886de9c 100644 --- a/Dependencies/assimp/code/Common/FileSystemFilter.h +++ b/Dependencies/assimp/code/Common/FileSystemFilter.h @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -namespace Assimp { +namespace Assimp { inline bool IsHex(char s) { return (s>='0' && s<='9') || (s>='a' && s<='f') || (s>='A' && s<='F'); diff --git a/Dependencies/assimp/code/Common/IFF.h b/Dependencies/assimp/code/Common/IFF.h index d5469a760..cdca13eb5 100644 --- a/Dependencies/assimp/code/Common/IFF.h +++ b/Dependencies/assimp/code/Common/IFF.h @@ -7,8 +7,8 @@ #include -namespace Assimp { -namespace IFF { +namespace Assimp { +namespace IFF { ///////////////////////////////////////////////////////////////////////////////// //! Describes an IFF chunk header diff --git a/Dependencies/assimp/code/Common/IOSystem.cpp b/Dependencies/assimp/code/Common/IOSystem.cpp index aa91e9b49..2768b0e95 100644 --- a/Dependencies/assimp/code/Common/IOSystem.cpp +++ b/Dependencies/assimp/code/Common/IOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/Importer.cpp b/Dependencies/assimp/code/Common/Importer.cpp index 284ad89cc..684419b94 100644 --- a/Dependencies/assimp/code/Common/Importer.cpp +++ b/Dependencies/assimp/code/Common/Importer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -733,7 +733,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { return nullptr; } } -#endif // no validation +#endif // ASSIMP_BUILD_NO_VALIDATEDS_PROCESS // Preprocess the scene and prepare it for post-processing if (profiler) { @@ -771,6 +771,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { #else pimpl->mErrorString = std::string("std::exception: ") + e.what(); #endif + pimpl->mException = std::current_exception(); ASSIMP_LOG_ERROR(pimpl->mErrorString); delete pimpl->mScene; pimpl->mScene = nullptr; @@ -848,11 +849,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) { break; } #ifdef ASSIMP_BUILD_DEBUG - -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - continue; -#endif // no validation - +#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step if (pimpl->bExtraVerbose) { ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures"); @@ -864,6 +861,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) { break; } } +#endif // no validation #endif // ! DEBUG } pimpl->mProgressHandler->UpdatePostProcess( static_cast(pimpl->mPostProcessingSteps.size()), @@ -939,6 +937,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess profiler->EndRegion( "postprocess" ); } +#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step if ( pimpl->bExtraVerbose || requestValidation ) { ASSIMP_LOG_DEBUG( "Verbose Import: revalidating data structures" ); @@ -949,6 +948,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess ASSIMP_LOG_ERROR( "Verbose Import: failed to revalidate data structures" ); } } +#endif // no validation // clear any data allocated by post-process steps pimpl->mPPShared->Clean(); diff --git a/Dependencies/assimp/code/Common/Importer.h b/Dependencies/assimp/code/Common/Importer.h index 2da55f173..5d3977647 100644 --- a/Dependencies/assimp/code/Common/Importer.h +++ b/Dependencies/assimp/code/Common/Importer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiScene; -namespace Assimp { +namespace Assimp { class ProgressHandler; class IOSystem; class BaseImporter; diff --git a/Dependencies/assimp/code/Common/ImporterRegistry.cpp b/Dependencies/assimp/code/Common/ImporterRegistry.cpp index 276f20974..fd503424e 100644 --- a/Dependencies/assimp/code/Common/ImporterRegistry.cpp +++ b/Dependencies/assimp/code/Common/ImporterRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/Maybe.h b/Dependencies/assimp/code/Common/Maybe.h index 99b18b67c..4548ad01f 100644 --- a/Dependencies/assimp/code/Common/Maybe.h +++ b/Dependencies/assimp/code/Common/Maybe.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -83,6 +83,7 @@ struct Maybe { Maybe &operator&() = delete; Maybe(const Maybe &) = delete; + Maybe &operator=(const Maybe &) = default; private: T _val; diff --git a/Dependencies/assimp/code/Common/PolyTools.h b/Dependencies/assimp/code/Common/PolyTools.h index 46ceb9d75..520ff09b8 100644 --- a/Dependencies/assimp/code/Common/PolyTools.h +++ b/Dependencies/assimp/code/Common/PolyTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/PostStepRegistry.cpp b/Dependencies/assimp/code/Common/PostStepRegistry.cpp index fdf33fc40..4efa46ebc 100644 --- a/Dependencies/assimp/code/Common/PostStepRegistry.cpp +++ b/Dependencies/assimp/code/Common/PostStepRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team diff --git a/Dependencies/assimp/code/Common/RemoveComments.cpp b/Dependencies/assimp/code/Common/RemoveComments.cpp index a6a472400..934930a9a 100644 --- a/Dependencies/assimp/code/Common/RemoveComments.cpp +++ b/Dependencies/assimp/code/Common/RemoveComments.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/SGSpatialSort.cpp b/Dependencies/assimp/code/Common/SGSpatialSort.cpp index d24ecf1b4..0196d819a 100644 --- a/Dependencies/assimp/code/Common/SGSpatialSort.cpp +++ b/Dependencies/assimp/code/Common/SGSpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/SceneCombiner.cpp b/Dependencies/assimp/code/Common/SceneCombiner.cpp index 88fa49793..0636c479b 100644 --- a/Dependencies/assimp/code/Common/SceneCombiner.cpp +++ b/Dependencies/assimp/code/Common/SceneCombiner.cpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -53,7 +52,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // ---------------------------------------------------------------------------- #include "ScenePrivate.h" -#include "time.h" #include #include #include @@ -61,9 +59,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include + #include +#include +#include namespace Assimp { @@ -96,6 +96,11 @@ inline void PrefixString(aiString &string, const char *prefix, unsigned int len) // ------------------------------------------------------------------------------------------------ // Add node identifiers to a hashing set void SceneCombiner::AddNodeHashes(aiNode *node, std::set &hashes) { + if (node == nullptr) { + ASSIMP_LOG_ERROR("Pointer to aiNode is nullptr."); + return; + } + // Add node name to hashing set if it is non-empty - empty nodes are allowed // and they can't have any anims assigned so its absolutely safe to duplicate them. if (node->mName.length) { @@ -316,15 +321,6 @@ void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vector > rndGen(rng, dist); #endif for (unsigned int i = 1; i < src.size(); ++i) { - //if (i != duplicates[i]) - //{ - // // duplicate scenes share the same UID - // ::strcpy( src[i].id, src[duplicates[i]].id ); - // src[i].idlen = src[duplicates[i]].idlen; - - // continue; - //} - src[i].idlen = ai_snprintf(src[i].id, 32, "$%.6X$_", i); if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { @@ -994,7 +990,7 @@ inline void GetArrayCopy(Type *&dest, ai_uint num) { Type *old = dest; dest = new Type[num]; - ::memcpy(dest, old, sizeof(Type) * num); + std::copy(old, old+num, dest); } // ------------------------------------------------------------------------------------------------ @@ -1104,10 +1100,6 @@ void SceneCombiner::Copy(aiMesh **_dest, const aiMesh *src) { // make a deep copy of all faces GetArrayCopy(dest->mFaces, dest->mNumFaces); - for (unsigned int i = 0; i < dest->mNumFaces; ++i) { - aiFace &f = dest->mFaces[i]; - GetArrayCopy(f.mIndices, f.mNumIndices); - } // make a deep copy of all blend shapes CopyPtrArray(dest->mAnimMeshes, dest->mAnimMeshes, dest->mNumAnimMeshes); diff --git a/Dependencies/assimp/code/Common/ScenePreprocessor.cpp b/Dependencies/assimp/code/Common/ScenePreprocessor.cpp index b4bbe9d67..1d884c778 100644 --- a/Dependencies/assimp/code/Common/ScenePreprocessor.cpp +++ b/Dependencies/assimp/code/Common/ScenePreprocessor.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/ScenePreprocessor.h b/Dependencies/assimp/code/Common/ScenePreprocessor.h index 6ffd7f8bd..d12527b38 100644 --- a/Dependencies/assimp/code/Common/ScenePreprocessor.h +++ b/Dependencies/assimp/code/Common/ScenePreprocessor.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/ScenePrivate.h b/Dependencies/assimp/code/Common/ScenePrivate.h index b8c524aa2..f8aa9a16b 100644 --- a/Dependencies/assimp/code/Common/ScenePrivate.h +++ b/Dependencies/assimp/code/Common/ScenePrivate.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/SkeletonMeshBuilder.cpp b/Dependencies/assimp/code/Common/SkeletonMeshBuilder.cpp index 167652700..1fa6ca2b6 100644 --- a/Dependencies/assimp/code/Common/SkeletonMeshBuilder.cpp +++ b/Dependencies/assimp/code/Common/SkeletonMeshBuilder.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/SpatialSort.cpp b/Dependencies/assimp/code/Common/SpatialSort.cpp index 6bce63af4..2f51eddba 100644 --- a/Dependencies/assimp/code/Common/SpatialSort.cpp +++ b/Dependencies/assimp/code/Common/SpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/StackAllocator.h b/Dependencies/assimp/code/Common/StackAllocator.h index fcb72a09e..e6e2e0b0c 100644 --- a/Dependencies/assimp/code/Common/StackAllocator.h +++ b/Dependencies/assimp/code/Common/StackAllocator.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/StackAllocator.inl b/Dependencies/assimp/code/Common/StackAllocator.inl index 44f15edbc..899d93fca 100644 --- a/Dependencies/assimp/code/Common/StackAllocator.inl +++ b/Dependencies/assimp/code/Common/StackAllocator.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/StandardShapes.cpp b/Dependencies/assimp/code/Common/StandardShapes.cpp index 4a967997e..91f0fc828 100644 --- a/Dependencies/assimp/code/Common/StandardShapes.cpp +++ b/Dependencies/assimp/code/Common/StandardShapes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/StbCommon.h b/Dependencies/assimp/code/Common/StbCommon.h index aef23ce17..d7b8940c6 100644 --- a/Dependencies/assimp/code/Common/StbCommon.h +++ b/Dependencies/assimp/code/Common/StbCommon.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/StdOStreamLogStream.h b/Dependencies/assimp/code/Common/StdOStreamLogStream.h index 683c87d5f..bfefbe43a 100644 --- a/Dependencies/assimp/code/Common/StdOStreamLogStream.h +++ b/Dependencies/assimp/code/Common/StdOStreamLogStream.h @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** @class StdOStreamLogStream diff --git a/Dependencies/assimp/code/Common/Subdivision.cpp b/Dependencies/assimp/code/Common/Subdivision.cpp index 78c249807..4ec32bf1e 100644 --- a/Dependencies/assimp/code/Common/Subdivision.cpp +++ b/Dependencies/assimp/code/Common/Subdivision.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -528,7 +528,7 @@ void CatmullClarkSubdivider::InternSubdivide( continue; } - ai_assert(adj[o] - moffsets[nidx].first < mp->mNumFaces); + ai_assert(adj[o] - moffsets[nidx].first < mp->mNumFaces); const aiFace &f = mp->mFaces[adj[o] - moffsets[nidx].first]; bool haveit = false; diff --git a/Dependencies/assimp/code/Common/TargetAnimation.cpp b/Dependencies/assimp/code/Common/TargetAnimation.cpp index 9ef4e5d6c..fc4da9053 100644 --- a/Dependencies/assimp/code/Common/TargetAnimation.cpp +++ b/Dependencies/assimp/code/Common/TargetAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/TargetAnimation.h b/Dependencies/assimp/code/Common/TargetAnimation.h index 116b55d2a..b8238b9bb 100644 --- a/Dependencies/assimp/code/Common/TargetAnimation.h +++ b/Dependencies/assimp/code/Common/TargetAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/Version.cpp b/Dependencies/assimp/code/Common/Version.cpp index 2fca44824..95a03b43e 100644 --- a/Dependencies/assimp/code/Common/Version.cpp +++ b/Dependencies/assimp/code/Common/Version.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static constexpr 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-2024, Assimp team\n" + "(c) 2006-2026, Assimp team\n" "License under the terms and conditions of the 3-clause BSD license\n" "https://www.assimp.org\n"; diff --git a/Dependencies/assimp/code/Common/VertexTriangleAdjacency.cpp b/Dependencies/assimp/code/Common/VertexTriangleAdjacency.cpp index 616e7e797..b134bc655 100644 --- a/Dependencies/assimp/code/Common/VertexTriangleAdjacency.cpp +++ b/Dependencies/assimp/code/Common/VertexTriangleAdjacency.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/VertexTriangleAdjacency.h b/Dependencies/assimp/code/Common/VertexTriangleAdjacency.h index 20d3bd32c..9a2ada7e6 100644 --- a/Dependencies/assimp/code/Common/VertexTriangleAdjacency.h +++ b/Dependencies/assimp/code/Common/VertexTriangleAdjacency.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMesh; struct aiFace; -namespace Assimp { +namespace Assimp { // -------------------------------------------------------------------------------------------- /** @brief The VertexTriangleAdjacency class computes a vertex-triangle diff --git a/Dependencies/assimp/code/Common/Win32DebugLogStream.h b/Dependencies/assimp/code/Common/Win32DebugLogStream.h index f8bc017af..9ce7a3d98 100644 --- a/Dependencies/assimp/code/Common/Win32DebugLogStream.h +++ b/Dependencies/assimp/code/Common/Win32DebugLogStream.h @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -52,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "windows.h" -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** @class Win32DebugLogStream diff --git a/Dependencies/assimp/code/Common/ZipArchiveIOSystem.cpp b/Dependencies/assimp/code/Common/ZipArchiveIOSystem.cpp index 23d7db15d..11cd362a1 100644 --- a/Dependencies/assimp/code/Common/ZipArchiveIOSystem.cpp +++ b/Dependencies/assimp/code/Common/ZipArchiveIOSystem.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/material.cpp b/Dependencies/assimp/code/Common/material.cpp index 76676ec1a..fa9250634 100644 --- a/Dependencies/assimp/code/Common/material.cpp +++ b/Dependencies/assimp/code/Common/material.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -90,6 +90,18 @@ const char *aiTextureTypeToString(aiTextureType in) { return "Clearcoat"; case aiTextureType_TRANSMISSION: return "Transmission"; + case aiTextureType_MAYA_BASE: + return "MayaBase"; + case aiTextureType_MAYA_SPECULAR: + return "MayaSpecular"; + case aiTextureType_MAYA_SPECULAR_COLOR: + return "MayaSpecularColor"; + case aiTextureType_MAYA_SPECULAR_ROUGHNESS: + return "MayaSpecularRoughness"; + case aiTextureType_ANISOTROPY: + return "Anisotropy"; + case aiTextureType_GLTF_METALLIC_ROUGHNESS: + return "glTFMetallicRoughness"; case aiTextureType_UNKNOWN: return "Unknown"; default: diff --git a/Dependencies/assimp/code/Common/scene.cpp b/Dependencies/assimp/code/Common/scene.cpp index 5c2e370d2..982b5194c 100644 --- a/Dependencies/assimp/code/Common/scene.cpp +++ b/Dependencies/assimp/code/Common/scene.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/simd.cpp b/Dependencies/assimp/code/Common/simd.cpp index 6a48750b0..59113acc4 100644 --- a/Dependencies/assimp/code/Common/simd.cpp +++ b/Dependencies/assimp/code/Common/simd.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Common/simd.h b/Dependencies/assimp/code/Common/simd.h index 05d27d253..dbbd304eb 100644 --- a/Dependencies/assimp/code/Common/simd.h +++ b/Dependencies/assimp/code/Common/simd.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/Geometry/GeometryUtils.cpp b/Dependencies/assimp/code/Geometry/GeometryUtils.cpp index 375e501d3..2b6631ce8 100644 --- a/Dependencies/assimp/code/Geometry/GeometryUtils.cpp +++ b/Dependencies/assimp/code/Geometry/GeometryUtils.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -47,8 +47,8 @@ namespace Assimp { // ------------------------------------------------------------------------------------------------ ai_real GeometryUtils::heron( ai_real a, ai_real b, ai_real c ) { - const ai_real s = (a + b + c) / 2; - const ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 ); + const ai_real s = (a + b + c) * 0.5; + const ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), static_cast(0.5)); return area; } @@ -57,8 +57,8 @@ ai_real GeometryUtils::distance3D( const aiVector3D &vA, const aiVector3D &vB ) const ai_real lx = ( vB.x - vA.x ); const ai_real ly = ( vB.y - vA.y ); const ai_real lz = ( vB.z - vA.z ); - const ai_real a = lx*lx + ly*ly + lz*lz; - const ai_real d = pow( a, (ai_real)0.5 ); + const ai_real a = lx*lx + ly*ly + lz*lz; + const ai_real d = pow( a, static_cast(0.5)); return d; } @@ -66,6 +66,9 @@ ai_real GeometryUtils::distance3D( const aiVector3D &vA, const aiVector3D &vB ) // ------------------------------------------------------------------------------------------------ ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) { ai_real area = 0; + if (mesh == nullptr) { + return area; + } const aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] ); const aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] ); @@ -81,8 +84,7 @@ ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh // ------------------------------------------------------------------------------------------------ // Check whether a ray intersects a plane and find the intersection point -bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, - const aiVector3D& planeNormal, aiVector3D& pos) { +bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, const aiVector3D& planeNormal, aiVector3D& pos) { const ai_real b = planeNormal * (planePos - ray.pos); ai_real h = ray.dir * planeNormal; if ((h < 10e-5 && h > -10e-5) || (h = b/h) < 0) @@ -93,11 +95,14 @@ bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, } // ------------------------------------------------------------------------------------------------ -void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, - size_t numVectors) { +void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors) { + if (vectorArrayIn == nullptr || vectorArrayOut == nullptr) { + return; + } + for (size_t i=0; imProperties[i]; if (prop /* just for safety ... */ - && 0 == strcmp(prop->mKey.data, pKey) && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */ + && 0 == strncmp(prop->mKey.data, pKey, strlen(pKey)) && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */ && (UINT_MAX == index || prop->mIndex == index)) { *pPropOut = pMat->mProperties[i]; return AI_SUCCESS; @@ -84,13 +83,17 @@ aiReturn aiGetMaterialProperty(const aiMaterial *pMat, return AI_FAILURE; } +namespace +{ + // ------------------------------------------------------------------------------------------------ -// Get an array of floating-point values from the material. -aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat, +// Implementation of functions "aiGetMaterialFloatArray" and "aiGetMaterialFloatFloatArray". +template +aiReturn GetMaterialFloatArray(const aiMaterial *pMat, const char *pKey, unsigned int type, unsigned int index, - ai_real *pOut, + TReal *pOut, unsigned int *pMax) { ai_assert(pOut != nullptr); ai_assert(pMat != nullptr); @@ -101,7 +104,7 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat, return AI_FAILURE; } - // data is given in floats, convert to ai_real + // data is given in floats, convert to TReal unsigned int iWrite = 0; if (aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) { iWrite = prop->mDataLength / sizeof(float); @@ -111,14 +114,14 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat, } for (unsigned int a = 0; a < iWrite; ++a) { - pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); + pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); } if (pMax) { *pMax = iWrite; } } - // data is given in doubles, convert to float + // data is given in doubles, convert to TReal else if (aiPTI_Double == prop->mType) { iWrite = prop->mDataLength / sizeof(double); if (pMax) { @@ -126,13 +129,13 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat, ; } for (unsigned int a = 0; a < iWrite; ++a) { - pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); + pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); } if (pMax) { *pMax = iWrite; } } - // data is given in ints, convert to float + // data is given in ints, convert to TReal else if (aiPTI_Integer == prop->mType) { iWrite = prop->mDataLength / sizeof(int32_t); if (pMax) { @@ -140,7 +143,7 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat, ; } for (unsigned int a = 0; a < iWrite; ++a) { - pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); + pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); } if (pMax) { *pMax = iWrite; @@ -156,7 +159,7 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat, ai_assert(prop->mDataLength >= 5); ai_assert(!prop->mData[prop->mDataLength - 1]); for (unsigned int a = 0;; ++a) { - cur = fast_atoreal_move(cur, pOut[a]); + cur = fast_atoreal_move(cur, pOut[a]); if (a == iWrite - 1) { break; } @@ -175,92 +178,27 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat, } // ------------------------------------------------------------------------------------------------ -// Get an array of floating-point values from the material. -aiReturn aiGetMaterialDoubleArray(const aiMaterial *pMat, +// Get an array of float typed float values from the material. +aiReturn aiGetMaterialFloatFloatArray(const aiMaterial *pMat, const char *pKey, unsigned int type, unsigned int index, - double *pOut, + float *pOut, unsigned int *pMax) { - ai_assert(pOut != nullptr); - ai_assert(pMat != nullptr); - - const aiMaterialProperty *prop; - aiGetMaterialProperty(pMat, pKey, type, index, (const aiMaterialProperty **)&prop); - if (nullptr == prop) { - return AI_FAILURE; - } - - // data is given in floats, convert to ai_real - unsigned int iWrite = 0; - if (aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) { - iWrite = prop->mDataLength / sizeof(float); - if (pMax) { - iWrite = std::min(*pMax, iWrite); - ; - } + return ::GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax); +} - for (unsigned int a = 0; a < iWrite; ++a) { - pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); - } +} // namespace - if (pMax) { - *pMax = iWrite; - } - } - // data is given in doubles, convert to float - else if (aiPTI_Double == prop->mType) { - iWrite = prop->mDataLength / sizeof(double); - if (pMax) { - iWrite = std::min(*pMax, iWrite); - ; - } - for (unsigned int a = 0; a < iWrite; ++a) { - pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); - } - if (pMax) { - *pMax = iWrite; - } - } - // data is given in ints, convert to float - else if (aiPTI_Integer == prop->mType) { - iWrite = prop->mDataLength / sizeof(int32_t); - if (pMax) { - iWrite = std::min(*pMax, iWrite); - } - for (unsigned int a = 0; a < iWrite; ++a) { - pOut[a] = static_cast(reinterpret_cast(prop->mData)[a]); - } - if (pMax) { - *pMax = iWrite; - } - } - // a string ... read floats separated by spaces - else { - if (pMax) { - iWrite = *pMax; - } - // strings are zero-terminated with a 32 bit length prefix, so this is safe - const char *cur = prop->mData + 4; - ai_assert(prop->mDataLength >= 5); - ai_assert(!prop->mData[prop->mDataLength - 1]); - for (unsigned int a = 0;; ++a) { - cur = fast_atoreal_move(cur, pOut[a]); - if (a == iWrite - 1) { - break; - } - if (!IsSpace(*cur)) { - ASSIMP_LOG_ERROR("Material property", pKey, - " is a string; failed to parse a float array out of it."); - return AI_FAILURE; - } - } - - if (pMax) { - *pMax = iWrite; - } - } - return AI_SUCCESS; +// ------------------------------------------------------------------------------------------------ +// Get an array of floating-point values from the material. +aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat, + const char *pKey, + unsigned int type, + unsigned int index, + ai_real *pOut, + unsigned int *pMax) { + return ::GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax); } // ------------------------------------------------------------------------------------------------ @@ -349,7 +287,7 @@ aiReturn aiGetMaterialColor(const aiMaterial *pMat, unsigned int index, aiColor4D *pOut) { unsigned int iMax = 4; - const aiReturn eRet = aiGetMaterialFloatArray(pMat, pKey, type, index, (ai_real *)pOut, &iMax); + const aiReturn eRet = aiGetMaterialFloatFloatArray(pMat, pKey, type, index, (float *)pOut, &iMax); // if no alpha channel is defined: set it to 1.0 if (3 == iMax) { @@ -402,6 +340,12 @@ aiReturn aiGetMaterialString(const aiMaterial *pMat, return AI_SUCCESS; } +// ------------------------------------------------------------------------------------------------ +// Get a c-like string fron an aiString +const char *aiGetStringC_Str(const aiString *str) { + return str->data; +} + // ------------------------------------------------------------------------------------------------ // Get the number of textures on a particular texture stack unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial *pMat, C_ENUM aiTextureType type) { diff --git a/Dependencies/assimp/code/Material/MaterialSystem.h b/Dependencies/assimp/code/Material/MaterialSystem.h index e7c752179..bf8f67f52 100644 --- a/Dependencies/assimp/code/Material/MaterialSystem.h +++ b/Dependencies/assimp/code/Material/MaterialSystem.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMaterial; -namespace Assimp { +namespace Assimp { // ------------------------------------------------------------------------------ /** Computes a hash (hopefully unique) from all material properties diff --git a/Dependencies/assimp/code/Pbrt/PbrtExporter.cpp b/Dependencies/assimp/code/Pbrt/PbrtExporter.cpp index 907e9a6a2..fb5e1ab1a 100644 --- a/Dependencies/assimp/code/Pbrt/PbrtExporter.cpp +++ b/Dependencies/assimp/code/Pbrt/PbrtExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -93,17 +93,22 @@ void ExportScenePbrt(const char *pFile, IOSystem *pIOSystem, const aiScene *pSce const ExportProperties *) { std::string path = DefaultIOSystem::absolutePath(std::string(pFile)); std::string file = DefaultIOSystem::completeBaseName(std::string(pFile)); - path = path + file + ".pbrt"; + std::string texturesPath = path; + if (!texturesPath.empty()) { + texturesPath+=pIOSystem->getOsSeparator(); + } + texturesPath+="textures"; + // initialize the exporter - PbrtExporter exporter(pScene, pIOSystem, path, file); + PbrtExporter exporter(pScene, pIOSystem, path, file, texturesPath); } } // end of namespace Assimp -static void create_embedded_textures_folder(const aiScene *scene, IOSystem *pIOSystem) { +static void create_embedded_textures_folder(const aiScene *scene, IOSystem *pIOSystem, const std::string &texturesPath) { if (scene->mNumTextures > 0) { - if (!pIOSystem->Exists("textures")) { - if (!pIOSystem->CreateDirectory("textures")) { + if (!pIOSystem->Exists(texturesPath)) { + if (!pIOSystem->CreateDirectory(texturesPath)) { throw DeadlyExportError("Could not create textures/ directory."); } } @@ -112,11 +117,12 @@ static void create_embedded_textures_folder(const aiScene *scene, IOSystem *pIOS PbrtExporter::PbrtExporter( const aiScene *pScene, IOSystem *pIOSystem, - const std::string &path, const std::string &file) : + const std::string &path, const std::string &file, const std::string &texturesPath) : mScene(pScene), mIOSystem(pIOSystem), mPath(path), mFile(file), + mTexturesPath(texturesPath), mRootTransform( // rotates the (already left-handed) CRS -90 degrees around the x axis in order to // make +Z 'up' and +Y 'towards viewer', as in default in pbrt @@ -132,10 +138,10 @@ PbrtExporter::PbrtExporter( 0.f, 0.f, 1.f, 0.f, // 0.f, 0.f, 0.f, 1.f // ) * mRootTransform; - + // Export embedded textures. - create_embedded_textures_folder(mScene, mIOSystem); - + create_embedded_textures_folder(mScene, mIOSystem, mTexturesPath); + for (unsigned int i = 0; i < mScene->mNumTextures; ++i) { aiTexture* tex = mScene->mTextures[i]; std::string fn = CleanTextureFilename(tex->mFilename, false); @@ -174,7 +180,13 @@ PbrtExporter::PbrtExporter( WriteWorldDefinition(); // And write the file to disk... - std::unique_ptr outfile(mIOSystem->Open(mPath,"wt")); + std::string outputFilePath = mPath; + if (!outputFilePath.empty()) { + outputFilePath = outputFilePath + mIOSystem->getOsSeparator(); + } + outputFilePath = outputFilePath + mFile +".pbrt"; + + std::unique_ptr outfile(mIOSystem->Open(outputFilePath,"wt")); if (!outfile) { throw DeadlyExportError("could not open output .pbrt file: " + std::string(mFile)); } @@ -678,7 +690,7 @@ std::string PbrtExporter::CleanTextureFilename(const aiString &f, bool rewriteEx } // Expect all textures in textures - fn = std::string("textures") + mIOSystem->getOsSeparator() + fn; + fn = mTexturesPath + mIOSystem->getOsSeparator() + fn; // Rewrite extension for unsupported file formats. if (rewriteExtension) { @@ -800,10 +812,20 @@ void PbrtExporter::WriteLights() { void PbrtExporter::WriteMesh(aiMesh* mesh) { mOutput << "# - Mesh: "; + const char* mName; if (mesh->mName == aiString("")) - mOutput << "\n"; + mName = ""; else - mOutput << mesh->mName.C_Str() << "\n"; + mName = mesh->mName.C_Str(); + mOutput << mName << "\n"; + + // Check if any types other than tri + if ( (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) + || (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) + || (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) { + std::cerr << "Error: ignoring point / line / polygon mesh " << mName << ".\n"; + return; + } mOutput << "AttributeBegin\n"; aiMaterial* material = mScene->mMaterials[mesh->mMaterialIndex]; @@ -816,14 +838,6 @@ void PbrtExporter::WriteMesh(aiMesh* mesh) { mOutput << " AreaLightSource \"diffuse\" \"rgb L\" [ " << emission.r << " " << emission.g << " " << emission.b << " ]\n"; - // Check if any types other than tri - if ( (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) - || (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) - || (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) { - std::cerr << "Error: ignoring point / line / polygon mesh " << mesh->mName.C_Str() << ".\n"; - return; - } - // Alpha mask std::string alpha; aiString opacityTexture; diff --git a/Dependencies/assimp/code/Pbrt/PbrtExporter.h b/Dependencies/assimp/code/Pbrt/PbrtExporter.h index 0242ddcf0..a18bc39d2 100644 --- a/Dependencies/assimp/code/Pbrt/PbrtExporter.h +++ b/Dependencies/assimp/code/Pbrt/PbrtExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -74,7 +74,7 @@ class PbrtExporter { public: /// Constructor for a specific scene to export PbrtExporter(const aiScene *pScene, IOSystem *pIOSystem, - const std::string &path, const std::string &file); + const std::string &path, const std::string &file, const std::string &texturesPath); /// Destructor virtual ~PbrtExporter() = default; @@ -114,6 +114,9 @@ class PbrtExporter { /// Name of the file (without extension) where the scene will be exported const std::string mFile; + /// Path of the textures directory (inlcuding seperator) + const std::string mTexturesPath; + // A private set to keep track of which textures have been declared std::set mTextureSet; diff --git a/Dependencies/assimp/code/PostProcessing/ArmaturePopulate.cpp b/Dependencies/assimp/code/PostProcessing/ArmaturePopulate.cpp index fa524a7fd..bcba0dbcd 100644 --- a/Dependencies/assimp/code/PostProcessing/ArmaturePopulate.cpp +++ b/Dependencies/assimp/code/PostProcessing/ArmaturePopulate.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -81,7 +81,7 @@ void ArmaturePopulate::Execute(aiScene *out) { aiBone *bone = kvp.first; aiNode *bone_node = kvp.second; ASSIMP_LOG_VERBOSE_DEBUG("active node lookup: ", bone->mName.C_Str()); - + // lcl transform grab - done in generate_nodes :) aiNode *armature = GetArmatureRoot(bone_node, bones); diff --git a/Dependencies/assimp/code/PostProcessing/ArmaturePopulate.h b/Dependencies/assimp/code/PostProcessing/ArmaturePopulate.h index af1792fb0..843fef8a5 100644 --- a/Dependencies/assimp/code/PostProcessing/ArmaturePopulate.h +++ b/Dependencies/assimp/code/PostProcessing/ArmaturePopulate.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -66,22 +65,22 @@ namespace Assimp { * You can contact RevoluPowered * For more info about this */ -class ASSIMP_API ArmaturePopulate : public BaseProcess { +class ASSIMP_API ArmaturePopulate final : public BaseProcess { public: /// The default class constructor. ArmaturePopulate() = default; /// The class destructor. - virtual ~ArmaturePopulate() = default; + ~ArmaturePopulate() override = default; /// Overwritten, @see BaseProcess - virtual bool IsActive( unsigned int pFlags ) const; + bool IsActive( unsigned int pFlags ) const override; /// Overwritten, @see BaseProcess - virtual void SetupProperties( const Importer* pImp ); + void SetupProperties( const Importer* pImp ) override; /// Overwritten, @see BaseProcess - virtual void Execute( aiScene* pScene ); + void Execute( aiScene* pScene ) override; static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector &bone_list); diff --git a/Dependencies/assimp/code/PostProcessing/CalcTangentsProcess.cpp b/Dependencies/assimp/code/PostProcessing/CalcTangentsProcess.cpp index 8fd063260..25d5b5139 100644 --- a/Dependencies/assimp/code/PostProcessing/CalcTangentsProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/CalcTangentsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team @@ -200,7 +200,7 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) { localBitangent.NormalizeSafe(); // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN. - bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z) + bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z) || (-0.5f < localTangent.x && localTangent.x < 0.5f && -0.5f < localTangent.y && localTangent.y < 0.5f && -0.5f < localTangent.z && localTangent.z < 0.5f); bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z) || (-0.5f < localBitangent.x && localBitangent.x < 0.5f && -0.5f < localBitangent.y && localBitangent.y < 0.5f && -0.5f < localBitangent.z && localBitangent.z < 0.5f); diff --git a/Dependencies/assimp/code/PostProcessing/CalcTangentsProcess.h b/Dependencies/assimp/code/PostProcessing/CalcTangentsProcess.h index 3d7bb2a5e..19e3ab6a8 100644 --- a/Dependencies/assimp/code/PostProcessing/CalcTangentsProcess.h +++ b/Dependencies/assimp/code/PostProcessing/CalcTangentsProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -59,7 +58,7 @@ namespace Assimp * because the joining of vertices also considers tangents and bitangents for * uniqueness. */ -class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess { +class ASSIMP_API_WINONLY CalcTangentsProcess final : public BaseProcess { public: CalcTangentsProcess(); ~CalcTangentsProcess() override = default; diff --git a/Dependencies/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp b/Dependencies/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp index cac51e8d0..8a2f8d413 100644 --- a/Dependencies/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/ComputeUVMappingProcess.h b/Dependencies/assimp/code/PostProcessing/ComputeUVMappingProcess.h index 2a40a15b1..78ca18da8 100644 --- a/Dependencies/assimp/code/PostProcessing/ComputeUVMappingProcess.h +++ b/Dependencies/assimp/code/PostProcessing/ComputeUVMappingProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -59,7 +58,7 @@ namespace Assimp { /** ComputeUVMappingProcess - converts special mappings, such as spherical, * cylindrical or boxed to proper UV coordinates for rendering. */ -class ComputeUVMappingProcess : public BaseProcess { +class ComputeUVMappingProcess final : public BaseProcess { public: ComputeUVMappingProcess() = default; ~ComputeUVMappingProcess() override = default; diff --git a/Dependencies/assimp/code/PostProcessing/ConvertToLHProcess.cpp b/Dependencies/assimp/code/PostProcessing/ConvertToLHProcess.cpp index 77c7cb853..31d37e0a6 100644 --- a/Dependencies/assimp/code/PostProcessing/ConvertToLHProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/ConvertToLHProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/ConvertToLHProcess.h b/Dependencies/assimp/code/PostProcessing/ConvertToLHProcess.h index e5ef19a8d..9cdeb2225 100644 --- a/Dependencies/assimp/code/PostProcessing/ConvertToLHProcess.h +++ b/Dependencies/assimp/code/PostProcessing/ConvertToLHProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -60,7 +60,7 @@ struct aiNode; struct aiMaterial; struct aiCamera; -namespace Assimp { +namespace Assimp { // ----------------------------------------------------------------------------------- /** @brief The MakeLeftHandedProcess converts all imported data to a left-handed @@ -72,7 +72,7 @@ namespace Assimp { * * @note RH-LH and LH-RH is the same, so this class can be used for both */ -class MakeLeftHandedProcess : public BaseProcess { +class MakeLeftHandedProcess final : public BaseProcess { public: MakeLeftHandedProcess() = default; ~MakeLeftHandedProcess() override = default; @@ -147,7 +147,7 @@ class FlipWindingOrderProcess : public BaseProcess { // --------------------------------------------------------------------------- /** Postprocessing step to flip the UV coordinate system of the import data */ -class FlipUVsProcess : public BaseProcess +class FlipUVsProcess final : public BaseProcess { friend class Importer; @@ -156,13 +156,13 @@ class FlipUVsProcess : public BaseProcess FlipUVsProcess(); /** Destructor, private as well */ - ~FlipUVsProcess(); + ~FlipUVsProcess() override; // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; + bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- - void Execute( aiScene* pScene); + void Execute( aiScene* pScene) override; protected: void ProcessMesh( aiMesh* pMesh); diff --git a/Dependencies/assimp/code/PostProcessing/DeboneProcess.cpp b/Dependencies/assimp/code/PostProcessing/DeboneProcess.cpp index 1ae79ee30..b886cffcc 100644 --- a/Dependencies/assimp/code/PostProcessing/DeboneProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/DeboneProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -187,7 +187,7 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) { } } else { vertexBones[vid] = i; - } + } } if(!isBoneNecessary[i]) { diff --git a/Dependencies/assimp/code/PostProcessing/DeboneProcess.h b/Dependencies/assimp/code/PostProcessing/DeboneProcess.h index cc2d43cb7..2727130a1 100644 --- a/Dependencies/assimp/code/PostProcessing/DeboneProcess.h +++ b/Dependencies/assimp/code/PostProcessing/DeboneProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -52,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#// Forward declarations +// Forward declarations class DeboneTest; namespace Assimp { @@ -67,13 +66,15 @@ namespace Assimp { * the bone are split from the mesh. The split off (new) mesh is boneless. At any * point in time, bones without affect upon a given mesh are to be removed. */ -class DeboneProcess : public BaseProcess { +class DeboneProcess final : public BaseProcess { public: DeboneProcess(); ~DeboneProcess() override = default; // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. + /** + * @brief Returns whether the processing step is present in the given flag. + * * @param pFlags The processing flags the importer was called with. * A bitwise combination of #aiPostProcessSteps. * @return true if the process is present in this flag fields, @@ -82,7 +83,9 @@ class DeboneProcess : public BaseProcess { bool IsActive( unsigned int pFlags) const override; // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). + /** + * @brief Called prior to ExecuteOnScene(). + * * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ @@ -90,33 +93,41 @@ class DeboneProcess : public BaseProcess { protected: // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ + /** + * @brief Executes the post processing step on the given imported data. + * + * At the moment a process is not supposed to fail. + * @param pScene The imported data to work at. + */ void Execute( aiScene* pScene) override; // ------------------------------------------------------------------- - /** Counts bones total/removable in a given mesh. + /** + * @brief Counts bones total/removable in a given mesh. + * * @param pMesh The mesh to process. + * @return false in case of an error. */ bool ConsiderMesh( const aiMesh* pMesh); - /// Splits the given mesh by bone count. + /// @brief Splits the given mesh by bone count. /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split. /// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary. void SplitMesh(const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const; - /// Recursively updates the node's mesh list to account for the changed mesh list + /// @brief Recursively updates the node's mesh list to account for the changed mesh list + /// @param pNode The root node to update. void UpdateNode(aiNode* pNode) const; // ------------------------------------------------------------------- - // Apply transformation to a mesh + /// @brief Apply transformation to a mesh + /// @param mesh The mesh to apply the transformation + /// @param mat The transformation to appy void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const; public: - /** Number of bones present in the scene. */ - unsigned int mNumBones; + /// Number of bones present in the scene. + unsigned int mNumBones; unsigned int mNumBonesCanDoWithout; float mThreshold; diff --git a/Dependencies/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp b/Dependencies/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp index 29967b74b..b3d743c2f 100644 --- a/Dependencies/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team diff --git a/Dependencies/assimp/code/PostProcessing/DropFaceNormalsProcess.h b/Dependencies/assimp/code/PostProcessing/DropFaceNormalsProcess.h index 84f9dbe83..ce1a9ceeb 100644 --- a/Dependencies/assimp/code/PostProcessing/DropFaceNormalsProcess.h +++ b/Dependencies/assimp/code/PostProcessing/DropFaceNormalsProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -53,7 +52,7 @@ namespace Assimp { // --------------------------------------------------------------------------- /** The DropFaceNormalsProcess computes face normals for all faces of all meshes */ -class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess { +class ASSIMP_API_WINONLY DropFaceNormalsProcess final : public BaseProcess { public: DropFaceNormalsProcess() = default; ~DropFaceNormalsProcess() override = default; diff --git a/Dependencies/assimp/code/PostProcessing/EmbedTexturesProcess.cpp b/Dependencies/assimp/code/PostProcessing/EmbedTexturesProcess.cpp index 568031d8f..60f535776 100644 --- a/Dependencies/assimp/code/PostProcessing/EmbedTexturesProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/EmbedTexturesProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ProcessHelper.h" #include +#include using namespace Assimp; @@ -91,25 +92,47 @@ void EmbedTexturesProcess::Execute(aiScene* pScene) { ASSIMP_LOG_INFO("EmbedTexturesProcess finished. Embedded ", embeddedTexturesCount, " textures." ); } +std::string EmbedTexturesProcess::tryToFindValidPath(const std::string &imagePath) const +{ + // Test path directly + if (mIOHandler->Exists(imagePath)) { + return imagePath; + } + ASSIMP_LOG_WARN("EmbedTexturesProcess: Cannot find image: ", imagePath, ". Will try to find it in root folder."); + + // Test path in root path + std::string testPath = mRootPath + imagePath; + if (mIOHandler->Exists(testPath)) { + return testPath; + } + + // Test path basename in root path + testPath = mRootPath + imagePath.substr(imagePath.find_last_of("\\/") + 1u); + if (mIOHandler->Exists(testPath)) { + return testPath; + } + + // In unix systems, '\' is a valid file name character, but some files may use \ as a directory separator. + // Try replacing '\' by '/'. + if (mIOHandler->getOsSeparator() != '\\' && imagePath.find('\\') != std::string::npos) { + ASSIMP_LOG_WARN("EmbedTexturesProcess: Cannot find image '", imagePath, "' in root folder. Will try replacing directory separators."); + testPath = imagePath; + std::replace(testPath.begin(), testPath.end(), '\\', mIOHandler->getOsSeparator()); + return tryToFindValidPath(testPath); + } + + ASSIMP_LOG_ERROR("EmbedTexturesProcess: Unable to embed texture: ", imagePath, "."); + return {}; +} + bool EmbedTexturesProcess::addTexture(aiScene *pScene, const std::string &path) const { std::streampos imageSize = 0; - std::string imagePath = path; + std::string imagePath = tryToFindValidPath(path); - // Test path directly - if (!mIOHandler->Exists(imagePath)) { - ASSIMP_LOG_WARN("EmbedTexturesProcess: Cannot find image: ", imagePath, ". Will try to find it in root folder."); - - // Test path in root path - imagePath = mRootPath + path; - if (!mIOHandler->Exists(imagePath)) { - // Test path basename in root path - imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u); - if (!mIOHandler->Exists(imagePath)) { - ASSIMP_LOG_ERROR("EmbedTexturesProcess: Unable to embed texture: ", path, "."); - return false; - } - } + if (imagePath.empty()) { + return false; } + IOStream* pFile = mIOHandler->Open(imagePath); if (pFile == nullptr) { ASSIMP_LOG_ERROR("EmbedTexturesProcess: Unable to embed texture: ", path, "."); diff --git a/Dependencies/assimp/code/PostProcessing/EmbedTexturesProcess.h b/Dependencies/assimp/code/PostProcessing/EmbedTexturesProcess.h index 8210eec96..991474d39 100644 --- a/Dependencies/assimp/code/PostProcessing/EmbedTexturesProcess.h +++ b/Dependencies/assimp/code/PostProcessing/EmbedTexturesProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -59,7 +58,7 @@ namespace Assimp { * it will check if a file with the same name exists at the root folder * of the imported model. And if so, it uses that. */ -class ASSIMP_API EmbedTexturesProcess : public BaseProcess { +class ASSIMP_API EmbedTexturesProcess final : public BaseProcess { public: /// The default class constructor. EmbedTexturesProcess() = default; @@ -74,9 +73,11 @@ class ASSIMP_API EmbedTexturesProcess : public BaseProcess { void SetupProperties(const Importer* pImp) override; /// Overwritten, @see BaseProcess - virtual void Execute(aiScene* pScene) override; + void Execute(aiScene* pScene) override; private: + // Try several ways to attempt to resolve the image path + std::string tryToFindValidPath(const std::string &imagePath) const; // Resolve the path and add the file content to the scene as a texture. bool addTexture(aiScene *pScene, const std::string &path) const; diff --git a/Dependencies/assimp/code/PostProcessing/FindDegenerates.cpp b/Dependencies/assimp/code/PostProcessing/FindDegenerates.cpp index 7401ea0e7..8f0ed62ed 100644 --- a/Dependencies/assimp/code/PostProcessing/FindDegenerates.cpp +++ b/Dependencies/assimp/code/PostProcessing/FindDegenerates.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/FindDegenerates.h b/Dependencies/assimp/code/PostProcessing/FindDegenerates.h index 0d046df2d..940f20e29 100644 --- a/Dependencies/assimp/code/PostProcessing/FindDegenerates.h +++ b/Dependencies/assimp/code/PostProcessing/FindDegenerates.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -50,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include class FindDegeneratesProcessTest; -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- diff --git a/Dependencies/assimp/code/PostProcessing/FindInstancesProcess.cpp b/Dependencies/assimp/code/PostProcessing/FindInstancesProcess.cpp index 9186dd3dd..c33ece2c1 100644 --- a/Dependencies/assimp/code/PostProcessing/FindInstancesProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/FindInstancesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team diff --git a/Dependencies/assimp/code/PostProcessing/FindInstancesProcess.h b/Dependencies/assimp/code/PostProcessing/FindInstancesProcess.h index 63e988abf..3e06b3e38 100644 --- a/Dependencies/assimp/code/PostProcessing/FindInstancesProcess.h +++ b/Dependencies/assimp/code/PostProcessing/FindInstancesProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/FindInvalidDataProcess.cpp b/Dependencies/assimp/code/PostProcessing/FindInvalidDataProcess.cpp index 12f345407..c1fa7795d 100644 --- a/Dependencies/assimp/code/PostProcessing/FindInvalidDataProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/FindInvalidDataProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/FindInvalidDataProcess.h b/Dependencies/assimp/code/PostProcessing/FindInvalidDataProcess.h index 516db4272..bac6c0eb7 100644 --- a/Dependencies/assimp/code/PostProcessing/FindInvalidDataProcess.h +++ b/Dependencies/assimp/code/PostProcessing/FindInvalidDataProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/FixNormalsStep.cpp b/Dependencies/assimp/code/PostProcessing/FixNormalsStep.cpp index 2bf85430f..444de7963 100644 --- a/Dependencies/assimp/code/PostProcessing/FixNormalsStep.cpp +++ b/Dependencies/assimp/code/PostProcessing/FixNormalsStep.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team diff --git a/Dependencies/assimp/code/PostProcessing/FixNormalsStep.h b/Dependencies/assimp/code/PostProcessing/FixNormalsStep.h index b25d92282..1657bbd9a 100644 --- a/Dependencies/assimp/code/PostProcessing/FixNormalsStep.h +++ b/Dependencies/assimp/code/PostProcessing/FixNormalsStep.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp b/Dependencies/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp index da9fd7137..ee3b38e7f 100644 --- a/Dependencies/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/GenBoundingBoxesProcess.h b/Dependencies/assimp/code/PostProcessing/GenBoundingBoxesProcess.h index c24009dc9..c7cd19677 100644 --- a/Dependencies/assimp/code/PostProcessing/GenBoundingBoxesProcess.h +++ b/Dependencies/assimp/code/PostProcessing/GenBoundingBoxesProcess.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -19,7 +19,7 @@ conditions are met: copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -s + * Neither the name of the assimp team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior @@ -54,7 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -/** +/** * @brief Post-processing process to find axis-aligned bounding volumes for amm meshes * used in a scene. */ diff --git a/Dependencies/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp b/Dependencies/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp index 79a30ca24..bcbc94b59 100644 --- a/Dependencies/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -41,9 +39,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -/** @file Implementation of the post processing step to generate face -* normals for all imported faces. -*/ +/** + * @file Implementation of the post-processing step to generate face + * normals for all imported faces. + */ #include "GenFaceNormalsProcess.h" #include @@ -52,10 +51,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include + using namespace Assimp; // ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. +// Returns whether the processing step is in the given flag field. bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const { force_ = (pFlags & aiProcess_ForceGenNormals) != 0; flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0; @@ -64,7 +66,7 @@ bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const { } // ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. +// Executes the post-processing step on the given imported data. void GenFaceNormalsProcess::Execute(aiScene *pScene) { ASSIMP_LOG_DEBUG("GenFaceNormalsProcess begin"); @@ -87,8 +89,66 @@ void GenFaceNormalsProcess::Execute(aiScene *pScene) { } } +namespace { + +template +void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { + // replace vertex data with the unique data sets + pMesh->mNumVertices = static_cast(uniqueVertices.size()); + + // ---------------------------------------------------------------------------- + // NOTE - we're *not* calling Vertex::SortBack() because it would check for + // presence of every single vertex component once PER VERTEX. And our CPU + // dislikes branches, even if they're easily predictable. + // ---------------------------------------------------------------------------- + + // Position, if present (check made for aiAnimMesh) + if (pMesh->mVertices) { + std::unique_ptr oldVertices(pMesh->mVertices); + pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mVertices[a] = oldVertices[uniqueVertices[a]]; + } + } + + // Tangents, if present + if (pMesh->mTangents) { + std::unique_ptr oldTangents(pMesh->mTangents); + pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mTangents[a] = oldTangents[uniqueVertices[a]]; + } + } + // Bitangents as well + if (pMesh->mBitangents) { + std::unique_ptr oldBitangents(pMesh->mBitangents); + pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { + pMesh->mBitangents[a] = oldBitangents[uniqueVertices[a]]; + } + } + // Vertex colors + for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) { + std::unique_ptr oldColors(pMesh->mColors[a]); + pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices]; + for (unsigned int b = 0; b < pMesh->mNumVertices; b++) { + pMesh->mColors[a][b] = oldColors[uniqueVertices[b]]; + } + } + // Texture coords + for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) { + std::unique_ptr oldTextureCoords(pMesh->mTextureCoords[a]); + pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices]; + for (unsigned int b = 0; b < pMesh->mNumVertices; b++) { + pMesh->mTextureCoords[a][b] = oldTextureCoords[uniqueVertices[b]]; + } + } +} + +} // namespace + // ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. +// Executes the post-processing step on the given imported data. bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) { if (nullptr != pMesh->mNormals) { if (force_) { @@ -107,8 +167,31 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) { } // allocate an array to hold the output normals - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - const float qnan = get_qnan(); + std::vector normals; + normals.resize(pMesh->mNumVertices); + + // mask to indicate if a vertex was already referenced and needs to be duplicated + std::vector alreadyReferenced; + alreadyReferenced.resize(pMesh->mNumVertices, false); + + std::vector duplicatedVertices; + duplicatedVertices.resize(pMesh->mNumVertices); + std::iota(std::begin(duplicatedVertices), std::end(duplicatedVertices), 0); + + auto storeNormalSplitVertex = [&](unsigned int index, const aiVector3D& normal) { + if (!alreadyReferenced[index]) { + normals[index] = normal; + alreadyReferenced[index] = true; + } else { + normals.push_back(normal); + duplicatedVertices.push_back(index); + index = static_cast(duplicatedVertices.size() - 1); + } + + return index; + }; + + const aiVector3D undefinedNormal = aiVector3D(get_qnan()); // iterate through all faces and compute per-face normals but store them per-vertex. for (unsigned int a = 0; a < pMesh->mNumFaces; a++) { @@ -116,7 +199,7 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) { if (face.mNumIndices < 3) { // either a point or a line -> no well-defined normal vector for (unsigned int i = 0; i < face.mNumIndices; ++i) { - pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan); + face.mIndices[i] = storeNormalSplitVertex(face.mIndices[i], undefinedNormal); } continue; } @@ -124,15 +207,23 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) { const aiVector3D *pV1 = &pMesh->mVertices[face.mIndices[0]]; const aiVector3D *pV2 = &pMesh->mVertices[face.mIndices[1]]; const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]]; - // Boolean XOR - if either but not both of these flags is set, then the winding order has - // changed and the cross product to calculate the normal needs to be reversed - if (flippedWindingOrder_ != leftHanded_) + // Boolean XOR - if either but not both of these flags are set, then the winding order has + // changed and the cross-product to calculate the normal needs to be reversed + if (flippedWindingOrder_ != leftHanded_) std::swap(pV2, pV3); const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe(); for (unsigned int i = 0; i < face.mNumIndices; ++i) { - pMesh->mNormals[face.mIndices[i]] = vNor; + face.mIndices[i] = storeNormalSplitVertex(face.mIndices[i], vNor); } } + + // store normals (and additional vertices) back into the mesh + if (pMesh->mNumVertices != std::size(duplicatedVertices)) { + updateXMeshVertices(pMesh, duplicatedVertices); + } + pMesh->mNormals = new aiVector3D[normals.size()]; + memcpy(pMesh->mNormals, normals.data(), normals.size() * sizeof(aiVector3D)); + return true; } diff --git a/Dependencies/assimp/code/PostProcessing/GenFaceNormalsProcess.h b/Dependencies/assimp/code/PostProcessing/GenFaceNormalsProcess.h index a5aad13d1..78a0be858 100644 --- a/Dependencies/assimp/code/PostProcessing/GenFaceNormalsProcess.h +++ b/Dependencies/assimp/code/PostProcessing/GenFaceNormalsProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -50,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { // --------------------------------------------------------------------------- -/** +/** * @brief The GenFaceNormalsProcess computes face normals for all faces of all meshes */ class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess { diff --git a/Dependencies/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp b/Dependencies/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp index f7fef6bc4..4780b5daf 100644 --- a/Dependencies/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/GenVertexNormalsProcess.h b/Dependencies/assimp/code/PostProcessing/GenVertexNormalsProcess.h index 677c06a43..89970f4d2 100644 --- a/Dependencies/assimp/code/PostProcessing/GenVertexNormalsProcess.h +++ b/Dependencies/assimp/code/PostProcessing/GenVertexNormalsProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/ImproveCacheLocality.cpp b/Dependencies/assimp/code/PostProcessing/ImproveCacheLocality.cpp index e108354b1..34c51c707 100644 --- a/Dependencies/assimp/code/PostProcessing/ImproveCacheLocality.cpp +++ b/Dependencies/assimp/code/PostProcessing/ImproveCacheLocality.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -380,4 +380,3 @@ ai_real ImproveCacheLocalityProcess::ProcessMesh(aiMesh *pMesh, unsigned int mes } } // namespace Assimp - diff --git a/Dependencies/assimp/code/PostProcessing/ImproveCacheLocality.h b/Dependencies/assimp/code/PostProcessing/ImproveCacheLocality.h index 30fa59608..f4e9c517d 100644 --- a/Dependencies/assimp/code/PostProcessing/ImproveCacheLocality.h +++ b/Dependencies/assimp/code/PostProcessing/ImproveCacheLocality.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/JoinVerticesProcess.cpp b/Dependencies/assimp/code/PostProcessing/JoinVerticesProcess.cpp index f4c623c98..89c7c51ce 100644 --- a/Dependencies/assimp/code/PostProcessing/JoinVerticesProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/JoinVerticesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include using namespace Assimp; @@ -99,51 +100,64 @@ void JoinVerticesProcess::Execute( aiScene* pScene) { namespace { -bool areVerticesEqual( - const Vertex &lhs, - const Vertex &rhs, - unsigned numUVChannels, - unsigned numColorChannels) { - // A little helper to find locally close vertices faster. - // Try to reuse the lookup table from the last step. - const static float epsilon = 1e-5f; - // Squared because we check against squared length of the vector difference - static const float squareEpsilon = epsilon * epsilon; - - // Square compare is useful for animeshes vertices compare - if ((lhs.position - rhs.position).SquareLength() > squareEpsilon) { - return false; - } +struct CompareVerticesAlmostEqual { + bool operator () (const Vertex & a, const Vertex & b) const { + static const float epsilon = 1e-5f; + static const float squareEpsilon = epsilon * epsilon; - // We just test the other attributes even if they're not present in the mesh. - // In this case they're initialized to 0 so the comparison succeeds. - // By this method the non-present attributes are effectively ignored in the comparison. - if ((lhs.normal - rhs.normal).SquareLength() > squareEpsilon) { - return false; - } + if ((a.position - b.position).SquareLength() > squareEpsilon) { + return false; + } - if ((lhs.tangent - rhs.tangent).SquareLength() > squareEpsilon) { - return false; - } + // We just test the other attributes even if they're not present in the mesh. + // In this case they're initialized to 0 so the comparison succeeds. + // By this method the non-present attributes are effectively ignored in the comparison. - if ((lhs.bitangent - rhs.bitangent).SquareLength() > squareEpsilon) { - return false; - } + if ((a.normal - b.normal).SquareLength() > squareEpsilon) { + return false; + } - for (unsigned i = 0; i < numUVChannels; i++) { - if ((lhs.texcoords[i] - rhs.texcoords[i]).SquareLength() > squareEpsilon) { + if ((a.tangent - b.tangent).SquareLength() > squareEpsilon) { return false; } - } - for (unsigned i = 0; i < numColorChannels; i++) { - if (GetColorDifference(lhs.colors[i], rhs.colors[i]) > squareEpsilon) { + if ((a.bitangent - b.bitangent).SquareLength() > squareEpsilon) { return false; } + + for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i ++) { + if ((a.texcoords[i] - b.texcoords[i]).SquareLength() > squareEpsilon) { + return false; + } + } + + for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; i ++) { + if (GetColorDifference(a.colors[i], b.colors[i]) > squareEpsilon) { + return false; + } + } + + // If reached this point, they are ~equal + return true; } +}; - return true; -} +struct HashVertex { + inline void hash_combine(std::size_t& seed, const ai_real& v) const { + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + + size_t operator () (const Vertex & v) const { + size_t hash = 0; + + hash_combine(hash, v.position.x); + hash_combine(hash, v.position.y); + hash_combine(hash, v.position.z); + + return hash; + } +}; template void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { @@ -157,7 +171,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { // ---------------------------------------------------------------------------- // Position, if present (check made for aiAnimMesh) - if (pMesh->mVertices) { + if (pMesh->mVertices) { std::unique_ptr oldVertices(pMesh->mVertices); pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; for (unsigned int a = 0; a < pMesh->mNumVertices; a++) @@ -204,41 +218,6 @@ void updateXMeshVertices(XMesh *pMesh, std::vector &uniqueVertices) { } // namespace // ------------------------------------------------------------------------------------------------ -// Unites identical vertices in the given mesh -// combine hashes -inline void hash_combine(std::size_t &) { - // empty -} - -template -inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) { - std::hash hasher; - seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); - hash_combine(seed, rest...); -} -//template specialization for std::hash for Vertex -template<> -struct std::hash { - std::size_t operator()(Vertex const& v) const noexcept { - size_t seed = 0; - hash_combine(seed, v.position.x ,v.position.y,v.position.z); - return seed; - } -}; -//template specialization for std::equal_to for Vertex -template<> -struct std::equal_to { - equal_to(unsigned numUVChannels, unsigned numColorChannels) : - mNumUVChannels(numUVChannels), - mNumColorChannels(numColorChannels) {} - bool operator()(const Vertex &lhs, const Vertex &rhs) const { - return areVerticesEqual(lhs, rhs, mNumUVChannels, mNumColorChannels); - } - -private: - unsigned mNumUVChannels; - unsigned mNumColorChannels; -}; static constexpr size_t JOINED_VERTICES_MARK = 0x80000000u; @@ -266,7 +245,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) { // We'll never have more vertices afterwards. std::vector uniqueVertices; - uniqueVertices.reserve( pMesh->mNumVertices); // For each vertex the index of the vertex it was replaced by. // Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark @@ -276,31 +254,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) { static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff"); std::vector replaceIndex( pMesh->mNumVertices, 0xffffffff); - // float posEpsilonSqr; - SpatialSort *vertexFinder = nullptr; - SpatialSort _vertexFinder; - - typedef std::pair SpatPair; - if (shared) { - std::vector* avf; - shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); - if (avf) { - SpatPair& blubb = (*avf)[meshIndex]; - vertexFinder = &blubb.first; - // posEpsilonSqr = blubb.second; - } - } - if (!vertexFinder) { - // bad, need to compute it. - _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); - vertexFinder = &_vertexFinder; - // posEpsilonSqr = ComputePositionEpsilon(pMesh); - } - - // Again, better waste some bytes than a realloc ... - std::vector verticesFound; - verticesFound.reserve(10); - // Run an optimized code path if we don't have multiple UVs or vertex colors. // This should yield false in more than 99% of all imports ... const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0; @@ -314,14 +267,8 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) { } } // a map that maps a vertex to its new index - const auto numBuckets = pMesh->mNumVertices; - const auto hasher = std::hash(); - const auto comparator = std::equal_to( - pMesh->GetNumUVChannels(), - pMesh->GetNumColorChannels()); - std::unordered_map vertex2Index(numBuckets, hasher, comparator); + std::unordered_map vertex2Index = {}; // we can not end up with more vertices than we started with - vertex2Index.reserve(pMesh->mNumVertices); // Now check each vertex if it brings something new to the table int newIndex = 0; for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { @@ -336,8 +283,8 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) { // if the vertex is not in the map then it is a new vertex add it. if (it == vertex2Index.end()) { // this is a new vertex give it a new index - vertex2Index[v] = newIndex; - //keep track of its index and increment 1 + vertex2Index.emplace(v, newIndex); + // keep track of its index and increment 1 replaceIndex[a] = newIndex++; // add the vertex to the unique vertices uniqueVertices.push_back(a); diff --git a/Dependencies/assimp/code/PostProcessing/JoinVerticesProcess.h b/Dependencies/assimp/code/PostProcessing/JoinVerticesProcess.h index 60630dae3..19f82b860 100644 --- a/Dependencies/assimp/code/PostProcessing/JoinVerticesProcess.h +++ b/Dependencies/assimp/code/PostProcessing/JoinVerticesProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -65,7 +64,7 @@ class ASSIMP_API JoinVerticesProcess : public BaseProcess { public: // ------------------------------------------------------------------- /// The default class constructor / destructor. - JoinVerticesProcess() = default; + JoinVerticesProcess() = default; ~JoinVerticesProcess() override = default; // ------------------------------------------------------------------- diff --git a/Dependencies/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp b/Dependencies/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp index 71b6f9ec6..0c5ad86a3 100644 --- a/Dependencies/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -68,7 +68,7 @@ bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const { // Executes the post processing step on the given imported data. void LimitBoneWeightsProcess::Execute( aiScene* pScene) { ai_assert(pScene != nullptr); - + ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin"); for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) { @@ -88,7 +88,7 @@ void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) { // ------------------------------------------------------------------------------------------------ static unsigned int removeEmptyBones(aiMesh *pMesh) { ai_assert(pMesh != nullptr); - + unsigned int writeBone = 0; for (unsigned int readBone = 0; readBone< pMesh->mNumBones; ++readBone) { aiBone* bone = pMesh->mBones[readBone]; @@ -98,7 +98,7 @@ static unsigned int removeEmptyBones(aiMesh *pMesh) { delete bone; } } - + return writeBone; } diff --git a/Dependencies/assimp/code/PostProcessing/LimitBoneWeightsProcess.h b/Dependencies/assimp/code/PostProcessing/LimitBoneWeightsProcess.h index b2612c313..f3bdd473a 100644 --- a/Dependencies/assimp/code/PostProcessing/LimitBoneWeightsProcess.h +++ b/Dependencies/assimp/code/PostProcessing/LimitBoneWeightsProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/MakeVerboseFormat.cpp b/Dependencies/assimp/code/PostProcessing/MakeVerboseFormat.cpp index d0c5693e7..6783668a3 100644 --- a/Dependencies/assimp/code/PostProcessing/MakeVerboseFormat.cpp +++ b/Dependencies/assimp/code/PostProcessing/MakeVerboseFormat.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team diff --git a/Dependencies/assimp/code/PostProcessing/MakeVerboseFormat.h b/Dependencies/assimp/code/PostProcessing/MakeVerboseFormat.h index 02fe21fa7..42dc450ab 100644 --- a/Dependencies/assimp/code/PostProcessing/MakeVerboseFormat.h +++ b/Dependencies/assimp/code/PostProcessing/MakeVerboseFormat.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -50,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMesh; -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** MakeVerboseFormatProcess: Class to convert an asset to the verbose diff --git a/Dependencies/assimp/code/PostProcessing/OptimizeGraph.cpp b/Dependencies/assimp/code/PostProcessing/OptimizeGraph.cpp index 01f6fca14..4197116be 100644 --- a/Dependencies/assimp/code/PostProcessing/OptimizeGraph.cpp +++ b/Dependencies/assimp/code/PostProcessing/OptimizeGraph.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/OptimizeGraph.h b/Dependencies/assimp/code/PostProcessing/OptimizeGraph.h index c32748d7f..db2be3f21 100644 --- a/Dependencies/assimp/code/PostProcessing/OptimizeGraph.h +++ b/Dependencies/assimp/code/PostProcessing/OptimizeGraph.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -58,7 +57,7 @@ struct aiMesh; class OptimizeGraphProcessTest; -namespace Assimp { +namespace Assimp { // ----------------------------------------------------------------------------- /** @brief Postprocessing step to optimize the scenegraph diff --git a/Dependencies/assimp/code/PostProcessing/OptimizeMeshes.cpp b/Dependencies/assimp/code/PostProcessing/OptimizeMeshes.cpp index 44792420c..6f5a89fa1 100644 --- a/Dependencies/assimp/code/PostProcessing/OptimizeMeshes.cpp +++ b/Dependencies/assimp/code/PostProcessing/OptimizeMeshes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team diff --git a/Dependencies/assimp/code/PostProcessing/OptimizeMeshes.h b/Dependencies/assimp/code/PostProcessing/OptimizeMeshes.h index e424ae24a..f5dbb0320 100644 --- a/Dependencies/assimp/code/PostProcessing/OptimizeMeshes.h +++ b/Dependencies/assimp/code/PostProcessing/OptimizeMeshes.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -56,7 +55,7 @@ struct aiMesh; struct aiNode; class OptimizeMeshesProcessTest; -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** @brief Postprocessing step to optimize mesh usage diff --git a/Dependencies/assimp/code/PostProcessing/PretransformVertices.cpp b/Dependencies/assimp/code/PostProcessing/PretransformVertices.cpp index 0203ac211..c65ee2559 100644 --- a/Dependencies/assimp/code/PostProcessing/PretransformVertices.cpp +++ b/Dependencies/assimp/code/PostProcessing/PretransformVertices.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -348,7 +348,7 @@ void PretransformVertices::BuildWCSMeshes(std::vector &out, aiMesh **i mesh->mBones = reinterpret_cast(&node->mTransformation); mesh->mNumBones = UINT_MAX; continue; - } + } // try to find us in the list of newly created meshes for (unsigned int n = 0; n < out.size(); ++n) { diff --git a/Dependencies/assimp/code/PostProcessing/PretransformVertices.h b/Dependencies/assimp/code/PostProcessing/PretransformVertices.h index 74c886488..e4234420a 100644 --- a/Dependencies/assimp/code/PostProcessing/PretransformVertices.h +++ b/Dependencies/assimp/code/PostProcessing/PretransformVertices.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/ProcessHelper.cpp b/Dependencies/assimp/code/PostProcessing/ProcessHelper.cpp index cfbac3e80..f4e3a250e 100644 --- a/Dependencies/assimp/code/PostProcessing/ProcessHelper.cpp +++ b/Dependencies/assimp/code/PostProcessing/ProcessHelper.cpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/ProcessHelper.h b/Dependencies/assimp/code/PostProcessing/ProcessHelper.h index 273b122ae..12882aa70 100644 --- a/Dependencies/assimp/code/PostProcessing/ProcessHelper.h +++ b/Dependencies/assimp/code/PostProcessing/ProcessHelper.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp b/Dependencies/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp index 111c233b1..f1744bfef 100644 --- a/Dependencies/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp +++ b/Dependencies/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -78,7 +78,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) { if (pScene->mNumMaterials == 0) { return; } - + // Find out which materials are referenced by meshes std::vector abReferenced(pScene->mNumMaterials,false); for (unsigned int i = 0;i < pScene->mNumMeshes;++i) { diff --git a/Dependencies/assimp/code/PostProcessing/RemoveRedundantMaterials.h b/Dependencies/assimp/code/PostProcessing/RemoveRedundantMaterials.h index 107de0daa..9fd3f2342 100644 --- a/Dependencies/assimp/code/PostProcessing/RemoveRedundantMaterials.h +++ b/Dependencies/assimp/code/PostProcessing/RemoveRedundantMaterials.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class RemoveRedundantMatsTest; -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** RemoveRedundantMatsProcess: Post-processing step to remove redundant diff --git a/Dependencies/assimp/code/PostProcessing/RemoveVCProcess.cpp b/Dependencies/assimp/code/PostProcessing/RemoveVCProcess.cpp index 13ef81e23..b5c1561d9 100644 --- a/Dependencies/assimp/code/PostProcessing/RemoveVCProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/RemoveVCProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/RemoveVCProcess.h b/Dependencies/assimp/code/PostProcessing/RemoveVCProcess.h index 8d9b5167a..93baeba0c 100644 --- a/Dependencies/assimp/code/PostProcessing/RemoveVCProcess.h +++ b/Dependencies/assimp/code/PostProcessing/RemoveVCProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -83,7 +82,7 @@ class ASSIMP_API RemoveVCProcess : public BaseProcess { * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - virtual void SetupProperties(const Importer* pImp) override; + void SetupProperties(const Importer* pImp) override; // ------------------------------------------------------------------- /** Manually setup the configuration flags for the step diff --git a/Dependencies/assimp/code/PostProcessing/ScaleProcess.cpp b/Dependencies/assimp/code/PostProcessing/ScaleProcess.cpp index 5cd7eea6e..d3066e323 100644 --- a/Dependencies/assimp/code/PostProcessing/ScaleProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/ScaleProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/ScaleProcess.h b/Dependencies/assimp/code/PostProcessing/ScaleProcess.h index 2887c7221..740db69fa 100644 --- a/Dependencies/assimp/code/PostProcessing/ScaleProcess.h +++ b/Dependencies/assimp/code/PostProcessing/ScaleProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -74,13 +73,13 @@ class ASSIMP_API ScaleProcess : public BaseProcess { ai_real getScale() const; /// Overwritten, @see BaseProcess - virtual bool IsActive( unsigned int pFlags ) const override; + bool IsActive( unsigned int pFlags ) const override; /// Overwritten, @see BaseProcess - virtual void SetupProperties( const Importer* pImp ) override; + void SetupProperties( const Importer* pImp ) override; /// Overwritten, @see BaseProcess - virtual void Execute( aiScene* pScene ) override; + void Execute( aiScene* pScene ) override; private: void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 ); diff --git a/Dependencies/assimp/code/PostProcessing/SortByPTypeProcess.cpp b/Dependencies/assimp/code/PostProcessing/SortByPTypeProcess.cpp index 48ebbc573..af4021b32 100644 --- a/Dependencies/assimp/code/PostProcessing/SortByPTypeProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/SortByPTypeProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -65,37 +65,47 @@ void SortByPTypeProcess::SetupProperties(const Importer *pImp) { mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, 0); } +// ------------------------------------------------------------------------------------------------ +static void clearMeshesInNode(aiNode *node) { + delete[] node->mMeshes; + node->mNumMeshes = 0; + node->mMeshes = nullptr; +} + // ------------------------------------------------------------------------------------------------ // Update changed meshes in all nodes void UpdateNodes(const std::vector &replaceMeshIndex, aiNode *node) { + ai_assert(node != nullptr); + if (node->mNumMeshes) { unsigned int newSize = 0; for (unsigned int m = 0; m < node->mNumMeshes; ++m) { unsigned int add = node->mMeshes[m] << 2; for (unsigned int i = 0; i < 4; ++i) { - if (UINT_MAX != replaceMeshIndex[add + i]) ++newSize; + if (UINT_MAX != replaceMeshIndex[add + i]) { + ++newSize; + } } } - if (!newSize) { - delete[] node->mMeshes; - node->mNumMeshes = 0; - node->mMeshes = nullptr; - } else { - // Try to reuse the old array if possible - unsigned int *newMeshes = (newSize > node->mNumMeshes ? new unsigned int[newSize] : node->mMeshes); - - for (unsigned int m = 0; m < node->mNumMeshes; ++m) { - unsigned int add = node->mMeshes[m] << 2; - for (unsigned int i = 0; i < 4; ++i) { - if (UINT_MAX != replaceMeshIndex[add + i]) - *newMeshes++ = replaceMeshIndex[add + i]; + if (newSize == 0) { + clearMeshesInNode(node); + return; + } + + // Try to reuse the old array if possible + unsigned int *newMeshes = (newSize > node->mNumMeshes ? new unsigned int[newSize] : node->mMeshes); + for (unsigned int m = 0; m < node->mNumMeshes; ++m) { + unsigned int add = node->mMeshes[m] << 2; + for (unsigned int i = 0; i < 4; ++i) { + if (UINT_MAX != replaceMeshIndex[add + i]) { + *newMeshes++ = replaceMeshIndex[add + i]; } } - if (newSize > node->mNumMeshes) - delete[] node->mMeshes; - - node->mMeshes = newMeshes - (node->mNumMeshes = newSize); } + if (newSize > node->mNumMeshes) { + clearMeshesInNode(node); + } + node->mMeshes = newMeshes - (node->mNumMeshes = newSize); } // call all subnodes recursively @@ -126,6 +136,9 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { aiMesh *const mesh = pScene->mMeshes[i]; if (mesh->mPrimitiveTypes == 0) { + for (size_t idx = 0; idx < outMeshes.size(); ++idx) { + delete outMeshes[idx]; + } throw DeadlyImportError("Mesh with invalid primitive type: ", mesh->mName.C_Str()); } @@ -152,6 +165,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) { *meshIdx = static_cast(outMeshes.size()); outMeshes.emplace_back(mesh); + pScene->mMeshes[i] = nullptr; // Indicate ownership transfer } else { delete mesh; pScene->mMeshes[i] = nullptr; @@ -167,16 +181,23 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { // with the largest number of primitives unsigned int aiNumPerPType[4] = { 0, 0, 0, 0 }; aiFace *pFirstFace = mesh->mFaces; + if (pFirstFace == nullptr) { + continue; + } + aiFace *const pLastFace = pFirstFace + mesh->mNumFaces; unsigned int numPolyVerts = 0; for (; pFirstFace != pLastFace; ++pFirstFace) { - if (pFirstFace->mNumIndices <= 3) + if (pFirstFace->mNumIndices >= 1 && pFirstFace->mNumIndices <= 3) ++aiNumPerPType[pFirstFace->mNumIndices - 1]; else { ++aiNumPerPType[3]; numPolyVerts += pFirstFace->mNumIndices; } + if (pFirstFace->mNumIndices == 0) { + ASSIMP_LOG_WARN("Face with 0 indices treated as polygon"); + } } VertexWeightTable *avw = ComputeVertexBoneWeightTable(mesh); @@ -308,7 +329,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { if (vert) { *vert++ = mesh->mVertices[idx]; } - if (nor) + if (nor) *nor++ = mesh->mNormals[idx]; if (tan) { *tan++ = mesh->mTangents[idx]; @@ -316,13 +337,13 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { } for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) { - if (!uv[pp]) + if (!uv[pp]) break; *uv[pp]++ = mesh->mTextureCoords[pp][idx]; } for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) { - if (!cols[pp]) + if (!cols[pp]) break; *cols[pp]++ = mesh->mColors[pp][idx]; } diff --git a/Dependencies/assimp/code/PostProcessing/SortByPTypeProcess.h b/Dependencies/assimp/code/PostProcessing/SortByPTypeProcess.h index aa7774d7f..f00066a99 100644 --- a/Dependencies/assimp/code/PostProcessing/SortByPTypeProcess.h +++ b/Dependencies/assimp/code/PostProcessing/SortByPTypeProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -50,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class SortByPTypeProcessTest; -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- diff --git a/Dependencies/assimp/code/PostProcessing/SplitByBoneCountProcess.cpp b/Dependencies/assimp/code/PostProcessing/SplitByBoneCountProcess.cpp index f63478767..3c6c4376c 100644 --- a/Dependencies/assimp/code/PostProcessing/SplitByBoneCountProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/SplitByBoneCountProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/SplitByBoneCountProcess.h b/Dependencies/assimp/code/PostProcessing/SplitByBoneCountProcess.h index c90661cb5..8e76991d1 100644 --- a/Dependencies/assimp/code/PostProcessing/SplitByBoneCountProcess.h +++ b/Dependencies/assimp/code/PostProcessing/SplitByBoneCountProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -74,7 +74,7 @@ class SplitByBoneCountProcess : public BaseProcess { /// @brief Called prior to ExecuteOnScene(). /// The function is a request to the process to update its configuration /// basing on the Importer's configuration property list. - virtual void SetupProperties(const Importer* pImp) override; + void SetupProperties(const Importer* pImp) override; /// @brief Will return the maximal number of bones. /// @return The maximal number of bones. diff --git a/Dependencies/assimp/code/PostProcessing/SplitLargeMeshes.cpp b/Dependencies/assimp/code/PostProcessing/SplitLargeMeshes.cpp index 3bee28521..d38abde2a 100644 --- a/Dependencies/assimp/code/PostProcessing/SplitLargeMeshes.cpp +++ b/Dependencies/assimp/code/PostProcessing/SplitLargeMeshes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -100,6 +100,11 @@ void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) { // ------------------------------------------------------------------------------------------------ // Update a node after some meshes have been split void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector >& avList) { + if (pcNode == nullptr) { + ASSIMP_LOG_WARN("UpdateNode skipped, nullptr detected."); + return; + } + // for every index in out list build a new entry std::vector aiEntries; aiEntries.reserve(pcNode->mNumMeshes + 1); diff --git a/Dependencies/assimp/code/PostProcessing/SplitLargeMeshes.h b/Dependencies/assimp/code/PostProcessing/SplitLargeMeshes.h index 25bf300d5..ed140238e 100644 --- a/Dependencies/assimp/code/PostProcessing/SplitLargeMeshes.h +++ b/Dependencies/assimp/code/PostProcessing/SplitLargeMeshes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/TextureTransform.cpp b/Dependencies/assimp/code/PostProcessing/TextureTransform.cpp index 228e97e42..2e529ace3 100644 --- a/Dependencies/assimp/code/PostProcessing/TextureTransform.cpp +++ b/Dependencies/assimp/code/PostProcessing/TextureTransform.cpp @@ -1,8 +1,7 @@ /* Open Asset Import Library (assimp) ---------------------------------------------------------------------- - -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -35,27 +34,20 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ---------------------------------------------------------------------- */ /** @file A helper class that processes texture transformations */ +#include "TextureTransform.h" + #include #include #include #include - -#include "TextureTransform.h" #include -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -TextureTransformStep::TextureTransformStep() : configFlags() { - // nothing to do here -} +namespace Assimp { // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. @@ -202,7 +194,6 @@ inline static const char* MappingModeToChar(aiTextureMapMode map) { void TextureTransformStep::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("TransformUVCoordsProcess begin"); - /* We build a per-mesh list of texture transformations we'll need * to apply. To achieve this, we iterate through all materials, * find all textures and get their transformations and UV indices. @@ -426,7 +417,6 @@ void TextureTransformStep::Execute( aiScene* pScene) { // it shouldn't be too worse if we remove them. unsigned int size = (unsigned int)trafo.size(); if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) { - if (!DefaultLogger::isNullLogger()) { ASSIMP_LOG_ERROR(static_cast(trafo.size()), " UV channels required but just ", AI_MAX_NUMBER_OF_TEXTURECOORDS, " available"); @@ -434,7 +424,6 @@ void TextureTransformStep::Execute( aiScene* pScene) { size = AI_MAX_NUMBER_OF_TEXTURECOORDS; } - aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS]; for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) old[n] = mesh->mTextureCoords[n]; @@ -443,14 +432,13 @@ void TextureTransformStep::Execute( aiScene* pScene) { // that we're not going to need later can be overridden. it = trafo.begin(); for (unsigned int n = 0; n < trafo.size();++n,++it) { - if (n >= size) { // Try to use an untransformed channel for all channels we threw over board UpdateUVIndex((*it).updateList,untransformed); continue; } - outChannels++; + ++outChannels; // Write to the log if (!DefaultLogger::isNullLogger()) { @@ -470,15 +458,18 @@ void TextureTransformStep::Execute( aiScene* pScene) { // Check whether we need a new buffer here if (mesh->mTextureCoords[n]) { - it2 = it;++it2; + it2 = it; + ++it2; for (unsigned int m = n+1; m < size;++m, ++it2) { - if ((*it2).uvIndex == n){ it2 = trafo.begin(); break; } } - if (it2 == trafo.begin()){ + if (it2 == trafo.begin()) { + { + std::unique_ptr oldTextureCoords(mesh->mTextureCoords[n]); + } mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; } } @@ -536,13 +527,12 @@ void TextureTransformStep::Execute( aiScene* pScene) { // Print some detailed statistics into the log if (!DefaultLogger::isNullLogger()) { - if (transformedChannels) { ASSIMP_LOG_INFO("TransformUVCoordsProcess end: ", outChannels, " output channels (in: ", inChannels, ", modified: ", transformedChannels,")"); } else { - ASSIMP_LOG_DEBUG("TransformUVCoordsProcess finished"); + ASSIMP_LOG_INFO("TransformUVCoordsProcess finished"); } } } - +} // namespace Assimp diff --git a/Dependencies/assimp/code/PostProcessing/TextureTransform.h b/Dependencies/assimp/code/PostProcessing/TextureTransform.h index 7c0addf09..ce90cfd74 100644 --- a/Dependencies/assimp/code/PostProcessing/TextureTransform.h +++ b/Dependencies/assimp/code/PostProcessing/TextureTransform.h @@ -1,9 +1,7 @@ /* Open Asset Import Library (assimp) ---------------------------------------------------------------------- - -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -44,142 +42,116 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_TEXTURE_TRANSFORM_H_INCLUDED #define AI_TEXTURE_TRANSFORM_H_INCLUDED -#include #include "Common/BaseProcess.h" +#include #include #include struct aiNode; struct aiMaterial; -namespace Assimp { +namespace Assimp { #define AI_TT_UV_IDX_LOCK_TBD 0xffffffff #define AI_TT_UV_IDX_LOCK_NONE 0xeeeeeeee - - #define AI_TT_ROTATION_EPSILON ((float)AI_DEG_TO_RAD(0.5)) // --------------------------------------------------------------------------- -/** Small helper structure representing a shortcut into the material list - * to be able to update some values quickly. -*/ +/** + * @brief Small helper structure representing a shortcut into the material list + * to be able to update some values quickly. + */ struct TTUpdateInfo { - TTUpdateInfo() AI_NO_EXCEPT - : directShortcut(nullptr) - , mat(nullptr) - , semantic(0) - , index(0) { - // empty - } - //! Direct shortcut, if available - unsigned int* directShortcut; + unsigned int* directShortcut = nullptr; //! Material - aiMaterial *mat; + aiMaterial *mat = nullptr; - //! Texture type and index - unsigned int semantic, index; -}; + //! Texture type + unsigned int semantic = 0; + //! Texture index + unsigned int index = 0; +}; // --------------------------------------------------------------------------- -/** Helper class representing texture coordinate transformations -*/ +/** + * @brief Helper class representing texture coordinate transformations + */ struct STransformVecInfo : public aiUVTransform { - STransformVecInfo() AI_NO_EXCEPT - : uvIndex(0) - , mapU(aiTextureMapMode_Wrap) - , mapV(aiTextureMapMode_Wrap) - , lockedPos(AI_TT_UV_IDX_LOCK_NONE) { - // empty - } - //! Source texture coordinate index - unsigned int uvIndex; + unsigned int uvIndex = 0; + + //! Texture mapping mode in the u direction + aiTextureMapMode mapU = aiTextureMapMode_Wrap; - //! Texture mapping mode in the u, v direction - aiTextureMapMode mapU,mapV; + //! Texture mapping mode in the v direction + aiTextureMapMode mapV = aiTextureMapMode_Wrap; //! Locked destination UV index //! AI_TT_UV_IDX_LOCK_TBD - to be determined //! AI_TT_UV_IDX_LOCK_NONE - none (default) - unsigned int lockedPos; + unsigned int lockedPos = AI_TT_UV_IDX_LOCK_NONE; //! Update info - shortcuts into all materials //! that are referencing this transform setup std::list updateList; - - // ------------------------------------------------------------------- - /** Compare two transform setups - */ - inline bool operator== (const STransformVecInfo& other) const - { + inline bool operator== (const STransformVecInfo& other) const { // We use a small epsilon here const static float epsilon = 0.05f; if (std::fabs( mTranslation.x - other.mTranslation.x ) > epsilon || - std::fabs( mTranslation.y - other.mTranslation.y ) > epsilon) - { + std::fabs( mTranslation.y - other.mTranslation.y ) > epsilon) { return false; } if (std::fabs( mScaling.x - other.mScaling.x ) > epsilon || - std::fabs( mScaling.y - other.mScaling.y ) > epsilon) - { + std::fabs( mScaling.y - other.mScaling.y ) > epsilon) { return false; } - if (std::fabs( mRotation - other.mRotation) > epsilon) - { + if (std::fabs( mRotation - other.mRotation) > epsilon) { return false; } return true; } - inline bool operator!= (const STransformVecInfo& other) const - { + inline bool operator!= (const STransformVecInfo& other) const { return !(*this == other); } - // ------------------------------------------------------------------- - /** Returns whether this is an untransformed texture coordinate set - */ - inline bool IsUntransformed() const - { + /** + * @brief Returns whether this is an untransformed texture coordinate set + */ + inline bool IsUntransformed() const { return (1.0f == mScaling.x && 1.f == mScaling.y && - !mTranslation.x && !mTranslation.y && - mRotation < AI_TT_ROTATION_EPSILON); + !mTranslation.x && !mTranslation.y && mRotation < AI_TT_ROTATION_EPSILON); } // ------------------------------------------------------------------- - /** Build a 3x3 matrix from the transformations - */ - inline void GetMatrix(aiMatrix3x3& mOut) - { + /** + * @brief Build a 3x3 matrix from the transformations + */ + inline void GetMatrix(aiMatrix3x3& mOut) { mOut = aiMatrix3x3(); - - if (1.0f != mScaling.x || 1.0f != mScaling.y) - { + if (1.0f != mScaling.x || 1.0f != mScaling.y) { aiMatrix3x3 mScale; mScale.a1 = mScaling.x; mScale.b2 = mScaling.y; mOut = mScale; } - if (mRotation) - { + if (mRotation) { aiMatrix3x3 mRot; mRot.a1 = mRot.b2 = std::cos(mRotation); mRot.a2 = mRot.b1 = std::sin(mRotation); mRot.a2 = -mRot.a2; mOut *= mRot; } - if (mTranslation.x || mTranslation.y) - { + if (mTranslation.x || mTranslation.y) { aiMatrix3x3 mTrans; mTrans.a3 = mTranslation.x; mTrans.b3 = mTranslation.y; @@ -188,16 +160,18 @@ struct STransformVecInfo : public aiUVTransform { } }; - // --------------------------------------------------------------------------- -/** Helper step to compute final UV coordinate sets if there are scalings +/** + * @brief Helper step to compute final UV coordinate sets if there are scalings * or rotations in the original data read from the file. -*/ -class TextureTransformStep : public BaseProcess { + */ +class TextureTransformStep final : public BaseProcess { public: // ------------------------------------------------------------------- - /// The default class constructor / destructor. - TextureTransformStep(); + /// The default class constructor. / + TextureTransformStep() = default; + + /// The default class destructor. ~TextureTransformStep() override = default; // ------------------------------------------------------------------- @@ -211,16 +185,17 @@ class TextureTransformStep : public BaseProcess { protected: // ------------------------------------------------------------------- - /** Preprocess a specific UV transformation setup + /** + * @brief Preprocess a specific UV transformation setup * * @param info Transformation setup to be preprocessed. - */ + */ void PreProcessUVTransform(STransformVecInfo& info); private: unsigned int configFlags; }; - + } // namespace Assimp #endif //! AI_TEXTURE_TRANSFORM_H_INCLUDED diff --git a/Dependencies/assimp/code/PostProcessing/TriangulateProcess.cpp b/Dependencies/assimp/code/PostProcessing/TriangulateProcess.cpp index c0ffffd6b..cc92b441d 100644 --- a/Dependencies/assimp/code/PostProcessing/TriangulateProcess.cpp +++ b/Dependencies/assimp/code/PostProcessing/TriangulateProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -62,6 +62,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "PostProcessing/TriangulateProcess.h" #include "PostProcessing/ProcessHelper.h" #include "Common/PolyTools.h" +#include "contrib/earcut-hpp/earcut.hpp" #include #include @@ -74,6 +75,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define POLY_GRID_XPAD 20 #define POLY_OUTPUT_FILE "assimp_polygons_debug.txt" +namespace mapbox::util { + +template <> +struct nth<0, aiVector2D> { + inline static auto get(const aiVector2D& t) { + return t.x; + } +}; +template <> +struct nth<1, aiVector2D> { + inline static auto get(const aiVector2D& t) { + return t.y; + } +}; + +} // namespace mapbox::util + using namespace Assimp; namespace { @@ -225,7 +243,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) { ASSIMP_LOG_ERROR( "Invalidation detected in the number of indices: does not fit to the primitive type." ); return false; } - + aiVector3D *nor_out = nullptr; // if we don't have normals yet, but expect them to be a cheap side @@ -244,7 +262,9 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) { aiFace* out = new aiFace[numOut](), *curOut = out; std::vector temp_verts3d(max_out+2); /* temporary storage for vertices */ - std::vector temp_verts(max_out+2); + std::vector> temp_poly(1); /* temporary storage for earcut.hpp */ + std::vector& temp_verts = temp_poly[0]; + temp_verts.reserve(max_out + 2); NGONEncoder ngonEncoder; @@ -264,13 +284,11 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) { const aiVector3D* verts = pMesh->mVertices; - // use std::unique_ptr to avoid slow std::vector specialiations - std::unique_ptr done(new bool[max_out]); for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { aiFace& face = pMesh->mFaces[a]; unsigned int* idx = face.mIndices; - int num = (int)face.mNumIndices, ear = 0, tmp, prev = num-1, next = 0, max = num; + unsigned int num = face.mNumIndices; // Apply vertex colors to represent the face winding? #ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING @@ -363,16 +381,16 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) { // We project it onto a plane to get a 2d triangle. // Collect all vertices of of the polygon. - for (tmp = 0; tmp < max; ++tmp) { + for (unsigned int tmp = 0; tmp < num; ++tmp) { temp_verts3d[tmp] = verts[idx[tmp]]; } // Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh aiVector3D n; - NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z); + NewellNormal<3, 3, 3>(n, num, &temp_verts3d.front().x, &temp_verts3d.front().y, &temp_verts3d.front().z); if (nor_out) { - for (tmp = 0; tmp < max; ++tmp) - nor_out[idx[tmp]] = n; + for (unsigned int tmp = 0; tmp < num; ++tmp) + nor_out[idx[tmp]] = n; } // Select largest normal coordinate to ignore for projection @@ -398,10 +416,20 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) { std::swap(ac,bc); } - for (tmp =0; tmp < max; ++tmp) { + temp_verts.resize(num); + for (unsigned int tmp = 0; tmp < num; ++tmp) { temp_verts[tmp].x = verts[idx[tmp]][ac]; temp_verts[tmp].y = verts[idx[tmp]][bc]; - done[tmp] = false; + } + + auto indices = mapbox::earcut(temp_poly); + for (size_t i = 0; i < indices.size(); i += 3) { + aiFace& nface = *curOut++; + nface.mIndices = new unsigned int[3]; + nface.mNumIndices = 3; + nface.mIndices[0] = indices[i]; + nface.mIndices[1] = indices[i + 1]; + nface.mIndices[2] = indices[i + 2]; } #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS @@ -431,120 +459,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) { fprintf(fout,"\ntriangulation sequence: "); #endif - - // - // FIXME: currently this is the slow O(kn) variant with a worst case - // complexity of O(n^2) (I think). Can be done in O(n). - while (num > 3) { - - // Find the next ear of the polygon - int num_found = 0; - for (ear = next;;prev = ear,ear = next) { - - // break after we looped two times without a positive match - for (next=ear+1;done[(next>=max?next=0:next)];++next); - if (next < ear) { - if (++num_found == 2) { - break; - } - } - const aiVector2D* pnt1 = &temp_verts[ear], - *pnt0 = &temp_verts[prev], - *pnt2 = &temp_verts[next]; - - // Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1. - if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1) == 1) { - continue; - } - - // Skip when three point is in a line - aiVector2D left = *pnt0 - *pnt1; - aiVector2D right = *pnt2 - *pnt1; - - left.Normalize(); - right.Normalize(); - auto mul = left * right; - - // if the angle is 0 or 180 - if (std::abs(mul - 1.f) < ai_epsilon || std::abs(mul + 1.f) < ai_epsilon) { - // skip this ear - ASSIMP_LOG_WARN("Skip a ear, due to its angle is near 0 or 180."); - continue; - } - - // and no other point may be contained in this triangle - for ( tmp = 0; tmp < max; ++tmp) { - - // We need to compare the actual values because it's possible that multiple indexes in - // the polygon are referring to the same position. concave_polygon.obj is a sample - // - // FIXME: Use 'epsiloned' comparisons instead? Due to numeric inaccuracies in - // PointInTriangle() I'm guessing that it's actually possible to construct - // input data that would cause us to end up with no ears. The problem is, - // which epsilon? If we chose a too large value, we'd get wrong results - const aiVector2D& vtmp = temp_verts[tmp]; - if ( vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0,*pnt1,*pnt2,vtmp)) { - break; - } - } - if (tmp != max) { - continue; - } - - // this vertex is an ear - break; - } - if (num_found == 2) { - - // Due to the 'two ear theorem', every simple polygon with more than three points must - // have 2 'ears'. Here's definitely something wrong ... but we don't give up yet. - // - - // Instead we're continuing with the standard tri-fanning algorithm which we'd - // use if we had only convex polygons. That's life. - ASSIMP_LOG_ERROR("Failed to triangulate polygon (no ear found). Probably not a simple polygon?"); - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - fprintf(fout,"critical error here, no ear found! "); -#endif - num = 0; - break; - } - - aiFace& nface = *curOut++; - nface.mNumIndices = 3; - - if (!nface.mIndices) { - nface.mIndices = new unsigned int[3]; - } - - // setup indices for the new triangle ... - nface.mIndices[0] = prev; - nface.mIndices[1] = ear; - nface.mIndices[2] = next; - - // exclude the ear from most further processing - done[ear] = true; - --num; - } - if (num > 0) { - // We have three indices forming the last 'ear' remaining. Collect them. - aiFace& nface = *curOut++; - nface.mNumIndices = 3; - if (!nface.mIndices) { - nface.mIndices = new unsigned int[3]; - } - - for (tmp = 0; done[tmp]; ++tmp); - nface.mIndices[0] = tmp; - - for (++tmp; done[tmp]; ++tmp); - nface.mIndices[1] = tmp; - - for (++tmp; done[tmp]; ++tmp); - nface.mIndices[2] = tmp; - - } } #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS diff --git a/Dependencies/assimp/code/PostProcessing/TriangulateProcess.h b/Dependencies/assimp/code/PostProcessing/TriangulateProcess.h index e17a10e33..ed0841459 100644 --- a/Dependencies/assimp/code/PostProcessing/TriangulateProcess.h +++ b/Dependencies/assimp/code/PostProcessing/TriangulateProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/code/PostProcessing/ValidateDataStructure.cpp b/Dependencies/assimp/code/PostProcessing/ValidateDataStructure.cpp index 8441b48be..166eb9e24 100644 --- a/Dependencies/assimp/code/PostProcessing/ValidateDataStructure.cpp +++ b/Dependencies/assimp/code/PostProcessing/ValidateDataStructure.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -134,7 +134,7 @@ inline void ValidateDSProcess::DoValidationEx(T **parray, unsigned int size, if (size == 0) { return; } - + if (!parray) { ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", firstName, secondName, size); @@ -447,7 +447,7 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh, const aiBone *pBone, float if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) { ReportError("aiBone::mWeights[%i].mVertexId is out of range", i); } else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) { - ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value", i); + ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value %i. Value must be greater than zero and less than 1.", i, pBone->mWeights[i].mWeight); } afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight; } @@ -891,6 +891,9 @@ void ValidateDSProcess::Validate(const aiNode *pNode) { ReportError("aiNode \"%s\" child %i \"%s\" parent is someone else: \"%s\"", pNode->mName.C_Str(), i, pChild->mName.C_Str(), parentName); } } + } else if (pNode->mChildren) { + ReportError("aiNode::mChildren is not nullptr for empty node %s (aiNode::mNumChildren is %i)", + nodeName, pNode->mNumChildren); } } diff --git a/Dependencies/assimp/code/PostProcessing/ValidateDataStructure.h b/Dependencies/assimp/code/PostProcessing/ValidateDataStructure.h index 8bc13e60d..ea80d04d3 100644 --- a/Dependencies/assimp/code/PostProcessing/ValidateDataStructure.h +++ b/Dependencies/assimp/code/PostProcessing/ValidateDataStructure.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -63,7 +62,7 @@ struct aiString; struct aiCamera; struct aiLight; -namespace Assimp { +namespace Assimp { // -------------------------------------------------------------------------------------- /** Validates the whole ASSIMP scene data structure for correctness. diff --git a/Dependencies/assimp/contrib/earcut-hpp/LICENSE b/Dependencies/assimp/contrib/earcut-hpp/LICENSE new file mode 100644 index 000000000..8bafb5773 --- /dev/null +++ b/Dependencies/assimp/contrib/earcut-hpp/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2015, Mapbox + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/Dependencies/assimp/contrib/earcut-hpp/earcut.hpp b/Dependencies/assimp/contrib/earcut-hpp/earcut.hpp new file mode 100644 index 000000000..fd3381484 --- /dev/null +++ b/Dependencies/assimp/contrib/earcut-hpp/earcut.hpp @@ -0,0 +1,814 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mapbox { + +namespace util { + +template struct nth { + inline static typename std::tuple_element::type + get(const T& t) { return std::get(t); }; +}; + +} + +namespace detail { + +template +class Earcut { +public: + std::vector indices; + std::size_t vertices = 0; + + template + void operator()(const Polygon& points); + +private: + struct Node { + Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {} + Node(const Node&) = delete; + Node& operator=(const Node&) = delete; + Node(Node&&) = delete; + Node& operator=(Node&&) = delete; + + const N i; + const double x; + const double y; + + // previous and next vertice nodes in a polygon ring + Node* prev = nullptr; + Node* next = nullptr; + + // z-order curve value + int32_t z = 0; + + // previous and next nodes in z-order + Node* prevZ = nullptr; + Node* nextZ = nullptr; + + // indicates whether this is a steiner point + bool steiner = false; + }; + + template Node* linkedList(const Ring& points, const bool clockwise); + Node* filterPoints(Node* start, Node* end = nullptr); + void earcutLinked(Node* ear, int pass = 0); + bool isEar(Node* ear); + bool isEarHashed(Node* ear); + Node* cureLocalIntersections(Node* start); + void splitEarcut(Node* start); + template Node* eliminateHoles(const Polygon& points, Node* outerNode); + Node* eliminateHole(Node* hole, Node* outerNode); + Node* findHoleBridge(Node* hole, Node* outerNode); + bool sectorContainsSector(const Node* m, const Node* p); + void indexCurve(Node* start); + Node* sortLinked(Node* list); + int32_t zOrder(const double x_, const double y_); + Node* getLeftmost(Node* start); + bool pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const; + bool isValidDiagonal(Node* a, Node* b); + double area(const Node* p, const Node* q, const Node* r) const; + bool equals(const Node* p1, const Node* p2); + bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2); + bool onSegment(const Node* p, const Node* q, const Node* r); + int sign(double val); + bool intersectsPolygon(const Node* a, const Node* b); + bool locallyInside(const Node* a, const Node* b); + bool middleInside(const Node* a, const Node* b); + Node* splitPolygon(Node* a, Node* b); + template Node* insertNode(std::size_t i, const Point& p, Node* last); + void removeNode(Node* p); + + bool hashing; + double minX, maxX; + double minY, maxY; + double inv_size = 0; + + template > + class ObjectPool { + public: + ObjectPool() { } + ObjectPool(std::size_t blockSize_) { + reset(blockSize_); + } + ~ObjectPool() { + clear(); + } + template + T* construct(Args&&... args) { + if (currentIndex >= blockSize) { + currentBlock = alloc_traits::allocate(alloc, blockSize); + allocations.emplace_back(currentBlock); + currentIndex = 0; + } + T* object = ¤tBlock[currentIndex++]; + alloc_traits::construct(alloc, object, std::forward(args)...); + return object; + } + void reset(std::size_t newBlockSize) { + for (auto allocation : allocations) { + alloc_traits::deallocate(alloc, allocation, blockSize); + } + allocations.clear(); + blockSize = std::max(1, newBlockSize); + currentBlock = nullptr; + currentIndex = blockSize; + } + void clear() { reset(blockSize); } + private: + T* currentBlock = nullptr; + std::size_t currentIndex = 1; + std::size_t blockSize = 1; + std::vector allocations; + Alloc alloc; + typedef typename std::allocator_traits alloc_traits; + }; + ObjectPool nodes; +}; + +template template +void Earcut::operator()(const Polygon& points) { + // reset + indices.clear(); + vertices = 0; + + if (points.empty()) return; + + double x; + double y; + int threshold = 80; + std::size_t len = 0; + + for (size_t i = 0; threshold >= 0 && i < points.size(); i++) { + threshold -= static_cast(points[i].size()); + len += points[i].size(); + } + + //estimate size of nodes and indices + nodes.reset(len * 3 / 2); + indices.reserve(len + points[0].size()); + + Node* outerNode = linkedList(points[0], true); + if (!outerNode || outerNode->prev == outerNode->next) return; + + if (points.size() > 1) outerNode = eliminateHoles(points, outerNode); + + // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + hashing = threshold < 0; + if (hashing) { + Node* p = outerNode->next; + minX = maxX = outerNode->x; + minY = maxY = outerNode->y; + do { + x = p->x; + y = p->y; + minX = std::min(minX, x); + minY = std::min(minY, y); + maxX = std::max(maxX, x); + maxY = std::max(maxY, y); + p = p->next; + } while (p != outerNode); + + // minX, minY and inv_size are later used to transform coords into integers for z-order calculation + inv_size = std::max(maxX - minX, maxY - minY); + inv_size = inv_size != .0 ? (32767. / inv_size) : .0; + } + + earcutLinked(outerNode); + + nodes.clear(); +} + +// create a circular doubly linked list from polygon points in the specified winding order +template template +typename Earcut::Node* +Earcut::linkedList(const Ring& points, const bool clockwise) { + using Point = typename Ring::value_type; + double sum = 0; + const std::size_t len = points.size(); + std::size_t i, j; + Node* last = nullptr; + + // calculate original winding order of a polygon ring + for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) { + const auto& p1 = points[i]; + const auto& p2 = points[j]; + const double p20 = util::nth<0, Point>::get(p2); + const double p10 = util::nth<0, Point>::get(p1); + const double p11 = util::nth<1, Point>::get(p1); + const double p21 = util::nth<1, Point>::get(p2); + sum += (p20 - p10) * (p11 + p21); + } + + // link points into circular doubly-linked list in the specified winding order + if (clockwise == (sum > 0)) { + for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last); + } else { + for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last); + } + + if (last && equals(last, last->next)) { + removeNode(last); + last = last->next; + } + + vertices += len; + + return last; +} + +// eliminate colinear or duplicate points +template +typename Earcut::Node* +Earcut::filterPoints(Node* start, Node* end) { + if (!end) end = start; + + Node* p = start; + bool again; + do { + again = false; + + if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) { + removeNode(p); + p = end = p->prev; + + if (p == p->next) break; + again = true; + + } else { + p = p->next; + } + } while (again || p != end); + + return end; +} + +// main ear slicing loop which triangulates a polygon (given as a linked list) +template +void Earcut::earcutLinked(Node* ear, int pass) { + if (!ear) return; + + // interlink polygon nodes in z-order + if (!pass && hashing) indexCurve(ear); + + Node* stop = ear; + Node* prev; + Node* next; + + // iterate through ears, slicing them one by one + while (ear->prev != ear->next) { + prev = ear->prev; + next = ear->next; + + if (hashing ? isEarHashed(ear) : isEar(ear)) { + // cut off the triangle + indices.emplace_back(prev->i); + indices.emplace_back(ear->i); + indices.emplace_back(next->i); + + removeNode(ear); + + // skipping the next vertice leads to less sliver triangles + ear = next->next; + stop = next->next; + + continue; + } + + ear = next; + + // if we looped through the whole remaining polygon and can't find any more ears + if (ear == stop) { + // try filtering points and slicing again + if (!pass) earcutLinked(filterPoints(ear), 1); + + // if this didn't work, try curing all small self-intersections locally + else if (pass == 1) { + ear = cureLocalIntersections(filterPoints(ear)); + earcutLinked(ear, 2); + + // as a last resort, try splitting the remaining polygon into two + } else if (pass == 2) splitEarcut(ear); + + break; + } + } +} + +// check whether a polygon node forms a valid ear with adjacent nodes +template +bool Earcut::isEar(Node* ear) { + const Node* a = ear->prev; + const Node* b = ear; + const Node* c = ear->next; + + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear + + // now make sure we don't have other points inside the potential ear + Node* p = ear->next->next; + + while (p != ear->prev) { + if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) return false; + p = p->next; + } + + return true; +} + +template +bool Earcut::isEarHashed(Node* ear) { + const Node* a = ear->prev; + const Node* b = ear; + const Node* c = ear->next; + + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear + + // triangle bbox; min & max are calculated like this for speed + const double minTX = std::min(a->x, std::min(b->x, c->x)); + const double minTY = std::min(a->y, std::min(b->y, c->y)); + const double maxTX = std::max(a->x, std::max(b->x, c->x)); + const double maxTY = std::max(a->y, std::max(b->y, c->y)); + + // z-order range for the current triangle bbox; + const int32_t minZ = zOrder(minTX, minTY); + const int32_t maxZ = zOrder(maxTX, maxTY); + + // first look for points inside the triangle in increasing z-order + Node* p = ear->nextZ; + + while (p && p->z <= maxZ) { + if (p != ear->prev && p != ear->next && + pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) return false; + p = p->nextZ; + } + + // then look for points in decreasing z-order + p = ear->prevZ; + + while (p && p->z >= minZ) { + if (p != ear->prev && p != ear->next && + pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && + area(p->prev, p, p->next) >= 0) return false; + p = p->prevZ; + } + + return true; +} + +// go through all polygon nodes and cure small local self-intersections +template +typename Earcut::Node* +Earcut::cureLocalIntersections(Node* start) { + Node* p = start; + do { + Node* a = p->prev; + Node* b = p->next->next; + + // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2]) + if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) { + indices.emplace_back(a->i); + indices.emplace_back(p->i); + indices.emplace_back(b->i); + + // remove two nodes involved + removeNode(p); + removeNode(p->next); + + p = start = b; + } + p = p->next; + } while (p != start); + + return filterPoints(p); +} + +// try splitting polygon into two and triangulate them independently +template +void Earcut::splitEarcut(Node* start) { + // look for a valid diagonal that divides the polygon into two + Node* a = start; + do { + Node* b = a->next->next; + while (b != a->prev) { + if (a->i != b->i && isValidDiagonal(a, b)) { + // split the polygon in two by the diagonal + Node* c = splitPolygon(a, b); + + // filter colinear points around the cuts + a = filterPoints(a, a->next); + c = filterPoints(c, c->next); + + // run earcut on each half + earcutLinked(a); + earcutLinked(c); + return; + } + b = b->next; + } + a = a->next; + } while (a != start); +} + +// link every hole into the outer loop, producing a single-ring polygon without holes +template template +typename Earcut::Node* +Earcut::eliminateHoles(const Polygon& points, Node* outerNode) { + const size_t len = points.size(); + + std::vector queue; + for (size_t i = 1; i < len; i++) { + Node* list = linkedList(points[i], false); + if (list) { + if (list == list->next) list->steiner = true; + queue.push_back(getLeftmost(list)); + } + } + std::sort(queue.begin(), queue.end(), [](const Node* a, const Node* b) { + return a->x < b->x; + }); + + // process holes from left to right + for (size_t i = 0; i < queue.size(); i++) { + outerNode = eliminateHole(queue[i], outerNode); + } + + return outerNode; +} + +// find a bridge between vertices that connects hole with an outer ring and and link it +template +typename Earcut::Node* +Earcut::eliminateHole(Node* hole, Node* outerNode) { + Node* bridge = findHoleBridge(hole, outerNode); + if (!bridge) { + return outerNode; + } + + Node* bridgeReverse = splitPolygon(bridge, hole); + + // filter collinear points around the cuts + filterPoints(bridgeReverse, bridgeReverse->next); + + // Check if input node was removed by the filtering + return filterPoints(bridge, bridge->next); +} + +// David Eberly's algorithm for finding a bridge between hole and outer polygon +template +typename Earcut::Node* +Earcut::findHoleBridge(Node* hole, Node* outerNode) { + Node* p = outerNode; + double hx = hole->x; + double hy = hole->y; + double qx = -std::numeric_limits::infinity(); + Node* m = nullptr; + + // find a segment intersected by a ray from the hole's leftmost Vertex to the left; + // segment's endpoint with lesser x will be potential connection Vertex + do { + if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) { + double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y); + if (x <= hx && x > qx) { + qx = x; + m = p->x < p->next->x ? p : p->next; + if (x == hx) return m; // hole touches outer segment; pick leftmost endpoint + } + } + p = p->next; + } while (p != outerNode); + + if (!m) return 0; + + // look for points inside the triangle of hole Vertex, segment intersection and endpoint; + // if there are no points found, we have a valid connection; + // otherwise choose the Vertex of the minimum angle with the ray as connection Vertex + + const Node* stop = m; + double tanMin = std::numeric_limits::infinity(); + double tanCur = 0; + + p = m; + double mx = m->x; + double my = m->y; + + do { + if (hx >= p->x && p->x >= mx && hx != p->x && + pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) { + + tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential + + if (locallyInside(p, hole) && + (tanCur < tanMin || (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) { + m = p; + tanMin = tanCur; + } + } + + p = p->next; + } while (p != stop); + + return m; +} + +// whether sector in vertex m contains sector in vertex p in the same coordinates +template +bool Earcut::sectorContainsSector(const Node* m, const Node* p) { + return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0; +} + +// interlink polygon nodes in z-order +template +void Earcut::indexCurve(Node* start) { + assert(start); + Node* p = start; + + do { + p->z = p->z ? p->z : zOrder(p->x, p->y); + p->prevZ = p->prev; + p->nextZ = p->next; + p = p->next; + } while (p != start); + + p->prevZ->nextZ = nullptr; + p->prevZ = nullptr; + + sortLinked(p); +} + +// Simon Tatham's linked list merge sort algorithm +// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html +template +typename Earcut::Node* +Earcut::sortLinked(Node* list) { + assert(list); + Node* p; + Node* q; + Node* e; + Node* tail; + int i, numMerges, pSize, qSize; + int inSize = 1; + + for (;;) { + p = list; + list = nullptr; + tail = nullptr; + numMerges = 0; + + while (p) { + numMerges++; + q = p; + pSize = 0; + for (i = 0; i < inSize; i++) { + pSize++; + q = q->nextZ; + if (!q) break; + } + + qSize = inSize; + + while (pSize > 0 || (qSize > 0 && q)) { + + if (pSize == 0) { + e = q; + q = q->nextZ; + qSize--; + } else if (qSize == 0 || !q) { + e = p; + p = p->nextZ; + pSize--; + } else if (p->z <= q->z) { + e = p; + p = p->nextZ; + pSize--; + } else { + e = q; + q = q->nextZ; + qSize--; + } + + if (tail) tail->nextZ = e; + else list = e; + + e->prevZ = tail; + tail = e; + } + + p = q; + } + + tail->nextZ = nullptr; + + if (numMerges <= 1) return list; + + inSize *= 2; + } +} + +// z-order of a Vertex given coords and size of the data bounding box +template +int32_t Earcut::zOrder(const double x_, const double y_) { + // coords are transformed into non-negative 15-bit integer range + int32_t x = static_cast((x_ - minX) * inv_size); + int32_t y = static_cast((y_ - minY) * inv_size); + + x = (x | (x << 8)) & 0x00FF00FF; + x = (x | (x << 4)) & 0x0F0F0F0F; + x = (x | (x << 2)) & 0x33333333; + x = (x | (x << 1)) & 0x55555555; + + y = (y | (y << 8)) & 0x00FF00FF; + y = (y | (y << 4)) & 0x0F0F0F0F; + y = (y | (y << 2)) & 0x33333333; + y = (y | (y << 1)) & 0x55555555; + + return x | (y << 1); +} + +// find the leftmost node of a polygon ring +template +typename Earcut::Node* +Earcut::getLeftmost(Node* start) { + Node* p = start; + Node* leftmost = start; + do { + if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) + leftmost = p; + p = p->next; + } while (p != start); + + return leftmost; +} + +// check if a point lies within a convex triangle +template +bool Earcut::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const { + return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && + (ax - px) * (by - py) >= (bx - px) * (ay - py) && + (bx - px) * (cy - py) >= (cx - px) * (by - py); +} + +// check if a diagonal between two polygon nodes is valid (lies in polygon interior) +template +bool Earcut::isValidDiagonal(Node* a, Node* b) { + return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges + ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible + (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors + (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case +} + +// signed area of a triangle +template +double Earcut::area(const Node* p, const Node* q, const Node* r) const { + return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y); +} + +// check if two points are equal +template +bool Earcut::equals(const Node* p1, const Node* p2) { + return p1->x == p2->x && p1->y == p2->y; +} + +// check if two segments intersect +template +bool Earcut::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) { + int o1 = sign(area(p1, q1, p2)); + int o2 = sign(area(p1, q1, q2)); + int o3 = sign(area(p2, q2, p1)); + int o4 = sign(area(p2, q2, q1)); + + if (o1 != o2 && o3 != o4) return true; // general case + + if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 + if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 + if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 + if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 + + return false; +} + +// for collinear points p, q, r, check if point q lies on segment pr +template +bool Earcut::onSegment(const Node* p, const Node* q, const Node* r) { + return q->x <= std::max(p->x, r->x) && + q->x >= std::min(p->x, r->x) && + q->y <= std::max(p->y, r->y) && + q->y >= std::min(p->y, r->y); +} + +template +int Earcut::sign(double val) { + return (0.0 < val) - (val < 0.0); +} + +// check if a polygon diagonal intersects any polygon segments +template +bool Earcut::intersectsPolygon(const Node* a, const Node* b) { + const Node* p = a; + do { + if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i && + intersects(p, p->next, a, b)) return true; + p = p->next; + } while (p != a); + + return false; +} + +// check if a polygon diagonal is locally inside the polygon +template +bool Earcut::locallyInside(const Node* a, const Node* b) { + return area(a->prev, a, a->next) < 0 ? + area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 : + area(a, b, a->prev) < 0 || area(a, a->next, b) < 0; +} + +// check if the middle Vertex of a polygon diagonal is inside the polygon +template +bool Earcut::middleInside(const Node* a, const Node* b) { + const Node* p = a; + bool inside = false; + double px = (a->x + b->x) / 2; + double py = (a->y + b->y) / 2; + do { + if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y && + (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x)) + inside = !inside; + p = p->next; + } while (p != a); + + return inside; +} + +// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits +// polygon into two; if one belongs to the outer ring and another to a hole, it merges it into a +// single ring +template +typename Earcut::Node* +Earcut::splitPolygon(Node* a, Node* b) { + Node* a2 = nodes.construct(a->i, a->x, a->y); + Node* b2 = nodes.construct(b->i, b->x, b->y); + Node* an = a->next; + Node* bp = b->prev; + + a->next = b; + b->prev = a; + + a2->next = an; + an->prev = a2; + + b2->next = a2; + a2->prev = b2; + + bp->next = b2; + b2->prev = bp; + + return b2; +} + +// create a node and util::optionally link it with previous one (in a circular doubly linked list) +template template +typename Earcut::Node* +Earcut::insertNode(std::size_t i, const Point& pt, Node* last) { + Node* p = nodes.construct(static_cast(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt)); + + if (!last) { + p->prev = p; + p->next = p; + + } else { + assert(last); + p->next = last->next; + p->prev = last; + last->next->prev = p; + last->next = p; + } + return p; +} + +template +void Earcut::removeNode(Node* p) { + p->next->prev = p->prev; + p->prev->next = p->next; + + if (p->prevZ) p->prevZ->nextZ = p->nextZ; + if (p->nextZ) p->nextZ->prevZ = p->prevZ; +} +} + +template +std::vector earcut(const Polygon& poly) { + mapbox::detail::Earcut earcut; + earcut(poly); + return std::move(earcut.indices); +} +} diff --git a/Dependencies/assimp/contrib/pugixml/CMakeLists.txt b/Dependencies/assimp/contrib/pugixml/CMakeLists.txt index af6b577e6..81ff5615b 100644 --- a/Dependencies/assimp/contrib/pugixml/CMakeLists.txt +++ b/Dependencies/assimp/contrib/pugixml/CMakeLists.txt @@ -1,87 +1,297 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.10...3.30) -project(pugixml) +# Policy configuration; this *MUST* be specified before project is defined +if(POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) # Enables use of MSVC_RUNTIME_LIBRARY +endif() + +project(pugixml VERSION 1.15 LANGUAGES CXX) + +include(CMakePackageConfigHelpers) +include(CMakeDependentOption) +include(GNUInstallDirs) + +cmake_dependent_option(PUGIXML_USE_VERSIONED_LIBDIR + "Use a private subdirectory to install the headers and libraries" OFF + "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) + +cmake_dependent_option(PUGIXML_USE_POSTFIX + "Use separate postfix for each configuration to make sure you can install multiple build outputs" OFF + "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) -option(BUILD_SHARED_LIBS "Build shared instead of static library" OFF) -option(BUILD_TESTS "Build tests" OFF) -option(BUILD_PKGCONFIG "Build in PKGCONFIG mode" OFF) +cmake_dependent_option(PUGIXML_STATIC_CRT + "Use static MSVC RT libraries" OFF + "MSVC" OFF) -set(BUILD_DEFINES "" CACHE STRING "Build defines") +cmake_dependent_option(PUGIXML_BUILD_TESTS + "Build pugixml tests" OFF + "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) -if(MSVC) - option(STATIC_CRT "Use static CRT libraries" OFF) +# Custom build defines +set(PUGIXML_BUILD_DEFINES CACHE STRING "Build defines for custom options") +separate_arguments(PUGIXML_BUILD_DEFINES) - # Rewrite command line flags to use /MT if necessary - if(STATIC_CRT) - foreach(flag_var - CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE - CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) - if(${flag_var} MATCHES "/MD") - string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - endif(${flag_var} MATCHES "/MD") - endforeach(flag_var) - endif() +# Technically not needed for this file. This is builtin CMAKE global variable. +option(BUILD_SHARED_LIBS "Build shared instead of static library") + +# Expose option to build PUGIXML as static as well when the global BUILD_SHARED_LIBS variable is set +cmake_dependent_option(PUGIXML_BUILD_SHARED_AND_STATIC_LIBS + "Build both shared and static libraries" OFF + "BUILD_SHARED_LIBS" OFF) + +# Expose options from the pugiconfig.hpp +option(PUGIXML_WCHAR_MODE "Enable wchar_t mode" OFF) +option(PUGIXML_COMPACT "Enable compact mode" OFF) +option(PUGIXML_INSTALL "Enable installation rules" ON) + +# Advanced options from pugiconfig.hpp +option(PUGIXML_NO_XPATH "Disable XPath" OFF) +option(PUGIXML_NO_STL "Disable STL" OFF) +option(PUGIXML_NO_EXCEPTIONS "Disable Exceptions" OFF) +mark_as_advanced(PUGIXML_NO_XPATH PUGIXML_NO_STL PUGIXML_NO_EXCEPTIONS) + +if (APPLE) + option(PUGIXML_BUILD_APPLE_FRAMEWORK "Build as Apple Frameworks" OFF) endif() -# Pre-defines standard install locations on *nix systems. -include(GNUInstallDirs) -mark_as_advanced(CLEAR CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_INCLUDEDIR) +set(PUGIXML_PUBLIC_DEFINITIONS + $<$:PUGIXML_WCHAR_MODE> + $<$:PUGIXML_COMPACT> + $<$:PUGIXML_NO_XPATH> + $<$:PUGIXML_NO_STL> + $<$:PUGIXML_NO_EXCEPTIONS> +) -set(HEADERS src/pugixml.hpp src/pugiconfig.hpp) -set(SOURCES src/pugixml.cpp) +# This is used to backport a CMake 3.15 feature, but is also forwards compatible +if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) + set(CMAKE_MSVC_RUNTIME_LIBRARY + MultiThreaded$<$:Debug>$<$>:DLL>) +endif() + +# Set the default C++ standard to C++17 if not set; CMake will automatically downgrade this if the compiler does not support it +# When CMAKE_CXX_STANDARD_REQUIRED is set, we fall back to C++11 to avoid breaking older compilers +if (NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED AND NOT DEFINED CMAKE_CXX_STANDARD AND NOT CMAKE_VERSION VERSION_LESS 3.8) -if(DEFINED BUILD_DEFINES) - foreach(DEFINE ${BUILD_DEFINES}) - add_definitions("-D" ${DEFINE}) - endforeach() + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED OFF) +elseif (NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) endif() -#message(pugixml" "${BUILD_SHARED_LIBS}) -#if(BUILD_SHARED_LIBS) -# add_library(pugixml SHARED ${HEADERS} ${SOURCES}) -#else() - add_library(pugixml STATIC ${HEADERS} ${SOURCES}) -#endif() - -# Export symbols for shared library builds -if(BUILD_SHARED_LIBS AND MSVC) - target_compile_definitions(pugixml PRIVATE "PUGIXML_API=__declspec(dllexport)") + +if (PUGIXML_USE_POSTFIX) + set(CMAKE_RELWITHDEBINFO_POSTFIX _r) + set(CMAKE_MINSIZEREL_POSTFIX _m) + set(CMAKE_DEBUG_POSTFIX _d) endif() -# Enable C++11 long long for compilers that are capable of it -if(NOT ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} STRLESS 3.1 AND ";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_long_long_type;") - target_compile_features(pugixml PUBLIC cxx_long_long_type) +if (CMAKE_VERSION VERSION_LESS 3.15) + set(msvc-rt $) + + set(msvc-rt-mtd-shared $) + set(msvc-rt-mtd-static $) + set(msvc-rt-mt-shared $) + set(msvc-rt-mt-static $) + unset(msvc-rt) + + set(msvc-rt-mtd-shared $<${msvc-rt-mtd-shared}:-MDd>) + set(msvc-rt-mtd-static $<${msvc-rt-mtd-static}:-MTd>) + set(msvc-rt-mt-shared $<${msvc-rt-mt-shared}:-MD>) + set(msvc-rt-mt-static $<${msvc-rt-mt-static}:-MT>) endif() -set_target_properties(pugixml PROPERTIES VERSION 1.9 SOVERSION 1) -get_target_property(PUGIXML_VERSION_STRING pugixml VERSION) +set(versioned-dir $<$:/pugixml-${PROJECT_VERSION}>) -if(BUILD_PKGCONFIG) - # Install library into its own directory under LIBDIR - set(INSTALL_SUFFIX /pugixml-${PUGIXML_VERSION_STRING}) +set(libs) + +if (BUILD_SHARED_LIBS) + add_library(pugixml-shared SHARED + ${PROJECT_SOURCE_DIR}/scripts/pugixml_dll.rc + ${PROJECT_SOURCE_DIR}/src/pugixml.cpp) + add_library(pugixml::shared ALIAS pugixml-shared) + list(APPEND libs pugixml-shared) + string(CONCAT pugixml.msvc $, + $ + >) + + set_property(TARGET pugixml-shared PROPERTY EXPORT_NAME shared) + target_include_directories(pugixml-shared + PUBLIC + $) + target_compile_definitions(pugixml-shared + PUBLIC + ${PUGIXML_BUILD_DEFINES} + ${PUGIXML_PUBLIC_DEFINITIONS} + PRIVATE + PUGIXML_API=$ + ) + target_compile_options(pugixml-shared + PRIVATE + ${msvc-rt-mtd-shared} + ${msvc-rt-mtd-static} + ${msvc-rt-mt-shared} + ${msvc-rt-mt-static}) endif() -target_include_directories(pugixml PUBLIC - $ - $) +if (NOT BUILD_SHARED_LIBS OR PUGIXML_BUILD_SHARED_AND_STATIC_LIBS) + add_library(pugixml-static STATIC + ${PROJECT_SOURCE_DIR}/src/pugixml.cpp) + add_library(pugixml::static ALIAS pugixml-static) + list(APPEND libs pugixml-static) -install(TARGETS pugixml EXPORT pugixml-config - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}${INSTALL_SUFFIX} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}${INSTALL_SUFFIX} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) -install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}${INSTALL_SUFFIX}) -install(EXPORT pugixml-config DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml) + set_property(TARGET pugixml-static PROPERTY EXPORT_NAME static) + target_include_directories(pugixml-static + PUBLIC + $) + target_compile_definitions(pugixml-static + PUBLIC + ${PUGIXML_BUILD_DEFINES} + ${PUGIXML_PUBLIC_DEFINITIONS}) + target_compile_options(pugixml-static + PRIVATE + ${msvc-rt-mtd-shared} + ${msvc-rt-mtd-static} + ${msvc-rt-mt-shared} + ${msvc-rt-mt-static}) +endif() -if(BUILD_PKGCONFIG) - configure_file(scripts/pugixml.pc.in ${PROJECT_BINARY_DIR}/pugixml.pc @ONLY) - install(FILES ${PROJECT_BINARY_DIR}/pugixml.pc DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig) +if (BUILD_SHARED_LIBS) + set(pugixml-alias pugixml-shared) +else() + set(pugixml-alias pugixml-static) endif() +add_library(pugixml INTERFACE) +target_link_libraries(pugixml INTERFACE ${pugixml-alias}) +add_library(pugixml::pugixml ALIAS pugixml) + +set_target_properties(${libs} + PROPERTIES + MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY} + EXCLUDE_FROM_ALL ON + POSITION_INDEPENDENT_CODE ON + SOVERSION ${PROJECT_VERSION_MAJOR} + VERSION ${PROJECT_VERSION} + OUTPUT_NAME pugixml) + +set_target_properties(${libs} + PROPERTIES + EXCLUDE_FROM_ALL OFF) +set(install-targets pugixml ${libs}) + +if (PUGIXML_BUILD_APPLE_FRAMEWORK) + set_target_properties(${libs} PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PROJECT_VERSION} + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER com.zeux.pugixml + MACOSX_FRAMEWORK_IDENTIFIER com.zeux.pugixml + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}) +endif() + +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/scripts/pugixml-config.cmake.in" + "${PROJECT_BINARY_DIR}/pugixml-config.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR} + NO_CHECK_REQUIRED_COMPONENTS_MACRO + NO_SET_AND_CHECK_MACRO) + +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/pugixml-config-version.cmake" + COMPATIBILITY SameMajorVersion) + +if (PUGIXML_USE_POSTFIX) + if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) + set(LIB_POSTFIX ${CMAKE_RELWITHDEBINFO_POSTFIX}) + elseif(CMAKE_BUILD_TYPE MATCHES MinSizeRel) + set(LIB_POSTFIX ${CMAKE_MINSIZEREL_POSTFIX}) + elseif(CMAKE_BUILD_TYPE MATCHES Debug) + set(LIB_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + endif() +endif() + +# Handle both relative and absolute paths (e.g. NixOS) for a relocatable package +if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") + set(PUGIXML_PC_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") +else() + set(PUGIXML_PC_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") +endif() +if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") + set(PUGIXML_PC_LIBDIR "${CMAKE_INSTALL_LIBDIR}") +else() + set(PUGIXML_PC_LIBDIR "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") +endif() +configure_file(scripts/pugixml.pc.in pugixml.pc @ONLY) + +export(TARGETS ${install-targets} + NAMESPACE pugixml:: + FILE pugixml-targets.cmake) + +if(PUGIXML_INSTALL) + if (NOT DEFINED PUGIXML_RUNTIME_COMPONENT) + set(PUGIXML_RUNTIME_COMPONENT Runtime) + endif() + + if (NOT DEFINED PUGIXML_LIBRARY_COMPONENT) + set(PUGIXML_LIBRARY_COMPONENT Library) + endif() + + if (NOT DEFINED PUGIXML_DEVELOPMENT_COMPONENT) + set(PUGIXML_DEVELOPMENT_COMPONENT Development) + endif() + + set(namelink-component) + if (NOT CMAKE_VERSION VERSION_LESS 3.12) + set(namelink-component NAMELINK_COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) + endif() + install(TARGETS ${install-targets} + EXPORT pugixml-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${PUGIXML_RUNTIME_COMPONENT} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${PUGIXML_LIBRARY_COMPONENT} ${namelink-component} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir} + FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT runtime OPTIONAL) + + install(EXPORT pugixml-targets + NAMESPACE pugixml:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) + + install(FILES + "${PROJECT_BINARY_DIR}/pugixml-config-version.cmake" + "${PROJECT_BINARY_DIR}/pugixml-config.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) + + install(FILES ${PROJECT_BINARY_DIR}/pugixml.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) + + install( + FILES + "${PROJECT_SOURCE_DIR}/src/pugiconfig.hpp" + "${PROJECT_SOURCE_DIR}/src/pugixml.hpp" + DESTINATION + ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir} COMPONENT ${PUGIXML_DEVELOPMENT_COMPONENT}) +endif() + +if (PUGIXML_BUILD_TESTS) + include(CTest) + set(fuzz-pattern "tests/fuzz_*.cpp") + set(test-pattern "tests/*.cpp") + if (CMAKE_VERSION VERSION_GREATER 3.11) + list(INSERT fuzz-pattern 0 CONFIGURE_DEPENDS) + list(INSERT test-pattern 0 CONFIGURE_DEPENDS) + endif() + file(GLOB test-sources ${test-pattern}) + file(GLOB fuzz-sources ${fuzz-pattern}) + list(REMOVE_ITEM test-sources ${fuzz-sources}) -if(BUILD_TESTS) - file(GLOB TEST_SOURCES tests/*.cpp) - file(GLOB FUZZ_SOURCES tests/fuzz_*.cpp) - list(REMOVE_ITEM TEST_SOURCES ${FUZZ_SOURCES}) + add_custom_target(check + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure) - add_executable(check ${TEST_SOURCES}) - target_link_libraries(check pugixml) - add_custom_command(TARGET check POST_BUILD COMMAND check WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + add_executable(pugixml-check ${test-sources}) + add_test(NAME pugixml::test + COMMAND pugixml-check + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + add_dependencies(check pugixml-check) + target_link_libraries(pugixml-check + PRIVATE + pugixml::pugixml) endif() diff --git a/Dependencies/assimp/contrib/pugixml/readme.txt b/Dependencies/assimp/contrib/pugixml/readme.txt index 2c1865437..0f1b72f30 100644 --- a/Dependencies/assimp/contrib/pugixml/readme.txt +++ b/Dependencies/assimp/contrib/pugixml/readme.txt @@ -1,6 +1,6 @@ -pugixml 1.13 - an XML processing library +pugixml 1.15 - an XML processing library -Copyright (c) 2006-2024, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +Copyright (C) 2006-2026, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) Report bugs and download new versions at https://pugixml.org/ This is the distribution of pugixml, which is a C++ XML processing library, @@ -26,7 +26,7 @@ The distribution contains the following folders: This library is distributed under the MIT License: -Copyright (c) 2006-2024 Arseny Kapoulkine +Copyright (c) 2006-2026 Arseny Kapoulkine Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/Dependencies/assimp/contrib/pugixml/src/pugiconfig.hpp b/Dependencies/assimp/contrib/pugixml/src/pugiconfig.hpp index 1a3956903..ce10cfe16 100644 --- a/Dependencies/assimp/contrib/pugixml/src/pugiconfig.hpp +++ b/Dependencies/assimp/contrib/pugixml/src/pugiconfig.hpp @@ -1,7 +1,7 @@ /** - * pugixml parser - version 1.13 + * pugixml parser - version 1.15 * -------------------------------------------------------- - * Copyright (c) 2006-2024, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (C) 2006-2026, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -30,9 +30,14 @@ // #define PUGIXML_NO_EXCEPTIONS // Set this to control attributes for public classes/functions, i.e.: -// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL -// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL -// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall +#ifdef _WIN32 +# define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL +#else +# define PUGIXML_API __attribute__((visibility("default"))) +#endif // _WIN32 +# +//define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL +//#define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead // Tune these constants to adjust memory-related behavior @@ -44,15 +49,18 @@ // #define PUGIXML_XPATH_DEPTH_LIMIT 1024 // Uncomment this to switch to header-only version -#define PUGIXML_HEADER_ONLY +// #define PUGIXML_HEADER_ONLY -// Uncomment this to enable long long support +// Uncomment this to enable long long support (usually enabled automatically) // #define PUGIXML_HAS_LONG_LONG +// Uncomment this to enable support for std::string_view (usually enabled automatically) +// #define PUGIXML_HAS_STRING_VIEW + #endif /** - * Copyright (c) 2006-2024 Arseny Kapoulkine + * Copyright (c) 2006-2026 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/Dependencies/assimp/contrib/pugixml/src/pugixml.cpp b/Dependencies/assimp/contrib/pugixml/src/pugixml.cpp index 6d6bd0edb..c9fdffb4a 100644 --- a/Dependencies/assimp/contrib/pugixml/src/pugixml.cpp +++ b/Dependencies/assimp/contrib/pugixml/src/pugixml.cpp @@ -1,7 +1,7 @@ /** - * pugixml parser - version 1.13 + * pugixml parser - version 1.15 * -------------------------------------------------------- - * Copyright (c) 2006-2024, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (C) 2006-2026, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -40,6 +40,11 @@ // For placement new #include +// For load_file +#if defined(__linux__) || defined(__APPLE__) +#include +#endif + #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant @@ -48,6 +53,11 @@ # pragma warning(disable: 4996) // this function or variable may be unsafe #endif +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // NULL as null pointer constant +#endif + #if defined(_MSC_VER) && defined(__c2__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated" // this function or variable may be unsafe @@ -82,39 +92,39 @@ // Inlining controls #if defined(_MSC_VER) && _MSC_VER >= 1300 -# define PUGI__NO_INLINE __declspec(noinline) +# define PUGI_IMPL_NO_INLINE __declspec(noinline) #elif defined(__GNUC__) -# define PUGI__NO_INLINE __attribute__((noinline)) +# define PUGI_IMPL_NO_INLINE __attribute__((noinline)) #else -# define PUGI__NO_INLINE +# define PUGI_IMPL_NO_INLINE #endif // Branch weight controls #if defined(__GNUC__) && !defined(__c2__) -# define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0) +# define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0) #else -# define PUGI__UNLIKELY(cond) (cond) +# define PUGI_IMPL_UNLIKELY(cond) (cond) #endif // Simple static assertion -#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } +#define PUGI_IMPL_STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } // Digital Mars C++ bug workaround for passing char loaded from memory via stack #ifdef __DMC__ -# define PUGI__DMC_VOLATILE volatile +# define PUGI_IMPL_DMC_VOLATILE volatile #else -# define PUGI__DMC_VOLATILE +# define PUGI_IMPL_DMC_VOLATILE #endif // Integer sanitizer workaround; we only apply this for clang since gcc8 has no_sanitize but not unsigned-integer-overflow and produces "attribute directive ignored" warnings #if defined(__clang__) && defined(__has_attribute) # if __has_attribute(no_sanitize) -# define PUGI__UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow"))) +# define PUGI_IMPL_UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow"))) # else -# define PUGI__UNSIGNED_OVERFLOW +# define PUGI_IMPL_UNSIGNED_OVERFLOW # endif #else -# define PUGI__UNSIGNED_OVERFLOW +# define PUGI_IMPL_UNSIGNED_OVERFLOW #endif // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) @@ -124,6 +134,12 @@ using std::memmove; using std::memset; #endif +// Old versions of GCC do not define ::malloc and ::free depending on header include order +#if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)) +using std::malloc; +using std::free; +#endif + // Some MinGW/GCC versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions from limits.h in some configurations #if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX) # define LLONG_MIN (-LLONG_MAX - 1LL) @@ -133,36 +149,38 @@ using std::memset; // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features #if defined(_MSC_VER) && !defined(__S3E__) && !defined(_WIN32_WCE) -# define PUGI__MSVC_CRT_VERSION _MSC_VER +# define PUGI_IMPL_MSVC_CRT_VERSION _MSC_VER #elif defined(_WIN32_WCE) -# define PUGI__MSVC_CRT_VERSION 1310 // MSVC7.1 +# define PUGI_IMPL_MSVC_CRT_VERSION 1310 // MSVC7.1 #endif // Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size. #if __cplusplus >= 201103 -# define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) -#elif defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 -# define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__) +# define PUGI_IMPL_SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) +#elif defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 +# define PUGI_IMPL_SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__) +#elif defined(__APPLE__) && __clang_major__ >= 14 // Xcode 14 marks sprintf as deprecated while still using C++98 by default +# define PUGI_IMPL_SNPRINTF(buf, fmt, arg1, arg2) snprintf(buf, sizeof(buf), fmt, arg1, arg2) #else -# define PUGI__SNPRINTF sprintf +# define PUGI_IMPL_SNPRINTF sprintf #endif // We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat. #ifdef PUGIXML_HEADER_ONLY -# define PUGI__NS_BEGIN namespace pugi { namespace impl { -# define PUGI__NS_END } } -# define PUGI__FN inline -# define PUGI__FN_NO_INLINE inline +# define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl { +# define PUGI_IMPL_NS_END } } +# define PUGI_IMPL_FN inline +# define PUGI_IMPL_FN_NO_INLINE inline #else # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces -# define PUGI__NS_BEGIN namespace pugi { namespace impl { -# define PUGI__NS_END } } +# define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl { +# define PUGI_IMPL_NS_END } } # else -# define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace { -# define PUGI__NS_END } } } +# define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl { namespace { +# define PUGI_IMPL_NS_END } } } # endif -# define PUGI__FN -# define PUGI__FN_NO_INLINE PUGI__NO_INLINE +# define PUGI_IMPL_FN +# define PUGI_IMPL_FN_NO_INLINE PUGI_IMPL_NO_INLINE #endif // uintptr_t @@ -182,13 +200,13 @@ namespace pugi #endif // Memory allocation -PUGI__NS_BEGIN - PUGI__FN void* default_allocate(size_t size) +PUGI_IMPL_NS_BEGIN + PUGI_IMPL_FN void* default_allocate(size_t size) { return malloc(size); } - PUGI__FN void default_deallocate(void* ptr) + PUGI_IMPL_FN void default_deallocate(void* ptr) { free(ptr); } @@ -206,12 +224,12 @@ PUGI__NS_BEGIN template deallocation_function xml_memory_management_function_storage::deallocate = default_deallocate; typedef xml_memory_management_function_storage xml_memory; -PUGI__NS_END +PUGI_IMPL_NS_END // String utilities -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN // Get string length - PUGI__FN size_t strlength(const char_t* s) + PUGI_IMPL_FN size_t strlength(const char_t* s) { assert(s); @@ -223,7 +241,7 @@ PUGI__NS_BEGIN } // Compare two strings - PUGI__FN bool strequal(const char_t* src, const char_t* dst) + PUGI_IMPL_FN bool strequal(const char_t* src, const char_t* dst) { assert(src && dst); @@ -234,8 +252,26 @@ PUGI__NS_BEGIN #endif } +#ifdef PUGIXML_HAS_STRING_VIEW + // Check if the null-terminated dst string is equal to the entire contents of srcview + PUGI_IMPL_FN bool stringview_equal(string_view_t srcview, const char_t* dst) + { + // std::basic_string_view::compare(const char*) has the right behavior, but it performs an + // extra traversal of dst to compute its length. + assert(dst); + const char_t* src = srcview.data(); + size_t srclen = srcview.size(); + + while (srclen && *dst && *src == *dst) + { + --srclen; ++dst; ++src; + } + return srclen == 0 && *dst == 0; + } +#endif + // Compare lhs with [rhs_begin, rhs_end) - PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) + PUGI_IMPL_FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) { for (size_t i = 0; i < count; ++i) if (lhs[i] != rhs[i]) @@ -245,7 +281,7 @@ PUGI__NS_BEGIN } // Get length of wide string, even if CRT lacks wide character support - PUGI__FN size_t strlength_wide(const wchar_t* s) + PUGI_IMPL_FN size_t strlength_wide(const wchar_t* s) { assert(s); @@ -257,10 +293,10 @@ PUGI__NS_BEGIN return static_cast(end - s); #endif } -PUGI__NS_END +PUGI_IMPL_NS_END // auto_ptr-like object for exception recovery -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN template struct auto_deleter { typedef void (*D)(T*); @@ -280,18 +316,18 @@ PUGI__NS_BEGIN T* release() { T* result = data; - data = 0; + data = nullptr; return result; } }; -PUGI__NS_END +PUGI_IMPL_NS_END #ifdef PUGIXML_COMPACT -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN class compact_hash_table { public: - compact_hash_table(): _items(0), _capacity(0), _count(0) + compact_hash_table(): _items(NULL), _capacity(0), _count(0) { } @@ -300,7 +336,7 @@ PUGI__NS_BEGIN if (_items) { xml_memory::deallocate(_items); - _items = 0; + _items = nullptr; _capacity = 0; _count = 0; } @@ -308,11 +344,11 @@ PUGI__NS_BEGIN void* find(const void* key) { - if (_capacity == 0) return 0; + if (_capacity == 0) return nullptr; item_t* item = get_item(key); assert(item); - assert(item->key == key || (item->key == 0 && item->value == 0)); + assert(item->key == key || (item->key == nullptr && item->value == nullptr)); return item->value; } @@ -324,7 +360,7 @@ PUGI__NS_BEGIN item_t* item = get_item(key); assert(item); - if (item->key == 0) + if (item->key == nullptr) { _count++; item->key = key; @@ -367,7 +403,7 @@ PUGI__NS_BEGIN { item_t& probe_item = _items[bucket]; - if (probe_item.key == key || probe_item.key == 0) + if (probe_item.key == key || probe_item.key == nullptr) return &probe_item; // hash collision, quadratic probing @@ -375,10 +411,10 @@ PUGI__NS_BEGIN } assert(false && "Hash table is full"); // unreachable - return 0; + return nullptr; } - static PUGI__UNSIGNED_OVERFLOW unsigned int hash(const void* key) + static PUGI_IMPL_UNSIGNED_OVERFLOW unsigned int hash(const void* key) { unsigned int h = static_cast(reinterpret_cast(key) & 0xffffffff); @@ -393,7 +429,7 @@ PUGI__NS_BEGIN } }; - PUGI__FN_NO_INLINE bool compact_hash_table::rehash(size_t count) + PUGI_IMPL_FN_NO_INLINE bool compact_hash_table::rehash(size_t count) { size_t capacity = 32; while (count >= capacity - capacity / 4) @@ -423,10 +459,10 @@ PUGI__NS_BEGIN return true; } -PUGI__NS_END +PUGI_IMPL_NS_END #endif -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN #ifdef PUGIXML_COMPACT static const uintptr_t xml_memory_block_alignment = 4; #else @@ -444,16 +480,16 @@ PUGI__NS_BEGIN static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; #ifdef PUGIXML_COMPACT - #define PUGI__GETHEADER_IMPL(object, page, flags) // unused - #define PUGI__GETPAGE_IMPL(header) (header).get_page() + #define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) // unused + #define PUGI_IMPL_GETPAGE_IMPL(header) (header).get_page() #else - #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast(object) - reinterpret_cast(page)) << 8) | (flags)) + #define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) (((reinterpret_cast(object) - reinterpret_cast(page)) << 8) | (flags)) // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings - #define PUGI__GETPAGE_IMPL(header) static_cast(const_cast(static_cast(reinterpret_cast(&header) - (header >> 8)))) + #define PUGI_IMPL_GETPAGE_IMPL(header) static_cast(const_cast(static_cast(reinterpret_cast(&header) - (header >> 8)))) #endif - #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header) - #define PUGI__NODETYPE(n) static_cast((n)->header & impl::xml_memory_page_type_mask) + #define PUGI_IMPL_GETPAGE(n) PUGI_IMPL_GETPAGE_IMPL((n)->header) + #define PUGI_IMPL_NODETYPE(n) static_cast((n)->header & impl::xml_memory_page_type_mask) struct xml_allocator; @@ -463,16 +499,16 @@ PUGI__NS_BEGIN { xml_memory_page* result = static_cast(memory); - result->allocator = 0; - result->prev = 0; - result->next = 0; + result->allocator = nullptr; + result->prev = nullptr; + result->next = nullptr; result->busy_size = 0; result->freed_size = 0; #ifdef PUGIXML_COMPACT - result->compact_string_base = 0; - result->compact_shared_parent = 0; - result->compact_page_marker = 0; + result->compact_string_base = nullptr; + result->compact_shared_parent = nullptr; + result->compact_page_marker = nullptr; #endif return result; @@ -512,7 +548,7 @@ PUGI__NS_BEGIN xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) { #ifdef PUGIXML_COMPACT - _hash = 0; + _hash = nullptr; #endif } @@ -522,7 +558,7 @@ PUGI__NS_BEGIN // allocate block with some alignment, leaving memory for worst-case padding void* memory = xml_memory::allocate(size); - if (!memory) return 0; + if (!memory) return nullptr; // prepare page structure xml_memory_page* page = xml_memory_page::construct(memory); @@ -543,7 +579,7 @@ PUGI__NS_BEGIN void* allocate_memory(size_t size, xml_memory_page*& out_page) { - if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size)) + if (PUGI_IMPL_UNLIKELY(_busy_size + size > xml_memory_page_size)) return allocate_memory_oob(size, out_page); void* buf = reinterpret_cast(_root) + sizeof(xml_memory_page) + _busy_size; @@ -559,12 +595,12 @@ PUGI__NS_BEGIN void* allocate_object(size_t size, xml_memory_page*& out_page) { void* result = allocate_memory(size + sizeof(uint32_t), out_page); - if (!result) return 0; + if (!result) return nullptr; // adjust for marker ptrdiff_t offset = static_cast(result) - reinterpret_cast(out_page->compact_page_marker); - if (PUGI__UNLIKELY(static_cast(offset) >= 256 * xml_memory_block_alignment)) + if (PUGI_IMPL_UNLIKELY(static_cast(offset) >= 256 * xml_memory_block_alignment)) { // insert new marker uint32_t* marker = static_cast(result); @@ -605,7 +641,7 @@ PUGI__NS_BEGIN if (page->freed_size == page->busy_size) { - if (page->next == 0) + if (page->next == nullptr) { assert(_root == page); @@ -615,9 +651,9 @@ PUGI__NS_BEGIN #ifdef PUGIXML_COMPACT // reset compact state to maximize efficiency - page->compact_string_base = 0; - page->compact_shared_parent = 0; - page->compact_page_marker = 0; + page->compact_string_base = nullptr; + page->compact_shared_parent = nullptr; + page->compact_page_marker = nullptr; #endif _busy_size = 0; @@ -641,7 +677,7 @@ PUGI__NS_BEGIN { static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment; - PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); + PUGI_IMPL_STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); // allocate memory for string and header block size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); @@ -652,7 +688,7 @@ PUGI__NS_BEGIN xml_memory_page* page; xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); - if (!header) return 0; + if (!header) return nullptr; // setup header ptrdiff_t page_offset = reinterpret_cast(header) - reinterpret_cast(page) - sizeof(xml_memory_page); @@ -707,14 +743,14 @@ PUGI__NS_BEGIN #endif }; - PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) + PUGI_IMPL_FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) { const size_t large_allocation_threshold = xml_memory_page_size / 4; xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); out_page = page; - if (!page) return 0; + if (!page) return nullptr; if (size <= large_allocation_threshold) { @@ -744,10 +780,10 @@ PUGI__NS_BEGIN return reinterpret_cast(page) + sizeof(xml_memory_page); } -PUGI__NS_END +PUGI_IMPL_NS_END #ifdef PUGIXML_COMPACT -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN static const uintptr_t compact_alignment_log2 = 2; static const uintptr_t compact_alignment = 1 << compact_alignment_log2; @@ -756,7 +792,7 @@ PUGI__NS_BEGIN public: compact_header(xml_memory_page* page, unsigned int flags) { - PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment); + PUGI_IMPL_STATIC_ASSERT(xml_memory_block_alignment == compact_alignment); ptrdiff_t offset = (reinterpret_cast(this) - reinterpret_cast(page->compact_page_marker)); assert(offset % compact_alignment == 0 && static_cast(offset) < 256 * compact_alignment); @@ -794,19 +830,19 @@ PUGI__NS_BEGIN unsigned char _flags; }; - PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset) + PUGI_IMPL_FN xml_memory_page* compact_get_page(const void* object, int header_offset) { const compact_header* header = reinterpret_cast(static_cast(object) - header_offset); return header->get_page(); } - template PUGI__FN_NO_INLINE T* compact_get_value(const void* object) + template PUGI_IMPL_FN_NO_INLINE T* compact_get_value(const void* object) { return static_cast(compact_get_page(object, header_offset)->allocator->_hash->find(object)); } - template PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value) + template PUGI_IMPL_FN_NO_INLINE void compact_set_value(const void* object, T* value) { compact_get_page(object, header_offset)->allocator->_hash->insert(object, value); } @@ -861,7 +897,7 @@ PUGI__NS_BEGIN return compact_get_value(this); } else - return 0; + return nullptr; } T* operator->() const @@ -904,7 +940,7 @@ PUGI__NS_BEGIN { xml_memory_page* page = compact_get_page(this, header_offset); - if (PUGI__UNLIKELY(page->compact_shared_parent == 0)) + if (PUGI_IMPL_UNLIKELY(page->compact_shared_parent == nullptr)) page->compact_shared_parent = value; if (page->compact_shared_parent == value) @@ -941,7 +977,7 @@ PUGI__NS_BEGIN return compact_get_value(this); } else - return 0; + return nullptr; } T* operator->() const @@ -971,7 +1007,7 @@ PUGI__NS_BEGIN { xml_memory_page* page = compact_get_page(this, header_offset); - if (PUGI__UNLIKELY(page->compact_string_base == 0)) + if (PUGI_IMPL_UNLIKELY(page->compact_string_base == nullptr)) page->compact_string_base = value; ptrdiff_t offset = value - page->compact_string_base; @@ -1037,13 +1073,13 @@ PUGI__NS_BEGIN } } else - return 0; + return nullptr; } private: unsigned char _data; }; -PUGI__NS_END +PUGI_IMPL_NS_END #endif #ifdef PUGIXML_COMPACT @@ -1053,7 +1089,7 @@ namespace pugi { xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0) { - PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8); + PUGI_IMPL_STATIC_ASSERT(sizeof(xml_attribute_struct) == 8); } impl::compact_header header; @@ -1071,7 +1107,7 @@ namespace pugi { xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) { - PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); + PUGI_IMPL_STATIC_ASSERT(sizeof(xml_node_struct) == 12); } impl::compact_header header; @@ -1096,9 +1132,9 @@ namespace pugi { struct xml_attribute_struct { - xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0) + xml_attribute_struct(impl::xml_memory_page* page): name(nullptr), value(nullptr), prev_attribute_c(nullptr), next_attribute(nullptr) { - header = PUGI__GETHEADER_IMPL(this, page, 0); + header = PUGI_IMPL_GETHEADER_IMPL(this, page, 0); } uintptr_t header; @@ -1112,9 +1148,9 @@ namespace pugi struct xml_node_struct { - xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) + xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(nullptr), value(nullptr), parent(nullptr), first_child(nullptr), prev_sibling_c(nullptr), next_sibling(nullptr), first_attribute(nullptr) { - header = PUGI__GETHEADER_IMPL(this, page, type); + header = PUGI_IMPL_GETHEADER_IMPL(this, page, type); } uintptr_t header; @@ -1134,7 +1170,7 @@ namespace pugi } #endif -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN struct xml_extra_buffer { char_t* buffer; @@ -1143,7 +1179,7 @@ PUGI__NS_BEGIN struct xml_document_struct: public xml_node_struct, public xml_allocator { - xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) + xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(nullptr), extra_buffers(nullptr) { } @@ -1160,24 +1196,24 @@ PUGI__NS_BEGIN { assert(object); - return *PUGI__GETPAGE(object)->allocator; + return *PUGI_IMPL_GETPAGE(object)->allocator; } template inline xml_document_struct& get_document(const Object* object) { assert(object); - return *static_cast(PUGI__GETPAGE(object)->allocator); + return *static_cast(PUGI_IMPL_GETPAGE(object)->allocator); } -PUGI__NS_END +PUGI_IMPL_NS_END // Low-level DOM operations -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) { xml_memory_page* page; void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page); - if (!memory) return 0; + if (!memory) return nullptr; return new (memory) xml_attribute_struct(page); } @@ -1186,7 +1222,7 @@ PUGI__NS_BEGIN { xml_memory_page* page; void* memory = alloc.allocate_object(sizeof(xml_node_struct), page); - if (!memory) return 0; + if (!memory) return nullptr; return new (memory) xml_node_struct(page, type); } @@ -1199,7 +1235,7 @@ PUGI__NS_BEGIN if (a->header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); - alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a)); + alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI_IMPL_GETPAGE(a)); } inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) @@ -1228,7 +1264,7 @@ PUGI__NS_BEGIN child = next; } - alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n)); + alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI_IMPL_GETPAGE(n)); } inline void append_node(xml_node_struct* child, xml_node_struct* node) @@ -1325,9 +1361,9 @@ PUGI__NS_BEGIN else parent->first_child = next; - node->parent = 0; - node->prev_sibling_c = 0; - node->next_sibling = 0; + node->parent = nullptr; + node->prev_sibling_c = nullptr; + node->next_sibling = nullptr; } inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node) @@ -1408,37 +1444,37 @@ PUGI__NS_BEGIN else node->first_attribute = next; - attr->prev_attribute_c = 0; - attr->next_attribute = 0; + attr->prev_attribute_c = nullptr; + attr->next_attribute = nullptr; } - PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) + PUGI_IMPL_FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) { - if (!alloc.reserve()) return 0; + if (!alloc.reserve()) return nullptr; xml_node_struct* child = allocate_node(alloc, type); - if (!child) return 0; + if (!child) return nullptr; append_node(child, node); return child; } - PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc) + PUGI_IMPL_FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc) { - if (!alloc.reserve()) return 0; + if (!alloc.reserve()) return nullptr; xml_attribute_struct* attr = allocate_attribute(alloc); - if (!attr) return 0; + if (!attr) return nullptr; append_attribute(attr, node); return attr; } -PUGI__NS_END +PUGI_IMPL_NS_END // Helper classes for code generation -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN struct opt_false { enum { value = 0 }; @@ -1448,10 +1484,10 @@ PUGI__NS_BEGIN { enum { value = 1 }; }; -PUGI__NS_END +PUGI_IMPL_NS_END // Unicode utilities -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN inline uint16_t endian_swap(uint16_t value) { return static_cast(((value & 0xff) << 8) | (value >> 8)); @@ -1556,8 +1592,8 @@ PUGI__NS_BEGIN static value_type high(value_type result, uint32_t ch) { - uint32_t msh = static_cast(ch - 0x10000) >> 10; - uint32_t lsh = static_cast(ch - 0x10000) & 0x3ff; + uint32_t msh = (ch - 0x10000U) >> 10; + uint32_t lsh = (ch - 0x10000U) & 0x3ff; result[0] = static_cast(0xD800 + msh); result[1] = static_cast(0xDC00 + lsh); @@ -1833,15 +1869,15 @@ PUGI__NS_BEGIN }; #ifdef PUGIXML_WCHAR_MODE - PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) + PUGI_IMPL_FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) { for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); } #endif -PUGI__NS_END +PUGI_IMPL_NS_END -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN enum chartype_t { ct_parse_pcdata = 1, // \0, &, \r, < @@ -1854,7 +1890,7 @@ PUGI__NS_BEGIN ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : }; - static const unsigned char chartype_table[256] = + static constexpr unsigned char chartype_table[256] = { 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 @@ -1884,7 +1920,7 @@ PUGI__NS_BEGIN ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . }; - static const unsigned char chartypex_table[256] = + static constexpr unsigned char chartypex_table[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, // 0-15 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 @@ -1907,24 +1943,24 @@ PUGI__NS_BEGIN }; #ifdef PUGIXML_WCHAR_MODE - #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) + #define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) #else - #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) + #define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) #endif - #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table) - #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table) + #define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table) + #define PUGI_IMPL_IS_CHARTYPEX(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartypex_table) - PUGI__FN bool is_little_endian() + PUGI_IMPL_FN bool is_little_endian() { unsigned int ui = 1; return *reinterpret_cast(&ui) == 1; } - PUGI__FN xml_encoding get_wchar_encoding() + PUGI_IMPL_FN xml_encoding get_wchar_encoding() { - PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + PUGI_IMPL_STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); if (sizeof(wchar_t) == 2) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; @@ -1932,13 +1968,13 @@ PUGI__NS_BEGIN return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; } - PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length) + PUGI_IMPL_FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length) { - #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; } - #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; } + #define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; } + #define PUGI_IMPL_SCANCHARTYPE(ct) { while (offset < size && PUGI_IMPL_IS_CHARTYPE(data[offset], ct)) offset++; } // check if we have a non-empty XML declaration - if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space))) + if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI_IMPL_IS_CHARTYPE(data[5], ct_space))) return false; // scan XML declaration until the encoding field @@ -1953,28 +1989,28 @@ PUGI__NS_BEGIN size_t offset = i; // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed - PUGI__SCANCHAR('e'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('c'); PUGI__SCANCHAR('o'); - PUGI__SCANCHAR('d'); PUGI__SCANCHAR('i'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('g'); + PUGI_IMPL_SCANCHAR('e'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('c'); PUGI_IMPL_SCANCHAR('o'); + PUGI_IMPL_SCANCHAR('d'); PUGI_IMPL_SCANCHAR('i'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('g'); // S? = S? - PUGI__SCANCHARTYPE(ct_space); - PUGI__SCANCHAR('='); - PUGI__SCANCHARTYPE(ct_space); + PUGI_IMPL_SCANCHARTYPE(ct_space); + PUGI_IMPL_SCANCHAR('='); + PUGI_IMPL_SCANCHARTYPE(ct_space); // the only two valid delimiters are ' and " uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\''; - PUGI__SCANCHAR(delimiter); + PUGI_IMPL_SCANCHAR(delimiter); size_t start = offset; out_encoding = data + offset; - PUGI__SCANCHARTYPE(ct_symbol); + PUGI_IMPL_SCANCHARTYPE(ct_symbol); out_length = offset - start; - PUGI__SCANCHAR(delimiter); + PUGI_IMPL_SCANCHAR(delimiter); return true; } @@ -1982,11 +2018,11 @@ PUGI__NS_BEGIN return false; - #undef PUGI__SCANCHAR - #undef PUGI__SCANCHARTYPE + #undef PUGI_IMPL_SCANCHAR + #undef PUGI_IMPL_SCANCHARTYPE } - PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size) + PUGI_IMPL_FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size) { // skip encoding autodetection if input buffer is too small if (size < 4) return encoding_utf8; @@ -2011,7 +2047,7 @@ PUGI__NS_BEGIN if (d0 == 0x3c && d1 == 0) return encoding_utf16_le; // no known BOM detected; parse declaration - const uint8_t* enc = 0; + const uint8_t* enc = nullptr; size_t enc_length = 0; if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length)) @@ -2034,7 +2070,7 @@ PUGI__NS_BEGIN return encoding_utf8; } - PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size) + PUGI_IMPL_FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size) { // replace wchar encoding with utf implementation if (encoding == encoding_wchar) return get_wchar_encoding(); @@ -2054,7 +2090,7 @@ PUGI__NS_BEGIN return guess_buffer_encoding(data, size); } - PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + PUGI_IMPL_FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { size_t length = size / sizeof(char_t); @@ -2083,13 +2119,13 @@ PUGI__NS_BEGIN } #ifdef PUGIXML_WCHAR_MODE - PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) + PUGI_IMPL_FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) { return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); } - PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + PUGI_IMPL_FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { const char_t* data = static_cast(contents); size_t length = size / sizeof(char_t); @@ -2118,7 +2154,7 @@ PUGI__NS_BEGIN return true; } - template PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) + template PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) { const typename D::type* data = static_cast(contents); size_t data_length = size / sizeof(typename D::type); @@ -2143,7 +2179,7 @@ PUGI__NS_BEGIN return true; } - PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + PUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // get native encoding xml_encoding wchar_encoding = get_wchar_encoding(); @@ -2188,7 +2224,7 @@ PUGI__NS_BEGIN return false; } #else - template PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) + template PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) { const typename D::type* data = static_cast(contents); size_t data_length = size / sizeof(typename D::type); @@ -2213,7 +2249,7 @@ PUGI__NS_BEGIN return true; } - PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) + PUGI_IMPL_FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) { for (size_t i = 0; i < size; ++i) if (data[i] > 127) @@ -2222,7 +2258,7 @@ PUGI__NS_BEGIN return size; } - PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + PUGI_IMPL_FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) { const uint8_t* data = static_cast(contents); size_t data_length = size; @@ -2259,7 +2295,7 @@ PUGI__NS_BEGIN return true; } - PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + PUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) { // fast path: no conversion required if (encoding == encoding_utf8) @@ -2294,13 +2330,13 @@ PUGI__NS_BEGIN } #endif - PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) + PUGI_IMPL_FN size_t as_utf8_begin(const wchar_t* str, size_t length) { // get length in utf8 characters return wchar_decoder::process(str, length, 0, utf8_counter()); } - PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) + PUGI_IMPL_FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) { // convert to utf8 uint8_t* begin = reinterpret_cast(buffer); @@ -2312,7 +2348,7 @@ PUGI__NS_BEGIN } #ifndef PUGIXML_NO_STL - PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) + PUGI_IMPL_FN std::string as_utf8_impl(const wchar_t* str, size_t length) { // first pass: get length in utf8 characters size_t size = as_utf8_begin(str, length); @@ -2327,7 +2363,7 @@ PUGI__NS_BEGIN return result; } - PUGI__FN std::basic_string as_wide_impl(const char* str, size_t size) + PUGI_IMPL_FN std::basic_string as_wide_impl(const char* str, size_t size) { const uint8_t* data = reinterpret_cast(str); @@ -2370,17 +2406,19 @@ PUGI__NS_BEGIN } template - PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length) + PUGI_IMPL_FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length) { + assert((header & header_mask) == 0 || dest); // header bit indicates whether dest was previously allocated + if (source_length == 0) { // empty string and null pointer are equivalent, so just deallocate old memory - xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; + xml_allocator* alloc = PUGI_IMPL_GETPAGE_IMPL(header)->allocator; if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated - dest = 0; + dest = nullptr; header &= ~header_mask; return true; @@ -2395,7 +2433,7 @@ PUGI__NS_BEGIN } else { - xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; + xml_allocator* alloc = PUGI_IMPL_GETPAGE_IMPL(header)->allocator; if (!alloc->reserve()) return false; @@ -2423,7 +2461,7 @@ PUGI__NS_BEGIN char_t* end; size_t size; - gap(): end(0), size(0) + gap(): end(nullptr), size(0) { } @@ -2435,7 +2473,7 @@ PUGI__NS_BEGIN { // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) assert(s >= end); - memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); + memmove(end - size, end, (s - end) * sizeof(char_t)); } s += count; // end of current gap @@ -2452,7 +2490,7 @@ PUGI__NS_BEGIN { // Move [old_gap_end, current_pos) to [old_gap_start, ...) assert(s >= end); - memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); + memmove(end - size, end, (s - end) * sizeof(char_t)); return s - size; } @@ -2460,7 +2498,7 @@ PUGI__NS_BEGIN } }; - PUGI__FN char_t* strconv_escape(char_t* s, gap& g) + PUGI_IMPL_FN char_t* strconv_escape(char_t* s, gap& g) { char_t* stre = s + 1; @@ -2601,25 +2639,25 @@ PUGI__NS_BEGIN } // Parser utilities - #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) - #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } - #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) - #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } - #define PUGI__POPNODE() { cursor = cursor->parent; } - #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } - #define PUGI__SCANWHILE(X) { while (X) ++s; } - #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } - #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } - #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(0) - #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } - - PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) + #define PUGI_IMPL_ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) + #define PUGI_IMPL_SKIPWS() { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; } + #define PUGI_IMPL_OPTSET(OPT) ( optmsk & (OPT) ) + #define PUGI_IMPL_PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); } + #define PUGI_IMPL_POPNODE() { cursor = cursor->parent; } + #define PUGI_IMPL_SCANFOR(X) { while (*s != 0 && !(X)) ++s; } + #define PUGI_IMPL_SCANWHILE(X) { while (X) ++s; } + #define PUGI_IMPL_SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } } + #define PUGI_IMPL_ENDSEG() { ch = *s; *s = 0; ++s; } + #define PUGI_IMPL_THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(nullptr) + #define PUGI_IMPL_CHECK_ERROR(err, m) { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); } + + PUGI_IMPL_FN char_t* strconv_comment(char_t* s, char_t endch) { gap g; while (true) { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); + PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_comment)); if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { @@ -2627,7 +2665,7 @@ PUGI__NS_BEGIN if (*s == '\n') g.push(s, 1); } - else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here + else if (s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>')) // comment ends here { *g.flush(s) = 0; @@ -2635,19 +2673,19 @@ PUGI__NS_BEGIN } else if (*s == 0) { - return 0; + return nullptr; } else ++s; } } - PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) + PUGI_IMPL_FN char_t* strconv_cdata(char_t* s, char_t endch) { gap g; while (true) { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); + PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_cdata)); if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair { @@ -2655,7 +2693,7 @@ PUGI__NS_BEGIN if (*s == '\n') g.push(s, 1); } - else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here + else if (s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>')) // CDATA ends here { *g.flush(s) = 0; @@ -2663,7 +2701,7 @@ PUGI__NS_BEGIN } else if (*s == 0) { - return 0; + return nullptr; } else ++s; } @@ -2681,14 +2719,14 @@ PUGI__NS_BEGIN while (true) { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata)); + PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_pcdata)); if (*s == '<') // PCDATA ends here { char_t* end = g.flush(s); if (opt_trim::value) - while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) + while (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space)) --end; *end = 0; @@ -2710,7 +2748,7 @@ PUGI__NS_BEGIN char_t* end = g.flush(s); if (opt_trim::value) - while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) + while (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space)) --end; *end = 0; @@ -2722,9 +2760,9 @@ PUGI__NS_BEGIN } }; - PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) + PUGI_IMPL_FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) { - PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); + PUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (trim eol escapes); this simultaneously checks 3 options from assertion above { @@ -2736,7 +2774,7 @@ PUGI__NS_BEGIN case 5: return strconv_pcdata_impl::parse; case 6: return strconv_pcdata_impl::parse; case 7: return strconv_pcdata_impl::parse; - default: assert(false); return 0; // unreachable + default: assert(false); return nullptr; // unreachable } } @@ -2749,37 +2787,37 @@ PUGI__NS_BEGIN gap g; // trim leading whitespaces - if (PUGI__IS_CHARTYPE(*s, ct_space)) + if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) { char_t* str = s; do ++str; - while (PUGI__IS_CHARTYPE(*str, ct_space)); + while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space)); g.push(s, str - s); } while (true) { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); + PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); if (*s == end_quote) { char_t* str = g.flush(s); do *str-- = 0; - while (PUGI__IS_CHARTYPE(*str, ct_space)); + while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space)); return s + 1; } - else if (PUGI__IS_CHARTYPE(*s, ct_space)) + else if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) { *s++ = ' '; - if (PUGI__IS_CHARTYPE(*s, ct_space)) + if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) { char_t* str = s + 1; - while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; + while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space)) ++str; g.push(s, str - s); } @@ -2790,7 +2828,7 @@ PUGI__NS_BEGIN } else if (!*s) { - return 0; + return nullptr; } else ++s; } @@ -2802,7 +2840,7 @@ PUGI__NS_BEGIN while (true) { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); + PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws)); if (*s == end_quote) { @@ -2810,7 +2848,7 @@ PUGI__NS_BEGIN return s + 1; } - else if (PUGI__IS_CHARTYPE(*s, ct_space)) + else if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) { if (*s == '\r') { @@ -2826,7 +2864,7 @@ PUGI__NS_BEGIN } else if (!*s) { - return 0; + return nullptr; } else ++s; } @@ -2838,7 +2876,7 @@ PUGI__NS_BEGIN while (true) { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); + PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { @@ -2858,7 +2896,7 @@ PUGI__NS_BEGIN } else if (!*s) { - return 0; + return nullptr; } else ++s; } @@ -2870,7 +2908,7 @@ PUGI__NS_BEGIN while (true) { - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); + PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { @@ -2884,16 +2922,16 @@ PUGI__NS_BEGIN } else if (!*s) { - return 0; + return nullptr; } else ++s; } } }; - PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) + PUGI_IMPL_FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) { - PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); + PUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); switch ((optmask >> 4) & 15) // get bitmask for flags (wnorm wconv eol escapes); this simultaneously checks 4 options from assertion above { @@ -2913,7 +2951,7 @@ PUGI__NS_BEGIN case 13: return strconv_attribute_impl::parse_wnorm; case 14: return strconv_attribute_impl::parse_wnorm; case 15: return strconv_attribute_impl::parse_wnorm; - default: assert(false); return 0; // unreachable + default: assert(false); return nullptr; // unreachable } } @@ -2932,7 +2970,7 @@ PUGI__NS_BEGIN char_t* error_offset; xml_parse_status error_status; - xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) + xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(nullptr), error_status(status_ok) { } @@ -2949,8 +2987,8 @@ PUGI__NS_BEGIN { // quoted string char_t ch = *s++; - PUGI__SCANFOR(*s == ch); - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); + PUGI_IMPL_SCANFOR(*s == ch); + if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); s++; } @@ -2958,20 +2996,20 @@ PUGI__NS_BEGIN { // s += 2; - PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); + PUGI_IMPL_SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype + if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); s += 2; } else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') { s += 4; - PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype - if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); + PUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype + if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); s += 3; } - else PUGI__THROW_ERROR(status_bad_doctype, s); + else PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); return s; } @@ -3004,7 +3042,7 @@ PUGI__NS_BEGIN else s++; } - PUGI__THROW_ERROR(status_bad_doctype, s); + PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); } char_t* parse_doctype_group(char_t* s, char_t endch) @@ -3048,7 +3086,7 @@ PUGI__NS_BEGIN else s++; } - if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s); + if (depth != 0 || endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); return s; } @@ -3066,31 +3104,31 @@ PUGI__NS_BEGIN { ++s; - if (PUGI__OPTSET(parse_comments)) + if (PUGI_IMPL_OPTSET(parse_comments)) { - PUGI__PUSHNODE(node_comment); // Append a new node on the tree. + PUGI_IMPL_PUSHNODE(node_comment); // Append a new node on the tree. cursor->value = s; // Save the offset. } - if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) + if (PUGI_IMPL_OPTSET(parse_eol) && PUGI_IMPL_OPTSET(parse_comments)) { s = strconv_comment(s, endch); - if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); + if (!s) PUGI_IMPL_THROW_ERROR(status_bad_comment, cursor->value); } else { // Scan for terminating '-->'. - PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_comment, s); + PUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>')); + PUGI_IMPL_CHECK_ERROR(status_bad_comment, s); - if (PUGI__OPTSET(parse_comments)) + if (PUGI_IMPL_OPTSET(parse_comments)) *s = 0; // Zero-terminate this segment at the first terminating '-'. s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. } } - else PUGI__THROW_ERROR(status_bad_comment, s); + else PUGI_IMPL_THROW_ERROR(status_bad_comment, s); } else if (*s == '[') { @@ -3099,22 +3137,22 @@ PUGI__NS_BEGIN { ++s; - if (PUGI__OPTSET(parse_cdata)) + if (PUGI_IMPL_OPTSET(parse_cdata)) { - PUGI__PUSHNODE(node_cdata); // Append a new node on the tree. + PUGI_IMPL_PUSHNODE(node_cdata); // Append a new node on the tree. cursor->value = s; // Save the offset. - if (PUGI__OPTSET(parse_eol)) + if (PUGI_IMPL_OPTSET(parse_eol)) { s = strconv_cdata(s, endch); - if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); + if (!s) PUGI_IMPL_THROW_ERROR(status_bad_cdata, cursor->value); } else { // Scan for terminating ']]>'. - PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_cdata, s); + PUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>')); + PUGI_IMPL_CHECK_ERROR(status_bad_cdata, s); *s++ = 0; // Zero-terminate this segment. } @@ -3122,21 +3160,21 @@ PUGI__NS_BEGIN else // Flagged for discard, but we still have to scan for the terminator. { // Scan for terminating ']]>'. - PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); - PUGI__CHECK_ERROR(status_bad_cdata, s); + PUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>')); + PUGI_IMPL_CHECK_ERROR(status_bad_cdata, s); ++s; } s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. } - else PUGI__THROW_ERROR(status_bad_cdata, s); + else PUGI_IMPL_THROW_ERROR(status_bad_cdata, s); } - else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI__ENDSWITH(s[6], 'E')) + else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI_IMPL_ENDSWITH(s[6], 'E')) { s -= 2; - if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s); + if (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s); char_t* mark = s + 9; @@ -3146,18 +3184,18 @@ PUGI__NS_BEGIN assert((*s == 0 && endch == '>') || *s == '>'); if (*s) *s++ = 0; - if (PUGI__OPTSET(parse_doctype)) + if (PUGI_IMPL_OPTSET(parse_doctype)) { - while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark; + while (PUGI_IMPL_IS_CHARTYPE(*mark, ct_space)) ++mark; - PUGI__PUSHNODE(node_doctype); + PUGI_IMPL_PUSHNODE(node_doctype); cursor->value = mark; } } - else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); - else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s); - else PUGI__THROW_ERROR(status_unrecognized_tag, s); + else if (*s == 0 && endch == '-') PUGI_IMPL_THROW_ERROR(status_bad_comment, s); + else if (*s == 0 && endch == '[') PUGI_IMPL_THROW_ERROR(status_bad_cdata, s); + else PUGI_IMPL_THROW_ERROR(status_unrecognized_tag, s); return s; } @@ -3174,50 +3212,50 @@ PUGI__NS_BEGIN // read PI target char_t* target = s; - if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s); + if (!PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_pi, s); - PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); - PUGI__CHECK_ERROR(status_bad_pi, s); + PUGI_IMPL_SCANWHILE(PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol)); + PUGI_IMPL_CHECK_ERROR(status_bad_pi, s); // determine node type; stricmp / strcasecmp is not portable bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; - if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi)) + if (declaration ? PUGI_IMPL_OPTSET(parse_declaration) : PUGI_IMPL_OPTSET(parse_pi)) { if (declaration) { // disallow non top-level declarations - if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s); + if (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_pi, s); - PUGI__PUSHNODE(node_declaration); + PUGI_IMPL_PUSHNODE(node_declaration); } else { - PUGI__PUSHNODE(node_pi); + PUGI_IMPL_PUSHNODE(node_pi); } cursor->name = target; - PUGI__ENDSEG(); + PUGI_IMPL_ENDSEG(); // parse value/attributes if (ch == '?') { // empty node - if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s); + if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_pi, s); s += (*s == '>'); - PUGI__POPNODE(); + PUGI_IMPL_POPNODE(); } - else if (PUGI__IS_CHARTYPE(ch, ct_space)) + else if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space)) { - PUGI__SKIPWS(); + PUGI_IMPL_SKIPWS(); // scan for tag end char_t* value = s; - PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); - PUGI__CHECK_ERROR(status_bad_pi, s); + PUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>')); + PUGI_IMPL_CHECK_ERROR(status_bad_pi, s); if (declaration) { @@ -3232,20 +3270,20 @@ PUGI__NS_BEGIN // store value and step over > cursor->value = value; - PUGI__POPNODE(); + PUGI_IMPL_POPNODE(); - PUGI__ENDSEG(); + PUGI_IMPL_ENDSEG(); s += (*s == '>'); } } - else PUGI__THROW_ERROR(status_bad_pi, s); + else PUGI_IMPL_THROW_ERROR(status_bad_pi, s); } else { // scan for tag end - PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); - PUGI__CHECK_ERROR(status_bad_pi, s); + PUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>')); + PUGI_IMPL_CHECK_ERROR(status_bad_pi, s); s += (s[1] == '>' ? 2 : 1); } @@ -3264,6 +3302,7 @@ PUGI__NS_BEGIN char_t ch = 0; xml_node_struct* cursor = root; char_t* mark = s; + char_t* merged_pcdata = s; while (*s != 0) { @@ -3272,39 +3311,39 @@ PUGI__NS_BEGIN ++s; LOC_TAG: - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' + if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' { - PUGI__PUSHNODE(node_element); // Append a new node to the tree. + PUGI_IMPL_PUSHNODE(node_element); // Append a new node to the tree. cursor->name = s; - PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. + PUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. + PUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over. if (ch == '>') { // end of tag } - else if (PUGI__IS_CHARTYPE(ch, ct_space)) + else if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space)) { LOC_ATTRIBUTES: while (true) { - PUGI__SKIPWS(); // Eat any whitespace. + PUGI_IMPL_SKIPWS(); // Eat any whitespace. - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... + if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // <... #... { xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute. - if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); + if (!a) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); a->name = s; // Save the offset. - PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. + PUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. + PUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over. - if (PUGI__IS_CHARTYPE(ch, ct_space)) + if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space)) { - PUGI__SKIPWS(); // Eat any whitespace. + PUGI_IMPL_SKIPWS(); // Eat any whitespace. ch = *s; ++s; @@ -3312,7 +3351,7 @@ PUGI__NS_BEGIN if (ch == '=') // '<... #=...' { - PUGI__SKIPWS(); // Eat any whitespace. + PUGI_IMPL_SKIPWS(); // Eat any whitespace. if (*s == '"' || *s == '\'') // '<... #="...' { @@ -3322,16 +3361,16 @@ PUGI__NS_BEGIN s = strconv_attribute(s, ch); - if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); + if (!s) PUGI_IMPL_THROW_ERROR(status_bad_attribute, a->value); // After this line the loop continues from the start; // Whitespaces, / and > are ok, symbols and EOF are wrong, // everything else will be detected - if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s); + if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_attribute, s); } - else PUGI__THROW_ERROR(status_bad_attribute, s); + else PUGI_IMPL_THROW_ERROR(status_bad_attribute, s); } - else PUGI__THROW_ERROR(status_bad_attribute, s); + else PUGI_IMPL_THROW_ERROR(status_bad_attribute, s); } else if (*s == '/') { @@ -3339,16 +3378,16 @@ PUGI__NS_BEGIN if (*s == '>') { - PUGI__POPNODE(); + PUGI_IMPL_POPNODE(); s++; break; } else if (*s == 0 && endch == '>') { - PUGI__POPNODE(); + PUGI_IMPL_POPNODE(); break; } - else PUGI__THROW_ERROR(status_bad_start_element, s); + else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); } else if (*s == '>') { @@ -3360,16 +3399,16 @@ PUGI__NS_BEGIN { break; } - else PUGI__THROW_ERROR(status_bad_start_element, s); + else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); } // !!! } else if (ch == '/') // '<#.../' { - if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s); + if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); - PUGI__POPNODE(); // Pop. + PUGI_IMPL_POPNODE(); // Pop. s += (*s == '>'); } @@ -3378,9 +3417,9 @@ PUGI__NS_BEGIN // we stepped over null terminator, backtrack & handle closing tag --s; - if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); + if (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); } - else PUGI__THROW_ERROR(status_bad_start_element, s); + else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s); } else if (*s == '/') { @@ -3389,30 +3428,30 @@ PUGI__NS_BEGIN mark = s; char_t* name = cursor->name; - if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark); + if (!name) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark); - while (PUGI__IS_CHARTYPE(*s, ct_symbol)) + while (PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol)) { - if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark); + if (*s++ != *name++) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark); } if (*name) { - if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); - else PUGI__THROW_ERROR(status_end_element_mismatch, mark); + if (*s == 0 && name[0] == endch && name[1] == 0) PUGI_IMPL_THROW_ERROR(status_bad_end_element, s); + else PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark); } - PUGI__POPNODE(); // Pop. + PUGI_IMPL_POPNODE(); // Pop. - PUGI__SKIPWS(); + PUGI_IMPL_SKIPWS(); if (*s == 0) { - if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s); + if (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s); } else { - if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s); + if (*s != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s); ++s; } } @@ -3422,62 +3461,79 @@ PUGI__NS_BEGIN if (!s) return s; assert(cursor); - if (PUGI__NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES; + if (PUGI_IMPL_NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES; } else if (*s == '!') // 'first_child) continue; } } - if (!PUGI__OPTSET(parse_trim_pcdata)) + if (!PUGI_IMPL_OPTSET(parse_trim_pcdata)) s = mark; - if (cursor->parent || PUGI__OPTSET(parse_fragment)) + if (cursor->parent || PUGI_IMPL_OPTSET(parse_fragment)) { - if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) + char_t* parsed_pcdata = s; + + s = strconv_pcdata(s); + + if (PUGI_IMPL_OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) { - cursor->value = s; // Save the offset. + cursor->value = parsed_pcdata; // Save the offset. } - else + else if (PUGI_IMPL_OPTSET(parse_merge_pcdata) && cursor->first_child && PUGI_IMPL_NODETYPE(cursor->first_child->prev_sibling_c) == node_pcdata) { - PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. + assert(merged_pcdata >= cursor->first_child->prev_sibling_c->value); - cursor->value = s; // Save the offset. + // Catch up to the end of last parsed value; only needed for the first fragment. + merged_pcdata += strlength(merged_pcdata); - PUGI__POPNODE(); // Pop since this is a standalone. + size_t length = strlength(parsed_pcdata); + + // Must use memmove instead of memcpy as this move may overlap + memmove(merged_pcdata, parsed_pcdata, (length + 1) * sizeof(char_t)); + merged_pcdata += length; } + else + { + xml_node_struct* prev_cursor = cursor; + PUGI_IMPL_PUSHNODE(node_pcdata); // Append a new node on the tree. - s = strconv_pcdata(s); + cursor->value = parsed_pcdata; // Save the offset. + merged_pcdata = parsed_pcdata; // Used for parse_merge_pcdata above, cheaper to save unconditionally + + cursor = prev_cursor; // Pop since this is a standalone. + } if (!*s) break; } else { - PUGI__SCANFOR(*s == '<'); // '...<' + PUGI_IMPL_SCANFOR(*s == '<'); // '...<' if (!*s) break; ++s; @@ -3489,7 +3545,7 @@ PUGI__NS_BEGIN } // check that last tag is closed - if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s); + if (cursor != root) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, s); return s; } @@ -3511,7 +3567,7 @@ PUGI__NS_BEGIN { while (node) { - if (PUGI__NODETYPE(node) == node_element) return true; + if (PUGI_IMPL_NODETYPE(node) == node_element) return true; node = node->next_sibling; } @@ -3523,10 +3579,10 @@ PUGI__NS_BEGIN { // early-out for empty documents if (length == 0) - return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element); + return make_parse_result(PUGI_IMPL_OPTSET(parse_fragment) ? status_ok : status_no_document_element); // get last child of the root before parsing - xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0; + xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : nullptr; // create parser on stack xml_parser parser(static_cast(xmldoc)); @@ -3551,9 +3607,9 @@ PUGI__NS_BEGIN return make_parse_result(status_unrecognized_tag, length - 1); // check if there are any element nodes parsed - xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0; + xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child + 0; - if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) + if (!PUGI_IMPL_OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) return make_parse_result(status_no_document_element, length - 1); } else @@ -3568,7 +3624,7 @@ PUGI__NS_BEGIN }; // Output facilities - PUGI__FN xml_encoding get_write_native_encoding() + PUGI_IMPL_FN xml_encoding get_write_native_encoding() { #ifdef PUGIXML_WCHAR_MODE return get_wchar_encoding(); @@ -3577,7 +3633,7 @@ PUGI__NS_BEGIN #endif } - PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding) + PUGI_IMPL_FN xml_encoding get_write_encoding(xml_encoding encoding) { // replace wchar encoding with utf implementation if (encoding == encoding_wchar) return get_wchar_encoding(); @@ -3595,18 +3651,18 @@ PUGI__NS_BEGIN return encoding_utf8; } - template PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T) + template PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T) { - PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); + PUGI_IMPL_STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); typename T::value_type end = D::process(reinterpret_cast(data), length, dest, T()); return static_cast(end - dest) * sizeof(*dest); } - template PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap) + template PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap) { - PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); + PUGI_IMPL_STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); typename T::value_type end = D::process(reinterpret_cast(data), length, dest, T()); @@ -3620,7 +3676,7 @@ PUGI__NS_BEGIN } #ifdef PUGIXML_WCHAR_MODE - PUGI__FN size_t get_valid_length(const char_t* data, size_t length) + PUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 1) return 0; @@ -3628,7 +3684,7 @@ PUGI__NS_BEGIN return (sizeof(wchar_t) == 2 && static_cast(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; } - PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) + PUGI_IMPL_FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) { // only endian-swapping is required if (need_endian_swap_utf(encoding, get_wchar_encoding())) @@ -3666,7 +3722,7 @@ PUGI__NS_BEGIN return 0; } #else - PUGI__FN size_t get_valid_length(const char_t* data, size_t length) + PUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length) { if (length < 5) return 0; @@ -3682,7 +3738,7 @@ PUGI__NS_BEGIN return length; } - PUGI__FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) + PUGI_IMPL_FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) { if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) { @@ -3714,7 +3770,7 @@ PUGI__NS_BEGIN public: xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding)) { - PUGI__STATIC_ASSERT(bufcapacity >= 8); + PUGI_IMPL_STATIC_ASSERT(bufcapacity >= 8); } size_t flush() @@ -3920,14 +3976,14 @@ PUGI__NS_BEGIN xml_encoding encoding; }; - PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) + PUGI_IMPL_FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) { while (*s) { const char_t* prev = s; // While *s is a usual symbol - PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); + PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPEX(ss, type)); writer.write_buffer(prev, static_cast(s - prev)); @@ -3972,7 +4028,7 @@ PUGI__NS_BEGIN } } - PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) + PUGI_IMPL_FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) { if (flags & format_no_escapes) writer.write_string(s); @@ -3980,7 +4036,7 @@ PUGI__NS_BEGIN text_output_escaped(writer, s, type, flags); } - PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) + PUGI_IMPL_FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) { do { @@ -4002,7 +4058,7 @@ PUGI__NS_BEGIN while (*s); } - PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth) + PUGI_IMPL_FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth) { switch (indent_length) { @@ -4042,7 +4098,7 @@ PUGI__NS_BEGIN } } - PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s) + PUGI_IMPL_FN void node_output_comment(xml_buffered_writer& writer, const char_t* s) { writer.write('<', '!', '-', '-'); @@ -4067,7 +4123,7 @@ PUGI__NS_BEGIN writer.write('-', '-', '>'); } - PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s) + PUGI_IMPL_FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s) { while (*s) { @@ -4088,7 +4144,7 @@ PUGI__NS_BEGIN } } - PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) + PUGI_IMPL_FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t enquotation_char = (flags & format_attribute_single_quote) ? '\'' : '"'; @@ -4116,7 +4172,7 @@ PUGI__NS_BEGIN } } - PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) + PUGI_IMPL_FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t* name = node->name ? node->name + 0 : default_name; @@ -4178,7 +4234,7 @@ PUGI__NS_BEGIN } } - PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) + PUGI_IMPL_FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); const char_t* name = node->name ? node->name + 0 : default_name; @@ -4188,11 +4244,11 @@ PUGI__NS_BEGIN writer.write('>'); } - PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) + PUGI_IMPL_FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) { const char_t* default_name = PUGIXML_TEXT(":anonymous"); - switch (PUGI__NODETYPE(node)) + switch (PUGI_IMPL_NODETYPE(node)) { case node_pcdata: text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags); @@ -4250,7 +4306,7 @@ PUGI__NS_BEGIN indent_indent = 2 }; - PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth) + PUGI_IMPL_FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth) { size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0; unsigned int indent_flags = indent_indent; @@ -4262,7 +4318,7 @@ PUGI__NS_BEGIN assert(node); // begin writing current node - if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata) + if (PUGI_IMPL_NODETYPE(node) == node_pcdata || PUGI_IMPL_NODETYPE(node) == node_cdata) { node_output_simple(writer, node, flags); @@ -4276,7 +4332,7 @@ PUGI__NS_BEGIN if ((indent_flags & indent_indent) && indent_length) text_output_indent(writer, indent, indent_length, depth); - if (PUGI__NODETYPE(node) == node_element) + if (PUGI_IMPL_NODETYPE(node) == node_element) { indent_flags = indent_newline | indent_indent; @@ -4291,7 +4347,7 @@ PUGI__NS_BEGIN continue; } } - else if (PUGI__NODETYPE(node) == node_document) + else if (PUGI_IMPL_NODETYPE(node) == node_document) { indent_flags = indent_indent; @@ -4321,7 +4377,7 @@ PUGI__NS_BEGIN node = node->parent; // write closing node - if (PUGI__NODETYPE(node) == node_element) + if (PUGI_IMPL_NODETYPE(node) == node_element) { depth--; @@ -4343,11 +4399,11 @@ PUGI__NS_BEGIN writer.write('\n'); } - PUGI__FN bool has_declaration(xml_node_struct* node) + PUGI_IMPL_FN bool has_declaration(xml_node_struct* node) { for (xml_node_struct* child = node->first_child; child; child = child->next_sibling) { - xml_node_type type = PUGI__NODETYPE(child); + xml_node_type type = PUGI_IMPL_NODETYPE(child); if (type == node_declaration) return true; if (type == node_element) return false; @@ -4356,7 +4412,7 @@ PUGI__NS_BEGIN return false; } - PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node) + PUGI_IMPL_FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node) { for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) if (a == attr) @@ -4365,12 +4421,12 @@ PUGI__NS_BEGIN return false; } - PUGI__FN bool allow_insert_attribute(xml_node_type parent) + PUGI_IMPL_FN bool allow_insert_attribute(xml_node_type parent) { return parent == node_element || parent == node_declaration; } - PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child) + PUGI_IMPL_FN bool allow_insert_child(xml_node_type parent, xml_node_type child) { if (parent != node_document && parent != node_element) return false; if (child == node_document || child == node_null) return false; @@ -4379,7 +4435,7 @@ PUGI__NS_BEGIN return true; } - PUGI__FN bool allow_move(xml_node parent, xml_node child) + PUGI_IMPL_FN bool allow_move(xml_node parent, xml_node child) { // check that child can be a child of parent if (!allow_insert_child(parent.type(), child.type())) @@ -4404,9 +4460,9 @@ PUGI__NS_BEGIN } template - PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) + PUGI_IMPL_FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) { - assert(!dest && (header & header_mask) == 0); + assert(!dest && (header & header_mask) == 0); // copies are performed into fresh nodes if (source) { @@ -4423,7 +4479,7 @@ PUGI__NS_BEGIN } } - PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) + PUGI_IMPL_FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) { node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); @@ -4440,10 +4496,10 @@ PUGI__NS_BEGIN } } - PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn) + PUGI_IMPL_FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn) { xml_allocator& alloc = get_allocator(dn); - xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0; + xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : nullptr; node_copy_contents(dn, sn, shared_alloc); @@ -4458,7 +4514,7 @@ PUGI__NS_BEGIN // when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop if (sit != dn) { - xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit)); + xml_node_struct* copy = append_new_node(dit, alloc, PUGI_IMPL_NODETYPE(sit)); if (copy) { @@ -4494,10 +4550,10 @@ PUGI__NS_BEGIN assert(!sit || dit == dn->parent); } - PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa) + PUGI_IMPL_FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa) { xml_allocator& alloc = get_allocator(da); - xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0; + xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : nullptr; node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); @@ -4505,18 +4561,18 @@ PUGI__NS_BEGIN inline bool is_text_node(xml_node_struct* node) { - xml_node_type type = PUGI__NODETYPE(node); + xml_node_type type = PUGI_IMPL_NODETYPE(node); return type == node_pcdata || type == node_cdata; } // get value with conversion functions - template PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv) + template PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv) { U result = 0; const char_t* s = value; - while (PUGI__IS_CHARTYPE(*s, ct_space)) + while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) s++; bool negative = (*s == '-'); @@ -4571,7 +4627,7 @@ PUGI__NS_BEGIN size_t digits = static_cast(s - start); - PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2); + PUGI_IMPL_STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2); const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5; const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6'; @@ -4593,35 +4649,35 @@ PUGI__NS_BEGIN return (overflow || result > maxv) ? maxv : result; } - PUGI__FN int get_value_int(const char_t* value) + PUGI_IMPL_FN int get_value_int(const char_t* value) { return string_to_integer(value, static_cast(INT_MIN), INT_MAX); } - PUGI__FN unsigned int get_value_uint(const char_t* value) + PUGI_IMPL_FN unsigned int get_value_uint(const char_t* value) { return string_to_integer(value, 0, UINT_MAX); } - PUGI__FN double get_value_double(const char_t* value) + PUGI_IMPL_FN double get_value_double(const char_t* value) { #ifdef PUGIXML_WCHAR_MODE - return wcstod(value, 0); + return wcstod(value, nullptr); #else - return strtod(value, 0); + return strtod(value, nullptr); #endif } - PUGI__FN float get_value_float(const char_t* value) + PUGI_IMPL_FN float get_value_float(const char_t* value) { #ifdef PUGIXML_WCHAR_MODE - return static_cast(wcstod(value, 0)); + return static_cast(wcstod(value, nullptr)); #else - return static_cast(strtod(value, 0)); + return static_cast(strtod(value, nullptr)); #endif } - PUGI__FN bool get_value_bool(const char_t* value) + PUGI_IMPL_FN bool get_value_bool(const char_t* value) { // only look at first char char_t first = *value; @@ -4631,18 +4687,18 @@ PUGI__NS_BEGIN } #ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN long long get_value_llong(const char_t* value) + PUGI_IMPL_FN long long get_value_llong(const char_t* value) { return string_to_integer(value, static_cast(LLONG_MIN), LLONG_MAX); } - PUGI__FN unsigned long long get_value_ullong(const char_t* value) + PUGI_IMPL_FN unsigned long long get_value_ullong(const char_t* value) { return string_to_integer(value, 0, ULLONG_MAX); } #endif - template PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) + template PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) { char_t* result = end - 1; U rest = negative ? 0 - value : value; @@ -4664,7 +4720,7 @@ PUGI__NS_BEGIN // set value with conversion functions template - PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf) + PUGI_IMPL_FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf) { #ifdef PUGIXML_WCHAR_MODE char_t wbuf[128]; @@ -4680,7 +4736,7 @@ PUGI__NS_BEGIN } template - PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) + PUGI_IMPL_FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) { char_t buf[64]; char_t* end = buf + sizeof(buf) / sizeof(buf[0]); @@ -4690,30 +4746,30 @@ PUGI__NS_BEGIN } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision) + PUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision) { char buf[128]; - PUGI__SNPRINTF(buf, "%.*g", precision, double(value)); + PUGI_IMPL_SNPRINTF(buf, "%.*g", precision, double(value)); return set_value_ascii(dest, header, header_mask, buf); } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision) + PUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision) { char buf[128]; - PUGI__SNPRINTF(buf, "%.*g", precision, value); + PUGI_IMPL_SNPRINTF(buf, "%.*g", precision, value); return set_value_ascii(dest, header, header_mask, buf); } template - PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) + PUGI_IMPL_FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) { return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); } - PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) + PUGI_IMPL_FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) { // check input buffer if (!contents && size) return make_parse_result(status_io_error); @@ -4722,10 +4778,10 @@ PUGI__NS_BEGIN xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); // if convert_buffer below throws bad_alloc, we still need to deallocate contents if we own it - auto_deleter contents_guard(own ? contents : 0, xml_memory::deallocate); + auto_deleter contents_guard(own ? contents : nullptr, xml_memory::deallocate); // get private buffer - char_t* buffer = 0; + char_t* buffer = nullptr; size_t length = 0; // coverity[var_deref_model] @@ -4752,48 +4808,60 @@ PUGI__NS_BEGIN return res; } + template PUGI_IMPL_FN xml_parse_status convert_file_size(T length, size_t& out_result) + { + // check for I/O errors + if (length < 0) return status_io_error; + + // check for overflow + size_t result = static_cast(length); + + if (static_cast(result) != length) return status_out_of_memory; + + out_result = result; + return status_ok; + } + // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick - PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) + PUGI_IMPL_FN xml_parse_status get_file_size(FILE* file, size_t& out_result) { - #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 - // there are 64-bit versions of fseek/ftell, let's use them - typedef __int64 length_type; + #if defined(__linux__) || defined(__APPLE__) + // this simultaneously retrieves the file size and file mode (to guard against loading non-files) + struct stat st; + if (fstat(fileno(file), &st) != 0) return status_io_error; + // anything that's not a regular file doesn't have a coherent length + if (!S_ISREG(st.st_mode)) return status_io_error; + + xml_parse_status status = convert_file_size(st.st_size, out_result); + #elif defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 + // there are 64-bit versions of fseek/ftell, let's use them _fseeki64(file, 0, SEEK_END); - length_type length = _ftelli64(file); + __int64 length = _ftelli64(file); _fseeki64(file, 0, SEEK_SET); + + xml_parse_status status = convert_file_size(length, out_result); #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)) // there are 64-bit versions of fseek/ftell, let's use them - typedef off64_t length_type; - fseeko64(file, 0, SEEK_END); - length_type length = ftello64(file); + off64_t length = ftello64(file); fseeko64(file, 0, SEEK_SET); + + xml_parse_status status = convert_file_size(length, out_result); #else // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. - typedef long length_type; - fseek(file, 0, SEEK_END); - length_type length = ftell(file); + long length = ftell(file); fseek(file, 0, SEEK_SET); - #endif - - // check for I/O errors - if (length < 0) return status_io_error; - - // check for overflow - size_t result = static_cast(length); - - if (static_cast(result) != length) return status_out_of_memory; - // finalize - out_result = result; + xml_parse_status status = convert_file_size(length, out_result); + #endif - return status_ok; + return status; } // This function assumes that buffer has extra sizeof(char_t) writable bytes after size - PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) + PUGI_IMPL_FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) { // We only need to zero-terminate if encoding conversion does not do it for us #ifdef PUGIXML_WCHAR_MODE @@ -4817,7 +4885,7 @@ PUGI__NS_BEGIN return size; } - PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer) + PUGI_IMPL_FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer) { if (!file) return make_parse_result(status_file_not_found); @@ -4846,7 +4914,7 @@ PUGI__NS_BEGIN return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer); } - PUGI__FN void close_file(FILE* file) + PUGI_IMPL_FN void close_file(FILE* file) { fclose(file); } @@ -4857,7 +4925,7 @@ PUGI__NS_BEGIN static xml_stream_chunk* create() { void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); - if (!memory) return 0; + if (!memory) return nullptr; return new (memory) xml_stream_chunk(); } @@ -4875,7 +4943,7 @@ PUGI__NS_BEGIN } } - xml_stream_chunk(): next(0), size(0) + xml_stream_chunk(): next(nullptr), size(0) { } @@ -4885,13 +4953,13 @@ PUGI__NS_BEGIN T data[xml_memory_page_size / sizeof(T)]; }; - template PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream& stream, void** out_buffer, size_t* out_size) + template PUGI_IMPL_FN xml_parse_status load_stream_data_noseek(std::basic_istream& stream, void** out_buffer, size_t* out_size) { - auto_deleter > chunks(0, xml_stream_chunk::destroy); + auto_deleter > chunks(nullptr, xml_stream_chunk::destroy); // read file to a chunk list size_t total = 0; - xml_stream_chunk* last = 0; + xml_stream_chunk* last = nullptr; while (!stream.eof()) { @@ -4939,7 +5007,7 @@ PUGI__NS_BEGIN return status_ok; } - template PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream& stream, void** out_buffer, size_t* out_size) + template PUGI_IMPL_FN xml_parse_status load_stream_data_seek(std::basic_istream& stream, void** out_buffer, size_t* out_size) { // get length of remaining data in stream typename std::basic_istream::pos_type pos = stream.tellg(); @@ -4975,9 +5043,9 @@ PUGI__NS_BEGIN return status_ok; } - template PUGI__FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer) + template PUGI_IMPL_FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer) { - void* buffer = 0; + void* buffer = nullptr; size_t size = 0; xml_parse_status status = status_ok; @@ -5001,18 +5069,26 @@ PUGI__NS_BEGIN } #endif -#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) - PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) +#if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) + PUGI_IMPL_FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { -#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 - FILE* file = 0; - return _wfopen_s(&file, path, mode) == 0 ? file : 0; +#ifdef PUGIXML_NO_STL + // ensure these symbols are consistently referenced to avoid 'unreferenced function' warnings + // note that generally these functions are used in STL builds, but PUGIXML_NO_STL leaves the only usage in convert_path_heap + (void)&as_utf8_begin; + (void)&as_utf8_end; + (void)&strlength_wide; +#endif + +#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 + FILE* file = nullptr; + return _wfopen_s(&file, path, mode) == 0 ? file : nullptr; #else return _wfopen(path, mode); #endif } #else - PUGI__FN char* convert_path_heap(const wchar_t* str) + PUGI_IMPL_FN char* convert_path_heap(const wchar_t* str) { assert(str); @@ -5022,7 +5098,7 @@ PUGI__NS_BEGIN // allocate resulting string char* result = static_cast(xml_memory::allocate(size + 1)); - if (!result) return 0; + if (!result) return nullptr; // second pass: convert to utf8 as_utf8_end(result, size, str, length); @@ -5033,11 +5109,11 @@ PUGI__NS_BEGIN return result; } - PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + PUGI_IMPL_FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) { // there is no standard function to open wide paths, so our best bet is to try utf8 path char* path_utf8 = convert_path_heap(path); - if (!path_utf8) return 0; + if (!path_utf8) return nullptr; // convert mode to ASCII (we mirror _wfopen interface) char mode_ascii[4] = {0}; @@ -5053,17 +5129,17 @@ PUGI__NS_BEGIN } #endif - PUGI__FN FILE* open_file(const char* path, const char* mode) + PUGI_IMPL_FN FILE* open_file(const char* path, const char* mode) { -#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 - FILE* file = 0; - return fopen_s(&file, path, mode) == 0 ? file : 0; +#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 + FILE* file = nullptr; + return fopen_s(&file, path, mode) == 0 ? file : nullptr; #else return fopen(path, mode); #endif } - PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) + PUGI_IMPL_FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) { if (!file) return false; @@ -5080,7 +5156,7 @@ PUGI__NS_BEGIN name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name) { - node->name = 0; + node->name = nullptr; } ~name_null_sentry() @@ -5088,30 +5164,34 @@ PUGI__NS_BEGIN node->name = name; } }; -PUGI__NS_END +PUGI_IMPL_NS_END namespace pugi { - PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_) + PUGI_IMPL_FN xml_writer::~xml_writer() { } - PUGI__FN void xml_writer_file::write(const void* data, size_t size) + PUGI_IMPL_FN xml_writer_file::xml_writer_file(void* file_): file(file_) + { + } + + PUGI_IMPL_FN void xml_writer_file::write(const void* data, size_t size) { size_t result = fwrite(data, 1, size, static_cast(file)); (void)!result; // unfortunately we can't do proper error handling here } #ifndef PUGIXML_NO_STL - PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(&stream), wide_stream(0) + PUGI_IMPL_FN xml_writer_stream::xml_writer_stream(std::basic_ostream& stream): narrow_stream(&stream), wide_stream(nullptr) { } - PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(0), wide_stream(&stream) + PUGI_IMPL_FN xml_writer_stream::xml_writer_stream(std::basic_ostream& stream): narrow_stream(nullptr), wide_stream(&stream) { } - PUGI__FN void xml_writer_stream::write(const void* data, size_t size) + PUGI_IMPL_FN void xml_writer_stream::write(const void* data, size_t size) { if (narrow_stream) { @@ -5128,130 +5208,130 @@ namespace pugi } #endif - PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) + PUGI_IMPL_FN xml_tree_walker::xml_tree_walker(): _depth(0) { } - PUGI__FN xml_tree_walker::~xml_tree_walker() + PUGI_IMPL_FN xml_tree_walker::~xml_tree_walker() { } - PUGI__FN int xml_tree_walker::depth() const + PUGI_IMPL_FN int xml_tree_walker::depth() const { return _depth; } - PUGI__FN bool xml_tree_walker::begin(xml_node&) + PUGI_IMPL_FN bool xml_tree_walker::begin(xml_node&) { return true; } - PUGI__FN bool xml_tree_walker::end(xml_node&) + PUGI_IMPL_FN bool xml_tree_walker::end(xml_node&) { return true; } - PUGI__FN xml_attribute::xml_attribute(): _attr(0) + PUGI_IMPL_FN xml_attribute::xml_attribute(): _attr(nullptr) { } - PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) + PUGI_IMPL_FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) { } - PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***) + PUGI_IMPL_FN static void unspecified_bool_xml_attribute(xml_attribute***) { } - PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const + PUGI_IMPL_FN xml_attribute::operator xml_attribute::unspecified_bool_type() const { - return _attr ? unspecified_bool_xml_attribute : 0; + return _attr ? unspecified_bool_xml_attribute : nullptr; } - PUGI__FN bool xml_attribute::operator!() const + PUGI_IMPL_FN bool xml_attribute::operator!() const { return !_attr; } - PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const + PUGI_IMPL_FN bool xml_attribute::operator==(const xml_attribute& r) const { return (_attr == r._attr); } - PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const + PUGI_IMPL_FN bool xml_attribute::operator!=(const xml_attribute& r) const { return (_attr != r._attr); } - PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const + PUGI_IMPL_FN bool xml_attribute::operator<(const xml_attribute& r) const { return (_attr < r._attr); } - PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const + PUGI_IMPL_FN bool xml_attribute::operator>(const xml_attribute& r) const { return (_attr > r._attr); } - PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const + PUGI_IMPL_FN bool xml_attribute::operator<=(const xml_attribute& r) const { return (_attr <= r._attr); } - PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const + PUGI_IMPL_FN bool xml_attribute::operator>=(const xml_attribute& r) const { return (_attr >= r._attr); } - PUGI__FN xml_attribute xml_attribute::next_attribute() const + PUGI_IMPL_FN xml_attribute xml_attribute::next_attribute() const { if (!_attr) return xml_attribute(); return xml_attribute(_attr->next_attribute); } - PUGI__FN xml_attribute xml_attribute::previous_attribute() const + PUGI_IMPL_FN xml_attribute xml_attribute::previous_attribute() const { if (!_attr) return xml_attribute(); xml_attribute_struct* prev = _attr->prev_attribute_c; return prev->next_attribute ? xml_attribute(prev) : xml_attribute(); } - PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const + PUGI_IMPL_FN const char_t* xml_attribute::as_string(const char_t* def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? value : def; } - PUGI__FN int xml_attribute::as_int(int def) const + PUGI_IMPL_FN int xml_attribute::as_int(int def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_int(value) : def; } - PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const + PUGI_IMPL_FN unsigned int xml_attribute::as_uint(unsigned int def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_uint(value) : def; } - PUGI__FN double xml_attribute::as_double(double def) const + PUGI_IMPL_FN double xml_attribute::as_double(double def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_double(value) : def; } - PUGI__FN float xml_attribute::as_float(float def) const + PUGI_IMPL_FN float xml_attribute::as_float(float def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_float(value) : def; } - PUGI__FN bool xml_attribute::as_bool(bool def) const + PUGI_IMPL_FN bool xml_attribute::as_bool(bool def) const { if (!_attr) return def; const char_t* value = _attr->value; @@ -5259,14 +5339,14 @@ namespace pugi } #ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN long long xml_attribute::as_llong(long long def) const + PUGI_IMPL_FN long long xml_attribute::as_llong(long long def) const { if (!_attr) return def; const char_t* value = _attr->value; return value ? impl::get_value_llong(value) : def; } - PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const + PUGI_IMPL_FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const { if (!_attr) return def; const char_t* value = _attr->value; @@ -5274,175 +5354,208 @@ namespace pugi } #endif - PUGI__FN bool xml_attribute::empty() const + PUGI_IMPL_FN bool xml_attribute::empty() const { return !_attr; } - PUGI__FN const char_t* xml_attribute::name() const + PUGI_IMPL_FN const char_t* xml_attribute::name() const { if (!_attr) return PUGIXML_TEXT(""); const char_t* name = _attr->name; return name ? name : PUGIXML_TEXT(""); } - PUGI__FN const char_t* xml_attribute::value() const + PUGI_IMPL_FN const char_t* xml_attribute::value() const { if (!_attr) return PUGIXML_TEXT(""); const char_t* value = _attr->value; return value ? value : PUGIXML_TEXT(""); } - PUGI__FN size_t xml_attribute::hash_value() const + PUGI_IMPL_FN size_t xml_attribute::hash_value() const { - return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); + return reinterpret_cast(_attr) / sizeof(xml_attribute_struct); } - PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const + PUGI_IMPL_FN xml_attribute_struct* xml_attribute::internal_object() const { return _attr; } - PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(const char_t* rhs) { set_value(rhs); return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(int rhs) { set_value(rhs); return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned int rhs) { set_value(rhs); return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(long rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long rhs) { set_value(rhs); return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned long rhs) { set_value(rhs); return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(double rhs) { set_value(rhs); return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(float rhs) { set_value(rhs); return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(bool rhs) { set_value(rhs); return *this; } +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(string_view_t rhs) + { + set_value(rhs); + return *this; + } +#endif + #ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long long rhs) { set_value(rhs); return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs) + PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned long long rhs) { set_value(rhs); return *this; } #endif - PUGI__FN bool xml_attribute::set_name(const char_t* rhs) + PUGI_IMPL_FN bool xml_attribute::set_name(const char_t* rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } - PUGI__FN bool xml_attribute::set_value(const char_t* rhs, size_t sz) + PUGI_IMPL_FN bool xml_attribute::set_name(const char_t* rhs, size_t size) { if (!_attr) return false; - return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, sz); + return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, size); } - PUGI__FN bool xml_attribute::set_value(const char_t* rhs) +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN bool xml_attribute::set_name(string_view_t rhs) + { + if (!_attr) return false; + + return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.size()); + } +#endif + + PUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs) { if (!_attr) return false; return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); } - PUGI__FN bool xml_attribute::set_value(int rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs, size_t size) + { + if (!_attr) return false; + + return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, size); + } + +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN bool xml_attribute::set_value(string_view_t rhs) + { + if (!_attr) return false; + + return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size()); + } +#endif + + PUGI_IMPL_FN bool xml_attribute::set_value(int rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } - PUGI__FN bool xml_attribute::set_value(unsigned int rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(unsigned int rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } - PUGI__FN bool xml_attribute::set_value(long rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } - PUGI__FN bool xml_attribute::set_value(unsigned long rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(unsigned long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } - PUGI__FN bool xml_attribute::set_value(double rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(double rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision); } - PUGI__FN bool xml_attribute::set_value(double rhs, int precision) + PUGI_IMPL_FN bool xml_attribute::set_value(double rhs, int precision) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } - PUGI__FN bool xml_attribute::set_value(float rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(float rhs) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision); } - PUGI__FN bool xml_attribute::set_value(float rhs, int precision) + PUGI_IMPL_FN bool xml_attribute::set_value(float rhs, int precision) { if (!_attr) return false; return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } - PUGI__FN bool xml_attribute::set_value(bool rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(bool rhs) { if (!_attr) return false; @@ -5450,14 +5563,14 @@ namespace pugi } #ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN bool xml_attribute::set_value(long long rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(long long rhs) { if (!_attr) return false; return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } - PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) + PUGI_IMPL_FN bool xml_attribute::set_value(unsigned long long rhs) { if (!_attr) return false; @@ -5466,129 +5579,129 @@ namespace pugi #endif #ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) + PUGI_IMPL_FN bool operator&&(const xml_attribute& lhs, bool rhs) { return (bool)lhs && rhs; } - PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs) + PUGI_IMPL_FN bool operator||(const xml_attribute& lhs, bool rhs) { return (bool)lhs || rhs; } #endif - PUGI__FN xml_node::xml_node(): _root(0) + PUGI_IMPL_FN xml_node::xml_node(): _root(nullptr) { } - PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) + PUGI_IMPL_FN xml_node::xml_node(xml_node_struct* p): _root(p) { } - PUGI__FN static void unspecified_bool_xml_node(xml_node***) + PUGI_IMPL_FN static void unspecified_bool_xml_node(xml_node***) { } - PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const + PUGI_IMPL_FN xml_node::operator xml_node::unspecified_bool_type() const { - return _root ? unspecified_bool_xml_node : 0; + return _root ? unspecified_bool_xml_node : nullptr; } - PUGI__FN bool xml_node::operator!() const + PUGI_IMPL_FN bool xml_node::operator!() const { return !_root; } - PUGI__FN xml_node::iterator xml_node::begin() const + PUGI_IMPL_FN xml_node::iterator xml_node::begin() const { - return iterator(_root ? _root->first_child + 0 : 0, _root); + return iterator(_root ? _root->first_child + 0 : nullptr, _root); } - PUGI__FN xml_node::iterator xml_node::end() const + PUGI_IMPL_FN xml_node::iterator xml_node::end() const { - return iterator(0, _root); + return iterator(nullptr, _root); } - PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const + PUGI_IMPL_FN xml_node::attribute_iterator xml_node::attributes_begin() const { - return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root); + return attribute_iterator(_root ? _root->first_attribute + 0 : nullptr, _root); } - PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const + PUGI_IMPL_FN xml_node::attribute_iterator xml_node::attributes_end() const { - return attribute_iterator(0, _root); + return attribute_iterator(nullptr, _root); } - PUGI__FN xml_object_range xml_node::children() const + PUGI_IMPL_FN xml_object_range xml_node::children() const { return xml_object_range(begin(), end()); } - PUGI__FN xml_object_range xml_node::children(const char_t* name_) const + PUGI_IMPL_FN xml_object_range xml_node::children(const char_t* name_) const { - return xml_object_range(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_)); + return xml_object_range(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(nullptr, _root, name_)); } - PUGI__FN xml_object_range xml_node::attributes() const + PUGI_IMPL_FN xml_object_range xml_node::attributes() const { return xml_object_range(attributes_begin(), attributes_end()); } - PUGI__FN bool xml_node::operator==(const xml_node& r) const + PUGI_IMPL_FN bool xml_node::operator==(const xml_node& r) const { return (_root == r._root); } - PUGI__FN bool xml_node::operator!=(const xml_node& r) const + PUGI_IMPL_FN bool xml_node::operator!=(const xml_node& r) const { return (_root != r._root); } - PUGI__FN bool xml_node::operator<(const xml_node& r) const + PUGI_IMPL_FN bool xml_node::operator<(const xml_node& r) const { return (_root < r._root); } - PUGI__FN bool xml_node::operator>(const xml_node& r) const + PUGI_IMPL_FN bool xml_node::operator>(const xml_node& r) const { return (_root > r._root); } - PUGI__FN bool xml_node::operator<=(const xml_node& r) const + PUGI_IMPL_FN bool xml_node::operator<=(const xml_node& r) const { return (_root <= r._root); } - PUGI__FN bool xml_node::operator>=(const xml_node& r) const + PUGI_IMPL_FN bool xml_node::operator>=(const xml_node& r) const { return (_root >= r._root); } - PUGI__FN bool xml_node::empty() const + PUGI_IMPL_FN bool xml_node::empty() const { return !_root; } - PUGI__FN const char_t* xml_node::name() const + PUGI_IMPL_FN const char_t* xml_node::name() const { if (!_root) return PUGIXML_TEXT(""); const char_t* name = _root->name; return name ? name : PUGIXML_TEXT(""); } - PUGI__FN xml_node_type xml_node::type() const + PUGI_IMPL_FN xml_node_type xml_node::type() const { - return _root ? PUGI__NODETYPE(_root) : node_null; + return _root ? PUGI_IMPL_NODETYPE(_root) : node_null; } - PUGI__FN const char_t* xml_node::value() const + PUGI_IMPL_FN const char_t* xml_node::value() const { if (!_root) return PUGIXML_TEXT(""); const char_t* value = _root->value; return value ? value : PUGIXML_TEXT(""); } - PUGI__FN xml_node xml_node::child(const char_t* name_) const + PUGI_IMPL_FN xml_node xml_node::child(const char_t* name_) const { if (!_root) return xml_node(); @@ -5602,7 +5715,7 @@ namespace pugi return xml_node(); } - PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const + PUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_) const { if (!_root) return xml_attribute(); @@ -5616,7 +5729,7 @@ namespace pugi return xml_attribute(); } - PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const + PUGI_IMPL_FN xml_node xml_node::next_sibling(const char_t* name_) const { if (!_root) return xml_node(); @@ -5630,12 +5743,12 @@ namespace pugi return xml_node(); } - PUGI__FN xml_node xml_node::next_sibling() const + PUGI_IMPL_FN xml_node xml_node::next_sibling() const { return _root ? xml_node(_root->next_sibling) : xml_node(); } - PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const + PUGI_IMPL_FN xml_node xml_node::previous_sibling(const char_t* name_) const { if (!_root) return xml_node(); @@ -5649,7 +5762,65 @@ namespace pugi return xml_node(); } - PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN xml_node xml_node::child(string_view_t name_) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + { + const char_t* iname = i->name; + if (iname && impl::stringview_equal(name_, iname)) + return xml_node(i); + } + + return xml_node(); + } + + PUGI_IMPL_FN xml_attribute xml_node::attribute(string_view_t name_) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) + { + const char_t* iname = i->name; + if (iname && impl::stringview_equal(name_, iname)) + return xml_attribute(i); + } + + return xml_attribute(); + } + + PUGI_IMPL_FN xml_node xml_node::next_sibling(string_view_t name_) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) + { + const char_t* iname = i->name; + if (iname && impl::stringview_equal(name_, iname)) + return xml_node(i); + } + + return xml_node(); + } + + PUGI_IMPL_FN xml_node xml_node::previous_sibling(string_view_t name_) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) + { + const char_t* iname = i->name; + if (iname && impl::stringview_equal(name_, iname)) + return xml_node(i); + } + + return xml_node(); + } +#endif + + PUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const { xml_attribute_struct* hint = hint_._attr; @@ -5688,34 +5859,75 @@ namespace pugi return xml_attribute(); } - PUGI__FN xml_node xml_node::previous_sibling() const +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN xml_attribute xml_node::attribute(string_view_t name_, xml_attribute& hint_) const + { + xml_attribute_struct* hint = hint_._attr; + + // if hint is not an attribute of node, behavior is not defined + assert(!hint || (_root && impl::is_attribute_of(hint, _root))); + + if (!_root) return xml_attribute(); + + // optimistically search from hint up until the end + for (xml_attribute_struct* i = hint; i; i = i->next_attribute) + { + const char_t* iname = i->name; + if (iname && impl::stringview_equal(name_, iname)) + { + // update hint to maximize efficiency of searching for consecutive attributes + hint_._attr = i->next_attribute; + + return xml_attribute(i); + } + } + + // wrap around and search from the first attribute until the hint + // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails + for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) + { + const char_t* jname = j->name; + if (jname && impl::stringview_equal(name_, jname)) + { + // update hint to maximize efficiency of searching for consecutive attributes + hint_._attr = j->next_attribute; + + return xml_attribute(j); + } + } + + return xml_attribute(); + } +#endif + + PUGI_IMPL_FN xml_node xml_node::previous_sibling() const { if (!_root) return xml_node(); xml_node_struct* prev = _root->prev_sibling_c; return prev->next_sibling ? xml_node(prev) : xml_node(); } - PUGI__FN xml_node xml_node::parent() const + PUGI_IMPL_FN xml_node xml_node::parent() const { return _root ? xml_node(_root->parent) : xml_node(); } - PUGI__FN xml_node xml_node::root() const + PUGI_IMPL_FN xml_node xml_node::root() const { return _root ? xml_node(&impl::get_document(_root)) : xml_node(); } - PUGI__FN xml_text xml_node::text() const + PUGI_IMPL_FN xml_text xml_node::text() const { return xml_text(_root); } - PUGI__FN const char_t* xml_node::child_value() const + PUGI_IMPL_FN const char_t* xml_node::child_value() const { if (!_root) return PUGIXML_TEXT(""); // element nodes can have value if parse_embed_pcdata was used - if (PUGI__NODETYPE(_root) == node_element && _root->value) + if (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value) return _root->value; for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) @@ -5728,40 +5940,40 @@ namespace pugi return PUGIXML_TEXT(""); } - PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const + PUGI_IMPL_FN const char_t* xml_node::child_value(const char_t* name_) const { return child(name_).child_value(); } - PUGI__FN xml_attribute xml_node::first_attribute() const + PUGI_IMPL_FN xml_attribute xml_node::first_attribute() const { if (!_root) return xml_attribute(); return xml_attribute(_root->first_attribute); } - PUGI__FN xml_attribute xml_node::last_attribute() const + PUGI_IMPL_FN xml_attribute xml_node::last_attribute() const { if (!_root) return xml_attribute(); xml_attribute_struct* first = _root->first_attribute; return first ? xml_attribute(first->prev_attribute_c) : xml_attribute(); } - PUGI__FN xml_node xml_node::first_child() const + PUGI_IMPL_FN xml_node xml_node::first_child() const { if (!_root) return xml_node(); return xml_node(_root->first_child); } - PUGI__FN xml_node xml_node::last_child() const + PUGI_IMPL_FN xml_node xml_node::last_child() const { if (!_root) return xml_node(); xml_node_struct* first = _root->first_child; return first ? xml_node(first->prev_sibling_c) : xml_node(); } - PUGI__FN bool xml_node::set_name(const char_t* rhs) + PUGI_IMPL_FN bool xml_node::set_name(const char_t* rhs) { - xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; + xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; @@ -5769,19 +5981,31 @@ namespace pugi return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } - PUGI__FN bool xml_node::set_value(const char_t* rhs, size_t sz) + PUGI_IMPL_FN bool xml_node::set_name(const char_t* rhs, size_t size) { - xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; + xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; - if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) + if (type_ != node_element && type_ != node_pi && type_ != node_declaration) + return false; + + return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, size); + } + +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN bool xml_node::set_name(string_view_t rhs) + { + xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; + + if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; - return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, sz); + return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.size()); } +#endif - PUGI__FN bool xml_node::set_value(const char_t* rhs) + PUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs) { - xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; + xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) return false; @@ -5789,7 +6013,100 @@ namespace pugi return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); } - PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) + PUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs, size_t size) + { + xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; + + if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) + return false; + + return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, size); + } + +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN bool xml_node::set_value(string_view_t rhs) + { + xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null; + + if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) + return false; + + return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size()); + } +#endif + + PUGI_IMPL_FN xml_attribute xml_node::append_attribute(const char_t* name_) + { + if (!impl::allow_insert_attribute(type())) return xml_attribute(); + + impl::xml_allocator& alloc = impl::get_allocator(_root); + if (!alloc.reserve()) return xml_attribute(); + + xml_attribute a(impl::allocate_attribute(alloc)); + if (!a) return xml_attribute(); + + impl::append_attribute(a._attr, _root); + + a.set_name(name_); + + return a; + } + + PUGI_IMPL_FN xml_attribute xml_node::prepend_attribute(const char_t* name_) + { + if (!impl::allow_insert_attribute(type())) return xml_attribute(); + + impl::xml_allocator& alloc = impl::get_allocator(_root); + if (!alloc.reserve()) return xml_attribute(); + + xml_attribute a(impl::allocate_attribute(alloc)); + if (!a) return xml_attribute(); + + impl::prepend_attribute(a._attr, _root); + + a.set_name(name_); + + return a; + } + + PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) + { + if (!impl::allow_insert_attribute(type())) return xml_attribute(); + if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); + + impl::xml_allocator& alloc = impl::get_allocator(_root); + if (!alloc.reserve()) return xml_attribute(); + + xml_attribute a(impl::allocate_attribute(alloc)); + if (!a) return xml_attribute(); + + impl::insert_attribute_after(a._attr, attr._attr, _root); + + a.set_name(name_); + + return a; + } + + PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) + { + if (!impl::allow_insert_attribute(type())) return xml_attribute(); + if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); + + impl::xml_allocator& alloc = impl::get_allocator(_root); + if (!alloc.reserve()) return xml_attribute(); + + xml_attribute a(impl::allocate_attribute(alloc)); + if (!a) return xml_attribute(); + + impl::insert_attribute_before(a._attr, attr._attr, _root); + + a.set_name(name_); + + return a; + } + +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN xml_attribute xml_node::append_attribute(string_view_t name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5806,7 +6123,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) + PUGI_IMPL_FN xml_attribute xml_node::prepend_attribute(string_view_t name_) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5823,7 +6140,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) + PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5841,7 +6158,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) + PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5858,8 +6175,9 @@ namespace pugi return a; } +#endif - PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto) + PUGI_IMPL_FN xml_attribute xml_node::append_copy(const xml_attribute& proto) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5876,7 +6194,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) + PUGI_IMPL_FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5893,7 +6211,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) + PUGI_IMPL_FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5911,7 +6229,7 @@ namespace pugi return a; } - PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) + PUGI_IMPL_FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) { if (!proto) return xml_attribute(); if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5929,7 +6247,7 @@ namespace pugi return a; } - PUGI__FN xml_node xml_node::append_child(xml_node_type type_) + PUGI_IMPL_FN xml_node xml_node::append_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); @@ -5946,7 +6264,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) + PUGI_IMPL_FN xml_node xml_node::prepend_child(xml_node_type type_) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); @@ -5963,7 +6281,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) + PUGI_IMPL_FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); @@ -5981,7 +6299,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) + PUGI_IMPL_FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) { if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); @@ -5999,7 +6317,44 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::append_child(const char_t* name_) + PUGI_IMPL_FN xml_node xml_node::append_child(const char_t* name_) + { + xml_node result = append_child(node_element); + + result.set_name(name_); + + return result; + } + + PUGI_IMPL_FN xml_node xml_node::prepend_child(const char_t* name_) + { + xml_node result = prepend_child(node_element); + + result.set_name(name_); + + return result; + } + + PUGI_IMPL_FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) + { + xml_node result = insert_child_after(node_element, node); + + result.set_name(name_); + + return result; + } + + PUGI_IMPL_FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) + { + xml_node result = insert_child_before(node_element, node); + + result.set_name(name_); + + return result; + } + +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN xml_node xml_node::append_child(string_view_t name_) { xml_node result = append_child(node_element); @@ -6008,7 +6363,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) + PUGI_IMPL_FN xml_node xml_node::prepend_child(string_view_t name_) { xml_node result = prepend_child(node_element); @@ -6017,7 +6372,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) + PUGI_IMPL_FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node) { xml_node result = insert_child_after(node_element, node); @@ -6026,7 +6381,7 @@ namespace pugi return result; } - PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) + PUGI_IMPL_FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node) { xml_node result = insert_child_before(node_element, node); @@ -6034,8 +6389,9 @@ namespace pugi return result; } +#endif - PUGI__FN xml_node xml_node::append_copy(const xml_node& proto) + PUGI_IMPL_FN xml_node xml_node::append_copy(const xml_node& proto) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); @@ -6052,7 +6408,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto) + PUGI_IMPL_FN xml_node xml_node::prepend_copy(const xml_node& proto) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); @@ -6069,7 +6425,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) + PUGI_IMPL_FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); @@ -6087,7 +6443,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) + PUGI_IMPL_FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) { xml_node_type type_ = proto.type(); if (!impl::allow_insert_child(type(), type_)) return xml_node(); @@ -6105,7 +6461,7 @@ namespace pugi return n; } - PUGI__FN xml_node xml_node::append_move(const xml_node& moved) + PUGI_IMPL_FN xml_node xml_node::append_move(const xml_node& moved) { if (!impl::allow_move(*this, moved)) return xml_node(); @@ -6121,7 +6477,7 @@ namespace pugi return moved; } - PUGI__FN xml_node xml_node::prepend_move(const xml_node& moved) + PUGI_IMPL_FN xml_node xml_node::prepend_move(const xml_node& moved) { if (!impl::allow_move(*this, moved)) return xml_node(); @@ -6137,7 +6493,7 @@ namespace pugi return moved; } - PUGI__FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node) + PUGI_IMPL_FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node) { if (!impl::allow_move(*this, moved)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); @@ -6155,7 +6511,7 @@ namespace pugi return moved; } - PUGI__FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node) + PUGI_IMPL_FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node) { if (!impl::allow_move(*this, moved)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); @@ -6173,12 +6529,19 @@ namespace pugi return moved; } - PUGI__FN bool xml_node::remove_attribute(const char_t* name_) + PUGI_IMPL_FN bool xml_node::remove_attribute(const char_t* name_) { return remove_attribute(attribute(name_)); } - PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a) +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN bool xml_node::remove_attribute(string_view_t name_) + { + return remove_attribute(attribute(name_)); + } +#endif + + PUGI_IMPL_FN bool xml_node::remove_attribute(const xml_attribute& a) { if (!_root || !a._attr) return false; if (!impl::is_attribute_of(a._attr, _root)) return false; @@ -6192,7 +6555,7 @@ namespace pugi return true; } - PUGI__FN bool xml_node::remove_attributes() + PUGI_IMPL_FN bool xml_node::remove_attributes() { if (!_root) return false; @@ -6208,17 +6571,24 @@ namespace pugi attr = next; } - _root->first_attribute = 0; + _root->first_attribute = nullptr; return true; } - PUGI__FN bool xml_node::remove_child(const char_t* name_) + PUGI_IMPL_FN bool xml_node::remove_child(const char_t* name_) + { + return remove_child(child(name_)); + } + +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN bool xml_node::remove_child(string_view_t name_) { return remove_child(child(name_)); } +#endif - PUGI__FN bool xml_node::remove_child(const xml_node& n) + PUGI_IMPL_FN bool xml_node::remove_child(const xml_node& n) { if (!_root || !n._root || n._root->parent != _root) return false; @@ -6231,7 +6601,7 @@ namespace pugi return true; } - PUGI__FN bool xml_node::remove_children() + PUGI_IMPL_FN bool xml_node::remove_children() { if (!_root) return false; @@ -6247,16 +6617,19 @@ namespace pugi cur = next; } - _root->first_child = 0; + _root->first_child = nullptr; return true; } - PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) + PUGI_IMPL_FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) { // append_buffer is only valid for elements/documents if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root); + // append buffer can not merge PCDATA into existing PCDATA nodes + if ((options & parse_merge_pcdata) != 0 && last_child().type() == node_pcdata) return impl::make_parse_result(status_append_invalid_root); + // get document node impl::xml_document_struct* doc = &impl::get_document(_root); @@ -6264,7 +6637,7 @@ namespace pugi doc->header |= impl::xml_memory_page_contents_shared_mask; // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) - impl::xml_memory_page* page = 0; + impl::xml_memory_page* page = nullptr; impl::xml_extra_buffer* extra = static_cast(doc->allocate_memory(sizeof(impl::xml_extra_buffer) + sizeof(void*), page)); (void)page; @@ -6277,7 +6650,7 @@ namespace pugi #endif // add extra buffer to the list - extra->buffer = 0; + extra->buffer = nullptr; extra->next = doc->extra_buffers; doc->extra_buffers = extra; @@ -6287,7 +6660,7 @@ namespace pugi return impl::load_buffer_impl(doc, _root, const_cast(contents), size, options, encoding, false, false, &extra->buffer); } - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const + PUGI_IMPL_FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); @@ -6312,7 +6685,7 @@ namespace pugi return xml_node(); } - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const + PUGI_IMPL_FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const { if (!_root) return xml_node(); @@ -6332,7 +6705,7 @@ namespace pugi } #ifndef PUGIXML_NO_STL - PUGI__FN string_t xml_node::path(char_t delimiter) const + PUGI_IMPL_FN string_t xml_node::path(char_t delimiter) const { if (!_root) return string_t(); @@ -6369,7 +6742,7 @@ namespace pugi } #endif - PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const + PUGI_IMPL_FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const { xml_node context = path_[0] == delimiter ? root() : *this; @@ -6410,14 +6783,14 @@ namespace pugi } } - PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) + PUGI_IMPL_FN bool xml_node::traverse(xml_tree_walker& walker) { walker._depth = -1; xml_node arg_begin(_root); if (!walker.begin(arg_begin)) return false; - xml_node_struct* cur = _root ? _root->first_child + 0 : 0; + xml_node_struct* cur = _root ? _root->first_child + 0 : nullptr; if (cur) { @@ -6457,17 +6830,17 @@ namespace pugi return walker.end(arg_end); } - PUGI__FN size_t xml_node::hash_value() const + PUGI_IMPL_FN size_t xml_node::hash_value() const { - return static_cast(reinterpret_cast(_root) / sizeof(xml_node_struct)); + return reinterpret_cast(_root) / sizeof(xml_node_struct); } - PUGI__FN xml_node_struct* xml_node::internal_object() const + PUGI_IMPL_FN xml_node_struct* xml_node::internal_object() const { return _root; } - PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + PUGI_IMPL_FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const { if (!_root) return; @@ -6479,14 +6852,14 @@ namespace pugi } #ifndef PUGIXML_NO_STL - PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + PUGI_IMPL_FN void xml_node::print(std::basic_ostream& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const { xml_writer_stream writer(stream); print(writer, indent, flags, encoding, depth); } - PUGI__FN void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const + PUGI_IMPL_FN void xml_node::print(std::basic_ostream& stream, const char_t* indent, unsigned int flags, unsigned int depth) const { xml_writer_stream writer(stream); @@ -6494,7 +6867,7 @@ namespace pugi } #endif - PUGI__FN ptrdiff_t xml_node::offset_debug() const + PUGI_IMPL_FN ptrdiff_t xml_node::offset_debug() const { if (!_root) return -1; @@ -6526,37 +6899,37 @@ namespace pugi } #ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_node& lhs, bool rhs) + PUGI_IMPL_FN bool operator&&(const xml_node& lhs, bool rhs) { return (bool)lhs && rhs; } - PUGI__FN bool operator||(const xml_node& lhs, bool rhs) + PUGI_IMPL_FN bool operator||(const xml_node& lhs, bool rhs) { return (bool)lhs || rhs; } #endif - PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root) + PUGI_IMPL_FN xml_text::xml_text(xml_node_struct* root): _root(root) { } - PUGI__FN xml_node_struct* xml_text::_data() const + PUGI_IMPL_FN xml_node_struct* xml_text::_data() const { if (!_root || impl::is_text_node(_root)) return _root; // element nodes can have value if parse_embed_pcdata was used - if (PUGI__NODETYPE(_root) == node_element && _root->value) + if (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value) return _root; for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) if (impl::is_text_node(node)) return node; - return 0; + return nullptr; } - PUGI__FN xml_node_struct* xml_text::_data_new() + PUGI_IMPL_FN xml_node_struct* xml_text::_data_new() { xml_node_struct* d = _data(); if (d) return d; @@ -6564,30 +6937,30 @@ namespace pugi return xml_node(_root).append_child(node_pcdata).internal_object(); } - PUGI__FN xml_text::xml_text(): _root(0) + PUGI_IMPL_FN xml_text::xml_text(): _root() { } - PUGI__FN static void unspecified_bool_xml_text(xml_text***) + PUGI_IMPL_FN static void unspecified_bool_xml_text(xml_text***) { } - PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const + PUGI_IMPL_FN xml_text::operator xml_text::unspecified_bool_type() const { - return _data() ? unspecified_bool_xml_text : 0; + return _data() ? unspecified_bool_xml_text : nullptr; } - PUGI__FN bool xml_text::operator!() const + PUGI_IMPL_FN bool xml_text::operator!() const { return !_data(); } - PUGI__FN bool xml_text::empty() const + PUGI_IMPL_FN bool xml_text::empty() const { - return _data() == 0; + return _data() == nullptr; } - PUGI__FN const char_t* xml_text::get() const + PUGI_IMPL_FN const char_t* xml_text::get() const { xml_node_struct* d = _data(); if (!d) return PUGIXML_TEXT(""); @@ -6595,7 +6968,7 @@ namespace pugi return value ? value : PUGIXML_TEXT(""); } - PUGI__FN const char_t* xml_text::as_string(const char_t* def) const + PUGI_IMPL_FN const char_t* xml_text::as_string(const char_t* def) const { xml_node_struct* d = _data(); if (!d) return def; @@ -6603,7 +6976,7 @@ namespace pugi return value ? value : def; } - PUGI__FN int xml_text::as_int(int def) const + PUGI_IMPL_FN int xml_text::as_int(int def) const { xml_node_struct* d = _data(); if (!d) return def; @@ -6611,7 +6984,7 @@ namespace pugi return value ? impl::get_value_int(value) : def; } - PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const + PUGI_IMPL_FN unsigned int xml_text::as_uint(unsigned int def) const { xml_node_struct* d = _data(); if (!d) return def; @@ -6619,7 +6992,7 @@ namespace pugi return value ? impl::get_value_uint(value) : def; } - PUGI__FN double xml_text::as_double(double def) const + PUGI_IMPL_FN double xml_text::as_double(double def) const { xml_node_struct* d = _data(); if (!d) return def; @@ -6627,7 +7000,7 @@ namespace pugi return value ? impl::get_value_double(value) : def; } - PUGI__FN float xml_text::as_float(float def) const + PUGI_IMPL_FN float xml_text::as_float(float def) const { xml_node_struct* d = _data(); if (!d) return def; @@ -6635,7 +7008,7 @@ namespace pugi return value ? impl::get_value_float(value) : def; } - PUGI__FN bool xml_text::as_bool(bool def) const + PUGI_IMPL_FN bool xml_text::as_bool(bool def) const { xml_node_struct* d = _data(); if (!d) return def; @@ -6644,7 +7017,7 @@ namespace pugi } #ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN long long xml_text::as_llong(long long def) const + PUGI_IMPL_FN long long xml_text::as_llong(long long def) const { xml_node_struct* d = _data(); if (!d) return def; @@ -6652,7 +7025,7 @@ namespace pugi return value ? impl::get_value_llong(value) : def; } - PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const + PUGI_IMPL_FN unsigned long long xml_text::as_ullong(unsigned long long def) const { xml_node_struct* d = _data(); if (!d) return def; @@ -6661,77 +7034,86 @@ namespace pugi } #endif - PUGI__FN bool xml_text::set(const char_t* rhs, size_t sz) + PUGI_IMPL_FN bool xml_text::set(const char_t* rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, sz) : false; + return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false; } - PUGI__FN bool xml_text::set(const char_t* rhs) + PUGI_IMPL_FN bool xml_text::set(const char_t* rhs, size_t size) { xml_node_struct* dn = _data_new(); - return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false; + return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, size) : false; + } + +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN bool xml_text::set(string_view_t rhs) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.size()) : false; } +#endif - PUGI__FN bool xml_text::set(int rhs) + PUGI_IMPL_FN bool xml_text::set(int rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } - PUGI__FN bool xml_text::set(unsigned int rhs) + PUGI_IMPL_FN bool xml_text::set(unsigned int rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } - PUGI__FN bool xml_text::set(long rhs) + PUGI_IMPL_FN bool xml_text::set(long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } - PUGI__FN bool xml_text::set(unsigned long rhs) + PUGI_IMPL_FN bool xml_text::set(unsigned long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } - PUGI__FN bool xml_text::set(float rhs) + PUGI_IMPL_FN bool xml_text::set(float rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false; } - PUGI__FN bool xml_text::set(float rhs, int precision) + PUGI_IMPL_FN bool xml_text::set(float rhs, int precision) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } - PUGI__FN bool xml_text::set(double rhs) + PUGI_IMPL_FN bool xml_text::set(double rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false; } - PUGI__FN bool xml_text::set(double rhs, int precision) + PUGI_IMPL_FN bool xml_text::set(double rhs, int precision) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } - PUGI__FN bool xml_text::set(bool rhs) + PUGI_IMPL_FN bool xml_text::set(bool rhs) { xml_node_struct* dn = _data_new(); @@ -6739,14 +7121,14 @@ namespace pugi } #ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN bool xml_text::set(long long rhs) + PUGI_IMPL_FN bool xml_text::set(long long rhs) { xml_node_struct* dn = _data_new(); return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } - PUGI__FN bool xml_text::set(unsigned long long rhs) + PUGI_IMPL_FN bool xml_text::set(unsigned long long rhs) { xml_node_struct* dn = _data_new(); @@ -6754,256 +7136,264 @@ namespace pugi } #endif - PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(const char_t* rhs) { set(rhs); return *this; } - PUGI__FN xml_text& xml_text::operator=(int rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(int rhs) { set(rhs); return *this; } - PUGI__FN xml_text& xml_text::operator=(unsigned int rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned int rhs) { set(rhs); return *this; } - PUGI__FN xml_text& xml_text::operator=(long rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(long rhs) { set(rhs); return *this; } - PUGI__FN xml_text& xml_text::operator=(unsigned long rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned long rhs) { set(rhs); return *this; } - PUGI__FN xml_text& xml_text::operator=(double rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(double rhs) { set(rhs); return *this; } - PUGI__FN xml_text& xml_text::operator=(float rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(float rhs) { set(rhs); return *this; } - PUGI__FN xml_text& xml_text::operator=(bool rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(bool rhs) { set(rhs); return *this; } +#ifdef PUGIXML_HAS_STRING_VIEW + PUGI_IMPL_FN xml_text& xml_text::operator=(string_view_t rhs) + { + set(rhs); + return *this; + } +#endif + #ifdef PUGIXML_HAS_LONG_LONG - PUGI__FN xml_text& xml_text::operator=(long long rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(long long rhs) { set(rhs); return *this; } - PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs) + PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned long long rhs) { set(rhs); return *this; } #endif - PUGI__FN xml_node xml_text::data() const + PUGI_IMPL_FN xml_node xml_text::data() const { return xml_node(_data()); } #ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xml_text& lhs, bool rhs) + PUGI_IMPL_FN bool operator&&(const xml_text& lhs, bool rhs) { return (bool)lhs && rhs; } - PUGI__FN bool operator||(const xml_text& lhs, bool rhs) + PUGI_IMPL_FN bool operator||(const xml_text& lhs, bool rhs) { return (bool)lhs || rhs; } #endif - PUGI__FN xml_node_iterator::xml_node_iterator() + PUGI_IMPL_FN xml_node_iterator::xml_node_iterator() { } - PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) + PUGI_IMPL_FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) { } - PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + PUGI_IMPL_FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) { } - PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const + PUGI_IMPL_FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } - PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const + PUGI_IMPL_FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; } - PUGI__FN xml_node& xml_node_iterator::operator*() const + PUGI_IMPL_FN xml_node& xml_node_iterator::operator*() const { assert(_wrap._root); return _wrap; } - PUGI__FN xml_node* xml_node_iterator::operator->() const + PUGI_IMPL_FN xml_node* xml_node_iterator::operator->() const { assert(_wrap._root); - return const_cast(&_wrap); // BCC5 workaround + return &_wrap; } - PUGI__FN xml_node_iterator& xml_node_iterator::operator++() + PUGI_IMPL_FN xml_node_iterator& xml_node_iterator::operator++() { assert(_wrap._root); _wrap._root = _wrap._root->next_sibling; return *this; } - PUGI__FN xml_node_iterator xml_node_iterator::operator++(int) + PUGI_IMPL_FN xml_node_iterator xml_node_iterator::operator++(int) { xml_node_iterator temp = *this; ++*this; return temp; } - PUGI__FN xml_node_iterator& xml_node_iterator::operator--() + PUGI_IMPL_FN xml_node_iterator& xml_node_iterator::operator--() { _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); return *this; } - PUGI__FN xml_node_iterator xml_node_iterator::operator--(int) + PUGI_IMPL_FN xml_node_iterator xml_node_iterator::operator--(int) { xml_node_iterator temp = *this; --*this; return temp; } - PUGI__FN xml_attribute_iterator::xml_attribute_iterator() + PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator() { } - PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) + PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) { } - PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) { } - PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const + PUGI_IMPL_FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const { return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; } - PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const + PUGI_IMPL_FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const { return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; } - PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const + PUGI_IMPL_FN xml_attribute& xml_attribute_iterator::operator*() const { assert(_wrap._attr); return _wrap; } - PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const + PUGI_IMPL_FN xml_attribute* xml_attribute_iterator::operator->() const { assert(_wrap._attr); - return const_cast(&_wrap); // BCC5 workaround + return &_wrap; } - PUGI__FN xml_attribute_iterator& xml_attribute_iterator::operator++() + PUGI_IMPL_FN xml_attribute_iterator& xml_attribute_iterator::operator++() { assert(_wrap._attr); _wrap._attr = _wrap._attr->next_attribute; return *this; } - PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int) + PUGI_IMPL_FN xml_attribute_iterator xml_attribute_iterator::operator++(int) { xml_attribute_iterator temp = *this; ++*this; return temp; } - PUGI__FN xml_attribute_iterator& xml_attribute_iterator::operator--() + PUGI_IMPL_FN xml_attribute_iterator& xml_attribute_iterator::operator--() { _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); return *this; } - PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int) + PUGI_IMPL_FN xml_attribute_iterator xml_attribute_iterator::operator--(int) { xml_attribute_iterator temp = *this; --*this; return temp; } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) + PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(): _name(nullptr) { } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) + PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) { } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) + PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) { } - PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const + PUGI_IMPL_FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const { return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; } - PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const + PUGI_IMPL_FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const { return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; } - PUGI__FN xml_node& xml_named_node_iterator::operator*() const + PUGI_IMPL_FN xml_node& xml_named_node_iterator::operator*() const { assert(_wrap._root); return _wrap; } - PUGI__FN xml_node* xml_named_node_iterator::operator->() const + PUGI_IMPL_FN xml_node* xml_named_node_iterator::operator->() const { assert(_wrap._root); - return const_cast(&_wrap); // BCC5 workaround + return &_wrap; } - PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator++() + PUGI_IMPL_FN xml_named_node_iterator& xml_named_node_iterator::operator++() { assert(_wrap._root); _wrap = _wrap.next_sibling(_name); return *this; } - PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int) + PUGI_IMPL_FN xml_named_node_iterator xml_named_node_iterator::operator++(int) { xml_named_node_iterator temp = *this; ++*this; return temp; } - PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator--() + PUGI_IMPL_FN xml_named_node_iterator& xml_named_node_iterator::operator--() { if (_wrap._root) _wrap = _wrap.previous_sibling(_name); @@ -7018,23 +7408,23 @@ namespace pugi return *this; } - PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(int) + PUGI_IMPL_FN xml_named_node_iterator xml_named_node_iterator::operator--(int) { xml_named_node_iterator temp = *this; --*this; return temp; } - PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) + PUGI_IMPL_FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) { } - PUGI__FN xml_parse_result::operator bool() const + PUGI_IMPL_FN xml_parse_result::operator bool() const { return status == status_ok; } - PUGI__FN const char* xml_parse_result::description() const + PUGI_IMPL_FN const char* xml_parse_result::description() const { switch (status) { @@ -7065,24 +7455,24 @@ namespace pugi } } - PUGI__FN xml_document::xml_document(): _buffer(0) + PUGI_IMPL_FN xml_document::xml_document(): _buffer(nullptr) { _create(); } - PUGI__FN xml_document::~xml_document() + PUGI_IMPL_FN xml_document::~xml_document() { _destroy(); } #ifdef PUGIXML_HAS_MOVE - PUGI__FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(0) + PUGI_IMPL_FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(nullptr) { _create(); _move(rhs); } - PUGI__FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT + PUGI_IMPL_FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT { if (this == &rhs) return *this; @@ -7094,20 +7484,20 @@ namespace pugi } #endif - PUGI__FN void xml_document::reset() + PUGI_IMPL_FN void xml_document::reset() { _destroy(); _create(); } - PUGI__FN void xml_document::reset(const xml_document& proto) + PUGI_IMPL_FN void xml_document::reset(const xml_document& proto) { reset(); impl::node_copy_tree(_root, proto._root); } - PUGI__FN void xml_document::_create() + PUGI_IMPL_FN void xml_document::_create() { assert(!_root); @@ -7119,7 +7509,7 @@ namespace pugi #endif // initialize sentinel page - PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory)); + PUGI_IMPL_STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory)); // prepare page structure impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory); @@ -7150,7 +7540,7 @@ namespace pugi assert(reinterpret_cast(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); } - PUGI__FN void xml_document::_destroy() + PUGI_IMPL_FN void xml_document::_destroy() { assert(_root); @@ -7158,7 +7548,7 @@ namespace pugi if (_buffer) { impl::xml_memory::deallocate(_buffer); - _buffer = 0; + _buffer = nullptr; } // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator) @@ -7168,7 +7558,7 @@ namespace pugi } // destroy dynamic storage, leave sentinel page (it's in static memory) - impl::xml_memory_page* root_page = PUGI__GETPAGE(_root); + impl::xml_memory_page* root_page = PUGI_IMPL_GETPAGE(_root); assert(root_page && !root_page->prev); assert(reinterpret_cast(root_page) >= _memory && reinterpret_cast(root_page) < _memory + sizeof(_memory)); @@ -7186,11 +7576,11 @@ namespace pugi static_cast(_root)->hash.clear(); #endif - _root = 0; + _root = nullptr; } #ifdef PUGIXML_HAS_MOVE - PUGI__FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT + PUGI_IMPL_FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT { impl::xml_document_struct* doc = static_cast(_root); impl::xml_document_struct* other = static_cast(rhs._root); @@ -7224,7 +7614,7 @@ namespace pugi // move allocation state // note that other->_root may point to the embedded document page, in which case we should keep original (empty) state - if (other->_root != PUGI__GETPAGE(other)) + if (other->_root != PUGI_IMPL_GETPAGE(other)) { doc->_root = other->_root; doc->_busy_size = other->_busy_size; @@ -7241,14 +7631,14 @@ namespace pugi doc->_hash = &doc->hash; // make sure we don't access other hash up until the end when we reinitialize other document - other->_hash = 0; + other->_hash = nullptr; #endif // move page structure - impl::xml_memory_page* doc_page = PUGI__GETPAGE(doc); + impl::xml_memory_page* doc_page = PUGI_IMPL_GETPAGE(doc); assert(doc_page && !doc_page->prev && !doc_page->next); - impl::xml_memory_page* other_page = PUGI__GETPAGE(other); + impl::xml_memory_page* other_page = PUGI_IMPL_GETPAGE(other); assert(other_page && !other_page->prev); // relink pages since root page is embedded into xml_document @@ -7259,7 +7649,7 @@ namespace pugi page->prev = doc_page; doc_page->next = page; - other_page->next = 0; + other_page->next = nullptr; } // make sure pages point to the correct document state @@ -7295,20 +7685,20 @@ namespace pugi } // reset other document - new (other) impl::xml_document_struct(PUGI__GETPAGE(other)); - rhs._buffer = 0; + new (other) impl::xml_document_struct(PUGI_IMPL_GETPAGE(other)); + rhs._buffer = nullptr; } #endif #ifndef PUGIXML_NO_STL - PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) + PUGI_IMPL_FN xml_parse_result xml_document::load(std::basic_istream& stream, unsigned int options, xml_encoding encoding) { reset(); return impl::load_stream_impl(static_cast(_root), stream, options, encoding, &_buffer); } - PUGI__FN xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) + PUGI_IMPL_FN xml_parse_result xml_document::load(std::basic_istream& stream, unsigned int options) { reset(); @@ -7316,7 +7706,7 @@ namespace pugi } #endif - PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options) + PUGI_IMPL_FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options) { // Force native encoding (skip autodetection) #ifdef PUGIXML_WCHAR_MODE @@ -7328,12 +7718,12 @@ namespace pugi return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); } - PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) + PUGI_IMPL_FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) { return load_string(contents, options); } - PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) + PUGI_IMPL_FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) { reset(); @@ -7343,7 +7733,7 @@ namespace pugi return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } - PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) + PUGI_IMPL_FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) { reset(); @@ -7353,32 +7743,32 @@ namespace pugi return impl::load_file_impl(static_cast(_root), file.data, options, encoding, &_buffer); } - PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) + PUGI_IMPL_FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, const_cast(contents), size, options, encoding, false, false, &_buffer); } - PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) + PUGI_IMPL_FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, false, &_buffer); } - PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) + PUGI_IMPL_FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) { reset(); return impl::load_buffer_impl(static_cast(_root), _root, contents, size, options, encoding, true, true, &_buffer); } - PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const + PUGI_IMPL_FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const { impl::xml_buffered_writer buffered_writer(writer, encoding); - if ((flags & format_write_bom) && encoding != encoding_latin1) + if ((flags & format_write_bom) && buffered_writer.encoding != encoding_latin1) { // BOM always represents the codepoint U+FEFF, so just write it in native encoding #ifdef PUGIXML_WCHAR_MODE @@ -7392,7 +7782,7 @@ namespace pugi if (!(flags & format_no_declaration) && !impl::has_declaration(_root)) { buffered_writer.write_string(PUGIXML_TEXT("'); if (!(flags & format_raw)) buffered_writer.write('\n'); } @@ -7403,14 +7793,14 @@ namespace pugi } #ifndef PUGIXML_NO_STL - PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const + PUGI_IMPL_FN void xml_document::save(std::basic_ostream& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const { xml_writer_stream writer(stream); save(writer, indent, flags, encoding); } - PUGI__FN void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags) const + PUGI_IMPL_FN void xml_document::save(std::basic_ostream& stream, const char_t* indent, unsigned int flags) const { xml_writer_stream writer(stream); @@ -7418,7 +7808,7 @@ namespace pugi } #endif - PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const + PUGI_IMPL_FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file); @@ -7426,7 +7816,7 @@ namespace pugi return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0; } - PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const + PUGI_IMPL_FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const { using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file); @@ -7434,55 +7824,55 @@ namespace pugi return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0; } - PUGI__FN xml_node xml_document::document_element() const + PUGI_IMPL_FN xml_node xml_document::document_element() const { assert(_root); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (PUGI__NODETYPE(i) == node_element) + if (PUGI_IMPL_NODETYPE(i) == node_element) return xml_node(i); return xml_node(); } #ifndef PUGIXML_NO_STL - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) + PUGI_IMPL_FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) { assert(str); return impl::as_utf8_impl(str, impl::strlength_wide(str)); } - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) + PUGI_IMPL_FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) { return impl::as_utf8_impl(str.c_str(), str.size()); } - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) + PUGI_IMPL_FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) { assert(str); return impl::as_wide_impl(str, strlen(str)); } - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) + PUGI_IMPL_FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) { return impl::as_wide_impl(str.c_str(), str.size()); } #endif - PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) + PUGI_IMPL_FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) { impl::xml_memory::allocate = allocate; impl::xml_memory::deallocate = deallocate; } - PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() + PUGI_IMPL_FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() { return impl::xml_memory::allocate; } - PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() + PUGI_IMPL_FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() { return impl::xml_memory::deallocate; } @@ -7492,17 +7882,17 @@ namespace pugi namespace std { // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) - PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) + PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) { return std::bidirectional_iterator_tag(); } - PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) + PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) { return std::bidirectional_iterator_tag(); } - PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) + PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) { return std::bidirectional_iterator_tag(); } @@ -7513,17 +7903,17 @@ namespace std namespace std { // Workarounds for (non-standard) iterator category detection - PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) + PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) { return std::bidirectional_iterator_tag(); } - PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) + PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) { return std::bidirectional_iterator_tag(); } - PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) + PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) { return std::bidirectional_iterator_tag(); } @@ -7532,7 +7922,7 @@ namespace std #ifndef PUGIXML_NO_XPATH // STL replacements -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN struct equal_to { template bool operator()(const T& lhs, const T& rhs) const @@ -7572,7 +7962,7 @@ PUGI__NS_BEGIN rhs = temp; } - template PUGI__FN I min_element(I begin, I end, const Pred& pred) + template PUGI_IMPL_FN I min_element(I begin, I end, const Pred& pred) { I result = begin; @@ -7583,13 +7973,13 @@ PUGI__NS_BEGIN return result; } - template PUGI__FN void reverse(I begin, I end) + template PUGI_IMPL_FN void reverse(I begin, I end) { while (end - begin > 1) swap(*begin++, *--end); } - template PUGI__FN I unique(I begin, I end) + template PUGI_IMPL_FN I unique(I begin, I end) { // fast skip head while (end - begin > 1 && *begin != *(begin + 1)) @@ -7614,7 +8004,7 @@ PUGI__NS_BEGIN return write + 1; } - template PUGI__FN void insertion_sort(T* begin, T* end, const Pred& pred) + template PUGI_IMPL_FN void insertion_sort(T* begin, T* end, const Pred& pred) { if (begin == end) return; @@ -7648,7 +8038,7 @@ PUGI__NS_BEGIN return middle; } - template PUGI__FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend) + template PUGI_IMPL_FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend) { // invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups) T* eq = begin; @@ -7675,7 +8065,7 @@ PUGI__NS_BEGIN *out_eqend = gt; } - template PUGI__FN void sort(I begin, I end, const Pred& pred) + template PUGI_IMPL_FN void sort(I begin, I end, const Pred& pred) { // sort large chunks while (end - begin > 16) @@ -7705,7 +8095,7 @@ PUGI__NS_BEGIN insertion_sort(begin, end, pred); } - PUGI__FN bool hash_insert(const void** table, size_t size, const void* key) + PUGI_IMPL_FN bool hash_insert(const void** table, size_t size, const void* key) { assert(key); @@ -7723,7 +8113,7 @@ PUGI__NS_BEGIN for (size_t probe = 0; probe <= hashmod; ++probe) { - if (table[bucket] == 0) + if (table[bucket] == nullptr) { table[bucket] = key; return true; @@ -7739,10 +8129,10 @@ PUGI__NS_BEGIN assert(false && "Hash table is full"); // unreachable return false; } -PUGI__NS_END +PUGI_IMPL_NS_END // Allocator used for AST and evaluation stacks -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN static const size_t xpath_memory_page_size = #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE PUGIXML_MEMORY_XPATH_PAGE_SIZE @@ -7771,7 +8161,7 @@ PUGI__NS_BEGIN size_t _root_size; bool* _error; - xpath_allocator(xpath_memory_block* root, bool* error = 0): _root(root), _root_size(0), _error(error) + xpath_allocator(xpath_memory_block* root, bool* error = nullptr): _root(root), _root_size(0), _error(error) { } @@ -7799,7 +8189,7 @@ PUGI__NS_BEGIN if (!block) { if (_error) *_error = true; - return 0; + return nullptr; } block->next = _root; @@ -7819,7 +8209,7 @@ PUGI__NS_BEGIN new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); // we can only reallocate the last object - assert(ptr == 0 || static_cast(ptr) + old_size == &_root->data[0] + _root_size); + assert(ptr == nullptr || static_cast(ptr) + old_size == &_root->data[0] + _root_size); // try to reallocate the object inplace if (ptr && _root_size - old_size + new_size <= _root->capacity) @@ -7830,7 +8220,7 @@ PUGI__NS_BEGIN // allocate a new block void* result = allocate(new_size); - if (!result) return 0; + if (!result) return nullptr; // we have a new block if (ptr) @@ -7925,7 +8315,7 @@ PUGI__NS_BEGIN xpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false) { - blocks[0].next = blocks[1].next = 0; + blocks[0].next = blocks[1].next = nullptr; blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data); stack.result = &result; @@ -7938,10 +8328,10 @@ PUGI__NS_BEGIN temp.release(); } }; -PUGI__NS_END +PUGI_IMPL_NS_END // String class -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN class xpath_string { const char_t* _buffer; @@ -7951,7 +8341,7 @@ PUGI__NS_BEGIN static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) { char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); - if (!result) return 0; + if (!result) return nullptr; memcpy(result, string, length * sizeof(char_t)); result[length] = 0; @@ -8011,7 +8401,7 @@ PUGI__NS_BEGIN size_t result_length = target_length + source_length; // allocate new buffer - char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); + char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : nullptr, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t))); if (!result) return; // append first string to the new buffer in case there was no reallocation @@ -8046,7 +8436,7 @@ PUGI__NS_BEGIN size_t length_ = strlength(_buffer); const char_t* data_ = duplicate_string(_buffer, length_, alloc); - if (!data_) return 0; + if (!data_) return nullptr; _buffer = data_; _uses_heap = true; @@ -8076,10 +8466,10 @@ PUGI__NS_BEGIN return _uses_heap; } }; -PUGI__NS_END +PUGI_IMPL_NS_END -PUGI__NS_BEGIN - PUGI__FN bool starts_with(const char_t* string, const char_t* pattern) +PUGI_IMPL_NS_BEGIN + PUGI_IMPL_FN bool starts_with(const char_t* string, const char_t* pattern) { while (*pattern && *string == *pattern) { @@ -8090,7 +8480,7 @@ PUGI__NS_BEGIN return *pattern == 0; } - PUGI__FN const char_t* find_char(const char_t* s, char_t c) + PUGI_IMPL_FN const char_t* find_char(const char_t* s, char_t c) { #ifdef PUGIXML_WCHAR_MODE return wcschr(s, c); @@ -8099,7 +8489,7 @@ PUGI__NS_BEGIN #endif } - PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p) + PUGI_IMPL_FN const char_t* find_substring(const char_t* s, const char_t* p) { #ifdef PUGIXML_WCHAR_MODE // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) @@ -8110,12 +8500,12 @@ PUGI__NS_BEGIN } // Converts symbol to lower case, if it is an ASCII one - PUGI__FN char_t tolower_ascii(char_t ch) + PUGI_IMPL_FN char_t tolower_ascii(char_t ch) { return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; } - PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) + PUGI_IMPL_FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) { if (na.attribute()) return xpath_string::from_const(na.attribute().value()); @@ -8169,7 +8559,7 @@ PUGI__NS_BEGIN } } - PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) + PUGI_IMPL_FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) { assert(ln->parent == rn->parent); @@ -8193,7 +8583,7 @@ PUGI__NS_BEGIN return !rs; } - PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) + PUGI_IMPL_FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) { // find common ancestor at the same depth, if any xml_node_struct* lp = ln; @@ -8236,14 +8626,14 @@ PUGI__NS_BEGIN return node_is_before_sibling(ln, rn); } - PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node) + PUGI_IMPL_FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node) { while (node && node != parent) node = node->parent; return parent && node == parent; } - PUGI__FN const void* document_buffer_order(const xpath_node& xnode) + PUGI_IMPL_FN const void* document_buffer_order(const xpath_node& xnode) { xml_node_struct* node = xnode.node().internal_object(); @@ -8255,7 +8645,7 @@ PUGI__NS_BEGIN if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value; } - return 0; + return nullptr; } xml_attribute_struct* attr = xnode.attribute().internal_object(); @@ -8268,10 +8658,10 @@ PUGI__NS_BEGIN if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value; } - return 0; + return nullptr; } - return 0; + return nullptr; } struct document_order_comparator @@ -8328,10 +8718,10 @@ PUGI__NS_BEGIN } }; - PUGI__FN double gen_nan() + PUGI_IMPL_FN double gen_nan() { #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) - PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); + PUGI_IMPL_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); typedef uint32_t UI; // BCC5 workaround union { float f; UI i; } u; u.i = 0x7fc00000; @@ -8343,9 +8733,9 @@ PUGI__NS_BEGIN #endif } - PUGI__FN bool is_nan(double value) + PUGI_IMPL_FN bool is_nan(double value) { - #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) + #if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__) return !!_isnan(value); #elif defined(fpclassify) && defined(FP_NAN) return fpclassify(value) == FP_NAN; @@ -8356,9 +8746,9 @@ PUGI__NS_BEGIN #endif } - PUGI__FN const char_t* convert_number_to_string_special(double value) + PUGI_IMPL_FN const char_t* convert_number_to_string_special(double value) { - #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) + #if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__) if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; if (_isnan(value)) return PUGIXML_TEXT("NaN"); return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); @@ -8384,16 +8774,16 @@ PUGI__NS_BEGIN if (v == 0) return PUGIXML_TEXT("0"); if (v != v) return PUGIXML_TEXT("NaN"); if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); - return 0; + return nullptr; #endif } - PUGI__FN bool convert_number_to_boolean(double value) + PUGI_IMPL_FN bool convert_number_to_boolean(double value) { return (value != 0 && !is_nan(value)); } - PUGI__FN void truncate_zeros(char* begin, char* end) + PUGI_IMPL_FN void truncate_zeros(char* begin, char* end) { while (begin != end && end[-1] == '0') end--; @@ -8401,8 +8791,8 @@ PUGI__NS_BEGIN } // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent -#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 - PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) +#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400 + PUGI_IMPL_FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get base values int sign, exponent; @@ -8416,10 +8806,10 @@ PUGI__NS_BEGIN *out_exponent = exponent; } #else - PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) + PUGI_IMPL_FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent) { // get a scientific notation value with IEEE DBL_DIG decimals - PUGI__SNPRINTF(buffer, "%.*e", DBL_DIG, value); + PUGI_IMPL_SNPRINTF(buffer, "%.*e", DBL_DIG, value); // get the exponent (possibly negative) char* exponent_string = strchr(buffer, 'e'); @@ -8429,7 +8819,7 @@ PUGI__NS_BEGIN // extract mantissa string: skip sign char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; - assert(mantissa[0] != '0' && mantissa[1] == '.'); + assert(mantissa[0] != '0' && (mantissa[1] == '.' || mantissa[1] == ',')); // divide mantissa by 10 to eliminate integer part mantissa[1] = mantissa[0]; @@ -8445,7 +8835,7 @@ PUGI__NS_BEGIN } #endif - PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) + PUGI_IMPL_FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) { // try special number conversion const char_t* special = convert_number_to_string_special(value); @@ -8512,10 +8902,10 @@ PUGI__NS_BEGIN return xpath_string::from_heap_preallocated(result, s); } - PUGI__FN bool check_string_to_number_format(const char_t* string) + PUGI_IMPL_FN bool check_string_to_number_format(const char_t* string) { // parse leading whitespace - while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; + while (PUGI_IMPL_IS_CHARTYPE(*string, ct_space)) ++string; // parse sign if (*string == '-') ++string; @@ -8523,39 +8913,39 @@ PUGI__NS_BEGIN if (!*string) return false; // if there is no integer part, there should be a decimal part with at least one digit - if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false; + if (!PUGI_IMPL_IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI_IMPL_IS_CHARTYPEX(string[1], ctx_digit))) return false; // parse integer part - while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; + while (PUGI_IMPL_IS_CHARTYPEX(*string, ctx_digit)) ++string; // parse decimal part if (*string == '.') { ++string; - while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; + while (PUGI_IMPL_IS_CHARTYPEX(*string, ctx_digit)) ++string; } // parse trailing whitespace - while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; + while (PUGI_IMPL_IS_CHARTYPE(*string, ct_space)) ++string; return *string == 0; } - PUGI__FN double convert_string_to_number(const char_t* string) + PUGI_IMPL_FN double convert_string_to_number(const char_t* string) { // check string format if (!check_string_to_number_format(string)) return gen_nan(); // parse string #ifdef PUGIXML_WCHAR_MODE - return wcstod(string, 0); + return wcstod(string, nullptr); #else - return strtod(string, 0); + return strtod(string, nullptr); #endif } - PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result) + PUGI_IMPL_FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result) { size_t length = static_cast(end - begin); char_t* scratch = buffer; @@ -8579,24 +8969,24 @@ PUGI__NS_BEGIN return true; } - PUGI__FN double round_nearest(double value) + PUGI_IMPL_FN double round_nearest(double value) { return floor(value + 0.5); } - PUGI__FN double round_nearest_nzero(double value) + PUGI_IMPL_FN double round_nearest_nzero(double value) { // same as round_nearest, but returns -0 for [-0.5, -0] // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); } - PUGI__FN const char_t* qualified_name(const xpath_node& node) + PUGI_IMPL_FN const char_t* qualified_name(const xpath_node& node) { return node.attribute() ? node.attribute().name() : node.node().name(); } - PUGI__FN const char_t* local_name(const xpath_node& node) + PUGI_IMPL_FN const char_t* local_name(const xpath_node& node) { const char_t* name = qualified_name(node); const char_t* p = find_char(name, ':'); @@ -8613,7 +9003,7 @@ PUGI__NS_BEGIN { const char_t* pos = find_char(name, ':'); - prefix = pos ? name : 0; + prefix = pos ? name : nullptr; prefix_length = pos ? static_cast(pos - name) : 0; } @@ -8627,7 +9017,7 @@ PUGI__NS_BEGIN } }; - PUGI__FN const char_t* namespace_uri(xml_node node) + PUGI_IMPL_FN const char_t* namespace_uri(xml_node node) { namespace_uri_predicate pred = node.name(); @@ -8645,7 +9035,7 @@ PUGI__NS_BEGIN return PUGIXML_TEXT(""); } - PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) + PUGI_IMPL_FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) { namespace_uri_predicate pred = attr.name(); @@ -8666,12 +9056,12 @@ PUGI__NS_BEGIN return PUGIXML_TEXT(""); } - PUGI__FN const char_t* namespace_uri(const xpath_node& node) + PUGI_IMPL_FN const char_t* namespace_uri(const xpath_node& node) { return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); } - PUGI__FN char_t* normalize_space(char_t* buffer) + PUGI_IMPL_FN char_t* normalize_space(char_t* buffer) { char_t* write = buffer; @@ -8679,10 +9069,10 @@ PUGI__NS_BEGIN { char_t ch = *it++; - if (PUGI__IS_CHARTYPE(ch, ct_space)) + if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space)) { // replace whitespace sequence with single space - while (PUGI__IS_CHARTYPE(*it, ct_space)) it++; + while (PUGI_IMPL_IS_CHARTYPE(*it, ct_space)) it++; // avoid leading spaces if (write != buffer) *write++ = ' '; @@ -8691,7 +9081,7 @@ PUGI__NS_BEGIN } // remove trailing space - if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--; + if (write != buffer && PUGI_IMPL_IS_CHARTYPE(write[-1], ct_space)) write--; // zero-terminate *write = 0; @@ -8699,13 +9089,13 @@ PUGI__NS_BEGIN return write; } - PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length) + PUGI_IMPL_FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length) { char_t* write = buffer; while (*buffer) { - PUGI__DMC_VOLATILE char_t ch = *buffer++; + PUGI_IMPL_DMC_VOLATILE char_t ch = *buffer++; const char_t* pos = find_char(from, ch); @@ -8721,7 +9111,7 @@ PUGI__NS_BEGIN return write; } - PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to) + PUGI_IMPL_FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to) { unsigned char table[128] = {0}; @@ -8731,7 +9121,7 @@ PUGI__NS_BEGIN unsigned int tc = static_cast(*to); if (fc >= 128 || tc >= 128) - return 0; + return nullptr; // code=128 means "skip character" if (!table[fc]) @@ -8746,14 +9136,14 @@ PUGI__NS_BEGIN table[i] = static_cast(i); void* result = alloc->allocate(sizeof(table)); - if (!result) return 0; + if (!result) return nullptr; memcpy(result, table, sizeof(table)); return static_cast(result); } - PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table) + PUGI_IMPL_FN char_t* translate_table(char_t* buffer, const unsigned char* table) { char_t* write = buffer; @@ -8810,7 +9200,7 @@ PUGI__NS_BEGIN struct xpath_variable_string: xpath_variable { - xpath_variable_string(): xpath_variable(xpath_type_string), value(0) + xpath_variable_string(): xpath_variable(xpath_type_string), value(nullptr) { } @@ -8835,7 +9225,7 @@ PUGI__NS_BEGIN static const xpath_node_set dummy_node_set; - PUGI__FN PUGI__UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str) + PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str) { // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) unsigned int result = 0; @@ -8854,14 +9244,14 @@ PUGI__NS_BEGIN return result; } - template PUGI__FN T* new_xpath_variable(const char_t* name) + template PUGI_IMPL_FN T* new_xpath_variable(const char_t* name) { size_t length = strlength(name); - if (length == 0) return 0; // empty variable names are invalid + if (length == 0) return nullptr; // empty variable names are invalid // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t)); - if (!memory) return 0; + if (!memory) return nullptr; T* result = new (memory) T(); @@ -8870,7 +9260,7 @@ PUGI__NS_BEGIN return result; } - PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) + PUGI_IMPL_FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) { switch (type) { @@ -8887,17 +9277,17 @@ PUGI__NS_BEGIN return new_xpath_variable(name); default: - return 0; + return nullptr; } } - template PUGI__FN void delete_xpath_variable(T* var) + template PUGI_IMPL_FN void delete_xpath_variable(T* var) { var->~T(); xml_memory::deallocate(var); } - PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) + PUGI_IMPL_FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) { switch (type) { @@ -8922,7 +9312,7 @@ PUGI__NS_BEGIN } } - PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs) + PUGI_IMPL_FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs) { switch (rhs->type()) { @@ -8944,7 +9334,7 @@ PUGI__NS_BEGIN } } - PUGI__FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result) + PUGI_IMPL_FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result) { size_t length = static_cast(end - begin); char_t* scratch = buffer; @@ -8967,11 +9357,11 @@ PUGI__NS_BEGIN return true; } -PUGI__NS_END +PUGI_IMPL_NS_END // Internal node set class -PUGI__NS_BEGIN - PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end) +PUGI_IMPL_NS_BEGIN + PUGI_IMPL_FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end) { if (end - begin < 2) return xpath_node_set::type_sorted; @@ -8987,7 +9377,7 @@ PUGI__NS_BEGIN return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse; } - PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) + PUGI_IMPL_FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) { xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; @@ -9010,7 +9400,7 @@ PUGI__NS_BEGIN return order; } - PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) + PUGI_IMPL_FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) { if (begin == end) return xpath_node(); @@ -9040,7 +9430,7 @@ PUGI__NS_BEGIN xpath_node* _eos; public: - xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) + xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(nullptr), _end(nullptr), _eos(nullptr) { } @@ -9164,7 +9554,7 @@ PUGI__NS_BEGIN } }; - PUGI__FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc) + PUGI_IMPL_FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc) { size_t capacity = static_cast(_eos - _begin); @@ -9183,9 +9573,9 @@ PUGI__NS_BEGIN // push *_end++ = node; } -PUGI__NS_END +PUGI_IMPL_NS_END -PUGI__NS_BEGIN +PUGI_IMPL_NS_BEGIN struct xpath_context { xpath_node n; @@ -9232,7 +9622,7 @@ PUGI__NS_BEGIN const char_t* begin; const char_t* end; - xpath_lexer_string(): begin(0), end(0) + xpath_lexer_string(): begin(nullptr), end(nullptr) { } @@ -9267,7 +9657,7 @@ PUGI__NS_BEGIN { const char_t* cur = _cur; - while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; + while (PUGI_IMPL_IS_CHARTYPE(*cur, ct_space)) ++cur; // save lexeme position for error reporting _cur_lexeme_pos = cur; @@ -9349,17 +9739,17 @@ PUGI__NS_BEGIN case '$': cur += 1; - if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) + if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_start_symbol)) { _cur_lexeme_contents.begin = cur; - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++; - if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname + if (cur[0] == ':' && PUGI_IMPL_IS_CHARTYPEX(cur[1], ctx_symbol)) // qname { cur++; // : - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++; } _cur_lexeme_contents.end = cur; @@ -9422,13 +9812,13 @@ PUGI__NS_BEGIN cur += 2; _cur_lexeme = lex_double_dot; } - else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit)) + else if (PUGI_IMPL_IS_CHARTYPEX(*(cur+1), ctx_digit)) { _cur_lexeme_contents.begin = cur; // . ++cur; - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; + while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++; _cur_lexeme_contents.end = cur; @@ -9482,28 +9872,28 @@ PUGI__NS_BEGIN break; default: - if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) + if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) { _cur_lexeme_contents.begin = cur; - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; + while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++; if (*cur == '.') { cur++; - while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; + while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++; } _cur_lexeme_contents.end = cur; _cur_lexeme = lex_number; } - else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) + else if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_start_symbol)) { _cur_lexeme_contents.begin = cur; - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++; if (cur[0] == ':') { @@ -9511,11 +9901,11 @@ PUGI__NS_BEGIN { cur += 2; // :* } - else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname + else if (PUGI_IMPL_IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname { cur++; // : - while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++; } } @@ -9927,7 +10317,8 @@ PUGI__NS_BEGIN xpath_node* last = ns.begin() + first; - xpath_context c(xpath_node(), 1, size); + xpath_node cn; + xpath_context c(cn, 1, size); double er = expr->eval_number(c, stack); @@ -10014,7 +10405,7 @@ PUGI__NS_BEGIN { assert(n); - xml_node_type type = PUGI__NODETYPE(n); + xml_node_type type = PUGI_IMPL_NODETYPE(n); switch (_test) { @@ -10419,40 +10810,40 @@ PUGI__NS_BEGIN public: xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) + _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(nullptr), _right(nullptr), _next(nullptr) { assert(type == ast_string_constant); _data.string = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) + _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(nullptr), _right(nullptr), _next(nullptr) { assert(type == ast_number_constant); _data.number = value; } xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) + _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(nullptr), _right(nullptr), _next(nullptr) { assert(type == ast_variable); _data.variable = value; } - xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): - _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) + xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = nullptr, xpath_ast_node* right = nullptr): + _type(static_cast(type)), _rettype(static_cast(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(nullptr) { } xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): - _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(static_cast(axis)), _test(static_cast(test)), _left(left), _right(0), _next(0) + _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(static_cast(axis)), _test(static_cast(test)), _left(left), _right(nullptr), _next(nullptr) { assert(type == ast_step); _data.nodetest = contents; } xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test): - _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast(test)), _left(left), _right(right), _next(0) + _type(static_cast(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast(test)), _left(left), _right(right), _next(nullptr) { assert(type == ast_filter || type == ast_predicate); } @@ -10512,7 +10903,7 @@ PUGI__NS_BEGIN xpath_string lr = _left->eval_string(c, stack); xpath_string rr = _right->eval_string(c, stack); - return find_substring(lr.c_str(), rr.c_str()) != 0; + return find_substring(lr.c_str(), rr.c_str()) != nullptr; } case ast_func_boolean: @@ -11321,7 +11712,7 @@ PUGI__NS_BEGIN _result->error = message; _result->offset = _lexer.current_pos() - _query; - return 0; + return nullptr; } xpath_ast_node* error_oom() @@ -11329,7 +11720,7 @@ PUGI__NS_BEGIN assert(_alloc->_error); *_alloc->_error = true; - return 0; + return nullptr; } xpath_ast_node* error_rec() @@ -11345,37 +11736,37 @@ PUGI__NS_BEGIN xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, const char_t* value) { void* memory = alloc_node(); - return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; + return memory ? new (memory) xpath_ast_node(type, rettype, value) : nullptr; } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, double value) { void* memory = alloc_node(); - return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; + return memory ? new (memory) xpath_ast_node(type, rettype, value) : nullptr; } xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value) { void* memory = alloc_node(); - return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0; + return memory ? new (memory) xpath_ast_node(type, rettype, value) : nullptr; } - xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0) + xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = nullptr, xpath_ast_node* right = nullptr) { void* memory = alloc_node(); - return memory ? new (memory) xpath_ast_node(type, rettype, left, right) : 0; + return memory ? new (memory) xpath_ast_node(type, rettype, left, right) : nullptr; } xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents) { void* memory = alloc_node(); - return memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : 0; + return memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : nullptr; } xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test) { void* memory = alloc_node(); - return memory ? new (memory) xpath_ast_node(type, left, right, test) : 0; + return memory ? new (memory) xpath_ast_node(type, left, right, test) : nullptr; } const char_t* alloc_string(const xpath_lexer_string& value) @@ -11386,7 +11777,7 @@ PUGI__NS_BEGIN size_t length = static_cast(value.end - value.begin); char_t* c = static_cast(_alloc->allocate((length + 1) * sizeof(char_t))); - if (!c) return 0; + if (!c) return nullptr; memcpy(c, value.begin, length * sizeof(char_t)); c[length] = 0; @@ -11629,7 +12020,7 @@ PUGI__NS_BEGIN if (!_variables) return error("Unknown variable: variable set is not provided"); - xpath_variable* var = 0; + xpath_variable* var = nullptr; if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var)) return error_oom(); @@ -11646,7 +12037,7 @@ PUGI__NS_BEGIN _lexer.next(); xpath_ast_node* n = parse_expression(); - if (!n) return 0; + if (!n) return NULL; if (_lexer.current() != lex_close_brace) return error("Expected ')' to match an opening '('"); @@ -11659,7 +12050,7 @@ PUGI__NS_BEGIN case lex_quoted_string: { const char_t* value = alloc_string(_lexer.contents()); - if (!value) return 0; + if (!value) return nullptr; _lexer.next(); @@ -11680,13 +12071,13 @@ PUGI__NS_BEGIN case lex_string: { - xpath_ast_node* args[2] = {0}; + xpath_ast_node* args[2] = {nullptr}; size_t argc = 0; xpath_lexer_string function = _lexer.contents(); _lexer.next(); - xpath_ast_node* last_arg = 0; + xpath_ast_node* last_arg = nullptr; if (_lexer.current() != lex_open_brace) return error("Unrecognized function call"); @@ -11707,7 +12098,7 @@ PUGI__NS_BEGIN return error_rec(); xpath_ast_node* n = parse_expression(); - if (!n) return 0; + if (!n) return nullptr; if (argc < 2) args[argc] = n; else last_arg->set_next(n); @@ -11734,7 +12125,7 @@ PUGI__NS_BEGIN xpath_ast_node* parse_filter_expression() { xpath_ast_node* n = parse_primary_expression(); - if (!n) return 0; + if (!n) return nullptr; size_t old_depth = _depth; @@ -11749,10 +12140,10 @@ PUGI__NS_BEGIN return error("Predicate has to be applied to node set"); xpath_ast_node* expr = parse_expression(); - if (!expr) return 0; + if (!expr) return nullptr; n = alloc_node(ast_filter, n, expr, predicate_default); - if (!n) return 0; + if (!n) return nullptr; if (_lexer.current() != lex_close_square_brace) return error("Expected ']' to match an opening '['"); @@ -11792,7 +12183,7 @@ PUGI__NS_BEGIN if (_lexer.current() == lex_open_square_brace) return error("Predicates are not allowed after an abbreviated step"); - return alloc_node(ast_step, set, axis_self, nodetest_type_node, 0); + return alloc_node(ast_step, set, axis_self, nodetest_type_node, nullptr); } else if (_lexer.current() == lex_double_dot) { @@ -11801,7 +12192,7 @@ PUGI__NS_BEGIN if (_lexer.current() == lex_open_square_brace) return error("Predicates are not allowed after an abbreviated step"); - return alloc_node(ast_step, set, axis_parent, nodetest_type_node, 0); + return alloc_node(ast_step, set, axis_parent, nodetest_type_node, nullptr); } nodetest_t nt_type = nodetest_none; @@ -11908,14 +12299,14 @@ PUGI__NS_BEGIN } const char_t* nt_name_copy = alloc_string(nt_name); - if (!nt_name_copy) return 0; + if (!nt_name_copy) return nullptr; xpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy); - if (!n) return 0; + if (!n) return nullptr; size_t old_depth = _depth; - xpath_ast_node* last = 0; + xpath_ast_node* last = nullptr; while (_lexer.current() == lex_open_square_brace) { @@ -11925,10 +12316,10 @@ PUGI__NS_BEGIN return error_rec(); xpath_ast_node* expr = parse_expression(); - if (!expr) return 0; + if (!expr) return nullptr; - xpath_ast_node* pred = alloc_node(ast_predicate, 0, expr, predicate_default); - if (!pred) return 0; + xpath_ast_node* pred = alloc_node(ast_predicate, nullptr, expr, predicate_default); + if (!pred) return nullptr; if (_lexer.current() != lex_close_square_brace) return error("Expected ']' to match an opening '['"); @@ -11949,7 +12340,7 @@ PUGI__NS_BEGIN xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) { xpath_ast_node* n = parse_step(set); - if (!n) return 0; + if (!n) return nullptr; size_t old_depth = _depth; @@ -11960,8 +12351,8 @@ PUGI__NS_BEGIN if (l == lex_double_slash) { - n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - if (!n) return 0; + n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, nullptr); + if (!n) return nullptr; ++_depth; } @@ -11970,7 +12361,7 @@ PUGI__NS_BEGIN return error_rec(); n = parse_step(n); - if (!n) return 0; + if (!n) return nullptr; } _depth = old_depth; @@ -11987,7 +12378,7 @@ PUGI__NS_BEGIN _lexer.next(); xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set); - if (!n) return 0; + if (!n) return nullptr; // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path lexeme_t l = _lexer.current(); @@ -12002,16 +12393,16 @@ PUGI__NS_BEGIN _lexer.next(); xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set); - if (!n) return 0; + if (!n) return nullptr; - n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - if (!n) return 0; + n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, nullptr); + if (!n) return nullptr; return parse_relative_location_path(n); } // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 - return parse_relative_location_path(0); + return parse_relative_location_path(nullptr); } // PathExpr ::= LocationPath @@ -12037,7 +12428,7 @@ PUGI__NS_BEGIN // This is either a function call, or not - if not, we shall proceed with location path const char_t* state = _lexer.state(); - while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; + while (PUGI_IMPL_IS_CHARTYPE(*state, ct_space)) ++state; if (*state != '(') return parse_location_path(); @@ -12048,7 +12439,7 @@ PUGI__NS_BEGIN } xpath_ast_node* n = parse_filter_expression(); - if (!n) return 0; + if (!n) return nullptr; if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) { @@ -12060,8 +12451,8 @@ PUGI__NS_BEGIN if (n->rettype() != xpath_type_node_set) return error("Step has to be applied to node set"); - n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); - if (!n) return 0; + n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, nullptr); + if (!n) return nullptr; } // select from location path @@ -12076,7 +12467,7 @@ PUGI__NS_BEGIN // precedence 7+ - only parses union expressions xpath_ast_node* n = parse_expression(7); - if (!n) return 0; + if (!n) return nullptr; return alloc_node(ast_op_negate, xpath_type_number, n); } @@ -12164,14 +12555,14 @@ PUGI__NS_BEGIN return error_rec(); xpath_ast_node* rhs = parse_path_or_unary_expression(); - if (!rhs) return 0; + if (!rhs) return nullptr; binary_op_t nextop = binary_op_t::parse(_lexer); while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence) { rhs = parse_expression_rec(rhs, nextop.precedence); - if (!rhs) return 0; + if (!rhs) return nullptr; nextop = binary_op_t::parse(_lexer); } @@ -12180,7 +12571,7 @@ PUGI__NS_BEGIN return error("Union operator has to be applied to node sets"); lhs = alloc_node(op.asttype, op.rettype, lhs, rhs); - if (!lhs) return 0; + if (!lhs) return nullptr; op = binary_op_t::parse(_lexer); } @@ -12214,7 +12605,7 @@ PUGI__NS_BEGIN return error_rec(); xpath_ast_node* n = parse_path_or_unary_expression(); - if (!n) return 0; + if (!n) return nullptr; n = parse_expression_rec(n, limit); @@ -12230,7 +12621,7 @@ PUGI__NS_BEGIN xpath_ast_node* parse() { xpath_ast_node* n = parse_expression(); - if (!n) return 0; + if (!n) return nullptr; assert(_depth == 0); @@ -12254,7 +12645,7 @@ PUGI__NS_BEGIN static xpath_query_impl* create() { void* memory = xml_memory::allocate(sizeof(xpath_query_impl)); - if (!memory) return 0; + if (!memory) return nullptr; return new (memory) xpath_query_impl(); } @@ -12268,9 +12659,9 @@ PUGI__NS_BEGIN xml_memory::deallocate(impl); } - xpath_query_impl(): root(0), alloc(&block, &oom), oom(false) + xpath_query_impl(): root(nullptr), alloc(&block, &oom), oom(false) { - block.next = 0; + block.next = nullptr; block.capacity = sizeof(block.data); } @@ -12280,9 +12671,9 @@ PUGI__NS_BEGIN bool oom; }; - PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl) + PUGI_IMPL_FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl) { - if (!impl) return 0; + if (!impl) return nullptr; if (impl->root->rettype() != xpath_type_node_set) { @@ -12298,91 +12689,91 @@ PUGI__NS_BEGIN return impl->root; } -PUGI__NS_END +PUGI_IMPL_NS_END namespace pugi { #ifndef PUGIXML_NO_EXCEPTIONS - PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) + PUGI_IMPL_FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) { assert(_result.error); } - PUGI__FN const char* xpath_exception::what() const throw() + PUGI_IMPL_FN const char* xpath_exception::what() const PUGIXML_NOEXCEPT { return _result.error; } - PUGI__FN const xpath_parse_result& xpath_exception::result() const + PUGI_IMPL_FN const xpath_parse_result& xpath_exception::result() const { return _result; } #endif - PUGI__FN xpath_node::xpath_node() + PUGI_IMPL_FN xpath_node::xpath_node() { } - PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) + PUGI_IMPL_FN xpath_node::xpath_node(const xml_node& node_): _node(node_) { } - PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) + PUGI_IMPL_FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) { } - PUGI__FN xml_node xpath_node::node() const + PUGI_IMPL_FN xml_node xpath_node::node() const { return _attribute ? xml_node() : _node; } - PUGI__FN xml_attribute xpath_node::attribute() const + PUGI_IMPL_FN xml_attribute xpath_node::attribute() const { return _attribute; } - PUGI__FN xml_node xpath_node::parent() const + PUGI_IMPL_FN xml_node xpath_node::parent() const { return _attribute ? _node : _node.parent(); } - PUGI__FN static void unspecified_bool_xpath_node(xpath_node***) + PUGI_IMPL_FN static void unspecified_bool_xpath_node(xpath_node***) { } - PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const + PUGI_IMPL_FN xpath_node::operator xpath_node::unspecified_bool_type() const { - return (_node || _attribute) ? unspecified_bool_xpath_node : 0; + return (_node || _attribute) ? unspecified_bool_xpath_node : nullptr; } - PUGI__FN bool xpath_node::operator!() const + PUGI_IMPL_FN bool xpath_node::operator!() const { return !(_node || _attribute); } - PUGI__FN bool xpath_node::operator==(const xpath_node& n) const + PUGI_IMPL_FN bool xpath_node::operator==(const xpath_node& n) const { return _node == n._node && _attribute == n._attribute; } - PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const + PUGI_IMPL_FN bool xpath_node::operator!=(const xpath_node& n) const { return _node != n._node || _attribute != n._attribute; } #ifdef __BORLANDC__ - PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs) + PUGI_IMPL_FN bool operator&&(const xpath_node& lhs, bool rhs) { return (bool)lhs && rhs; } - PUGI__FN bool operator||(const xpath_node& lhs, bool rhs) + PUGI_IMPL_FN bool operator||(const xpath_node& lhs, bool rhs) { return (bool)lhs || rhs; } #endif - PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_) + PUGI_IMPL_FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_) { assert(begin_ <= end_); @@ -12414,7 +12805,7 @@ namespace pugi } #ifdef PUGIXML_HAS_MOVE - PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT + PUGI_IMPL_FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT { _type = rhs._type; _storage[0] = rhs._storage[0]; @@ -12427,27 +12818,27 @@ namespace pugi } #endif - PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage) + PUGI_IMPL_FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage) { } - PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage) + PUGI_IMPL_FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage) { _assign(begin_, end_, type_); } - PUGI__FN xpath_node_set::~xpath_node_set() + PUGI_IMPL_FN xpath_node_set::~xpath_node_set() { if (_begin != _storage) impl::xml_memory::deallocate(_begin); } - PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage) + PUGI_IMPL_FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage) { _assign(ns._begin, ns._end, ns._type); } - PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) + PUGI_IMPL_FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) { if (this == &ns) return *this; @@ -12457,12 +12848,12 @@ namespace pugi } #ifdef PUGIXML_HAS_MOVE - PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage) + PUGI_IMPL_FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage) { _move(rhs); } - PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT + PUGI_IMPL_FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT { if (this == &rhs) return *this; @@ -12475,66 +12866,66 @@ namespace pugi } #endif - PUGI__FN xpath_node_set::type_t xpath_node_set::type() const + PUGI_IMPL_FN xpath_node_set::type_t xpath_node_set::type() const { return _type; } - PUGI__FN size_t xpath_node_set::size() const + PUGI_IMPL_FN size_t xpath_node_set::size() const { return _end - _begin; } - PUGI__FN bool xpath_node_set::empty() const + PUGI_IMPL_FN bool xpath_node_set::empty() const { return _begin == _end; } - PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const + PUGI_IMPL_FN const xpath_node& xpath_node_set::operator[](size_t index) const { assert(index < size()); return _begin[index]; } - PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const + PUGI_IMPL_FN xpath_node_set::const_iterator xpath_node_set::begin() const { return _begin; } - PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const + PUGI_IMPL_FN xpath_node_set::const_iterator xpath_node_set::end() const { return _end; } - PUGI__FN void xpath_node_set::sort(bool reverse) + PUGI_IMPL_FN void xpath_node_set::sort(bool reverse) { _type = impl::xpath_sort(_begin, _end, _type, reverse); } - PUGI__FN xpath_node xpath_node_set::first() const + PUGI_IMPL_FN xpath_node xpath_node_set::first() const { return impl::xpath_first(_begin, _end, _type); } - PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) + PUGI_IMPL_FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) { } - PUGI__FN xpath_parse_result::operator bool() const + PUGI_IMPL_FN xpath_parse_result::operator bool() const { - return error == 0; + return error == nullptr; } - PUGI__FN const char* xpath_parse_result::description() const + PUGI_IMPL_FN const char* xpath_parse_result::description() const { return error ? error : "No error"; } - PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0) + PUGI_IMPL_FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(nullptr) { } - PUGI__FN const char_t* xpath_variable::name() const + PUGI_IMPL_FN const char_t* xpath_variable::name() const { switch (_type) { @@ -12552,37 +12943,37 @@ namespace pugi default: assert(false && "Invalid variable type"); // unreachable - return 0; + return nullptr; } } - PUGI__FN xpath_value_type xpath_variable::type() const + PUGI_IMPL_FN xpath_value_type xpath_variable::type() const { return _type; } - PUGI__FN bool xpath_variable::get_boolean() const + PUGI_IMPL_FN bool xpath_variable::get_boolean() const { return (_type == xpath_type_boolean) ? static_cast(this)->value : false; } - PUGI__FN double xpath_variable::get_number() const + PUGI_IMPL_FN double xpath_variable::get_number() const { return (_type == xpath_type_number) ? static_cast(this)->value : impl::gen_nan(); } - PUGI__FN const char_t* xpath_variable::get_string() const + PUGI_IMPL_FN const char_t* xpath_variable::get_string() const { - const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : 0; + const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : nullptr; return value ? value : PUGIXML_TEXT(""); } - PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const + PUGI_IMPL_FN const xpath_node_set& xpath_variable::get_node_set() const { return (_type == xpath_type_node_set) ? static_cast(this)->value : impl::dummy_node_set; } - PUGI__FN bool xpath_variable::set(bool value) + PUGI_IMPL_FN bool xpath_variable::set(bool value) { if (_type != xpath_type_boolean) return false; @@ -12590,7 +12981,7 @@ namespace pugi return true; } - PUGI__FN bool xpath_variable::set(double value) + PUGI_IMPL_FN bool xpath_variable::set(double value) { if (_type != xpath_type_number) return false; @@ -12598,7 +12989,7 @@ namespace pugi return true; } - PUGI__FN bool xpath_variable::set(const char_t* value) + PUGI_IMPL_FN bool xpath_variable::set(const char_t* value) { if (_type != xpath_type_string) return false; @@ -12619,7 +13010,7 @@ namespace pugi return true; } - PUGI__FN bool xpath_variable::set(const xpath_node_set& value) + PUGI_IMPL_FN bool xpath_variable::set(const xpath_node_set& value) { if (_type != xpath_type_node_set) return false; @@ -12627,27 +13018,27 @@ namespace pugi return true; } - PUGI__FN xpath_variable_set::xpath_variable_set() + PUGI_IMPL_FN xpath_variable_set::xpath_variable_set() { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) - _data[i] = 0; + _data[i] = nullptr; } - PUGI__FN xpath_variable_set::~xpath_variable_set() + PUGI_IMPL_FN xpath_variable_set::~xpath_variable_set() { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _destroy(_data[i]); } - PUGI__FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs) + PUGI_IMPL_FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs) { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) - _data[i] = 0; + _data[i] = nullptr; _assign(rhs); } - PUGI__FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs) + PUGI_IMPL_FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs) { if (this == &rhs) return *this; @@ -12657,30 +13048,30 @@ namespace pugi } #ifdef PUGIXML_HAS_MOVE - PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT + PUGI_IMPL_FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { _data[i] = rhs._data[i]; - rhs._data[i] = 0; + rhs._data[i] = nullptr; } } - PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT + PUGI_IMPL_FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { _destroy(_data[i]); _data[i] = rhs._data[i]; - rhs._data[i] = 0; + rhs._data[i] = nullptr; } return *this; } #endif - PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs) + PUGI_IMPL_FN void xpath_variable_set::_assign(const xpath_variable_set& rhs) { xpath_variable_set temp; @@ -12691,7 +13082,7 @@ namespace pugi _swap(temp); } - PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs) + PUGI_IMPL_FN void xpath_variable_set::_swap(xpath_variable_set& rhs) { for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) { @@ -12702,7 +13093,7 @@ namespace pugi } } - PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const + PUGI_IMPL_FN xpath_variable* xpath_variable_set::_find(const char_t* name) const { const size_t hash_size = sizeof(_data) / sizeof(_data[0]); size_t hash = impl::hash_string(name) % hash_size; @@ -12712,12 +13103,12 @@ namespace pugi if (impl::strequal(var->name(), name)) return var; - return 0; + return nullptr; } - PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result) + PUGI_IMPL_FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result) { - xpath_variable* last = 0; + xpath_variable* last = nullptr; while (var) { @@ -12742,7 +13133,7 @@ namespace pugi return true; } - PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var) + PUGI_IMPL_FN void xpath_variable_set::_destroy(xpath_variable* var) { while (var) { @@ -12754,7 +13145,7 @@ namespace pugi } } - PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) + PUGI_IMPL_FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) { const size_t hash_size = sizeof(_data) / sizeof(_data[0]); size_t hash = impl::hash_string(name) % hash_size; @@ -12762,7 +13153,7 @@ namespace pugi // look for existing variable for (xpath_variable* var = _data[hash]; var; var = var->_next) if (impl::strequal(var->name(), name)) - return var->type() == type ? var : 0; + return var->type() == type ? var : nullptr; // add new variable xpath_variable* result = impl::new_xpath_variable(type, name); @@ -12777,41 +13168,41 @@ namespace pugi return result; } - PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value) + PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, bool value) { xpath_variable* var = add(name, xpath_type_boolean); return var ? var->set(value) : false; } - PUGI__FN bool xpath_variable_set::set(const char_t* name, double value) + PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, double value) { xpath_variable* var = add(name, xpath_type_number); return var ? var->set(value) : false; } - PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value) + PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, const char_t* value) { xpath_variable* var = add(name, xpath_type_string); return var ? var->set(value) : false; } - PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) + PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) { xpath_variable* var = add(name, xpath_type_node_set); return var ? var->set(value) : false; } - PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name) + PUGI_IMPL_FN xpath_variable* xpath_variable_set::get(const char_t* name) { return _find(name); } - PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const + PUGI_IMPL_FN const xpath_variable* xpath_variable_set::get(const char_t* name) const { return _find(name); } - PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) + PUGI_IMPL_FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(nullptr) { impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create(); @@ -12835,7 +13226,7 @@ namespace pugi qimpl->root->optimize(&qimpl->alloc); _impl = impl.release(); - _result.error = 0; + _result.error = nullptr; } else { @@ -12849,26 +13240,26 @@ namespace pugi } } - PUGI__FN xpath_query::xpath_query(): _impl(0) + PUGI_IMPL_FN xpath_query::xpath_query(): _impl(nullptr) { } - PUGI__FN xpath_query::~xpath_query() + PUGI_IMPL_FN xpath_query::~xpath_query() { if (_impl) impl::xpath_query_impl::destroy(static_cast(_impl)); } #ifdef PUGIXML_HAS_MOVE - PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT + PUGI_IMPL_FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT { _impl = rhs._impl; _result = rhs._result; - rhs._impl = 0; + rhs._impl = nullptr; rhs._result = xpath_parse_result(); } - PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT + PUGI_IMPL_FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT { if (this == &rhs) return *this; @@ -12877,21 +13268,21 @@ namespace pugi _impl = rhs._impl; _result = rhs._result; - rhs._impl = 0; + rhs._impl = nullptr; rhs._result = xpath_parse_result(); return *this; } #endif - PUGI__FN xpath_value_type xpath_query::return_type() const + PUGI_IMPL_FN xpath_value_type xpath_query::return_type() const { if (!_impl) return xpath_type_none; return static_cast(_impl)->root->rettype(); } - PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const + PUGI_IMPL_FN bool xpath_query::evaluate_boolean(const xpath_node& n) const { if (!_impl) return false; @@ -12912,7 +13303,7 @@ namespace pugi return r; } - PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const + PUGI_IMPL_FN double xpath_query::evaluate_number(const xpath_node& n) const { if (!_impl) return impl::gen_nan(); @@ -12934,7 +13325,7 @@ namespace pugi } #ifndef PUGIXML_NO_STL - PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const + PUGI_IMPL_FN string_t xpath_query::evaluate_string(const xpath_node& n) const { if (!_impl) return string_t(); @@ -12956,7 +13347,7 @@ namespace pugi } #endif - PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const + PUGI_IMPL_FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const { impl::xpath_context c(n, 1, 1); impl::xpath_stack_data sd; @@ -12986,7 +13377,7 @@ namespace pugi return full_size; } - PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const + PUGI_IMPL_FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const { impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); if (!root) return xpath_node_set(); @@ -13008,7 +13399,7 @@ namespace pugi return xpath_node_set(r.begin(), r.end(), r.type()); } - PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const + PUGI_IMPL_FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const { impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast(_impl)); if (!root) return xpath_node(); @@ -13030,54 +13421,54 @@ namespace pugi return r.first(); } - PUGI__FN const xpath_parse_result& xpath_query::result() const + PUGI_IMPL_FN const xpath_parse_result& xpath_query::result() const { return _result; } - PUGI__FN static void unspecified_bool_xpath_query(xpath_query***) + PUGI_IMPL_FN static void unspecified_bool_xpath_query(xpath_query***) { } - PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const + PUGI_IMPL_FN xpath_query::operator xpath_query::unspecified_bool_type() const { - return _impl ? unspecified_bool_xpath_query : 0; + return _impl ? unspecified_bool_xpath_query : nullptr; } - PUGI__FN bool xpath_query::operator!() const + PUGI_IMPL_FN bool xpath_query::operator!() const { return !_impl; } - PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const + PUGI_IMPL_FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node(*this); } - PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const + PUGI_IMPL_FN xpath_node xml_node::select_node(const xpath_query& query) const { return query.evaluate_node(*this); } - PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const + PUGI_IMPL_FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node_set(*this); } - PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const + PUGI_IMPL_FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const { return query.evaluate_node_set(*this); } - PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const + PUGI_IMPL_FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const { xpath_query q(query, variables); return q.evaluate_node(*this); } - PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const + PUGI_IMPL_FN xpath_node xml_node::select_single_node(const xpath_query& query) const { return query.evaluate_node(*this); } @@ -13089,51 +13480,55 @@ namespace pugi # pragma option pop #endif +#if defined(_MSC_VER) && defined(__c2__) +# pragma clang diagnostic pop +#endif + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + // Intel C++ does not properly keep warning state for function templates, // so popping warning state at the end of translation unit leads to warnings in the middle. #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) # pragma warning(pop) #endif -#if defined(_MSC_VER) && defined(__c2__) -# pragma clang diagnostic pop -#endif - // Undefine all local macros (makes sure we're not leaking macros in header-only mode) -#undef PUGI__NO_INLINE -#undef PUGI__UNLIKELY -#undef PUGI__STATIC_ASSERT -#undef PUGI__DMC_VOLATILE -#undef PUGI__UNSIGNED_OVERFLOW -#undef PUGI__MSVC_CRT_VERSION -#undef PUGI__SNPRINTF -#undef PUGI__NS_BEGIN -#undef PUGI__NS_END -#undef PUGI__FN -#undef PUGI__FN_NO_INLINE -#undef PUGI__GETHEADER_IMPL -#undef PUGI__GETPAGE_IMPL -#undef PUGI__GETPAGE -#undef PUGI__NODETYPE -#undef PUGI__IS_CHARTYPE_IMPL -#undef PUGI__IS_CHARTYPE -#undef PUGI__IS_CHARTYPEX -#undef PUGI__ENDSWITH -#undef PUGI__SKIPWS -#undef PUGI__OPTSET -#undef PUGI__PUSHNODE -#undef PUGI__POPNODE -#undef PUGI__SCANFOR -#undef PUGI__SCANWHILE -#undef PUGI__SCANWHILE_UNROLL -#undef PUGI__ENDSEG -#undef PUGI__THROW_ERROR -#undef PUGI__CHECK_ERROR +#undef PUGI_IMPL_NO_INLINE +#undef PUGI_IMPL_UNLIKELY +#undef PUGI_IMPL_STATIC_ASSERT +#undef PUGI_IMPL_DMC_VOLATILE +#undef PUGI_IMPL_UNSIGNED_OVERFLOW +#undef PUGI_IMPL_MSVC_CRT_VERSION +#undef PUGI_IMPL_SNPRINTF +#undef PUGI_IMPL_NS_BEGIN +#undef PUGI_IMPL_NS_END +#undef PUGI_IMPL_FN +#undef PUGI_IMPL_FN_NO_INLINE +#undef PUGI_IMPL_GETHEADER_IMPL +#undef PUGI_IMPL_GETPAGE_IMPL +#undef PUGI_IMPL_GETPAGE +#undef PUGI_IMPL_NODETYPE +#undef PUGI_IMPL_IS_CHARTYPE_IMPL +#undef PUGI_IMPL_IS_CHARTYPE +#undef PUGI_IMPL_IS_CHARTYPEX +#undef PUGI_IMPL_ENDSWITH +#undef PUGI_IMPL_SKIPWS +#undef PUGI_IMPL_OPTSET +#undef PUGI_IMPL_PUSHNODE +#undef PUGI_IMPL_POPNODE +#undef PUGI_IMPL_SCANFOR +#undef PUGI_IMPL_SCANWHILE +#undef PUGI_IMPL_SCANWHILE_UNROLL +#undef PUGI_IMPL_ENDSEG +#undef PUGI_IMPL_THROW_ERROR +#undef PUGI_IMPL_CHECK_ERROR #endif /** - * Copyright (c) 2006-2024 Arseny Kapoulkine + * Copyright (c) 2006-2026 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/Dependencies/assimp/contrib/pugixml/src/pugixml.hpp b/Dependencies/assimp/contrib/pugixml/src/pugixml.hpp index fde6a4a86..840b0451a 100644 --- a/Dependencies/assimp/contrib/pugixml/src/pugixml.hpp +++ b/Dependencies/assimp/contrib/pugixml/src/pugixml.hpp @@ -1,7 +1,7 @@ /** - * pugixml parser - version 1.13 + * pugixml parser - version 1.15 * -------------------------------------------------------- - * Copyright (c) 2006-2024, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + * Copyright (C) 2006-2026, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ * * This library is distributed under the MIT License. See notice at the end @@ -14,7 +14,7 @@ // Define version macro; evaluates to major * 1000 + minor * 10 + patch so that it's safe to use in less-than comparisons // Note: pugixml used major * 100 + minor * 10 + patch format up until 1.9 (which had version identifier 190); starting from pugixml 1.10, the minor version number is two digits #ifndef PUGIXML_VERSION -# define PUGIXML_VERSION 1130 // 1.13 +# define PUGIXML_VERSION 1150 // 1.15 #endif // Include user configuration file (this can define various configuration macros) @@ -38,6 +38,20 @@ # include #endif +// Check if std::string_view is available +#if !defined(PUGIXML_HAS_STRING_VIEW) && !defined(PUGIXML_NO_STL) +# if __cplusplus >= 201703L +# define PUGIXML_HAS_STRING_VIEW +# elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L +# define PUGIXML_HAS_STRING_VIEW +# endif +#endif + +// Include string_view if appropriate +#ifdef PUGIXML_HAS_STRING_VIEW +# include +#endif + // Macro for deprecated features #ifndef PUGIXML_DEPRECATED # if defined(__GNUC__) @@ -82,14 +96,14 @@ # endif #endif -// If C++ is 2011 or higher, add 'noexcept' specifiers +// If C++ is 2011 or higher, use 'noexcept' specifiers #ifndef PUGIXML_NOEXCEPT # if __cplusplus >= 201103 # define PUGIXML_NOEXCEPT noexcept # elif defined(_MSC_VER) && _MSC_VER >= 1900 # define PUGIXML_NOEXCEPT noexcept # else -# define PUGIXML_NOEXCEPT +# define PUGIXML_NOEXCEPT throw() # endif #endif @@ -138,7 +152,12 @@ namespace pugi #ifndef PUGIXML_NO_STL // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE - typedef std::basic_string, std::allocator > string_t; + typedef std::basic_string string_t; +#endif + +#ifdef PUGIXML_HAS_STRING_VIEW + // String view type used for operations that can work with a length delimited string; depends on PUGIXML_WCHAR_MODE + typedef std::basic_string_view string_view_t; #endif } @@ -213,6 +232,10 @@ namespace pugi // This flag is off by default. const unsigned int parse_embed_pcdata = 0x2000; + // This flag determines whether determines whether the the two pcdata should be merged or not, if no intermediatory data are parsed in the document. + // This flag is off by default. + const unsigned int parse_merge_pcdata = 0x4000; + // The default parsing mode. // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. @@ -324,7 +347,7 @@ namespace pugi class PUGIXML_CLASS xml_writer { public: - virtual ~xml_writer() {} + virtual ~xml_writer(); // Write memory chunk into stream/file/whatever virtual void write(const void* data, size_t size) = 0; @@ -349,14 +372,14 @@ namespace pugi { public: // Construct writer from an output stream object - xml_writer_stream(std::basic_ostream >& stream); - xml_writer_stream(std::basic_ostream >& stream); + xml_writer_stream(std::basic_ostream& stream); + xml_writer_stream(std::basic_ostream& stream); virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; private: - std::basic_ostream >* narrow_stream; - std::basic_ostream >* wide_stream; + std::basic_ostream* narrow_stream; + std::basic_ostream* wide_stream; }; #endif @@ -392,7 +415,7 @@ namespace pugi bool operator<=(const xml_attribute& r) const; bool operator>=(const xml_attribute& r) const; - // Check if attribute is empty + // Check if attribute is empty (null) bool empty() const; // Get attribute name/value, or "" if attribute is empty @@ -418,8 +441,15 @@ namespace pugi // Set attribute name/value (returns false if attribute is empty or there is not enough memory) bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs, size_t sz); + bool set_name(const char_t* rhs, size_t size); + #ifdef PUGIXML_HAS_STRING_VIEW + bool set_name(string_view_t rhs); + #endif bool set_value(const char_t* rhs); + bool set_value(const char_t* rhs, size_t size); + #ifdef PUGIXML_HAS_STRING_VIEW + bool set_value(string_view_t rhs); + #endif // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); @@ -447,6 +477,10 @@ namespace pugi xml_attribute& operator=(float rhs); xml_attribute& operator=(bool rhs); + #ifdef PUGIXML_HAS_STRING_VIEW + xml_attribute& operator=(string_view_t rhs); + #endif + #ifdef PUGIXML_HAS_LONG_LONG xml_attribute& operator=(long long rhs); xml_attribute& operator=(unsigned long long rhs); @@ -502,7 +536,7 @@ namespace pugi bool operator<=(const xml_node& r) const; bool operator>=(const xml_node& r) const; - // Check if node is empty. + // Check if node is empty (null) bool empty() const; // Get node type @@ -541,9 +575,18 @@ namespace pugi xml_attribute attribute(const char_t* name) const; xml_node next_sibling(const char_t* name) const; xml_node previous_sibling(const char_t* name) const; + #ifdef PUGIXML_HAS_STRING_VIEW + xml_node child(string_view_t name) const; + xml_attribute attribute(string_view_t name) const; + xml_node next_sibling(string_view_t name) const; + xml_node previous_sibling(string_view_t name) const; + #endif // Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast) xml_attribute attribute(const char_t* name, xml_attribute& hint) const; + #ifdef PUGIXML_HAS_STRING_VIEW + xml_attribute attribute(string_view_t name, xml_attribute& hint) const; + #endif // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA const char_t* child_value() const; @@ -553,14 +596,27 @@ namespace pugi // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs, size_t sz); + bool set_name(const char_t* rhs, size_t size); + #ifdef PUGIXML_HAS_STRING_VIEW + bool set_name(string_view_t rhs); + #endif bool set_value(const char_t* rhs); + bool set_value(const char_t* rhs, size_t size); + #ifdef PUGIXML_HAS_STRING_VIEW + bool set_value(string_view_t rhs); + #endif // Add attribute with specified name. Returns added attribute, or empty attribute on errors. xml_attribute append_attribute(const char_t* name); xml_attribute prepend_attribute(const char_t* name); xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); + #ifdef PUGIXML_HAS_STRING_VIEW + xml_attribute append_attribute(string_view_t name); + xml_attribute prepend_attribute(string_view_t name); + xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr); + xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr); + #endif // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. xml_attribute append_copy(const xml_attribute& proto); @@ -579,6 +635,12 @@ namespace pugi xml_node prepend_child(const char_t* name); xml_node insert_child_after(const char_t* name, const xml_node& node); xml_node insert_child_before(const char_t* name, const xml_node& node); + #ifdef PUGIXML_HAS_STRING_VIEW + xml_node append_child(string_view_t name); + xml_node prepend_child(string_view_t name); + xml_node insert_child_after(string_view_t, const xml_node& node); + xml_node insert_child_before(string_view_t name, const xml_node& node); + #endif // Add a copy of the specified node as a child. Returns added node, or empty node on errors. xml_node append_copy(const xml_node& proto); @@ -595,6 +657,9 @@ namespace pugi // Remove specified attribute bool remove_attribute(const xml_attribute& a); bool remove_attribute(const char_t* name); + #ifdef PUGIXML_HAS_STRING_VIEW + bool remove_attribute(string_view_t name); + #endif // Remove all attributes bool remove_attributes(); @@ -602,6 +667,9 @@ namespace pugi // Remove specified child bool remove_child(const xml_node& n); bool remove_child(const char_t* name); + #ifdef PUGIXML_HAS_STRING_VIEW + bool remove_child(string_view_t name); + #endif // Remove all children bool remove_children(); @@ -694,8 +762,8 @@ namespace pugi #ifndef PUGIXML_NO_STL // Print subtree to stream - void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; - void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; + void print(std::basic_ostream& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + void print(std::basic_ostream& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; #endif // Child nodes iterators @@ -712,9 +780,12 @@ namespace pugi // Range-based for support xml_object_range children() const; - xml_object_range children(const char_t* name) const; xml_object_range attributes() const; + // Range-based for support for all children with the specified name + // Note: name pointer must have a longer lifetime than the returned object; be careful with passing temporaries! + xml_object_range children(const char_t* name) const; + // Get node offset in parsed file/string (in char_t units) for debugging purposes ptrdiff_t offset_debug() const; @@ -755,7 +826,7 @@ namespace pugi // Borland C++ workaround bool operator!() const; - // Check if text object is empty + // Check if text object is empty (null) bool empty() const; // Get text, or "" if object is empty @@ -779,8 +850,11 @@ namespace pugi bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) - bool set(const char_t* rhs, size_t sz); bool set(const char_t* rhs); + bool set(const char_t* rhs, size_t size); + #ifdef PUGIXML_HAS_STRING_VIEW + bool set(string_view_t rhs); + #endif // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); @@ -808,6 +882,10 @@ namespace pugi xml_text& operator=(float rhs); xml_text& operator=(bool rhs); + #ifdef PUGIXML_HAS_STRING_VIEW + xml_text& operator=(string_view_t rhs); + #endif + #ifdef PUGIXML_HAS_LONG_LONG xml_text& operator=(long long rhs); xml_text& operator=(unsigned long long rhs); @@ -927,6 +1005,7 @@ namespace pugi xml_named_node_iterator(); // Construct an iterator which points to the specified node + // Note: name pointer is stored in the iterator and must have a longer lifetime than iterator itself xml_named_node_iterator(const xml_node& node, const char_t* name); // Iterator operators @@ -1062,8 +1141,8 @@ namespace pugi #ifndef PUGIXML_NO_STL // Load document from stream. - xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); - xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); + xml_parse_result load(std::basic_istream& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load(std::basic_istream& stream, unsigned int options = parse_default); #endif // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied. @@ -1092,8 +1171,8 @@ namespace pugi #ifndef PUGIXML_NO_STL // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). - void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; - void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; + void save(std::basic_ostream& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + void save(std::basic_ostream& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; #endif // Save XML to file @@ -1304,7 +1383,7 @@ namespace pugi explicit xpath_exception(const xpath_parse_result& result); // Get error message - virtual const char* what() const throw() PUGIXML_OVERRIDE; + virtual const char* what() const PUGIXML_NOEXCEPT PUGIXML_OVERRIDE; // Get parse result const xpath_parse_result& result() const; @@ -1429,12 +1508,12 @@ namespace pugi #ifndef PUGIXML_NO_STL // Convert wide string to UTF8 - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); + std::basic_string PUGIXML_FUNCTION as_utf8(const wchar_t* str); + std::basic_string PUGIXML_FUNCTION as_utf8(const std::basic_string& str); // Convert UTF8 to wide string - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); + std::basic_string PUGIXML_FUNCTION as_wide(const char* str); + std::basic_string PUGIXML_FUNCTION as_wide(const std::basic_string& str); #endif // Memory allocation function interface; returns pointer to allocated memory or NULL on failure @@ -1481,7 +1560,7 @@ namespace std #endif /** - * Copyright (c) 2006-2024 Arseny Kapoulkine + * Copyright (c) 2006-2026 Arseny Kapoulkine * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/Dependencies/assimp/contrib/zlib/gzguts.h b/Dependencies/assimp/contrib/zlib/gzguts.h index 60ed8891c..e229b9562 100644 --- a/Dependencies/assimp/contrib/zlib/gzguts.h +++ b/Dependencies/assimp/contrib/zlib/gzguts.h @@ -12,6 +12,15 @@ # endif #endif +#ifdef _WIN32 +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +# endif // _CRT_SECURE_NO_WARNINGS +# ifndef _CRT_NONSTDC_NO_DEPRECATE +# define _CRT_NONSTDC_NO_DEPRECATE +# endif // _CRT_NONSTDC_NO_DEPRECATE +#endif // _WIN32 + #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else @@ -35,10 +44,6 @@ # include #endif -#ifdef __unix__ -# include -#endif - #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include #endif diff --git a/Dependencies/assimp/contrib/zlib/gzlib.c b/Dependencies/assimp/contrib/zlib/gzlib.c index 55da46a45..0a577269c 100644 --- a/Dependencies/assimp/contrib/zlib/gzlib.c +++ b/Dependencies/assimp/contrib/zlib/gzlib.c @@ -3,6 +3,15 @@ * For conditions of distribution and use, see copyright notice in zlib.h */ +#ifdef _WIN32 +# ifndef _CRT_NONSTDC_NO_DEPRECATE +# define _CRT_NONSTDC_NO_DEPRECATE +# endif +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +# endif //_CRT_SECURE_NO_WARNINGS +#endif // _WIN32 + #include "gzguts.h" #if defined(_WIN32) && !defined(__BORLANDC__) diff --git a/Dependencies/assimp/contrib/zlib/gzread.c b/Dependencies/assimp/contrib/zlib/gzread.c index dd7738159..6c1b5dcf3 100644 --- a/Dependencies/assimp/contrib/zlib/gzread.c +++ b/Dependencies/assimp/contrib/zlib/gzread.c @@ -3,6 +3,15 @@ * For conditions of distribution and use, see copyright notice in zlib.h */ +#ifdef _WIN32 +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +# endif // _CRT_SECURE_NO_WARNINGS +# ifndef _CRT_NONSTDC_NO_DEPRECATE +# define _CRT_NONSTDC_NO_DEPRECATE +# endif // _CRT_NONSTDC_NO_DEPRECATE +#endif // _WIN32 + #include "gzguts.h" /* Local functions */ diff --git a/Dependencies/assimp/contrib/zlib/gzwrite.c b/Dependencies/assimp/contrib/zlib/gzwrite.c index eb8a0e589..d508ede83 100644 --- a/Dependencies/assimp/contrib/zlib/gzwrite.c +++ b/Dependencies/assimp/contrib/zlib/gzwrite.c @@ -2,7 +2,6 @@ * Copyright (C) 2004-2019 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ - #include "gzguts.h" /* Local functions */ diff --git a/Dependencies/assimp/contrib/zlib/zutil.c b/Dependencies/assimp/contrib/zlib/zutil.c index 9543ae825..30bbd2bde 100644 --- a/Dependencies/assimp/contrib/zlib/zutil.c +++ b/Dependencies/assimp/contrib/zlib/zutil.c @@ -23,7 +23,6 @@ z_const char * const z_errmsg[10] = { (z_const char *)"" }; - const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; diff --git a/Dependencies/assimp/include/assimp/AssertHandler.h b/Dependencies/assimp/include/assimp/AssertHandler.h index 1247ff490..0c7d39113 100644 --- a/Dependencies/assimp/include/assimp/AssertHandler.h +++ b/Dependencies/assimp/include/assimp/AssertHandler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2020, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -58,6 +58,7 @@ using AiAssertHandler = void (*)(const char* failedExpression, const char* file, // --------------------------------------------------------------------------- /** * @brief Set the assert handler. + * @param handler The assertion handler to use. */ ASSIMP_API void setAiAssertHandler(AiAssertHandler handler); @@ -65,12 +66,18 @@ ASSIMP_API void setAiAssertHandler(AiAssertHandler handler); /** The assert handler which is set by default. * * @brief This issues a message to stderr and calls abort. + * @param failedExpression The failed expression as a string. + * @param file The name of the source file. + * @param line The line in the source file. */ AI_WONT_RETURN ASSIMP_API void defaultAiAssertHandler(const char* failedExpression, const char* file, int line) AI_WONT_RETURN_SUFFIX; // --------------------------------------------------------------------------- /** - * @brief Dispatches an assert violation to the assert handler. + * @brief Dispatches an assert violation to the assert handler. + * @param failedExpression The failed expression as a string. + * @param file The name of the source file. + * @param line The line in the source file. */ ASSIMP_API void aiAssertViolation(const char* failedExpression, const char* file, int line); diff --git a/Dependencies/assimp/include/assimp/Base64.hpp b/Dependencies/assimp/include/assimp/Base64.hpp index 6a3551307..11d691a50 100644 --- a/Dependencies/assimp/include/assimp/Base64.hpp +++ b/Dependencies/assimp/include/assimp/Base64.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/BaseImporter.h b/Dependencies/assimp/include/assimp/BaseImporter.h index 167b254d6..73f0bd754 100644 --- a/Dependencies/assimp/include/assimp/BaseImporter.h +++ b/Dependencies/assimp/include/assimp/BaseImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -70,7 +70,8 @@ class BaseProcess; class SharedPostProcessInfo; class IOStream; -// utility to do char4 to uint32 in a portable manner +/// @def AI_MAKE_MAGIC +/// @brief Utility to do char4 to uint32 in a portable manner #define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \ (string[1] << 16) + (string[2] << 8) + string[3])) @@ -188,60 +189,7 @@ class ASSIMP_API BaseImporter { * @param extension set to collect file extensions in*/ void GetExtensionList(std::set &extensions); -protected: - double importerScale = 1.0; - double fileScale = 1.0; - - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. The - * function is expected to throw an ImportErrorException if there is - * an error. If it terminates normally, the data in aiScene is - * expected to be correct. Override this function to implement the - * actual importing. - *
- * The output scene must meet the following requirements:
- *
    - *
  • At least a root node must be there, even if its only purpose - * is to reference one mesh.
  • - *
  • aiMesh::mPrimitiveTypes may be 0. The types of primitives - * in the mesh are determined automatically in this case.
  • - *
  • the vertex data is stored in a pseudo-indexed "verbose" format. - * In fact this means that every vertex that is referenced by - * a face is unique. Or the other way round: a vertex index may - * not occur twice in a single aiMesh.
  • - *
  • aiAnimation::mDuration may be -1. Assimp determines the length - * of the animation automatically in this case as the length of - * the longest animation channel.
  • - *
  • aiMesh::mBitangents may be nullptr if tangents and normals are - * given. In this case bitangents are computed as the cross product - * between normal and tangent.
  • - *
  • There needn't be a material. If none is there a default material - * is generated. However, it is recommended practice for loaders - * to generate a default material for yourself that matches the - * default material setting for the file format better than Assimp's - * generic default material. Note that default materials *should* - * be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded - * or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy) - * texture.
  • - *
- * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:
    - *
  • at least one mesh must be there
  • - *
  • there may be no meshes with 0 vertices or faces
  • - *
- * This won't be checked (except by the validation step): Assimp will - * crash if one of the conditions is not met! - * - * @param pFile Path of the file to be imported. - * @param pScene The scene object to hold the imported data. - * nullptr is not a valid parameter. - * @param pIOHandler The IO handler to use for any file access. - * nullptr is not a valid parameter. */ - virtual void InternReadFile( - const std::string &pFile, - aiScene *pScene, - IOSystem *pIOHandler) = 0; - -public: // static utilities + // static utilities // ------------------------------------------------------------------- /** A utility for CanRead(). * @@ -394,6 +342,59 @@ class ASSIMP_API BaseImporter { } } +protected: + double importerScale = 1.0; + double fileScale = 1.0; + + // ------------------------------------------------------------------- + /** Imports the given file into the given scene structure. The + * function is expected to throw an ImportErrorException if there is + * an error. If it terminates normally, the data in aiScene is + * expected to be correct. Override this function to implement the + * actual importing. + *
+ * The output scene must meet the following requirements:
+ *
    + *
  • At least a root node must be there, even if its only purpose + * is to reference one mesh.
  • + *
  • aiMesh::mPrimitiveTypes may be 0. The types of primitives + * in the mesh are determined automatically in this case.
  • + *
  • the vertex data is stored in a pseudo-indexed "verbose" format. + * In fact this means that every vertex that is referenced by + * a face is unique. Or the other way round: a vertex index may + * not occur twice in a single aiMesh.
  • + *
  • aiAnimation::mDuration may be -1. Assimp determines the length + * of the animation automatically in this case as the length of + * the longest animation channel.
  • + *
  • aiMesh::mBitangents may be nullptr if tangents and normals are + * given. In this case bitangents are computed as the cross product + * between normal and tangent.
  • + *
  • There needn't be a material. If none is there a default material + * is generated. However, it is recommended practice for loaders + * to generate a default material for yourself that matches the + * default material setting for the file format better than Assimp's + * generic default material. Note that default materials *should* + * be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded + * or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy) + * texture.
  • + *
+ * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is not set:
    + *
  • at least one mesh must be there
  • + *
  • there may be no meshes with 0 vertices or faces
  • + *
+ * This won't be checked (except by the validation step): Assimp will + * crash if one of the conditions is not met! + * + * @param pFile Path of the file to be imported. + * @param pScene The scene object to hold the imported data. + * nullptr is not a valid parameter. + * @param pIOHandler The IO handler to use for any file access. + * nullptr is not a valid parameter. */ + virtual void InternReadFile( + const std::string &pFile, + aiScene *pScene, + IOSystem *pIOHandler) = 0; + private: /* Pushes state into importer for the importer scale */ void UpdateImporterScale(Importer *pImp); diff --git a/Dependencies/assimp/include/assimp/Bitmap.h b/Dependencies/assimp/include/assimp/Bitmap.h index 5145a6cd5..7f8d7a7dd 100644 --- a/Dependencies/assimp/include/assimp/Bitmap.h +++ b/Dependencies/assimp/include/assimp/Bitmap.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/BlobIOSystem.h b/Dependencies/assimp/include/assimp/BlobIOSystem.h index eb23f9e92..9c730c122 100644 --- a/Dependencies/assimp/include/assimp/BlobIOSystem.h +++ b/Dependencies/assimp/include/assimp/BlobIOSystem.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -64,7 +64,7 @@ class BlobIOSystem; // -------------------------------------------------------------------------------------------- /** Redirect IOStream to a blob */ // -------------------------------------------------------------------------------------------- -class BlobIOStream : public IOStream { +class BlobIOStream final : public IOStream { public: /// @brief The class constructor with all needed parameters /// @param creator Pointer to the creator instance @@ -84,7 +84,6 @@ class BlobIOStream : public IOStream { /// @brief The class destructor. ~BlobIOStream() override; -public: // ------------------------------------------------------------------- aiExportDataBlob *GetBlob() { aiExportDataBlob *blob = new aiExportDataBlob(); @@ -193,11 +192,10 @@ class BlobIOStream : public IOStream { // -------------------------------------------------------------------------------------------- /** Redirect IOSystem to a blob */ // -------------------------------------------------------------------------------------------- -class BlobIOSystem : public IOSystem { +class BlobIOSystem final : public IOSystem { friend class BlobIOStream; - typedef std::pair BlobEntry; - + using BlobEntry = std::pair; public: /// @brief The default class constructor. @@ -230,7 +228,7 @@ class BlobIOSystem : public IOSystem { const bool hasBaseName = baseName != AI_BLOBIO_MAGIC; // one must be the master - aiExportDataBlob *master = nullptr, *cur; + aiExportDataBlob *master = nullptr; for (const BlobEntry &blobby : blobs) { if (blobby.first == magicName) { @@ -245,7 +243,7 @@ class BlobIOSystem : public IOSystem { return nullptr; } - cur = master; + aiExportDataBlob *cur = master; for (const BlobEntry &blobby : blobs) { if (blobby.second == master) { diff --git a/Dependencies/assimp/include/assimp/ByteSwapper.h b/Dependencies/assimp/include/assimp/ByteSwapper.h index 73c115b8a..a779eef9e 100644 --- a/Dependencies/assimp/include/assimp/ByteSwapper.h +++ b/Dependencies/assimp/include/assimp/ByteSwapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -57,7 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #endif -namespace Assimp { +namespace Assimp { // -------------------------------------------------------------------------------------- /** Defines some useful byte order swap routines. * diff --git a/Dependencies/assimp/include/assimp/ColladaMetaData.h b/Dependencies/assimp/include/assimp/ColladaMetaData.h index 9973d16a5..249fe0844 100644 --- a/Dependencies/assimp/include/assimp/ColladaMetaData.h +++ b/Dependencies/assimp/include/assimp/ColladaMetaData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/CreateAnimMesh.h b/Dependencies/assimp/include/assimp/CreateAnimMesh.h index 6e14ac747..21904e6d4 100644 --- a/Dependencies/assimp/include/assimp/CreateAnimMesh.h +++ b/Dependencies/assimp/include/assimp/CreateAnimMesh.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/DefaultIOStream.h b/Dependencies/assimp/include/assimp/DefaultIOStream.h index c39d9a8e1..44a304b38 100644 --- a/Dependencies/assimp/include/assimp/DefaultIOStream.h +++ b/Dependencies/assimp/include/assimp/DefaultIOStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/DefaultIOSystem.h b/Dependencies/assimp/include/assimp/DefaultIOSystem.h index 0aeef9eb8..9f4033f6d 100644 --- a/Dependencies/assimp/include/assimp/DefaultIOSystem.h +++ b/Dependencies/assimp/include/assimp/DefaultIOSystem.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -52,11 +52,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** Default implementation of IOSystem using the standard C file functions */ -class ASSIMP_API DefaultIOSystem : public IOSystem { +class ASSIMP_API DefaultIOSystem final : public IOSystem { public: // ------------------------------------------------------------------- /** Tests for the existence of a file at the given path. */ diff --git a/Dependencies/assimp/include/assimp/DefaultLogger.hpp b/Dependencies/assimp/include/assimp/DefaultLogger.hpp index b43eebb70..2eb26ad9d 100644 --- a/Dependencies/assimp/include/assimp/DefaultLogger.hpp +++ b/Dependencies/assimp/include/assimp/DefaultLogger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -56,6 +56,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "NullLogger.hpp" #include +#ifndef ASSIMP_BUILD_SINGLETHREADED +#include +#include +#endif + namespace Assimp { // ------------------------------------------------------------------------------------ class IOStream; @@ -77,7 +82,7 @@ struct LogStreamInfo; * If you wish to customize the logging at an even deeper level supply your own * implementation of #Logger to #set(). * @note The whole logging stuff causes a small extra overhead for all imports. */ -class ASSIMP_API DefaultLogger : public Logger { +class ASSIMP_API DefaultLogger final : public Logger { public: // ---------------------------------------------------------------------- /** @brief Creates a logging instance. @@ -103,6 +108,9 @@ class ASSIMP_API DefaultLogger : public Logger { * your needs. If the provided message formatting is OK for you, * it's much easier to use #create() and to attach your own custom * output streams to it. + * Since set is intended to be used for custom loggers, the user is + * responsible for instantiation and destruction (new / delete). + * Before deletion of the custom logger, set(nullptr); must be called. * @param logger Pass NULL to setup a default NullLogger*/ static void set(Logger *logger); @@ -120,8 +128,8 @@ class ASSIMP_API DefaultLogger : public Logger { static bool isNullLogger(); // ---------------------------------------------------------------------- - /** @brief Kills the current singleton logger and replaces it with a - * #NullLogger instance. */ + /** @brief Kills and deletes the current singleton logger and replaces + * it with a #NullLogger instance. */ static void kill(); // ---------------------------------------------------------------------- @@ -139,7 +147,7 @@ class ASSIMP_API DefaultLogger : public Logger { explicit DefaultLogger(LogSeverity severity); // ---------------------------------------------------------------------- - /** @briefDestructor */ + /** @brief Destructor */ ~DefaultLogger() override; /** @brief Logs debug infos, only been written when severity level DEBUG or higher is set */ @@ -181,6 +189,10 @@ class ASSIMP_API DefaultLogger : public Logger { //! Attached streams StreamArray m_StreamArray; +#ifndef ASSIMP_BUILD_SINGLETHREADED + std::mutex m_arrayMutex; +#endif + bool noRepeatMsg; char lastMsg[MAX_LOG_MESSAGE_LENGTH * 2]; size_t lastLen; diff --git a/Dependencies/assimp/include/assimp/Exceptional.h b/Dependencies/assimp/include/assimp/Exceptional.h index b4b51863f..428964c2e 100644 --- a/Dependencies/assimp/include/assimp/Exceptional.h +++ b/Dependencies/assimp/include/assimp/Exceptional.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -104,7 +104,7 @@ class ASSIMP_API DeadlyImportError : public DeadlyErrorBase { /** FOR EXPORTER PLUGINS ONLY: Simple exception class to be thrown if an * unrecoverable error occurs while exporting. Exporting APIs return * nullptr instead of a valid aiScene then. */ -class ASSIMP_API DeadlyExportError : public DeadlyErrorBase { +class ASSIMP_API DeadlyExportError final : public DeadlyErrorBase { public: /** Constructor with arguments */ template diff --git a/Dependencies/assimp/include/assimp/Exporter.hpp b/Dependencies/assimp/include/assimp/Exporter.hpp index bdec20b97..51a176512 100644 --- a/Dependencies/assimp/include/assimp/Exporter.hpp +++ b/Dependencies/assimp/include/assimp/Exporter.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/GenericProperty.h b/Dependencies/assimp/include/assimp/GenericProperty.h index a35ebf23d..77ffd9050 100644 --- a/Dependencies/assimp/include/assimp/GenericProperty.h +++ b/Dependencies/assimp/include/assimp/GenericProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/GltfMaterial.h b/Dependencies/assimp/include/assimp/GltfMaterial.h index 5e63b9132..f2cfc07a3 100644 --- a/Dependencies/assimp/include/assimp/GltfMaterial.h +++ b/Dependencies/assimp/include/assimp/GltfMaterial.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0 +#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_GLTF_METALLIC_ROUGHNESS, 0 #define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0 #define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0 diff --git a/Dependencies/assimp/include/assimp/Hash.h b/Dependencies/assimp/include/assimp/Hash.h index 9dec87408..847af3aaa 100644 --- a/Dependencies/assimp/include/assimp/Hash.h +++ b/Dependencies/assimp/include/assimp/Hash.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -52,15 +52,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // ------------------------------------------------------------------------------------------------ -// Hashing function taken from -// http://www.azillionmonkeys.com/qed/hash.html -// (incremental version) -// -// This code is Copyright 2004-2008 by Paul Hsieh. It is used here in the belief that -// Assimp's license is considered compatible with Pauls's derivative license as specified -// on his web page. -// -// (stdint.h should have been been included here) +/// @brief Hashing function taken from +/// http://www.azillionmonkeys.com/qed/hash.html +/// (incremental version) +/// +/// This code is Copyright 2004-2008 by Paul Hsieh. It is used here in the belief that +/// Assimp's license is considered compatible with Pauls's derivative license as specified +/// on his web page. +/// +/// (stdint.h should have been been included here) // ------------------------------------------------------------------------------------------------ #undef get16bits #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ diff --git a/Dependencies/assimp/include/assimp/IOStream.hpp b/Dependencies/assimp/include/assimp/IOStream.hpp index 1866a3d72..2b123905c 100644 --- a/Dependencies/assimp/include/assimp/IOStream.hpp +++ b/Dependencies/assimp/include/assimp/IOStream.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/IOStreamBuffer.h b/Dependencies/assimp/include/assimp/IOStreamBuffer.h index 5a6924a09..c6e16bb12 100644 --- a/Dependencies/assimp/include/assimp/IOStreamBuffer.h +++ b/Dependencies/assimp/include/assimp/IOStreamBuffer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -292,15 +292,13 @@ AI_FORCE_INLINE bool IOStreamBuffer::getNextLine(std::vector &buffer) { if (IsLineEnd(m_cache[m_cachePos])) { // skip line end - while (m_cache[m_cachePos] != '\n') { + do { ++m_cachePos; - } - ++m_cachePos; - if (isEndOfCache(m_cachePos, m_cacheSize)) { - if (!readNextBlock()) { + if (isEndOfCache(m_cachePos, m_cacheSize) && !readNextBlock()) { return false; } } + while (m_cache[m_cachePos] != '\n'); } size_t i(0); @@ -320,7 +318,10 @@ AI_FORCE_INLINE bool IOStreamBuffer::getNextLine(std::vector &buffer) { } } buffer[i] = '\n'; - while (m_cachePos < m_cacheSize && (m_cache[m_cachePos] == '\r' || m_cache[m_cachePos] == '\n')) { + if (m_cachePos < m_cacheSize && (m_cache[m_cachePos] == '\r')) { + ++m_cachePos; + } + if (m_cachePos < m_cacheSize && (m_cache[m_cachePos] == '\n')) { ++m_cachePos; } diff --git a/Dependencies/assimp/include/assimp/IOSystem.hpp b/Dependencies/assimp/include/assimp/IOSystem.hpp index b345151d5..697abd1e8 100644 --- a/Dependencies/assimp/include/assimp/IOSystem.hpp +++ b/Dependencies/assimp/include/assimp/IOSystem.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -71,7 +71,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace Assimp { +namespace Assimp { class IOStream; diff --git a/Dependencies/assimp/include/assimp/Importer.hpp b/Dependencies/assimp/include/assimp/Importer.hpp index a3a0d9eae..d7bc9de12 100644 --- a/Dependencies/assimp/include/assimp/Importer.hpp +++ b/Dependencies/assimp/include/assimp/Importer.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -108,6 +108,10 @@ namespace Assimp { * allocations and may take some time, so it's better to reuse them as often as * possible. * +* If you want to let assimp deal with OutOfMemory-exception make sure that +* ASSIMP_CATCH_GLOBAL_EXCEPTIONS is set. +* If this is not the case you need to catch the exception by yourself. +* * If you need the Importer to do custom file handling to access the files, * implement IOSystem and IOStream and supply an instance of your custom * IOSystem implementation by calling SetIOHandler() before calling ReadFile(). diff --git a/Dependencies/assimp/include/assimp/LineSplitter.h b/Dependencies/assimp/include/assimp/LineSplitter.h index 635349dc0..25fc3c08a 100644 --- a/Dependencies/assimp/include/assimp/LineSplitter.h +++ b/Dependencies/assimp/include/assimp/LineSplitter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -78,25 +78,30 @@ for(LineSplitter splitter(stream);splitter;++splitter) { // ------------------------------------------------------------------------------------------------ class LineSplitter { public: - typedef size_t line_idx; + /// The current line index in the data block. + using line_idx = size_t; // ----------------------------------------- - /** construct from existing stream reader - note: trim is *always* assumed true if skyp_empty_lines==true - */ + /// @brief The class constructor. + /// @note trim is *always* assumed true if skyp_empty_lines==true LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true); + // ----------------------------------------- + /// @brief The class destructor. ~LineSplitter() = default; // ----------------------------------------- - /** pseudo-iterator increment */ + /// @brief pseudo-iterator increment LineSplitter& operator++(); // ----------------------------------------- + /// @brief pseudo-iterator increment LineSplitter& operator++(int); // ----------------------------------------- - /** get a pointer to the beginning of a particular token */ + /// @brief Get a pointer to the beginning of a particular token. + /// @param idx The index into the token. + /// @return The token. const char* operator[] (size_t idx) const; // ----------------------------------------- @@ -105,33 +110,41 @@ class LineSplitter { void get_tokens(const char* (&tokens)[N]) const; // ----------------------------------------- - /** member access */ + /// member access via -> operator. const std::string* operator -> () const; + // ----------------------------------------- + /// member access via * operator. std::string operator* () const; - + + /// @brief Will return the end marker, end of the buffer plus one. + /// @return The end pointer marker. const char *getEnd() const; // ----------------------------------------- - /** boolean context */ + /// boolean context. operator bool() const; // ----------------------------------------- - /** line indices are zero-based, empty lines are included */ + /// line indices are zero-based, empty lines are included operator line_idx() const; + /// @brief Will return the current index. + /// @return The current index. line_idx get_index() const; // ----------------------------------------- - /** access the underlying stream object */ + /// @brief Access the underlying stream object. + /// @return Reference to the stream reader. StreamReaderLE& get_stream(); // ----------------------------------------- - /** !strcmp((*this)->substr(0,strlen(check)),check) */ + /// !strcmp((*this)->substr(0,strlen(check)),check) + /// @return true if token matches. bool match_start(const char* check); // ----------------------------------------- - /** swallow the next call to ++, return the previous value. */ + /// @brief Swallow the next call to ++, return the previous value. void swallow_next_increment(); LineSplitter( const LineSplitter & ) = delete; @@ -139,19 +152,17 @@ class LineSplitter { LineSplitter &operator = ( const LineSplitter & ) = delete; private: - line_idx mIdx; - std::string mCur; - const char *mEnd; - StreamReaderLE& mStream; - bool mSwallow, mSkip_empty_lines, mTrim; + line_idx mIdx{0}; + std::string mCur{}; + const char *mEnd{nullptr}; + StreamReaderLE &mStream; + bool mSwallow{false}; + bool mSkip_empty_lines{ false }; + bool mTrim{ false }; }; AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim ) : - mIdx(0), - mCur(), - mEnd(nullptr), mStream(stream), - mSwallow(), mSkip_empty_lines(skip_empty_lines), mTrim(trim) { mCur.reserve(1024); diff --git a/Dependencies/assimp/include/assimp/LogAux.h b/Dependencies/assimp/include/assimp/LogAux.h index 20a7564b8..53e17c9a7 100644 --- a/Dependencies/assimp/include/assimp/LogAux.h +++ b/Dependencies/assimp/include/assimp/LogAux.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/LogStream.hpp b/Dependencies/assimp/include/assimp/LogStream.hpp index 2d9f1d350..fa53d49ca 100644 --- a/Dependencies/assimp/include/assimp/LogStream.hpp +++ b/Dependencies/assimp/include/assimp/LogStream.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -69,11 +69,11 @@ class ASSIMP_API LogStream { protected: /** @brief Default constructor */ - LogStream() AI_NO_EXCEPT; + LogStream() AI_NO_EXCEPT = default; public: /** @brief Virtual destructor */ - virtual ~LogStream(); + virtual ~LogStream() = default; // ------------------------------------------------------------------- /** @brief Overwrite this for your own output methods @@ -99,10 +99,6 @@ class ASSIMP_API LogStream }; // !class LogStream -inline LogStream::LogStream() AI_NO_EXCEPT = default; - -inline LogStream::~LogStream() = default; - } // Namespace Assimp #endif // INCLUDED_AI_LOGSTREAM_H diff --git a/Dependencies/assimp/include/assimp/Logger.hpp b/Dependencies/assimp/include/assimp/Logger.hpp index 0051153e2..80a6ac772 100644 --- a/Dependencies/assimp/include/assimp/Logger.hpp +++ b/Dependencies/assimp/include/assimp/Logger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -94,7 +94,7 @@ class ASSIMP_API Logger }; /** @brief Virtual destructor */ - virtual ~Logger(); + virtual ~Logger() = default; // ---------------------------------------------------------------------- /** @brief Writes a debug message @@ -184,12 +184,12 @@ class ASSIMP_API Logger protected: /** - * Default constructor + * @brief Default constructor */ - Logger() AI_NO_EXCEPT; + Logger() AI_NO_EXCEPT = default; /** - * Construction with a given log severity + * @brief Construction with a given log severity */ explicit Logger(LogSeverity severity); @@ -253,18 +253,9 @@ class ASSIMP_API Logger } protected: - LogSeverity m_Severity; + LogSeverity m_Severity{NORMAL}; }; -// ---------------------------------------------------------------------------------- -inline Logger::Logger() AI_NO_EXCEPT : - m_Severity(NORMAL) { - // empty -} - -// ---------------------------------------------------------------------------------- -inline Logger::~Logger() = default; - // ---------------------------------------------------------------------------------- inline Logger::Logger(LogSeverity severity) : m_Severity(severity) { diff --git a/Dependencies/assimp/include/assimp/MathFunctions.h b/Dependencies/assimp/include/assimp/MathFunctions.h index eaa8b4ac4..03596ea79 100644 --- a/Dependencies/assimp/include/assimp/MathFunctions.h +++ b/Dependencies/assimp/include/assimp/MathFunctions.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/MemoryIOWrapper.h b/Dependencies/assimp/include/assimp/MemoryIOWrapper.h index ef06af273..669edb137 100644 --- a/Dependencies/assimp/include/assimp/MemoryIOWrapper.h +++ b/Dependencies/assimp/include/assimp/MemoryIOWrapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -55,7 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace Assimp { +namespace Assimp { #define AI_MEMORYIO_MAGIC_FILENAME "$$$___magic___$$$" #define AI_MEMORYIO_MAGIC_FILENAME_LENGTH 17 diff --git a/Dependencies/assimp/include/assimp/NullLogger.hpp b/Dependencies/assimp/include/assimp/NullLogger.hpp index 552bcf66a..c4d761959 100644 --- a/Dependencies/assimp/include/assimp/NullLogger.hpp +++ b/Dependencies/assimp/include/assimp/NullLogger.hpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/ObjMaterial.h b/Dependencies/assimp/include/assimp/ObjMaterial.h index 21087ebcb..30a9ab991 100644 --- a/Dependencies/assimp/include/assimp/ObjMaterial.h +++ b/Dependencies/assimp/include/assimp/ObjMaterial.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -55,16 +55,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --------------------------------------------------------------------------- -// the original illum property +/// @brief The original illum property #define AI_MATKEY_OBJ_ILLUM "$mat.illum", 0, 0 // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- -// Pure key names for all obj texture-related properties +/// @brief Pure key names for all obj texture-related properties //! @cond MATS_DOC_FULL -// support for bump -bm +/// @brief Support for bump -bm #define _AI_MATKEY_OBJ_BUMPMULT_BASE "$tex.bumpmult" //! @endcond @@ -80,5 +80,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //! @endcond - -#endif +#endif // AI_OBJMATERIAL_H_INC diff --git a/Dependencies/assimp/include/assimp/ParsingUtils.h b/Dependencies/assimp/include/assimp/ParsingUtils.h index e0ee2d77c..17e992849 100644 --- a/Dependencies/assimp/include/assimp/ParsingUtils.h +++ b/Dependencies/assimp/include/assimp/ParsingUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -59,48 +59,69 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { -// NOTE: the functions below are mostly intended as replacement for -// std::upper, std::lower, std::isupper, std::islower, std::isspace. -// we don't bother of locales. We don't want them. We want reliable -// (i.e. identical) results across all locales. +/// NOTE: the functions below are mostly intended as replacement for +/// std::upper, std::lower, std::isupper, std::islower, std::isspace. +/// we don't bother of locales. We don't want them. We want reliable +/// (i.e. identical) results across all locales, because we had a lot +/// of issues in the past . -// The functions below accept any character type, but know only -// about ASCII. However, UTF-32 is the only safe ASCII superset to -// use since it doesn't have multi-byte sequences. +/// The functions below accept any character type, but know only +/// about ASCII. However, UTF-32 is the only safe ASCII superset to +/// use since it doesn't have multi-byte sequences. -static const unsigned int BufferSize = 4096; +static constexpr unsigned int BufferSize = 4096; // --------------------------------------------------------------------------------- +/// @brief Returns true, if the character is upper-case. +/// @param in The character to test. +/// @return true if upper-case, false if not. template AI_FORCE_INLINE bool IsUpper(char_t in) { return (in >= (char_t)'A' && in <= (char_t)'Z'); } // --------------------------------------------------------------------------------- +/// @brief Returns true, if the character is lower-case. +/// @param in The character to test. +/// @return true if lower-case, false if not. template AI_FORCE_INLINE bool IsLower(char_t in) { return (in >= (char_t)'a' && in <= (char_t)'z'); } // --------------------------------------------------------------------------------- +/// @brief Returns true, if the character is a space. +/// @param in The character to test. +/// @return true if a space, false if not. template AI_FORCE_INLINE bool IsSpace(char_t in) { return (in == (char_t)' ' || in == (char_t)'\t'); } // --------------------------------------------------------------------------------- +/// @brief Returns true, if the character is a line end. +/// @param in The character to test. +/// @return true if a line end, false if not. template AI_FORCE_INLINE bool IsLineEnd(char_t in) { return (in == (char_t)'\r' || in == (char_t)'\n' || in == (char_t)'\0' || in == (char_t)'\f'); } // --------------------------------------------------------------------------------- +/// @brief Returns true, if the character is a space or a line end. +/// @param in The character to test. +/// @return true if a space or a line end, false if not. template AI_FORCE_INLINE bool IsSpaceOrNewLine(char_t in) { return IsSpace(in) || IsLineEnd(in); } // --------------------------------------------------------------------------------- +/// @brief Will skip all spaces in a buffer. +/// @param in The incoming buffer. +/// @param out The buffer with skipped data. +/// @param end The end of the buffer. +/// @return true if valid. template AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out, const char_t *end) { while ((*in == (char_t)' ' || *in == (char_t)'\t') && in != end) { @@ -111,15 +132,24 @@ AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out, const char } // --------------------------------------------------------------------------------- +/// @brief Will skip all spaces in a buffer in-situ. +/// @param inout The in/out buffer. +/// @param end The end of the buffer. +/// @return true if valid. template AI_FORCE_INLINE bool SkipSpaces(const char_t **inout, const char_t *end) { return SkipSpaces(*inout, inout, end); } // --------------------------------------------------------------------------------- +/// @brief Will skip a line. +/// @param in The incoming buffer. +/// @param out The buffer with skipped data. +/// @param end The end of the buffer. +/// @return true if valid. template AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out, const char_t *end) { - while ((*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0') && in != end) { + while ((*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0') && *in != (char_t)'#' && in != end) { ++in; } @@ -132,12 +162,20 @@ AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out, const char_t } // --------------------------------------------------------------------------------- +/// @brief Will skip a line in-situ. +/// @param in The in/out buffer. +/// @param end The end of the buffer. +/// @return true if valid. template AI_FORCE_INLINE bool SkipLine(const char_t **inout, const char_t *end) { return SkipLine(*inout, inout, end); } // --------------------------------------------------------------------------------- +/// @brief Returns true, if the character is a space or a line end. +/// @param in The character to test. +/// @param out The buffer with the skipped data. +/// @return true if valid. template AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out, const char_t *end) { while ((*in == (char_t)' ' || *in == (char_t)'\t' || *in == (char_t)'\r' || *in == (char_t)'\n') && in != end) { @@ -148,12 +186,20 @@ AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out, } // --------------------------------------------------------------------------------- +/// @brief Returns true, if the character is a space or a line end. +/// @param in The character to test. +/// @param out The buffer with the skipped data. +/// @return true if valid. template AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t **inout, const char_t *end) { return SkipSpacesAndLineEnd(*inout, inout, end); } // --------------------------------------------------------------------------------- +/// @brief Will return point showing to the next line. +/// @param buffer The in buffer. +/// @param out The next line. +/// @return true if a new lne was found, else false. template AI_FORCE_INLINE bool GetNextLine(const char_t *&buffer, char_t out[BufferSize]) { if ((char_t)'\0' == *buffer) { @@ -161,13 +207,13 @@ AI_FORCE_INLINE bool GetNextLine(const char_t *&buffer, char_t out[BufferSize]) } char *_out = out; - char *const end = _out + BufferSize; + char *const end = _out + BufferSize - 1; while (!IsLineEnd(*buffer) && _out < end) { *_out++ = *buffer++; } *_out = (char_t)'\0'; - while (IsLineEnd(*buffer) && '\0' != *buffer) { + while (IsLineEnd(*buffer) && '\0' != *buffer && buffer != end) { ++buffer; } @@ -175,12 +221,20 @@ AI_FORCE_INLINE bool GetNextLine(const char_t *&buffer, char_t out[BufferSize]) } // --------------------------------------------------------------------------------- +/// @brief Returns true, if the character is a number. +/// @param in The character to test. +/// @return true if a number, false if not. template AI_FORCE_INLINE bool IsNumeric(char_t in) { return (in >= '0' && in <= '9') || '-' == in || '+' == in; } // --------------------------------------------------------------------------------- +/// @brief Will check an incoming buffer for a given token. +/// @param in The incoming buffer. +/// @param token The token to check for. +/// @param len the buffer length. +/// @return true if token was found, false if not. template AI_FORCE_INLINE bool TokenMatch(char_t *&in, const char *token, unsigned int len) { if (!::strncmp(token, in, len) && IsSpaceOrNewLine(in[len])) { @@ -196,11 +250,11 @@ AI_FORCE_INLINE bool TokenMatch(char_t *&in, const char *token, unsigned int len return false; } // --------------------------------------------------------------------------------- -/** @brief Case-ignoring version of TokenMatch - * @param in Input - * @param token Token to check for - * @param len Number of characters to check - */ +/// @brief Case-ignoring version of TokenMatch +/// @param in Input +/// @param token Token to check for +/// @param len Number of characters to check +/// @return true if token was found, false if not. AI_FORCE_INLINE bool TokenMatchI(const char *&in, const char *token, unsigned int len) { if (!ASSIMP_strincmp(token, in, len) && IsSpaceOrNewLine(in[len])) { in += len + 1; @@ -210,6 +264,9 @@ AI_FORCE_INLINE bool TokenMatchI(const char *&in, const char *token, unsigned in } // --------------------------------------------------------------------------------- +/// @brief Will skip the next token. +/// @param in The incoming buffer. +/// @param end The end marker of the buffer. AI_FORCE_INLINE void SkipToken(const char *&in, const char *end) { SkipSpaces(&in, end); while (!IsSpaceOrNewLine(*in)) { @@ -218,6 +275,10 @@ AI_FORCE_INLINE void SkipToken(const char *&in, const char *end) { } // --------------------------------------------------------------------------------- +/// @brief Will return the next token as a string. +/// @param in The incoming buffer. +/// @param end The end marker of the buffer. +/// @return The next token. AI_FORCE_INLINE std::string GetNextToken(const char *&in, const char *end) { SkipSpacesAndLineEnd(&in, end); const char *cur = in; @@ -228,12 +289,11 @@ AI_FORCE_INLINE std::string GetNextToken(const char *&in, const char *end) { } // --------------------------------------------------------------------------------- -/** @brief Will perform a simple tokenize. - * @param str String to tokenize. - * @param tokens Array with tokens, will be empty if no token was found. - * @param delimiters Delimiter for tokenize. - * @return Number of found token. - */ +/// @brief Will perform a simple tokenize. +/// @param str String to tokenize. +/// @param tokens Array with tokens, will be empty if no token was found. +/// @param delimiters Delimiter for tokenize. +/// @return Number of found token. template AI_FORCE_INLINE unsigned int tokenize(const string_type &str, std::vector &tokens, const string_type &delimiters) { @@ -258,6 +318,10 @@ AI_FORCE_INLINE unsigned int tokenize(const string_type &str, std::vector(tokens.size()); } +// --------------------------------------------------------------------------------- +/// @brief Will convert the given string to lowercase with stl-strings. +/// @param str The stl-string to convert. +/// @return The lowercase string as a stl-string. inline std::string ai_stdStrToLower(const std::string &str) { std::string out(str); for (size_t i = 0; i < str.size(); ++i) { diff --git a/Dependencies/assimp/include/assimp/Profiler.h b/Dependencies/assimp/include/assimp/Profiler.h index ff4f590c3..9fdf9e3e8 100644 --- a/Dependencies/assimp/include/assimp/Profiler.h +++ b/Dependencies/assimp/include/assimp/Profiler.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -57,45 +56,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace Assimp { -namespace Profiling { +namespace Assimp::Profiling { using namespace Formatter; // ------------------------------------------------------------------------------------------------ -/** Simple wrapper around boost::timer to simplify reporting. Timings are automatically - * dumped to the log file. - */ +/// @brief Simple wrapper around boost::timer to simplify reporting. +/// +/// Timings are automatically dumped to the log file. class Profiler { public: + /// @brief The class constructor. Profiler() = default; + /// @brief The class destructor. + ~Profiler() = default; - /** Start a named timer */ + /// @brief Starts a named timer. + /// @param region The profiling region name. void BeginRegion(const std::string& region) { - regions[region] = std::chrono::system_clock::now(); + mRegions[region] = std::chrono::system_clock::now(); ASSIMP_LOG_DEBUG("START `",region,"`"); } - - /** End a specific named timer and write its end time to the log */ + /// @brief End a specific named timer and write its end time to the log. + /// @param region The profiling region name. void EndRegion(const std::string& region) { - RegionMap::const_iterator it = regions.find(region); - if (it == regions.end()) { + if (auto it = mRegions.find(region); it == mRegions.end()) { return; } - std::chrono::duration elapsedSeconds = std::chrono::system_clock::now() - regions[region]; + auto elapsedSeconds = std::chrono::system_clock::now() - mRegions[region]; ASSIMP_LOG_DEBUG("END `",region,"`, dt= ", elapsedSeconds.count()," s"); } private: - typedef std::map> RegionMap; - RegionMap regions; + using RegionMap = std::map>; + RegionMap mRegions{}; }; -} -} +} // namespace Assimp::Profiling #endif // AI_INCLUDED_PROFILER_H diff --git a/Dependencies/assimp/include/assimp/ProgressHandler.hpp b/Dependencies/assimp/include/assimp/ProgressHandler.hpp index 2a1ab309c..518e37e76 100644 --- a/Dependencies/assimp/include/assimp/ProgressHandler.hpp +++ b/Dependencies/assimp/include/assimp/ProgressHandler.hpp @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/RemoveComments.h b/Dependencies/assimp/include/assimp/RemoveComments.h index a7a9a2381..de5fcf1fe 100644 --- a/Dependencies/assimp/include/assimp/RemoveComments.h +++ b/Dependencies/assimp/include/assimp/RemoveComments.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -52,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** \brief Helper class to remove single and multi line comments from a file @@ -62,32 +62,33 @@ namespace Assimp { * module. */ class ASSIMP_API CommentRemover { - // class cannot be instanced - CommentRemover() {} - public: - - //! Remove single-line comments. The end of a line is - //! expected to be either NL or CR or NLCR. - //! \param szComment The start sequence of the comment, e.g. "//" - //! \param szBuffer Buffer to work with - //! \param chReplacement Character to be used as replacement - //! for commented lines. By default this is ' ' + // class cannot be instanced + CommentRemover() = delete; + ~CommentRemover() = delete; + + /// @brief Remove single-line comments. + /// The end of a line is expected to be either NL or CR or NLCR. + /// @param szComment The start sequence of the comment, e.g. "//" + /// @param szBuffer Buffer to work with + /// @param chReplacement Character to be used as replacement + /// for commented lines. By default this is ' ' static void RemoveLineComments(const char* szComment, char* szBuffer, char chReplacement = ' '); - //! Remove multi-line comments. The end of a line is - //! expected to be either NL or CR or NLCR. Multi-line comments - //! may not be nested (as in C). - //! \param szCommentStart The start sequence of the comment, e.g. "/*" - //! \param szCommentEnd The end sequence of the comment, e.g. "*/" - //! \param szBuffer Buffer to work with - //! \param chReplacement Character to be used as replacement - //! for commented lines. By default this is ' ' + /// @brief Remove multi-line comments. + /// The end of a line is expected to be either NL or CR or NLCR. Multi-line comments + /// may not be nested (as in C). + /// @param szCommentStart The start sequence of the comment, e.g. "/*" + /// @param szCommentEnd The end sequence of the comment, e.g. "*/" + /// @param szBuffer Buffer to work with + /// @param chReplacement Character to be used as replacement + /// for commented lines. By default this is ' ' static void RemoveMultiLineComments(const char* szCommentStart, const char* szCommentEnd,char* szBuffer, char chReplacement = ' '); }; + } // ! Assimp #endif // !! AI_REMOVE_COMMENTS_H_INC diff --git a/Dependencies/assimp/include/assimp/SGSpatialSort.h b/Dependencies/assimp/include/assimp/SGSpatialSort.h index 13a214d44..386a5c9a5 100644 --- a/Dependencies/assimp/include/assimp/SGSpatialSort.h +++ b/Dependencies/assimp/include/assimp/SGSpatialSort.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -namespace Assimp { +namespace Assimp { // ---------------------------------------------------------------------------------- /** Specialized version of SpatialSort to support smoothing groups diff --git a/Dependencies/assimp/include/assimp/SceneCombiner.h b/Dependencies/assimp/include/assimp/SceneCombiner.h index 790a18c2d..e0daa1df0 100644 --- a/Dependencies/assimp/include/assimp/SceneCombiner.h +++ b/Dependencies/assimp/include/assimp/SceneCombiner.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -82,32 +81,30 @@ namespace Assimp { * Describes to which node a scene must be attached to. */ struct AttachmentInfo { - AttachmentInfo() : - scene(nullptr), - attachToNode(nullptr) {} - - AttachmentInfo(aiScene *_scene, aiNode *_attachToNode) : - scene(_scene), attachToNode(_attachToNode) {} + AttachmentInfo() = default; + AttachmentInfo(aiScene *_scene, aiNode *_attachToNode) : scene(_scene), attachToNode(_attachToNode) { + // empty + } + ~AttachmentInfo() = default; - aiScene *scene; - aiNode *attachToNode; + aiScene *scene{nullptr}; + aiNode *attachToNode{nullptr}; }; // --------------------------------------------------------------------------- +/// @brief Helper data structure for SceneCombiner. struct NodeAttachmentInfo { - NodeAttachmentInfo() : - node(nullptr), - attachToNode(nullptr), - resolved(false), - src_idx(SIZE_MAX) {} - + NodeAttachmentInfo() = default; + ~NodeAttachmentInfo() = default; NodeAttachmentInfo(aiNode *_scene, aiNode *_attachToNode, size_t idx) : - node(_scene), attachToNode(_attachToNode), resolved(false), src_idx(idx) {} + node(_scene), attachToNode(_attachToNode), src_idx(idx) { + // empty + } - aiNode *node; - aiNode *attachToNode; - bool resolved; - size_t src_idx; + aiNode *node{nullptr}; + aiNode *attachToNode{nullptr}; + bool resolved{false}; + size_t src_idx{SIZE_MAX}; }; // --------------------------------------------------------------------------- @@ -140,7 +137,7 @@ struct NodeAttachmentInfo { */ #define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY 0x10 -typedef std::pair BoneSrcIndex; +using BoneSrcIndex = std::pair ; // --------------------------------------------------------------------------- /** @brief Helper data structure for SceneCombiner::MergeBones. @@ -190,12 +187,11 @@ struct SceneHelper { * and loaders (ie. LWS). */ class ASSIMP_API SceneCombiner { +public: // class cannot be instanced SceneCombiner() = delete; - ~SceneCombiner() = delete; -public: // ------------------------------------------------------------------- /** Merges two or more scenes. * @@ -275,8 +271,8 @@ class ASSIMP_API SceneCombiner { /** Builds a list of uniquely named bones in a mesh list * * @param asBones Receives the output list - * @param it First mesh to be processed - * @param end Last mesh to be processed + * @param it First mesh to be processed + * @param end Last mesh to be processed */ static void BuildUniqueBoneList(std::list &asBones, std::vector::const_iterator it, @@ -285,9 +281,9 @@ class ASSIMP_API SceneCombiner { // ------------------------------------------------------------------- /** Add a name prefix to all nodes in a scene. * - * @param Current node. This function is called recursively. + * @param node Current node. This function is called recursively. * @param prefix Prefix to be added to all nodes - * @param len STring length + * @param len String length */ static void AddNodePrefixes(aiNode *node, const char *prefix, unsigned int len); @@ -295,7 +291,7 @@ class ASSIMP_API SceneCombiner { // ------------------------------------------------------------------- /** Add an offset to all mesh indices in a node graph * - * @param Current node. This function is called recursively. + * @param node Current node. This function is called recursively. * @param offset Offset to be added to all mesh indices */ static void OffsetNodeMeshIndices(aiNode *node, unsigned int offset); @@ -310,7 +306,7 @@ class ASSIMP_API SceneCombiner { * the master graph), a scene is attached to the root of the master * graph (as an additional child node) * @duplicates List of duplicates. If elem[n] == n the scene is not - * a duplicate. Otherwise elem[n] links scene n to its first occurrence. + * a duplicate. Otherwise, elem[n] links scene n to its first occurrence. */ static void AttachToGraph(aiScene *master, std::vector &srcList); @@ -321,8 +317,9 @@ class ASSIMP_API SceneCombiner { // ------------------------------------------------------------------- /** Get a deep copy of a scene * - * @param dest Receives a pointer to the destination scene - * @param src Source scene - remains unmodified. + * @param dest Receives a pointer to the destination scene + * @param source Source scene - remains unmodified. + * @param allocate true for allocation a new scene */ static void CopyScene(aiScene **dest, const aiScene *source, bool allocate = true); diff --git a/Dependencies/assimp/include/assimp/SkeletonMeshBuilder.h b/Dependencies/assimp/include/assimp/SkeletonMeshBuilder.h index 620748632..4fa220504 100644 --- a/Dependencies/assimp/include/assimp/SkeletonMeshBuilder.h +++ b/Dependencies/assimp/include/assimp/SkeletonMeshBuilder.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/SmallVector.h b/Dependencies/assimp/include/assimp/SmallVector.h index 8e8e2db5f..185d5bf21 100644 --- a/Dependencies/assimp/include/assimp/SmallVector.h +++ b/Dependencies/assimp/include/assimp/SmallVector.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/SmoothingGroups.h b/Dependencies/assimp/include/assimp/SmoothingGroups.h index e77a8b2d9..3ef0aa184 100644 --- a/Dependencies/assimp/include/assimp/SmoothingGroups.h +++ b/Dependencies/assimp/include/assimp/SmoothingGroups.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/SmoothingGroups.inl b/Dependencies/assimp/include/assimp/SmoothingGroups.inl index 6de5ee997..468101c97 100644 --- a/Dependencies/assimp/include/assimp/SmoothingGroups.inl +++ b/Dependencies/assimp/include/assimp/SmoothingGroups.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/SpatialSort.h b/Dependencies/assimp/include/assimp/SpatialSort.h index 006234acb..2ed98278a 100644 --- a/Dependencies/assimp/include/assimp/SpatialSort.h +++ b/Dependencies/assimp/include/assimp/SpatialSort.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/StandardShapes.h b/Dependencies/assimp/include/assimp/StandardShapes.h index aad2ce395..6e5d27584 100644 --- a/Dependencies/assimp/include/assimp/StandardShapes.h +++ b/Dependencies/assimp/include/assimp/StandardShapes.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -57,7 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMesh; -namespace Assimp { +namespace Assimp { // --------------------------------------------------------------------------- /** \brief Helper class to generate vertex buffers for standard geometric diff --git a/Dependencies/assimp/include/assimp/StreamReader.h b/Dependencies/assimp/include/assimp/StreamReader.h index cc74bd652..73a3fe480 100644 --- a/Dependencies/assimp/include/assimp/StreamReader.h +++ b/Dependencies/assimp/include/assimp/StreamReader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -59,14 +59,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { // -------------------------------------------------------------------------------------------- -/** Wrapper class around IOStream to allow for consistent reading of binary data in both - * little and big endian format. Don't attempt to instance the template directly. Use - * StreamReaderLE to read from a little-endian stream and StreamReaderBE to read from a - * BE stream. The class expects that the endianness of any input data is known at - * compile-time, which should usually be true (#BaseImporter::ConvertToUTF8 implements - * runtime endianness conversions for text files). +/** + * @brief Wrapper class around IOStream to allow for consistent reading of binary data in both + * little and big endian format. * - * XXX switch from unsigned int for size types to size_t? or ptrdiff_t?*/ + * Don't attempt to instance the template directly. Use StreamReaderLE to read from a + * little-endian stream and StreamReaderBE to read from a BE stream. The class expects that + * the endianness of any input data is known at compile-time, which should usually be true + * (#BaseImporter::ConvertToUTF8 implements runtime endianness conversions for text files). + * + * XXX switch from unsigned int for size types to size_t? or ptrdiff_t? + */ // -------------------------------------------------------------------------------------------- template class StreamReader { diff --git a/Dependencies/assimp/include/assimp/StreamWriter.h b/Dependencies/assimp/include/assimp/StreamWriter.h index 32da6911b..57e9ff242 100644 --- a/Dependencies/assimp/include/assimp/StreamWriter.h +++ b/Dependencies/assimp/include/assimp/StreamWriter.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/StringComparison.h b/Dependencies/assimp/include/assimp/StringComparison.h index c4174c520..fb9f2fbf5 100644 --- a/Dependencies/assimp/include/assimp/StringComparison.h +++ b/Dependencies/assimp/include/assimp/StringComparison.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/StringUtils.h b/Dependencies/assimp/include/assimp/StringUtils.h index 4002d2daf..5f62ef743 100644 --- a/Dependencies/assimp/include/assimp/StringUtils.h +++ b/Dependencies/assimp/include/assimp/StringUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/Subdivision.h b/Dependencies/assimp/include/assimp/Subdivision.h index 75f44cbb5..1c0362166 100644 --- a/Dependencies/assimp/include/assimp/Subdivision.h +++ b/Dependencies/assimp/include/assimp/Subdivision.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -53,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiMesh; -namespace Assimp { +namespace Assimp { // ------------------------------------------------------------------------------ /** Helper class to evaluate subdivision surfaces. Different algorithms diff --git a/Dependencies/assimp/include/assimp/TinyFormatter.h b/Dependencies/assimp/include/assimp/TinyFormatter.h index 387fc86b6..9d58a956b 100644 --- a/Dependencies/assimp/include/assimp/TinyFormatter.h +++ b/Dependencies/assimp/include/assimp/TinyFormatter.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/Vertex.h b/Dependencies/assimp/include/assimp/Vertex.h index c0a6a836a..e22d290a4 100644 --- a/Dependencies/assimp/include/assimp/Vertex.h +++ b/Dependencies/assimp/include/assimp/Vertex.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -111,6 +111,7 @@ struct Vertex { aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS]; Vertex() = default; + ~Vertex() = default; // ---------------------------------------------------------------------------- /** Extract a particular vertex from a mesh and interleave all components */ diff --git a/Dependencies/assimp/include/assimp/XMLTools.h b/Dependencies/assimp/include/assimp/XMLTools.h index fa27af134..c2b898a1a 100644 --- a/Dependencies/assimp/include/assimp/XMLTools.h +++ b/Dependencies/assimp/include/assimp/XMLTools.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/XmlParser.h b/Dependencies/assimp/include/assimp/XmlParser.h index 800d2e993..98dbc1d69 100644 --- a/Dependencies/assimp/include/assimp/XmlParser.h +++ b/Dependencies/assimp/include/assimp/XmlParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "IOStream.hpp" #include +#include #include #include @@ -60,13 +61,14 @@ struct find_node_by_name_predicate { /// @brief The default constructor. find_node_by_name_predicate() = default; - - std::string mName; ///< The name to find. - find_node_by_name_predicate(const std::string &name) : - mName(name) { + /// @brief Constructor with the predicate name + /// @param name The name. + explicit find_node_by_name_predicate(const std::string &name) : mName(name) { // empty } + std::string mName; ///< The name to find. + bool operator()(pugi::xml_node node) const { return node.name() == mName; } @@ -77,6 +79,9 @@ struct find_node_by_name_predicate { template struct NodeConverter { public: + /// @brief Will convert the attribute from the node to an int. + /// @param node The XML-node. + /// @param attribName The name of the attribute. static int to_int(TNodeType &node, const char *attribName) { ai_assert(nullptr != attribName); return node.attribute(attribName).to_int(); @@ -128,6 +133,11 @@ class TXmlParser { /// @return true, if the parsing was successful, false if not. bool parse(IOStream *stream); + /// @brief Will parse an xml-file from a stringstream. + /// @param[in] str The input istream (note: not "const" to match pugixml param) + /// @return true, if the parsing was successful, false if not. + bool parse(std::istream &inStream); + /// @brief Will return true if a root node is there. /// @return true in case of an existing root. bool hasRoot() const; @@ -311,7 +321,23 @@ bool TXmlParser::parse(IOStream *stream) { mDoc = new pugi::xml_document(); // load_string assumes native encoding (aka always utf-8 per build options) //pugi::xml_parse_result parse_result = mDoc->load_string(&mData[0], pugi::parse_full); - pugi::xml_parse_result parse_result = mDoc->load_buffer(&mData[0], mData.size(), pugi::parse_full); + pugi::xml_parse_result parse_result = mDoc->load_buffer(&mData[0], mData.size(), pugi::parse_full); + if (parse_result.status == pugi::status_ok) { + return true; + } + + ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset); + + return false; +} + +template +bool TXmlParser::parse(std::istream &inStream) { + if (hasRoot()) { + clear(); + } + mDoc = new pugi::xml_document(); + pugi::xml_parse_result parse_result = mDoc->load(inStream); if (parse_result.status == pugi::status_ok) { return true; } diff --git a/Dependencies/assimp/include/assimp/ZipArchiveIOSystem.h b/Dependencies/assimp/include/assimp/ZipArchiveIOSystem.h index 8145e98f8..078cdef9e 100644 --- a/Dependencies/assimp/include/assimp/ZipArchiveIOSystem.h +++ b/Dependencies/assimp/include/assimp/ZipArchiveIOSystem.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -57,12 +57,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { +/// @brief This class implements a ZIP archive base file system. class ZipArchiveIOSystem : public IOSystem { public: - //! Open a Zip using the proffered IOSystem + /// @brief The class constructor with the zip-archive name. + /// @param pIOHandler The io handler + /// @param pFilename The archive name + /// @param pMode The access state ZipArchiveIOSystem(IOSystem* pIOHandler, const char *pFilename, const char* pMode = "r"); + + /// @brief The class constructor with the zip-archive name. + /// @param pIOHandler The io handler + /// @param pFilename The archive name + /// @param pMode The access state ZipArchiveIOSystem(IOSystem* pIOHandler, const std::string& rFilename, const char* pMode = "r"); - virtual ~ZipArchiveIOSystem() override; + + /// @brief The class destructor. + ~ZipArchiveIOSystem() override; + bool Exists(const char* pFilename) const override; char getOsSeparator() const override; IOStream* Open(const char* pFilename, const char* pMode = "rb") override; diff --git a/Dependencies/assimp/include/assimp/aabb.h b/Dependencies/assimp/include/assimp/aabb.h index bd78e67a6..51a583e1d 100644 --- a/Dependencies/assimp/include/assimp/aabb.h +++ b/Dependencies/assimp/include/assimp/aabb.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/ai_assert.h b/Dependencies/assimp/include/assimp/ai_assert.h index e4d43f31c..3e5527a51 100644 --- a/Dependencies/assimp/include/assimp/ai_assert.h +++ b/Dependencies/assimp/include/assimp/ai_assert.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/anim.h b/Dependencies/assimp/include/assimp/anim.h index a6b368c02..ae8452a01 100644 --- a/Dependencies/assimp/include/assimp/anim.h +++ b/Dependencies/assimp/include/assimp/anim.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/camera.h b/Dependencies/assimp/include/assimp/camera.h index b8ea59927..6819b7449 100644 --- a/Dependencies/assimp/include/assimp/camera.h +++ b/Dependencies/assimp/include/assimp/camera.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/cexport.h b/Dependencies/assimp/include/assimp/cexport.h index 175fe5ea4..d6c090166 100644 --- a/Dependencies/assimp/include/assimp/cexport.h +++ b/Dependencies/assimp/include/assimp/cexport.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/cfileio.h b/Dependencies/assimp/include/assimp/cfileio.h index bd971957c..c64066f62 100644 --- a/Dependencies/assimp/include/assimp/cfileio.h +++ b/Dependencies/assimp/include/assimp/cfileio.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/cimport.h b/Dependencies/assimp/include/assimp/cimport.h index b793eca44..01d789b1b 100644 --- a/Dependencies/assimp/include/assimp/cimport.h +++ b/Dependencies/assimp/include/assimp/cimport.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -170,10 +170,11 @@ ASSIMP_API const C_STRUCT aiScene *aiImportFileExWithProperties( // -------------------------------------------------------------------------------- /** Reads the given file from a given memory buffer, * - * If the call succeeds, the contents of the file are returned as a pointer to an - * aiScene object. The returned data is intended to be read-only, the importer keeps - * ownership of the data and will destroy it upon destruction. If the import fails, - * NULL is returned. + * If the call succeeds, the imported data is returned in an aiScene structure. + * The data is intended to be read-only, it stays property of the ASSIMP + * library and will be stable until aiReleaseImport() is called. After you're + * done with it, call aiReleaseImport() to free the resources associated with + * this file. If the import fails, NULL is returned. * A human-readable error description can be retrieved by calling aiGetErrorString(). * @param pBuffer Pointer to the file data * @param pLength Length of pBuffer, in bytes diff --git a/Dependencies/assimp/include/assimp/color4.h b/Dependencies/assimp/include/assimp/color4.h index 88900897e..8440eb0ee 100644 --- a/Dependencies/assimp/include/assimp/color4.h +++ b/Dependencies/assimp/include/assimp/color4.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/color4.inl b/Dependencies/assimp/include/assimp/color4.inl index 7fd067758..ddacbb0fa 100644 --- a/Dependencies/assimp/include/assimp/color4.inl +++ b/Dependencies/assimp/include/assimp/color4.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/commonMetaData.h b/Dependencies/assimp/include/assimp/commonMetaData.h index 53d2f37aa..31b185fa4 100644 --- a/Dependencies/assimp/include/assimp/commonMetaData.h +++ b/Dependencies/assimp/include/assimp/commonMetaData.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/defs.h b/Dependencies/assimp/include/assimp/defs.h index 38792c1c1..406deb5fb 100644 --- a/Dependencies/assimp/include/assimp/defs.h +++ b/Dependencies/assimp/include/assimp/defs.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -49,14 +49,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_DEFINES_H_INC #ifdef __GNUC__ -#pragma GCC system_header +# pragma GCC system_header #endif #include ////////////////////////////////////////////////////////////////////////// -/* Define ASSIMP_BUILD_NO_XX_IMPORTER to disable a specific - * file format loader. The loader is be excluded from the +/** + * @brief Define ASSIMP_BUILD_NO_XX_IMPORTER to disable a specific file format loader. + * + * The loader is be excluded from the * build in this case. 'XX' stands for the most common file * extension of the file format. E.g.: * ASSIMP_BUILD_NO_X_IMPORTER disables the X loader. @@ -76,34 +78,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ////////////////////////////////////////////////////////////////////////// #ifndef ASSIMP_BUILD_NO_COMPRESSED_X -#define ASSIMP_BUILD_NEED_Z_INFLATE +# define ASSIMP_BUILD_NEED_Z_INFLATE #endif #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND -#define ASSIMP_BUILD_NEED_Z_INFLATE +# define ASSIMP_BUILD_NEED_Z_INFLATE #endif #ifndef ASSIMP_BUILD_NO_COMPRESSED_IFC -#define ASSIMP_BUILD_NEED_Z_INFLATE -#define ASSIMP_BUILD_NEED_UNZIP +# define ASSIMP_BUILD_NEED_Z_INFLATE +# define ASSIMP_BUILD_NEED_UNZIP #endif #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER -#define ASSIMP_BUILD_NEED_Z_INFLATE -#define ASSIMP_BUILD_NEED_UNZIP +# define ASSIMP_BUILD_NEED_Z_INFLATE +# define ASSIMP_BUILD_NEED_UNZIP #endif -// We need those constants, workaround for any platforms where nobody defined them yet +/** + * @brief We need those constants, workaround for any platforms where nobody defined them yet. + */ #if (!defined SIZE_MAX) -#define SIZE_MAX (~((size_t)0)) +# define SIZE_MAX (~((size_t)0)) #endif -/*#if (!defined UINT_MAX) -#define UINT_MAX (~((unsigned int)0)) -#endif*/ - ////////////////////////////////////////////////////////////////////////// -/* Define ASSIMP_BUILD_NO_XX_PROCESS to disable a specific +/** @brief Define ASSIMP_BUILD_NO_XX_PROCESS to disable a specific + * * post processing step. This is the current list of process names ('XX'): * CALCTANGENTS * JOINVERTICES @@ -134,46 +135,53 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OPTIMIZEGRAPH * GENENTITYMESHES * FIXTEXTUREPATHS - * GENBOUNDINGBOXES */ -////////////////////////////////////////////////////////////////////////// - -#ifdef _WIN32 -#undef ASSIMP_API -////////////////////////////////////////////////////////////////////////// -/* Define 'ASSIMP_BUILD_DLL_EXPORT' to build a DLL of the library */ -////////////////////////////////////////////////////////////////////////// -#ifdef ASSIMP_BUILD_DLL_EXPORT -#define ASSIMP_API __declspec(dllexport) -#define ASSIMP_API_WINONLY __declspec(dllexport) + * GENBOUNDINGBOXES + */ ////////////////////////////////////////////////////////////////////////// -/* Define 'ASSIMP_DLL' before including Assimp to link to ASSIMP in - * an external DLL under Windows. Default is static linkage. */ +/** @brief Define 'ASSIMP_BUILD_DLL_EXPORT' to build a DLL of the library + * + * Define 'ASSIMP_DLL' before including Assimp to link to ASSIMP in + * an external DLL under Windows. Default is static linkage. + */ ////////////////////////////////////////////////////////////////////////// -#elif (defined ASSIMP_DLL) -#define ASSIMP_API __declspec(dllimport) -#define ASSIMP_API_WINONLY __declspec(dllimport) -#else -#define ASSIMP_API -#define ASSIMP_API_WINONLY -#endif -#elif defined(SWIG) -/* Do nothing, the relevant defines are all in AssimpSwigPort.i */ +#ifdef _WIN32 +# undef ASSIMP_API +# ifdef ASSIMP_BUILD_DLL_EXPORT +# define ASSIMP_API __declspec(dllexport) +# define ASSIMP_API_WINONLY __declspec(dllexport) +# elif (defined ASSIMP_DLL) +# define ASSIMP_API __declspec(dllimport) +# define ASSIMP_API_WINONLY __declspec(dllimport) +# else +# define ASSIMP_API +# define ASSIMP_API_WINONLY +# endif #else -#define ASSIMP_API __attribute__((visibility("default"))) -#define ASSIMP_API_WINONLY +# define ASSIMP_API __attribute__((visibility("default"))) +# define ASSIMP_API_WINONLY #endif // _WIN32 +/** + * @brief Helper macros + * + * @def AI_FORCE_INLINE + * @brief Force the compiler to inline a function, if possible + * + * @def AI_WONT_RETURN + * @brief Tells the compiler that a function never returns. + * + * Used in code analysis to skip dead paths (e.g. after an assertion evaluated to false). + */ #ifdef _MSC_VER - #pragma warning(disable : 4521 4512 4714 4127 4351 4510) + #pragma warning(disable : 4521 4512 4714 4127 4510) + #if _MSC_VER < 1900 + #pragma warning(disable : 4351) + #endif #ifdef ASSIMP_BUILD_DLL_EXPORT #pragma warning(disable : 4251) #endif - /* Force the compiler to inline a function, if possible */ #define AI_FORCE_INLINE inline - - /* Tells the compiler that a function never returns. Used in code analysis - * to skip dead paths (e.g. after an assertion evaluated to false). */ #define AI_WONT_RETURN __declspec(noreturn) #elif defined(SWIG) /* Do nothing, the relevant defines are all in AssimpSwigPort.i */ @@ -223,29 +231,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * to typedef all structs/enums. */ ////////////////////////////////////////////////////////////////////////// #if (defined ASSIMP_DOXYGEN_BUILD) -#define C_STRUCT -#define C_ENUM +# define C_STRUCT +# define C_ENUM #else -#define C_STRUCT struct -#define C_ENUM enum +# define C_STRUCT struct +# define C_ENUM enum #endif #endif #if (defined(__BORLANDC__) || defined(__BCPLUSPLUS__)) -#error Currently, Borland is unsupported. Feel free to port Assimp. +# error Currently, Borland is unsupported. Feel free to port Assimp. #endif ////////////////////////////////////////////////////////////////////////// -/* Define ASSIMP_BUILD_SINGLETHREADED to compile assimp - * without threading support. The library doesn't utilize - * threads then and is itself not threadsafe. */ +/** + * Define ASSIMP_BUILD_SINGLETHREADED to compile assimp + * without threading support. The library doesn't utilize + * threads then and is itself not threadsafe. + */ ////////////////////////////////////////////////////////////////////////// #ifndef ASSIMP_BUILD_SINGLETHREADED -#define ASSIMP_BUILD_SINGLETHREADED +# define ASSIMP_BUILD_SINGLETHREADED #endif #if defined(_DEBUG) || !defined(NDEBUG) -#define ASSIMP_BUILD_DEBUG +# define ASSIMP_BUILD_DEBUG #endif ////////////////////////////////////////////////////////////////////////// @@ -291,55 +301,74 @@ typedef unsigned int ai_uint; #ifdef __cplusplus constexpr ai_real ai_epsilon = (ai_real) 1e-6; #else -#define ai_epsilon ((ai_real)1e-6) +# define ai_epsilon ((ai_real)1e-6) #endif -/* Support for big-endian builds */ +/** + * @brief Support for big-endian builds + * + * This will check which byte ordering is used on the target architecture. + */ #if defined(__BYTE_ORDER__) -#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#if !defined(__BIG_ENDIAN__) -#define __BIG_ENDIAN__ -#endif -#else /* little endian */ -#if defined(__BIG_ENDIAN__) -#undef __BIG_ENDIAN__ -#endif -#endif +# if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +# if !defined(__BIG_ENDIAN__) +# define __BIG_ENDIAN__ +# endif +# else /* little endian */ +# if defined(__BIG_ENDIAN__) +# undef __BIG_ENDIAN__ +# endif +# endif #endif #if defined(__BIG_ENDIAN__) -#define AI_BUILD_BIG_ENDIAN +# define AI_BUILD_BIG_ENDIAN #endif /** - * To avoid running out of memory + * @brief To avoid running out of memory + * * This can be adjusted for specific use cases * It's NOT a total limit, just a limit for individual allocations */ #define AI_MAX_ALLOC(type) ((256U * 1024 * 1024) / sizeof(type)) #ifndef _MSC_VER -#if __cplusplus >= 201103L // C++11 -#define AI_NO_EXCEPT noexcept -#else -#define AI_NO_EXCEPT -#endif +# if __cplusplus >= 201103L // C++11 +# define AI_NO_EXCEPT noexcept +# else +# define AI_NO_EXCEPT +# endif #else -#if (_MSC_VER >= 1915) -#define AI_NO_EXCEPT noexcept -#else -#define AI_NO_EXCEPT -#endif +# if (_MSC_VER >= 1915) +# define AI_NO_EXCEPT noexcept +# else +# define AI_NO_EXCEPT +# endif #endif // _MSC_VER /** - * Helper macro to set a pointer to NULL in debug builds + * @brief Helper macro to set a pointer to NULL in debug builds */ #if (defined ASSIMP_BUILD_DEBUG) -#define AI_DEBUG_INVALIDATE_PTR(x) x = NULL; +# define AI_DEBUG_INVALIDATE_PTR(x) x = NULL; #else -#define AI_DEBUG_INVALIDATE_PTR(x) +# define AI_DEBUG_INVALIDATE_PTR(x) #endif #define AI_COUNT_OF(X) (sizeof(X) / sizeof((X)[0])) +/** + * @brief Will mark functions or classes as deprecated. + * + * Deprecation means that we will remove this function, class or methods in the next m + */ +#if defined(__GNUC__) || defined(__clang__) +# define AI_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define AI_DEPRECATED __declspec(deprecated) +#else +# pragma message("WARNING: You need to implement DEPRECATED for this compiler") +# define AI_DEPRECATED +#endif + #endif // !! AI_DEFINES_H_INC diff --git a/Dependencies/assimp/include/assimp/importerdesc.h b/Dependencies/assimp/include/assimp/importerdesc.h index e26751049..c64403f07 100644 --- a/Dependencies/assimp/include/assimp/importerdesc.h +++ b/Dependencies/assimp/include/assimp/importerdesc.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/light.h b/Dependencies/assimp/include/assimp/light.h index 3233cec70..d2fbccd14 100644 --- a/Dependencies/assimp/include/assimp/light.h +++ b/Dependencies/assimp/include/assimp/light.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/material.h b/Dependencies/assimp/include/assimp/material.h index 244c6607e..80d963f3e 100644 --- a/Dependencies/assimp/include/assimp/material.h +++ b/Dependencies/assimp/include/assimp/material.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -334,12 +334,29 @@ enum aiTextureType { aiTextureType_MAYA_SPECULAR_COLOR = 24, aiTextureType_MAYA_SPECULAR_ROUGHNESS = 25, + /** Anisotropy + * Simulates a surface with directional properties + */ + aiTextureType_ANISOTROPY = 26, + + /** + * gltf material declarations + * Refs: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#metallic-roughness-material + * "textures for metalness and roughness properties are packed together in a single + * texture called metallicRoughnessTexture. Its green channel contains roughness + * values and its blue channel contains metalness values..." + * https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_material_pbrmetallicroughness_metallicroughnesstexture + * "The metalness values are sampled from the B channel. The roughness values are + * sampled from the G channel..." + */ + aiTextureType_GLTF_METALLIC_ROUGHNESS = 27, + #ifndef SWIG _aiTextureType_Force32Bit = INT_MAX #endif }; -#define AI_TEXTURE_TYPE_MAX aiTextureType_MAYA_SPECULAR_ROUGHNESS +#define AI_TEXTURE_TYPE_MAX aiTextureType_GLTF_METALLIC_ROUGHNESS // ------------------------------------------------------------------------------- /** @@ -438,7 +455,7 @@ enum aiShadingMode { }; // --------------------------------------------------------------------------- -/** +/** * @brief Defines some mixed flags for a particular texture. * * Usually you'll instruct your cg artists how textures have to look like ... @@ -478,7 +495,7 @@ enum aiTextureFlags { }; // --------------------------------------------------------------------------- -/** +/** * @brief Defines alpha-blend flags. * * If you're familiar with OpenGL or D3D, these flags aren't new to you. @@ -523,7 +540,7 @@ enum aiBlendMode { #include "./Compiler/pushpack1.h" // --------------------------------------------------------------------------- -/** +/** * @brief Defines how an UV channel is transformed. * * This is just a helper structure for the #AI_MATKEY_UVTRANSFORM key. @@ -568,7 +585,7 @@ struct aiUVTransform { //! @cond AI_DOX_INCLUDE_INTERNAL // --------------------------------------------------------------------------- -/** +/** * @brief A very primitive RTTI system for the contents of material properties. */ enum aiPropertyTypeInfo { @@ -701,7 +718,7 @@ struct aiMaterialProperty { * Material data is stored using a key-value structure. A single key-value * pair is called a 'material property'. C++ users should use the provided * member functions of aiMaterial to process material properties, C users -* have to stick with the aiMaterialGetXXX family of unbound functions. +* have to stick with the aiGetMaterialXXX family of unbound functions. * The library defines a set of standard keys (AI_MATKEY_XXX). */ #ifdef __cplusplus @@ -714,7 +731,7 @@ struct aiMaterial #ifdef __cplusplus public: - /** + /** * @brief The class constructor. */ aiMaterial(); @@ -1073,6 +1090,11 @@ extern "C" { #define AI_MATKEY_EMISSIVE_INTENSITY "$mat.emissiveIntensity", 0, 0 #define AI_MATKEY_USE_AO_MAP "$mat.useAOMap", 0, 0 +// Anisotropy +// ---------- +#define AI_MATKEY_ANISOTROPY_ROTATION "$mat.anisotropyRotation", 0, 0 +#define AI_MATKEY_ANISOTROPY_TEXTURE aiTextureType_ANISOTROPY, 0 + // --------------------------------------------------------------------------- // Pure key names for all texture-related properties //! @cond MATS_DOC_FULL @@ -1535,7 +1557,7 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialFloatArray( const char *pKey, unsigned int type, unsigned int index, - float *pOut, + ai_real *pOut, unsigned int *pMax); // --------------------------------------------------------------------------- @@ -1557,12 +1579,12 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialFloatArray( * @return Specifies whether the key has been found. If not, the output * float remains unmodified.*/ // --------------------------------------------------------------------------- -inline aiReturn aiGetMaterialFloat(const C_STRUCT aiMaterial *pMat, +static inline aiReturn aiGetMaterialFloat(const C_STRUCT aiMaterial *pMat, const char *pKey, unsigned int type, unsigned int index, - float *pOut) { - return aiGetMaterialFloatArray(pMat, pKey, type, index, pOut, (unsigned int *)0x0); + ai_real *pOut) { + return aiGetMaterialFloatArray(pMat, pKey, type, index, pOut, NULL); } // --------------------------------------------------------------------------- @@ -1582,12 +1604,12 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialIntegerArray(const C_STRUCT aiMaterial * * * See the sample for aiGetMaterialFloat for more information.*/ // --------------------------------------------------------------------------- -inline aiReturn aiGetMaterialInteger(const C_STRUCT aiMaterial *pMat, +static inline aiReturn aiGetMaterialInteger(const C_STRUCT aiMaterial *pMat, const char *pKey, unsigned int type, unsigned int index, int *pOut) { - return aiGetMaterialIntegerArray(pMat, pKey, type, index, pOut, (unsigned int *)0x0); + return aiGetMaterialIntegerArray(pMat, pKey, type, index, pOut, NULL); } // --------------------------------------------------------------------------- diff --git a/Dependencies/assimp/include/assimp/material.inl b/Dependencies/assimp/include/assimp/material.inl index 31dd438fe..d04fb713b 100644 --- a/Dependencies/assimp/include/assimp/material.inl +++ b/Dependencies/assimp/include/assimp/material.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -67,7 +67,7 @@ AI_FORCE_INLINE aiReturn aiMaterial::GetTexture( aiTextureType type, C_STRUCT aiString* path, aiTextureMapping* mapping /*= NULL*/, unsigned int* uvindex /*= NULL*/, - float* blend /*= NULL*/, + ai_real* blend /*= NULL*/, aiTextureOp* op /*= NULL*/, aiTextureMapMode* mapmode /*= NULL*/) const { return ::aiGetMaterialTexture(this,type,index,path,mapping,uvindex,blend,op,mapmode); @@ -191,7 +191,7 @@ AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type, } // --------------------------------------------------------------------------- AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx, float& pOut) const { + unsigned int idx, ai_real& pOut) const { return aiGetMaterialFloat(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- diff --git a/Dependencies/assimp/include/assimp/matrix3x3.h b/Dependencies/assimp/include/assimp/matrix3x3.h index a49394ea4..9992f78ab 100644 --- a/Dependencies/assimp/include/assimp/matrix3x3.h +++ b/Dependencies/assimp/include/assimp/matrix3x3.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/matrix3x3.inl b/Dependencies/assimp/include/assimp/matrix3x3.inl index c41a5a076..4f507aa77 100644 --- a/Dependencies/assimp/include/assimp/matrix3x3.inl +++ b/Dependencies/assimp/include/assimp/matrix3x3.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/matrix4x4.h b/Dependencies/assimp/include/assimp/matrix4x4.h index 861a7acef..de0b748b7 100644 --- a/Dependencies/assimp/include/assimp/matrix4x4.h +++ b/Dependencies/assimp/include/assimp/matrix4x4.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team @@ -73,11 +73,14 @@ template class aiQuaterniont; template class aiMatrix4x4t { public: - - /** set to identity */ + /** + * @brief Set to identity + * */ aiMatrix4x4t() AI_NO_EXCEPT; - /** construction from single values */ + /** + * @brief Construction from single values + * */ aiMatrix4x4t ( TReal _a1, TReal _a2, TReal _a3, TReal _a4, TReal _b1, TReal _b2, TReal _b3, TReal _b4, TReal _c1, TReal _c2, TReal _c3, TReal _c4, @@ -93,18 +96,18 @@ class aiMatrix4x4t { * @param position The position for the x,y,z axes */ aiMatrix4x4t(const aiVector3t& scaling, const aiQuaterniont& rotation, - const aiVector3t& position); + const aiVector3t& position); // array access operators - /** @fn TReal* operator[] (unsigned int p_iIndex) - * @param [in] p_iIndex - index of the row. - * @return pointer to pointed row. - */ - TReal* operator[] (unsigned int p_iIndex); - - /** @fn const TReal* operator[] (unsigned int p_iIndex) const - * @overload TReal* operator[] (unsigned int p_iIndex) - */ + /** @fn TReal* operator[] (unsigned int p_iIndex) + * @param [in] p_iIndex - index of the row. + * @return pointer to pointed row. + */ + TReal* operator[] (unsigned int p_iIndex); + + /** @fn const TReal* operator[] (unsigned int p_iIndex) const + * @overload TReal* operator[] (unsigned int p_iIndex) + */ const TReal* operator[] (unsigned int p_iIndex) const; // comparison operators @@ -132,8 +135,12 @@ class aiMatrix4x4t { * Beware, use (f != f) to check whether a TReal f is qnan. */ aiMatrix4x4t& Inverse(); - TReal Determinant() const; + // ------------------------------------------------------------------- + /** + * @brief Inverts the matrix if it is invertible. + */ + TReal Determinant() const; // ------------------------------------------------------------------- /** @brief Returns true of the matrix is the identity matrix. @@ -147,40 +154,38 @@ class aiMatrix4x4t { // ------------------------------------------------------------------- /** @brief Decompose a trafo matrix into its original components - * @param scaling Receives the output scaling for the x,y,z axes - * @param rotation Receives the output rotation as a hamilton - * quaternion + * @param scaling Receives the output scaling for the x,y,z axes + * @param rotation Receives the output rotation as a hamilton quaternion * @param position Receives the output position for the x,y,z axes */ void Decompose (aiVector3t& scaling, aiQuaterniont& rotation, aiVector3t& position) const; - // ------------------------------------------------------------------- - /** @fn void Decompose(aiVector3t& pScaling, aiVector3t& pRotation, aiVector3t& pPosition) const + // ------------------------------------------------------------------- + /** * @brief Decompose a trafo matrix into its original components. - * Thx to good FAQ at http://www.gamedev.ru/code/articles/faq_matrix_quat - * @param [out] pScaling - Receives the output scaling for the x,y,z axes. + * Thx to good FAQ at http://www.gamedev.ru/code/articles/faq_matrix_quat + * @param [out] pScaling - Receives the output scaling for the x,y,z axes. * @param [out] pRotation - Receives the output rotation as a Euler angles. * @param [out] pPosition - Receives the output position for the x,y,z axes. */ void Decompose(aiVector3t& pScaling, aiVector3t& pRotation, aiVector3t& pPosition) const; - // ------------------------------------------------------------------- - /** @fn void Decompose(aiVector3t& pScaling, aiVector3t& pRotationAxis, TReal& pRotationAngle, aiVector3t& pPosition) const + // ------------------------------------------------------------------- + /** * @brief Decompose a trafo matrix into its original components - * Thx to good FAQ at http://www.gamedev.ru/code/articles/faq_matrix_quat - * @param [out] pScaling - Receives the output scaling for the x,y,z axes. - * @param [out] pRotationAxis - Receives the output rotation axis. - * @param [out] pRotationAngle - Receives the output rotation angle for @ref pRotationAxis. - * @param [out] pPosition - Receives the output position for the x,y,z axes. + * Thx to good FAQ at http://www.gamedev.ru/code/articles/faq_matrix_quat + * @param [out] pScaling - Receives the output scaling for the x,y,z axes. + * @param [out] pRotationAxis - Receives the output rotation axis. + * @param [out] pRotationAngle - Receives the output rotation angle for @ref pRotationAxis. + * @param [out] pPosition - Receives the output position for the x,y,z axes. */ void Decompose(aiVector3t& pScaling, aiVector3t& pRotationAxis, TReal& pRotationAngle, aiVector3t& pPosition) const; // ------------------------------------------------------------------- /** @brief Decompose a trafo matrix with no scaling into its * original components - * @param rotation Receives the output rotation as a hamilton - * quaternion + * @param rotation Receives the output rotation as a hamilton quaternion * @param position Receives the output position for the x,y,z axes */ void DecomposeNoScaling (aiQuaterniont& rotation, @@ -197,7 +202,7 @@ class aiMatrix4x4t { // ------------------------------------------------------------------- /** @brief Returns a rotation matrix for a rotation around the x axis - * @param a Rotation angle, in radians + * @param a Rotation angle, in radians * @param out Receives the output matrix * @return Reference to the output matrix */ @@ -205,7 +210,7 @@ class aiMatrix4x4t { // ------------------------------------------------------------------- /** @brief Returns a rotation matrix for a rotation around the y axis - * @param a Rotation angle, in radians + * @param a Rotation angle, in radians * @param out Receives the output matrix * @return Reference to the output matrix */ diff --git a/Dependencies/assimp/include/assimp/matrix4x4.inl b/Dependencies/assimp/include/assimp/matrix4x4.inl index 56f7296e5..95e2b47ae 100644 --- a/Dependencies/assimp/include/assimp/matrix4x4.inl +++ b/Dependencies/assimp/include/assimp/matrix4x4.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/mesh.h b/Dependencies/assimp/include/assimp/mesh.h index da81cc24c..abe35f1f0 100644 --- a/Dependencies/assimp/include/assimp/mesh.h +++ b/Dependencies/assimp/include/assimp/mesh.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma GCC system_header #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) && _MSC_VER < 1900 #pragma warning(disable : 4351) #endif // _MSC_VER @@ -660,7 +660,7 @@ struct aiMesh { /** * @brief Vertex positions. - * + * * This array is always present in a mesh. The array is * mNumVertices in size. */ @@ -668,7 +668,7 @@ struct aiMesh { /** * @brief Vertex normals. - * + * * The array contains normalized vectors, nullptr if not present. * The array is mNumVertices in size. Normals are undefined for * point and line primitives. A mesh consisting of points and @@ -692,7 +692,7 @@ struct aiMesh { /** * @brief Vertex tangents. - * + * * The tangent of a vertex points in the direction of the positive * X texture axis. The array contains normalized vectors, nullptr if * not present. The array is mNumVertices in size. A mesh consisting @@ -708,7 +708,7 @@ struct aiMesh { /** * @brief Vertex bitangents. - * + * * The bitangent of a vertex points in the direction of the positive * Y texture axis. The array contains normalized vectors, nullptr if not * present. The array is mNumVertices in size. @@ -719,7 +719,7 @@ struct aiMesh { /** * @brief Vertex color sets. - * + * * A mesh may contain 0 to #AI_MAX_NUMBER_OF_COLOR_SETS vertex * colors per vertex. nullptr if not present. Each array is * mNumVertices in size if present. @@ -728,7 +728,7 @@ struct aiMesh { /** * @brief Vertex texture coordinates, also known as UV channels. - * + * * A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS channels per * vertex. Used and unused (nullptr) channels may go in any order. * The array is mNumVertices in size. @@ -737,7 +737,7 @@ struct aiMesh { /** * @brief Specifies the number of components for a given UV channel. - * + * * Up to three channels are supported (UVW, for accessing volume * or cube maps). If the value is 2 for a given channel n, the * component p.z of mTextureCoords[n][p] is set to 0.0f. @@ -748,7 +748,7 @@ struct aiMesh { /** * @brief The faces the mesh is constructed from. - * + * * Each face refers to a number of vertices by their indices. * This array is always present in a mesh, its size is given * in mNumFaces. If the #AI_SCENE_FLAGS_NON_VERBOSE_FORMAT @@ -763,7 +763,7 @@ struct aiMesh { /** * @brief The bones of this mesh. - * + * * A bone consists of a name by which it can be found in the * frame hierarchy and a set of vertex weights. */ @@ -771,7 +771,7 @@ struct aiMesh { /** * @brief The material used by this mesh. - * + * * A mesh uses only a single material. If an imported model uses * multiple materials, the import splits up the mesh. Use this value * as index into the scene's material list. @@ -918,7 +918,7 @@ struct aiMesh { } //! @brief Check whether the mesh contains tangent and bitangent vectors. - //! + //! //! It is not possible that it contains tangents and no bitangents //! (or the other way round). The existence of one of them //! implies that the second is there, too. @@ -934,7 +934,7 @@ struct aiMesh { if (index >= AI_MAX_NUMBER_OF_COLOR_SETS) { return false; } - return mColors[index] != nullptr && mNumVertices > 0; + return mColors[index] != nullptr && mNumVertices > 0; } //! @brief Check whether the mesh contains a texture coordinate set diff --git a/Dependencies/assimp/include/assimp/metadata.h b/Dependencies/assimp/include/assimp/metadata.h index 4fd4adf7e..1924c8ea5 100644 --- a/Dependencies/assimp/include/assimp/metadata.h +++ b/Dependencies/assimp/include/assimp/metadata.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/pbrmaterial.h b/Dependencies/assimp/include/assimp/pbrmaterial.h index 172d2b8cb..b481c7c87 100644 --- a/Dependencies/assimp/include/assimp/pbrmaterial.h +++ b/Dependencies/assimp/include/assimp/pbrmaterial.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/postprocess.h b/Dependencies/assimp/include/assimp/postprocess.h index 4fcbbea37..bb75174cf 100644 --- a/Dependencies/assimp/include/assimp/postprocess.h +++ b/Dependencies/assimp/include/assimp/postprocess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -506,7 +505,7 @@ enum aiPostProcessSteps * * Output UV coordinate system: * @code - * 0y|0y ---------- 1x|0y + * 0x|0y ---------- 1x|0y * | | * | | * | | diff --git a/Dependencies/assimp/include/assimp/qnan.h b/Dependencies/assimp/include/assimp/qnan.h index 2c071320f..94c6f606d 100644 --- a/Dependencies/assimp/include/assimp/qnan.h +++ b/Dependencies/assimp/include/assimp/qnan.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team @@ -70,9 +70,15 @@ union _IEEESingle { float Float; struct { +#if (defined AI_BUILD_BIG_ENDIAN) + uint32_t Sign : 1; + uint32_t Exp : 8; + uint32_t Frac : 23; +#else uint32_t Frac : 23; uint32_t Exp : 8; uint32_t Sign : 1; +#endif } IEEE; }; @@ -83,9 +89,15 @@ union _IEEEDouble { double Double; struct { +#if (defined AI_BUILD_BIG_ENDIAN) + uint64_t Sign : 1; + uint64_t Exp : 11; + uint64_t Frac : 52; +#else uint64_t Frac : 52; uint64_t Exp : 11; uint64_t Sign : 1; +#endif } IEEE; }; diff --git a/Dependencies/assimp/include/assimp/quaternion.h b/Dependencies/assimp/include/assimp/quaternion.h index 457c650aa..afe5ea136 100644 --- a/Dependencies/assimp/include/assimp/quaternion.h +++ b/Dependencies/assimp/include/assimp/quaternion.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/quaternion.inl b/Dependencies/assimp/include/assimp/quaternion.inl index d3e391331..6d4d1addb 100644 --- a/Dependencies/assimp/include/assimp/quaternion.inl +++ b/Dependencies/assimp/include/assimp/quaternion.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team diff --git a/Dependencies/assimp/include/assimp/revision.h b/Dependencies/assimp/include/assimp/revision.h index 6a3464b5e..175b9935e 100644 --- a/Dependencies/assimp/include/assimp/revision.h +++ b/Dependencies/assimp/include/assimp/revision.h @@ -4,9 +4,9 @@ #define GitVersion 0x0 #define GitBranch "" -#define VER_MAJOR 5 -#define VER_MINOR 4 -#define VER_PATCH 3 +#define VER_MAJOR 6 +#define VER_MINOR 0 +#define VER_PATCH 4 #define VER_BUILD 0 #define STR_HELP(x) #x @@ -18,7 +18,7 @@ #else #define VER_FILEVERSION_STR STR(VER_MAJOR) "." STR(VER_MINOR) "." STR(VER_PATCH) "." STR(VER_BUILD) " (Commit 0)" #endif -#define VER_COPYRIGHT_STR "\xA9 2006-2023" +#define VER_COPYRIGHT_STR "\xA9 2006-2026" #ifdef NDEBUG #define VER_ORIGINAL_FILENAME_STR "assimp-vc143-mt.dll" diff --git a/Dependencies/assimp/include/assimp/scene.h b/Dependencies/assimp/include/assimp/scene.h index f3701d600..11cfccae5 100644 --- a/Dependencies/assimp/include/assimp/scene.h +++ b/Dependencies/assimp/include/assimp/scene.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -165,6 +165,33 @@ struct ASSIMP_API aiNode { const aiNode* FindNode(const char* name) const; aiNode* FindNode(const char* name); + // ------------------------------------------------------------------------------------------------ + // Helper to find the node associated with a bone in the scene + const aiNode *findBoneNode(const aiBone *bone) const { + if (bone == nullptr) { + return nullptr; + } + + if (mName == bone->mName) { + return this; + } + + for (unsigned int i = 0; i < mNumChildren; ++i) { + aiNode *aChild = mChildren[i]; + if (aChild == nullptr) { + continue; + } + + const aiNode *foundFromChild = nullptr; + foundFromChild = aChild->findBoneNode(bone); + if (foundFromChild) { + return foundFromChild; + } + } + + return nullptr; + } + /** * @brief Will add new children. * @param numChildren Number of children to add. @@ -394,7 +421,8 @@ struct ASSIMP_API aiScene { return mAnimations != nullptr && mNumAnimations > 0; } - bool hasSkeletons() const { + //! Check whether the scene contains skeletons + inline bool HasSkeletons() const { return mSkeletons != nullptr && mNumSkeletons > 0; } @@ -441,6 +469,33 @@ struct ASSIMP_API aiScene { } return std::make_pair(nullptr, -1); } + + /** + * @brief Will try to locate a bone described by its name. + * + * @param name The name to look for. + * @return The bone as a pointer. + */ + inline aiBone *findBone(const aiString &name) const { + for (size_t m = 0; m < mNumMeshes; m++) { + aiMesh *mesh = mMeshes[m]; + if (mesh == nullptr) { + continue; + } + + for (size_t b = 0; b < mesh->mNumBones; b++) { + aiBone *bone = mesh->mBones[b]; + if (bone == nullptr) { + continue; + } + if (name == bone->mName) { + return bone; + } + } + } + return nullptr; + } + #endif // __cplusplus /** Internal data, do not touch */ diff --git a/Dependencies/assimp/include/assimp/texture.h b/Dependencies/assimp/include/assimp/texture.h index 53837fc86..76d3b084c 100644 --- a/Dependencies/assimp/include/assimp/texture.h +++ b/Dependencies/assimp/include/assimp/texture.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -169,7 +169,8 @@ struct aiTexture { /** Data of the texture. * * Points to an array of mWidth * mHeight aiTexel's. - * The format of the texture data is always ARGB8888 to + * The format of the texture data shall always be ARGB8888 if the texture-hint of the type is empty. + * If the hint is not empty you can interpret the format by looking into this hint. * make the implementation for user of the library as easy * as possible. If mHeight = 0 this is a pointer to a memory * buffer of size mWidth containing the compressed texture diff --git a/Dependencies/assimp/include/assimp/types.h b/Dependencies/assimp/include/assimp/types.h index 4b52b4ad5..e4cb64881 100644 --- a/Dependencies/assimp/include/assimp/types.h +++ b/Dependencies/assimp/include/assimp/types.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -118,7 +118,7 @@ extern "C" { /** Maximum dimension for strings, ASSIMP strings are zero terminated. */ #ifdef __cplusplus -static const size_t AI_MAXLEN = 1024; +static constexpr size_t AI_MAXLEN = 1024; #else #define AI_MAXLEN 1024 #endif @@ -243,7 +243,7 @@ struct aiColor3D { }; // !struct aiColor3D // ---------------------------------------------------------------------------------- -/** +/** * @brief Represents an UTF-8 string, zero byte terminated. * * The character set of an aiString is explicitly defined to be UTF-8. This Unicode @@ -267,7 +267,7 @@ struct aiColor3D { struct aiString { #ifdef __cplusplus /** Default constructor, the string is set to have zero length */ - aiString() AI_NO_EXCEPT : + aiString() AI_NO_EXCEPT : length(0), data{'\0'} { #ifdef ASSIMP_BUILD_DEBUG // Debug build: overwrite the string on its full length with ESC (27) @@ -283,7 +283,7 @@ struct aiString { memcpy(data, rOther.data, length); data[length] = '\0'; } - + /** Constructor from std::string */ explicit aiString(const std::string &pString) : length((ai_uint32)pString.length()), data{'\0'} { @@ -303,12 +303,21 @@ struct aiString { } /** Copy a const char* to the aiString */ - void Set(const char *sz) { - ai_int32 len = (ai_uint32)::strlen(sz); - if (len > static_cast(AI_MAXLEN - 1)) { - len = static_cast(AI_MAXLEN - 1); + void Set(const char *sz, size_t maxlen) { + if (sz == nullptr) { + return; + } + size_t len = 0; + for (size_t i=0; i AI_MAXLEN - 1) { + len = AI_MAXLEN - 1; + } + length = static_cast(len); memcpy(data, sz, len); data[len] = 0; } @@ -384,6 +393,14 @@ struct aiString { return data; } + /** + * @brief Will return true, if the string is empty. + * @return true if the string is empty, false if not + */ + bool Empty() const { + return length == 0; + } + #endif // !__cplusplus /** Binary length of the string excluding the terminal 0. This is NOT the diff --git a/Dependencies/assimp/include/assimp/vector2.h b/Dependencies/assimp/include/assimp/vector2.h index a8bfddba2..265d3ca89 100644 --- a/Dependencies/assimp/include/assimp/vector2.h +++ b/Dependencies/assimp/include/assimp/vector2.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/vector2.inl b/Dependencies/assimp/include/assimp/vector2.inl index a5592ea31..5286a4ae7 100644 --- a/Dependencies/assimp/include/assimp/vector2.inl +++ b/Dependencies/assimp/include/assimp/vector2.inl @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team - - +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/vector3.h b/Dependencies/assimp/include/assimp/vector3.h index c09fe9b08..e86d32a18 100644 --- a/Dependencies/assimp/include/assimp/vector3.h +++ b/Dependencies/assimp/include/assimp/vector3.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. @@ -85,6 +85,10 @@ class aiVector3t { /// @param o The instance to copy from. aiVector3t( const aiVector3t& o ) = default; + /// @brief The copy assignment operator. + /// @param o The instance to copy. + aiVector3t& operator=(const aiVector3t& o) = default; + /// @brief combined operators /// @brief The copy constructor. const aiVector3t& operator += (const aiVector3t& o); diff --git a/Dependencies/assimp/include/assimp/vector3.inl b/Dependencies/assimp/include/assimp/vector3.inl index c42e4cf32..cb1781bbf 100644 --- a/Dependencies/assimp/include/assimp/vector3.inl +++ b/Dependencies/assimp/include/assimp/vector3.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/include/assimp/version.h b/Dependencies/assimp/include/assimp/version.h index f7bcf5bbf..bc6bf4d72 100644 --- a/Dependencies/assimp/include/assimp/version.h +++ b/Dependencies/assimp/include/assimp/version.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2024, assimp team +Copyright (c) 2006-2026, assimp team All rights reserved. diff --git a/Dependencies/assimp/premake5.lua b/Dependencies/assimp/premake5.lua index d940af766..984f479ef 100644 --- a/Dependencies/assimp/premake5.lua +++ b/Dependencies/assimp/premake5.lua @@ -133,6 +133,9 @@ project 'assimp' 'ASSIMP_BUILD_NO_PBRT_EXPORTER' } + filter { "system:linux" } + defines { "HAVE_UNISTD_H" } + filter { "configurations:Debug" } defines { "DEBUG", "_DEBUG" } symbols "On" diff --git a/Sources/OvRendering/src/OvRendering/Resources/Parsers/AssimpParser.cpp b/Sources/OvRendering/src/OvRendering/Resources/Parsers/AssimpParser.cpp index d1bc07e4c..7a34b504b 100644 --- a/Sources/OvRendering/src/OvRendering/Resources/Parsers/AssimpParser.cpp +++ b/Sources/OvRendering/src/OvRendering/Resources/Parsers/AssimpParser.cpp @@ -125,7 +125,12 @@ namespace return false; } - void AddSkeletonNodeRecursive(OvRendering::Animation::Skeleton& p_skeleton, aiNode* p_node, int32_t p_parentIndex) + void AddSkeletonNodeRecursive( + OvRendering::Animation::Skeleton& p_skeleton, + aiNode* p_node, + int32_t p_parentIndex, + std::unordered_map* p_nodeIndexByPointer + ) { const auto currentIndex = static_cast(p_skeleton.nodes.size()); @@ -144,10 +149,19 @@ namespace }); p_skeleton.nodeByName.emplace(p_node->mName.C_Str(), currentIndex); + if (p_nodeIndexByPointer) + { + p_nodeIndexByPointer->emplace(p_node, currentIndex); + } for (uint32_t i = 0; i < p_node->mNumChildren; ++i) { - AddSkeletonNodeRecursive(p_skeleton, p_node->mChildren[i], static_cast(currentIndex)); + AddSkeletonNodeRecursive( + p_skeleton, + p_node->mChildren[i], + static_cast(currentIndex), + p_nodeIndexByPointer + ); } } @@ -637,6 +651,32 @@ namespace std::vector& p_animations ) { + auto findAnimationNodeIndex = [&](std::string_view p_name) -> std::optional + { + std::optional fallbackIndex; + for (uint32_t nodeIndex = 0; nodeIndex < p_skeleton.nodes.size(); ++nodeIndex) + { + const auto& node = p_skeleton.nodes[nodeIndex]; + if (node.name != p_name) + { + continue; + } + + if (!fallbackIndex.has_value()) + { + fallbackIndex = nodeIndex; + } + + // Prefer the node that is effectively used by the skinning bones. + if (node.boneIndex >= 0) + { + return nodeIndex; + } + } + + return fallbackIndex; + }; + p_animations.reserve(p_scene->mNumAnimations); for (uint32_t animIndex = 0; animIndex < p_scene->mNumAnimations; ++animIndex) @@ -656,7 +696,7 @@ namespace const auto* channel = animation->mChannels[channelIndex]; const std::string nodeName = channel->mNodeName.C_Str(); - if (auto foundNode = p_skeleton.FindNodeIndex(nodeName)) + if (auto foundNode = findAnimationNodeIndex(nodeName)) { OvRendering::Animation::NodeAnimationTrack track; track.nodeIndex = foundNode.value(); @@ -704,7 +744,8 @@ namespace OvRendering::Resources::Mesh* ProcessMesh( const aiMatrix4x4& p_transform, aiMesh* p_mesh, - OvRendering::Animation::Skeleton* p_skeleton + OvRendering::Animation::Skeleton* p_skeleton, + const std::unordered_map* p_nodeIndexByPointer ) { std::vector indices; @@ -767,6 +808,18 @@ namespace if (p_skeleton && p_mesh->HasBones()) { + const OvMaths::FMatrix4 meshGlobalBindTransform = ToMatrix4(p_transform); + std::optional meshGlobalBindTransformInverse; + + try + { + meshGlobalBindTransformInverse = OvMaths::FMatrix4::Inverse(meshGlobalBindTransform); + } + catch (...) + { + meshGlobalBindTransformInverse = std::nullopt; + } + std::vector vertices(p_mesh->mNumVertices); for (uint32_t i = 0; i < p_mesh->mNumVertices; ++i) { @@ -777,33 +830,61 @@ namespace { const aiBone* bone = p_mesh->mBones[boneID]; const std::string boneName = bone->mName.C_Str(); - const auto offsetMatrix = ToMatrix4(bone->mOffsetMatrix); + const OvMaths::FMatrix4 rawOffsetMatrix = ToMatrix4(bone->mOffsetMatrix); + + std::optional nodeIndex; +#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS + if (p_nodeIndexByPointer && bone->mNode) + { + if (const auto foundNode = p_nodeIndexByPointer->find(bone->mNode); foundNode != p_nodeIndexByPointer->end()) + { + nodeIndex = foundNode->second; + } + } +#endif - auto nodeIndex = p_skeleton->FindNodeIndex(boneName); if (!nodeIndex) + { + nodeIndex = p_skeleton->FindNodeIndex(boneName); + } + + if (!nodeIndex.has_value()) { OVLOG_WARNING("AssimpParser: Bone '" + boneName + "' has no matching node in hierarchy and will be ignored."); continue; } - uint32_t boneIndex = 0; + OvMaths::FMatrix4 normalizedOffsetMatrix = rawOffsetMatrix; + if (meshGlobalBindTransformInverse) + { + // Assimp FBX stores aiBone::mOffsetMatrix relative to the source mesh bind space. + // Our importer bakes mesh vertices to scene/root space via p_transform, so we must + // remap the offset to the same space for consistent skinning across sub-meshes. + normalizedOffsetMatrix = rawOffsetMatrix * meshGlobalBindTransformInverse.value(); + } - if (auto existing = p_skeleton->FindBoneIndex(boneName)) + uint32_t boneIndex = 0; + const int32_t existingNodeBoneIndex = p_skeleton->nodes[nodeIndex.value()].boneIndex; + if (existingNodeBoneIndex >= 0) { - boneIndex = existing.value(); + boneIndex = static_cast(existingNodeBoneIndex); } else { boneIndex = static_cast(p_skeleton->bones.size()); - p_skeleton->boneByName.emplace(boneName, boneIndex); + if (!p_skeleton->boneByName.contains(boneName)) + { + p_skeleton->boneByName.emplace(boneName, boneIndex); + } + p_skeleton->bones.push_back({ .name = boneName, .nodeIndex = nodeIndex.value(), - .offsetMatrix = offsetMatrix + .offsetMatrix = normalizedOffsetMatrix }); - } - p_skeleton->nodes[nodeIndex.value()].boneIndex = static_cast(boneIndex); + p_skeleton->nodes[nodeIndex.value()].boneIndex = static_cast(boneIndex); + } for (uint32_t weightID = 0; weightID < bone->mNumWeights; ++weightID) { @@ -832,14 +913,20 @@ namespace aiNode* p_node, const aiScene* p_scene, std::vector& p_meshes, - OvRendering::Animation::Skeleton* p_skeleton + OvRendering::Animation::Skeleton* p_skeleton, + const std::unordered_map* p_nodeIndexByPointer ) { const aiMatrix4x4 nodeTransform = p_transform * p_node->mTransformation; for (uint32_t i = 0; i < p_node->mNumMeshes; ++i) { - if (OvRendering::Resources::Mesh* result = ProcessMesh(nodeTransform, p_scene->mMeshes[p_node->mMeshes[i]], p_skeleton)) + if (OvRendering::Resources::Mesh* result = ProcessMesh( + nodeTransform, + p_scene->mMeshes[p_node->mMeshes[i]], + p_skeleton, + p_nodeIndexByPointer + )) { p_meshes.push_back(result); // The model will handle mesh destruction } @@ -847,7 +934,14 @@ namespace for (uint32_t i = 0; i < p_node->mNumChildren; ++i) { - ProcessNode(nodeTransform, p_node->mChildren[i], p_scene, p_meshes, p_skeleton); + ProcessNode( + nodeTransform, + p_node->mChildren[i], + p_scene, + p_meshes, + p_skeleton, + p_nodeIndexByPointer + ); } } } @@ -869,8 +963,13 @@ bool OvRendering::Resources::Parsers::AssimpParser::LoadModel( // Fix the flags to avoid conflicts/invalid scenarios. // This is a workaround, ideally the editor UI should not allow this to happen. p_parserFlags = FixFlags(p_parserFlags); + uint32_t assimpFlags = static_cast(p_parserFlags); - const aiScene* scene = import.ReadFile(p_fileName, static_cast(p_parserFlags)); +#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS + assimpFlags |= aiProcess_PopulateArmatureData; +#endif + + const aiScene* scene = import.ReadFile(p_fileName, assimpFlags); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { @@ -899,15 +998,28 @@ bool OvRendering::Resources::Parsers::AssimpParser::LoadModel( p_skeleton.reset(); p_animations.clear(); + std::unordered_map nodeIndexByPointer; if (hasBones) { p_skeleton.emplace(); - AddSkeletonNodeRecursive(p_skeleton.value(), scene->mRootNode, -1); - ProcessAnimations(scene, p_skeleton.value(), p_animations); + nodeIndexByPointer.reserve(512); + AddSkeletonNodeRecursive(p_skeleton.value(), scene->mRootNode, -1, &nodeIndexByPointer); } - ProcessNode(aiMatrix4x4{}, scene->mRootNode, scene, p_meshes, p_skeleton ? &p_skeleton.value() : nullptr); + ProcessNode( + aiMatrix4x4{}, + scene->mRootNode, + scene, + p_meshes, + p_skeleton ? &p_skeleton.value() : nullptr, + hasBones ? &nodeIndexByPointer : nullptr + ); + + if (hasBones && p_skeleton.has_value()) + { + ProcessAnimations(scene, p_skeleton.value(), p_animations); + } if (p_skeleton && p_skeleton->bones.empty()) {