diff options
Diffstat (limited to 'indra/llxml/llxmlnode.cpp')
-rw-r--r-- | indra/llxml/llxmlnode.cpp | 288 |
1 files changed, 197 insertions, 91 deletions
diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 800b13573f..07cc612a0a 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -47,6 +47,7 @@ #include "llquaternion.h" #include "llstring.h" #include "lluuid.h" +#include "lldir.h" const S32 MAX_COLUMN_WIDTH = 80; @@ -64,6 +65,7 @@ LLXMLNode::LLXMLNode() : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -85,6 +87,7 @@ LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -106,6 +109,7 @@ LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) : mPrecision(64), mType(TYPE_CONTAINER), mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), mParent(NULL), mChildren(NULL), mAttributes(), @@ -145,7 +149,7 @@ LLXMLNodePtr LLXMLNode::deepCopy() if (mChildren.notNull()) { for (LLXMLChildList::iterator iter = mChildren->map.begin(); - iter != mChildren->map.end(); ++iter) + iter != mChildren->map.end(); ++iter) { newnode->addChild(iter->second->deepCopy()); } @@ -226,6 +230,10 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) { mChildren->head = target_child->mNext; } + if (target_child == mChildren->tail) + { + mChildren->tail = target_child->mPrev; + } LLXMLNodePtr prev = target_child->mPrev; LLXMLNodePtr next = target_child->mNext; @@ -294,6 +302,22 @@ void LLXMLNode::addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child) mChildren->tail = new_child; } } + // if after_child == parent, then put new_child at beginning + else if (after_child == this) + { + // add to front of list + new_child->mNext = mChildren->head; + if (mChildren->head) + { + mChildren->head->mPrev = new_child; + mChildren->head = new_child; + } + else // no children + { + mChildren->head = new_child; + mChildren->tail = new_child; + } + } else { if (after_child->mNext.notNull()) @@ -387,6 +411,7 @@ void XMLCALL StartXMLNode(void *userData, { // Create a new node LLXMLNode *new_node_ptr = new LLXMLNode(name, FALSE); + LLXMLNodePtr new_node = new_node_ptr; new_node->mID.clear(); LLXMLNodePtr ptr_new_node = new_node; @@ -401,7 +426,8 @@ void XMLCALL StartXMLNode(void *userData, } new_node_ptr->mParser = parent->mParser; - + new_node_ptr->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); + // Set the current active node to the new node XML_Parser *parser = parent->mParser; XML_SetUserData(*parser, (void *)new_node_ptr); @@ -492,6 +518,7 @@ void XMLCALL StartXMLNode(void *userData, if (!new_node->getAttribute(attr_name.c_str(), attr_node, FALSE)) { attr_node = new LLXMLNode(attr_name.c_str(), TRUE); + attr_node->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); } attr_node->setValue(attr_value); new_node->addChild(attr_node); @@ -836,12 +863,66 @@ BOOL LLXMLNode::isFullyDefault() } // static -void LLXMLNode::writeHeaderToFile(LLFILE *fOut) +bool LLXMLNode::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root, + const std::vector<std::string>& paths) { - fprintf(fOut, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n"); + std::string full_filename = gDirUtilp->findSkinnedFilename(paths.front(), xui_filename); + if (full_filename.empty()) + { + return false; + } + + if (!LLXMLNode::parseFile(full_filename, root, NULL)) + { + // try filename as passed in since sometimes we load an xml file from a user-supplied path + if (!LLXMLNode::parseFile(xui_filename, root, NULL)) + { + llwarns << "Problem reading UI description file: " << xui_filename << llendl; + return false; + } + } + + LLXMLNodePtr updateRoot; + + std::vector<std::string>::const_iterator itor; + + for (itor = paths.begin(), ++itor; itor != paths.end(); ++itor) + { + std::string nodeName; + std::string updateName; + + std::string layer_filename = gDirUtilp->findSkinnedFilename((*itor), xui_filename); + if(layer_filename.empty()) + { + // no localized version of this file, that's ok, keep looking + continue; + } + + if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL)) + { + llwarns << "Problem reading localized UI description file: " << (*itor) + gDirUtilp->getDirDelimiter() + xui_filename << llendl; + return false; + } + + updateRoot->getAttributeString("name", updateName); + root->getAttributeString("name", nodeName); + + if (updateName == nodeName) + { + LLXMLNode::updateNode(root, updateRoot); + } + } + + return true; } -void LLXMLNode::writeToFile(LLFILE *fOut, const std::string& indent) +// static +void LLXMLNode::writeHeaderToFile(LLFILE *out_file) +{ + fprintf(out_file, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n"); +} + +void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations) { if (isFullyDefault()) { @@ -850,15 +931,16 @@ void LLXMLNode::writeToFile(LLFILE *fOut, const std::string& indent) } std::ostringstream ostream; - writeToOstream(ostream, indent); + writeToOstream(ostream, indent, use_type_decorations); std::string outstring = ostream.str(); - if (fwrite(outstring.c_str(), 1, outstring.length(), fOut) != outstring.length()) + size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file); + if (written != outstring.length()) { llwarns << "Short write" << llendl; } } -void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent) +void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent, bool use_type_decorations) { if (isFullyDefault()) { @@ -872,84 +954,86 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i BOOL has_default_length = mDefault.isNull()?FALSE:(mLength == mDefault->mLength); // stream the name - output_stream << indent << "<" << mName->mString; + output_stream << indent << "<" << mName->mString << "\n"; - // ID - if (mID != "") + if (use_type_decorations) { - output_stream << " id=\"" << mID << "\""; - } + // ID + if (mID != "") + { + output_stream << indent << " id=\"" << mID << "\"\n"; + } - // Type - if (!has_default_type) - { - switch (mType) + // Type + if (!has_default_type) { - case TYPE_BOOLEAN: - output_stream << " type=\"boolean\""; - break; - case TYPE_INTEGER: - output_stream << " type=\"integer\""; - break; - case TYPE_FLOAT: - output_stream << " type=\"float\""; - break; - case TYPE_STRING: - output_stream << " type=\"string\""; - break; - case TYPE_UUID: - output_stream << " type=\"uuid\""; - break; - case TYPE_NODEREF: - output_stream << " type=\"noderef\""; - break; - default: - // default on switch(enum) eliminates a warning on linux - break; - }; - } + switch (mType) + { + case TYPE_BOOLEAN: + output_stream << indent << " type=\"boolean\"\n"; + break; + case TYPE_INTEGER: + output_stream << indent << " type=\"integer\"\n"; + break; + case TYPE_FLOAT: + output_stream << indent << " type=\"float\"\n"; + break; + case TYPE_STRING: + output_stream << indent << " type=\"string\"\n"; + break; + case TYPE_UUID: + output_stream << indent << " type=\"uuid\"\n"; + break; + case TYPE_NODEREF: + output_stream << indent << " type=\"noderef\"\n"; + break; + default: + // default on switch(enum) eliminates a warning on linux + break; + }; + } - // Encoding - if (!has_default_encoding) - { - switch (mEncoding) + // Encoding + if (!has_default_encoding) { - case ENCODING_DECIMAL: - output_stream << " encoding=\"decimal\""; - break; - case ENCODING_HEX: - output_stream << " encoding=\"hex\""; - break; - /*case ENCODING_BASE32: - output_stream << " encoding=\"base32\""; - break;*/ - default: - // default on switch(enum) eliminates a warning on linux - break; - }; - } + switch (mEncoding) + { + case ENCODING_DECIMAL: + output_stream << indent << " encoding=\"decimal\"\n"; + break; + case ENCODING_HEX: + output_stream << indent << " encoding=\"hex\"\n"; + break; + /*case ENCODING_BASE32: + output_stream << indent << " encoding=\"base32\"\n"; + break;*/ + default: + // default on switch(enum) eliminates a warning on linux + break; + }; + } - // Precision - if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT)) - { - output_stream << " precision=\"" << mPrecision << "\""; - } + // Precision + if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT)) + { + output_stream << indent << " precision=\"" << mPrecision << "\"\n"; + } - // Version - if (mVersionMajor > 0 || mVersionMinor > 0) - { - output_stream << " version=\"" << mVersionMajor << "." << mVersionMinor << "\""; - } + // Version + if (mVersionMajor > 0 || mVersionMinor > 0) + { + output_stream << indent << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"\n"; + } - // Array length - if (!has_default_length && mLength > 0) - { - output_stream << " length=\"" << mLength << "\""; + // Array length + if (!has_default_length && mLength > 0) + { + output_stream << indent << " length=\"" << mLength << "\"\n"; + } } { // Write out attributes - S32 col_pos = 0; LLXMLAttribList::const_iterator attr_itr; LLXMLAttribList::const_iterator attr_end = mAttributes.end(); for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr) @@ -958,12 +1042,13 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue) { std::string attr = child->mName->mString; - if (attr == "id" || - attr == "type" || - attr == "encoding" || - attr == "precision" || - attr == "version" || - attr == "length") + if (use_type_decorations + && (attr == "id" || + attr == "type" || + attr == "encoding" || + attr == "precision" || + attr == "version" || + attr == "length")) { continue; // skip built-in attributes } @@ -971,17 +1056,14 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i std::string attr_str = llformat(" %s=\"%s\"", attr.c_str(), escapeXML(child->mValue).c_str()); - if (col_pos + (S32)attr_str.length() > MAX_COLUMN_WIDTH) - { - output_stream << "\n" << indent << " "; - col_pos = 4; - } - col_pos += attr_str.length(); - output_stream << attr_str; + output_stream << indent << attr_str << "\n"; } } } + // erase last \n before attaching final > or /> + output_stream.seekp(-1, std::ios::cur); + if (mChildren.isNull() && mValue == "") { output_stream << " />\n"; @@ -993,16 +1075,16 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i if (mChildren.notNull()) { // stream non-attributes - std::string next_indent = indent + "\t"; + std::string next_indent = indent + " "; for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling()) { - child->writeToOstream(output_stream, next_indent); + child->writeToOstream(output_stream, next_indent, use_type_decorations); } } if (!mValue.empty()) { std::string contents = getTextContents(); - output_stream << indent << "\t" << escapeXML(contents) << "\n"; + output_stream << indent << " " << escapeXML(contents) << "\n"; } output_stream << indent << "</" << mName->mString << ">\n"; } @@ -2475,14 +2557,15 @@ std::string LLXMLNode::escapeXML(const std::string& xml) return out; } -void LLXMLNode::setStringValue(U32 length, const std::string *array) +void LLXMLNode::setStringValue(U32 length, const std::string *strings) { if (length == 0) return; std::string new_value; for (U32 pos=0; pos<length; ++pos) { - new_value.append(escapeXML(array[pos])); + // *NOTE: Do not escape strings here - do it on output + new_value.append( strings[pos] ); if (pos < length-1) new_value.append(" "); } @@ -3150,6 +3233,19 @@ LLXMLNodePtr LLXMLNode::getNextSibling() const return ret; } +std::string LLXMLNode::getSanitizedValue() const +{ + if (mIsAttribute) + { + return getValue() ; + } + else + { + return getTextContents(); + } +} + + std::string LLXMLNode::getTextContents() const { std::string msg; @@ -3215,3 +3311,13 @@ std::string LLXMLNode::getTextContents() const } return msg; } + +void LLXMLNode::setLineNumber(S32 line_number) +{ + mLineNumber = line_number; +} + +S32 LLXMLNode::getLineNumber() +{ + return mLineNumber; +} |