File indexing completed on 2026-09-14 08:38:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
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 <istream>
0054 #include <utility>
0055 #include <vector>
0056
0057 namespace Assimp {
0058
0059
0060 struct find_node_by_name_predicate {
0061
0062 find_node_by_name_predicate() = default;
0063
0064
0065 std::string mName;
0066 find_node_by_name_predicate(const std::string &name) :
0067 mName(name) {
0068
0069 }
0070
0071 bool operator()(pugi::xml_node node) const {
0072 return node.name() == mName;
0073 }
0074 };
0075
0076
0077
0078 template <class TNodeType>
0079 struct NodeConverter {
0080 public:
0081 static int to_int(TNodeType &node, const char *attribName) {
0082 ai_assert(nullptr != attribName);
0083 return node.attribute(attribName).to_int();
0084 }
0085 };
0086
0087 using XmlNode = pugi::xml_node;
0088 using XmlAttribute = pugi::xml_attribute;
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 template <class TNodeType>
0106 class TXmlParser {
0107 public:
0108
0109 TXmlParser();
0110
0111
0112 ~TXmlParser();
0113
0114
0115 void clear();
0116
0117
0118
0119
0120 TNodeType *findNode(const std::string &name);
0121
0122
0123
0124
0125 bool hasNode(const std::string &name);
0126
0127
0128
0129
0130 bool parse(IOStream *stream);
0131
0132
0133
0134
0135 bool parse(std::istream &inStream);
0136
0137
0138
0139 bool hasRoot() const;
0140
0141
0142
0143 pugi::xml_document *getDocument() const;
0144
0145
0146
0147 const TNodeType getRootNode() const;
0148
0149
0150
0151 TNodeType getRootNode();
0152
0153
0154
0155
0156
0157 static inline bool hasNode(XmlNode &node, const char *name);
0158
0159
0160
0161
0162
0163 static inline bool hasAttribute(XmlNode &xmlNode, const char *name);
0164
0165
0166
0167
0168
0169
0170 static inline bool getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val);
0171
0172
0173
0174
0175
0176
0177 static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val);
0178
0179
0180
0181
0182
0183
0184 static inline bool getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val);
0185
0186
0187
0188
0189
0190
0191 static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val);
0192
0193
0194
0195
0196
0197
0198 static inline bool getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val);
0199
0200
0201
0202
0203
0204
0205 static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val);
0206
0207
0208
0209
0210
0211
0212 static inline bool getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val);
0213
0214
0215
0216
0217
0218 static inline bool getValueAsString(XmlNode &node, std::string &text);
0219
0220
0221
0222
0223
0224 static inline bool getValueAsReal(XmlNode &node, ai_real &v);
0225
0226
0227
0228
0229
0230 static inline bool getValueAsFloat(XmlNode &node, float &v);
0231
0232
0233
0234
0235
0236 static inline bool getValueAsInt(XmlNode &node, int &v);
0237
0238
0239
0240
0241
0242 static inline bool getValueAsBool(XmlNode &node, bool &v);
0243
0244 private:
0245 pugi::xml_document *mDoc;
0246 TNodeType mCurrent;
0247 std::vector<char> mData;
0248 };
0249
0250 template <class TNodeType>
0251 inline TXmlParser<TNodeType>::TXmlParser() :
0252 mDoc(nullptr),
0253 mData() {
0254
0255 }
0256
0257 template <class TNodeType>
0258 inline TXmlParser<TNodeType>::~TXmlParser() {
0259 clear();
0260 }
0261
0262 template <class TNodeType>
0263 inline void TXmlParser<TNodeType>::clear() {
0264 if (mData.empty()) {
0265 if (mDoc) {
0266 delete mDoc;
0267 }
0268 mDoc = nullptr;
0269 return;
0270 }
0271
0272 mData.clear();
0273 delete mDoc;
0274 mDoc = nullptr;
0275 }
0276
0277 template <class TNodeType>
0278 inline TNodeType *TXmlParser<TNodeType>::findNode(const std::string &name) {
0279 if (name.empty()) {
0280 return nullptr;
0281 }
0282
0283 if (nullptr == mDoc) {
0284 return nullptr;
0285 }
0286
0287 find_node_by_name_predicate predicate(name);
0288 mCurrent = mDoc->find_node(std::move(predicate));
0289 if (mCurrent.empty()) {
0290 return nullptr;
0291 }
0292
0293 return &mCurrent;
0294 }
0295
0296 template <class TNodeType>
0297 bool TXmlParser<TNodeType>::hasNode(const std::string &name) {
0298 return nullptr != findNode(name);
0299 }
0300
0301 template <class TNodeType>
0302 bool TXmlParser<TNodeType>::parse(IOStream *stream) {
0303 if (hasRoot()) {
0304 clear();
0305 }
0306
0307 if (nullptr == stream) {
0308 ASSIMP_LOG_DEBUG("Stream is nullptr.");
0309 return false;
0310 }
0311
0312 const size_t len = stream->FileSize();
0313 mData.resize(len + 1);
0314 memset(&mData[0], '\0', len + 1);
0315 stream->Read(&mData[0], 1, len);
0316
0317 mDoc = new pugi::xml_document();
0318
0319
0320 pugi::xml_parse_result parse_result = mDoc->load_buffer(&mData[0], mData.size(), pugi::parse_full);
0321 if (parse_result.status == pugi::status_ok) {
0322 return true;
0323 }
0324
0325 ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset);
0326
0327 return false;
0328 }
0329
0330 template <class TNodeType>
0331 bool TXmlParser<TNodeType>::parse(std::istream &inStream) {
0332 if (hasRoot()) {
0333 clear();
0334 }
0335 mDoc = new pugi::xml_document();
0336 pugi::xml_parse_result parse_result = mDoc->load(inStream);
0337 if (parse_result.status == pugi::status_ok) {
0338 return true;
0339 }
0340
0341 ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset);
0342
0343 return false;
0344 }
0345
0346 template <class TNodeType>
0347 bool TXmlParser<TNodeType>::hasRoot() const {
0348 return nullptr != mDoc;
0349 }
0350
0351 template <class TNodeType>
0352 pugi::xml_document *TXmlParser<TNodeType>::getDocument() const {
0353 return mDoc;
0354 }
0355
0356 template <class TNodeType>
0357 const TNodeType TXmlParser<TNodeType>::getRootNode() const {
0358 static pugi::xml_node none;
0359 if (nullptr == mDoc) {
0360 return none;
0361 }
0362 return mDoc->root();
0363 }
0364
0365 template <class TNodeType>
0366 TNodeType TXmlParser<TNodeType>::getRootNode() {
0367 static pugi::xml_node none;
0368 if (nullptr == mDoc) {
0369 return none;
0370 }
0371
0372 return mDoc->root();
0373 }
0374
0375 template <class TNodeType>
0376 inline bool TXmlParser<TNodeType>::hasNode(XmlNode &node, const char *name) {
0377 pugi::xml_node child = node.find_child(find_node_by_name_predicate(name));
0378 return !child.empty();
0379 }
0380
0381 template <class TNodeType>
0382 inline bool TXmlParser<TNodeType>::hasAttribute(XmlNode &xmlNode, const char *name) {
0383 pugi::xml_attribute attr = xmlNode.attribute(name);
0384 return !attr.empty();
0385 }
0386
0387 template <class TNodeType>
0388 inline bool TXmlParser<TNodeType>::getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val) {
0389 pugi::xml_attribute attr = xmlNode.attribute(name);
0390 if (attr.empty()) {
0391 return false;
0392 }
0393
0394 val = attr.as_uint();
0395 return true;
0396 }
0397
0398 template <class TNodeType>
0399 inline bool TXmlParser<TNodeType>::getIntAttribute(XmlNode &xmlNode, const char *name, int &val) {
0400 pugi::xml_attribute attr = xmlNode.attribute(name);
0401 if (attr.empty()) {
0402 return false;
0403 }
0404
0405 val = attr.as_int();
0406 return true;
0407 }
0408
0409 template <class TNodeType>
0410 inline bool TXmlParser<TNodeType>::getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val) {
0411 pugi::xml_attribute attr = xmlNode.attribute(name);
0412 if (attr.empty()) {
0413 return false;
0414 }
0415 #ifdef ASSIMP_DOUBLE_PRECISION
0416 val = attr.as_double();
0417 #else
0418 val = attr.as_float();
0419 #endif
0420 return true;
0421 }
0422
0423 template <class TNodeType>
0424 inline bool TXmlParser<TNodeType>::getFloatAttribute(XmlNode &xmlNode, const char *name, float &val) {
0425 pugi::xml_attribute attr = xmlNode.attribute(name);
0426 if (attr.empty()) {
0427 return false;
0428 }
0429
0430 val = attr.as_float();
0431
0432 return true;
0433 }
0434
0435 template <class TNodeType>
0436 inline bool TXmlParser<TNodeType>::getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val) {
0437 pugi::xml_attribute attr = xmlNode.attribute(name);
0438 if (attr.empty()) {
0439 return false;
0440 }
0441
0442 val = attr.as_double();
0443
0444 return true;
0445 }
0446
0447 template <class TNodeType>
0448 inline bool TXmlParser<TNodeType>::getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) {
0449 pugi::xml_attribute attr = xmlNode.attribute(name);
0450 if (attr.empty()) {
0451 return false;
0452 }
0453
0454 val = attr.as_string();
0455
0456 return true;
0457 }
0458
0459 template <class TNodeType>
0460 inline bool TXmlParser<TNodeType>::getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val) {
0461 pugi::xml_attribute attr = xmlNode.attribute(name);
0462 if (attr.empty()) {
0463 return false;
0464 }
0465
0466 val = attr.as_bool();
0467
0468 return true;
0469 }
0470
0471 template <class TNodeType>
0472 inline bool TXmlParser<TNodeType>::getValueAsString(XmlNode &node, std::string &text) {
0473 text = std::string();
0474 if (node.empty()) {
0475 return false;
0476 }
0477
0478 text = node.text().as_string();
0479 text = ai_trim(text);
0480
0481 return true;
0482 }
0483
0484 template <class TNodeType>
0485 inline bool TXmlParser<TNodeType>::getValueAsReal(XmlNode& node, ai_real& v) {
0486 if (node.empty()) {
0487 return false;
0488 }
0489
0490 v = node.text().as_float();
0491
0492 return true;
0493 }
0494
0495
0496 template <class TNodeType>
0497 inline bool TXmlParser<TNodeType>::getValueAsFloat(XmlNode &node, float &v) {
0498 if (node.empty()) {
0499 return false;
0500 }
0501
0502 v = node.text().as_float();
0503
0504 return true;
0505 }
0506
0507 template <class TNodeType>
0508 inline bool TXmlParser<TNodeType>::getValueAsInt(XmlNode &node, int &v) {
0509 if (node.empty()) {
0510 return false;
0511 }
0512
0513 v = node.text().as_int();
0514
0515 return true;
0516 }
0517
0518 template <class TNodeType>
0519 inline bool TXmlParser<TNodeType>::getValueAsBool(XmlNode &node, bool &v) {
0520 if (node.empty()) {
0521 return false;
0522 }
0523
0524 v = node.text().as_bool();
0525
0526 return true;
0527 }
0528
0529 using XmlParser = TXmlParser<pugi::xml_node>;
0530
0531
0532 class XmlNodeIterator {
0533 public:
0534
0535 enum IterationMode {
0536 PreOrderMode,
0537 PostOrderMode
0538 };
0539
0540
0541
0542 explicit XmlNodeIterator(XmlNode &parent, IterationMode mode) :
0543 mParent(parent),
0544 mNodes(),
0545 mIndex(0) {
0546 if (mode == PreOrderMode) {
0547 collectChildrenPreOrder(parent);
0548 } else {
0549 collectChildrenPostOrder(parent);
0550 }
0551 }
0552
0553
0554 ~XmlNodeIterator() = default;
0555
0556
0557
0558 void collectChildrenPreOrder(XmlNode &node) {
0559 if (node != mParent && node.type() == pugi::node_element) {
0560 mNodes.push_back(node);
0561 }
0562 for (XmlNode currentNode : node.children()) {
0563 collectChildrenPreOrder(currentNode);
0564 }
0565 }
0566
0567
0568
0569 void collectChildrenPostOrder(XmlNode &node) {
0570 for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
0571 collectChildrenPostOrder(currentNode);
0572 }
0573 if (node != mParent) {
0574 mNodes.push_back(node);
0575 }
0576 }
0577
0578
0579
0580
0581 bool getNext(XmlNode &next) {
0582 if (mIndex == mNodes.size()) {
0583 return false;
0584 }
0585
0586 next = mNodes[mIndex];
0587 ++mIndex;
0588
0589 return true;
0590 }
0591
0592
0593
0594 size_t size() const {
0595 return mNodes.size();
0596 }
0597
0598
0599
0600 bool isEmpty() const {
0601 return mNodes.empty();
0602 }
0603
0604
0605 void clear() {
0606 if (mNodes.empty()) {
0607 return;
0608 }
0609
0610 mNodes.clear();
0611 mIndex = 0;
0612 }
0613
0614 private:
0615 XmlNode &mParent;
0616 std::vector<XmlNode> mNodes;
0617 size_t mIndex;
0618 };
0619
0620 }
0621
0622 #endif