/src/assimp/include/assimp/XmlParser.h
Line | Count | Source |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2026, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | | |
39 | | ---------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | #ifndef INCLUDED_AI_IRRXML_WRAPPER |
43 | | #define INCLUDED_AI_IRRXML_WRAPPER |
44 | | |
45 | | #include <assimp/ai_assert.h> |
46 | | #include <assimp/StringUtils.h> |
47 | | #include <assimp/DefaultLogger.hpp> |
48 | | |
49 | | #include "BaseImporter.h" |
50 | | #include "IOStream.hpp" |
51 | | |
52 | | #include <pugixml.hpp> |
53 | | #include <istream> |
54 | | #include <utility> |
55 | | #include <vector> |
56 | | |
57 | | namespace Assimp { |
58 | | |
59 | | /// @brief Will find a node by its name. |
60 | | struct find_node_by_name_predicate { |
61 | | /// @brief The default constructor. |
62 | | find_node_by_name_predicate() = default; |
63 | | |
64 | | /// @brief Constructor with the predicate name |
65 | | /// @param name The name. |
66 | 0 | explicit find_node_by_name_predicate(const std::string &name) : mName(name) { |
67 | | // empty |
68 | 0 | } |
69 | | |
70 | | std::string mName; ///< The name to find. |
71 | | |
72 | 0 | bool operator()(pugi::xml_node node) const { |
73 | 0 | return node.name() == mName; |
74 | 0 | } |
75 | | }; |
76 | | |
77 | | /// @brief Will convert an attribute to its int value. |
78 | | /// @tparam[in] TNodeType The node type. |
79 | | template <class TNodeType> |
80 | | struct NodeConverter { |
81 | | public: |
82 | | /// @brief Will convert the attribute from the node to an int. |
83 | | /// @param node The XML-node. |
84 | | /// @param attribName The name of the attribute. |
85 | | static int to_int(TNodeType &node, const char *attribName) { |
86 | | ai_assert(nullptr != attribName); |
87 | | return node.attribute(attribName).to_int(); |
88 | | } |
89 | | }; |
90 | | |
91 | | using XmlNode = pugi::xml_node; |
92 | | using XmlAttribute = pugi::xml_attribute; |
93 | | |
94 | | /// @brief The Xml-Parser class. |
95 | | /// |
96 | | /// Use this parser if you have to import any kind of xml-format. |
97 | | /// |
98 | | /// An example: |
99 | | /// @code |
100 | | /// TXmlParser<XmlNode> theParser; |
101 | | /// if (theParser.parse(fileStream)) { |
102 | | /// auto node = theParser.getRootNode(); |
103 | | /// for ( auto currentNode : node.children()) { |
104 | | /// // Will loop over all children |
105 | | /// } |
106 | | /// } |
107 | | /// @endcode |
108 | | /// @tparam TNodeType |
109 | | template <class TNodeType> |
110 | | class TXmlParser { |
111 | | public: |
112 | | /// @brief The default class constructor. |
113 | | TXmlParser(); |
114 | | |
115 | | /// @brief The class destructor. |
116 | | ~TXmlParser(); |
117 | | |
118 | | /// @brief Will clear the parsed xml-file. |
119 | | void clear(); |
120 | | |
121 | | /// @brief Will search for a child-node by its name |
122 | | /// @param[in] name The name of the child-node. |
123 | | /// @return The node instance or nullptr, if nothing was found. |
124 | | TNodeType *findNode(const std::string &name); |
125 | | |
126 | | /// @brief Will return true, if the node is a child-node. |
127 | | /// @param[in] name The name of the child node to look for. |
128 | | /// @return true, if the node is a child-node or false if not. |
129 | | bool hasNode(const std::string &name); |
130 | | |
131 | | /// @brief Will parse an xml-file from a given stream. |
132 | | /// @param[in] stream The input stream. |
133 | | /// @return true, if the parsing was successful, false if not. |
134 | | bool parse(IOStream *stream); |
135 | | |
136 | | /// @brief Will parse an xml-file from a stringstream. |
137 | | /// @param[in] str The input istream (note: not "const" to match pugixml param) |
138 | | /// @return true, if the parsing was successful, false if not. |
139 | | bool parse(std::istream &inStream); |
140 | | |
141 | | /// @brief Will return true if a root node is there. |
142 | | /// @return true in case of an existing root. |
143 | | bool hasRoot() const; |
144 | | |
145 | | /// @brief Will return the document pointer, is nullptr if no xml-file was parsed. |
146 | | /// @return The pointer showing to the document. |
147 | | pugi::xml_document *getDocument() const; |
148 | | |
149 | | /// @brief Will return the root node, const version. |
150 | | /// @return The root node. |
151 | | const TNodeType getRootNode() const; |
152 | | |
153 | | /// @brief Will return the root node, non-const version. |
154 | | /// @return The root node. |
155 | | TNodeType getRootNode(); |
156 | | |
157 | | /// @brief Will check if a node with the given name is in. |
158 | | /// @param[in] node The node to look in. |
159 | | /// @param[in] name The name of the child-node. |
160 | | /// @return true, if node was found, false if not. |
161 | | static inline bool hasNode(XmlNode &node, const char *name); |
162 | | |
163 | | /// @brief Will check if an attribute is part of the XmlNode. |
164 | | /// @param[in] xmlNode The node to search in. |
165 | | /// @param[in] name The attribute name to look for. |
166 | | /// @return true, if the was found, false if not. |
167 | | static inline bool hasAttribute(XmlNode &xmlNode, const char *name); |
168 | | |
169 | | /// @brief Will try to get an unsigned int attribute value. |
170 | | /// @param[in] xmlNode The node to search in. |
171 | | /// @param[in] name The attribute name to look for. |
172 | | /// @param[out] val The unsigned int value from the attribute. |
173 | | /// @return true, if the node contains an attribute with the given name and if the value is an unsigned int. |
174 | | static inline bool getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val); |
175 | | |
176 | | /// @brief Will try to get an int attribute value. |
177 | | /// @param[in] xmlNode The node to search in. |
178 | | /// @param[in] name The attribute name to look for. |
179 | | /// @param[out] val The int value from the attribute. |
180 | | /// @return true, if the node contains an attribute with the given name and if the value is an int. |
181 | | static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val); |
182 | | |
183 | | /// @brief Will try to get a real attribute value. |
184 | | /// @param[in] xmlNode The node to search in. |
185 | | /// @param[in] name The attribute name to look for. |
186 | | /// @param[out] val The real value from the attribute. |
187 | | /// @return true, if the node contains an attribute with the given name and if the value is a real. |
188 | | static inline bool getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val); |
189 | | |
190 | | /// @brief Will try to get a float attribute value. |
191 | | /// @param[in] xmlNode The node to search in. |
192 | | /// @param[in] name The attribute name to look for. |
193 | | /// @param[out] val The float value from the attribute. |
194 | | /// @return true, if the node contains an attribute with the given name and if the value is a float. |
195 | | static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val); |
196 | | |
197 | | /// @brief Will try to get a double attribute value. |
198 | | /// @param[in] xmlNode The node to search in. |
199 | | /// @param[in] name The attribute name to look for. |
200 | | /// @param[out] val The double value from the attribute. |
201 | | /// @return true, if the node contains an attribute with the given name and if the value is a double. |
202 | | static inline bool getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val); |
203 | | |
204 | | /// @brief Will try to get a std::string attribute value. |
205 | | /// @param[in] xmlNode The node to search in. |
206 | | /// @param[in] name The attribute name to look for. |
207 | | /// @param[out] val The std::string value from the attribute. |
208 | | /// @return true, if the node contains an attribute with the given name and if the value is a std::string. |
209 | | static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val); |
210 | | |
211 | | /// @brief Will try to get a bool attribute value. |
212 | | /// @param[in] xmlNode The node to search in. |
213 | | /// @param[in] name The attribute name to look for. |
214 | | /// @param[out] val The bool value from the attribute. |
215 | | /// @return true, if the node contains an attribute with the given name and if the value is a bool. |
216 | | static inline bool getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val); |
217 | | |
218 | | /// @brief Will try to get the value of the node as a string. |
219 | | /// @param[in] node The node to search in. |
220 | | /// @param[out] text The value as a text. |
221 | | /// @return true, if the value can be read out. |
222 | | static inline bool getValueAsString(XmlNode &node, std::string &text); |
223 | | |
224 | | /// @brief Will try to get the value of the node as a real. |
225 | | /// @param[in] node The node to search in. |
226 | | /// @param[out] v The value as a ai_real. |
227 | | /// @return true, if the value can be read out. |
228 | | static inline bool getValueAsReal(XmlNode &node, ai_real &v); |
229 | | |
230 | | /// @brief Will try to get the value of the node as a float. |
231 | | /// @param[in] node The node to search in. |
232 | | /// @param[out]v The value as a float. |
233 | | /// @return true, if the value can be read out. |
234 | | static inline bool getValueAsFloat(XmlNode &node, float &v); |
235 | | |
236 | | /// @brief Will try to get the value of the node as an integer. |
237 | | /// @param[in] node The node to search in. |
238 | | /// @param[out] i The value as a int. |
239 | | /// @return true, if the value can be read out. |
240 | | static inline bool getValueAsInt(XmlNode &node, int &v); |
241 | | |
242 | | /// @brief Will try to get the value of the node as an bool. |
243 | | /// @param[in] node The node to search in. |
244 | | /// @param[out] v The value as a bool. |
245 | | /// @return true, if the value can be read out. |
246 | | static inline bool getValueAsBool(XmlNode &node, bool &v); |
247 | | |
248 | | private: |
249 | | pugi::xml_document *mDoc; |
250 | | TNodeType mCurrent; |
251 | | std::vector<char> mData; |
252 | | }; |
253 | | |
254 | | template <class TNodeType> |
255 | | inline TXmlParser<TNodeType>::TXmlParser() : |
256 | 9.25k | mDoc(nullptr), |
257 | 9.25k | mData() { |
258 | | // empty |
259 | 9.25k | } |
260 | | |
261 | | template <class TNodeType> |
262 | 9.25k | inline TXmlParser<TNodeType>::~TXmlParser() { |
263 | 9.25k | clear(); |
264 | 9.25k | } |
265 | | |
266 | | template <class TNodeType> |
267 | 9.25k | inline void TXmlParser<TNodeType>::clear() { |
268 | 9.25k | if (mData.empty()) { |
269 | 9.25k | if (mDoc) { |
270 | 0 | delete mDoc; |
271 | 0 | } |
272 | 9.25k | mDoc = nullptr; |
273 | 9.25k | return; |
274 | 9.25k | } |
275 | | |
276 | 0 | mData.clear(); |
277 | 0 | delete mDoc; |
278 | 0 | mDoc = nullptr; |
279 | 0 | } |
280 | | |
281 | | template <class TNodeType> |
282 | 0 | inline TNodeType *TXmlParser<TNodeType>::findNode(const std::string &name) { |
283 | 0 | if (name.empty()) { |
284 | 0 | return nullptr; |
285 | 0 | } |
286 | | |
287 | 0 | if (nullptr == mDoc) { |
288 | 0 | return nullptr; |
289 | 0 | } |
290 | | |
291 | 0 | find_node_by_name_predicate predicate(name); |
292 | 0 | mCurrent = mDoc->find_node(std::move(predicate)); |
293 | 0 | if (mCurrent.empty()) { |
294 | 0 | return nullptr; |
295 | 0 | } |
296 | | |
297 | 0 | return &mCurrent; |
298 | 0 | } |
299 | | |
300 | | template <class TNodeType> |
301 | 0 | bool TXmlParser<TNodeType>::hasNode(const std::string &name) { |
302 | 0 | return nullptr != findNode(name); |
303 | 0 | } |
304 | | |
305 | | template <class TNodeType> |
306 | 0 | bool TXmlParser<TNodeType>::parse(IOStream *stream) { |
307 | 0 | if (hasRoot()) { |
308 | 0 | clear(); |
309 | 0 | } |
310 | |
|
311 | 0 | if (nullptr == stream) { |
312 | 0 | ASSIMP_LOG_DEBUG("Stream is nullptr."); |
313 | 0 | return false; |
314 | 0 | } |
315 | | |
316 | 0 | const size_t len = stream->FileSize(); |
317 | 0 | mData.resize(len + 1); |
318 | 0 | memset(&mData[0], '\0', len + 1); |
319 | 0 | stream->Read(&mData[0], 1, len); |
320 | |
|
321 | 0 | mDoc = new pugi::xml_document(); |
322 | | // load_string assumes native encoding (aka always utf-8 per build options) |
323 | | //pugi::xml_parse_result parse_result = mDoc->load_string(&mData[0], pugi::parse_full); |
324 | 0 | pugi::xml_parse_result parse_result = mDoc->load_buffer(&mData[0], mData.size(), pugi::parse_full); |
325 | 0 | if (parse_result.status == pugi::status_ok) { |
326 | 0 | return true; |
327 | 0 | } |
328 | | |
329 | 0 | ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset); |
330 | |
|
331 | 0 | return false; |
332 | 0 | } |
333 | | |
334 | | template <class TNodeType> |
335 | 0 | bool TXmlParser<TNodeType>::parse(std::istream &inStream) { |
336 | 0 | if (hasRoot()) { |
337 | 0 | clear(); |
338 | 0 | } |
339 | 0 | mDoc = new pugi::xml_document(); |
340 | 0 | pugi::xml_parse_result parse_result = mDoc->load(inStream); |
341 | 0 | if (parse_result.status == pugi::status_ok) { |
342 | 0 | return true; |
343 | 0 | } |
344 | | |
345 | 0 | ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset); |
346 | |
|
347 | 0 | return false; |
348 | 0 | } |
349 | | |
350 | | template <class TNodeType> |
351 | 0 | bool TXmlParser<TNodeType>::hasRoot() const { |
352 | 0 | return nullptr != mDoc; |
353 | 0 | } |
354 | | |
355 | | template <class TNodeType> |
356 | | pugi::xml_document *TXmlParser<TNodeType>::getDocument() const { |
357 | | return mDoc; |
358 | | } |
359 | | |
360 | | template <class TNodeType> |
361 | | const TNodeType TXmlParser<TNodeType>::getRootNode() const { |
362 | | static pugi::xml_node none; |
363 | | if (nullptr == mDoc) { |
364 | | return none; |
365 | | } |
366 | | return mDoc->root(); |
367 | | } |
368 | | |
369 | | template <class TNodeType> |
370 | 0 | TNodeType TXmlParser<TNodeType>::getRootNode() { |
371 | 0 | static pugi::xml_node none; |
372 | 0 | if (nullptr == mDoc) { |
373 | 0 | return none; |
374 | 0 | } |
375 | | |
376 | 0 | return mDoc->root(); |
377 | 0 | } |
378 | | |
379 | | template <class TNodeType> |
380 | | inline bool TXmlParser<TNodeType>::hasNode(XmlNode &node, const char *name) { |
381 | | pugi::xml_node child = node.find_child(find_node_by_name_predicate(name)); |
382 | | return !child.empty(); |
383 | | } |
384 | | |
385 | | template <class TNodeType> |
386 | 0 | inline bool TXmlParser<TNodeType>::hasAttribute(XmlNode &xmlNode, const char *name) { |
387 | 0 | pugi::xml_attribute attr = xmlNode.attribute(name); |
388 | 0 | return !attr.empty(); |
389 | 0 | } |
390 | | |
391 | | template <class TNodeType> |
392 | 0 | inline bool TXmlParser<TNodeType>::getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val) { |
393 | 0 | pugi::xml_attribute attr = xmlNode.attribute(name); |
394 | 0 | if (attr.empty()) { |
395 | 0 | return false; |
396 | 0 | } |
397 | | |
398 | 0 | val = attr.as_uint(); |
399 | 0 | return true; |
400 | 0 | } |
401 | | |
402 | | template <class TNodeType> |
403 | 0 | inline bool TXmlParser<TNodeType>::getIntAttribute(XmlNode &xmlNode, const char *name, int &val) { |
404 | 0 | pugi::xml_attribute attr = xmlNode.attribute(name); |
405 | 0 | if (attr.empty()) { |
406 | 0 | return false; |
407 | 0 | } |
408 | | |
409 | 0 | val = attr.as_int(); |
410 | 0 | return true; |
411 | 0 | } |
412 | | |
413 | | template <class TNodeType> |
414 | 0 | inline bool TXmlParser<TNodeType>::getRealAttribute(XmlNode &xmlNode, const char *name, ai_real &val) { |
415 | 0 | pugi::xml_attribute attr = xmlNode.attribute(name); |
416 | 0 | if (attr.empty()) { |
417 | 0 | return false; |
418 | 0 | } |
419 | | #ifdef ASSIMP_DOUBLE_PRECISION |
420 | | val = attr.as_double(); |
421 | | #else |
422 | 0 | val = attr.as_float(); |
423 | 0 | #endif |
424 | 0 | return true; |
425 | 0 | } |
426 | | |
427 | | template <class TNodeType> |
428 | 0 | inline bool TXmlParser<TNodeType>::getFloatAttribute(XmlNode &xmlNode, const char *name, float &val) { |
429 | 0 | pugi::xml_attribute attr = xmlNode.attribute(name); |
430 | 0 | if (attr.empty()) { |
431 | 0 | return false; |
432 | 0 | } |
433 | | |
434 | 0 | val = attr.as_float(); |
435 | |
|
436 | 0 | return true; |
437 | 0 | } |
438 | | |
439 | | template <class TNodeType> |
440 | 0 | inline bool TXmlParser<TNodeType>::getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val) { |
441 | 0 | pugi::xml_attribute attr = xmlNode.attribute(name); |
442 | 0 | if (attr.empty()) { |
443 | 0 | return false; |
444 | 0 | } |
445 | | |
446 | 0 | val = attr.as_double(); |
447 | |
|
448 | 0 | return true; |
449 | 0 | } |
450 | | |
451 | | template <class TNodeType> |
452 | 0 | inline bool TXmlParser<TNodeType>::getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) { |
453 | 0 | pugi::xml_attribute attr = xmlNode.attribute(name); |
454 | 0 | if (attr.empty()) { |
455 | 0 | return false; |
456 | 0 | } |
457 | | |
458 | 0 | val = attr.as_string(); |
459 | |
|
460 | 0 | return true; |
461 | 0 | } |
462 | | |
463 | | template <class TNodeType> |
464 | 0 | inline bool TXmlParser<TNodeType>::getBoolAttribute(XmlNode &xmlNode, const char *name, bool &val) { |
465 | 0 | pugi::xml_attribute attr = xmlNode.attribute(name); |
466 | 0 | if (attr.empty()) { |
467 | 0 | return false; |
468 | 0 | } |
469 | | |
470 | 0 | val = attr.as_bool(); |
471 | |
|
472 | 0 | return true; |
473 | 0 | } |
474 | | |
475 | | template <class TNodeType> |
476 | 0 | inline bool TXmlParser<TNodeType>::getValueAsString(XmlNode &node, std::string &text) { |
477 | 0 | text = std::string(); |
478 | 0 | if (node.empty()) { |
479 | 0 | return false; |
480 | 0 | } |
481 | | |
482 | 0 | text = node.text().as_string(); |
483 | 0 | text = ai_trim(text); |
484 | |
|
485 | 0 | return true; |
486 | 0 | } |
487 | | |
488 | | template <class TNodeType> |
489 | 0 | inline bool TXmlParser<TNodeType>::getValueAsReal(XmlNode& node, ai_real& v) { |
490 | 0 | if (node.empty()) { |
491 | 0 | return false; |
492 | 0 | } |
493 | | |
494 | 0 | v = node.text().as_float(); |
495 | |
|
496 | 0 | return true; |
497 | 0 | } |
498 | | |
499 | | |
500 | | template <class TNodeType> |
501 | 0 | inline bool TXmlParser<TNodeType>::getValueAsFloat(XmlNode &node, float &v) { |
502 | 0 | if (node.empty()) { |
503 | 0 | return false; |
504 | 0 | } |
505 | | |
506 | 0 | v = node.text().as_float(); |
507 | |
|
508 | 0 | return true; |
509 | 0 | } |
510 | | |
511 | | template <class TNodeType> |
512 | | inline bool TXmlParser<TNodeType>::getValueAsInt(XmlNode &node, int &v) { |
513 | | if (node.empty()) { |
514 | | return false; |
515 | | } |
516 | | |
517 | | v = node.text().as_int(); |
518 | | |
519 | | return true; |
520 | | } |
521 | | |
522 | | template <class TNodeType> |
523 | 0 | inline bool TXmlParser<TNodeType>::getValueAsBool(XmlNode &node, bool &v) { |
524 | 0 | if (node.empty()) { |
525 | 0 | return false; |
526 | 0 | } |
527 | | |
528 | 0 | v = node.text().as_bool(); |
529 | |
|
530 | 0 | return true; |
531 | 0 | } |
532 | | |
533 | | using XmlParser = TXmlParser<pugi::xml_node>; |
534 | | |
535 | | /// @brief This class declares an iterator to loop through all children of the root node. |
536 | | class XmlNodeIterator { |
537 | | public: |
538 | | /// @brief The iteration mode. |
539 | | enum IterationMode { |
540 | | PreOrderMode, ///< Pre-ordering, get the values, continue the iteration. |
541 | | PostOrderMode ///< Post-ordering, continue the iteration, get the values. |
542 | | }; |
543 | | /// @brief The class constructor |
544 | | /// @param parent [in] The xml parent to to iterate through. |
545 | | /// @param mode [in] The iteration mode. |
546 | | explicit XmlNodeIterator(XmlNode &parent, IterationMode mode) : |
547 | 0 | mParent(parent), |
548 | 0 | mNodes(), |
549 | 0 | mIndex(0) { |
550 | 0 | if (mode == PreOrderMode) { |
551 | 0 | collectChildrenPreOrder(parent); |
552 | 0 | } else { |
553 | 0 | collectChildrenPostOrder(parent); |
554 | 0 | } |
555 | 0 | } |
556 | | |
557 | | /// @brief The class destructor, default implementation. |
558 | 0 | ~XmlNodeIterator() = default; |
559 | | |
560 | | /// @brief Will iterate through all children in pre-order iteration. |
561 | | /// @param node [in] The nod to iterate through. |
562 | 0 | void collectChildrenPreOrder(XmlNode &node) { |
563 | 0 | if (node != mParent && node.type() == pugi::node_element) { |
564 | 0 | mNodes.push_back(node); |
565 | 0 | } |
566 | 0 | for (XmlNode currentNode : node.children()) { |
567 | 0 | collectChildrenPreOrder(currentNode); |
568 | 0 | } |
569 | 0 | } |
570 | | |
571 | | /// @brief Will iterate through all children in post-order iteration. |
572 | | /// @param node [in] The nod to iterate through. |
573 | 0 | void collectChildrenPostOrder(XmlNode &node) { |
574 | 0 | for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { |
575 | 0 | collectChildrenPostOrder(currentNode); |
576 | 0 | } |
577 | 0 | if (node != mParent) { |
578 | 0 | mNodes.push_back(node); |
579 | 0 | } |
580 | 0 | } |
581 | | |
582 | | /// @brief Will iterate through all collected nodes. |
583 | | /// @param next The next node, if there is any. |
584 | | /// @return true, if there is a node left. |
585 | 0 | bool getNext(XmlNode &next) { |
586 | 0 | if (mIndex == mNodes.size()) { |
587 | 0 | return false; |
588 | 0 | } |
589 | | |
590 | 0 | next = mNodes[mIndex]; |
591 | 0 | ++mIndex; |
592 | |
|
593 | 0 | return true; |
594 | 0 | } |
595 | | |
596 | | /// @brief Will return the number of collected nodes. |
597 | | /// @return The number of collected nodes. |
598 | 0 | size_t size() const { |
599 | 0 | return mNodes.size(); |
600 | 0 | } |
601 | | |
602 | | /// @brief Returns true, if the node is empty. |
603 | | /// @return true, if the node is empty, false if not. |
604 | 0 | bool isEmpty() const { |
605 | 0 | return mNodes.empty(); |
606 | 0 | } |
607 | | |
608 | | /// @brief Will clear all collected nodes. |
609 | 0 | void clear() { |
610 | 0 | if (mNodes.empty()) { |
611 | 0 | return; |
612 | 0 | } |
613 | 0 |
|
614 | 0 | mNodes.clear(); |
615 | 0 | mIndex = 0; |
616 | 0 | } |
617 | | |
618 | | private: |
619 | | XmlNode &mParent; |
620 | | std::vector<XmlNode> mNodes; |
621 | | size_t mIndex; |
622 | | }; |
623 | | |
624 | | } // namespace Assimp |
625 | | |
626 | | #endif // !! INCLUDED_AI_IRRXML_WRAPPER |