summaryrefslogtreecommitdiff
path: root/indra/llxml
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llxml')
-rw-r--r--indra/llxml/llxmlnode.cpp185
-rw-r--r--indra/llxml/llxmlnode.h26
2 files changed, 175 insertions, 36 deletions
diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp
index 750c1fc1ef..aef1488e51 100644
--- a/indra/llxml/llxmlnode.cpp
+++ b/indra/llxml/llxmlnode.cpp
@@ -65,6 +65,9 @@ LLXMLNode::LLXMLNode() :
mEncoding(ENCODING_DEFAULT),
mParent(NULL),
mChildren(NULL),
+ mAttributes(),
+ mPrev(NULL),
+ mNext(NULL),
mName(NULL),
mValue(""),
mDefault(NULL)
@@ -83,6 +86,9 @@ LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) :
mEncoding(ENCODING_DEFAULT),
mParent(NULL),
mChildren(NULL),
+ mAttributes(),
+ mPrev(NULL),
+ mNext(NULL),
mValue(""),
mDefault(NULL)
{
@@ -101,17 +107,65 @@ LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) :
mEncoding(ENCODING_DEFAULT),
mParent(NULL),
mChildren(NULL),
+ mAttributes(),
+ mPrev(NULL),
+ mNext(NULL),
mName(name),
mValue(""),
mDefault(NULL)
{
}
+// copy constructor (except for the children)
+LLXMLNode::LLXMLNode(const LLXMLNode& rhs) :
+ mID(rhs.mID),
+ mIsAttribute(rhs.mIsAttribute),
+ mVersionMajor(rhs.mVersionMajor),
+ mVersionMinor(rhs.mVersionMinor),
+ mLength(rhs.mLength),
+ mPrecision(rhs.mPrecision),
+ mType(rhs.mType),
+ mEncoding(rhs.mEncoding),
+ mParent(NULL),
+ mChildren(NULL),
+ mAttributes(),
+ mPrev(NULL),
+ mNext(NULL),
+ mName(rhs.mName),
+ mValue(rhs.mValue),
+ mDefault(rhs.mDefault)
+{
+}
+
+// returns a new copy of this node and all its children
+LLXMLNodePtr LLXMLNode::deepCopy()
+{
+ LLXMLNodePtr newnode = LLXMLNodePtr(new LLXMLNode(*this));
+ if (mChildren.notNull())
+ {
+ for (LLXMLChildList::iterator iter = mChildren->map.begin();
+ iter != mChildren->map.end(); ++iter)
+ {
+ newnode->addChild(iter->second->deepCopy());
+ }
+ }
+ for (LLXMLAttribList::iterator iter = mAttributes.begin();
+ iter != mAttributes.end(); ++iter)
+ {
+ newnode->addChild(iter->second->deepCopy());
+ }
+
+ return newnode;
+}
+
// virtual
LLXMLNode::~LLXMLNode()
{
// Strictly speaking none of this should be required execept 'delete mChildren'...
- if (mChildren)
+ // Sadly, that's only true if we hadn't had reference-counted smart pointers linked
+ // in three different directions. This entire class is a frightening, hard-to-maintain
+ // mess.
+ if (mChildren.notNull())
{
for (LLXMLChildList::iterator iter = mChildren->map.begin();
iter != mChildren->map.end(); ++iter)
@@ -124,7 +178,7 @@ LLXMLNode::~LLXMLNode()
mChildren->map.clear();
mChildren->head = NULL;
mChildren->tail = NULL;
- delete mChildren;
+ mChildren = NULL;
}
for (LLXMLAttribList::iterator iter = mAttributes.begin();
iter != mAttributes.end(); ++iter)
@@ -160,7 +214,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child)
return TRUE;
}
}
- else if (mChildren)
+ else if (mChildren.notNull())
{
LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName);
while (children_itr != mChildren->map.end())
@@ -183,7 +237,6 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child)
mChildren->map.erase(children_itr);
if (mChildren->map.empty())
{
- delete mChildren;
mChildren = NULL;
}
return TRUE;
@@ -201,7 +254,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child)
return FALSE;
}
-void LLXMLNode::addChild(LLXMLNodePtr new_child)
+void LLXMLNode::addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child)
{
if (new_child->mParent != NULL)
{
@@ -219,7 +272,7 @@ void LLXMLNode::addChild(LLXMLNodePtr new_child)
}
else
{
- if (!mChildren)
+ if (mChildren.isNull())
{
mChildren = new LLXMLChildren();
mChildren->head = new_child;
@@ -227,11 +280,33 @@ void LLXMLNode::addChild(LLXMLNodePtr new_child)
}
mChildren->map.insert(std::make_pair(new_child->mName, new_child));
- if (mChildren->tail != new_child)
+ // if after_child is specified, it damn well better be in the list of children
+ // for this node. I'm not going to assert that, because it would be expensive,
+ // but don't specify that parameter if you didn't get the value for it from the
+ // list of children of this node!
+ if (after_child.isNull())
{
- mChildren->tail->mNext = new_child;
- new_child->mPrev = mChildren->tail;
- mChildren->tail = new_child;
+ if (mChildren->tail != new_child)
+ {
+ mChildren->tail->mNext = new_child;
+ new_child->mPrev = mChildren->tail;
+ mChildren->tail = new_child;
+ }
+ }
+ else
+ {
+ if (after_child->mNext.notNull())
+ {
+ // if after_child was not the last item, fix up some pointers
+ after_child->mNext->mPrev = new_child;
+ new_child->mNext = after_child->mNext;
+ }
+ new_child->mPrev = after_child;
+ after_child->mNext = new_child;
+ if (mChildren->tail == after_child)
+ {
+ mChildren->tail = new_child;
+ }
}
}
@@ -293,7 +368,7 @@ void LLXMLNode::updateDefault()
}
}
- if (mChildren)
+ if (mChildren.notNull())
{
LLXMLChildList::const_iterator children_itr;
LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -566,6 +641,24 @@ bool LLXMLNode::updateNode(
}
+// static
+LLXMLNodePtr LLXMLNode::replaceNode(LLXMLNodePtr node, LLXMLNodePtr update_node)
+{
+ if (!node || !update_node)
+ {
+ llwarns << "Node invalid" << llendl;
+ return node;
+ }
+
+ LLXMLNodePtr cloned_node = update_node->deepCopy();
+ node->mParent->addChild(cloned_node, node); // add after node
+ LLXMLNodePtr parent = node->mParent;
+ parent->removeChild(node);
+ parent->updateDefault();
+
+ return cloned_node;
+}
+
// static
@@ -618,7 +711,7 @@ bool LLXMLNode::parseBuffer(
{
llwarns << "Error parsing xml error code: "
<< XML_ErrorString(XML_GetErrorCode(my_parser))
- << " on lne " << XML_GetCurrentLineNumber(my_parser)
+ << " on line " << XML_GetCurrentLineNumber(my_parser)
<< llendl;
}
@@ -722,7 +815,7 @@ BOOL LLXMLNode::isFullyDefault()
&& has_default_length
&& has_default_attribute)
{
- if (mChildren)
+ if (mChildren.notNull())
{
LLXMLChildList::const_iterator children_itr;
LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -888,7 +981,7 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i
}
}
- if (!mChildren && mValue == "")
+ if (mChildren.isNull() && mValue == "")
{
output_stream << " />\n";
return;
@@ -896,7 +989,7 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i
else
{
output_stream << ">\n";
- if (mChildren)
+ if (mChildren.notNull())
{
// stream non-attributes
std::string next_indent = indent + "\t";
@@ -922,7 +1015,7 @@ void LLXMLNode::findName(const std::string& name, LLXMLNodeList &results)
results.insert(std::make_pair(this->mName->mString, this));
return;
}
- if (mChildren)
+ if (mChildren.notNull())
{
LLXMLChildList::const_iterator children_itr;
LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -941,7 +1034,7 @@ void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results)
results.insert(std::make_pair(this->mName->mString, this));
return;
}
- if (mChildren)
+ if (mChildren.notNull())
{
LLXMLChildList::const_iterator children_itr;
LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -960,7 +1053,7 @@ void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results)
results.insert(std::make_pair(this->mName->mString, this));
return;
}
- if (mChildren)
+ if (mChildren.notNull())
{
LLXMLChildList::const_iterator children_itr;
LLXMLChildList::const_iterator children_end = mChildren->map.end();
@@ -974,11 +1067,11 @@ void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results)
void LLXMLNode::scrubToTree(LLXMLNode *tree)
{
- if (!tree || !tree->mChildren)
+ if (!tree || tree->mChildren.isNull())
{
return;
}
- if (mChildren)
+ if (mChildren.notNull())
{
std::vector<LLXMLNodePtr> to_delete_list;
LLXMLChildList::iterator itor = mChildren->map.begin();
@@ -1023,7 +1116,7 @@ bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, BOOL use_default_
bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
{
- if (mChildren)
+ if (mChildren.notNull())
{
LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
if (child_itr != mChildren->map.end())
@@ -1047,7 +1140,7 @@ void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, BOOL use_
void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing) const
{
- if (mChildren)
+ if (mChildren.notNull())
{
LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
if (child_itr != mChildren->map.end())
@@ -1071,6 +1164,25 @@ void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &child
}
}
+// recursively walks the tree and returns all children at all nesting levels matching the name
+void LLXMLNode::getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const
+{
+ if (mChildren.notNull())
+ {
+ for (LLXMLChildList::const_iterator child_itr = mChildren->map.begin();
+ child_itr != mChildren->map.end(); ++child_itr)
+ {
+ LLXMLNodePtr child = (*child_itr).second;
+ if (name == child->mName)
+ {
+ children.insert(std::make_pair(child->mName->mString, child));
+ }
+ // and check each child as well
+ child->getDescendants(name, children);
+ }
+ }
+}
+
bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing)
{
return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing);
@@ -1111,6 +1223,23 @@ BOOL LLXMLNode::hasAttribute(const char* name )
return getAttribute(name, node);
}
+// the structure of these getAttribute_ functions is ugly, but it's because the
+// underlying system is based on BOOL and LLString; if we change
+// so that they're based on more generic mechanisms, these will be
+// simplified.
+bool LLXMLNode::getAttribute_bool(const char* name, bool& value )
+{
+ LLXMLNodePtr node;
+ if (!getAttribute(name, node))
+ {
+ return false;
+ }
+ BOOL temp;
+ bool retval = node->getBoolValue(1, &temp);
+ value = temp;
+ return retval;
+}
+
BOOL LLXMLNode::getAttributeBOOL(const char* name, BOOL& value )
{
LLXMLNodePtr node;
@@ -2521,7 +2650,7 @@ void LLXMLNode::setName(LLStringTableEntry* name)
U32 LLXMLNode::getChildCount() const
{
- if (mChildren)
+ if (mChildren.notNull())
{
return mChildren->map.size();
}
@@ -2540,7 +2669,7 @@ U32 get_rand(U32 max_value)
LLXMLNode *get_rand_node(LLXMLNode *node)
{
- if (node->mChildren)
+ if (node->mChildren.notNull())
{
U32 num_children = node->mChildren->map.size();
if (get_rand(2) == 0)
@@ -2748,7 +2877,7 @@ void LLXMLNode::createUnitTest(S32 max_num_children)
BOOL LLXMLNode::performUnitTest(std::string &error_buffer)
{
- if (!mChildren)
+ if (mChildren.isNull())
{
error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString));
return FALSE;
@@ -3007,14 +3136,14 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer)
return TRUE;
}
-LLXMLNodePtr LLXMLNode::getFirstChild()
+LLXMLNodePtr LLXMLNode::getFirstChild() const
{
- if (!mChildren) return NULL;
+ if (mChildren.isNull()) return NULL;
LLXMLNodePtr ret = mChildren->head;
return ret;
}
-LLXMLNodePtr LLXMLNode::getNextSibling()
+LLXMLNodePtr LLXMLNode::getNextSibling() const
{
LLXMLNodePtr ret = mNext;
return ret;
diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h
index 5ca726effe..dec225dde6 100644
--- a/indra/llxml/llxmlnode.h
+++ b/indra/llxml/llxmlnode.h
@@ -87,12 +87,13 @@ class LLVector3d;
class LLVector4;
class LLVector4U;
-struct LLXMLChildren
+struct LLXMLChildren : public LLThreadSafeRefCount
{
LLXMLChildList map; // Map of children names->pointers
LLXMLNodePtr head; // Head of the double-linked list
LLXMLNodePtr tail; // Tail of the double-linked list
};
+typedef LLPointer<LLXMLChildren> LLXMLChildrenPtr;
class LLXMLNode : public LLThreadSafeRefCount
{
@@ -124,11 +125,13 @@ public:
LLXMLNode();
LLXMLNode(const char* name, BOOL is_attribute);
LLXMLNode(LLStringTableEntry* name, BOOL is_attribute);
+ LLXMLNode(const LLXMLNode& rhs);
+ LLXMLNodePtr deepCopy();
BOOL isNull();
BOOL deleteChild(LLXMLNode* child);
- void addChild(LLXMLNodePtr new_parent);
+ void addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child = LLXMLNodePtr(NULL));
void setParent(LLXMLNodePtr new_parent); // reparent if necessary
// Serialization
@@ -146,8 +149,9 @@ public:
LLXMLNodePtr& node,
LLXMLNode* defaults);
static bool updateNode(
- LLXMLNodePtr& node,
- LLXMLNodePtr& update_node);
+ LLXMLNodePtr& node,
+ LLXMLNodePtr& update_node);
+ static LLXMLNodePtr replaceNode(LLXMLNodePtr node, LLXMLNodePtr replacement_node);
static void writeHeaderToFile(LLFILE *fOut);
void writeToFile(LLFILE *fOut, const std::string& indent = std::string());
void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string());
@@ -176,6 +180,10 @@ public:
BOOL hasAttribute(const char* name );
+ // these are designed to be more generic versions of the functions
+ // rather than relying on LL-types
+ bool getAttribute_bool(const char* name, bool& value );
+
BOOL getAttributeBOOL(const char* name, BOOL& value );
BOOL getAttributeU8(const char* name, U8& value );
BOOL getAttributeS8(const char* name, S8& value );
@@ -211,13 +219,16 @@ public:
bool getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
void getChildren(const char* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const;
void getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const;
+
+ // recursively finds all children at any level matching name
+ void getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const;
bool getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
// The following skip over attributes
- LLXMLNodePtr getFirstChild();
- LLXMLNodePtr getNextSibling();
+ LLXMLNodePtr getFirstChild() const;
+ LLXMLNodePtr getNextSibling() const;
LLXMLNodePtr getRoot();
@@ -251,7 +262,6 @@ public:
void setName(LLStringTableEntry* name);
// Escapes " (quot) ' (apos) & (amp) < (lt) > (gt)
- // TomY TODO: Make this private
static std::string escapeXML(const std::string& xml);
// Set the default node corresponding to this default node
@@ -291,7 +301,7 @@ public:
Encoding mEncoding; // The value encoding
LLXMLNode* mParent; // The parent node
- LLXMLChildren* mChildren; // The child nodes
+ LLXMLChildrenPtr mChildren; // The child nodes
LLXMLAttribList mAttributes; // The attribute nodes
LLXMLNodePtr mPrev; // Double-linked list previous node
LLXMLNodePtr mNext; // Double-linked list next node