aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llxml/llxmlnode.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llxml/llxmlnode.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/llxml/llxmlnode.cpp3027
1 files changed, 3027 insertions, 0 deletions
diff --git a/linden/indra/llxml/llxmlnode.cpp b/linden/indra/llxml/llxmlnode.cpp
new file mode 100644
index 0000000..6366519
--- /dev/null
+++ b/linden/indra/llxml/llxmlnode.cpp
@@ -0,0 +1,3027 @@
1/**
2 * @file llxmlnode.cpp
3 * @author Tom Yedwab
4 * @brief LLXMLNode implementation
5 *
6 * Copyright (c) 2005-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#include "linden_common.h"
30
31#include <iostream>
32#include <map>
33
34#include "llxmlnode.h"
35
36#include "v3color.h"
37#include "v4color.h"
38#include "v4coloru.h"
39#include "v3math.h"
40#include "v3dmath.h"
41#include "v4math.h"
42#include "llquaternion.h"
43#include "lluuid.h"
44
45const S32 MAX_COLUMN_WIDTH = 80;
46
47// static
48BOOL LLXMLNode::sStripEscapedStrings = TRUE;
49BOOL LLXMLNode::sStripWhitespaceValues = FALSE;
50
51LLXMLNode::LLXMLNode() :
52 mID(""),
53 mIsAttribute(FALSE),
54 mVersionMajor(0),
55 mVersionMinor(0),
56 mLength(0),
57 mPrecision(64),
58 mType(TYPE_CONTAINER),
59 mEncoding(ENCODING_DEFAULT),
60 mParent(NULL),
61 mChildren(NULL),
62 mName(NULL),
63 mValue(""),
64 mDefault(NULL)
65{
66}
67
68LLXMLNode::LLXMLNode(const LLString& name, BOOL is_attribute) :
69 mID(""),
70 mIsAttribute(is_attribute),
71 mVersionMajor(0),
72 mVersionMinor(0),
73 mLength(0),
74 mPrecision(64),
75 mType(TYPE_CONTAINER),
76 mEncoding(ENCODING_DEFAULT),
77 mParent(NULL),
78 mChildren(NULL),
79 mValue(""),
80 mDefault(NULL)
81{
82 mName = gStringTable.addStringEntry(name);
83}
84
85LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) :
86 mID(""),
87 mIsAttribute(is_attribute),
88 mVersionMajor(0),
89 mVersionMinor(0),
90 mLength(0),
91 mPrecision(64),
92 mType(TYPE_CONTAINER),
93 mEncoding(ENCODING_DEFAULT),
94 mParent(NULL),
95 mChildren(NULL),
96 mName(name),
97 mValue(""),
98 mDefault(NULL)
99{
100}
101
102// virtual
103LLXMLNode::~LLXMLNode()
104{
105 // Strictly speaking none of this should be required execept 'delete mChildren'...
106 if (mChildren)
107 {
108 for (LLXMLChildList::iterator iter = mChildren->map.begin();
109 iter != mChildren->map.end(); ++iter)
110 {
111 LLXMLNodePtr child = iter->second;
112 child->mParent = NULL;
113 child->mNext = NULL;
114 child->mPrev = NULL;
115 }
116 mChildren->map.clear();
117 mChildren->head = NULL;
118 mChildren->tail = NULL;
119 delete mChildren;
120 }
121 for (LLXMLAttribList::iterator iter = mAttributes.begin();
122 iter != mAttributes.end(); ++iter)
123 {
124 LLXMLNodePtr attr = iter->second;
125 attr->mParent = NULL;
126 attr->mNext = NULL;
127 attr->mPrev = NULL;
128 }
129 llassert(mParent == NULL);
130 mDefault = NULL;
131}
132
133BOOL LLXMLNode::isNull()
134{
135 return (mName == NULL);
136}
137
138// protected
139BOOL LLXMLNode::removeChild(LLXMLNode *target_child)
140{
141 if (!target_child)
142 {
143 return FALSE;
144 }
145 if (target_child->mIsAttribute)
146 {
147 LLXMLAttribList::iterator children_itr = mAttributes.find(target_child->mName);
148 if (children_itr != mAttributes.end())
149 {
150 target_child->mParent = NULL;
151 mAttributes.erase(children_itr);
152 return TRUE;
153 }
154 }
155 else if (mChildren)
156 {
157 LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName);
158 while (children_itr != mChildren->map.end())
159 {
160 if (target_child == children_itr->second)
161 {
162 if (target_child == mChildren->head)
163 {
164 mChildren->head = target_child->mNext;
165 }
166
167 LLXMLNodePtr prev = target_child->mPrev;
168 LLXMLNodePtr next = target_child->mNext;
169 if (prev.notNull()) prev->mNext = next;
170 if (next.notNull()) next->mPrev = prev;
171
172 target_child->mPrev = NULL;
173 target_child->mNext = NULL;
174 target_child->mParent = NULL;
175 mChildren->map.erase(children_itr);
176 if (mChildren->map.empty())
177 {
178 delete mChildren;
179 mChildren = NULL;
180 }
181 return TRUE;
182 }
183 else if (children_itr->first != target_child->mName)
184 {
185 break;
186 }
187 else
188 {
189 ++children_itr;
190 }
191 }
192 }
193 return FALSE;
194}
195
196void LLXMLNode::addChild(LLXMLNodePtr new_child)
197{
198 if (new_child->mParent != NULL)
199 {
200 if (new_child->mParent == this)
201 {
202 return;
203 }
204 new_child->mParent->removeChild(new_child);
205 }
206
207 new_child->mParent = this;
208 if (new_child->mIsAttribute)
209 {
210 mAttributes.insert(std::pair<LLStringTableEntry*, LLXMLNodePtr>(new_child->mName, new_child));
211 }
212 else
213 {
214 if (!mChildren)
215 {
216 mChildren = new LLXMLChildren();
217 mChildren->head = new_child;
218 mChildren->tail = new_child;
219 }
220 mChildren->map.insert(std::pair<LLStringTableEntry*, LLXMLNodePtr>(new_child->mName, new_child));
221
222 if (mChildren->tail != new_child)
223 {
224 mChildren->tail->mNext = new_child;
225 new_child->mPrev = mChildren->tail;
226 mChildren->tail = new_child;
227 }
228 }
229
230 new_child->updateDefault();
231}
232
233// virtual
234LLXMLNodePtr LLXMLNode::createChild(const LLString& name, BOOL is_attribute)
235{
236 return createChild(gStringTable.addStringEntry(name), is_attribute);
237}
238
239// virtual
240LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, BOOL is_attribute)
241{
242 LLXMLNode* ret = new LLXMLNode(name, is_attribute);
243 ret->mID = "";
244 addChild(ret);
245 return ret;
246}
247
248BOOL LLXMLNode::deleteChild(LLXMLNode *child)
249{
250 if (removeChild(child))
251 {
252 return TRUE;
253 }
254 return FALSE;
255}
256
257void LLXMLNode::setParent(LLXMLNodePtr new_parent)
258{
259 if (new_parent.notNull())
260 {
261 new_parent->addChild(this);
262 }
263 else
264 {
265 if (mParent != NULL)
266 {
267 LLXMLNodePtr old_parent = mParent;
268 mParent = NULL;
269 old_parent->removeChild(this);
270 }
271 }
272}
273
274
275void LLXMLNode::updateDefault()
276{
277 if (mParent != NULL && !mParent->mDefault.isNull())
278 {
279 mDefault = NULL;
280
281 // Find default value in parent's default tree
282 if (!mParent->mDefault.isNull())
283 {
284 findDefault(mParent->mDefault);
285 }
286 }
287
288 if (mChildren)
289 {
290 LLXMLChildList::const_iterator children_itr;
291 LLXMLChildList::const_iterator children_end = mChildren->map.end();
292 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
293 {
294 LLXMLNodePtr child = (*children_itr).second;
295 child->updateDefault();
296 }
297 }
298}
299
300void XMLCALL StartXMLNode(void *userData,
301 const XML_Char *name,
302 const XML_Char **atts)
303{
304 // Create a new node
305 LLXMLNode *new_node_ptr = new LLXMLNode(name, FALSE);
306 LLXMLNodePtr new_node = new_node_ptr;
307 new_node->mID = "";
308 LLXMLNodePtr ptr_new_node = new_node;
309
310 // Set the parent-child relationship with the current active node
311 LLXMLNode* parent = (LLXMLNode *)userData;
312
313 new_node_ptr->mParser = parent->mParser;
314
315 // Set the current active node to the new node
316 XML_Parser *parser = parent->mParser;
317 XML_SetUserData(*parser, (void *)new_node_ptr);
318
319 // Parse attributes
320 U32 pos = 0;
321 while (atts[pos] != NULL)
322 {
323 LLString attr_name = atts[pos];
324 LLString attr_value = atts[pos+1];
325
326 // Special cases
327 if ('i' == attr_name[0] && "id" == attr_name)
328 {
329 new_node->mID = attr_value;
330 }
331 else if ('v' == attr_name[0] && "version" == attr_name)
332 {
333 U32 version_major = 0;
334 U32 version_minor = 0;
335 if (sscanf(attr_value.c_str(), "%d.%d", &version_major, &version_minor) > 0)
336 {
337 new_node->mVersionMajor = version_major;
338 new_node->mVersionMinor = version_minor;
339 }
340 }
341 else if (('s' == attr_name[0] && "size" == attr_name) || ('l' == attr_name[0] && "length" == attr_name))
342 {
343 U32 length;
344 if (sscanf(attr_value.c_str(), "%d", &length) > 0)
345 {
346 new_node->mLength = length;
347 }
348 }
349 else if ('p' == attr_name[0] && "precision" == attr_name)
350 {
351 U32 precision;
352 if (sscanf(attr_value.c_str(), "%d", &precision) > 0)
353 {
354 new_node->mPrecision = precision;
355 }
356 }
357 else if ('t' == attr_name[0] && "type" == attr_name)
358 {
359 if ("boolean" == attr_value)
360 {
361 new_node->mType = LLXMLNode::TYPE_BOOLEAN;
362 }
363 else if ("integer" == attr_value)
364 {
365 new_node->mType = LLXMLNode::TYPE_INTEGER;
366 }
367 else if ("float" == attr_value)
368 {
369 new_node->mType = LLXMLNode::TYPE_FLOAT;
370 }
371 else if ("string" == attr_value)
372 {
373 new_node->mType = LLXMLNode::TYPE_STRING;
374 }
375 else if ("uuid" == attr_value)
376 {
377 new_node->mType = LLXMLNode::TYPE_UUID;
378 }
379 else if ("noderef" == attr_value)
380 {
381 new_node->mType = LLXMLNode::TYPE_NODEREF;
382 }
383 }
384 else if ('e' == attr_name[0] && "encoding" == attr_name)
385 {
386 if ("decimal" == attr_value)
387 {
388 new_node->mEncoding = LLXMLNode::ENCODING_DECIMAL;
389 }
390 else if ("hex" == attr_value)
391 {
392 new_node->mEncoding = LLXMLNode::ENCODING_HEX;
393 }
394 /*else if (attr_value == "base32")
395 {
396 new_node->mEncoding = LLXMLNode::ENCODING_BASE32;
397 }*/
398 }
399
400 // only one attribute child per description
401 LLXMLNodePtr attr_node;
402 if (!new_node->getAttribute(attr_name, attr_node, FALSE))
403 {
404 attr_node = new LLXMLNode(attr_name, TRUE);
405 }
406 attr_node->setValue(attr_value);
407 new_node->addChild(attr_node);
408
409 pos += 2;
410 }
411
412 if (parent)
413 {
414 parent->addChild(new_node);
415 }
416}
417
418void XMLCALL EndXMLNode(void *userData,
419 const XML_Char *name)
420{
421 // [FUGLY] Set the current active node to the current node's parent
422 LLXMLNode *node = (LLXMLNode *)userData;
423 XML_Parser *parser = node->mParser;
424 XML_SetUserData(*parser, (void *)node->mParent);
425 // SJB: total hack:
426 if (LLXMLNode::sStripWhitespaceValues)
427 {
428 LLString value = node->getValue();
429 BOOL is_empty = TRUE;
430 for (std::string::size_type s = 0; s < value.length(); s++)
431 {
432 char c = value[s];
433 if (c != ' ' && c != '\t' && c != '\n')
434 {
435 is_empty = FALSE;
436 break;
437 }
438 }
439 if (is_empty)
440 {
441 value.clear();
442 node->setValue(value);
443 }
444 }
445}
446
447void XMLCALL XMLData(void *userData,
448 const XML_Char *s,
449 int len)
450{
451 LLXMLNode* current_node = (LLXMLNode *)userData;
452 LLString value = current_node->getValue();
453 if (LLXMLNode::sStripEscapedStrings)
454 {
455 if (s[0] == '\"' && s[len-1] == '\"')
456 {
457 // Special-case: Escaped string.
458 LLString unescaped_string;
459 for (S32 pos=1; pos<len-1; ++pos)
460 {
461 if (s[pos] == '\\' && s[pos+1] == '\\')
462 {
463 unescaped_string.append("\\");
464 ++pos;
465 }
466 else if (s[pos] == '\\' && s[pos+1] == '\"')
467 {
468 unescaped_string.append("\"");
469 ++pos;
470 }
471 else
472 {
473 unescaped_string.append(&s[pos], 1);
474 }
475 }
476 value.append(unescaped_string);
477 current_node->setValue(value);
478 return;
479 }
480 }
481 value.append(LLString(s, 0, len));
482 current_node->setValue(value);
483}
484
485
486
487// static
488bool LLXMLNode::updateNode(
489 LLXMLNodePtr& node,
490 LLXMLNodePtr& update_node)
491{
492
493 if (!node || !update_node)
494 {
495 llwarns << "Node invalid" << llendl;
496 return FALSE;
497 }
498
499 //update the node value
500 node->mValue = update_node->mValue;
501
502 //update all attribute values
503 LLXMLAttribList::const_iterator itor;
504
505 for(itor = update_node->mAttributes.begin(); itor != update_node->mAttributes.end(); ++itor)
506 {
507 const LLStringTableEntry* attribNameEntry = (*itor).first;
508 LLXMLNodePtr updateAttribNode = (*itor).second;
509
510 LLXMLNodePtr attribNode;
511
512 node->getAttribute(attribNameEntry, attribNode, 0);
513
514 if (attribNode)
515 {
516 attribNode->mValue = updateAttribNode->mValue;
517 }
518 }
519
520 //update all of node's children with updateNodes children that match name
521 LLXMLNodePtr child;
522 LLXMLNodePtr updateChild;
523
524 for (updateChild = update_node->getFirstChild(); updateChild.notNull();
525 updateChild = updateChild->getNextSibling())
526 {
527 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
528 {
529 LLString nodeName;
530 LLString updateName;
531
532 updateChild->getAttributeString("name", updateName);
533 child->getAttributeString("name", nodeName);
534
535
536 //if it's a combobox there's no name, but there is a value
537 if (updateName.empty())
538 {
539 updateChild->getAttributeString("value", updateName);
540 child->getAttributeString("value", nodeName);
541 }
542
543 if ((nodeName != "") && (updateName == nodeName))
544 {
545 updateNode(child, updateChild);
546 break;
547 }
548 }
549 }
550
551 return TRUE;
552}
553
554
555
556
557// static
558bool LLXMLNode::parseFile(
559 LLString filename,
560 LLXMLNodePtr& node,
561 LLXMLNode* defaults_tree)
562{
563 // Read file
564 FILE* fp = LLFile::fopen(filename.c_str(), "rb");
565 if (fp == NULL)
566 {
567 node = new LLXMLNode();
568 return false;
569 }
570 fseek(fp, 0, SEEK_END);
571 U32 length = ftell(fp);
572 fseek(fp, 0, SEEK_SET);
573
574 U8* buffer = new U8[length+1];
575 fread(buffer, 1, length, fp);
576 buffer[length] = 0;
577 fclose(fp);
578
579 bool rv = parseBuffer(buffer, length, node, defaults_tree);
580 delete [] buffer;
581 return rv;
582}
583
584// static
585bool LLXMLNode::parseBuffer(
586 U8* buffer,
587 U32 length,
588 LLXMLNodePtr& node,
589 LLXMLNode* defaults)
590{
591 // Init
592 XML_Parser my_parser = XML_ParserCreate(NULL);
593 XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
594 XML_SetCharacterDataHandler(my_parser, XMLData);
595
596 // Create a root node
597 LLXMLNode *file_node_ptr = new LLXMLNode("XML", FALSE);
598 LLXMLNodePtr file_node = file_node_ptr;
599
600 file_node->mParser = &my_parser;
601
602 XML_SetUserData(my_parser, (void *)file_node_ptr);
603
604 // Do the parsing
605 if (XML_Parse(my_parser, (const char *)buffer, length, TRUE) != XML_STATUS_OK)
606 {
607 llwarns << "Error parsing xml error code: "
608 << XML_ErrorString(XML_GetErrorCode(my_parser))
609 << " on lne " << XML_GetCurrentLineNumber(my_parser)
610 << llendl;
611 }
612
613 // Deinit
614 XML_ParserFree(my_parser);
615
616 if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
617 {
618 llwarns << "Parse failure - wrong number of top-level nodes xml."
619 << llendl;
620 node = new LLXMLNode();
621 return false;
622 }
623
624 LLXMLNode *return_node = file_node->mChildren->map.begin()->second;
625
626 return_node->setDefault(defaults);
627 return_node->updateDefault();
628
629 node = return_node;
630 return true;
631}
632
633BOOL LLXMLNode::isFullyDefault()
634{
635 if (mDefault.isNull())
636 {
637 return FALSE;
638 }
639 BOOL has_default_value = (mValue == mDefault->mValue);
640 BOOL has_default_attribute = (mIsAttribute == mDefault->mIsAttribute);
641 BOOL has_default_type = mIsAttribute || (mType == mDefault->mType);
642 BOOL has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding);
643 BOOL has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision);
644 BOOL has_default_length = mIsAttribute || (mLength == mDefault->mLength);
645
646 if (has_default_value
647 && has_default_type
648 && has_default_encoding
649 && has_default_precision
650 && has_default_length
651 && has_default_attribute)
652 {
653 if (mChildren)
654 {
655 LLXMLChildList::const_iterator children_itr;
656 LLXMLChildList::const_iterator children_end = mChildren->map.end();
657 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
658 {
659 LLXMLNodePtr child = (*children_itr).second;
660 if (!child->isFullyDefault())
661 {
662 return FALSE;
663 }
664 }
665 }
666 return TRUE;
667 }
668
669 return FALSE;
670}
671
672// static
673void LLXMLNode::writeHeaderToFile(FILE *fOut)
674{
675 fprintf(fOut, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n");
676}
677
678void LLXMLNode::writeToFile(FILE *fOut, LLString indent)
679{
680 if (isFullyDefault())
681 {
682 // Don't write out nodes that are an exact match to defaults
683 return;
684 }
685
686 std::ostringstream ostream;
687 writeToOstream(ostream, indent);
688 LLString outstring = ostream.str();
689 fwrite(outstring.c_str(), 1, outstring.length(), fOut);
690}
691
692void LLXMLNode::writeToOstream(std::ostream& output_stream, const LLString& indent)
693{
694 if (isFullyDefault())
695 {
696 // Don't write out nodes that are an exact match to defaults
697 return;
698 }
699
700 BOOL has_default_type = mDefault.isNull()?FALSE:(mType == mDefault->mType);
701 BOOL has_default_encoding = mDefault.isNull()?FALSE:(mEncoding == mDefault->mEncoding);
702 BOOL has_default_precision = mDefault.isNull()?FALSE:(mPrecision == mDefault->mPrecision);
703 BOOL has_default_length = mDefault.isNull()?FALSE:(mLength == mDefault->mLength);
704
705 // stream the name
706 output_stream << indent.c_str() << "<" << mName->mString;
707
708 // ID
709 if (mID != "")
710 {
711 output_stream << " id=\"" << mID.c_str() << "\"";
712 }
713
714 // Type
715 if (!has_default_type)
716 {
717 switch (mType)
718 {
719 case TYPE_BOOLEAN:
720 output_stream << " type=\"boolean\"";
721 break;
722 case TYPE_INTEGER:
723 output_stream << " type=\"integer\"";
724 break;
725 case TYPE_FLOAT:
726 output_stream << " type=\"float\"";
727 break;
728 case TYPE_STRING:
729 output_stream << " type=\"string\"";
730 break;
731 case TYPE_UUID:
732 output_stream << " type=\"uuid\"";
733 break;
734 case TYPE_NODEREF:
735 output_stream << " type=\"noderef\"";
736 break;
737 default:
738 // default on switch(enum) eliminates a warning on linux
739 break;
740 };
741 }
742
743 // Encoding
744 if (!has_default_encoding)
745 {
746 switch (mEncoding)
747 {
748 case ENCODING_DECIMAL:
749 output_stream << " encoding=\"decimal\"";
750 break;
751 case ENCODING_HEX:
752 output_stream << " encoding=\"hex\"";
753 break;
754 /*case ENCODING_BASE32:
755 output_stream << " encoding=\"base32\"";
756 break;*/
757 default:
758 // default on switch(enum) eliminates a warning on linux
759 break;
760 };
761 }
762
763 // Precision
764 if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT))
765 {
766 output_stream << " precision=\"" << mPrecision << "\"";
767 }
768
769 // Version
770 if (mVersionMajor > 0 || mVersionMinor > 0)
771 {
772 output_stream << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"";
773 }
774
775 // Array length
776 if (!has_default_length && mLength > 0)
777 {
778 output_stream << " length=\"" << mLength << "\"";
779 }
780
781 {
782 // Write out attributes
783 S32 col_pos = 0;
784 LLXMLAttribList::const_iterator attr_itr;
785 LLXMLAttribList::const_iterator attr_end = mAttributes.end();
786 for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr)
787 {
788 LLXMLNodePtr child = (*attr_itr).second;
789 if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue)
790 {
791 LLString attr = child->mName->mString;
792 if (attr == "id" ||
793 attr == "type" ||
794 attr == "encoding" ||
795 attr == "precision" ||
796 attr == "version" ||
797 attr == "length")
798 {
799 continue; // skip built-in attributes
800 }
801
802 LLString attr_str = llformat(" %s=\"%s\"",
803 attr.c_str(),
804 escapeXML(child->mValue).c_str());
805 if (col_pos + (S32)attr_str.length() > MAX_COLUMN_WIDTH)
806 {
807 output_stream << "\n" << indent << " ";
808 col_pos = 4;
809 }
810 col_pos += attr_str.length();
811 output_stream << attr_str;
812 }
813 }
814 }
815
816 if (!mChildren && mValue == "")
817 {
818 output_stream << " />\n";
819 return;
820 }
821 else
822 {
823 output_stream << ">\n";
824 if (mChildren)
825 {
826 // stream non-attributes
827 LLString next_indent = indent + "\t";
828 for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling())
829 {
830 child->writeToOstream(output_stream, next_indent);
831 }
832 }
833 if (!mValue.empty())
834 {
835 LLString contents = getTextContents();
836 output_stream << indent.c_str() << "\t" << escapeXML(contents) << "\n";
837 }
838 output_stream << indent.c_str() << "</" << mName->mString << ">\n";
839 }
840}
841
842void LLXMLNode::findName(const LLString& name, LLXMLNodeList &results)
843{
844 LLStringTableEntry* name_entry = gStringTable.checkStringEntry(name);
845 if (name_entry == mName)
846 {
847 results.insert(std::pair<LLString, LLXMLNode*>(this->mName->mString, this));
848 return;
849 }
850 if (mChildren)
851 {
852 LLXMLChildList::const_iterator children_itr;
853 LLXMLChildList::const_iterator children_end = mChildren->map.end();
854 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
855 {
856 LLXMLNodePtr child = (*children_itr).second;
857 child->findName(name_entry, results);
858 }
859 }
860}
861
862void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results)
863{
864 if (name == mName)
865 {
866 results.insert(std::pair<LLString, LLXMLNode*>(this->mName->mString, this));
867 return;
868 }
869 if (mChildren)
870 {
871 LLXMLChildList::const_iterator children_itr;
872 LLXMLChildList::const_iterator children_end = mChildren->map.end();
873 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
874 {
875 LLXMLNodePtr child = (*children_itr).second;
876 child->findName(name, results);
877 }
878 }
879}
880
881void LLXMLNode::findID(const LLString& id, LLXMLNodeList &results)
882{
883 if (id == mID)
884 {
885 results.insert(std::pair<LLString, LLXMLNode*>(this->mName->mString, this));
886 return;
887 }
888 if (mChildren)
889 {
890 LLXMLChildList::const_iterator children_itr;
891 LLXMLChildList::const_iterator children_end = mChildren->map.end();
892 for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
893 {
894 LLXMLNodePtr child = (*children_itr).second;
895 child->findID(id, results);
896 }
897 }
898}
899
900void LLXMLNode::scrubToTree(LLXMLNode *tree)
901{
902 if (!tree || !tree->mChildren)
903 {
904 return;
905 }
906 if (mChildren)
907 {
908 std::vector<LLXMLNodePtr> to_delete_list;
909 LLXMLChildList::iterator itor = mChildren->map.begin();
910 while (itor != mChildren->map.end())
911 {
912 LLXMLNodePtr child = itor->second;
913 LLXMLNodePtr child_tree = NULL;
914 // Look for this child in the default's children
915 bool found = false;
916 LLXMLChildList::iterator itor2 = tree->mChildren->map.begin();
917 while (itor2 != tree->mChildren->map.end())
918 {
919 if (child->mName == itor2->second->mName)
920 {
921 child_tree = itor2->second;
922 found = true;
923 }
924 ++itor2;
925 }
926 if (!found)
927 {
928 to_delete_list.push_back(child);
929 }
930 else
931 {
932 child->scrubToTree(child_tree);
933 }
934 ++itor;
935 }
936 std::vector<LLXMLNodePtr>::iterator itor3;
937 for (itor3=to_delete_list.begin(); itor3!=to_delete_list.end(); ++itor3)
938 {
939 (*itor3)->setParent(NULL);
940 }
941 }
942}
943
944bool LLXMLNode::getChild(const LLString& name, LLXMLNodePtr& node, BOOL use_default_if_missing)
945{
946 return getChild(gStringTable.checkStringEntry(name), node, use_default_if_missing);
947}
948
949bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
950{
951 if (mChildren)
952 {
953 LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
954 if (child_itr != mChildren->map.end())
955 {
956 node = (*child_itr).second;
957 return true;
958 }
959 }
960 if (use_default_if_missing && !mDefault.isNull())
961 {
962 return mDefault->getChild(name, node, FALSE);
963 }
964 node = new LLXMLNode();
965 return false;
966}
967
968void LLXMLNode::getChildren(const LLString& name, LLXMLNodeList &children, BOOL use_default_if_missing) const
969{
970 getChildren(gStringTable.checkStringEntry(name), children, use_default_if_missing);
971}
972
973void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing) const
974{
975 if (mChildren)
976 {
977 LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
978 if (child_itr != mChildren->map.end())
979 {
980 LLXMLChildList::const_iterator children_end = mChildren->map.end();
981 while (child_itr != children_end)
982 {
983 LLXMLNodePtr child = (*child_itr).second;
984 if (name != child->mName)
985 {
986 break;
987 }
988 children.insert(std::pair<LLString, LLXMLNodePtr>(child->mName->mString, child));
989 child_itr++;
990 }
991 }
992 }
993 if (children.size() == 0 && use_default_if_missing && !mDefault.isNull())
994 {
995 mDefault->getChildren(name, children, FALSE);
996 }
997}
998
999bool LLXMLNode::getAttribute(const LLString& name, LLXMLNodePtr& node, BOOL use_default_if_missing)
1000{
1001 return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing);
1002}
1003
1004bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
1005{
1006 LLXMLAttribList::const_iterator child_itr = mAttributes.find(name);
1007 if (child_itr != mAttributes.end())
1008 {
1009 node = (*child_itr).second;
1010 return true;
1011 }
1012 if (use_default_if_missing && !mDefault.isNull())
1013 {
1014 return mDefault->getAttribute(name, node, FALSE);
1015 }
1016 node = new LLXMLNode();
1017 return false;
1018}
1019
1020bool LLXMLNode::setAttributeString(const LLString& attr, const LLString& value)
1021{
1022 LLStringTableEntry* name = gStringTable.checkStringEntry(attr);
1023 LLXMLAttribList::const_iterator child_itr = mAttributes.find(name);
1024 if (child_itr != mAttributes.end())
1025 {
1026 LLXMLNodePtr node = (*child_itr).second;
1027 node->setValue(value);
1028 return true;
1029 }
1030 return false;
1031}
1032
1033BOOL LLXMLNode::hasAttribute(const LLString& name )
1034{
1035 LLXMLNodePtr node;
1036 return getAttribute(name, node);
1037}
1038
1039BOOL LLXMLNode::getAttributeBOOL(const LLString& name, BOOL& value )
1040{
1041 LLXMLNodePtr node;
1042 return (getAttribute(name, node) && node->getBoolValue(1, &value));
1043}
1044
1045BOOL LLXMLNode::getAttributeU8(const LLString& name, U8& value )
1046{
1047 LLXMLNodePtr node;
1048 return (getAttribute(name, node) && node->getByteValue(1, &value));
1049}
1050
1051BOOL LLXMLNode::getAttributeS8(const LLString& name, S8& value )
1052{
1053 LLXMLNodePtr node;
1054 S32 val;
1055 if (!(getAttribute(name, node) && node->getIntValue(1, &val)))
1056 {
1057 return false;
1058 }
1059 value = val;
1060 return true;
1061}
1062
1063BOOL LLXMLNode::getAttributeU16(const LLString& name, U16& value )
1064{
1065 LLXMLNodePtr node;
1066 U32 val;
1067 if (!(getAttribute(name, node) && node->getUnsignedValue(1, &val)))
1068 {
1069 return false;
1070 }
1071 value = val;
1072 return true;
1073}
1074
1075BOOL LLXMLNode::getAttributeS16(const LLString& name, S16& value )
1076{
1077 LLXMLNodePtr node;
1078 S32 val;
1079 if (!(getAttribute(name, node) && node->getIntValue(1, &val)))
1080 {
1081 return false;
1082 }
1083 value = val;
1084 return true;
1085}
1086
1087BOOL LLXMLNode::getAttributeU32(const LLString& name, U32& value )
1088{
1089 LLXMLNodePtr node;
1090 return (getAttribute(name, node) && node->getUnsignedValue(1, &value));
1091}
1092
1093BOOL LLXMLNode::getAttributeS32(const LLString& name, S32& value )
1094{
1095 LLXMLNodePtr node;
1096 return (getAttribute(name, node) && node->getIntValue(1, &value));
1097}
1098
1099BOOL LLXMLNode::getAttributeF32(const LLString& name, F32& value )
1100{
1101 LLXMLNodePtr node;
1102 return (getAttribute(name, node) && node->getFloatValue(1, &value));
1103}
1104
1105BOOL LLXMLNode::getAttributeF64(const LLString& name, F64& value )
1106{
1107 LLXMLNodePtr node;
1108 return (getAttribute(name, node) && node->getDoubleValue(1, &value));
1109}
1110
1111BOOL LLXMLNode::getAttributeColor(const LLString& name, LLColor4& value )
1112{
1113 LLXMLNodePtr node;
1114 return (getAttribute(name, node) && node->getFloatValue(4, value.mV));
1115}
1116
1117BOOL LLXMLNode::getAttributeColor4(const LLString& name, LLColor4& value )
1118{
1119 LLXMLNodePtr node;
1120 return (getAttribute(name, node) && node->getFloatValue(4, value.mV));
1121}
1122
1123BOOL LLXMLNode::getAttributeColor4U(const LLString& name, LLColor4U& value )
1124{
1125 LLXMLNodePtr node;
1126 return (getAttribute(name, node) && node->getByteValue(4, value.mV));
1127}
1128
1129BOOL LLXMLNode::getAttributeVector3(const LLString& name, LLVector3& value )
1130{
1131 LLXMLNodePtr node;
1132 return (getAttribute(name, node) && node->getFloatValue(3, value.mV));
1133}
1134
1135BOOL LLXMLNode::getAttributeVector3d(const LLString& name, LLVector3d& value )
1136{
1137 LLXMLNodePtr node;
1138 return (getAttribute(name, node) && node->getDoubleValue(3, value.mdV));
1139}
1140
1141BOOL LLXMLNode::getAttributeQuat(const LLString& name, LLQuaternion& value )
1142{
1143 LLXMLNodePtr node;
1144 return (getAttribute(name, node) && node->getFloatValue(4, value.mQ));
1145}
1146
1147BOOL LLXMLNode::getAttributeUUID(const LLString& name, LLUUID& value )
1148{
1149 LLXMLNodePtr node;
1150 return (getAttribute(name, node) && node->getUUIDValue(1, &value));
1151}
1152
1153BOOL LLXMLNode::getAttributeString(const LLString& name, LLString& value )
1154{
1155 LLXMLNodePtr node;
1156 if (!getAttribute(name, node))
1157 {
1158 return false;
1159 }
1160 value = node->getValue();
1161 return true;
1162}
1163
1164LLXMLNodePtr LLXMLNode::getRoot()
1165{
1166 if (mParent == NULL)
1167 {
1168 return this;
1169 }
1170 return mParent->getRoot();
1171}
1172
1173/*static */
1174const char *LLXMLNode::skipWhitespace(const char *str)
1175{
1176 // skip whitespace characters
1177 while (str[0] == ' ' || str[0] == '\t' || str[0] == '\n') ++str;
1178 return str;
1179}
1180
1181/*static */
1182const char *LLXMLNode::skipNonWhitespace(const char *str)
1183{
1184 // skip non-whitespace characters
1185 while (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != 0) ++str;
1186 return str;
1187}
1188
1189/*static */
1190const char *LLXMLNode::parseInteger(const char *str, U64 *dest, BOOL *is_negative, U32 precision, Encoding encoding)
1191{
1192 *dest = 0;
1193 *is_negative = FALSE;
1194
1195 str = skipWhitespace(str);
1196
1197 if (str[0] == 0) return NULL;
1198
1199 if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT)
1200 {
1201 if (str[0] == '+')
1202 {
1203 ++str;
1204 }
1205 if (str[0] == '-')
1206 {
1207 *is_negative = TRUE;
1208 ++str;
1209 }
1210
1211 str = skipWhitespace(str);
1212
1213 U64 ret = 0;
1214 while (str[0] >= '0' && str[0] <= '9')
1215 {
1216 ret *= 10;
1217 ret += str[0] - '0';
1218 ++str;
1219 }
1220
1221 if (str[0] == '.')
1222 {
1223 // If there is a fractional part, skip it
1224 str = skipNonWhitespace(str);
1225 }
1226
1227 *dest = ret;
1228 return str;
1229 }
1230 if (encoding == ENCODING_HEX)
1231 {
1232 U64 ret = 0;
1233 str = skipWhitespace(str);
1234 for (U32 pos=0; pos<(precision/4); ++pos)
1235 {
1236 ret <<= 4;
1237 str = skipWhitespace(str);
1238 if (str[0] >= '0' && str[0] <= '9')
1239 {
1240 ret += str[0] - '0';
1241 }
1242 else if (str[0] >= 'a' && str[0] <= 'f')
1243 {
1244 ret += str[0] - 'a' + 10;
1245 }
1246 else if (str[0] >= 'A' && str[0] <= 'F')
1247 {
1248 ret += str[0] - 'A' + 10;
1249 }
1250 else
1251 {
1252 return NULL;
1253 }
1254 ++str;
1255 }
1256
1257 *dest = ret;
1258 return str;
1259 }
1260 return NULL;
1261}
1262
1263// 25 elements - decimal expansions of 1/(2^n), multiplied by 10 each iteration
1264const U64 float_coeff_table[] =
1265 { 5, 25, 125, 625, 3125,
1266 15625, 78125, 390625, 1953125, 9765625,
1267 48828125, 244140625, 1220703125, 6103515625LL, 30517578125LL,
1268 152587890625LL, 762939453125LL, 3814697265625LL, 19073486328125LL, 95367431640625LL,
1269 476837158203125LL, 2384185791015625LL, 11920928955078125LL, 59604644775390625LL, 298023223876953125LL };
1270
1271// 36 elements - decimal expansions of 1/(2^n) after the last 28, truncated, no multiply each iteration
1272const U64 float_coeff_table_2[] =
1273 { 149011611938476562LL,74505805969238281LL,
1274 37252902984619140LL, 18626451492309570LL, 9313225746154785LL, 4656612873077392LL,
1275 2328306436538696LL, 1164153218269348LL, 582076609134674LL, 291038304567337LL,
1276 145519152283668LL, 72759576141834LL, 36379788070917LL, 18189894035458LL,
1277 9094947017729LL, 4547473508864LL, 2273736754432LL, 1136868377216LL,
1278 568434188608LL, 284217094304LL, 142108547152LL, 71054273576LL,
1279 35527136788LL, 17763568394LL, 8881784197LL, 4440892098LL,
1280 2220446049LL, 1110223024LL, 555111512LL, 277555756LL,
1281 138777878, 69388939, 34694469, 17347234,
1282 8673617, 4336808, 2168404, 1084202,
1283 542101, 271050, 135525, 67762,
1284 };
1285
1286/*static */
1287const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding)
1288{
1289 str = skipWhitespace(str);
1290
1291 if (str[0] == 0) return NULL;
1292
1293 if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT)
1294 {
1295 str = skipWhitespace(str);
1296
1297 if (memcmp(str, "inf", 3) == 0)
1298 {
1299 *(U64 *)dest = 0x7FF0000000000000ll;
1300 return str + 3;
1301 }
1302 if (memcmp(str, "-inf", 4) == 0)
1303 {
1304 *(U64 *)dest = 0xFFF0000000000000ll;
1305 return str + 4;
1306 }
1307 if (memcmp(str, "1.#INF", 6) == 0)
1308 {
1309 *(U64 *)dest = 0x7FF0000000000000ll;
1310 return str + 6;
1311 }
1312 if (memcmp(str, "-1.#INF", 7) == 0)
1313 {
1314 *(U64 *)dest = 0xFFF0000000000000ll;
1315 return str + 7;
1316 }
1317
1318 F64 negative = 1.0f;
1319 if (str[0] == '+')
1320 {
1321 ++str;
1322 }
1323 if (str[0] == '-')
1324 {
1325 negative = -1.0f;
1326 ++str;
1327 }
1328
1329 const char* base_str = str;
1330 str = skipWhitespace(str);
1331
1332 // Parse the integer part of the expression
1333 U64 int_part = 0;
1334 while (str[0] >= '0' && str[0] <= '9')
1335 {
1336 int_part *= 10;
1337 int_part += U64(str[0] - '0');
1338 ++str;
1339 }
1340
1341 U64 f_part = 0;//, f_decimal = 1;
1342 if (str[0] == '.')
1343 {
1344 ++str;
1345 U64 remainder = 0;
1346 U32 pos = 0;
1347 // Parse the decimal part of the expression
1348 while (str[0] >= '0' && str[0] <= '9' && pos < 25)
1349 {
1350 remainder = (remainder*10) + U64(str[0] - '0');
1351 f_part <<= 1;
1352 //f_decimal <<= 1;
1353 // Check the n'th bit
1354 if (remainder >= float_coeff_table[pos])
1355 {
1356 remainder -= float_coeff_table[pos];
1357 f_part |= 1;
1358 }
1359 ++pos;
1360 ++str;
1361 }
1362 if (pos == 25)
1363 {
1364 // Drop any excessive digits
1365 while (str[0] >= '0' && str[0] <= '9')
1366 {
1367 ++str;
1368 }
1369 }
1370 else
1371 {
1372 while (pos < 25)
1373 {
1374 remainder *= 10;
1375 f_part <<= 1;
1376 //f_decimal <<= 1;
1377 // Check the n'th bit
1378 if (remainder >= float_coeff_table[pos])
1379 {
1380 remainder -= float_coeff_table[pos];
1381 f_part |= 1;
1382 }
1383 ++pos;
1384 }
1385 }
1386 pos = 0;
1387 while (pos < 36)
1388 {
1389 f_part <<= 1;
1390 //f_decimal <<= 1;
1391 if (remainder >= float_coeff_table_2[pos])
1392 {
1393 remainder -= float_coeff_table_2[pos];
1394 f_part |= 1;
1395 }
1396 ++pos;
1397 }
1398 }
1399
1400 F64 ret = F64(int_part) + (F64(f_part)/F64(1LL<<61));
1401
1402 F64 exponent = 1.f;
1403 if (str[0] == 'e')
1404 {
1405 // Scientific notation!
1406 ++str;
1407 U64 exp;
1408 BOOL is_negative;
1409 str = parseInteger(str, &exp, &is_negative, 64, ENCODING_DECIMAL);
1410 if (str == NULL)
1411 {
1412 exp = 1;
1413 }
1414 F64 exp_d = F64(exp) * (is_negative?-1:1);
1415 exponent = pow(10.0, exp_d);
1416 }
1417
1418 if (str == base_str)
1419 {
1420 // no digits parsed
1421 return NULL;
1422 }
1423 else
1424 {
1425 *dest = ret*negative*exponent;
1426 return str;
1427 }
1428 }
1429 if (encoding == ENCODING_HEX)
1430 {
1431 U64 bytes_dest;
1432 BOOL is_negative;
1433 str = parseInteger(str, (U64 *)&bytes_dest, &is_negative, precision, ENCODING_HEX);
1434 // Upcast to F64
1435 switch (precision)
1436 {
1437 case 32:
1438 {
1439 U32 short_dest = (U32)bytes_dest;
1440 F32 ret_val = *(F32 *)&short_dest;
1441 *dest = ret_val;
1442 }
1443 break;
1444 case 64:
1445 *dest = *(F64 *)&bytes_dest;
1446 break;
1447 default:
1448 return NULL;
1449 }
1450 return str;
1451 }
1452 return NULL;
1453}
1454
1455U32 LLXMLNode::getBoolValue(U32 expected_length, BOOL *array)
1456{
1457 llassert(array);
1458
1459 // Check type - accept booleans or strings
1460 if (mType != TYPE_BOOLEAN && mType != TYPE_STRING && mType != TYPE_UNKNOWN)
1461 {
1462 return 0;
1463 }
1464
1465 LLString *str_array = new LLString[expected_length];
1466
1467 U32 length = getStringValue(expected_length, str_array);
1468
1469 U32 ret_length = 0;
1470 for (U32 i=0; i<length; ++i)
1471 {
1472 LLString::toLower(str_array[i]);
1473 if (str_array[i] == "false")
1474 {
1475 array[ret_length++] = FALSE;
1476 }
1477 else if (str_array[i] == "true")
1478 {
1479 array[ret_length++] = TRUE;
1480 }
1481 }
1482
1483 delete[] str_array;
1484
1485#if LL_DEBUG
1486 if (ret_length != expected_length)
1487 {
1488 lldebugs << "LLXMLNode::getBoolValue() failed for node named '"
1489 << mName->mString << "' -- expected " << expected_length << " but "
1490 << "only found " << ret_length << llendl;
1491 }
1492#endif
1493 return ret_length;
1494}
1495
1496U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding)
1497{
1498 llassert(array);
1499
1500 // Check type - accept bytes or integers (below 256 only)
1501 if (mType != TYPE_INTEGER
1502 && mType != TYPE_UNKNOWN)
1503 {
1504 return 0;
1505 }
1506
1507 if (mLength > 0 && mLength != expected_length)
1508 {
1509 llwarns << "XMLNode::getByteValue asked for " << expected_length
1510 << " elements, while node has " << mLength << llendl;
1511 return 0;
1512 }
1513
1514 if (encoding == ENCODING_DEFAULT)
1515 {
1516 encoding = mEncoding;
1517 }
1518
1519 const char *value_string = mValue.c_str();
1520
1521 U32 i;
1522 for (i=0; i<expected_length; ++i)
1523 {
1524 U64 value;
1525 BOOL is_negative;
1526 value_string = parseInteger(value_string, &value, &is_negative, 8, encoding);
1527 if (value_string == NULL)
1528 {
1529 break;
1530 }
1531 if (value > 255 || is_negative)
1532 {
1533 llwarns << "getByteValue: Value outside of valid range." << llendl;
1534 break;
1535 }
1536 array[i] = U8(value);
1537 }
1538#if LL_DEBUG
1539 if (i != expected_length)
1540 {
1541 lldebugs << "LLXMLNode::getByteValue() failed for node named '"
1542 << mName->mString << "' -- expected " << expected_length << " but "
1543 << "only found " << i << llendl;
1544 }
1545#endif
1546 return i;
1547}
1548
1549U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding)
1550{
1551 llassert(array);
1552
1553 // Check type - accept bytes or integers
1554 if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
1555 {
1556 return 0;
1557 }
1558
1559 if (mLength > 0 && mLength != expected_length)
1560 {
1561 llwarns << "XMLNode::getIntValue asked for " << expected_length
1562 << " elements, while node has " << mLength << llendl;
1563 return 0;
1564 }
1565
1566 if (encoding == ENCODING_DEFAULT)
1567 {
1568 encoding = mEncoding;
1569 }
1570
1571 const char *value_string = mValue.c_str();
1572
1573 U32 i = 0;
1574 for (i=0; i<expected_length; ++i)
1575 {
1576 U64 value;
1577 BOOL is_negative;
1578 value_string = parseInteger(value_string, &value, &is_negative, 32, encoding);
1579 if (value_string == NULL)
1580 {
1581 break;
1582 }
1583 if (value > 0x7fffffff)
1584 {
1585 llwarns << "getIntValue: Value outside of valid range." << llendl;
1586 break;
1587 }
1588 array[i] = S32(value) * (is_negative?-1:1);
1589 }
1590
1591#if LL_DEBUG
1592 if (i != expected_length)
1593 {
1594 lldebugs << "LLXMLNode::getIntValue() failed for node named '"
1595 << mName->mString << "' -- expected " << expected_length << " but "
1596 << "only found " << i << llendl;
1597 }
1598#endif
1599 return i;
1600}
1601
1602U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding)
1603{
1604 llassert(array);
1605
1606 // Check type - accept bytes or integers
1607 if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
1608 {
1609 return 0;
1610 }
1611
1612 if (mLength > 0 && mLength != expected_length)
1613 {
1614 llwarns << "XMLNode::getUnsignedValue asked for " << expected_length
1615 << " elements, while node has " << mLength << llendl;
1616 return 0;
1617 }
1618
1619 if (encoding == ENCODING_DEFAULT)
1620 {
1621 encoding = mEncoding;
1622 }
1623
1624 const char *value_string = mValue.c_str();
1625
1626 U32 i = 0;
1627 // Int type
1628 for (i=0; i<expected_length; ++i)
1629 {
1630 U64 value;
1631 BOOL is_negative;
1632 value_string = parseInteger(value_string, &value, &is_negative, 32, encoding);
1633 if (value_string == NULL)
1634 {
1635 break;
1636 }
1637 if (is_negative || value > 0xffffffff)
1638 {
1639 llwarns << "getUnsignedValue: Value outside of valid range." << llendl;
1640 break;
1641 }
1642 array[i] = U32(value);
1643 }
1644
1645#if LL_DEBUG
1646 if (i != expected_length)
1647 {
1648 lldebugs << "LLXMLNode::getUnsignedValue() failed for node named '"
1649 << mName->mString << "' -- expected " << expected_length << " but "
1650 << "only found " << i << llendl;
1651 }
1652#endif
1653
1654 return i;
1655}
1656
1657U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding)
1658{
1659 llassert(array);
1660
1661 // Check type - accept bytes or integers
1662 if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
1663 {
1664 return 0;
1665 }
1666
1667 if (mLength > 0 && mLength != expected_length)
1668 {
1669 llwarns << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
1670 return 0;
1671 }
1672
1673 if (encoding == ENCODING_DEFAULT)
1674 {
1675 encoding = mEncoding;
1676 }
1677
1678 const char *value_string = mValue.c_str();
1679
1680 U32 i = 0;
1681 // Int type
1682 for (i=0; i<expected_length; ++i)
1683 {
1684 U64 value;
1685 BOOL is_negative;
1686 value_string = parseInteger(value_string, &value, &is_negative, 64, encoding);
1687 if (value_string == NULL)
1688 {
1689 break;
1690 }
1691 if (is_negative)
1692 {
1693 llwarns << "getLongValue: Value outside of valid range." << llendl;
1694 break;
1695 }
1696 array[i] = value;
1697 }
1698
1699#if LL_DEBUG
1700 if (i != expected_length)
1701 {
1702 lldebugs << "LLXMLNode::getLongValue() failed for node named '"
1703 << mName->mString << "' -- expected " << expected_length << " but "
1704 << "only found " << i << llendl;
1705 }
1706#endif
1707
1708 return i;
1709}
1710
1711U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding)
1712{
1713 llassert(array);
1714
1715 // Check type - accept only floats or doubles
1716 if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN)
1717 {
1718 return 0;
1719 }
1720
1721 if (mLength > 0 && mLength != expected_length)
1722 {
1723 llwarns << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
1724 return 0;
1725 }
1726
1727 if (encoding == ENCODING_DEFAULT)
1728 {
1729 encoding = mEncoding;
1730 }
1731
1732 const char *value_string = mValue.c_str();
1733
1734 U32 i;
1735 for (i=0; i<expected_length; ++i)
1736 {
1737 F64 value;
1738 value_string = parseFloat(value_string, &value, 32, encoding);
1739 if (value_string == NULL)
1740 {
1741 break;
1742 }
1743 array[i] = F32(value);
1744 }
1745#if LL_DEBUG
1746 if (i != expected_length)
1747 {
1748 lldebugs << "LLXMLNode::getFloatValue() failed for node named '"
1749 << mName->mString << "' -- expected " << expected_length << " but "
1750 << "only found " << i << llendl;
1751 }
1752#endif
1753 return i;
1754}
1755
1756U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding)
1757{
1758 llassert(array);
1759
1760 // Check type - accept only floats or doubles
1761 if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN)
1762 {
1763 return 0;
1764 }
1765
1766 if (mLength > 0 && mLength != expected_length)
1767 {
1768 llwarns << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
1769 return 0;
1770 }
1771
1772 if (encoding == ENCODING_DEFAULT)
1773 {
1774 encoding = mEncoding;
1775 }
1776
1777 const char *value_string = mValue.c_str();
1778
1779 U32 i;
1780 for (i=0; i<expected_length; ++i)
1781 {
1782 F64 value;
1783 value_string = parseFloat(value_string, &value, 64, encoding);
1784 if (value_string == NULL)
1785 {
1786 break;
1787 }
1788 array[i] = value;
1789 }
1790#if LL_DEBUG
1791 if (i != expected_length)
1792 {
1793 lldebugs << "LLXMLNode::getDoubleValue() failed for node named '"
1794 << mName->mString << "' -- expected " << expected_length << " but "
1795 << "only found " << i << llendl;
1796 }
1797#endif
1798 return i;
1799}
1800
1801U32 LLXMLNode::getStringValue(U32 expected_length, LLString *array)
1802{
1803 llassert(array);
1804
1805 // Can always return any value as a string
1806
1807 if (mLength > 0 && mLength != expected_length)
1808 {
1809 llwarns << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << llendl;
1810 return 0;
1811 }
1812
1813 U32 num_returned_strings = 0;
1814
1815 // Array of strings is whitespace-separated
1816 const std::string sep(" \n\t");
1817
1818 std::string::size_type n = 0;
1819 std::string::size_type m = 0;
1820 while(1)
1821 {
1822 if (num_returned_strings >= expected_length)
1823 {
1824 break;
1825 }
1826 n = mValue.find_first_not_of(sep, m);
1827 m = mValue.find_first_of(sep, n);
1828 if (m == std::string::npos)
1829 {
1830 break;
1831 }
1832 array[num_returned_strings++] = mValue.substr(n,m-n);
1833 }
1834 if (n != std::string::npos && num_returned_strings < expected_length)
1835 {
1836 array[num_returned_strings++] = mValue.substr(n);
1837 }
1838#if LL_DEBUG
1839 if (num_returned_strings != expected_length)
1840 {
1841 lldebugs << "LLXMLNode::getStringValue() failed for node named '"
1842 << mName->mString << "' -- expected " << expected_length << " but "
1843 << "only found " << num_returned_strings << llendl;
1844 }
1845#endif
1846
1847 return num_returned_strings;
1848}
1849
1850U32 LLXMLNode::getUUIDValue(U32 expected_length, LLUUID *array)
1851{
1852 llassert(array);
1853
1854 // Check type
1855 if (mType != TYPE_UUID && mType != TYPE_UNKNOWN)
1856 {
1857 return 0;
1858 }
1859
1860 const char *value_string = mValue.c_str();
1861
1862 U32 i;
1863 for (i=0; i<expected_length; ++i)
1864 {
1865 LLUUID uuid_value;
1866 value_string = skipWhitespace(value_string);
1867
1868 if (strlen(value_string) < (UUID_STR_LENGTH-1))
1869 {
1870 break;
1871 }
1872 char uuid_string[UUID_STR_LENGTH];
1873 memcpy(uuid_string, value_string, (UUID_STR_LENGTH-1));
1874 uuid_string[(UUID_STR_LENGTH-1)] = 0;
1875
1876 if (!LLUUID::parseUUID(uuid_string, &uuid_value))
1877 {
1878 break;
1879 }
1880 value_string = &value_string[(UUID_STR_LENGTH-1)];
1881 array[i] = uuid_value;
1882 }
1883#if LL_DEBUG
1884 if (i != expected_length)
1885 {
1886 lldebugs << "LLXMLNode::getUUIDValue() failed for node named '"
1887 << mName->mString << "' -- expected " << expected_length << " but "
1888 << "only found " << i << llendl;
1889 }
1890#endif
1891 return i;
1892}
1893
1894U32 LLXMLNode::getNodeRefValue(U32 expected_length, LLXMLNode **array)
1895{
1896 llassert(array);
1897
1898 // Check type
1899 if (mType != TYPE_NODEREF && mType != TYPE_UNKNOWN)
1900 {
1901 return 0;
1902 }
1903
1904 LLString *string_array = new LLString[expected_length];
1905
1906 U32 num_strings = getStringValue(expected_length, string_array);
1907
1908 U32 num_returned_refs = 0;
1909
1910 LLXMLNodePtr root = getRoot();
1911 for (U32 strnum=0; strnum<num_strings; ++strnum)
1912 {
1913 LLXMLNodeList node_list;
1914 root->findID(string_array[strnum], node_list);
1915 if (node_list.empty())
1916 {
1917 llwarns << "XML: Could not find node ID: " << string_array[strnum] << llendl;
1918 }
1919 else if (node_list.size() > 1)
1920 {
1921 llwarns << "XML: Node ID not unique: " << string_array[strnum] << llendl;
1922 }
1923 else
1924 {
1925 LLXMLNodeList::const_iterator list_itr = node_list.begin();
1926 if (list_itr != node_list.end())
1927 {
1928 LLXMLNode* child = (*list_itr).second;
1929
1930 array[num_returned_refs++] = child;
1931 }
1932 }
1933 }
1934
1935 delete[] string_array;
1936
1937 return num_returned_refs;
1938}
1939
1940void LLXMLNode::setBoolValue(U32 length, const BOOL *array)
1941{
1942 if (length == 0) return;
1943
1944 LLString new_value;
1945 for (U32 pos=0; pos<length; ++pos)
1946 {
1947 if (pos > 0)
1948 {
1949 new_value = llformat("%s %s", new_value.c_str(), array[pos]?"true":"false");
1950 }
1951 else
1952 {
1953 new_value = array[pos]?"true":"false";
1954 }
1955 }
1956
1957 mValue = new_value;
1958 mEncoding = ENCODING_DEFAULT;
1959 mLength = length;
1960 mType = TYPE_BOOLEAN;
1961}
1962
1963void LLXMLNode::setByteValue(U32 length, const U8* const array, Encoding encoding)
1964{
1965 if (length == 0) return;
1966
1967 LLString new_value;
1968 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
1969 {
1970 for (U32 pos=0; pos<length; ++pos)
1971 {
1972 if (pos > 0)
1973 {
1974 new_value.append(llformat(" %u", array[pos]));
1975 }
1976 else
1977 {
1978 new_value = llformat("%u", array[pos]);
1979 }
1980 }
1981 }
1982 if (encoding == ENCODING_HEX)
1983 {
1984 for (U32 pos=0; pos<length; ++pos)
1985 {
1986 if (pos > 0 && pos % 16 == 0)
1987 {
1988 new_value.append(llformat(" %02X", array[pos]));
1989 }
1990 else
1991 {
1992 new_value.append(llformat("%02X", array[pos]));
1993 }
1994 }
1995 }
1996 // TODO -- Handle Base32
1997
1998 mValue = new_value;
1999 mEncoding = encoding;
2000 mLength = length;
2001 mType = TYPE_INTEGER;
2002 mPrecision = 8;
2003}
2004
2005
2006void LLXMLNode::setIntValue(U32 length, const S32 *array, Encoding encoding)
2007{
2008 if (length == 0) return;
2009
2010 LLString new_value;
2011 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
2012 {
2013 for (U32 pos=0; pos<length; ++pos)
2014 {
2015 if (pos > 0)
2016 {
2017 new_value.append(llformat(" %d", array[pos]));
2018 }
2019 else
2020 {
2021 new_value = llformat("%d", array[pos]);
2022 }
2023 }
2024 mValue = new_value;
2025 }
2026 else if (encoding == ENCODING_HEX)
2027 {
2028 for (U32 pos=0; pos<length; ++pos)
2029 {
2030 if (pos > 0 && pos % 16 == 0)
2031 {
2032 new_value.append(llformat(" %08X", ((U32 *)array)[pos]));
2033 }
2034 else
2035 {
2036 new_value.append(llformat("%08X", ((U32 *)array)[pos]));
2037 }
2038 }
2039 mValue = new_value;
2040 }
2041 else
2042 {
2043 mValue = new_value;
2044 }
2045 // TODO -- Handle Base32
2046
2047 mEncoding = encoding;
2048 mLength = length;
2049 mType = TYPE_INTEGER;
2050 mPrecision = 32;
2051}
2052
2053void LLXMLNode::setUnsignedValue(U32 length, const U32* array, Encoding encoding)
2054{
2055 if (length == 0) return;
2056
2057 LLString new_value;
2058 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
2059 {
2060 for (U32 pos=0; pos<length; ++pos)
2061 {
2062 if (pos > 0)
2063 {
2064 new_value.append(llformat(" %u", array[pos]));
2065 }
2066 else
2067 {
2068 new_value = llformat("%u", array[pos]);
2069 }
2070 }
2071 }
2072 if (encoding == ENCODING_HEX)
2073 {
2074 for (U32 pos=0; pos<length; ++pos)
2075 {
2076 if (pos > 0 && pos % 16 == 0)
2077 {
2078 new_value.append(llformat(" %08X", array[pos]));
2079 }
2080 else
2081 {
2082 new_value.append(llformat("%08X", array[pos]));
2083 }
2084 }
2085 mValue = new_value;
2086 }
2087 // TODO -- Handle Base32
2088
2089 mValue = new_value;
2090 mEncoding = encoding;
2091 mLength = length;
2092 mType = TYPE_INTEGER;
2093 mPrecision = 32;
2094}
2095
2096#if LL_WINDOWS
2097#define PU64 "I64u"
2098#else
2099#define PU64 "llu"
2100#endif
2101
2102void LLXMLNode::setLongValue(U32 length, const U64* array, Encoding encoding)
2103{
2104 if (length == 0) return;
2105
2106 LLString new_value;
2107 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
2108 {
2109 for (U32 pos=0; pos<length; ++pos)
2110 {
2111 if (pos > 0)
2112 {
2113 new_value.append(llformat(" %" PU64, array[pos]));
2114 }
2115 else
2116 {
2117 new_value = llformat("%" PU64, array[pos]);
2118 }
2119 }
2120 mValue = new_value;
2121 }
2122 if (encoding == ENCODING_HEX)
2123 {
2124 for (U32 pos=0; pos<length; ++pos)
2125 {
2126 U32 upper_32 = U32(array[pos]>>32);
2127 U32 lower_32 = U32(array[pos]&0xffffffff);
2128 if (pos > 0 && pos % 8 == 0)
2129 {
2130 new_value.append(llformat(" %08X%08X", upper_32, lower_32));
2131 }
2132 else
2133 {
2134 new_value.append(llformat("%08X%08X", upper_32, lower_32));
2135 }
2136 }
2137 mValue = new_value;
2138 }
2139 else
2140 {
2141 mValue = new_value;
2142 }
2143 // TODO -- Handle Base32
2144
2145 mEncoding = encoding;
2146 mLength = length;
2147 mType = TYPE_INTEGER;
2148 mPrecision = 64;
2149}
2150
2151void LLXMLNode::setFloatValue(U32 length, const F32 *array, Encoding encoding, U32 precision)
2152{
2153 if (length == 0) return;
2154
2155 LLString new_value;
2156 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
2157 {
2158 char format_string[10];
2159 if (precision > 0)
2160 {
2161 if (precision > 25)
2162 {
2163 precision = 25;
2164 }
2165 sprintf(format_string, "%%.%dg", precision);
2166 }
2167 else
2168 {
2169 sprintf(format_string, "%%g");
2170 }
2171
2172 for (U32 pos=0; pos<length; ++pos)
2173 {
2174 if (pos > 0)
2175 {
2176 new_value.append(" ");
2177 new_value.append(llformat(format_string, array[pos]));
2178 }
2179 else
2180 {
2181 new_value.assign(llformat(format_string, array[pos]));
2182 }
2183 }
2184 mValue = new_value;
2185 }
2186 else if (encoding == ENCODING_HEX)
2187 {
2188 U32 *byte_array = (U32 *)array;
2189 setUnsignedValue(length, byte_array, ENCODING_HEX);
2190 }
2191 else
2192 {
2193 mValue = new_value;
2194 }
2195
2196 mEncoding = encoding;
2197 mLength = length;
2198 mType = TYPE_FLOAT;
2199 mPrecision = 32;
2200}
2201
2202void LLXMLNode::setDoubleValue(U32 length, const F64 *array, Encoding encoding, U32 precision)
2203{
2204 if (length == 0) return;
2205
2206 LLString new_value;
2207 if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
2208 {
2209 char format_string[10];
2210 if (precision > 0)
2211 {
2212 if (precision > 25)
2213 {
2214 precision = 25;
2215 }
2216 sprintf(format_string, "%%.%dg", precision);
2217 }
2218 else
2219 {
2220 sprintf(format_string, "%%g");
2221 }
2222 for (U32 pos=0; pos<length; ++pos)
2223 {
2224 if (pos > 0)
2225 {
2226 new_value.append(" ");
2227 new_value.append(llformat(format_string, array[pos]));
2228 }
2229 else
2230 {
2231 new_value.assign(llformat(format_string, array[pos]));
2232 }
2233 }
2234 mValue = new_value;
2235 }
2236 if (encoding == ENCODING_HEX)
2237 {
2238 U64 *byte_array = (U64 *)array;
2239 setLongValue(length, byte_array, ENCODING_HEX);
2240 }
2241 else
2242 {
2243 mValue = new_value;
2244 }
2245 // TODO -- Handle Base32
2246
2247 mEncoding = encoding;
2248 mLength = length;
2249 mType = TYPE_FLOAT;
2250 mPrecision = 64;
2251}
2252
2253// static
2254LLString LLXMLNode::escapeXML(const LLString& xml)
2255{
2256 LLString out;
2257 for (LLString::size_type i = 0; i < xml.size(); ++i)
2258 {
2259 char c = xml[i];
2260 switch(c)
2261 {
2262 case '"': out.append("&quot;"); break;
2263 case '\'': out.append("&apos;"); break;
2264 case '&': out.append("&amp;"); break;
2265 case '<': out.append("&lt;"); break;
2266 case '>': out.append("&gt;"); break;
2267 default: out.push_back(c); break;
2268 }
2269 }
2270 return out;
2271}
2272
2273void LLXMLNode::setStringValue(U32 length, const LLString *array)
2274{
2275 if (length == 0) return;
2276
2277 LLString new_value;
2278 for (U32 pos=0; pos<length; ++pos)
2279 {
2280 new_value.append(escapeXML(array[pos]));
2281 if (pos < length-1) new_value.append(" ");
2282 }
2283
2284 mValue = new_value;
2285 mEncoding = ENCODING_DEFAULT;
2286 mLength = length;
2287 mType = TYPE_STRING;
2288}
2289
2290void LLXMLNode::setUUIDValue(U32 length, const LLUUID *array)
2291{
2292 if (length == 0) return;
2293
2294 LLString new_value;
2295 for (U32 pos=0; pos<length; ++pos)
2296 {
2297 new_value.append(array[pos].getString());
2298 if (pos < length-1) new_value.append(" ");
2299 }
2300
2301 mValue = new_value;
2302 mEncoding = ENCODING_DEFAULT;
2303 mLength = length;
2304 mType = TYPE_UUID;
2305}
2306
2307void LLXMLNode::setNodeRefValue(U32 length, const LLXMLNode **array)
2308{
2309 if (length == 0) return;
2310
2311 LLString new_value;
2312 for (U32 pos=0; pos<length; ++pos)
2313 {
2314 if (array[pos]->mID != "")
2315 {
2316 new_value.append(array[pos]->mID);
2317 }
2318 else
2319 {
2320 new_value.append("(null)");
2321 }
2322 if (pos < length-1) new_value.append(" ");
2323 }
2324
2325 mValue = new_value;
2326 mEncoding = ENCODING_DEFAULT;
2327 mLength = length;
2328 mType = TYPE_NODEREF;
2329}
2330
2331void LLXMLNode::setValue(const LLString& value)
2332{
2333 if (TYPE_CONTAINER == mType)
2334 {
2335 mType = TYPE_UNKNOWN;
2336 }
2337 mValue = value;
2338}
2339
2340void LLXMLNode::setDefault(LLXMLNode *default_node)
2341{
2342 mDefault = default_node;
2343}
2344
2345void LLXMLNode::findDefault(LLXMLNode *defaults_list)
2346{
2347 if (defaults_list)
2348 {
2349 LLXMLNodeList children;
2350 defaults_list->getChildren(mName->mString, children);
2351
2352 LLXMLNodeList::const_iterator children_itr;
2353 LLXMLNodeList::const_iterator children_end = children.end();
2354 for (children_itr = children.begin(); children_itr != children_end; ++children_itr)
2355 {
2356 LLXMLNode* child = (*children_itr).second;
2357 if (child->mVersionMajor == mVersionMajor &&
2358 child->mVersionMinor == mVersionMinor)
2359 {
2360 mDefault = child;
2361 return;
2362 }
2363 }
2364 }
2365 mDefault = NULL;
2366}
2367
2368BOOL LLXMLNode::deleteChildren(const LLString& name)
2369{
2370 U32 removed_count = 0;
2371 LLXMLNodeList node_list;
2372 findName(name, node_list);
2373 if (!node_list.empty())
2374 {
2375 // TODO -- use multimap::find()
2376 // TODO -- need to watch out for invalid iterators
2377 LLXMLNodeList::iterator children_itr;
2378 for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr)
2379 {
2380 LLXMLNode* child = (*children_itr).second;
2381 if (deleteChild(child))
2382 {
2383 removed_count++;
2384 }
2385 }
2386 }
2387 return removed_count > 0 ? TRUE : FALSE;
2388}
2389
2390BOOL LLXMLNode::deleteChildren(LLStringTableEntry* name)
2391{
2392 U32 removed_count = 0;
2393 LLXMLNodeList node_list;
2394 findName(name, node_list);
2395 if (!node_list.empty())
2396 {
2397 // TODO -- use multimap::find()
2398 // TODO -- need to watch out for invalid iterators
2399 LLXMLNodeList::iterator children_itr;
2400 for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr)
2401 {
2402 LLXMLNode* child = (*children_itr).second;
2403 if (deleteChild(child))
2404 {
2405 removed_count++;
2406 }
2407 }
2408 }
2409 return removed_count > 0 ? TRUE : FALSE;
2410}
2411
2412void LLXMLNode::setAttributes(LLXMLNode::ValueType type, U32 precision, LLXMLNode::Encoding encoding, U32 length)
2413{
2414 mType = type;
2415 mEncoding = encoding;
2416 mPrecision = precision;
2417 mLength = length;
2418}
2419
2420void LLXMLNode::setName(const LLString& name)
2421{
2422 setName(gStringTable.addStringEntry(name));
2423}
2424
2425void LLXMLNode::setName(LLStringTableEntry* name)
2426{
2427 LLXMLNode* old_parent = mParent;
2428 if (mParent)
2429 {
2430 // we need to remove and re-add to the parent so that
2431 // the multimap key agrees with this node's name
2432 mParent->removeChild(this);
2433 }
2434 mName = name;
2435 if (old_parent)
2436 {
2437 old_parent->addChild(this);
2438 }
2439}
2440
2441void LLXMLNode::appendValue(const LLString& value)
2442{
2443 mValue.append(value);
2444}
2445
2446U32 LLXMLNode::getChildCount() const
2447{
2448 if (mChildren)
2449 {
2450 return mChildren->map.size();
2451 }
2452 return 0;
2453}
2454
2455//***************************************************
2456// UNIT TESTING
2457//***************************************************
2458
2459U32 get_rand(U32 max_value)
2460{
2461 U32 random_num = rand() + ((U32)rand() << 16);
2462 return (random_num % max_value);
2463}
2464
2465LLXMLNode *get_rand_node(LLXMLNode *node)
2466{
2467 if (node->mChildren)
2468 {
2469 U32 num_children = node->mChildren->map.size();
2470 if (get_rand(2) == 0)
2471 {
2472 while (true)
2473 {
2474 S32 child_num = S32(get_rand(num_children*2)) - num_children;
2475 LLXMLChildList::iterator itor = node->mChildren->map.begin();
2476 while (child_num > 0)
2477 {
2478 --child_num;
2479 ++itor;
2480 }
2481 if (!itor->second->mIsAttribute)
2482 {
2483 return get_rand_node(itor->second);
2484 }
2485 }
2486 }
2487 }
2488 return node;
2489}
2490
2491void LLXMLNode::createUnitTest(S32 max_num_children)
2492{
2493 // Random ID
2494 char rand_id[20];
2495 U32 rand_id_len = get_rand(10)+5;
2496 U32 pos = 0;
2497 for (; pos<rand_id_len; ++pos)
2498 {
2499 rand_id[pos] = get_rand(26)+'a';
2500 }
2501 rand_id[pos] = 0;
2502 mID = rand_id;
2503
2504 if (max_num_children < 2)
2505 {
2506 setStringValue(1, &mID);
2507 return;
2508 }
2509
2510 // Checksums
2511 U32 integer_checksum = 0;
2512 U64 long_checksum = 0;
2513 U32 bool_true_count = 0;
2514 LLUUID uuid_checksum;
2515 U32 noderef_checksum = 0;
2516 U32 float_checksum = 0;
2517
2518 // Create a random number of children
2519 U32 num_children = get_rand(max_num_children)+1;
2520 for (U32 child_num=0; child_num<num_children; ++child_num)
2521 {
2522 // Random Name
2523 char child_name[20];
2524 U32 child_name_len = get_rand(10)+5;
2525 pos = 0;
2526 for (; pos<child_name_len; ++pos)
2527 {
2528 child_name[pos] = get_rand(26)+'a';
2529 }
2530 child_name[pos] = 0;
2531
2532 LLXMLNode *new_child = createChild(child_name, FALSE);
2533
2534 // Random ID
2535 char child_id[20];
2536 U32 child_id_len = get_rand(10)+5;
2537 pos = 0;
2538 for (; pos<child_id_len; ++pos)
2539 {
2540 child_id[pos] = get_rand(26)+'a';
2541 }
2542 child_id[pos] = 0;
2543 new_child->mID = child_id;
2544
2545 // Random Length
2546 U32 array_size = get_rand(28)+1;
2547
2548 // Random Encoding
2549 Encoding new_encoding = get_rand(2)?ENCODING_DECIMAL:ENCODING_HEX;
2550
2551 // Random Type
2552 int type = get_rand(8);
2553 switch (type)
2554 {
2555 case 0: // TYPE_CONTAINER
2556 new_child->createUnitTest(max_num_children/2);
2557 break;
2558 case 1: // TYPE_BOOLEAN
2559 {
2560 BOOL random_bool_values[30];
2561 for (U32 value=0; value<array_size; ++value)
2562 {
2563 random_bool_values[value] = get_rand(2);
2564 if (random_bool_values[value])
2565 {
2566 ++bool_true_count;
2567 }
2568 }
2569 new_child->setBoolValue(array_size, random_bool_values);
2570 }
2571 break;
2572 case 2: // TYPE_INTEGER (32-bit)
2573 {
2574 U32 random_int_values[30];
2575 for (U32 value=0; value<array_size; ++value)
2576 {
2577 random_int_values[value] = get_rand(0xffffffff);
2578 integer_checksum ^= random_int_values[value];
2579 }
2580 new_child->setUnsignedValue(array_size, random_int_values, new_encoding);
2581 }
2582 break;
2583 case 3: // TYPE_INTEGER (64-bit)
2584 {
2585 U64 random_int_values[30];
2586 for (U64 value=0; value<array_size; ++value)
2587 {
2588 random_int_values[value] = (U64(get_rand(0xffffffff)) << 32) + get_rand(0xffffffff);
2589 long_checksum ^= random_int_values[value];
2590 }
2591 new_child->setLongValue(array_size, random_int_values, new_encoding);
2592 }
2593 break;
2594 case 4: // TYPE_FLOAT (32-bit)
2595 {
2596 F32 random_float_values[30];
2597 for (U32 value=0; value<array_size; ++value)
2598 {
2599 S32 exponent = get_rand(256) - 128;
2600 S32 fractional_part = get_rand(0xffffffff);
2601 S32 sign = get_rand(2) * 2 - 1;
2602 random_float_values[value] = F32(fractional_part) / F32(0xffffffff) * exp(F32(exponent)) * F32(sign);
2603
2604 U32 *float_bits = &((U32 *)random_float_values)[value];
2605 if (*float_bits == 0x80000000)
2606 {
2607 *float_bits = 0x00000000;
2608 }
2609 float_checksum ^= (*float_bits & 0xfffff000);
2610 }
2611 new_child->setFloatValue(array_size, random_float_values, new_encoding, 12);
2612 }
2613 break;
2614 case 5: // TYPE_FLOAT (64-bit)
2615 {
2616 F64 random_float_values[30];
2617 for (U32 value=0; value<array_size; ++value)
2618 {
2619 S32 exponent = get_rand(2048) - 1024;
2620 S32 fractional_part = get_rand(0xffffffff);
2621 S32 sign = get_rand(2) * 2 - 1;
2622 random_float_values[value] = F64(fractional_part) / F64(0xffffffff) * exp(F64(exponent)) * F64(sign);
2623
2624 U64 *float_bits = &((U64 *)random_float_values)[value];
2625 if (*float_bits == 0x8000000000000000ll)
2626 {
2627 *float_bits = 0x0000000000000000ll;
2628 }
2629 float_checksum ^= ((*float_bits & 0xfffffff000000000ll) >> 32);
2630 }
2631 new_child->setDoubleValue(array_size, random_float_values, new_encoding, 12);
2632 }
2633 break;
2634 case 6: // TYPE_UUID
2635 {
2636 LLUUID random_uuid_values[30];
2637 for (U32 value=0; value<array_size; ++value)
2638 {
2639 random_uuid_values[value].generate();
2640 for (S32 byte=0; byte<UUID_BYTES; ++byte)
2641 {
2642 uuid_checksum.mData[byte] ^= random_uuid_values[value].mData[byte];
2643 }
2644 }
2645 new_child->setUUIDValue(array_size, random_uuid_values);
2646 }
2647 break;
2648 case 7: // TYPE_NODEREF
2649 {
2650 LLXMLNode *random_node_array[30];
2651 LLXMLNode *root = getRoot();
2652 for (U32 value=0; value<array_size; ++value)
2653 {
2654 random_node_array[value] = get_rand_node(root);
2655 const char *node_name = random_node_array[value]->mName->mString;
2656 for (U32 pos=0; pos<strlen(node_name); ++pos)
2657 {
2658 U32 hash_contrib = U32(node_name[pos]) << ((pos % 4) * 8);
2659 noderef_checksum ^= hash_contrib;
2660 }
2661 }
2662 new_child->setNodeRefValue(array_size, (const LLXMLNode **)random_node_array);
2663 }
2664 break;
2665 }
2666 }
2667
2668 createChild("integer_checksum", TRUE)->setUnsignedValue(1, &integer_checksum, LLXMLNode::ENCODING_HEX);
2669 createChild("long_checksum", TRUE)->setLongValue(1, &long_checksum, LLXMLNode::ENCODING_HEX);
2670 createChild("bool_true_count", TRUE)->setUnsignedValue(1, &bool_true_count, LLXMLNode::ENCODING_HEX);
2671 createChild("uuid_checksum", TRUE)->setUUIDValue(1, &uuid_checksum);
2672 createChild("noderef_checksum", TRUE)->setUnsignedValue(1, &noderef_checksum, LLXMLNode::ENCODING_HEX);
2673 createChild("float_checksum", TRUE)->setUnsignedValue(1, &float_checksum, LLXMLNode::ENCODING_HEX);
2674}
2675
2676BOOL LLXMLNode::performUnitTest(LLString &error_buffer)
2677{
2678 if (!mChildren)
2679 {
2680 error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString));
2681 return FALSE;
2682 }
2683
2684 // Checksums
2685 U32 integer_checksum = 0;
2686 U32 bool_true_count = 0;
2687 LLUUID uuid_checksum;
2688 U32 noderef_checksum = 0;
2689 U32 float_checksum = 0;
2690 U64 long_checksum = 0;
2691
2692 LLXMLChildList::iterator itor;
2693 for (itor=mChildren->map.begin(); itor!=mChildren->map.end(); ++itor)
2694 {
2695 LLXMLNode *node = itor->second;
2696 if (node->mIsAttribute)
2697 {
2698 continue;
2699 }
2700 if (node->mType == TYPE_CONTAINER)
2701 {
2702 if (!node->performUnitTest(error_buffer))
2703 {
2704 error_buffer.append(llformat("Child test failed for %s.\n", mName->mString));
2705 //return FALSE;
2706 }
2707 continue;
2708 }
2709 if (node->mLength < 1 || node->mLength > 30)
2710 {
2711 error_buffer.append(llformat("ERROR Node %s: Invalid array length %d, child %s.\n", mName->mString, node->mLength, node->mName->mString));
2712 return FALSE;
2713 }
2714 switch (node->mType)
2715 {
2716 case TYPE_CONTAINER:
2717 case TYPE_UNKNOWN:
2718 break;
2719 case TYPE_BOOLEAN:
2720 {
2721 BOOL bool_array[30];
2722 if (node->getBoolValue(node->mLength, bool_array) < node->mLength)
2723 {
2724 error_buffer.append(llformat("ERROR Node %s: Could not read boolean array, child %s.\n", mName->mString, node->mName->mString));
2725 return FALSE;
2726 }
2727 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
2728 {
2729 if (bool_array[pos])
2730 {
2731 ++bool_true_count;
2732 }
2733 }
2734 }
2735 break;
2736 case TYPE_INTEGER:
2737 {
2738 if (node->mPrecision == 32)
2739 {
2740 U32 integer_array[30];
2741 if (node->getUnsignedValue(node->mLength, integer_array, node->mEncoding) < node->mLength)
2742 {
2743 error_buffer.append(llformat("ERROR Node %s: Could not read integer array, child %s.\n", mName->mString, node->mName->mString));
2744 return FALSE;
2745 }
2746 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
2747 {
2748 integer_checksum ^= integer_array[pos];
2749 }
2750 }
2751 else
2752 {
2753 U64 integer_array[30];
2754 if (node->getLongValue(node->mLength, integer_array, node->mEncoding) < node->mLength)
2755 {
2756 error_buffer.append(llformat("ERROR Node %s: Could not read long integer array, child %s.\n", mName->mString, node->mName->mString));
2757 return FALSE;
2758 }
2759 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
2760 {
2761 long_checksum ^= integer_array[pos];
2762 }
2763 }
2764 }
2765 break;
2766 case TYPE_FLOAT:
2767 {
2768 if (node->mPrecision == 32)
2769 {
2770 F32 float_array[30];
2771 if (node->getFloatValue(node->mLength, float_array, node->mEncoding) < node->mLength)
2772 {
2773 error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString));
2774 return FALSE;
2775 }
2776 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
2777 {
2778 U32 float_bits = ((U32 *)float_array)[pos];
2779 float_checksum ^= (float_bits & 0xfffff000);
2780 }
2781 }
2782 else
2783 {
2784 F64 float_array[30];
2785 if (node->getDoubleValue(node->mLength, float_array, node->mEncoding) < node->mLength)
2786 {
2787 error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString));
2788 return FALSE;
2789 }
2790 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
2791 {
2792 U64 float_bits = ((U64 *)float_array)[pos];
2793 float_checksum ^= ((float_bits & 0xfffffff000000000ll) >> 32);
2794 }
2795 }
2796 }
2797 break;
2798 case TYPE_STRING:
2799 break;
2800 case TYPE_UUID:
2801 {
2802 LLUUID uuid_array[30];
2803 if (node->getUUIDValue(node->mLength, uuid_array) < node->mLength)
2804 {
2805 error_buffer.append(llformat("ERROR Node %s: Could not read uuid array, child %s.\n", mName->mString, node->mName->mString));
2806 return FALSE;
2807 }
2808 for (U32 pos=0; pos<(U32)node->mLength; ++pos)
2809 {
2810 for (S32 byte=0; byte<UUID_BYTES; ++byte)
2811 {
2812 uuid_checksum.mData[byte] ^= uuid_array[pos].mData[byte];
2813 }
2814 }
2815 }
2816 break;
2817 case TYPE_NODEREF:
2818 {
2819 LLXMLNode *node_array[30];
2820 if (node->getNodeRefValue(node->mLength, node_array) < node->mLength)
2821 {
2822 error_buffer.append(llformat("ERROR Node %s: Could not read node ref array, child %s.\n", mName->mString, node->mName->mString));
2823 return FALSE;
2824 }
2825 for (U32 pos=0; pos<node->mLength; ++pos)
2826 {
2827 const char *node_name = node_array[pos]->mName->mString;
2828 for (U32 pos2=0; pos2<strlen(node_name); ++pos2)
2829 {
2830 U32 hash_contrib = U32(node_name[pos2]) << ((pos2 % 4) * 8);
2831 noderef_checksum ^= hash_contrib;
2832 }
2833 }
2834 }
2835 break;
2836 }
2837 }
2838
2839 LLXMLNodePtr checksum_node;
2840
2841 // Compare checksums
2842 {
2843 U32 node_integer_checksum = 0;
2844 if (!getAttribute("integer_checksum", checksum_node, FALSE) ||
2845 checksum_node->getUnsignedValue(1, &node_integer_checksum, ENCODING_HEX) != 1)
2846 {
2847 error_buffer.append(llformat("ERROR Node %s: Integer checksum missing.\n", mName->mString));
2848 return FALSE;
2849 }
2850 if (node_integer_checksum != integer_checksum)
2851 {
2852 error_buffer.append(llformat("ERROR Node %s: Integer checksum mismatch: read %X / calc %X.\n", mName->mString, node_integer_checksum, integer_checksum));
2853 return FALSE;
2854 }
2855 }
2856
2857 {
2858 U64 node_long_checksum = 0;
2859 if (!getAttribute("long_checksum", checksum_node, FALSE) ||
2860 checksum_node->getLongValue(1, &node_long_checksum, ENCODING_HEX) != 1)
2861 {
2862 error_buffer.append(llformat("ERROR Node %s: Long Integer checksum missing.\n", mName->mString));
2863 return FALSE;
2864 }
2865 if (node_long_checksum != long_checksum)
2866 {
2867 U32 *pp1 = (U32 *)&node_long_checksum;
2868 U32 *pp2 = (U32 *)&long_checksum;
2869 error_buffer.append(llformat("ERROR Node %s: Long Integer checksum mismatch: read %08X%08X / calc %08X%08X.\n", mName->mString, pp1[1], pp1[0], pp2[1], pp2[0]));
2870 return FALSE;
2871 }
2872 }
2873
2874 {
2875 U32 node_bool_true_count = 0;
2876 if (!getAttribute("bool_true_count", checksum_node, FALSE) ||
2877 checksum_node->getUnsignedValue(1, &node_bool_true_count, ENCODING_HEX) != 1)
2878 {
2879 error_buffer.append(llformat("ERROR Node %s: Boolean checksum missing.\n", mName->mString));
2880 return FALSE;
2881 }
2882 if (node_bool_true_count != bool_true_count)
2883 {
2884 error_buffer.append(llformat("ERROR Node %s: Boolean checksum mismatch: read %X / calc %X.\n", mName->mString, node_bool_true_count, bool_true_count));
2885 return FALSE;
2886 }
2887 }
2888
2889 {
2890 LLUUID node_uuid_checksum;
2891 if (!getAttribute("uuid_checksum", checksum_node, FALSE) ||
2892 checksum_node->getUUIDValue(1, &node_uuid_checksum) != 1)
2893 {
2894 error_buffer.append(llformat("ERROR Node %s: UUID checksum missing.\n", mName->mString));
2895 return FALSE;
2896 }
2897 if (node_uuid_checksum != uuid_checksum)
2898 {
2899 error_buffer.append(llformat("ERROR Node %s: UUID checksum mismatch: read %s / calc %s.\n", mName->mString, node_uuid_checksum.getString().c_str(), uuid_checksum.getString().c_str()));
2900 return FALSE;
2901 }
2902 }
2903
2904 {
2905 U32 node_noderef_checksum = 0;
2906 if (!getAttribute("noderef_checksum", checksum_node, FALSE) ||
2907 checksum_node->getUnsignedValue(1, &node_noderef_checksum, ENCODING_HEX) != 1)
2908 {
2909 error_buffer.append(llformat("ERROR Node %s: Node Ref checksum missing.\n", mName->mString));
2910 return FALSE;
2911 }
2912 if (node_noderef_checksum != noderef_checksum)
2913 {
2914 error_buffer.append(llformat("ERROR Node %s: Node Ref checksum mismatch: read %X / calc %X.\n", mName->mString, node_noderef_checksum, noderef_checksum));
2915 return FALSE;
2916 }
2917 }
2918
2919 {
2920 U32 node_float_checksum = 0;
2921 if (!getAttribute("float_checksum", checksum_node, FALSE) ||
2922 checksum_node->getUnsignedValue(1, &node_float_checksum, ENCODING_HEX) != 1)
2923 {
2924 error_buffer.append(llformat("ERROR Node %s: Float checksum missing.\n", mName->mString));
2925 return FALSE;
2926 }
2927 if (node_float_checksum != float_checksum)
2928 {
2929 error_buffer.append(llformat("ERROR Node %s: Float checksum mismatch: read %X / calc %X.\n", mName->mString, node_float_checksum, float_checksum));
2930 return FALSE;
2931 }
2932 }
2933
2934 return TRUE;
2935}
2936
2937LLXMLNodePtr LLXMLNode::getFirstChild()
2938{
2939 if (!mChildren) return NULL;
2940 LLXMLNodePtr ret = mChildren->head;
2941 return ret;
2942}
2943
2944LLXMLNodePtr LLXMLNode::getNextSibling()
2945{
2946 LLXMLNodePtr ret = mNext;
2947 return ret;
2948}
2949
2950LLString LLXMLNode::getTextContents() const
2951{
2952 std::string msg;
2953 LLXMLNodeList p_children;
2954 getChildren("p", p_children);
2955 if (p_children.size() > 0)
2956 {
2957 // Case 1: node has <p>text</p> tags
2958 LLXMLNodeList::iterator itor;
2959 for (itor = p_children.begin(); itor != p_children.end(); ++itor)
2960 {
2961 LLXMLNodePtr p = itor->second;
2962 msg += p->getValue() + "\n";
2963 }
2964 }
2965 else
2966 {
2967 LLString contents = mValue;
2968 std::string::size_type n = contents.find_first_not_of(" \t\n");
2969 if (n != std::string::npos && contents[n] == '\"')
2970 {
2971 // Case 2: node has quoted text
2972 S32 num_lines = 0;
2973 while(1)
2974 {
2975 // mContents[n] == '"'
2976 ++n;
2977 std::string::size_type t = n;
2978 std::string::size_type m = 0;
2979 // fix-up escaped characters
2980 while(1)
2981 {
2982 m = contents.find_first_of("\\\"", t); // find first \ or "
2983 if ((m == std::string::npos) || (contents[m] == '\"'))
2984 {
2985 break;
2986 }
2987 contents.erase(m,1);
2988 t = m+1;
2989 }
2990 if (m == std::string::npos)
2991 {
2992 break;
2993 }
2994 // mContents[m] == '"'
2995 num_lines++;
2996 msg += contents.substr(n,m-n) + "\n";
2997 n = contents.find_first_of("\"", m+1);
2998 if (n == std::string::npos)
2999 {
3000 if (num_lines == 1)
3001 {
3002 msg.erase(msg.size()-1); // remove "\n" if only one line
3003 }
3004 break;
3005 }
3006 }
3007 }
3008 else
3009 {
3010 // Case 3: node has embedded text (beginning and trailing whitespace trimmed)
3011 LLString::size_type start = mValue.find_first_not_of(" \t\n");
3012 if (start != mValue.npos)
3013 {
3014 LLString::size_type end = mValue.find_last_not_of(" \t\n");
3015 if (end != mValue.npos)
3016 {
3017 msg = mValue.substr(start, end+1-start);
3018 }
3019 else
3020 {
3021 msg = mValue.substr(start);
3022 }
3023 }
3024 }
3025 }
3026 return msg;
3027}