File indexing completed on 2025-02-21 09:30:11
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 <utility>
0054 #include <vector>
0055
0056 namespace Assimp {
0057
0058
0059 struct find_node_by_name_predicate {
0060
0061 find_node_by_name_predicate() = default;
0062
0063
0064 std::string mName;
0065 find_node_by_name_predicate(const std::string &name) :
0066 mName(name) {
0067
0068 }
0069
0070 bool operator()(pugi::xml_node node) const {
0071 return node.name() == mName;
0072 }
0073 };
0074
0075
0076
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
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 template <class TNodeType>
0105 class TXmlParser {
0106 public:
0107
0108 TXmlParser();
0109
0110
0111 ~TXmlParser();
0112
0113
0114 void clear();
0115
0116
0117
0118
0119 TNodeType *findNode(const std::string &name);
0120
0121
0122
0123
0124 bool hasNode(const std::string &name);
0125
0126
0127
0128
0129 bool parse(IOStream *stream);
0130
0131
0132
0133 bool hasRoot() const;
0134
0135
0136
0137 pugi::xml_document *getDocument() const;
0138
0139
0140
0141 const TNodeType getRootNode() const;
0142
0143
0144
0145 TNodeType getRootNode();
0146
0147
0148
0149
0150
0151 static inline bool hasNode(XmlNode &node, const char *name);
0152
0153
0154
0155
0156
0157 static inline bool hasAttribute(XmlNode &xmlNode, const char *name);
0158
0159
0160
0161
0162
0163
0164 static inline bool getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val);
0165
0166
0167
0168
0169
0170
0171 static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val);
0172
0173
0174
0175
0176
0177
0178 static inline bool getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val);
0179
0180
0181
0182
0183
0184
0185 static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val);
0186
0187
0188
0189
0190
0191
0192 static inline bool getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val);
0193
0194
0195
0196
0197
0198
0199 static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val);
0200
0201
0202
0203
0204
0205
0206 static inline bool getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val);
0207
0208
0209
0210
0211
0212 static inline bool getValueAsString(XmlNode &node, std::string &text);
0213
0214
0215
0216
0217
0218 static inline bool getValueAsReal(XmlNode &node, ai_real &v);
0219
0220
0221
0222
0223
0224 static inline bool getValueAsFloat(XmlNode &node, float &v);
0225
0226
0227
0228
0229
0230 static inline bool getValueAsInt(XmlNode &node, int &v);
0231
0232
0233
0234
0235
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
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
0313
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
0510 class XmlNodeIterator {
0511 public:
0512
0513 enum IterationMode {
0514 PreOrderMode,
0515 PostOrderMode
0516 };
0517
0518
0519
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
0532 ~XmlNodeIterator() = default;
0533
0534
0535
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
0546
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
0557
0558
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
0571
0572 size_t size() const {
0573 return mNodes.size();
0574 }
0575
0576
0577
0578 bool isEmpty() const {
0579 return mNodes.empty();
0580 }
0581
0582
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 }
0599
0600 #endif