Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 09:30:11

0001 /*
0002 Open Asset Import Library (assimp)
0003 ----------------------------------------------------------------------
0004 
0005 Copyright (c) 2006-2024, assimp team
0006 
0007 All rights reserved.
0008 
0009 Redistribution and use of this software in source and binary forms,
0010 with or without modification, are permitted provided that the
0011 following conditions are met:
0012 
0013 * Redistributions of source code must retain the above
0014 copyright notice, this list of conditions and the
0015 following disclaimer.
0016 
0017 * Redistributions in binary form must reproduce the above
0018 copyright notice, this list of conditions and the
0019 following disclaimer in the documentation and/or other
0020 materials provided with the distribution.
0021 
0022 * Neither the name of the assimp team, nor the names of its
0023 contributors may be used to endorse or promote products
0024 derived from this software without specific prior
0025 written permission of the assimp team.
0026 
0027 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0028 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0029 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0030 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0031 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0032 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0033 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0034 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0035 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0036 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0037 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0038 
0039 ----------------------------------------------------------------------
0040 */
0041 
0042 #ifndef INCLUDED_AI_IRRXML_WRAPPER
0043 #define INCLUDED_AI_IRRXML_WRAPPER
0044 
0045 #include <assimp/ai_assert.h>
0046 #include <assimp/StringUtils.h>
0047 #include <assimp/DefaultLogger.hpp>
0048 
0049 #include "BaseImporter.h"
0050 #include "IOStream.hpp"
0051 
0052 #include <pugixml.hpp>
0053 #include <utility>
0054 #include <vector>
0055 
0056 namespace Assimp {
0057 
0058 /// @brief  Will find a node by its name.
0059 struct find_node_by_name_predicate {
0060     /// @brief The default constructor.
0061     find_node_by_name_predicate() = default;
0062 
0063 
0064     std::string mName; ///< The name to find.
0065     find_node_by_name_predicate(const std::string &name) :
0066             mName(name) {
0067         // empty
0068     }
0069 
0070     bool operator()(pugi::xml_node node) const {
0071         return node.name() == mName;
0072     }
0073 };
0074 
0075 /// @brief  Will convert an attribute to its int value.
0076 /// @tparam[in] TNodeType  The node type.
0077 template <class TNodeType>
0078 struct NodeConverter {
0079 public:
0080     static int to_int(TNodeType &node, const char *attribName) {
0081         ai_assert(nullptr != attribName);
0082         return node.attribute(attribName).to_int();
0083     }
0084 };
0085 
0086 using XmlNode = pugi::xml_node;
0087 using XmlAttribute = pugi::xml_attribute;
0088 
0089 /// @brief The Xml-Parser class.
0090 ///
0091 /// Use this parser if you have to import any kind of xml-format.
0092 ///
0093 /// An example:
0094 /// @code
0095 /// TXmlParser<XmlNode> theParser;
0096 /// if (theParser.parse(fileStream)) {
0097 ///     auto node = theParser.getRootNode();
0098 ///     for ( auto currentNode : node.children()) {
0099 ///         // Will loop over all children
0100 ///     }
0101 /// }
0102 /// @endcode
0103 /// @tparam TNodeType
0104 template <class TNodeType>
0105 class TXmlParser {
0106 public:
0107     /// @brief The default class constructor.
0108     TXmlParser();
0109 
0110     /// @brief  The class destructor.
0111     ~TXmlParser();
0112 
0113     /// @brief  Will clear the parsed xml-file.
0114     void clear();
0115 
0116     /// @brief  Will search for a child-node by its name
0117     /// @param[in] name     The name of the child-node.
0118     /// @return The node instance or nullptr, if nothing was found.
0119     TNodeType *findNode(const std::string &name);
0120 
0121     /// @brief  Will return true, if the node is a child-node.
0122     /// @param[in]  name    The name of the child node to look for.
0123     /// @return true, if the node is a child-node or false if not.
0124     bool hasNode(const std::string &name);
0125 
0126     /// @brief  Will parse an xml-file from a given stream.
0127     /// @param[in] stream      The input stream.
0128     /// @return true, if the parsing was successful, false if not.
0129     bool parse(IOStream *stream);
0130 
0131     /// @brief  Will return true if a root node is there.
0132     /// @return true in case of an existing root.
0133     bool hasRoot() const;
0134 
0135     /// @brief  Will return the document pointer, is nullptr if no xml-file was parsed.
0136     /// @return The pointer showing to the document.
0137     pugi::xml_document *getDocument() const;
0138 
0139     /// @brief  Will return the root node, const version.
0140     /// @return The root node.
0141     const TNodeType getRootNode() const;
0142 
0143     /// @brief  Will return the root node, non-const version.
0144     /// @return The root node.
0145     TNodeType getRootNode();
0146 
0147     /// @brief Will check if a node with the given name is in.
0148     /// @param[in] node     The node to look in.
0149     /// @param[in] name     The name of the child-node.
0150     /// @return true, if node was found, false if not.
0151     static inline bool hasNode(XmlNode &node, const char *name);
0152 
0153     /// @brief Will check if an attribute is part of the XmlNode.
0154     /// @param[in] xmlNode  The node to search in.
0155     /// @param[in] name     The attribute name to look for.
0156     /// @return true, if the was found, false if not.
0157     static inline bool hasAttribute(XmlNode &xmlNode, const char *name);
0158 
0159     /// @brief Will try to get an unsigned int attribute value.
0160     /// @param[in] xmlNode  The node to search in.
0161     /// @param[in] name     The attribute name to look for.
0162     /// @param[out] val     The unsigned int value from the attribute.
0163     /// @return true, if the node contains an attribute with the given name and if the value is an unsigned int.
0164     static inline bool getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val);
0165 
0166     /// @brief Will try to get an int attribute value.
0167     /// @param[in] xmlNode  The node to search in.
0168     /// @param[in] name     The attribute name to look for.
0169     /// @param[out] val     The int value from the attribute.
0170     /// @return true, if the node contains an attribute with the given name and if the value is an int.
0171     static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val);
0172 
0173     /// @brief Will try to get a real attribute value.
0174     /// @param[in] xmlNode  The node to search in.
0175     /// @param[in] name     The attribute name to look for.
0176     /// @param[out] val     The real value from the attribute.
0177     /// @return true, if the node contains an attribute with the given name and if the value is a real.
0178     static inline bool getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val);
0179 
0180     /// @brief Will try to get a float attribute value.
0181     /// @param[in] xmlNode  The node to search in.
0182     /// @param[in] name     The attribute name to look for.
0183     /// @param[out] val     The float value from the attribute.
0184     /// @return true, if the node contains an attribute with the given name and if the value is a float.
0185     static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val);
0186 
0187     /// @brief Will try to get a double attribute value.
0188     /// @param[in] xmlNode  The node to search in.
0189     /// @param[in] name     The attribute name to look for.
0190     /// @param[out] val     The double value from the attribute.
0191     /// @return true, if the node contains an attribute with the given name and if the value is a double.
0192     static inline bool getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val);
0193 
0194     /// @brief Will try to get a std::string attribute value.
0195     /// @param[in] xmlNode  The node to search in.
0196     /// @param[in] name     The attribute name to look for.
0197     /// @param[out] val     The std::string value from the attribute.
0198     /// @return true, if the node contains an attribute with the given name and if the value is a std::string.
0199     static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val);
0200 
0201     /// @brief Will try to get a bool attribute value.
0202     /// @param[in] xmlNode  The node to search in.
0203     /// @param[in] name     The attribute name to look for.
0204     /// @param[out] val     The bool value from the attribute.
0205     /// @return true, if the node contains an attribute with the given name and if the value is a bool.
0206     static inline bool getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val);
0207 
0208     /// @brief Will try to get the value of the node as a string.
0209     /// @param[in] node     The node to search in.
0210     /// @param[out] text    The value as a text.
0211     /// @return true, if the value can be read out.
0212     static inline bool getValueAsString(XmlNode &node, std::string &text);
0213 
0214     /// @brief Will try to get the value of the node as a real.
0215     /// @param[in]  node   The node to search in.
0216     /// @param[out] v      The value as a ai_real.
0217     /// @return true, if the value can be read out.
0218     static inline bool getValueAsReal(XmlNode &node, ai_real &v);
0219 
0220     /// @brief Will try to get the value of the node as a float.
0221     /// @param[in] node     The node to search in.
0222     /// @param[out]v        The value as a float.
0223     /// @return true, if the value can be read out.
0224     static inline bool getValueAsFloat(XmlNode &node, float &v);
0225 
0226     /// @brief Will try to get the value of the node as an integer.
0227     /// @param[in]  node    The node to search in.
0228     /// @param[out] i       The value as a int.
0229     /// @return true, if the value can be read out.
0230     static inline bool getValueAsInt(XmlNode &node, int &v);
0231 
0232     /// @brief Will try to get the value of the node as an bool.
0233     /// @param[in]  node    The node to search in.
0234     /// @param[out] v       The value as a bool.
0235     /// @return true, if the value can be read out.
0236     static inline bool getValueAsBool(XmlNode &node, bool &v);
0237 
0238 private:
0239     pugi::xml_document *mDoc;
0240     TNodeType mCurrent;
0241     std::vector<char> mData;
0242 };
0243 
0244 template <class TNodeType>
0245 inline TXmlParser<TNodeType>::TXmlParser() :
0246         mDoc(nullptr),
0247         mData() {
0248     // empty
0249 }
0250 
0251 template <class TNodeType>
0252 inline TXmlParser<TNodeType>::~TXmlParser() {
0253     clear();
0254 }
0255 
0256 template <class TNodeType>
0257 inline void TXmlParser<TNodeType>::clear() {
0258     if (mData.empty()) {
0259         if (mDoc) {
0260             delete mDoc;
0261         }
0262         mDoc = nullptr;
0263         return;
0264     }
0265 
0266     mData.clear();
0267     delete mDoc;
0268     mDoc = nullptr;
0269 }
0270 
0271 template <class TNodeType>
0272 inline TNodeType *TXmlParser<TNodeType>::findNode(const std::string &name) {
0273     if (name.empty()) {
0274         return nullptr;
0275     }
0276 
0277     if (nullptr == mDoc) {
0278         return nullptr;
0279     }
0280 
0281     find_node_by_name_predicate predicate(name);
0282     mCurrent = mDoc->find_node(std::move(predicate));
0283     if (mCurrent.empty()) {
0284         return nullptr;
0285     }
0286 
0287     return &mCurrent;
0288 }
0289 
0290 template <class TNodeType>
0291 bool TXmlParser<TNodeType>::hasNode(const std::string &name) {
0292     return nullptr != findNode(name);
0293 }
0294 
0295 template <class TNodeType>
0296 bool TXmlParser<TNodeType>::parse(IOStream *stream) {
0297     if (hasRoot()) {
0298         clear();
0299     }
0300 
0301     if (nullptr == stream) {
0302         ASSIMP_LOG_DEBUG("Stream is nullptr.");
0303         return false;
0304     }
0305 
0306     const size_t len = stream->FileSize();
0307     mData.resize(len + 1);
0308     memset(&mData[0], '\0', len + 1);
0309     stream->Read(&mData[0], 1, len);
0310 
0311     mDoc = new pugi::xml_document();
0312     // load_string assumes native encoding (aka always utf-8 per build options)
0313     //pugi::xml_parse_result parse_result = mDoc->load_string(&mData[0], pugi::parse_full);
0314      pugi::xml_parse_result parse_result = mDoc->load_buffer(&mData[0], mData.size(), pugi::parse_full);
0315     if (parse_result.status == pugi::status_ok) {
0316         return true;
0317     }
0318 
0319     ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset);
0320 
0321     return false;
0322 }
0323 
0324 template <class TNodeType>
0325 bool TXmlParser<TNodeType>::hasRoot() const {
0326     return nullptr != mDoc;
0327 }
0328 
0329 template <class TNodeType>
0330 pugi::xml_document *TXmlParser<TNodeType>::getDocument() const {
0331     return mDoc;
0332 }
0333 
0334 template <class TNodeType>
0335 const TNodeType TXmlParser<TNodeType>::getRootNode() const {
0336     static pugi::xml_node none;
0337     if (nullptr == mDoc) {
0338         return none;
0339     }
0340     return mDoc->root();
0341 }
0342 
0343 template <class TNodeType>
0344 TNodeType TXmlParser<TNodeType>::getRootNode() {
0345     static pugi::xml_node none;
0346     if (nullptr == mDoc) {
0347         return none;
0348     }
0349 
0350     return mDoc->root();
0351 }
0352 
0353 template <class TNodeType>
0354 inline bool TXmlParser<TNodeType>::hasNode(XmlNode &node, const char *name) {
0355     pugi::xml_node child = node.find_child(find_node_by_name_predicate(name));
0356     return !child.empty();
0357 }
0358 
0359 template <class TNodeType>
0360 inline bool TXmlParser<TNodeType>::hasAttribute(XmlNode &xmlNode, const char *name) {
0361     pugi::xml_attribute attr = xmlNode.attribute(name);
0362     return !attr.empty();
0363 }
0364 
0365 template <class TNodeType>
0366 inline bool TXmlParser<TNodeType>::getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val) {
0367     pugi::xml_attribute attr = xmlNode.attribute(name);
0368     if (attr.empty()) {
0369         return false;
0370     }
0371 
0372     val = attr.as_uint();
0373     return true;
0374 }
0375 
0376 template <class TNodeType>
0377 inline bool TXmlParser<TNodeType>::getIntAttribute(XmlNode &xmlNode, const char *name, int &val) {
0378     pugi::xml_attribute attr = xmlNode.attribute(name);
0379     if (attr.empty()) {
0380         return false;
0381     }
0382 
0383     val = attr.as_int();
0384     return true;
0385 }
0386 
0387 template <class TNodeType>
0388 inline bool TXmlParser<TNodeType>::getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val) {
0389     pugi::xml_attribute attr = xmlNode.attribute(name);
0390     if (attr.empty()) {
0391         return false;
0392     }
0393 #ifdef ASSIMP_DOUBLE_PRECISION
0394     val = attr.as_double();
0395 #else
0396     val = attr.as_float();
0397 #endif
0398     return true;
0399 }
0400 
0401 template <class TNodeType>
0402 inline bool TXmlParser<TNodeType>::getFloatAttribute(XmlNode &xmlNode, const char *name, float &val) {
0403     pugi::xml_attribute attr = xmlNode.attribute(name);
0404     if (attr.empty()) {
0405         return false;
0406     }
0407 
0408     val = attr.as_float();
0409 
0410     return true;
0411 }
0412 
0413 template <class TNodeType>
0414 inline bool TXmlParser<TNodeType>::getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val) {
0415     pugi::xml_attribute attr = xmlNode.attribute(name);
0416     if (attr.empty()) {
0417         return false;
0418     }
0419 
0420     val = attr.as_double();
0421 
0422     return true;
0423 }
0424 
0425 template <class TNodeType>
0426 inline bool TXmlParser<TNodeType>::getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) {
0427     pugi::xml_attribute attr = xmlNode.attribute(name);
0428     if (attr.empty()) {
0429         return false;
0430     }
0431 
0432     val = attr.as_string();
0433 
0434     return true;
0435 }
0436 
0437 template <class TNodeType>
0438 inline bool TXmlParser<TNodeType>::getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val) {
0439     pugi::xml_attribute attr = xmlNode.attribute(name);
0440     if (attr.empty()) {
0441         return false;
0442     }
0443 
0444     val = attr.as_bool();
0445 
0446     return true;
0447 }
0448 
0449 template <class TNodeType>
0450 inline bool TXmlParser<TNodeType>::getValueAsString(XmlNode &node, std::string &text) {
0451     text = std::string();
0452     if (node.empty()) {
0453         return false;
0454     }
0455 
0456     text = node.text().as_string();
0457     text = ai_trim(text);
0458 
0459     return true;
0460 }
0461 
0462 template <class TNodeType>
0463 inline bool TXmlParser<TNodeType>::getValueAsReal(XmlNode& node, ai_real& v) {
0464     if (node.empty()) {
0465         return false;
0466     }
0467 
0468     v = node.text().as_float();
0469 
0470     return true;
0471 }
0472 
0473 
0474 template <class TNodeType>
0475 inline bool TXmlParser<TNodeType>::getValueAsFloat(XmlNode &node, float &v) {
0476     if (node.empty()) {
0477         return false;
0478     }
0479 
0480     v = node.text().as_float();
0481 
0482     return true;
0483 }
0484 
0485 template <class TNodeType>
0486 inline bool TXmlParser<TNodeType>::getValueAsInt(XmlNode &node, int &v) {
0487     if (node.empty()) {
0488         return false;
0489     }
0490 
0491     v = node.text().as_int();
0492 
0493     return true;
0494 }
0495 
0496 template <class TNodeType>
0497 inline bool TXmlParser<TNodeType>::getValueAsBool(XmlNode &node, bool &v) {
0498     if (node.empty()) {
0499         return false;
0500     }
0501 
0502     v = node.text().as_bool();
0503 
0504     return true;
0505 }
0506 
0507 using XmlParser = TXmlParser<pugi::xml_node>;
0508 
0509 /// @brief  This class declares an iterator to loop through all children of the root node.
0510 class XmlNodeIterator {
0511 public:
0512     /// @brief The iteration mode.
0513     enum IterationMode {
0514         PreOrderMode, ///< Pre-ordering, get the values, continue the iteration.
0515         PostOrderMode ///< Post-ordering, continue the iteration, get the values.
0516     };
0517     /// @brief  The class constructor
0518     /// @param  parent      [in] The xml parent to to iterate through.
0519     /// @param  mode        [in] The iteration mode.
0520     explicit XmlNodeIterator(XmlNode &parent, IterationMode mode) :
0521             mParent(parent),
0522             mNodes(),
0523             mIndex(0) {
0524         if (mode == PreOrderMode) {
0525             collectChildrenPreOrder(parent);
0526         } else {
0527             collectChildrenPostOrder(parent);
0528         }
0529     }
0530 
0531     /// @brief  The class destructor, default implementation.
0532     ~XmlNodeIterator() = default;
0533 
0534     /// @brief  Will iterate through all children in pre-order iteration.
0535     /// @param  node    [in] The nod to iterate through.
0536     void collectChildrenPreOrder(XmlNode &node) {
0537         if (node != mParent && node.type() == pugi::node_element) {
0538             mNodes.push_back(node);
0539         }
0540         for (XmlNode currentNode : node.children()) {
0541             collectChildrenPreOrder(currentNode);
0542         }
0543     }
0544 
0545     /// @brief  Will iterate through all children in post-order iteration.
0546     /// @param  node    [in] The nod to iterate through.
0547     void collectChildrenPostOrder(XmlNode &node) {
0548         for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
0549             collectChildrenPostOrder(currentNode);
0550         }
0551         if (node != mParent) {
0552             mNodes.push_back(node);
0553         }
0554     }
0555 
0556     /// @brief  Will iterate through all collected nodes.
0557     /// @param  next    The next node, if there is any.
0558     /// @return true, if there is a node left.
0559     bool getNext(XmlNode &next) {
0560         if (mIndex == mNodes.size()) {
0561             return false;
0562         }
0563 
0564         next = mNodes[mIndex];
0565         ++mIndex;
0566 
0567         return true;
0568     }
0569 
0570     /// @brief  Will return the number of collected nodes.
0571     /// @return The number of collected nodes.
0572     size_t size() const {
0573         return mNodes.size();
0574     }
0575 
0576     /// @brief  Returns true, if the node is empty.
0577     /// @return true, if the node is empty, false if not.
0578     bool isEmpty() const {
0579         return mNodes.empty();
0580     }
0581 
0582     /// @brief  Will clear all collected nodes.
0583     void clear() {
0584         if (mNodes.empty()) {
0585             return;
0586         }
0587 
0588         mNodes.clear();
0589         mIndex = 0;
0590     }
0591 
0592 private:
0593     XmlNode &mParent;
0594     std::vector<XmlNode> mNodes;
0595     size_t mIndex;
0596 };
0597 
0598 } // namespace Assimp
0599 
0600 #endif // !! INCLUDED_AI_IRRXML_WRAPPER