aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llxml
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
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 'linden/indra/llxml')
-rw-r--r--linden/indra/llxml/files.lst4
-rw-r--r--linden/indra/llxml/llcontrol.cpp1420
-rw-r--r--linden/indra/llxml/llcontrol.h274
-rw-r--r--linden/indra/llxml/llxml.vcproj189
-rw-r--r--linden/indra/llxml/llxmlnode.cpp3027
-rw-r--r--linden/indra/llxml/llxmlnode.h285
-rw-r--r--linden/indra/llxml/llxmlparser.cpp417
-rw-r--r--linden/indra/llxml/llxmlparser.h128
-rw-r--r--linden/indra/llxml/llxmltree.cpp690
-rw-r--r--linden/indra/llxml/llxmltree.h235
10 files changed, 6669 insertions, 0 deletions
diff --git a/linden/indra/llxml/files.lst b/linden/indra/llxml/files.lst
new file mode 100644
index 0000000..5fec309
--- /dev/null
+++ b/linden/indra/llxml/files.lst
@@ -0,0 +1,4 @@
1llxml/llcontrol.cpp
2llxml/llxmlnode.cpp
3llxml/llxmlparser.cpp
4llxml/llxmltree.cpp
diff --git a/linden/indra/llxml/llcontrol.cpp b/linden/indra/llxml/llcontrol.cpp
new file mode 100644
index 0000000..79fd522
--- /dev/null
+++ b/linden/indra/llxml/llcontrol.cpp
@@ -0,0 +1,1420 @@
1/**
2 * @file llcontrol.cpp
3 * @brief Holds global state for viewer.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include <iostream>
31#include <fstream>
32#include <algorithm>
33
34#include "llcontrol.h"
35
36#include "llstl.h"
37
38#include "linked_lists.h"
39#include "llstring.h"
40#include "v3math.h"
41#include "v3dmath.h"
42#include "v4coloru.h"
43#include "v4color.h"
44#include "v3color.h"
45#include "llrect.h"
46#include "llxmltree.h"
47#include "llsdserialize.h"
48
49#if LL_RELEASE_FOR_DOWNLOAD
50#define CONTROL_ERRS llwarns
51#else
52#define CONTROL_ERRS llerrs
53#endif
54
55//this defines the current version of the settings file
56U32 LLControlBase::sMaxControlNameLength = 0;
57
58//These lists are used to store the ID's of registered event listeners.
59std::list<S32> LLControlBase::mFreeIDs;
60std::list<S32> LLControlBase::mUsedIDs;
61
62S32 LLControlBase::mTopID;
63
64std::set<LLControlBase*> LLControlBase::mChangedControls;
65
66const S32 CURRENT_VERSION = 101;
67
68BOOL control_insert_before( LLControlBase* first, LLControlBase* second );
69
70BOOL LLControl::llsd_compare(const LLSD& a, const LLSD & b)
71{
72 switch (mType)
73 {
74 case TYPE_U32:
75 case TYPE_S32:
76 return a.asInteger() == b.asInteger();
77 case TYPE_BOOLEAN:
78 return a.asBoolean() == b.asBoolean();
79 case TYPE_F32:
80 return a.asReal() == b.asReal();
81 case TYPE_VEC3:
82 case TYPE_VEC3D:
83 return LLVector3d(a) == LLVector3d(b);
84 case TYPE_RECT:
85 return LLRect(a) == LLRect(b);
86 case TYPE_COL4:
87 return LLColor4(a) == LLColor4(b);
88 case TYPE_COL3:
89 return LLColor3(a) == LLColor3(b);
90 case TYPE_COL4U:
91 return LLColor4U(a) == LLColor4U(b);
92 case TYPE_STRING:
93 return a.asString() == b.asString();
94 default:
95 // no-op
96 break;
97 }
98
99 return FALSE;
100}
101
102LLControlBase::~LLControlBase()
103{
104}
105
106// virtual
107void LLControlBase::resetToDefault()
108{
109}
110
111LLControlGroup::LLControlGroup(): mNameTable()
112{
113 //mFreeStringOffset = 0;
114}
115
116LLControlGroup::~LLControlGroup()
117{
118}
119
120LLSD LLControlBase::registerListener(LLSimpleListenerObservable *listener, LLSD userdata)
121{
122 // Symmetric listener relationship
123 addListener(listener, "", userdata);
124 listener->addListener(this, "", userdata);
125 return getValue();
126}
127
128void LLControlGroup::cleanup()
129{
130 mNameTable.clear();
131}
132
133LLControlBase* LLControlGroup::getControl(const LLString& name)
134{
135 return mNameTable[name];
136}
137
138BOOL LLControlGroup::declareControl(const LLString& name, eControlType type, const LLSD initial_val, const LLString& comment, BOOL persist)
139{
140 if(!mNameTable[name])
141 {
142 // if not, create the control and add it to the name table
143 LLControl* control = new LLControl(name, type, initial_val, comment, persist);
144 mNameTable[name] = control;
145 return TRUE;
146 } else
147 {
148 llwarns << "LLControlGroup::declareControl: Control named " << name << " already exists." << llendl;
149 return FALSE;
150 }
151}
152
153BOOL LLControlGroup::declareU32(const LLString& name, const U32 initial_val, const LLString& comment, BOOL persist)
154{
155 return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist);
156}
157
158BOOL LLControlGroup::declareS32(const LLString& name, const S32 initial_val, const LLString& comment, BOOL persist)
159{
160 return declareControl(name, TYPE_S32, initial_val, comment, persist);
161}
162
163BOOL LLControlGroup::declareF32(const LLString& name, const F32 initial_val, const LLString& comment, BOOL persist)
164{
165 return declareControl(name, TYPE_F32, initial_val, comment, persist);
166}
167
168BOOL LLControlGroup::declareBOOL(const LLString& name, const BOOL initial_val, const LLString& comment, BOOL persist)
169{
170 return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist);
171}
172
173BOOL LLControlGroup::declareString(const LLString& name, const LLString& initial_val, const LLString& comment, BOOL persist)
174{
175 return declareControl(name, TYPE_STRING, initial_val, comment, persist);
176}
177
178BOOL LLControlGroup::declareVec3(const LLString& name, const LLVector3 &initial_val, const LLString& comment, BOOL persist)
179{
180 return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist);
181}
182
183BOOL LLControlGroup::declareVec3d(const LLString& name, const LLVector3d &initial_val, const LLString& comment, BOOL persist)
184{
185 return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist);
186}
187
188BOOL LLControlGroup::declareRect(const LLString& name, const LLRect &initial_val, const LLString& comment, BOOL persist)
189{
190 return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist);
191}
192
193BOOL LLControlGroup::declareColor4U(const LLString& name, const LLColor4U &initial_val, const LLString& comment, BOOL persist )
194{
195 return declareControl(name, TYPE_COL4U, initial_val.getValue(), comment, persist);
196}
197
198BOOL LLControlGroup::declareColor4(const LLString& name, const LLColor4 &initial_val, const LLString& comment, BOOL persist )
199{
200 return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist);
201}
202
203BOOL LLControlGroup::declareColor3(const LLString& name, const LLColor3 &initial_val, const LLString& comment, BOOL persist )
204{
205 return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist);
206}
207
208LLSD LLControlGroup::registerListener(const LLString& name, LLSimpleListenerObservable *listener)
209{
210 LLControlBase *control = mNameTable[name];
211 if (control)
212 {
213 return control->registerListener(listener);
214 }
215 return LLSD();
216}
217
218BOOL LLControlGroup::getBOOL(const LLString& name)
219{
220 LLControlBase* control = mNameTable[name];
221
222 if (control && control->isType(TYPE_BOOLEAN))
223 return control->get().asBoolean();
224 else
225 {
226 CONTROL_ERRS << "Invalid BOOL control " << name << llendl;
227 return FALSE;
228 }
229}
230
231S32 LLControlGroup::getS32(const LLString& name)
232{
233 LLControlBase* control = mNameTable[name];
234
235 if (control && control->isType(TYPE_S32))
236 return control->get().asInteger();
237 else
238 {
239 CONTROL_ERRS << "Invalid S32 control " << name << llendl;
240 return 0;
241 }
242}
243
244U32 LLControlGroup::getU32(const LLString& name)
245{
246 LLControlBase* control = mNameTable[name];
247
248 if (control && control->isType(TYPE_U32))
249 return control->get().asInteger();
250 else
251 {
252 CONTROL_ERRS << "Invalid U32 control " << name << llendl;
253 return 0;
254 }
255}
256
257F32 LLControlGroup::getF32(const LLString& name)
258{
259 LLControlBase* control = mNameTable[name];
260
261 if (control && control->isType(TYPE_F32))
262 return (F32) control->get().asReal();
263 else
264 {
265 CONTROL_ERRS << "Invalid F32 control " << name << llendl;
266 return 0.0f;
267 }
268}
269
270LLString LLControlGroup::findString(const LLString& name)
271{
272 LLControlBase* control = mNameTable[name];
273
274 if (control && control->isType(TYPE_STRING))
275 return control->get().asString();
276 return LLString::null;
277}
278
279LLString LLControlGroup::getString(const LLString& name)
280{
281 LLControlBase* control = mNameTable[name];
282
283 if (control && control->isType(TYPE_STRING))
284 return control->get().asString();
285 else
286 {
287 CONTROL_ERRS << "Invalid string control " << name << llendl;
288 return LLString::null;
289 }
290}
291
292LLWString LLControlGroup::getWString(const LLString& name)
293{
294 return utf8str_to_wstring(getString(name));
295}
296
297LLString LLControlGroup::getText(const LLString& name)
298{
299 LLString utf8_string = getString(name);
300 LLString::replaceChar(utf8_string, '^', '\n');
301 LLString::replaceChar(utf8_string, '%', ' ');
302 return (utf8_string);
303}
304
305LLVector3 LLControlGroup::getVector3(const LLString& name)
306{
307 LLControlBase* control = mNameTable[name];
308
309 if (control && control->isType(TYPE_VEC3))
310 return control->get();
311 else
312 {
313 CONTROL_ERRS << "Invalid LLVector3 control " << name << llendl;
314 return LLVector3::zero;
315 }
316}
317
318LLVector3d LLControlGroup::getVector3d(const LLString& name)
319{
320 LLControlBase* control = mNameTable[name];
321
322 if (control && control->isType(TYPE_VEC3D))
323 return control->get();
324 else
325 {
326 CONTROL_ERRS << "Invalid LLVector3d control " << name << llendl;
327 return LLVector3d::zero;
328 }
329}
330
331LLRect LLControlGroup::getRect(const LLString& name)
332{
333 LLControlBase* control = mNameTable[name];
334
335 if (control && control->isType(TYPE_RECT))
336 return control->get();
337 else
338 {
339 CONTROL_ERRS << "Invalid rect control " << name << llendl;
340 return LLRect::null;
341 }
342}
343
344
345LLColor4 LLControlGroup::getColor(const LLString& name)
346{
347 ctrl_name_table_t::const_iterator i = mNameTable.find(name);
348
349 if (i != mNameTable.end())
350 {
351 LLControlBase* control = i->second;
352
353 switch(control->mType)
354 {
355 case TYPE_COL4:
356 {
357 return LLColor4(control->get());
358 }
359 case TYPE_COL4U:
360 {
361 return LLColor4(LLColor4U(control->get()));
362 }
363 default:
364 {
365 CONTROL_ERRS << "Control " << name << " not a color" << llendl;
366 return LLColor4::white;
367 }
368 }
369 }
370 else
371 {
372 CONTROL_ERRS << "Invalid getColor control " << name << llendl;
373 return LLColor4::white;
374 }
375}
376
377LLColor4U LLControlGroup::getColor4U(const LLString& name)
378{
379 LLControlBase* control = mNameTable[name];
380
381 if (control && control->isType(TYPE_COL4U))
382 return control->get();
383 else
384 {
385 CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl;
386 return LLColor4U::white;
387 }
388}
389
390LLColor4 LLControlGroup::getColor4(const LLString& name)
391{
392 LLControlBase* control = mNameTable[name];
393
394 if (control && control->isType(TYPE_COL4))
395 return control->get();
396 else
397 {
398 CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl;
399 return LLColor4::white;
400 }
401}
402
403LLColor3 LLControlGroup::getColor3(const LLString& name)
404{
405 LLControlBase* control = mNameTable[name];
406
407 if (control && control->isType(TYPE_COL3))
408 return control->get();
409 else
410 {
411 CONTROL_ERRS << "Invalid LLColor3 control " << name << llendl;
412 return LLColor3::white;
413 }
414}
415
416BOOL LLControlGroup::controlExists(const LLString& name)
417{
418 void *control = mNameTable[name];
419
420 return (control != 0);
421}
422
423//-------------------------------------------------------------------
424// Set functions
425//-------------------------------------------------------------------
426
427void LLControlGroup::setBOOL(const LLString& name, BOOL val)
428{
429 LLControlBase* control = mNameTable[name];
430
431 if (control && control->isType(TYPE_BOOLEAN))
432 {
433 control->set(val);
434 }
435 else
436 {
437 CONTROL_ERRS << "Invalid control " << name << llendl;
438 }
439}
440
441
442void LLControlGroup::setS32(const LLString& name, S32 val)
443{
444 LLControlBase* control = mNameTable[name];
445
446 if (control && control->isType(TYPE_S32))
447 {
448 control->set(val);
449 }
450 else
451 {
452 CONTROL_ERRS << "Invalid control " << name << llendl;
453 }
454}
455
456
457void LLControlGroup::setF32(const LLString& name, F32 val)
458{
459 LLControlBase* control = mNameTable[name];
460
461 if (control && control->isType(TYPE_F32))
462 {
463 control->set(val);
464 }
465 else
466 {
467 CONTROL_ERRS << "Invalid control " << name << llendl;
468 }
469}
470
471
472void LLControlGroup::setU32(const LLString& name, U32 val)
473{
474 LLControlBase* control = mNameTable[name];
475
476 if (control && control->isType(TYPE_U32))
477 {
478 control->set((LLSD::Integer) val);
479 }
480 else
481 {
482 CONTROL_ERRS << "Invalid control " << name << llendl;
483 }
484}
485
486
487void LLControlGroup::setString(const LLString& name, const LLString &val)
488{
489 LLControlBase* control = mNameTable[name];
490
491 if (control && control->isType(TYPE_STRING))
492 {
493 control->set(val);
494 }
495 else
496 {
497 CONTROL_ERRS << "Invalid control " << name << llendl;
498 }
499}
500
501
502void LLControlGroup::setVector3(const LLString& name, const LLVector3 &val)
503{
504 LLControlBase* control = mNameTable[name];
505
506 if (control && control->isType(TYPE_VEC3))
507 {
508 control->set(val.getValue());
509 }
510 else
511 {
512 CONTROL_ERRS << "Invalid control " << name << llendl;
513 }
514}
515
516void LLControlGroup::setVector3d(const LLString& name, const LLVector3d &val)
517{
518 LLControlBase* control = mNameTable[name];
519
520 if (control && control->isType(TYPE_VEC3D))
521 {
522 control->set(val.getValue());
523 }
524 else
525 {
526 CONTROL_ERRS << "Invalid control " << name << llendl;
527 }
528}
529
530void LLControlGroup::setRect(const LLString& name, const LLRect &val)
531{
532 LLControlBase* control = mNameTable[name];
533
534 if (control && control->isType(TYPE_RECT))
535 {
536 control->set(val.getValue());
537 }
538 else
539 {
540 CONTROL_ERRS << "Invalid rect control " << name << llendl;
541 }
542}
543
544void LLControlGroup::setColor4U(const LLString& name, const LLColor4U &val)
545{
546 LLControlBase* control = mNameTable[name];
547
548 if (control && control->isType(TYPE_COL4U))
549 {
550 control->set(val.getValue());
551 }
552 else
553 {
554 CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl;
555 }
556}
557
558void LLControlGroup::setColor4(const LLString& name, const LLColor4 &val)
559{
560 LLControlBase* control = mNameTable[name];
561
562 if (control && control->isType(TYPE_COL4))
563 {
564 control->set(val.getValue());
565 }
566 else
567 {
568 CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl;
569 }
570}
571
572void LLControlGroup::setValue(const LLString& name, const LLSD& val)
573{
574 if (name.empty())
575 {
576 return;
577 }
578
579 LLControlBase* control = mNameTable[name];
580
581 if (control)
582 {
583 control->set(val);
584 }
585 else
586 {
587 CONTROL_ERRS << "Invalid control " << name << llendl;
588 }
589}
590
591//---------------------------------------------------------------
592// Load and save
593//---------------------------------------------------------------
594
595U32 LLControlGroup::loadFromFileLegacy(const LLString& filename, BOOL require_declaration, eControlType declare_as)
596{
597 U32 item = 0;
598 U32 validitems = 0;
599 llifstream file;
600 S32 version;
601
602 file.open(filename.c_str());
603
604 if (!file)
605 {
606 llinfos << "LLControlGroup::loadFromFile unable to open." << llendl;
607 return 0;
608 }
609
610 // Check file version
611 LLString name;
612 file >> name;
613 file >> version;
614 if (name != "version" || version != CURRENT_VERSION)
615 {
616 llinfos << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << llendl;
617 return 0;
618 }
619
620 while (!file.eof())
621 {
622 file >> name;
623
624 if (name.empty())
625 {
626 continue;
627 }
628
629 if (name.substr(0,2) == "//")
630 {
631 // This is a comment.
632 char buffer[MAX_STRING];
633 file.getline(buffer, MAX_STRING);
634 continue;
635 }
636
637 BOOL declared = mNameTable.find(name) != mNameTable.end();
638
639 if (require_declaration && !declared)
640 {
641 // Declaration required, but this name not declared.
642 // Complain about non-empty names.
643 if (!name.empty())
644 {
645 //read in to end of line
646 char buffer[MAX_STRING];
647 file.getline(buffer, MAX_STRING);
648 llwarns << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << llendl;
649 }
650 continue;
651 }
652
653 // Got an item. Load it up.
654 item++;
655
656 // If not declared, assume it's a string
657 if (!declared)
658 {
659 switch(declare_as)
660 {
661 case TYPE_COL4:
662 declareColor4(name, LLColor4::white, LLString::null, NO_PERSIST);
663 break;
664 case TYPE_COL4U:
665 declareColor4U(name, LLColor4U::white, LLString::null, NO_PERSIST);
666 break;
667 case TYPE_STRING:
668 default:
669 declareString(name, LLString::null, LLString::null, NO_PERSIST);
670 break;
671 }
672 }
673
674 // Control name has been declared in code.
675 LLControlBase *control = getControl(name);
676
677 llassert(control);
678
679 switch(control->mType)
680 {
681 case TYPE_F32:
682 {
683 F32 initial;
684
685 file >> initial;
686
687 control->set(initial);
688 validitems++;
689 }
690 break;
691 case TYPE_S32:
692 {
693 S32 initial;
694
695 file >> initial;
696
697 control->set(initial);
698 validitems++;
699 }
700 break;
701 case TYPE_U32:
702 {
703 U32 initial;
704
705 file >> initial;
706 control->set((LLSD::Integer) initial);
707 validitems++;
708 }
709 break;
710 case TYPE_BOOLEAN:
711 {
712 char boolstring[256];
713 BOOL valid = FALSE;
714 BOOL initial = FALSE;
715
716 file >> boolstring;
717 if (!strcmp("TRUE", boolstring))
718 {
719 initial = TRUE;
720 valid = TRUE;
721 }
722 else if (!strcmp("FALSE", boolstring))
723 {
724 initial = FALSE;
725 valid = TRUE;
726 }
727
728 if (valid)
729 {
730 control->set(initial);
731 }
732 else
733 {
734 llinfos << filename << "Item " << item << ": Invalid BOOL control " << name << ", " << boolstring << llendl;
735 }
736
737 validitems++;
738 }
739 break;
740 case TYPE_STRING:
741 {
742 LLString string;
743
744 file >> string;
745
746 control->set(string);
747 validitems++;
748 }
749 break;
750 case TYPE_VEC3:
751 {
752 F32 x, y, z;
753
754 file >> x >> y >> z;
755
756 LLVector3 vector(x, y, z);
757
758 control->set(vector.getValue());
759 validitems++;
760 }
761 break;
762 case TYPE_VEC3D:
763 {
764 F64 x, y, z;
765
766 file >> x >> y >> z;
767
768 LLVector3d vector(x, y, z);
769
770 control->set(vector.getValue());
771 validitems++;
772 }
773 break;
774 case TYPE_RECT:
775 {
776 S32 left, bottom, width, height;
777
778 file >> left >> bottom >> width >> height;
779
780 LLRect rect;
781 rect.setOriginAndSize(left, bottom, width, height);
782
783 control->set(rect.getValue());
784 validitems++;
785 }
786 break;
787 case TYPE_COL4U:
788 {
789 S32 red, green, blue, alpha;
790 LLColor4U color;
791 file >> red >> green >> blue >> alpha;
792 color.setVec(red, green, blue, alpha);
793 control->set(color.getValue());
794 validitems++;
795 }
796 break;
797 case TYPE_COL4:
798 {
799 LLColor4 color;
800 file >> color.mV[VRED] >> color.mV[VGREEN]
801 >> color.mV[VBLUE] >> color.mV[VALPHA];
802 control->set(color.getValue());
803 validitems++;
804 }
805 break;
806 case TYPE_COL3:
807 {
808 LLColor3 color;
809 file >> color.mV[VRED] >> color.mV[VGREEN]
810 >> color.mV[VBLUE];
811 control->set(color.getValue());
812 validitems++;
813 }
814 break;
815 }
816 }
817
818 file.close();
819
820 return validitems;
821}
822
823// Returns number of controls loaded, so 0 if failure
824U32 LLControlGroup::loadFromFile(const LLString& filename, BOOL require_declaration, eControlType declare_as)
825{
826 LLString name;
827
828 LLXmlTree xml_controls;
829
830 if (!xml_controls.parseFile(filename))
831 {
832 llwarns << "Unable to open control file " << filename << llendl;
833 return 0;
834 }
835
836 LLXmlTreeNode* rootp = xml_controls.getRoot();
837 if (!rootp || !rootp->hasAttribute("version"))
838 {
839 llwarns << "No valid settings header found in control file " << filename << llendl;
840 return 0;
841 }
842
843 U32 item = 0;
844 U32 validitems = 0;
845 S32 version;
846
847 rootp->getAttributeS32("version", version);
848
849 // Check file version
850 if (version != CURRENT_VERSION)
851 {
852 llinfos << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << llendl;
853 return 0;
854 }
855
856 LLXmlTreeNode* child_nodep = rootp->getFirstChild();
857 while(child_nodep)
858 {
859 name = child_nodep->getName();
860
861 BOOL declared = (mNameTable[name].notNull());
862
863 if (require_declaration && !declared)
864 {
865 // Declaration required, but this name not declared.
866 // Complain about non-empty names.
867 if (!name.empty())
868 {
869 //read in to end of line
870 llwarns << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << llendl;
871 }
872 child_nodep = rootp->getNextChild();
873 continue;
874 }
875
876 // Got an item. Load it up.
877 item++;
878
879 // If not declared, assume it's a string
880 if (!declared)
881 {
882 switch(declare_as)
883 {
884 case TYPE_COL4:
885 declareColor4(name, LLColor4::white, "", NO_PERSIST);
886 break;
887 case TYPE_COL4U:
888 declareColor4U(name, LLColor4U::white, "", NO_PERSIST);
889 break;
890 case TYPE_STRING:
891 default:
892 declareString(name, LLString::null, "", NO_PERSIST);
893 break;
894 }
895 }
896
897 // Control name has been declared in code.
898 LLControlBase *control = getControl(name);
899
900 llassert(control);
901
902 switch(control->mType)
903 {
904 case TYPE_F32:
905 {
906 F32 initial = 0.f;
907
908 child_nodep->getAttributeF32("value", initial);
909
910 control->set(initial);
911 validitems++;
912 }
913 break;
914 case TYPE_S32:
915 {
916 S32 initial = 0;
917
918 child_nodep->getAttributeS32("value", initial);
919
920 control->set(initial);
921 validitems++;
922 }
923 break;
924 case TYPE_U32:
925 {
926 U32 initial = 0;
927 child_nodep->getAttributeU32("value", initial);
928 control->set((LLSD::Integer) initial);
929 validitems++;
930 }
931 break;
932 case TYPE_BOOLEAN:
933 {
934 BOOL initial = FALSE;
935
936 child_nodep->getAttributeBOOL("value", initial);
937 control->set(initial);
938
939 validitems++;
940 }
941 break;
942 case TYPE_STRING:
943 {
944 LLString string;
945 child_nodep->getAttributeString("value", string);
946 if (string == LLString::null)
947 {
948 string = "";
949 }
950 control->set(string);
951 validitems++;
952 }
953 break;
954 case TYPE_VEC3:
955 {
956 LLVector3 vector;
957
958 child_nodep->getAttributeVector3("value", vector);
959 control->set(vector.getValue());
960 validitems++;
961 }
962 break;
963 case TYPE_VEC3D:
964 {
965 LLVector3d vector;
966
967 child_nodep->getAttributeVector3d("value", vector);
968
969 control->set(vector.getValue());
970 validitems++;
971 }
972 break;
973 case TYPE_RECT:
974 {
975 //RN: hack to support reading rectangles from a string
976 LLString rect_string;
977
978 child_nodep->getAttributeString("value", rect_string);
979 std::istringstream istream(rect_string);
980 S32 left, bottom, width, height;
981
982 istream >> left >> bottom >> width >> height;
983
984 LLRect rect;
985 rect.setOriginAndSize(left, bottom, width, height);
986
987 control->set(rect.getValue());
988 validitems++;
989 }
990 break;
991 case TYPE_COL4U:
992 {
993 LLColor4U color;
994
995 child_nodep->getAttributeColor4U("value", color);
996 control->set(color.getValue());
997 validitems++;
998 }
999 break;
1000 case TYPE_COL4:
1001 {
1002 LLColor4 color;
1003
1004 child_nodep->getAttributeColor4("value", color);
1005 control->set(color.getValue());
1006 validitems++;
1007 }
1008 break;
1009 case TYPE_COL3:
1010 {
1011 LLVector3 color;
1012
1013 child_nodep->getAttributeVector3("value", color);
1014 control->set(LLColor3(color.mV).getValue());
1015 validitems++;
1016 }
1017 break;
1018 }
1019
1020 child_nodep = rootp->getNextChild();
1021 }
1022
1023 return validitems;
1024}
1025
1026
1027U32 LLControlGroup::saveToFile(const LLString& filename, BOOL nondefault_only)
1028{
1029 const char ENDL = '\n';
1030
1031 llinfos << "Saving settings to file: " << filename << llendl;
1032
1033 // place the objects in a temporary container that enforces a sort
1034 // order to ease manual editing of the file
1035 LLLinkedList< LLControlBase > controls;
1036 controls.setInsertBefore( &control_insert_before );
1037 LLString name;
1038 for (ctrl_name_table_t::iterator iter = mNameTable.begin();
1039 iter != mNameTable.end(); iter++)
1040 {
1041 name = iter->first;
1042 if (name.empty())
1043 {
1044 CONTROL_ERRS << "Control with no name found!!!" << llendl;
1045 break;
1046 }
1047
1048 LLControlBase* control = (LLControlBase *)mNameTable[name];
1049
1050 if (!control)
1051 {
1052 llwarns << "Tried to save invalid control: " << name << llendl;
1053 }
1054
1055 if( control && control->mPersist )
1056 {
1057 if (!(nondefault_only && (control->mIsDefault)))
1058 {
1059 controls.addDataSorted( control );
1060 }
1061 else
1062 {
1063 // Debug spam
1064 // llinfos << "Skipping " << control->getName() << llendl;
1065 }
1066 }
1067 }
1068
1069 llofstream file;
1070 file.open(filename.c_str());
1071
1072 if (!file.is_open())
1073 {
1074 // This is a warning because sometime we want to use settings files which can't be written...
1075 llwarns << "LLControlGroup::saveToFile unable to open file for writing" << llendl;
1076 return 0;
1077 }
1078
1079 // Write file version
1080 file << "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n";
1081 file << "<settings version = \"" << CURRENT_VERSION << "\">\n";
1082 for( LLControlBase* control = controls.getFirstData();
1083 control != NULL;
1084 control = controls.getNextData() )
1085 {
1086 file << "\t<!--" << control->comment() << "-->" << ENDL;
1087 name = control->name();
1088 switch (control->type())
1089 {
1090 case TYPE_U32:
1091 {
1092 file << "\t<" << name << " value=\"" << (U32) control->get().asInteger() << "\"/>\n";
1093 break;
1094 }
1095 case TYPE_S32:
1096 {
1097 file << "\t<" << name << " value=\"" << (S32) control->get().asInteger() << "\"/>\n";
1098 break;
1099 }
1100 case TYPE_F32:
1101 {
1102 file << "\t<" << name << " value=\"" << (F32) control->get().asReal() << "\"/>\n";
1103 break;
1104 }
1105 case TYPE_VEC3:
1106 {
1107 LLVector3 vector(control->get());
1108 file << "\t<" << name << " value=\"" << vector.mV[VX] << " " << vector.mV[VY] << " " << vector.mV[VZ] << "\"/>\n";
1109 break;
1110 }
1111 case TYPE_VEC3D:
1112 {
1113 LLVector3d vector(control->get());
1114 file << "\t<" << name << " value=\"" << vector.mdV[VX] << " " << vector.mdV[VY] << " " << vector.mdV[VZ] << "\"/>\n";
1115 break;
1116 }
1117 case TYPE_RECT:
1118 {
1119 LLRect rect(control->get());
1120 file << "\t<" << name << " value=\"" << rect.mLeft << " " << rect.mBottom << " " << rect.getWidth() << " " << rect.getHeight() << "\"/>\n";
1121 break;
1122 }
1123 case TYPE_COL4:
1124 {
1125 LLColor4 color(control->get());
1126 file << "\t<" << name << " value=\"" << color.mV[VRED] << ", " << color.mV[VGREEN] << ", " << color.mV[VBLUE] << ", " << color.mV[VALPHA] << "\"/>\n";
1127 break;
1128 }
1129 case TYPE_COL3:
1130 {
1131 LLColor3 color(control->get());
1132 file << "\t<" << name << " value=\"" << color.mV[VRED] << ", " << color.mV[VGREEN] << ", " << color.mV[VBLUE] << "\"/>\n";
1133 break;
1134 }
1135 case TYPE_BOOLEAN:
1136 {
1137 file << "\t<" << name << " value=\"" << (control->get().asBoolean() ? "TRUE" : "FALSE") << "\"/>\n";
1138 break;
1139 }
1140 case TYPE_STRING:
1141 {
1142 file << "\t<" << name << " value=\"" << LLSDXMLFormatter::escapeString(control->get().asString()) << "\"/>\n";
1143 break;
1144 }
1145 default:
1146 {
1147 CONTROL_ERRS << "LLControlGroup::saveToFile - unknown control type!" << llendl;
1148 break;
1149 }
1150 }
1151
1152 // Debug spam
1153 // llinfos << name << " " << control->getValue().asString() << llendl;
1154 }// next
1155
1156 file << "</settings>\n";
1157 file.close();
1158
1159 return controls.getLength();
1160}
1161
1162void LLControlGroup::applyOverrides(const std::map<std::string, std::string>& overrides)
1163{
1164 for (std::map<std::string, std::string>::const_iterator iter = overrides.begin();
1165 iter != overrides.end(); ++iter)
1166 {
1167 const std::string& command = iter->first;
1168 const std::string& value = iter->second;
1169 LLControlBase* control = (LLControlBase *)mNameTable[command];
1170 if (control)
1171 {
1172 switch(control->mType)
1173 {
1174 case TYPE_U32:
1175 control->set((LLSD::Integer)atof(value.c_str()));
1176 break;
1177 case TYPE_S32:
1178 control->set((S32)atof(value.c_str()));
1179 break;
1180 case TYPE_F32:
1181 control->set((F32)atof(value.c_str()));
1182 break;
1183 case TYPE_BOOLEAN:
1184 if (!LLString::compareInsensitive(value.c_str(), "TRUE"))
1185 {
1186 control->set(TRUE);
1187 }
1188 else if (!LLString::compareInsensitive(value.c_str(), "FALSE"))
1189 {
1190 control->set(FALSE);
1191 }
1192 else
1193 {
1194 control->set((BOOL)atof(value.c_str()));
1195 }
1196 break;
1197 case TYPE_STRING:
1198 control->set(value);
1199 break;
1200// // *FIX: implement this given time and need.
1201// case TYPE_UUID:
1202// break;
1203 // we don't support command line overrides of vec3 or col4
1204 // yet - requires parsing of multiple values
1205 case TYPE_VEC3:
1206 case TYPE_VEC3D:
1207 case TYPE_COL4:
1208 case TYPE_COL3:
1209 default:
1210 break;
1211 }
1212 }
1213 else
1214 {
1215 llinfos << "There is no control variable " << command << llendl;
1216 }
1217 }
1218}
1219
1220void LLControlGroup::resetToDefaults()
1221{
1222 ctrl_name_table_t::iterator control_iter;
1223 for (control_iter = mNameTable.begin();
1224 control_iter != mNameTable.end();
1225 ++control_iter)
1226 {
1227 LLControlBase* control = (*control_iter).second;
1228 control->resetToDefault();
1229 }
1230}
1231
1232//============================================================================
1233// FIrst-use
1234
1235
1236void LLControlGroup::addWarning(const LLString& name)
1237{
1238 LLString warnname = "Warn" + name;
1239 if(!mNameTable[warnname])
1240 {
1241 LLString comment = LLString("Enables ") + name + LLString(" warning dialog");
1242 declareBOOL(warnname, TRUE, comment);
1243 mWarnings.insert(warnname);
1244 }
1245}
1246
1247BOOL LLControlGroup::getWarning(const LLString& name)
1248{
1249 LLString warnname = "Warn" + name;
1250 return getBOOL(warnname);
1251}
1252
1253void LLControlGroup::setWarning(const LLString& name, BOOL val)
1254{
1255 LLString warnname = "Warn" + name;
1256 setBOOL(warnname, val);
1257}
1258
1259void LLControlGroup::resetWarnings()
1260{
1261 for (std::set<LLString>::iterator iter = mWarnings.begin();
1262 iter != mWarnings.end(); ++iter)
1263 {
1264 setBOOL(*iter, TRUE);
1265 }
1266}
1267
1268
1269
1270//=============================================================================
1271// Listener ID generator/management
1272
1273void LLControlBase::releaseListenerID(S32 id)
1274{
1275 mFreeIDs.push_back(id);
1276}
1277
1278S32 LLControlBase::allocateListenerID()
1279{
1280 if(mFreeIDs.size() == 0)
1281 { //Out of IDs so generate some new ones.
1282 for(int t=0;t<32;t++)
1283 {
1284 mFreeIDs.push_back(mTopID++);
1285 }
1286 }
1287 S32 rtn = mFreeIDs.front();
1288 mFreeIDs.pop_front();
1289 mUsedIDs.push_back(rtn);
1290 return rtn;
1291}
1292
1293bool LLControlBase::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
1294{
1295 if (event->desc() == "value_changed")
1296 {
1297 setValue(((LLValueChangedEvent*)(LLEvent*)event)->mValue);
1298 return TRUE;
1299 }
1300 return TRUE;
1301}
1302
1303void LLControlBase::firePropertyChanged()
1304{
1305 LLValueChangedEvent *evt = new LLValueChangedEvent(this, getValue());
1306 fireEvent(evt, "");
1307}
1308
1309//============================================================================
1310// Used to add a listener callback that will be called on the frame that the controls value changes
1311
1312S32 LLControl::addListener(LLControl::tListenerCallback* cbfn)
1313{
1314 S32 id = allocateListenerID();
1315 mListeners.push_back(cbfn);
1316 mListenerIDs.push_back( id );
1317 return id;
1318}
1319
1320void LLControl::updateListeners() {
1321 LLControl::tPropertyChangedListIter iter = mChangeEvents.begin();
1322 while(iter!=mChangeEvents.end()){
1323 LLControl::tPropertyChangedEvent& evt = *iter;
1324 (*evt.mCBFN)(evt.mNewValue,evt.mID,*this);
1325 iter++;
1326 }
1327 mChangeEvents.clear();
1328}
1329
1330//static
1331void LLControlBase::updateAllListeners()
1332{
1333 std::set< LLControlBase* >::iterator iter = mChangedControls.begin();
1334 while(iter != mChangedControls.end()){
1335 (*iter)->updateListeners();
1336 iter++;
1337 }
1338 mChangedControls.clear();
1339}
1340
1341LLControl::LLControl(
1342 const LLString& name,
1343 eControlType type,
1344 LLSD initial,
1345 const LLString& comment,
1346 BOOL persist) :
1347 LLControlBase(name, type, comment, persist),
1348 mCurrent(initial),
1349 mDefault(initial)
1350{
1351}
1352
1353//============================================================================
1354
1355#ifdef TEST_HARNESS
1356void main()
1357{
1358 F32_CONTROL foo, getfoo;
1359
1360 S32_CONTROL bar, getbar;
1361
1362 BOOL_CONTROL baz;
1363
1364 U32 count = gGlobals.loadFromFile("controls.ini");
1365 llinfos << "Loaded " << count << " controls" << llendl;
1366
1367 // test insertion
1368 foo = new LLControl<F32>("gFoo", 5.f, 1.f, 20.f);
1369 gGlobals.addEntry("gFoo", foo);
1370
1371 bar = new LLControl<S32>("gBar", 10, 2, 22);
1372 gGlobals.addEntry("gBar", bar);
1373
1374 baz = new LLControl<BOOL>("gBaz", FALSE);
1375 gGlobals.addEntry("gBaz", baz);
1376
1377 // test retrieval
1378 getfoo = (LLControl<F32>*) gGlobals.resolveName("gFoo");
1379 getfoo->dump();
1380
1381 getbar = (S32_CONTROL) gGlobals.resolveName("gBar");
1382 getbar->dump();
1383
1384 // change data
1385 getfoo->set(10.f);
1386 getfoo->dump();
1387
1388 // Failure modes
1389
1390 // ...min > max
1391 // badfoo = new LLControl<F32>("gFoo2", 100.f, 20.f, 5.f);
1392
1393 // ...initial > max
1394 // badbar = new LLControl<S32>("gBar2", 10, 20, 100000);
1395
1396 // ...misspelled name
1397 // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled");
1398 // getfoo->dump();
1399
1400 // ...invalid data type
1401 getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo");
1402 getfoo->set(TRUE);
1403 getfoo->dump();
1404
1405 // ...out of range data
1406 // getfoo->set(100000000.f);
1407 // getfoo->dump();
1408
1409 // Clean Up
1410 delete foo;
1411 delete bar;
1412 delete baz;
1413}
1414#endif
1415
1416BOOL control_insert_before( LLControlBase* first, LLControlBase* second )
1417{
1418 return ( first->getName().compare(second->getName()) < 0 );
1419}
1420
diff --git a/linden/indra/llxml/llcontrol.h b/linden/indra/llxml/llcontrol.h
new file mode 100644
index 0000000..846a3b5
--- /dev/null
+++ b/linden/indra/llxml/llcontrol.h
@@ -0,0 +1,274 @@
1/**
2 * @file llcontrol.h
3 * @brief A mechanism for storing "control state" for a program
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLCONTROL_H
29#define LL_LLCONTROL_H
30
31#include "llevent.h"
32#include "llnametable.h"
33#include "llmap.h"
34#include "llstring.h"
35#include "llrect.h"
36
37class LLVector3;
38class LLVector3d;
39class LLColor4;
40class LLColor3;
41class LLColor4U;
42
43const BOOL NO_PERSIST = FALSE;
44
45typedef enum e_control_type
46{
47 TYPE_U32,
48 TYPE_S32,
49 TYPE_F32,
50 TYPE_BOOLEAN,
51 TYPE_STRING,
52 TYPE_VEC3,
53 TYPE_VEC3D,
54 TYPE_RECT,
55 TYPE_COL4,
56 TYPE_COL3,
57 TYPE_COL4U
58} eControlType;
59
60class LLControlBase : public LLSimpleListenerObservable
61{
62friend class LLControlGroup;
63protected:
64 LLString mName;
65 LLString mComment;
66 eControlType mType;
67 BOOL mHasRange;
68 BOOL mPersist;
69 BOOL mIsDefault;
70 static std::set<LLControlBase*> mChangedControls;
71 static std::list<S32> mFreeIDs;//These lists are used to store the ID's of registered event listeners.
72 static std::list<S32> mUsedIDs;
73 static S32 mTopID;//This is the index of the highest ID event listener ID. When the free pool is exhausted, new IDs are allocated from here.
74
75public:
76 static void releaseListenerID(S32 id);
77 static S32 allocateListenerID();
78 static void updateAllListeners();
79 virtual void updateListeners() = 0;
80
81 LLControlBase(const LLString& name, eControlType type, const LLString& comment, BOOL persist)
82 : mName(name),
83 mComment(comment),
84 mType(type),
85 mHasRange(FALSE),
86 mPersist(persist),
87 mIsDefault(TRUE)
88 {
89 if (mPersist && mComment.empty())
90 {
91 llerrs << "Must supply a comment for control " << mName << llendl;
92 }
93 sMaxControlNameLength = llmax((U32)mName.size(), sMaxControlNameLength);
94 }
95
96 virtual ~LLControlBase();
97
98 const LLString& getName() const { return mName; }
99 const LLString& getComment() const { return mComment; }
100
101 eControlType type() { return mType; }
102 BOOL isType(eControlType tp) { return tp == mType; }
103
104 // Defaults to no-op
105 virtual void resetToDefault();
106
107 LLSD registerListener(LLSimpleListenerObservable *listener, LLSD userdata = "");
108
109 virtual LLSD get() const = 0;
110 virtual LLSD getValue() const = 0;
111 virtual void setValue(LLSD value) = 0;
112 virtual void set(LLSD value) = 0;
113
114 // From LLSimpleListener
115 virtual bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata);
116
117 void firePropertyChanged();
118
119 static U32 sMaxControlNameLength;
120
121protected:
122 const char* name() { return mName.c_str(); }
123 const char* comment() { return mComment.c_str(); }
124};
125
126class LLControl
127: public LLControlBase
128{
129friend class LLControlGroup;
130protected:
131 LLSD mCurrent;
132 LLSD mDefault;
133
134public:
135
136 typedef void tListenerCallback(const LLSD& newValue,S32 listenerID, LLControl& control);
137 typedef struct{
138 S32 mID;
139 LLSD mNewValue;
140 tListenerCallback* mCBFN;
141 }tPropertyChangedEvent;
142
143 typedef std::list<tPropertyChangedEvent>::iterator tPropertyChangedListIter;
144 std::list<tPropertyChangedEvent> mChangeEvents;
145 std::list< tListenerCallback* > mListeners;
146 std::list< S32 > mListenerIDs;
147
148 virtual void updateListeners();
149 S32 addListener(tListenerCallback* cbfn);
150
151 LLControl(
152 const LLString& name,
153 eControlType type,
154 LLSD initial, const
155 LLString& comment,
156 BOOL persist = TRUE);
157
158 void set(LLSD val) { setValue(val); }
159 LLSD get() const { return getValue(); }
160 LLSD getdefault() const { return mDefault; }
161 LLSD getValue() const { return mCurrent; }
162 BOOL llsd_compare(const LLSD& a, const LLSD& b);
163
164 void setValue(LLSD value)
165 {
166 if (llsd_compare(mCurrent, value) == FALSE)
167 {
168 mCurrent = value;
169 mIsDefault = llsd_compare(mCurrent, mDefault);
170 firePropertyChanged();
171 }
172 }
173
174 /*virtual*/ void resetToDefault() { mCurrent = mDefault; mIsDefault = TRUE;}
175
176 virtual ~LLControl()
177 {
178 //Remove and deregister all listeners..
179 while(mListenerIDs.size())
180 {
181 S32 id = mListenerIDs.front();
182 mListenerIDs.pop_front();
183 releaseListenerID(id);
184 }
185 }
186};
187
188//const U32 STRING_CACHE_SIZE = 10000;
189class LLControlGroup
190{
191public:
192 typedef std::map<LLString, LLPointer<LLControlBase> > ctrl_name_table_t;
193 ctrl_name_table_t mNameTable;
194 std::set<LLString> mWarnings;
195
196public:
197 LLControlGroup();
198 ~LLControlGroup();
199 void cleanup();
200
201 LLControlBase* getControl(const LLString& name);
202 LLSD registerListener(const LLString& name, LLSimpleListenerObservable *listener);
203
204 BOOL declareControl(const LLString& name, eControlType type, const LLSD initial_val, const LLString& comment, BOOL persist);
205 BOOL declareU32(const LLString& name, U32 initial_val, const LLString& comment, BOOL persist = TRUE);
206 BOOL declareS32(const LLString& name, S32 initial_val, const LLString& comment, BOOL persist = TRUE);
207 BOOL declareF32(const LLString& name, F32 initial_val, const LLString& comment, BOOL persist = TRUE);
208 BOOL declareBOOL(const LLString& name, BOOL initial_val, const LLString& comment, BOOL persist = TRUE);
209 BOOL declareString(const LLString& name, const LLString &initial_val, const LLString& comment, BOOL persist = TRUE);
210 BOOL declareVec3(const LLString& name, const LLVector3 &initial_val,const LLString& comment, BOOL persist = TRUE);
211 BOOL declareVec3d(const LLString& name, const LLVector3d &initial_val, const LLString& comment, BOOL persist = TRUE);
212 BOOL declareRect(const LLString& name, const LLRect &initial_val, const LLString& comment, BOOL persist = TRUE);
213 BOOL declareColor4U(const LLString& name, const LLColor4U &initial_val, const LLString& comment, BOOL persist = TRUE);
214 BOOL declareColor4(const LLString& name, const LLColor4 &initial_val, const LLString& comment, BOOL persist = TRUE);
215 BOOL declareColor3(const LLString& name, const LLColor3 &initial_val, const LLString& comment, BOOL persist = TRUE);
216
217 LLString findString(const LLString& name);
218
219 LLString getString(const LLString& name);
220 LLWString getWString(const LLString& name);
221 LLString getText(const LLString& name);
222 LLVector3 getVector3(const LLString& name);
223 LLVector3d getVector3d(const LLString& name);
224 LLRect getRect(const LLString& name);
225 BOOL getBOOL(const LLString& name);
226 S32 getS32(const LLString& name);
227 F32 getF32(const LLString& name);
228 U32 getU32(const LLString& name);
229 LLSD getValue(const LLString& name);
230
231
232 // Note: If an LLColor4U control exists, it will cast it to the correct
233 // LLColor4 for you.
234 LLColor4 getColor(const LLString& name);
235 LLColor4U getColor4U(const LLString& name);
236 LLColor4 getColor4(const LLString& name);
237 LLColor3 getColor3(const LLString& name);
238
239 void setBOOL(const LLString& name, BOOL val);
240 void setS32(const LLString& name, S32 val);
241 void setF32(const LLString& name, F32 val);
242 void setU32(const LLString& name, U32 val);
243 void setString(const LLString& name, const LLString& val);
244 void setVector3(const LLString& name, const LLVector3 &val);
245 void setVector3d(const LLString& name, const LLVector3d &val);
246 void setRect(const LLString& name, const LLRect &val);
247 void setColor4U(const LLString& name, const LLColor4U &val);
248 void setColor4(const LLString& name, const LLColor4 &val);
249 void setColor3(const LLString& name, const LLColor3 &val);
250 void setValue(const LLString& name, const LLSD& val);
251
252 BOOL controlExists(const LLString& name);
253
254 // Returns number of controls loaded, 0 if failed
255 // If require_declaration is false, will auto-declare controls it finds
256 // as the given type.
257 U32 loadFromFileLegacy(const LLString& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING);
258 U32 loadFromFile(const LLString& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING);
259 U32 saveToFile(const LLString& filename, BOOL skip_if_default);
260 void applyOverrides(const std::map<std::string, std::string>& overrides);
261 void resetToDefaults();
262
263 // Ignorable Warnings
264
265 // Add a config variable to be reset on resetWarnings()
266 void addWarning(const LLString& name);
267 BOOL getWarning(const LLString& name);
268 void setWarning(const LLString& name, BOOL val);
269
270 // Resets all ignorables
271 void resetWarnings();
272};
273
274#endif
diff --git a/linden/indra/llxml/llxml.vcproj b/linden/indra/llxml/llxml.vcproj
new file mode 100644
index 0000000..2c1d266
--- /dev/null
+++ b/linden/indra/llxml/llxml.vcproj
@@ -0,0 +1,189 @@
1<?xml version="1.0" encoding="Windows-1252"?>
2<VisualStudioProject
3 ProjectType="Visual C++"
4 Version="7.10"
5 Name="llxml"
6 ProjectGUID="{A5470DA6-0C3A-4602-B930-43DB25511A59}"
7 Keyword="Win32Proj">
8 <Platforms>
9 <Platform
10 Name="Win32"/>
11 </Platforms>
12 <Configurations>
13 <Configuration
14 Name="Debug|Win32"
15 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
16 IntermediateDirectory="Debug"
17 ConfigurationType="4"
18 CharacterSet="1">
19 <Tool
20 Name="VCCLCompilerTool"
21 Optimization="0"
22 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\..\libraries\i686-win32\include;..\..\libraries\include\"
23 PreprocessorDefinitions="WIN32;_DEBUG;_LIB;LL_WINDOWS;LL_DEBUG"
24 MinimalRebuild="TRUE"
25 BasicRuntimeChecks="3"
26 RuntimeLibrary="1"
27 StructMemberAlignment="4"
28 ForceConformanceInForLoopScope="TRUE"
29 UsePrecompiledHeader="0"
30 WarningLevel="3"
31 WarnAsError="TRUE"
32 Detect64BitPortabilityProblems="FALSE"
33 DebugInformationFormat="4"/>
34 <Tool
35 Name="VCCustomBuildTool"/>
36 <Tool
37 Name="VCLibrarianTool"
38 OutputFile="$(OutDir)/llxml.lib"/>
39 <Tool
40 Name="VCMIDLTool"/>
41 <Tool
42 Name="VCPostBuildEventTool"/>
43 <Tool
44 Name="VCPreBuildEventTool"/>
45 <Tool
46 Name="VCPreLinkEventTool"/>
47 <Tool
48 Name="VCResourceCompilerTool"/>
49 <Tool
50 Name="VCWebServiceProxyGeneratorTool"/>
51 <Tool
52 Name="VCXMLDataGeneratorTool"/>
53 <Tool
54 Name="VCManagedWrapperGeneratorTool"/>
55 <Tool
56 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
57 </Configuration>
58 <Configuration
59 Name="Release|Win32"
60 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
61 IntermediateDirectory="Release"
62 ConfigurationType="4"
63 CharacterSet="1">
64 <Tool
65 Name="VCCLCompilerTool"
66 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\..\libraries\i686-win32\include;..\..\libraries\include\"
67 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE"
68 RuntimeLibrary="0"
69 StructMemberAlignment="0"
70 ForceConformanceInForLoopScope="TRUE"
71 UsePrecompiledHeader="0"
72 WarningLevel="3"
73 WarnAsError="TRUE"
74 Detect64BitPortabilityProblems="FALSE"
75 DebugInformationFormat="3"/>
76 <Tool
77 Name="VCCustomBuildTool"/>
78 <Tool
79 Name="VCLibrarianTool"
80 OutputFile="$(OutDir)/llxml.lib"/>
81 <Tool
82 Name="VCMIDLTool"/>
83 <Tool
84 Name="VCPostBuildEventTool"/>
85 <Tool
86 Name="VCPreBuildEventTool"/>
87 <Tool
88 Name="VCPreLinkEventTool"/>
89 <Tool
90 Name="VCResourceCompilerTool"/>
91 <Tool
92 Name="VCWebServiceProxyGeneratorTool"/>
93 <Tool
94 Name="VCXMLDataGeneratorTool"/>
95 <Tool
96 Name="VCManagedWrapperGeneratorTool"/>
97 <Tool
98 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
99 </Configuration>
100 <Configuration
101 Name="ReleaseNoOpt|Win32"
102 OutputDirectory="../lib_$(ConfigurationName)/i686-win32"
103 IntermediateDirectory="$(ConfigurationName)"
104 ConfigurationType="4"
105 CharacterSet="1">
106 <Tool
107 Name="VCCLCompilerTool"
108 Optimization="0"
109 AdditionalIncludeDirectories="..\llcommon;..\llmath;..\..\libraries\i686-win32\include;..\..\libraries\include\"
110 PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE"
111 RuntimeLibrary="0"
112 StructMemberAlignment="0"
113 ForceConformanceInForLoopScope="TRUE"
114 UsePrecompiledHeader="0"
115 WarningLevel="3"
116 WarnAsError="TRUE"
117 Detect64BitPortabilityProblems="FALSE"
118 DebugInformationFormat="3"/>
119 <Tool
120 Name="VCCustomBuildTool"/>
121 <Tool
122 Name="VCLibrarianTool"
123 OutputFile="$(OutDir)/llxml.lib"/>
124 <Tool
125 Name="VCMIDLTool"/>
126 <Tool
127 Name="VCPostBuildEventTool"/>
128 <Tool
129 Name="VCPreBuildEventTool"/>
130 <Tool
131 Name="VCPreLinkEventTool"/>
132 <Tool
133 Name="VCResourceCompilerTool"/>
134 <Tool
135 Name="VCWebServiceProxyGeneratorTool"/>
136 <Tool
137 Name="VCXMLDataGeneratorTool"/>
138 <Tool
139 Name="VCManagedWrapperGeneratorTool"/>
140 <Tool
141 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
142 </Configuration>
143 </Configurations>
144 <References>
145 </References>
146 <Files>
147 <Filter
148 Name="Source Files"
149 Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
150 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
151 <File
152 RelativePath=".\llcontrol.cpp">
153 </File>
154 <File
155 RelativePath=".\llxmlnode.cpp">
156 </File>
157 <File
158 RelativePath=".\llxmlparser.cpp">
159 </File>
160 <File
161 RelativePath=".\llxmltree.cpp">
162 </File>
163 </Filter>
164 <Filter
165 Name="Header Files"
166 Filter="h;hpp;hxx;hm;inl;inc;xsd"
167 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
168 <File
169 RelativePath=".\llcontrol.h">
170 </File>
171 <File
172 RelativePath=".\llxmlnode.h">
173 </File>
174 <File
175 RelativePath=".\llxmlparser.h">
176 </File>
177 <File
178 RelativePath=".\llxmltree.h">
179 </File>
180 </Filter>
181 <Filter
182 Name="Resource Files"
183 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
184 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
185 </Filter>
186 </Files>
187 <Globals>
188 </Globals>
189</VisualStudioProject>
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}
diff --git a/linden/indra/llxml/llxmlnode.h b/linden/indra/llxml/llxmlnode.h
new file mode 100644
index 0000000..6ecd9ce
--- /dev/null
+++ b/linden/indra/llxml/llxmlnode.h
@@ -0,0 +1,285 @@
1/**
2 * @file llxmlnode.h
3 * @brief LLXMLNode definition
4 *
5 * Copyright (c) 2000-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLXMLNODE_H
29#define LL_LLXMLNODE_H
30
31#define XML_STATIC
32#include "expat/expat.h"
33#include <map>
34
35#include "indra_constants.h"
36#include "llmemory.h"
37#include "llstring.h"
38#include "llstringtable.h"
39
40
41
42struct CompareAttributes
43{
44 bool operator()(const LLStringTableEntry* const lhs, const LLStringTableEntry* const rhs) const
45 {
46 if (lhs == NULL)
47 return TRUE;
48 if (rhs == NULL)
49 return FALSE;
50
51 return strcmp(lhs->mString, rhs->mString) < 0;
52 }
53};
54
55
56// Defines a simple node hierarchy for reading and writing task objects
57
58class LLXMLNode;
59typedef LLPointer<LLXMLNode> LLXMLNodePtr;
60typedef std::multimap<LLString, LLXMLNodePtr > LLXMLNodeList;
61typedef std::multimap<const LLStringTableEntry *, LLXMLNodePtr > LLXMLChildList;
62typedef std::map<const LLStringTableEntry *, LLXMLNodePtr, CompareAttributes> LLXMLAttribList;
63
64struct LLXMLChildren
65{
66 LLXMLChildList map; // Map of children names->pointers
67 LLXMLNodePtr head; // Head of the double-linked list
68 LLXMLNodePtr tail; // Tail of the double-linked list
69};
70
71class LLXMLNode : public LLThreadSafeRefCount
72{
73public:
74 enum ValueType
75 {
76 TYPE_CONTAINER, // A node which contains nodes
77 TYPE_UNKNOWN, // A node loaded from file without a specified type
78 TYPE_BOOLEAN, // "true" or "false"
79 TYPE_INTEGER, // any integer type: U8, U32, S32, U64, etc.
80 TYPE_FLOAT, // any floating point type: F32, F64
81 TYPE_STRING, // a string
82 TYPE_UUID, // a UUID
83 TYPE_NODEREF, // the ID of another node in the hierarchy to reference
84 };
85
86 enum Encoding
87 {
88 ENCODING_DEFAULT = 0,
89 ENCODING_DECIMAL,
90 ENCODING_HEX,
91 // ENCODING_BASE32, // Not implemented yet
92 };
93
94protected:
95 virtual ~LLXMLNode();
96
97public:
98 LLXMLNode();
99 LLXMLNode(const LLString& name, BOOL is_attribute);
100 LLXMLNode(LLStringTableEntry* name, BOOL is_attribute);
101
102 BOOL isNull();
103
104 BOOL deleteChild(LLXMLNode* child);
105 void addChild(LLXMLNodePtr new_parent);
106 void setParent(LLXMLNodePtr new_parent); // reparent if necessary
107
108 // Serialization
109 static bool parseFile(
110 LLString filename,
111 LLXMLNodePtr& node,
112 LLXMLNode* defaults_tree);
113 static bool parseBuffer(
114 U8* buffer,
115 U32 length,
116 LLXMLNodePtr& node,
117 LLXMLNode* defaults);
118 static bool updateNode(
119 LLXMLNodePtr& node,
120 LLXMLNodePtr& update_node);
121 static void writeHeaderToFile(FILE *fOut);
122 void writeToFile(FILE *fOut, LLString indent = "");
123 void writeToOstream(std::ostream& output_stream, const LLString& indent = "");
124
125 // Utility
126 void findName(const LLString& name, LLXMLNodeList &results);
127 void findName(LLStringTableEntry* name, LLXMLNodeList &results);
128 void findID(const LLString& id, LLXMLNodeList &results);
129
130
131 virtual LLXMLNodePtr createChild(const LLString& name, BOOL is_attribute);
132 virtual LLXMLNodePtr createChild(LLStringTableEntry* name, BOOL is_attribute);
133
134
135 // Getters
136 U32 getBoolValue(U32 expected_length, BOOL *array);
137 U32 getByteValue(U32 expected_length, U8 *array, Encoding encoding = ENCODING_DEFAULT);
138 U32 getIntValue(U32 expected_length, S32 *array, Encoding encoding = ENCODING_DEFAULT);
139 U32 getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding = ENCODING_DEFAULT);
140 U32 getLongValue(U32 expected_length, U64 *array, Encoding encoding = ENCODING_DEFAULT);
141 U32 getFloatValue(U32 expected_length, F32 *array, Encoding encoding = ENCODING_DEFAULT);
142 U32 getDoubleValue(U32 expected_length, F64 *array, Encoding encoding = ENCODING_DEFAULT);
143 U32 getStringValue(U32 expected_length, LLString *array);
144 U32 getUUIDValue(U32 expected_length, LLUUID *array);
145 U32 getNodeRefValue(U32 expected_length, LLXMLNode **array);
146
147 BOOL hasAttribute(const LLString& name );
148
149 BOOL getAttributeBOOL(const LLString& name, BOOL& value );
150 BOOL getAttributeU8(const LLString& name, U8& value );
151 BOOL getAttributeS8(const LLString& name, S8& value );
152 BOOL getAttributeU16(const LLString& name, U16& value );
153 BOOL getAttributeS16(const LLString& name, S16& value );
154 BOOL getAttributeU32(const LLString& name, U32& value );
155 BOOL getAttributeS32(const LLString& name, S32& value );
156 BOOL getAttributeF32(const LLString& name, F32& value );
157 BOOL getAttributeF64(const LLString& name, F64& value );
158 BOOL getAttributeColor(const LLString& name, LLColor4& value );
159 BOOL getAttributeColor4(const LLString& name, LLColor4& value );
160 BOOL getAttributeColor4U(const LLString& name, LLColor4U& value );
161 BOOL getAttributeVector3(const LLString& name, LLVector3& value );
162 BOOL getAttributeVector3d(const LLString& name, LLVector3d& value );
163 BOOL getAttributeQuat(const LLString& name, LLQuaternion& value );
164 BOOL getAttributeUUID(const LLString& name, LLUUID& value );
165 BOOL getAttributeString(const LLString& name, LLString& value );
166
167 const ValueType& getType() const { return mType; }
168 const U32 getLength() const { return mLength; }
169 const U32 getPrecision() const { return mPrecision; }
170 const LLString& getValue() const { return mValue; }
171 LLString getTextContents() const;
172 const LLStringTableEntry* getName() const { return mName; }
173 const BOOL hasName(LLString name) const { return mName == gStringTable.checkStringEntry(name); }
174 const LLString& getID() const { return mID; }
175
176 U32 getChildCount() const;
177 // getChild returns a Null LLXMLNode (not a NULL pointer) if there is no such child.
178 // This child has no value so any getTYPEValue() calls on it will return 0.
179 bool getChild(const LLString& name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
180 bool getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
181 void getChildren(const LLString& name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const;
182 void getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const;
183
184 bool getAttribute(const LLString& name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
185 bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
186
187 // The following skip over attributes
188 LLXMLNodePtr getFirstChild();
189 LLXMLNodePtr getNextSibling();
190
191 LLXMLNodePtr getRoot();
192
193 // Setters
194
195 bool setAttributeString(const LLString& attr, const LLString& value);
196
197 void setBoolValue(const BOOL value) { setBoolValue(1, &value); }
198 void setByteValue(const U8 value, Encoding encoding = ENCODING_DEFAULT) { setByteValue(1, &value, encoding); }
199 void setIntValue(const S32 value, Encoding encoding = ENCODING_DEFAULT) { setIntValue(1, &value, encoding); }
200 void setUnsignedValue(const U32 value, Encoding encoding = ENCODING_DEFAULT) { setUnsignedValue(1, &value, encoding); }
201 void setLongValue(const U64 value, Encoding encoding = ENCODING_DEFAULT) { setLongValue(1, &value, encoding); }
202 void setFloatValue(const F32 value, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0) { setFloatValue(1, &value, encoding); }
203 void setDoubleValue(const F64 value, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0) { setDoubleValue(1, &value, encoding); }
204 void setStringValue(const LLString value) { setStringValue(1, &value); }
205 void setUUIDValue(const LLUUID value) { setUUIDValue(1, &value); }
206 void setNodeRefValue(const LLXMLNode *value) { setNodeRefValue(1, &value); }
207
208 void setBoolValue(U32 length, const BOOL *array);
209 void setByteValue(U32 length, const U8 *array, Encoding encoding = ENCODING_DEFAULT);
210 void setIntValue(U32 length, const S32 *array, Encoding encoding = ENCODING_DEFAULT);
211 void setUnsignedValue(U32 length, const U32* array, Encoding encoding = ENCODING_DEFAULT);
212 void setLongValue(U32 length, const U64 *array, Encoding encoding = ENCODING_DEFAULT);
213 void setFloatValue(U32 length, const F32 *array, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0);
214 void setDoubleValue(U32 length, const F64 *array, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0);
215 void setStringValue(U32 length, const LLString *array);
216 void setUUIDValue(U32 length, const LLUUID *array);
217 void setNodeRefValue(U32 length, const LLXMLNode **array);
218 void setValue(const LLString& value);
219 void setName(const LLString& name);
220 void setName(LLStringTableEntry* name);
221
222 // Escapes " (quot) ' (apos) & (amp) < (lt) > (gt)
223 // TomY TODO: Make this private
224 static LLString escapeXML(const LLString& xml);
225
226 // Set the default node corresponding to this default node
227 void setDefault(LLXMLNode *default_node);
228
229 // Find the node within defaults_list which corresponds to this node
230 void findDefault(LLXMLNode *defaults_list);
231
232 void updateDefault();
233
234 // Delete any child nodes that aren't among the tree's children, recursive
235 void scrubToTree(LLXMLNode *tree);
236
237 BOOL deleteChildren(const LLString& name);
238 BOOL deleteChildren(LLStringTableEntry* name);
239 void setAttributes(ValueType type, U32 precision, Encoding encoding, U32 length);
240 void appendValue(const LLString& value);
241
242 // Unit Testing
243 void createUnitTest(S32 max_num_children);
244 BOOL performUnitTest(LLString &error_buffer);
245
246protected:
247 BOOL removeChild(LLXMLNode* child);
248
249public:
250 LLString mID; // The ID attribute of this node
251
252 XML_Parser *mParser; // Temporary pointer while loading
253
254 BOOL mIsAttribute; // Flag is only used for output formatting
255 U32 mVersionMajor; // Version of this tag to use
256 U32 mVersionMinor;
257 U32 mLength; // If the length is nonzero, then only return arrays of this length
258 U32 mPrecision; // The number of BITS per array item
259 ValueType mType; // The value type
260 Encoding mEncoding; // The value encoding
261
262 LLXMLNode* mParent; // The parent node
263 LLXMLChildren* mChildren; // The child nodes
264 LLXMLAttribList mAttributes; // The attribute nodes
265 LLXMLNodePtr mPrev; // Double-linked list previous node
266 LLXMLNodePtr mNext; // Double-linked list next node
267
268 static BOOL sStripEscapedStrings;
269 static BOOL sStripWhitespaceValues;
270
271protected:
272 LLStringTableEntry *mName; // The name of this node
273 LLString mValue; // The value of this node (use getters/setters only)
274
275 LLXMLNodePtr mDefault; // Mirror node in the default tree
276
277 static const char *skipWhitespace(const char *str);
278 static const char *skipNonWhitespace(const char *str);
279 static const char *parseInteger(const char *str, U64 *dest, BOOL *is_negative, U32 precision, Encoding encoding);
280 static const char *parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding);
281
282 BOOL isFullyDefault();
283};
284
285#endif // LL_LLXMLNODE
diff --git a/linden/indra/llxml/llxmlparser.cpp b/linden/indra/llxml/llxmlparser.cpp
new file mode 100644
index 0000000..57e6a30
--- /dev/null
+++ b/linden/indra/llxml/llxmlparser.cpp
@@ -0,0 +1,417 @@
1/**
2 * @file llxmlparser.cpp
3 * @brief LLXmlParser implementation
4 *
5 * Copyright (c) 2002-2007`, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28// llxmlparser.cpp
29//
30// copyright 2002, linden research inc
31
32
33#include "linden_common.h"
34
35#include "llxmlparser.h"
36#include "llerror.h"
37
38
39LLXmlParser::LLXmlParser()
40 :
41 mParser( NULL ),
42 mDepth( 0 )
43{
44 strcpy( mAuxErrorString, "no error" );
45
46 // Override the document's declared encoding.
47 mParser = XML_ParserCreate(NULL);
48
49 XML_SetUserData(mParser, this);
50 XML_SetElementHandler( mParser, startElementHandler, endElementHandler);
51 XML_SetCharacterDataHandler( mParser, characterDataHandler);
52 XML_SetProcessingInstructionHandler( mParser, processingInstructionHandler);
53 XML_SetCommentHandler( mParser, commentHandler);
54
55 XML_SetCdataSectionHandler( mParser, startCdataSectionHandler, endCdataSectionHandler);
56
57 // This sets the default handler but does not inhibit expansion of internal entities.
58 // The entity reference will not be passed to the default handler.
59 XML_SetDefaultHandlerExpand( mParser, defaultDataHandler);
60
61 XML_SetUnparsedEntityDeclHandler( mParser, unparsedEntityDeclHandler);
62}
63
64LLXmlParser::~LLXmlParser()
65{
66 XML_ParserFree( mParser );
67}
68
69
70BOOL LLXmlParser::parseFile(const std::string &path)
71{
72 llassert( !mDepth );
73
74 BOOL success = TRUE;
75
76 FILE *file = LLFile::fopen(path.c_str(), "rb");
77 if( !file )
78 {
79 sprintf( mAuxErrorString, "Couldn't open file %s", path.c_str());
80 success = FALSE;
81 }
82 else
83 {
84 S32 bytes_read = 0;
85
86 fseek(file, 0L, SEEK_END);
87 S32 buffer_size = ftell(file);
88 fseek(file, 0L, SEEK_SET);
89
90 void* buffer = XML_GetBuffer(mParser, buffer_size);
91 if( !buffer )
92 {
93 sprintf( mAuxErrorString, "Unable to allocate XML buffer while reading file %s", path.c_str() );
94 success = FALSE;
95 goto exit_label;
96 }
97
98 bytes_read = (S32)fread(buffer, 1, buffer_size, file);
99 if( bytes_read <= 0 )
100 {
101 sprintf( mAuxErrorString, "Error while reading file %s", path.c_str() );
102 success = FALSE;
103 goto exit_label;
104 }
105
106 if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) )
107 {
108 sprintf( mAuxErrorString, "Error while parsing file %s", path.c_str() );
109 success = FALSE;
110 }
111
112exit_label:
113 fclose( file );
114 }
115
116
117 if( success )
118 {
119 llassert( !mDepth );
120 }
121 mDepth = 0;
122
123 if( !success )
124 {
125 llwarns << mAuxErrorString << llendl;
126 }
127
128 return success;
129}
130
131
132// Parses some input. Returns 0 if a fatal error is detected.
133// The last call must have isFinal true;
134// len may be zero for this call (or any other).
135S32 LLXmlParser::parse( const char* buf, int len, int isFinal )
136{
137 return XML_Parse(mParser, buf, len, isFinal);
138}
139
140const char* LLXmlParser::getErrorString()
141{
142 const char* error_string = XML_ErrorString(XML_GetErrorCode( mParser ));
143 if( !error_string )
144 {
145 error_string = mAuxErrorString;
146 }
147 return error_string;
148}
149
150S32 LLXmlParser::getCurrentLineNumber()
151{
152 return XML_GetCurrentLineNumber( mParser );
153}
154
155S32 LLXmlParser::getCurrentColumnNumber()
156{
157 return XML_GetCurrentColumnNumber(mParser);
158}
159
160///////////////////////////////////////////////////////////////////////////////
161// Pseudo-private methods. These are only used by internal callbacks.
162
163// static
164void LLXmlParser::startElementHandler(
165 void *userData,
166 const XML_Char *name,
167 const XML_Char **atts)
168{
169 LLXmlParser* self = (LLXmlParser*) userData;
170 self->startElement( name, atts );
171 self->mDepth++;
172}
173
174// static
175void LLXmlParser::endElementHandler(
176 void *userData,
177 const XML_Char *name)
178{
179 LLXmlParser* self = (LLXmlParser*) userData;
180 self->mDepth--;
181 self->endElement( name );
182}
183
184// s is not 0 terminated.
185// static
186void LLXmlParser::characterDataHandler(
187 void *userData,
188 const XML_Char *s,
189 int len)
190{
191 LLXmlParser* self = (LLXmlParser*) userData;
192 self->characterData( s, len );
193}
194
195// target and data are 0 terminated
196// static
197void LLXmlParser::processingInstructionHandler(
198 void *userData,
199 const XML_Char *target,
200 const XML_Char *data)
201{
202 LLXmlParser* self = (LLXmlParser*) userData;
203 self->processingInstruction( target, data );
204}
205
206// data is 0 terminated
207// static
208void LLXmlParser::commentHandler(void *userData, const XML_Char *data)
209{
210 LLXmlParser* self = (LLXmlParser*) userData;
211 self->comment( data );
212}
213
214// static
215void LLXmlParser::startCdataSectionHandler(void *userData)
216{
217 LLXmlParser* self = (LLXmlParser*) userData;
218 self->mDepth++;
219 self->startCdataSection();
220}
221
222// static
223void LLXmlParser::endCdataSectionHandler(void *userData)
224{
225 LLXmlParser* self = (LLXmlParser*) userData;
226 self->endCdataSection();
227 self->mDepth++;
228}
229
230// This is called for any characters in the XML document for
231// which there is no applicable handler. This includes both
232// characters that are part of markup which is of a kind that is
233// not reported (comments, markup declarations), or characters
234// that are part of a construct which could be reported but
235// for which no handler has been supplied. The characters are passed
236// exactly as they were in the XML document except that
237// they will be encoded in UTF-8. Line boundaries are not normalized.
238// Note that a byte order mark character is not passed to the default handler.
239// There are no guarantees about how characters are divided between calls
240// to the default handler: for example, a comment might be split between
241// multiple calls.
242
243// static
244void LLXmlParser::defaultDataHandler(
245 void *userData,
246 const XML_Char *s,
247 int len)
248{
249 LLXmlParser* self = (LLXmlParser*) userData;
250 self->defaultData( s, len );
251}
252
253// This is called for a declaration of an unparsed (NDATA)
254// entity. The base argument is whatever was set by XML_SetBase.
255// The entityName, systemId and notationName arguments will never be null.
256// The other arguments may be.
257// static
258void LLXmlParser::unparsedEntityDeclHandler(
259 void *userData,
260 const XML_Char *entityName,
261 const XML_Char *base,
262 const XML_Char *systemId,
263 const XML_Char *publicId,
264 const XML_Char *notationName)
265{
266 LLXmlParser* self = (LLXmlParser*) userData;
267 self->unparsedEntityDecl( entityName, base, systemId, publicId, notationName );
268}
269
270
271
272
273////////////////////////////////////////////////////////////////////
274// Test code.
275
276/*
277class LLXmlDOMParser : public LLXmlParser
278{
279public:
280
281 LLXmlDOMParser() {}
282 virtual ~LLXmlDOMParser() {}
283
284 void tabs()
285 {
286 for ( int i = 0; i < getDepth(); i++)
287 {
288 putchar(' ');
289 }
290 }
291
292 virtual void startElement(const char *name, const char **atts)
293 {
294 tabs();
295 printf("startElement %s\n", name);
296
297 S32 i = 0;
298 while( atts[i] && atts[i+1] )
299 {
300 tabs();
301 printf( "\t%s=%s\n", atts[i], atts[i+1] );
302 i += 2;
303 }
304
305 if( atts[i] )
306 {
307 tabs();
308 printf( "\ttrailing attribute: %s\n", atts[i] );
309 }
310 }
311
312 virtual void endElement(const char *name)
313 {
314 tabs();
315 printf("endElement %s\n", name);
316 }
317
318 virtual void characterData(const char *s, int len)
319 {
320 tabs();
321
322 char* str = new char[len+1];
323 strncpy( str, s, len );
324 str[len] = '\0';
325 printf("CharacterData %s\n", str);
326 delete str;
327 }
328
329 virtual void processingInstruction(const char *target, const char *data)
330 {
331 tabs();
332 printf("processingInstruction %s\n", data);
333 }
334 virtual void comment(const char *data)
335 {
336 tabs();
337 printf("comment %s\n", data);
338 }
339
340 virtual void startCdataSection()
341 {
342 tabs();
343 printf("startCdataSection\n");
344 }
345
346 virtual void endCdataSection()
347 {
348 tabs();
349 printf("endCdataSection\n");
350 }
351
352 virtual void defaultData(const char *s, int len)
353 {
354 tabs();
355
356 char* str = new char[len+1];
357 strncpy( str, s, len );
358 str[len] = '\0';
359 printf("defaultData %s\n", str);
360 delete str;
361 }
362
363 virtual void unparsedEntityDecl(
364 const char *entityName,
365 const char *base,
366 const char *systemId,
367 const char *publicId,
368 const char *notationName)
369 {
370 tabs();
371
372 printf(
373 "unparsed entity:\n"
374 "\tentityName %s\n"
375 "\tbase %s\n"
376 "\tsystemId %s\n"
377 "\tpublicId %s\n"
378 "\tnotationName %s\n",
379 entityName,
380 base,
381 systemId,
382 publicId,
383 notationName );
384 }
385};
386
387
388int main()
389{
390 char buf[1024];
391
392 FILE* file = LLFile::fopen("test.xml", "rb");
393 if( !file )
394 {
395 return 1;
396 }
397
398 LLXmlDOMParser parser;
399 int done;
400 do {
401 size_t len = fread(buf, 1, sizeof(buf), file);
402 done = len < sizeof(buf);
403 if( 0 == parser.parse( buf, len, done) )
404 {
405 fprintf(stderr,
406 "%s at line %d\n",
407 parser.getErrorString(),
408 parser.getCurrentLineNumber() );
409 return 1;
410 }
411 } while (!done);
412
413 fclose( file );
414 return 0;
415}
416*/
417
diff --git a/linden/indra/llxml/llxmlparser.h b/linden/indra/llxml/llxmlparser.h
new file mode 100644
index 0000000..27c137a
--- /dev/null
+++ b/linden/indra/llxml/llxmlparser.h
@@ -0,0 +1,128 @@
1/**
2 * @file llxmlparser.h
3 * @brief LLXmlParser class definition
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#ifndef LL_LLXMLPARSER_H
29#define LL_LLXMLPARSER_H
30
31#define XML_STATIC
32#include "expat/expat.h"
33
34class LLXmlParser
35{
36public:
37 LLXmlParser();
38 virtual ~LLXmlParser();
39
40 // Parses entire file
41 BOOL parseFile(const std::string &path);
42
43 // Parses some input. Returns 0 if a fatal error is detected.
44 // The last call must have isFinal true;
45 // len may be zero for this call (or any other).
46 S32 parse( const char* buf, int len, int isFinal );
47
48 const char* getErrorString();
49
50 S32 getCurrentLineNumber();
51
52 S32 getCurrentColumnNumber();
53
54 S32 getDepth() { return mDepth; }
55
56protected:
57 // atts is array of name/value pairs, terminated by 0;
58 // names and values are 0 terminated.
59 virtual void startElement(const char *name, const char **atts) {}
60
61 virtual void endElement(const char *name) {}
62
63 // s is not 0 terminated.
64 virtual void characterData(const char *s, int len) {}
65
66 // target and data are 0 terminated
67 virtual void processingInstruction(const char *target, const char *data) {}
68
69 // data is 0 terminated
70 virtual void comment(const char *data) {}
71
72 virtual void startCdataSection() {}
73
74 virtual void endCdataSection() {}
75
76 // This is called for any characters in the XML document for
77 // which there is no applicable handler. This includes both
78 // characters that are part of markup which is of a kind that is
79 // not reported (comments, markup declarations), or characters
80 // that are part of a construct which could be reported but
81 // for which no handler has been supplied. The characters are passed
82 // exactly as they were in the XML document except that
83 // they will be encoded in UTF-8. Line boundaries are not normalized.
84 // Note that a byte order mark character is not passed to the default handler.
85 // There are no guarantees about how characters are divided between calls
86 // to the default handler: for example, a comment might be split between
87 // multiple calls.
88 virtual void defaultData(const char *s, int len) {}
89
90 // This is called for a declaration of an unparsed (NDATA)
91 // entity. The base argument is whatever was set by XML_SetBase.
92 // The entityName, systemId and notationName arguments will never be null.
93 // The other arguments may be.
94 virtual void unparsedEntityDecl(
95 const char *entityName,
96 const char *base,
97 const char *systemId,
98 const char *publicId,
99 const char *notationName) {}
100
101public:
102 ///////////////////////////////////////////////////////////////////////////////
103 // Pseudo-private methods. These are only used by internal callbacks.
104
105 static void startElementHandler(void *userData, const XML_Char *name, const XML_Char **atts);
106 static void endElementHandler(void *userData, const XML_Char *name);
107 static void characterDataHandler(void *userData, const XML_Char *s, int len);
108 static void processingInstructionHandler(void *userData, const XML_Char *target, const XML_Char *data);
109 static void commentHandler(void *userData, const XML_Char *data);
110 static void startCdataSectionHandler(void *userData);
111 static void endCdataSectionHandler(void *userData);
112 static void defaultDataHandler( void *userData, const XML_Char *s, int len);
113 static void unparsedEntityDeclHandler(
114 void *userData,
115 const XML_Char *entityName,
116 const XML_Char *base,
117 const XML_Char *systemId,
118 const XML_Char *publicId,
119 const XML_Char *notationName);
120
121
122protected:
123 XML_Parser mParser;
124 int mDepth;
125 char mAuxErrorString[1024];
126};
127
128#endif // LL_LLXMLPARSER_H
diff --git a/linden/indra/llxml/llxmltree.cpp b/linden/indra/llxml/llxmltree.cpp
new file mode 100644
index 0000000..2b6a6a1
--- /dev/null
+++ b/linden/indra/llxml/llxmltree.cpp
@@ -0,0 +1,690 @@
1/**
2 * @file llxmltree.cpp
3 * @brief LLXmlTree implementation
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "linden_common.h"
29
30#include "llxmltree.h"
31#include "v3color.h"
32#include "v4color.h"
33#include "v4coloru.h"
34#include "v3math.h"
35#include "v3dmath.h"
36#include "v4math.h"
37#include "llquaternion.h"
38#include "lluuid.h"
39
40//////////////////////////////////////////////////////////////
41// LLXmlTree
42
43// static
44LLStdStringTable LLXmlTree::sAttributeKeys(1024);
45
46LLXmlTree::LLXmlTree()
47 : mRoot( NULL ),
48 mNodeNames(512)
49{
50}
51
52LLXmlTree::~LLXmlTree()
53{
54 cleanup();
55}
56
57void LLXmlTree::cleanup()
58{
59 delete mRoot;
60 mRoot = NULL;
61 mNodeNames.cleanup();
62}
63
64
65BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents)
66{
67 delete mRoot;
68 mRoot = NULL;
69
70 LLXmlTreeParser parser(this);
71 BOOL success = parser.parseFile( path, &mRoot, keep_contents );
72 if( !success )
73 {
74 S32 line_number = parser.getCurrentLineNumber();
75 const char* error = parser.getErrorString();
76 llwarns << "LLXmlTree parse failed. Line " << line_number << ": " << error << llendl;
77 }
78 return success;
79}
80
81void LLXmlTree::dump()
82{
83 if( mRoot )
84 {
85 dumpNode( mRoot, " " );
86 }
87}
88
89void LLXmlTree::dumpNode( LLXmlTreeNode* node, const LLString& prefix )
90{
91 node->dump( prefix );
92
93 LLString new_prefix = prefix + " ";
94 for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() )
95 {
96 dumpNode( child, new_prefix );
97 }
98}
99
100//////////////////////////////////////////////////////////////
101// LLXmlTreeNode
102
103LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree )
104 : mName(name),
105 mParent(parent),
106 mTree(tree)
107{
108}
109
110LLXmlTreeNode::~LLXmlTreeNode()
111{
112 attribute_map_t::iterator iter;
113 for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
114 delete iter->second;
115 child_list_t::iterator child_iter;
116 for (child_iter=mChildList.begin(); child_iter != mChildList.end(); child_iter++)
117 delete *child_iter;
118}
119
120void LLXmlTreeNode::dump( const LLString& prefix )
121{
122 llinfos << prefix << mName ;
123 if( !mContents.empty() )
124 {
125 llcont << " contents = \"" << mContents << "\"";
126 }
127 attribute_map_t::iterator iter;
128 for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
129 {
130 LLStdStringHandle key = iter->first;
131 const LLString* value = iter->second;
132 llcont << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value);
133 }
134 llcont << llendl;
135}
136
137BOOL LLXmlTreeNode::hasAttribute(const std::string& name)
138{
139 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
140 attribute_map_t::iterator iter = mAttributes.find(canonical_name);
141 return (iter == mAttributes.end()) ? false : true;
142}
143
144void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& value)
145{
146 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
147 const LLString *newstr = new LLString(value);
148 mAttributes[canonical_name] = newstr; // insert + copy
149}
150
151LLXmlTreeNode* LLXmlTreeNode::getFirstChild()
152{
153 mChildListIter = mChildList.begin();
154 return getNextChild();
155}
156LLXmlTreeNode* LLXmlTreeNode::getNextChild()
157{
158 if (mChildListIter == mChildList.end())
159 return 0;
160 else
161 return *mChildListIter++;
162}
163
164LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name)
165{
166 LLStdStringHandle tableptr = mTree->mNodeNames.checkString(name);
167 mChildMapIter = mChildMap.lower_bound(tableptr);
168 mChildMapEndIter = mChildMap.upper_bound(tableptr);
169 return getNextNamedChild();
170}
171
172LLXmlTreeNode* LLXmlTreeNode::getNextNamedChild()
173{
174 if (mChildMapIter == mChildMapEndIter)
175 return NULL;
176 else
177 return (mChildMapIter++)->second;
178}
179
180void LLXmlTreeNode::appendContents(const std::string& str)
181{
182 mContents.append( str );
183}
184
185void LLXmlTreeNode::addChild(LLXmlTreeNode* child)
186{
187 llassert( child );
188 mChildList.push_back( child );
189
190 // Add a name mapping to this node
191 LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName);
192 mChildMap.insert( child_map_t::value_type(tableptr, child));
193
194 child->mParent = this;
195}
196
197//////////////////////////////////////////////////////////////
198
199// These functions assume that name is already in mAttritrubteKeys
200
201BOOL LLXmlTreeNode::getFastAttributeBOOL(LLStdStringHandle canonical_name, BOOL& value)
202{
203 const LLString *s = getAttribute( canonical_name );
204 return s && LLString::convertToBOOL( *s, value );
205}
206
207BOOL LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value)
208{
209 const LLString *s = getAttribute( canonical_name );
210 return s && LLString::convertToU8( *s, value );
211}
212
213BOOL LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value)
214{
215 const LLString *s = getAttribute( canonical_name );
216 return s && LLString::convertToS8( *s, value );
217}
218
219BOOL LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value)
220{
221 const LLString *s = getAttribute( canonical_name );
222 return s && LLString::convertToS16( *s, value );
223}
224
225BOOL LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value)
226{
227 const LLString *s = getAttribute( canonical_name );
228 return s && LLString::convertToU16( *s, value );
229}
230
231BOOL LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value)
232{
233 const LLString *s = getAttribute( canonical_name );
234 return s && LLString::convertToU32( *s, value );
235}
236
237BOOL LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value)
238{
239 const LLString *s = getAttribute( canonical_name );
240 return s && LLString::convertToS32( *s, value );
241}
242
243BOOL LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value)
244{
245 const LLString *s = getAttribute( canonical_name );
246 return s && LLString::convertToF32( *s, value );
247}
248
249BOOL LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value)
250{
251 const LLString *s = getAttribute( canonical_name );
252 return s && LLString::convertToF64( *s, value );
253}
254
255BOOL LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value)
256{
257 const LLString *s = getAttribute( canonical_name );
258 return s ? LLColor4::parseColor(s->c_str(), &value) : FALSE;
259}
260
261BOOL LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value)
262{
263 const LLString *s = getAttribute( canonical_name );
264 return s ? LLColor4::parseColor4(s->c_str(), &value) : FALSE;
265}
266
267BOOL LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value)
268{
269 const LLString *s = getAttribute( canonical_name );
270 return s ? LLColor4U::parseColor4U(s->c_str(), &value ) : FALSE;
271}
272
273BOOL LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value)
274{
275 const LLString *s = getAttribute( canonical_name );
276 return s ? LLVector3::parseVector3(s->c_str(), &value ) : FALSE;
277}
278
279BOOL LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value)
280{
281 const LLString *s = getAttribute( canonical_name );
282 return s ? LLVector3d::parseVector3d(s->c_str(), &value ) : FALSE;
283}
284
285BOOL LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value)
286{
287 const LLString *s = getAttribute( canonical_name );
288 return s ? LLQuaternion::parseQuat(s->c_str(), &value ) : FALSE;
289}
290
291BOOL LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value)
292{
293 const LLString *s = getAttribute( canonical_name );
294 return s ? LLUUID::parseUUID(s->c_str(), &value ) : FALSE;
295}
296
297BOOL LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, LLString& value)
298{
299 const LLString *s = getAttribute( canonical_name );
300 if( !s )
301 {
302 return FALSE;
303 }
304
305 value = *s;
306 return TRUE;
307}
308
309
310//////////////////////////////////////////////////////////////
311
312BOOL LLXmlTreeNode::getAttributeBOOL(const std::string& name, BOOL& value)
313{
314 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
315 return getFastAttributeBOOL(canonical_name, value);
316}
317
318BOOL LLXmlTreeNode::getAttributeU8(const std::string& name, U8& value)
319{
320 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
321 return getFastAttributeU8(canonical_name, value);
322}
323
324BOOL LLXmlTreeNode::getAttributeS8(const std::string& name, S8& value)
325{
326 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
327 return getFastAttributeS8(canonical_name, value);
328}
329
330BOOL LLXmlTreeNode::getAttributeS16(const std::string& name, S16& value)
331{
332 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
333 return getFastAttributeS16(canonical_name, value);
334}
335
336BOOL LLXmlTreeNode::getAttributeU16(const std::string& name, U16& value)
337{
338 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
339 return getFastAttributeU16(canonical_name, value);
340}
341
342BOOL LLXmlTreeNode::getAttributeU32(const std::string& name, U32& value)
343{
344 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
345 return getFastAttributeU32(canonical_name, value);
346}
347
348BOOL LLXmlTreeNode::getAttributeS32(const std::string& name, S32& value)
349{
350 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
351 return getFastAttributeS32(canonical_name, value);
352}
353
354BOOL LLXmlTreeNode::getAttributeF32(const std::string& name, F32& value)
355{
356 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
357 return getFastAttributeF32(canonical_name, value);
358}
359
360BOOL LLXmlTreeNode::getAttributeF64(const std::string& name, F64& value)
361{
362 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
363 return getFastAttributeF64(canonical_name, value);
364}
365
366BOOL LLXmlTreeNode::getAttributeColor(const std::string& name, LLColor4& value)
367{
368 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
369 return getFastAttributeColor(canonical_name, value);
370}
371
372BOOL LLXmlTreeNode::getAttributeColor4(const std::string& name, LLColor4& value)
373{
374 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
375 return getFastAttributeColor4(canonical_name, value);
376}
377
378BOOL LLXmlTreeNode::getAttributeColor4U(const std::string& name, LLColor4U& value)
379{
380 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
381 return getFastAttributeColor4U(canonical_name, value);
382}
383
384BOOL LLXmlTreeNode::getAttributeVector3(const std::string& name, LLVector3& value)
385{
386 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
387 return getFastAttributeVector3(canonical_name, value);
388}
389
390BOOL LLXmlTreeNode::getAttributeVector3d(const std::string& name, LLVector3d& value)
391{
392 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
393 return getFastAttributeVector3d(canonical_name, value);
394}
395
396BOOL LLXmlTreeNode::getAttributeQuat(const std::string& name, LLQuaternion& value)
397{
398 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
399 return getFastAttributeQuat(canonical_name, value);
400}
401
402BOOL LLXmlTreeNode::getAttributeUUID(const std::string& name, LLUUID& value)
403{
404 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
405 return getFastAttributeUUID(canonical_name, value);
406}
407
408BOOL LLXmlTreeNode::getAttributeString(const std::string& name, LLString& value)
409{
410 LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
411 return getFastAttributeString(canonical_name, value);
412}
413
414/*
415 The following xml <message> nodes will all return the string from getTextContents():
416 "The quick brown fox\n Jumps over the lazy dog"
417
418 1. HTML paragraph format:
419 <message>
420 <p>The quick brown fox</p>
421 <p> Jumps over the lazy dog</p>
422 </message>
423 2. Each quoted section -> paragraph:
424 <message>
425 "The quick brown fox"
426 " Jumps over the lazy dog"
427 </message>
428 3. Literal text with beginning and trailing whitespace removed:
429 <message>
430The quick brown fox
431 Jumps over the lazy dog
432 </message>
433
434*/
435
436LLString LLXmlTreeNode::getTextContents()
437{
438 std::string msg;
439 LLXmlTreeNode* p = getChildByName("p");
440 if (p)
441 {
442 // Case 1: node has <p>text</p> tags
443 while (p)
444 {
445 msg += p->getContents() + "\n";
446 p = getNextNamedChild();
447 }
448 }
449 else
450 {
451 std::string::size_type n = mContents.find_first_not_of(" \t\n");
452 if (n != std::string::npos && mContents[n] == '\"')
453 {
454 // Case 2: node has quoted text
455 S32 num_lines = 0;
456 while(1)
457 {
458 // mContents[n] == '"'
459 ++n;
460 std::string::size_type t = n;
461 std::string::size_type m = 0;
462 // fix-up escaped characters
463 while(1)
464 {
465 m = mContents.find_first_of("\\\"", t); // find first \ or "
466 if ((m == std::string::npos) || (mContents[m] == '\"'))
467 {
468 break;
469 }
470 mContents.erase(m,1);
471 t = m+1;
472 }
473 if (m == std::string::npos)
474 {
475 break;
476 }
477 // mContents[m] == '"'
478 num_lines++;
479 msg += mContents.substr(n,m-n) + "\n";
480 n = mContents.find_first_of("\"", m+1);
481 if (n == std::string::npos)
482 {
483 if (num_lines == 1)
484 {
485 msg.erase(msg.size()-1); // remove "\n" if only one line
486 }
487 break;
488 }
489 }
490 }
491 else
492 {
493 // Case 3: node has embedded text (beginning and trailing whitespace trimmed)
494 msg = mContents;
495 }
496 }
497 return msg;
498}
499
500
501//////////////////////////////////////////////////////////////
502// LLXmlTreeParser
503
504LLXmlTreeParser::LLXmlTreeParser(LLXmlTree* tree)
505 : mTree(tree),
506 mRoot( NULL ),
507 mCurrent( NULL ),
508 mDump( FALSE )
509{
510}
511
512LLXmlTreeParser::~LLXmlTreeParser()
513{
514}
515
516BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents)
517{
518 llassert( !mRoot );
519 llassert( !mCurrent );
520
521 mKeepContents = keep_contents;
522
523 BOOL success = LLXmlParser::parseFile(path);
524
525 *root = mRoot;
526 mRoot = NULL;
527
528 if( success )
529 {
530 llassert( !mCurrent );
531 }
532 mCurrent = NULL;
533
534 return success;
535}
536
537
538const std::string& LLXmlTreeParser::tabs()
539{
540 static LLString s;
541 s = "";
542 S32 num_tabs = getDepth() - 1;
543 for( S32 i = 0; i < num_tabs; i++)
544 {
545 s += " ";
546 }
547 return s;
548}
549
550void LLXmlTreeParser::startElement(const char* name, const char **atts)
551{
552 if( mDump )
553 {
554 llinfos << tabs() << "startElement " << name << llendl;
555
556 S32 i = 0;
557 while( atts[i] && atts[i+1] )
558 {
559 llinfos << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << llendl;
560 i += 2;
561 }
562 }
563
564 LLXmlTreeNode* child = CreateXmlTreeNode( std::string(name), mCurrent );
565
566 S32 i = 0;
567 while( atts[i] && atts[i+1] )
568 {
569 child->addAttribute( atts[i], atts[i+1] );
570 i += 2;
571 }
572
573 if( mCurrent )
574 {
575 mCurrent->addChild( child );
576
577 }
578 else
579 {
580 llassert( !mRoot );
581 mRoot = child;
582 }
583 mCurrent = child;
584}
585
586LLXmlTreeNode* LLXmlTreeParser::CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent)
587{
588 return new LLXmlTreeNode(name, parent, mTree);
589}
590
591
592void LLXmlTreeParser::endElement(const char* name)
593{
594 if( mDump )
595 {
596 llinfos << tabs() << "endElement " << name << llendl;
597 }
598
599 if( !mCurrent->mContents.empty() )
600 {
601 LLString::trim(mCurrent->mContents);
602 LLString::removeCRLF(mCurrent->mContents);
603 }
604
605 mCurrent = mCurrent->getParent();
606}
607
608void LLXmlTreeParser::characterData(const char *s, int len)
609{
610 LLString str(s, len);
611 if( mDump )
612 {
613 llinfos << tabs() << "CharacterData " << str << llendl;
614 }
615
616 if (mKeepContents)
617 {
618 mCurrent->appendContents( str );
619 }
620}
621
622void LLXmlTreeParser::processingInstruction(const char *target, const char *data)
623{
624 if( mDump )
625 {
626 llinfos << tabs() << "processingInstruction " << data << llendl;
627 }
628}
629
630void LLXmlTreeParser::comment(const char *data)
631{
632 if( mDump )
633 {
634 llinfos << tabs() << "comment " << data << llendl;
635 }
636}
637
638void LLXmlTreeParser::startCdataSection()
639{
640 if( mDump )
641 {
642 llinfos << tabs() << "startCdataSection" << llendl;
643 }
644}
645
646void LLXmlTreeParser::endCdataSection()
647{
648 if( mDump )
649 {
650 llinfos << tabs() << "endCdataSection" << llendl;
651 }
652}
653
654void LLXmlTreeParser::defaultData(const char *s, int len)
655{
656 if( mDump )
657 {
658 LLString str(s, len);
659 llinfos << tabs() << "defaultData " << str << llendl;
660 }
661}
662
663void LLXmlTreeParser::unparsedEntityDecl(
664 const char* entity_name,
665 const char* base,
666 const char* system_id,
667 const char* public_id,
668 const char* notation_name)
669{
670 if( mDump )
671 {
672 llinfos << tabs() << "unparsed entity:" << llendl;
673 llinfos << tabs() << " entityName " << entity_name << llendl;
674 llinfos << tabs() << " base " << base << llendl;
675 llinfos << tabs() << " systemId " << system_id << llendl;
676 llinfos << tabs() << " publicId " << public_id << llendl;
677 llinfos << tabs() << " notationName " << notation_name<< llendl;
678 }
679}
680
681void test_llxmltree()
682{
683 LLXmlTree tree;
684 BOOL success = tree.parseFile( "test.xml" );
685 if( success )
686 {
687 tree.dump();
688 }
689}
690
diff --git a/linden/indra/llxml/llxmltree.h b/linden/indra/llxml/llxmltree.h
new file mode 100644
index 0000000..6ce43af
--- /dev/null
+++ b/linden/indra/llxml/llxmltree.h
@@ -0,0 +1,235 @@
1/**
2 * @file llxmltree.h
3 * @author Aaron Yonas, Richard Nelson
4 * @brief LLXmlTree class definition
5 *
6 * Copyright (c) 2001-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#ifndef LL_LLXMLTREE_H
30#define LL_LLXMLTREE_H
31
32#include <map>
33#include <list>
34#include "llstring.h"
35#include "llxmlparser.h"
36#include "string_table.h"
37
38class LLColor4;
39class LLColor4U;
40class LLQuaternion;
41class LLUUID;
42class LLVector3;
43class LLVector3d;
44class LLXmlTreeNode;
45class LLXmlTreeParser;
46
47//////////////////////////////////////////////////////////////
48// LLXmlTree
49
50class LLXmlTree
51{
52 friend class LLXmlTreeNode;
53
54public:
55 LLXmlTree();
56 virtual ~LLXmlTree();
57 void cleanup();
58
59 virtual BOOL parseFile(const std::string &path, BOOL keep_contents = TRUE);
60
61 LLXmlTreeNode* getRoot() { return mRoot; }
62
63 void dump();
64 void dumpNode( LLXmlTreeNode* node, const LLString &prefix );
65
66 static LLStdStringHandle addAttributeString( const std::string& name)
67 {
68 return sAttributeKeys.addString( name );
69 }
70
71public:
72 // global
73 static LLStdStringTable sAttributeKeys;
74
75protected:
76 LLXmlTreeNode* mRoot;
77
78 // local
79 LLStdStringTable mNodeNames;
80};
81
82//////////////////////////////////////////////////////////////
83// LLXmlTreeNode
84
85class LLXmlTreeNode
86{
87 friend class LLXmlTree;
88 friend class LLXmlTreeParser;
89
90protected:
91 // Protected since nodes are only created and destroyed by friend classes and other LLXmlTreeNodes
92 LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree );
93
94public:
95 virtual ~LLXmlTreeNode();
96
97 const std::string& getName()
98 {
99 return mName;
100 }
101 BOOL hasName( const std::string& name )
102 {
103 return mName == name;
104 }
105
106 BOOL hasAttribute( const std::string& name );
107
108 // Fast versions use cannonical_name handlee to entru in LLXmlTree::sAttributeKeys string table
109 BOOL getFastAttributeBOOL( LLStdStringHandle cannonical_name, BOOL& value );
110 BOOL getFastAttributeU8( LLStdStringHandle cannonical_name, U8& value );
111 BOOL getFastAttributeS8( LLStdStringHandle cannonical_name, S8& value );
112 BOOL getFastAttributeU16( LLStdStringHandle cannonical_name, U16& value );
113 BOOL getFastAttributeS16( LLStdStringHandle cannonical_name, S16& value );
114 BOOL getFastAttributeU32( LLStdStringHandle cannonical_name, U32& value );
115 BOOL getFastAttributeS32( LLStdStringHandle cannonical_name, S32& value );
116 BOOL getFastAttributeF32( LLStdStringHandle cannonical_name, F32& value );
117 BOOL getFastAttributeF64( LLStdStringHandle cannonical_name, F64& value );
118 BOOL getFastAttributeColor( LLStdStringHandle cannonical_name, LLColor4& value );
119 BOOL getFastAttributeColor4( LLStdStringHandle cannonical_name, LLColor4& value );
120 BOOL getFastAttributeColor4U( LLStdStringHandle cannonical_name, LLColor4U& value );
121 BOOL getFastAttributeVector3( LLStdStringHandle cannonical_name, LLVector3& value );
122 BOOL getFastAttributeVector3d( LLStdStringHandle cannonical_name, LLVector3d& value );
123 BOOL getFastAttributeQuat( LLStdStringHandle cannonical_name, LLQuaternion& value );
124 BOOL getFastAttributeUUID( LLStdStringHandle cannonical_name, LLUUID& value );
125 BOOL getFastAttributeString( LLStdStringHandle cannonical_name, LLString& value );
126
127 // Normal versions find 'name' in LLXmlTree::sAttributeKeys then call fast versions
128 virtual BOOL getAttributeBOOL( const std::string& name, BOOL& value );
129 virtual BOOL getAttributeU8( const std::string& name, U8& value );
130 virtual BOOL getAttributeS8( const std::string& name, S8& value );
131 virtual BOOL getAttributeU16( const std::string& name, U16& value );
132 virtual BOOL getAttributeS16( const std::string& name, S16& value );
133 virtual BOOL getAttributeU32( const std::string& name, U32& value );
134 virtual BOOL getAttributeS32( const std::string& name, S32& value );
135 virtual BOOL getAttributeF32( const std::string& name, F32& value );
136 virtual BOOL getAttributeF64( const std::string& name, F64& value );
137 virtual BOOL getAttributeColor( const std::string& name, LLColor4& value );
138 virtual BOOL getAttributeColor4( const std::string& name, LLColor4& value );
139 virtual BOOL getAttributeColor4U( const std::string& name, LLColor4U& value );
140 virtual BOOL getAttributeVector3( const std::string& name, LLVector3& value );
141 virtual BOOL getAttributeVector3d( const std::string& name, LLVector3d& value );
142 virtual BOOL getAttributeQuat( const std::string& name, LLQuaternion& value );
143 virtual BOOL getAttributeUUID( const std::string& name, LLUUID& value );
144 virtual BOOL getAttributeString( const std::string& name, LLString& value );
145
146 const LLString& getContents()
147 {
148 return mContents;
149 }
150 LLString getTextContents();
151
152 LLXmlTreeNode* getParent() { return mParent; }
153 LLXmlTreeNode* getFirstChild();
154 LLXmlTreeNode* getNextChild();
155 S32 getChildCount() { return (S32)mChildList.size(); }
156 LLXmlTreeNode* getChildByName( const std::string& name ); // returns first child with name, NULL if none
157 LLXmlTreeNode* getNextNamedChild(); // returns next child with name, NULL if none
158
159protected:
160 const LLString* getAttribute( LLStdStringHandle name)
161 {
162 attribute_map_t::iterator iter = mAttributes.find(name);
163 return (iter == mAttributes.end()) ? 0 : iter->second;
164 }
165
166private:
167 void addAttribute( const std::string& name, const std::string& value );
168 void appendContents( const std::string& str );
169 void addChild( LLXmlTreeNode* child );
170
171 void dump( const LLString& prefix );
172
173protected:
174 typedef std::map<LLStdStringHandle, const LLString*> attribute_map_t;
175 attribute_map_t mAttributes;
176
177private:
178 LLString mName;
179 LLString mContents;
180
181 typedef std::list<class LLXmlTreeNode *> child_list_t;
182 child_list_t mChildList;
183 child_list_t::iterator mChildListIter;
184
185 typedef std::multimap<LLStdStringHandle, LLXmlTreeNode *> child_map_t;
186 child_map_t mChildMap; // for fast name lookups
187 child_map_t::iterator mChildMapIter;
188 child_map_t::iterator mChildMapEndIter;
189
190 LLXmlTreeNode* mParent;
191 LLXmlTree* mTree;
192};
193
194//////////////////////////////////////////////////////////////
195// LLXmlTreeParser
196
197class LLXmlTreeParser : public LLXmlParser
198{
199public:
200 LLXmlTreeParser(LLXmlTree* tree);
201 virtual ~LLXmlTreeParser();
202
203 BOOL parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents );
204
205protected:
206 const std::string& tabs();
207
208 // Overrides from LLXmlParser
209 virtual void startElement(const char *name, const char **attributes);
210 virtual void endElement(const char *name);
211 virtual void characterData(const char *s, int len);
212 virtual void processingInstruction(const char *target, const char *data);
213 virtual void comment(const char *data);
214 virtual void startCdataSection();
215 virtual void endCdataSection();
216 virtual void defaultData(const char *s, int len);
217 virtual void unparsedEntityDecl(
218 const char* entity_name,
219 const char* base,
220 const char* system_id,
221 const char* public_id,
222 const char* notation_name);
223
224 //template method pattern
225 virtual LLXmlTreeNode* CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent);
226
227protected:
228 LLXmlTree* mTree;
229 LLXmlTreeNode* mRoot;
230 LLXmlTreeNode* mCurrent;
231 BOOL mDump; // Dump parse tree to llinfos as it is read.
232 BOOL mKeepContents;
233};
234
235#endif // LL_LLXMLTREE_H