aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llxml
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llxml')
-rw-r--r--linden/indra/llxml/CMakeLists.txt1
-rw-r--r--linden/indra/llxml/llcontrol.cpp56
-rw-r--r--linden/indra/llxml/llcontrol.h16
-rw-r--r--linden/indra/llxml/llcontrolgroupreader.h74
-rw-r--r--linden/indra/llxml/llxmlnode.cpp188
-rw-r--r--linden/indra/llxml/llxmlnode.h29
-rw-r--r--linden/indra/llxml/llxmlparser.cpp3
-rw-r--r--linden/indra/llxml/llxmlparser.h3
-rw-r--r--linden/indra/llxml/llxmltree.cpp3
-rw-r--r--linden/indra/llxml/llxmltree.h3
10 files changed, 317 insertions, 59 deletions
diff --git a/linden/indra/llxml/CMakeLists.txt b/linden/indra/llxml/CMakeLists.txt
index 9febd97..487c5b9 100644
--- a/linden/indra/llxml/CMakeLists.txt
+++ b/linden/indra/llxml/CMakeLists.txt
@@ -23,6 +23,7 @@ set(llxml_HEADER_FILES
23 CMakeLists.txt 23 CMakeLists.txt
24 24
25 llcontrol.h 25 llcontrol.h
26 llcontrolgroupreader.h
26 llxmlnode.h 27 llxmlnode.h
27 llxmlparser.h 28 llxmlparser.h
28 llxmltree.h 29 llxmltree.h
diff --git a/linden/indra/llxml/llcontrol.cpp b/linden/indra/llxml/llcontrol.cpp
index 81c3e78..d9ed45a 100644
--- a/linden/indra/llxml/llcontrol.cpp
+++ b/linden/indra/llxml/llcontrol.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -101,11 +102,12 @@ bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b)
101 102
102LLControlVariable::LLControlVariable(const std::string& name, eControlType type, 103LLControlVariable::LLControlVariable(const std::string& name, eControlType type,
103 LLSD initial, const std::string& comment, 104 LLSD initial, const std::string& comment,
104 bool persist) 105 bool persist, bool hidefromsettingseditor)
105 : mName(name), 106 : mName(name),
106 mComment(comment), 107 mComment(comment),
107 mType(type), 108 mType(type),
108 mPersist(persist) 109 mPersist(persist),
110 mHideFromSettingsEditor(hidefromsettingseditor)
109{ 111{
110 if (mPersist && mComment.empty()) 112 if (mPersist && mComment.empty())
111 { 113 {
@@ -212,6 +214,11 @@ void LLControlVariable::setPersist(bool state)
212 mPersist = state; 214 mPersist = state;
213} 215}
214 216
217void LLControlVariable::setHiddenFromSettingsEditor(bool hide)
218{
219 mHideFromSettingsEditor = hide;
220}
221
215void LLControlVariable::setComment(const std::string& comment) 222void LLControlVariable::setComment(const std::string& comment)
216{ 223{
217 mComment = comment; 224 mComment = comment;
@@ -295,17 +302,27 @@ std::string LLControlGroup::typeEnumToString(eControlType typeenum)
295 return mTypeString[typeenum]; 302 return mTypeString[typeenum];
296} 303}
297 304
298BOOL LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, BOOL persist) 305BOOL LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, BOOL persist, BOOL hidefromsettingseditor)
299{ 306{
300 if(mNameTable.find(name) != mNameTable.end()) 307 LLControlVariable* existing_control = getControl(name);
301 { 308 if (existing_control)
302 llwarns << "LLControlGroup::declareControl: Control named " << name << " already exists." << llendl; 309 {
303 mNameTable[name]->setValue(initial_val); 310 if (persist && existing_control->isType(type))
304 return TRUE; 311 {
312 // Sometimes we need to declare a control *after* it has been loaded from a settings file.
313 LLSD cur_value = existing_control->getValue(); // get the current value
314 existing_control->setDefaultValue(initial_val); // set the default to the declared value
315 existing_control->setValue(cur_value); // now set to the loaded value
316 }
317 else
318 {
319 llwarns << "Control named " << name << " already exists, ignoring new declaration." << llendl;
320 }
321 return TRUE;
305 } 322 }
306 323
307 // if not, create the control and add it to the name table 324 // if not, create the control and add it to the name table
308 LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist); 325 LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor);
309 mNameTable[name] = control; 326 mNameTable[name] = control;
310 return TRUE; 327 return TRUE;
311} 328}
@@ -1042,7 +1059,8 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
1042 } 1059 }
1043 1060
1044 U32 validitems = 0; 1061 U32 validitems = 0;
1045 bool persist = false; 1062 bool persist = true;
1063 bool hidefromsettingseditor = false;
1046 for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) 1064 for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr)
1047 { 1065 {
1048 name = (*itr).first; 1066 name = (*itr).first;
@@ -1053,6 +1071,18 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
1053 persist = control_map["Persist"].asInteger(); 1071 persist = control_map["Persist"].asInteger();
1054 } 1072 }
1055 1073
1074 // Sometimes we want to use the settings system to provide cheap persistence, but we
1075 // don't want the settings themselves to be easily manipulated in the UI because
1076 // doing so can cause support problems. So we have this option:
1077 if(control_map.has("HideFromEditor"))
1078 {
1079 hidefromsettingseditor = control_map["HideFromEditor"].asInteger();
1080 }
1081 else
1082 {
1083 hidefromsettingseditor = false;
1084 }
1085
1056 // If the control exists just set the value from the input file. 1086 // If the control exists just set the value from the input file.
1057 LLControlVariable* existing_control = getControl(name); 1087 LLControlVariable* existing_control = getControl(name);
1058 if(existing_control) 1088 if(existing_control)
@@ -1066,6 +1096,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
1066 { 1096 {
1067 existing_control->setDefaultValue(control_map["Value"]); 1097 existing_control->setDefaultValue(control_map["Value"]);
1068 existing_control->setPersist(persist); 1098 existing_control->setPersist(persist);
1099 existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor);
1069 existing_control->setComment(control_map["Comment"].asString()); 1100 existing_control->setComment(control_map["Comment"].asString());
1070 } 1101 }
1071 else 1102 else
@@ -1089,7 +1120,8 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
1089 typeStringToEnum(control_map["Type"].asString()), 1120 typeStringToEnum(control_map["Type"].asString()),
1090 control_map["Value"], 1121 control_map["Value"],
1091 control_map["Comment"].asString(), 1122 control_map["Comment"].asString(),
1092 persist 1123 persist,
1124 hidefromsettingseditor
1093 ); 1125 );
1094 } 1126 }
1095 1127
diff --git a/linden/indra/llxml/llcontrol.h b/linden/indra/llxml/llcontrol.h
index 7b327ef..ba0a1c7 100644
--- a/linden/indra/llxml/llcontrol.h
+++ b/linden/indra/llxml/llcontrol.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -38,6 +39,8 @@
38#include "llstring.h" 39#include "llstring.h"
39#include "llrect.h" 40#include "llrect.h"
40 41
42#include "llcontrolgroupreader.h"
43
41#include <vector> 44#include <vector>
42 45
43// *NOTE: boost::visit_each<> generates warning 4675 on .net 2003 46// *NOTE: boost::visit_each<> generates warning 4675 on .net 2003
@@ -92,7 +95,8 @@ private:
92 std::string mName; 95 std::string mName;
93 std::string mComment; 96 std::string mComment;
94 eControlType mType; 97 eControlType mType;
95 bool mPersist; 98 bool mPersist;
99 bool mHideFromSettingsEditor;
96 std::vector<LLSD> mValues; 100 std::vector<LLSD> mValues;
97 101
98 signal_t mSignal; 102 signal_t mSignal;
@@ -100,7 +104,7 @@ private:
100public: 104public:
101 LLControlVariable(const std::string& name, eControlType type, 105 LLControlVariable(const std::string& name, eControlType type,
102 LLSD initial, const std::string& comment, 106 LLSD initial, const std::string& comment,
103 bool persist = true); 107 bool persist = true, bool hidefromsettingseditor = false);
104 108
105 virtual ~LLControlVariable(); 109 virtual ~LLControlVariable();
106 110
@@ -117,6 +121,7 @@ public:
117 bool isDefault() { return (mValues.size() == 1); } 121 bool isDefault() { return (mValues.size() == 1); }
118 bool isSaveValueDefault(); 122 bool isSaveValueDefault();
119 bool isPersisted() { return mPersist; } 123 bool isPersisted() { return mPersist; }
124 bool isHiddenFromSettingsEditor() { return mHideFromSettingsEditor; }
120 LLSD get() const { return getValue(); } 125 LLSD get() const { return getValue(); }
121 LLSD getValue() const { return mValues.back(); } 126 LLSD getValue() const { return mValues.back(); }
122 LLSD getDefault() const { return mValues.front(); } 127 LLSD getDefault() const { return mValues.front(); }
@@ -126,6 +131,7 @@ public:
126 void setValue(const LLSD& value, bool saved_value = TRUE); 131 void setValue(const LLSD& value, bool saved_value = TRUE);
127 void setDefaultValue(const LLSD& value); 132 void setDefaultValue(const LLSD& value);
128 void setPersist(bool state); 133 void setPersist(bool state);
134 void setHiddenFromSettingsEditor(bool hide);
129 void setComment(const std::string& comment); 135 void setComment(const std::string& comment);
130 136
131 void firePropertyChanged() 137 void firePropertyChanged()
@@ -139,7 +145,7 @@ private:
139}; 145};
140 146
141//const U32 STRING_CACHE_SIZE = 10000; 147//const U32 STRING_CACHE_SIZE = 10000;
142class LLControlGroup 148class LLControlGroup : public LLControlGroupReader
143{ 149{
144protected: 150protected:
145 typedef std::map<std::string, LLPointer<LLControlVariable> > ctrl_name_table_t; 151 typedef std::map<std::string, LLPointer<LLControlVariable> > ctrl_name_table_t;
@@ -163,7 +169,7 @@ public:
163 }; 169 };
164 void applyToAll(ApplyFunctor* func); 170 void applyToAll(ApplyFunctor* func);
165 171
166 BOOL declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, BOOL persist); 172 BOOL declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, BOOL persist, BOOL hidefromsettingseditor = FALSE);
167 BOOL declareU32(const std::string& name, U32 initial_val, const std::string& comment, BOOL persist = TRUE); 173 BOOL declareU32(const std::string& name, U32 initial_val, const std::string& comment, BOOL persist = TRUE);
168 BOOL declareS32(const std::string& name, S32 initial_val, const std::string& comment, BOOL persist = TRUE); 174 BOOL declareS32(const std::string& name, S32 initial_val, const std::string& comment, BOOL persist = TRUE);
169 BOOL declareF32(const std::string& name, F32 initial_val, const std::string& comment, BOOL persist = TRUE); 175 BOOL declareF32(const std::string& name, F32 initial_val, const std::string& comment, BOOL persist = TRUE);
diff --git a/linden/indra/llxml/llcontrolgroupreader.h b/linden/indra/llxml/llcontrolgroupreader.h
new file mode 100644
index 0000000..c4c04b9
--- /dev/null
+++ b/linden/indra/llxml/llcontrolgroupreader.h
@@ -0,0 +1,74 @@
1/**
2 * @file llcontrolgroupreader.h
3 * @brief Interface providing readonly access to LLControlGroup (intended for unit testing)
4 *
5 * $LicenseInfo:firstyear=2001&license=viewergpl$
6 *
7 * Copyright (c) 2001-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#ifndef LL_LLCONTROLGROUPREADER_H
34#define LL_LLCONTROLGROUPREADER_H
35
36#include "stdtypes.h"
37#include <string>
38
39// Many of the types below are commented out because for the purposes of the early testing we're doing,
40// we don't need them and we don't want to pull in all the machinery to support them.
41// But the model is here for future unit test extensions.
42
43class LLControlGroupReader
44{
45public:
46 LLControlGroupReader() {}
47 virtual ~LLControlGroupReader() {}
48
49 virtual std::string getString(const std::string& name) = 0;
50 //virtual LLWString getWString(const std::string& name) = 0;
51 virtual std::string getText(const std::string& name) = 0;
52 //virtual LLVector3 getVector3(const std::string& name) = 0;
53 //virtual LLVector3d getVector3d(const std::string& name) = 0;
54 //virtual LLRect getRect(const std::string& name) = 0;
55 virtual BOOL getBOOL(const std::string& name) = 0;
56 virtual S32 getS32(const std::string& name) = 0;
57 virtual F32 getF32(const std::string& name) = 0;
58 virtual U32 getU32(const std::string& name) = 0;
59 //virtual LLSD getLLSD(const std::string& name) = 0;
60
61 //virtual LLColor4 getColor(const std::string& name) = 0;
62 //virtual LLColor4U getColor4U(const std::string& name) = 0;
63 //virtual LLColor4 getColor4(const std::string& name) = 0;
64 //virtual LLColor3 getColor3(const std::string& name) = 0;
65};
66
67#endif /* LL_LLCONTROLGROUPREADER_H */
68
69
70
71
72
73
74
diff --git a/linden/indra/llxml/llxmlnode.cpp b/linden/indra/llxml/llxmlnode.cpp
index 7464529..800b135 100644
--- a/linden/indra/llxml/llxmlnode.cpp
+++ b/linden/indra/llxml/llxmlnode.cpp
@@ -18,7 +18,8 @@
18 * There are special exceptions to the terms and conditions of the GPL as 18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception 19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or 20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 * 23 *
23 * By copying, modifying or distributing this software, you acknowledge 24 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above, 25 * that you have read and understood your obligations described above,
@@ -65,6 +66,9 @@ LLXMLNode::LLXMLNode() :
65 mEncoding(ENCODING_DEFAULT), 66 mEncoding(ENCODING_DEFAULT),
66 mParent(NULL), 67 mParent(NULL),
67 mChildren(NULL), 68 mChildren(NULL),
69 mAttributes(),
70 mPrev(NULL),
71 mNext(NULL),
68 mName(NULL), 72 mName(NULL),
69 mValue(""), 73 mValue(""),
70 mDefault(NULL) 74 mDefault(NULL)
@@ -83,6 +87,9 @@ LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) :
83 mEncoding(ENCODING_DEFAULT), 87 mEncoding(ENCODING_DEFAULT),
84 mParent(NULL), 88 mParent(NULL),
85 mChildren(NULL), 89 mChildren(NULL),
90 mAttributes(),
91 mPrev(NULL),
92 mNext(NULL),
86 mValue(""), 93 mValue(""),
87 mDefault(NULL) 94 mDefault(NULL)
88{ 95{
@@ -101,17 +108,65 @@ LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) :
101 mEncoding(ENCODING_DEFAULT), 108 mEncoding(ENCODING_DEFAULT),
102 mParent(NULL), 109 mParent(NULL),
103 mChildren(NULL), 110 mChildren(NULL),
111 mAttributes(),
112 mPrev(NULL),
113 mNext(NULL),
104 mName(name), 114 mName(name),
105 mValue(""), 115 mValue(""),
106 mDefault(NULL) 116 mDefault(NULL)
107{ 117{
108} 118}
109 119
120// copy constructor (except for the children)
121LLXMLNode::LLXMLNode(const LLXMLNode& rhs) :
122 mID(rhs.mID),
123 mIsAttribute(rhs.mIsAttribute),
124 mVersionMajor(rhs.mVersionMajor),
125 mVersionMinor(rhs.mVersionMinor),
126 mLength(rhs.mLength),
127 mPrecision(rhs.mPrecision),
128 mType(rhs.mType),
129 mEncoding(rhs.mEncoding),
130 mParent(NULL),
131 mChildren(NULL),
132 mAttributes(),
133 mPrev(NULL),
134 mNext(NULL),
135 mName(rhs.mName),
136 mValue(rhs.mValue),
137 mDefault(rhs.mDefault)
138{
139}
140
141// returns a new copy of this node and all its children
142LLXMLNodePtr LLXMLNode::deepCopy()
143{
144 LLXMLNodePtr newnode = LLXMLNodePtr(new LLXMLNode(*this));
145 if (mChildren.notNull())
146 {
147 for (LLXMLChildList::iterator iter = mChildren->map.begin();
148 iter != mChildren->map.end(); ++iter)
149 {
150 newnode->addChild(iter->second->deepCopy());
151 }
152 }
153 for (LLXMLAttribList::iterator iter = mAttributes.begin();
154 iter != mAttributes.end(); ++iter)
155 {
156 newnode->addChild(iter->second->deepCopy());
157 }
158
159 return newnode;
160}
161
110// virtual 162// virtual
111LLXMLNode::~LLXMLNode() 163LLXMLNode::~LLXMLNode()
112{ 164{
113 // Strictly speaking none of this should be required execept 'delete mChildren'... 165 // Strictly speaking none of this should be required execept 'delete mChildren'...
114 if (mChildren) 166 // Sadly, that's only true if we hadn't had reference-counted smart pointers linked
167 // in three different directions. This entire class is a frightening, hard-to-maintain
168 // mess.
169 if (mChildren.notNull())
115 { 170 {
116 for (LLXMLChildList::iterator iter = mChildren->map.begin(); 171 for (LLXMLChildList::iterator iter = mChildren->map.begin();
117 iter != mChildren->map.end(); ++iter) 172 iter != mChildren->map.end(); ++iter)
@@ -124,7 +179,7 @@ LLXMLNode::~LLXMLNode()
124 mChildren->map.clear(); 179 mChildren->map.clear();
125 mChildren->head = NULL; 180 mChildren->head = NULL;
126 mChildren->tail = NULL; 181 mChildren->tail = NULL;
127 delete mChildren; 182 mChildren = NULL;
128 } 183 }
129 for (LLXMLAttribList::iterator iter = mAttributes.begin(); 184 for (LLXMLAttribList::iterator iter = mAttributes.begin();
130 iter != mAttributes.end(); ++iter) 185 iter != mAttributes.end(); ++iter)
@@ -160,7 +215,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child)
160 return TRUE; 215 return TRUE;
161 } 216 }
162 } 217 }
163 else if (mChildren) 218 else if (mChildren.notNull())
164 { 219 {
165 LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName); 220 LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName);
166 while (children_itr != mChildren->map.end()) 221 while (children_itr != mChildren->map.end())
@@ -183,7 +238,6 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child)
183 mChildren->map.erase(children_itr); 238 mChildren->map.erase(children_itr);
184 if (mChildren->map.empty()) 239 if (mChildren->map.empty())
185 { 240 {
186 delete mChildren;
187 mChildren = NULL; 241 mChildren = NULL;
188 } 242 }
189 return TRUE; 243 return TRUE;
@@ -201,7 +255,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child)
201 return FALSE; 255 return FALSE;
202} 256}
203 257
204void LLXMLNode::addChild(LLXMLNodePtr new_child) 258void LLXMLNode::addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child)
205{ 259{
206 if (new_child->mParent != NULL) 260 if (new_child->mParent != NULL)
207 { 261 {
@@ -219,7 +273,7 @@ void LLXMLNode::addChild(LLXMLNodePtr new_child)
219 } 273 }
220 else 274 else
221 { 275 {
222 if (!mChildren) 276 if (mChildren.isNull())
223 { 277 {
224 mChildren = new LLXMLChildren(); 278 mChildren = new LLXMLChildren();
225 mChildren->head = new_child; 279 mChildren->head = new_child;
@@ -227,11 +281,33 @@ void LLXMLNode::addChild(LLXMLNodePtr new_child)
227 } 281 }
228 mChildren->map.insert(std::make_pair(new_child->mName, new_child)); 282 mChildren->map.insert(std::make_pair(new_child->mName, new_child));
229 283
230 if (mChildren->tail != new_child) 284 // if after_child is specified, it damn well better be in the list of children
285 // for this node. I'm not going to assert that, because it would be expensive,
286 // but don't specify that parameter if you didn't get the value for it from the
287 // list of children of this node!
288 if (after_child.isNull())
231 { 289 {
232 mChildren->tail->mNext = new_child; 290 if (mChildren->tail != new_child)
233 new_child->mPrev = mChildren->tail; 291 {
234 mChildren->tail = new_child; 292 mChildren->tail->mNext = new_child;
293 new_child->mPrev = mChildren->tail;
294 mChildren->tail = new_child;
295 }
296 }
297 else
298 {
299 if (after_child->mNext.notNull())
300 {
301 // if after_child was not the last item, fix up some pointers
302 after_child->mNext->mPrev = new_child;
303 new_child->mNext = after_child->mNext;
304 }
305 new_child->mPrev = after_child;
306 after_child->mNext = new_child;
307 if (mChildren->tail == after_child)
308 {
309 mChildren->tail = new_child;
310 }
235 } 311 }
236 } 312 }
237 313
@@ -293,7 +369,7 @@ void LLXMLNode::updateDefault()
293 } 369 }
294 } 370 }
295 371
296 if (mChildren) 372 if (mChildren.notNull())
297 { 373 {
298 LLXMLChildList::const_iterator children_itr; 374 LLXMLChildList::const_iterator children_itr;
299 LLXMLChildList::const_iterator children_end = mChildren->map.end(); 375 LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -566,6 +642,24 @@ bool LLXMLNode::updateNode(
566} 642}
567 643
568 644
645// static
646LLXMLNodePtr LLXMLNode::replaceNode(LLXMLNodePtr node, LLXMLNodePtr update_node)
647{
648 if (!node || !update_node)
649 {
650 llwarns << "Node invalid" << llendl;
651 return node;
652 }
653
654 LLXMLNodePtr cloned_node = update_node->deepCopy();
655 node->mParent->addChild(cloned_node, node); // add after node
656 LLXMLNodePtr parent = node->mParent;
657 parent->removeChild(node);
658 parent->updateDefault();
659
660 return cloned_node;
661}
662
569 663
570 664
571// static 665// static
@@ -618,7 +712,7 @@ bool LLXMLNode::parseBuffer(
618 { 712 {
619 llwarns << "Error parsing xml error code: " 713 llwarns << "Error parsing xml error code: "
620 << XML_ErrorString(XML_GetErrorCode(my_parser)) 714 << XML_ErrorString(XML_GetErrorCode(my_parser))
621 << " on lne " << XML_GetCurrentLineNumber(my_parser) 715 << " on line " << XML_GetCurrentLineNumber(my_parser)
622 << llendl; 716 << llendl;
623 } 717 }
624 718
@@ -722,7 +816,7 @@ BOOL LLXMLNode::isFullyDefault()
722 && has_default_length 816 && has_default_length
723 && has_default_attribute) 817 && has_default_attribute)
724 { 818 {
725 if (mChildren) 819 if (mChildren.notNull())
726 { 820 {
727 LLXMLChildList::const_iterator children_itr; 821 LLXMLChildList::const_iterator children_itr;
728 LLXMLChildList::const_iterator children_end = mChildren->map.end(); 822 LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -888,7 +982,7 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i
888 } 982 }
889 } 983 }
890 984
891 if (!mChildren && mValue == "") 985 if (mChildren.isNull() && mValue == "")
892 { 986 {
893 output_stream << " />\n"; 987 output_stream << " />\n";
894 return; 988 return;
@@ -896,7 +990,7 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i
896 else 990 else
897 { 991 {
898 output_stream << ">\n"; 992 output_stream << ">\n";
899 if (mChildren) 993 if (mChildren.notNull())
900 { 994 {
901 // stream non-attributes 995 // stream non-attributes
902 std::string next_indent = indent + "\t"; 996 std::string next_indent = indent + "\t";
@@ -922,7 +1016,7 @@ void LLXMLNode::findName(const std::string& name, LLXMLNodeList &results)
922 results.insert(std::make_pair(this->mName->mString, this)); 1016 results.insert(std::make_pair(this->mName->mString, this));
923 return; 1017 return;
924 } 1018 }
925 if (mChildren) 1019 if (mChildren.notNull())
926 { 1020 {
927 LLXMLChildList::const_iterator children_itr; 1021 LLXMLChildList::const_iterator children_itr;
928 LLXMLChildList::const_iterator children_end = mChildren->map.end(); 1022 LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -941,7 +1035,7 @@ void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results)
941 results.insert(std::make_pair(this->mName->mString, this)); 1035 results.insert(std::make_pair(this->mName->mString, this));
942 return; 1036 return;
943 } 1037 }
944 if (mChildren) 1038 if (mChildren.notNull())
945 { 1039 {
946 LLXMLChildList::const_iterator children_itr; 1040 LLXMLChildList::const_iterator children_itr;
947 LLXMLChildList::const_iterator children_end = mChildren->map.end(); 1041 LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -960,7 +1054,7 @@ void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results)
960 results.insert(std::make_pair(this->mName->mString, this)); 1054 results.insert(std::make_pair(this->mName->mString, this));
961 return; 1055 return;
962 } 1056 }
963 if (mChildren) 1057 if (mChildren.notNull())
964 { 1058 {
965 LLXMLChildList::const_iterator children_itr; 1059 LLXMLChildList::const_iterator children_itr;
966 LLXMLChildList::const_iterator children_end = mChildren->map.end(); 1060 LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -974,11 +1068,11 @@ void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results)
974 1068
975void LLXMLNode::scrubToTree(LLXMLNode *tree) 1069void LLXMLNode::scrubToTree(LLXMLNode *tree)
976{ 1070{
977 if (!tree || !tree->mChildren) 1071 if (!tree || tree->mChildren.isNull())
978 { 1072 {
979 return; 1073 return;
980 } 1074 }
981 if (mChildren) 1075 if (mChildren.notNull())
982 { 1076 {
983 std::vector<LLXMLNodePtr> to_delete_list; 1077 std::vector<LLXMLNodePtr> to_delete_list;
984 LLXMLChildList::iterator itor = mChildren->map.begin(); 1078 LLXMLChildList::iterator itor = mChildren->map.begin();
@@ -1023,7 +1117,7 @@ bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, BOOL use_default_
1023 1117
1024bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing) 1118bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
1025{ 1119{
1026 if (mChildren) 1120 if (mChildren.notNull())
1027 { 1121 {
1028 LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); 1122 LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
1029 if (child_itr != mChildren->map.end()) 1123 if (child_itr != mChildren->map.end())
@@ -1047,7 +1141,7 @@ void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, BOOL use_
1047 1141
1048void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing) const 1142void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing) const
1049{ 1143{
1050 if (mChildren) 1144 if (mChildren.notNull())
1051 { 1145 {
1052 LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); 1146 LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
1053 if (child_itr != mChildren->map.end()) 1147 if (child_itr != mChildren->map.end())
@@ -1071,6 +1165,25 @@ void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &child
1071 } 1165 }
1072} 1166}
1073 1167
1168// recursively walks the tree and returns all children at all nesting levels matching the name
1169void LLXMLNode::getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const
1170{
1171 if (mChildren.notNull())
1172 {
1173 for (LLXMLChildList::const_iterator child_itr = mChildren->map.begin();
1174 child_itr != mChildren->map.end(); ++child_itr)
1175 {
1176 LLXMLNodePtr child = (*child_itr).second;
1177 if (name == child->mName)
1178 {
1179 children.insert(std::make_pair(child->mName->mString, child));
1180 }
1181 // and check each child as well
1182 child->getDescendants(name, children);
1183 }
1184 }
1185}
1186
1074bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing) 1187bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
1075{ 1188{
1076 return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing); 1189 return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing);
@@ -1111,6 +1224,23 @@ BOOL LLXMLNode::hasAttribute(const char* name )
1111 return getAttribute(name, node); 1224 return getAttribute(name, node);
1112} 1225}
1113 1226
1227// the structure of these getAttribute_ functions is ugly, but it's because the
1228// underlying system is based on BOOL and LLString; if we change
1229// so that they're based on more generic mechanisms, these will be
1230// simplified.
1231bool LLXMLNode::getAttribute_bool(const char* name, bool& value )
1232{
1233 LLXMLNodePtr node;
1234 if (!getAttribute(name, node))
1235 {
1236 return false;
1237 }
1238 BOOL temp;
1239 bool retval = node->getBoolValue(1, &temp);
1240 value = temp;
1241 return retval;
1242}
1243
1114BOOL LLXMLNode::getAttributeBOOL(const char* name, BOOL& value ) 1244BOOL LLXMLNode::getAttributeBOOL(const char* name, BOOL& value )
1115{ 1245{
1116 LLXMLNodePtr node; 1246 LLXMLNodePtr node;
@@ -2521,7 +2651,7 @@ void LLXMLNode::setName(LLStringTableEntry* name)
2521 2651
2522U32 LLXMLNode::getChildCount() const 2652U32 LLXMLNode::getChildCount() const
2523{ 2653{
2524 if (mChildren) 2654 if (mChildren.notNull())
2525 { 2655 {
2526 return mChildren->map.size(); 2656 return mChildren->map.size();
2527 } 2657 }
@@ -2540,7 +2670,7 @@ U32 get_rand(U32 max_value)
2540 2670
2541LLXMLNode *get_rand_node(LLXMLNode *node) 2671LLXMLNode *get_rand_node(LLXMLNode *node)
2542{ 2672{
2543 if (node->mChildren) 2673 if (node->mChildren.notNull())
2544 { 2674 {
2545 U32 num_children = node->mChildren->map.size(); 2675 U32 num_children = node->mChildren->map.size();
2546 if (get_rand(2) == 0) 2676 if (get_rand(2) == 0)
@@ -2748,7 +2878,7 @@ void LLXMLNode::createUnitTest(S32 max_num_children)
2748 2878
2749BOOL LLXMLNode::performUnitTest(std::string &error_buffer) 2879BOOL LLXMLNode::performUnitTest(std::string &error_buffer)
2750{ 2880{
2751 if (!mChildren) 2881 if (mChildren.isNull())
2752 { 2882 {
2753 error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString)); 2883 error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString));
2754 return FALSE; 2884 return FALSE;
@@ -3007,14 +3137,14 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer)
3007 return TRUE; 3137 return TRUE;
3008} 3138}
3009 3139
3010LLXMLNodePtr LLXMLNode::getFirstChild() 3140LLXMLNodePtr LLXMLNode::getFirstChild() const
3011{ 3141{
3012 if (!mChildren) return NULL; 3142 if (mChildren.isNull()) return NULL;
3013 LLXMLNodePtr ret = mChildren->head; 3143 LLXMLNodePtr ret = mChildren->head;
3014 return ret; 3144 return ret;
3015} 3145}
3016 3146
3017LLXMLNodePtr LLXMLNode::getNextSibling() 3147LLXMLNodePtr LLXMLNode::getNextSibling() const
3018{ 3148{
3019 LLXMLNodePtr ret = mNext; 3149 LLXMLNodePtr ret = mNext;
3020 return ret; 3150 return ret;
diff --git a/linden/indra/llxml/llxmlnode.h b/linden/indra/llxml/llxmlnode.h
index e73b4b1..d4e127b 100644
--- a/linden/indra/llxml/llxmlnode.h
+++ b/linden/indra/llxml/llxmlnode.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
@@ -87,12 +88,13 @@ class LLVector3d;
87class LLVector4; 88class LLVector4;
88class LLVector4U; 89class LLVector4U;
89 90
90struct LLXMLChildren 91struct LLXMLChildren : public LLThreadSafeRefCount
91{ 92{
92 LLXMLChildList map; // Map of children names->pointers 93 LLXMLChildList map; // Map of children names->pointers
93 LLXMLNodePtr head; // Head of the double-linked list 94 LLXMLNodePtr head; // Head of the double-linked list
94 LLXMLNodePtr tail; // Tail of the double-linked list 95 LLXMLNodePtr tail; // Tail of the double-linked list
95}; 96};
97typedef LLPointer<LLXMLChildren> LLXMLChildrenPtr;
96 98
97class LLXMLNode : public LLThreadSafeRefCount 99class LLXMLNode : public LLThreadSafeRefCount
98{ 100{
@@ -124,11 +126,13 @@ public:
124 LLXMLNode(); 126 LLXMLNode();
125 LLXMLNode(const char* name, BOOL is_attribute); 127 LLXMLNode(const char* name, BOOL is_attribute);
126 LLXMLNode(LLStringTableEntry* name, BOOL is_attribute); 128 LLXMLNode(LLStringTableEntry* name, BOOL is_attribute);
129 LLXMLNode(const LLXMLNode& rhs);
130 LLXMLNodePtr deepCopy();
127 131
128 BOOL isNull(); 132 BOOL isNull();
129 133
130 BOOL deleteChild(LLXMLNode* child); 134 BOOL deleteChild(LLXMLNode* child);
131 void addChild(LLXMLNodePtr new_parent); 135 void addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child = LLXMLNodePtr(NULL));
132 void setParent(LLXMLNodePtr new_parent); // reparent if necessary 136 void setParent(LLXMLNodePtr new_parent); // reparent if necessary
133 137
134 // Serialization 138 // Serialization
@@ -146,8 +150,9 @@ public:
146 LLXMLNodePtr& node, 150 LLXMLNodePtr& node,
147 LLXMLNode* defaults); 151 LLXMLNode* defaults);
148 static bool updateNode( 152 static bool updateNode(
149 LLXMLNodePtr& node, 153 LLXMLNodePtr& node,
150 LLXMLNodePtr& update_node); 154 LLXMLNodePtr& update_node);
155 static LLXMLNodePtr replaceNode(LLXMLNodePtr node, LLXMLNodePtr replacement_node);
151 static void writeHeaderToFile(LLFILE *fOut); 156 static void writeHeaderToFile(LLFILE *fOut);
152 void writeToFile(LLFILE *fOut, const std::string& indent = std::string()); 157 void writeToFile(LLFILE *fOut, const std::string& indent = std::string());
153 void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string()); 158 void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string());
@@ -176,6 +181,10 @@ public:
176 181
177 BOOL hasAttribute(const char* name ); 182 BOOL hasAttribute(const char* name );
178 183
184 // these are designed to be more generic versions of the functions
185 // rather than relying on LL-types
186 bool getAttribute_bool(const char* name, bool& value );
187
179 BOOL getAttributeBOOL(const char* name, BOOL& value ); 188 BOOL getAttributeBOOL(const char* name, BOOL& value );
180 BOOL getAttributeU8(const char* name, U8& value ); 189 BOOL getAttributeU8(const char* name, U8& value );
181 BOOL getAttributeS8(const char* name, S8& value ); 190 BOOL getAttributeS8(const char* name, S8& value );
@@ -211,13 +220,16 @@ public:
211 bool getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); 220 bool getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
212 void getChildren(const char* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const; 221 void getChildren(const char* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const;
213 void getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const; 222 void getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const;
223
224 // recursively finds all children at any level matching name
225 void getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const;
214 226
215 bool getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); 227 bool getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
216 bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE); 228 bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
217 229
218 // The following skip over attributes 230 // The following skip over attributes
219 LLXMLNodePtr getFirstChild(); 231 LLXMLNodePtr getFirstChild() const;
220 LLXMLNodePtr getNextSibling(); 232 LLXMLNodePtr getNextSibling() const;
221 233
222 LLXMLNodePtr getRoot(); 234 LLXMLNodePtr getRoot();
223 235
@@ -251,7 +263,6 @@ public:
251 void setName(LLStringTableEntry* name); 263 void setName(LLStringTableEntry* name);
252 264
253 // Escapes " (quot) ' (apos) & (amp) < (lt) > (gt) 265 // Escapes " (quot) ' (apos) & (amp) < (lt) > (gt)
254 // TomY TODO: Make this private
255 static std::string escapeXML(const std::string& xml); 266 static std::string escapeXML(const std::string& xml);
256 267
257 // Set the default node corresponding to this default node 268 // Set the default node corresponding to this default node
@@ -291,7 +302,7 @@ public:
291 Encoding mEncoding; // The value encoding 302 Encoding mEncoding; // The value encoding
292 303
293 LLXMLNode* mParent; // The parent node 304 LLXMLNode* mParent; // The parent node
294 LLXMLChildren* mChildren; // The child nodes 305 LLXMLChildrenPtr mChildren; // The child nodes
295 LLXMLAttribList mAttributes; // The attribute nodes 306 LLXMLAttribList mAttributes; // The attribute nodes
296 LLXMLNodePtr mPrev; // Double-linked list previous node 307 LLXMLNodePtr mPrev; // Double-linked list previous node
297 LLXMLNodePtr mNext; // Double-linked list next node 308 LLXMLNodePtr mNext; // Double-linked list next node
diff --git a/linden/indra/llxml/llxmlparser.cpp b/linden/indra/llxml/llxmlparser.cpp
index 3e87947..7d887f4 100644
--- a/linden/indra/llxml/llxmlparser.cpp
+++ b/linden/indra/llxml/llxmlparser.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llxml/llxmlparser.h b/linden/indra/llxml/llxmlparser.h
index 325bf04..d7595f6 100644
--- a/linden/indra/llxml/llxmlparser.h
+++ b/linden/indra/llxml/llxmlparser.h
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llxml/llxmltree.cpp b/linden/indra/llxml/llxmltree.cpp
index bd1e743..1bce5d2 100644
--- a/linden/indra/llxml/llxmltree.cpp
+++ b/linden/indra/llxml/llxmltree.cpp
@@ -17,7 +17,8 @@
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 22 *
22 * By copying, modifying or distributing this software, you acknowledge 23 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 24 * that you have read and understood your obligations described above,
diff --git a/linden/indra/llxml/llxmltree.h b/linden/indra/llxml/llxmltree.h
index 23ec57d..1a020f2 100644
--- a/linden/indra/llxml/llxmltree.h
+++ b/linden/indra/llxml/llxmltree.h
@@ -18,7 +18,8 @@
18 * There are special exceptions to the terms and conditions of the GPL as 18 * There are special exceptions to the terms and conditions of the GPL as
19 * it is applied to this Source Code. View the full text of the exception 19 * it is applied to this Source Code. View the full text of the exception
20 * in the file doc/FLOSS-exception.txt in this software distribution, or 20 * in the file doc/FLOSS-exception.txt in this software distribution, or
21 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception 21 * online at
22 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 * 23 *
23 * By copying, modifying or distributing this software, you acknowledge 24 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above, 25 * that you have read and understood your obligations described above,