From 088f2f4f6545ebc2ee01945938a40ae5c87ad27a Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 17 Feb 2024 00:51:13 +0100 Subject: More BOOL to bool replacements primarily in llappearance and llxml --- indra/llxml/llxmlnode.cpp | 265 ++++++++++++++++++++++------------------------ 1 file changed, 124 insertions(+), 141 deletions(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 455df13e48..9c7ac66f01 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -44,13 +44,13 @@ #include "lldir.h" // static -BOOL LLXMLNode::sStripEscapedStrings = TRUE; -BOOL LLXMLNode::sStripWhitespaceValues = FALSE; +bool LLXMLNode::sStripEscapedStrings = true; +bool LLXMLNode::sStripWhitespaceValues = false; LLXMLNode::LLXMLNode() : mID(""), mParser(NULL), - mIsAttribute(FALSE), + mIsAttribute(false), mVersionMajor(0), mVersionMinor(0), mLength(0), @@ -69,7 +69,7 @@ LLXMLNode::LLXMLNode() : { } -LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) : +LLXMLNode::LLXMLNode(const char* name, bool is_attribute) : mID(""), mParser(NULL), mIsAttribute(is_attribute), @@ -91,7 +91,7 @@ LLXMLNode::LLXMLNode(const char* name, BOOL is_attribute) : mName = gStringTable.addStringEntry(name); } -LLXMLNode::LLXMLNode(LLStringTableEntry* name, BOOL is_attribute) : +LLXMLNode::LLXMLNode(LLStringTableEntry* name, bool is_attribute) : mID(""), mParser(NULL), mIsAttribute(is_attribute), @@ -193,17 +193,17 @@ LLXMLNode::~LLXMLNode() mDefault = NULL; } -BOOL LLXMLNode::isNull() +bool LLXMLNode::isNull() { return (mName == NULL); } // protected -BOOL LLXMLNode::removeChild(LLXMLNode *target_child) +bool LLXMLNode::removeChild(LLXMLNode *target_child) { if (!target_child) { - return FALSE; + return false; } if (target_child->mIsAttribute) { @@ -212,7 +212,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) { target_child->mParent = NULL; mAttributes.erase(children_itr); - return TRUE; + return true; } } else if (mChildren.notNull()) @@ -244,7 +244,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) { mChildren = NULL; } - return TRUE; + return true; } else if (children_itr->first != target_child->mName) { @@ -256,7 +256,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) } } } - return FALSE; + return false; } void LLXMLNode::addChild(LLXMLNodePtr& new_child) @@ -302,13 +302,13 @@ void LLXMLNode::addChild(LLXMLNodePtr& new_child) } // virtual -LLXMLNodePtr LLXMLNode::createChild(const char* name, BOOL is_attribute) +LLXMLNodePtr LLXMLNode::createChild(const char* name, bool is_attribute) { return createChild(gStringTable.addStringEntry(name), is_attribute); } // virtual -LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, BOOL is_attribute) +LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, bool is_attribute) { LLXMLNodePtr ret(new LLXMLNode(name, is_attribute)); ret->mID.clear(); @@ -317,13 +317,13 @@ LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, BOOL is_attribute) return ret; } -BOOL LLXMLNode::deleteChild(LLXMLNode *child) +bool LLXMLNode::deleteChild(LLXMLNode *child) { if (removeChild(child)) { - return TRUE; + return true; } - return FALSE; + return false; } void LLXMLNode::setParent(LLXMLNodePtr& new_parent) @@ -375,7 +375,7 @@ void XMLCALL StartXMLNode(void *userData, const XML_Char **atts) { // Create a new node - LLXMLNode *new_node_ptr = new LLXMLNode(name, FALSE); + LLXMLNode *new_node_ptr = new LLXMLNode(name, false); LLXMLNodePtr new_node = new_node_ptr; new_node->mID.clear(); @@ -480,9 +480,9 @@ void XMLCALL StartXMLNode(void *userData, // only one attribute child per description LLXMLNodePtr attr_node; - if (!new_node->getAttribute(attr_name.c_str(), attr_node, FALSE)) + if (!new_node->getAttribute(attr_name.c_str(), attr_node, false)) { - attr_node = new LLXMLNode(attr_name.c_str(), TRUE); + attr_node = new LLXMLNode(attr_name.c_str(), true); attr_node->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); } attr_node->setValue(attr_value); @@ -508,13 +508,13 @@ void XMLCALL EndXMLNode(void *userData, if (LLXMLNode::sStripWhitespaceValues) { std::string value = node->getValue(); - BOOL is_empty = TRUE; + bool is_empty = true; for (std::string::size_type s = 0; s < value.length(); s++) { char c = value[s]; if (c != ' ' && c != '\t' && c != '\n') { - is_empty = FALSE; + is_empty = false; break; } } @@ -575,7 +575,7 @@ bool LLXMLNode::updateNode( if (!node || !update_node) { LL_WARNS() << "Node invalid" << LL_ENDL; - return FALSE; + return false; } //update the node value @@ -647,7 +647,7 @@ bool LLXMLNode::updateNode( } } - return TRUE; + return true; } // static @@ -688,7 +688,7 @@ bool LLXMLNode::parseBuffer( XML_SetCharacterDataHandler(my_parser, XMLData); // Create a root node - LLXMLNode *file_node_ptr = new LLXMLNode("XML", FALSE); + LLXMLNode *file_node_ptr = new LLXMLNode("XML", false); LLXMLNodePtr file_node = file_node_ptr; file_node->mParser = &my_parser; @@ -696,7 +696,7 @@ bool LLXMLNode::parseBuffer( XML_SetUserData(my_parser, (void *)file_node_ptr); // Do the parsing - if (XML_Parse(my_parser, (const char *)buffer, length, TRUE) != XML_STATUS_OK) + if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK) { LL_WARNS() << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) @@ -736,7 +736,7 @@ bool LLXMLNode::parseStream( XML_SetCharacterDataHandler(my_parser, XMLData); // Create a root node - LLXMLNode *file_node_ptr = new LLXMLNode("XML", FALSE); + LLXMLNode *file_node_ptr = new LLXMLNode("XML", false); LLXMLNodePtr file_node = file_node_ptr; file_node->mParser = &my_parser; @@ -784,18 +784,18 @@ bool LLXMLNode::parseStream( } -BOOL LLXMLNode::isFullyDefault() +bool LLXMLNode::isFullyDefault() { if (mDefault.isNull()) { - return FALSE; + return false; } - BOOL has_default_value = (mValue == mDefault->mValue); - BOOL has_default_attribute = (mIsAttribute == mDefault->mIsAttribute); - BOOL has_default_type = mIsAttribute || (mType == mDefault->mType); - BOOL has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding); - BOOL has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision); - BOOL has_default_length = mIsAttribute || (mLength == mDefault->mLength); + bool has_default_value = (mValue == mDefault->mValue); + bool has_default_attribute = (mIsAttribute == mDefault->mIsAttribute); + bool has_default_type = mIsAttribute || (mType == mDefault->mType); + bool has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding); + bool has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision); + bool has_default_length = mIsAttribute || (mLength == mDefault->mLength); if (has_default_value && has_default_type @@ -813,14 +813,14 @@ BOOL LLXMLNode::isFullyDefault() LLXMLNodePtr child = (*children_itr).second; if (!child->isFullyDefault()) { - return FALSE; + return false; } } } - return TRUE; + return true; } - return FALSE; + return false; } // static @@ -908,10 +908,10 @@ void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& i return; } - BOOL has_default_type = mDefault.isNull()?FALSE:(mType == mDefault->mType); - BOOL has_default_encoding = mDefault.isNull()?FALSE:(mEncoding == mDefault->mEncoding); - BOOL has_default_precision = mDefault.isNull()?FALSE:(mPrecision == mDefault->mPrecision); - BOOL has_default_length = mDefault.isNull()?FALSE:(mLength == mDefault->mLength); + bool has_default_type = mDefault.isNull()?false:(mType == mDefault->mType); + bool has_default_encoding = mDefault.isNull()?false:(mEncoding == mDefault->mEncoding); + bool has_default_precision = mDefault.isNull()?false:(mPrecision == mDefault->mPrecision); + bool has_default_length = mDefault.isNull()?false:(mLength == mDefault->mLength); // stream the name output_stream << indent << "<" << mName->mString << "\n"; @@ -1153,12 +1153,12 @@ void LLXMLNode::scrubToTree(LLXMLNode *tree) } } -bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing) +bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, bool use_default_if_missing) { return getChild(gStringTable.checkStringEntry(name), node, use_default_if_missing); } -bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing) +bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) { if (mChildren.notNull()) { @@ -1171,18 +1171,18 @@ bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOO } if (use_default_if_missing && !mDefault.isNull()) { - return mDefault->getChild(name, node, FALSE); + return mDefault->getChild(name, node, false); } node = NULL; return false; } -void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, BOOL use_default_if_missing) const +void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, bool use_default_if_missing) const { getChildren(gStringTable.checkStringEntry(name), children, use_default_if_missing); } -void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing) const +void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, bool use_default_if_missing) const { if (mChildren.notNull()) { @@ -1204,7 +1204,7 @@ void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &child } if (children.size() == 0 && use_default_if_missing && !mDefault.isNull()) { - mDefault->getChildren(name, children, FALSE); + mDefault->getChildren(name, children, false); } } @@ -1227,12 +1227,12 @@ void LLXMLNode::getDescendants(const LLStringTableEntry* name, LLXMLNodeList &ch } } -bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, BOOL use_default_if_missing) +bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, bool use_default_if_missing) { return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing); } -bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing) +bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) { LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); if (child_itr != mAttributes.end()) @@ -1242,7 +1242,7 @@ bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, } if (use_default_if_missing && !mDefault.isNull()) { - return mDefault->getAttribute(name, node, FALSE); + return mDefault->getAttribute(name, node, false); } return false; @@ -1261,42 +1261,25 @@ bool LLXMLNode::setAttributeString(const char* attr, const std::string& value) return false; } -BOOL LLXMLNode::hasAttribute(const char* name ) +bool LLXMLNode::hasAttribute(const char* name ) { LLXMLNodePtr node; 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 ) +bool LLXMLNode::getAttributeBOOL(const char* name, bool& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getBoolValue(1, &value)); } -BOOL LLXMLNode::getAttributeU8(const char* name, U8& value ) +bool LLXMLNode::getAttributeU8(const char* name, U8& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getByteValue(1, &value)); } -BOOL LLXMLNode::getAttributeS8(const char* name, S8& value ) +bool LLXMLNode::getAttributeS8(const char* name, S8& value ) { LLXMLNodePtr node; S32 val; @@ -1308,7 +1291,7 @@ BOOL LLXMLNode::getAttributeS8(const char* name, S8& value ) return true; } -BOOL LLXMLNode::getAttributeU16(const char* name, U16& value ) +bool LLXMLNode::getAttributeU16(const char* name, U16& value ) { LLXMLNodePtr node; U32 val; @@ -1320,7 +1303,7 @@ BOOL LLXMLNode::getAttributeU16(const char* name, U16& value ) return true; } -BOOL LLXMLNode::getAttributeS16(const char* name, S16& value ) +bool LLXMLNode::getAttributeS16(const char* name, S16& value ) { LLXMLNodePtr node; S32 val; @@ -1332,73 +1315,73 @@ BOOL LLXMLNode::getAttributeS16(const char* name, S16& value ) return true; } -BOOL LLXMLNode::getAttributeU32(const char* name, U32& value ) +bool LLXMLNode::getAttributeU32(const char* name, U32& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getUnsignedValue(1, &value)); } -BOOL LLXMLNode::getAttributeS32(const char* name, S32& value ) +bool LLXMLNode::getAttributeS32(const char* name, S32& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getIntValue(1, &value)); } -BOOL LLXMLNode::getAttributeF32(const char* name, F32& value ) +bool LLXMLNode::getAttributeF32(const char* name, F32& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getFloatValue(1, &value)); } -BOOL LLXMLNode::getAttributeF64(const char* name, F64& value ) +bool LLXMLNode::getAttributeF64(const char* name, F64& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getDoubleValue(1, &value)); } -BOOL LLXMLNode::getAttributeColor(const char* name, LLColor4& value ) +bool LLXMLNode::getAttributeColor(const char* name, LLColor4& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getFloatValue(4, value.mV)); } -BOOL LLXMLNode::getAttributeColor4(const char* name, LLColor4& value ) +bool LLXMLNode::getAttributeColor4(const char* name, LLColor4& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getFloatValue(4, value.mV)); } -BOOL LLXMLNode::getAttributeColor4U(const char* name, LLColor4U& value ) +bool LLXMLNode::getAttributeColor4U(const char* name, LLColor4U& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getByteValue(4, value.mV)); } -BOOL LLXMLNode::getAttributeVector3(const char* name, LLVector3& value ) +bool LLXMLNode::getAttributeVector3(const char* name, LLVector3& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getFloatValue(3, value.mV)); } -BOOL LLXMLNode::getAttributeVector3d(const char* name, LLVector3d& value ) +bool LLXMLNode::getAttributeVector3d(const char* name, LLVector3d& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getDoubleValue(3, value.mdV)); } -BOOL LLXMLNode::getAttributeQuat(const char* name, LLQuaternion& value ) +bool LLXMLNode::getAttributeQuat(const char* name, LLQuaternion& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getFloatValue(4, value.mQ)); } -BOOL LLXMLNode::getAttributeUUID(const char* name, LLUUID& value ) +bool LLXMLNode::getAttributeUUID(const char* name, LLUUID& value ) { LLXMLNodePtr node; return (getAttribute(name, node) && node->getUUIDValue(1, &value)); } -BOOL LLXMLNode::getAttributeString(const char* name, std::string& value ) +bool LLXMLNode::getAttributeString(const char* name, std::string& value ) { LLXMLNodePtr node; if (!getAttribute(name, node)) @@ -1435,10 +1418,10 @@ const char *LLXMLNode::skipNonWhitespace(const char *str) } /*static */ -const char *LLXMLNode::parseInteger(const char *str, U64 *dest, BOOL *is_negative, U32 precision, Encoding encoding) +const char *LLXMLNode::parseInteger(const char *str, U64 *dest, bool *is_negative, U32 precision, Encoding encoding) { *dest = 0; - *is_negative = FALSE; + *is_negative = false; str = skipWhitespace(str); @@ -1452,7 +1435,7 @@ const char *LLXMLNode::parseInteger(const char *str, U64 *dest, BOOL *is_negativ } if (str[0] == '-') { - *is_negative = TRUE; + *is_negative = true; ++str; } @@ -1653,7 +1636,7 @@ const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Enc // Scientific notation! ++str; U64 exp; - BOOL is_negative; + bool is_negative; str = parseInteger(str, &exp, &is_negative, 64, ENCODING_DECIMAL); if (str == NULL) { @@ -1677,7 +1660,7 @@ const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Enc if (encoding == ENCODING_HEX) { U64 bytes_dest; - BOOL is_negative; + bool is_negative; str = parseInteger(str, (U64 *)&bytes_dest, &is_negative, precision, ENCODING_HEX); // Upcast to F64 switch (precision) @@ -1700,7 +1683,7 @@ const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Enc return NULL; } -U32 LLXMLNode::getBoolValue(U32 expected_length, BOOL *array) +U32 LLXMLNode::getBoolValue(U32 expected_length, bool *array) { llassert(array); @@ -1720,11 +1703,11 @@ U32 LLXMLNode::getBoolValue(U32 expected_length, BOOL *array) LLStringUtil::toLower(str_array[i]); if (str_array[i] == "false") { - array[ret_length++] = FALSE; + array[ret_length++] = false; } else if (str_array[i] == "true") { - array[ret_length++] = TRUE; + array[ret_length++] = true; } } @@ -1770,7 +1753,7 @@ U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding) for (i=0; i 0 ? TRUE : FALSE; + return removed_count > 0; } -BOOL LLXMLNode::deleteChildren(LLStringTableEntry* name) +bool LLXMLNode::deleteChildren(LLStringTableEntry* name) { U32 removed_count = 0; LLXMLNodeList node_list; @@ -2655,7 +2638,7 @@ BOOL LLXMLNode::deleteChildren(LLStringTableEntry* name) } } } - return removed_count > 0 ? TRUE : FALSE; + return removed_count > 0; } void LLXMLNode::setAttributes(LLXMLNode::ValueType type, U32 precision, LLXMLNode::Encoding encoding, U32 length) @@ -2778,7 +2761,7 @@ void LLXMLNode::createUnitTest(S32 max_num_children) child_name.append(1, c); } - LLXMLNode *new_child = createChild(child_name.c_str(), FALSE); + LLXMLNode *new_child = createChild(child_name.c_str(), false); // Random ID std::string child_id; @@ -2805,7 +2788,7 @@ void LLXMLNode::createUnitTest(S32 max_num_children) break; case 1: // TYPE_BOOLEAN { - BOOL random_bool_values[30]; + bool random_bool_values[30]; for (U32 value=0; valuesetUnsignedValue(1, &integer_checksum, LLXMLNode::ENCODING_HEX); - createChild("long_checksum", TRUE)->setLongValue(1, &long_checksum, LLXMLNode::ENCODING_HEX); - createChild("bool_true_count", TRUE)->setUnsignedValue(1, &bool_true_count, LLXMLNode::ENCODING_HEX); - createChild("uuid_checksum", TRUE)->setUUIDValue(1, &uuid_checksum); - createChild("noderef_checksum", TRUE)->setUnsignedValue(1, &noderef_checksum, LLXMLNode::ENCODING_HEX); - createChild("float_checksum", TRUE)->setUnsignedValue(1, &float_checksum, LLXMLNode::ENCODING_HEX); + createChild("integer_checksum", true)->setUnsignedValue(1, &integer_checksum, LLXMLNode::ENCODING_HEX); + createChild("long_checksum", true)->setLongValue(1, &long_checksum, LLXMLNode::ENCODING_HEX); + createChild("bool_true_count", true)->setUnsignedValue(1, &bool_true_count, LLXMLNode::ENCODING_HEX); + createChild("uuid_checksum", true)->setUUIDValue(1, &uuid_checksum); + createChild("noderef_checksum", true)->setUnsignedValue(1, &noderef_checksum, LLXMLNode::ENCODING_HEX); + createChild("float_checksum", true)->setUnsignedValue(1, &float_checksum, LLXMLNode::ENCODING_HEX); } -BOOL LLXMLNode::performUnitTest(std::string &error_buffer) +bool LLXMLNode::performUnitTest(std::string &error_buffer) { if (mChildren.isNull()) { error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString)); - return FALSE; + return false; } // Checksums @@ -2950,14 +2933,14 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) if (!node->performUnitTest(error_buffer)) { error_buffer.append(llformat("Child test failed for %s.\n", mName->mString)); - //return FALSE; + //return false; } continue; } if (node->mLength < 1 || node->mLength > 30) { error_buffer.append(llformat("ERROR Node %s: Invalid array length %d, child %s.\n", mName->mString, node->mLength, node->mName->mString)); - return FALSE; + return false; } switch (node->mType) { @@ -2966,11 +2949,11 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) break; case TYPE_BOOLEAN: { - BOOL bool_array[30]; + bool bool_array[30]; if (node->getBoolValue(node->mLength, bool_array) < node->mLength) { error_buffer.append(llformat("ERROR Node %s: Could not read boolean array, child %s.\n", mName->mString, node->mName->mString)); - return FALSE; + return false; } for (U32 pos=0; pos<(U32)node->mLength; ++pos) { @@ -2989,7 +2972,7 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) if (node->getUnsignedValue(node->mLength, integer_array, node->mEncoding) < node->mLength) { error_buffer.append(llformat("ERROR Node %s: Could not read integer array, child %s.\n", mName->mString, node->mName->mString)); - return FALSE; + return false; } for (U32 pos=0; pos<(U32)node->mLength; ++pos) { @@ -3002,7 +2985,7 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) if (node->getLongValue(node->mLength, integer_array, node->mEncoding) < node->mLength) { error_buffer.append(llformat("ERROR Node %s: Could not read long integer array, child %s.\n", mName->mString, node->mName->mString)); - return FALSE; + return false; } for (U32 pos=0; pos<(U32)node->mLength; ++pos) { @@ -3019,7 +3002,7 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) if (node->getFloatValue(node->mLength, float_array, node->mEncoding) < node->mLength) { error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString)); - return FALSE; + return false; } for (U32 pos=0; pos<(U32)node->mLength; ++pos) { @@ -3033,7 +3016,7 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) if (node->getDoubleValue(node->mLength, float_array, node->mEncoding) < node->mLength) { error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString)); - return FALSE; + return false; } for (U32 pos=0; pos<(U32)node->mLength; ++pos) { @@ -3051,7 +3034,7 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) if (node->getUUIDValue(node->mLength, uuid_array) < node->mLength) { error_buffer.append(llformat("ERROR Node %s: Could not read uuid array, child %s.\n", mName->mString, node->mName->mString)); - return FALSE; + return false; } for (U32 pos=0; pos<(U32)node->mLength; ++pos) { @@ -3068,7 +3051,7 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) if (node->getNodeRefValue(node->mLength, node_array) < node->mLength) { error_buffer.append(llformat("ERROR Node %s: Could not read node ref array, child %s.\n", mName->mString, node->mName->mString)); - return FALSE; + return false; } for (U32 pos=0; posmLength; ++pos) { @@ -3089,97 +3072,97 @@ BOOL LLXMLNode::performUnitTest(std::string &error_buffer) // Compare checksums { U32 node_integer_checksum = 0; - if (!getAttribute("integer_checksum", checksum_node, FALSE) || + if (!getAttribute("integer_checksum", checksum_node, false) || checksum_node->getUnsignedValue(1, &node_integer_checksum, ENCODING_HEX) != 1) { error_buffer.append(llformat("ERROR Node %s: Integer checksum missing.\n", mName->mString)); - return FALSE; + return false; } if (node_integer_checksum != integer_checksum) { error_buffer.append(llformat("ERROR Node %s: Integer checksum mismatch: read %X / calc %X.\n", mName->mString, node_integer_checksum, integer_checksum)); - return FALSE; + return false; } } { U64 node_long_checksum = 0; - if (!getAttribute("long_checksum", checksum_node, FALSE) || + if (!getAttribute("long_checksum", checksum_node, false) || checksum_node->getLongValue(1, &node_long_checksum, ENCODING_HEX) != 1) { error_buffer.append(llformat("ERROR Node %s: Long Integer checksum missing.\n", mName->mString)); - return FALSE; + return false; } if (node_long_checksum != long_checksum) { U32 *pp1 = (U32 *)&node_long_checksum; U32 *pp2 = (U32 *)&long_checksum; 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])); - return FALSE; + return false; } } { U32 node_bool_true_count = 0; - if (!getAttribute("bool_true_count", checksum_node, FALSE) || + if (!getAttribute("bool_true_count", checksum_node, false) || checksum_node->getUnsignedValue(1, &node_bool_true_count, ENCODING_HEX) != 1) { error_buffer.append(llformat("ERROR Node %s: Boolean checksum missing.\n", mName->mString)); - return FALSE; + return false; } if (node_bool_true_count != bool_true_count) { error_buffer.append(llformat("ERROR Node %s: Boolean checksum mismatch: read %X / calc %X.\n", mName->mString, node_bool_true_count, bool_true_count)); - return FALSE; + return false; } } { LLUUID node_uuid_checksum; - if (!getAttribute("uuid_checksum", checksum_node, FALSE) || + if (!getAttribute("uuid_checksum", checksum_node, false) || checksum_node->getUUIDValue(1, &node_uuid_checksum) != 1) { error_buffer.append(llformat("ERROR Node %s: UUID checksum missing.\n", mName->mString)); - return FALSE; + return false; } if (node_uuid_checksum != uuid_checksum) { error_buffer.append(llformat("ERROR Node %s: UUID checksum mismatch: read %s / calc %s.\n", mName->mString, node_uuid_checksum.asString().c_str(), uuid_checksum.asString().c_str())); - return FALSE; + return false; } } { U32 node_noderef_checksum = 0; - if (!getAttribute("noderef_checksum", checksum_node, FALSE) || + if (!getAttribute("noderef_checksum", checksum_node, false) || checksum_node->getUnsignedValue(1, &node_noderef_checksum, ENCODING_HEX) != 1) { error_buffer.append(llformat("ERROR Node %s: Node Ref checksum missing.\n", mName->mString)); - return FALSE; + return false; } if (node_noderef_checksum != noderef_checksum) { error_buffer.append(llformat("ERROR Node %s: Node Ref checksum mismatch: read %X / calc %X.\n", mName->mString, node_noderef_checksum, noderef_checksum)); - return FALSE; + return false; } } { U32 node_float_checksum = 0; - if (!getAttribute("float_checksum", checksum_node, FALSE) || + if (!getAttribute("float_checksum", checksum_node, false) || checksum_node->getUnsignedValue(1, &node_float_checksum, ENCODING_HEX) != 1) { error_buffer.append(llformat("ERROR Node %s: Float checksum missing.\n", mName->mString)); - return FALSE; + return false; } if (node_float_checksum != float_checksum) { error_buffer.append(llformat("ERROR Node %s: Float checksum mismatch: read %X / calc %X.\n", mName->mString, node_float_checksum, float_checksum)); - return FALSE; + return false; } } - return TRUE; + return true; } LLXMLNodePtr LLXMLNode::getFirstChild() const -- cgit v1.2.3 From a865d423974ea06dffa47798c81e98e7570b02ec Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Tue, 5 Mar 2024 17:03:11 +0100 Subject: viewer#819 Avoid reading the same XML file multiple times --- indra/llxml/llxmlnode.cpp | 78 +++++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 27 deletions(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 9c7ac66f01..627e99a1e6 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -650,34 +650,56 @@ bool LLXMLNode::updateNode( return true; } -// static -bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree) +static std::map sXMLCache; +static LLSharedMutex sXMLCacheMutex; + +static void saveToCache(const std::string& filename, LLXMLNodePtr& node) { - // Read file - LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL; - LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ - if (fp == NULL) - { - node = NULL ; - return false; - } - fseek(fp, 0, SEEK_END); - U32 length = ftell(fp); - fseek(fp, 0, SEEK_SET); + LLExclusiveMutexLock lock(&sXMLCacheMutex); + sXMLCache.emplace(filename, node.notNull() ? node->deepCopy() : nullptr); +} - U8* buffer = new U8[length+1]; - size_t nread = fread(buffer, 1, length, fp); - buffer[nread] = 0; - fclose(fp); +static bool loadFromCache(const std::string& filename, LLXMLNodePtr& node) +{ + LLSharedMutexLock lock(&sXMLCacheMutex); + auto it = sXMLCache.find(filename); + if (it == sXMLCache.end()) + return false; + node = it->second.notNull() ? it->second->deepCopy() : nullptr; + return node.notNull(); +} - bool rv = parseBuffer(buffer, nread, node, defaults_tree); - delete [] buffer; - return rv; +// static +bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree, bool cacheable) +{ + // Try to read from cache + if (cacheable) + { + if (loadFromCache(filename, node)) + return true; + } + + std::string xml = gDirUtilp->getFileContents(filename); + if (xml.empty()) + { + LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL; + } + else if (parseBuffer(xml.data(), xml.size(), node, defaults_tree)) + { + if (cacheable) + { + saveToCache(filename, node); + } + return true; + } + + node = nullptr; + return false; } // static bool LLXMLNode::parseBuffer( - U8* buffer, + const char* buffer, U32 length, LLXMLNodePtr& node, LLXMLNode* defaults) @@ -696,7 +718,7 @@ bool LLXMLNode::parseBuffer( XML_SetUserData(my_parser, (void *)file_node_ptr); // Do the parsing - if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK) + if (XML_Parse(my_parser, buffer, length, true) != XML_STATUS_OK) { LL_WARNS() << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) @@ -824,18 +846,20 @@ bool LLXMLNode::isFullyDefault() } // static -bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, - const std::vector& paths) +bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, const std::vector& paths, bool cacheable) { - if (paths.empty()) return false; + if (paths.empty()) + { + return false; + } std::string filename = paths.front(); if (filename.empty()) { return false; } - - if (!LLXMLNode::parseFile(filename, root, NULL)) + + if (!LLXMLNode::parseFile(filename, root, nullptr, cacheable)) { LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL; return false; -- cgit v1.2.3 From ad6425173900855852b8c8437cc88120ea46cc53 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 7 May 2024 20:44:53 +0300 Subject: viewer#1420 Fixed names not showing in Chat Save node prior to calling updateDefault --- indra/llxml/llxmlnode.cpp | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 627e99a1e6..dc60b1aa66 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -137,19 +137,19 @@ LLXMLNode::LLXMLNode(const LLXMLNode& rhs) : } // returns a new copy of this node and all its children -LLXMLNodePtr LLXMLNode::deepCopy() +LLXMLNodePtr LLXMLNode::deepCopy() const { LLXMLNodePtr newnode = LLXMLNodePtr(new LLXMLNode(*this)); if (mChildren.notNull()) { - for (LLXMLChildList::iterator iter = mChildren->map.begin(); + for (LLXMLChildList::const_iterator iter = mChildren->map.begin(); iter != mChildren->map.end(); ++iter) { LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); newnode->addChild(temp_ptr_for_gcc); } } - for (LLXMLAttribList::iterator iter = mAttributes.begin(); + for (LLXMLAttribList::const_iterator iter = mAttributes.begin(); iter != mAttributes.end(); ++iter) { LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); @@ -653,10 +653,12 @@ bool LLXMLNode::updateNode( static std::map sXMLCache; static LLSharedMutex sXMLCacheMutex; -static void saveToCache(const std::string& filename, LLXMLNodePtr& node) +static void saveToCache(const std::string& filename, const LLXMLNodePtr& node) { + LLXMLNodePtr node_copy = node->deepCopy(); + LLExclusiveMutexLock lock(&sXMLCacheMutex); - sXMLCache.emplace(filename, node.notNull() ? node->deepCopy() : nullptr); + sXMLCache.emplace(filename, node_copy); } static bool loadFromCache(const std::string& filename, LLXMLNodePtr& node) @@ -665,8 +667,8 @@ static bool loadFromCache(const std::string& filename, LLXMLNodePtr& node) auto it = sXMLCache.find(filename); if (it == sXMLCache.end()) return false; - node = it->second.notNull() ? it->second->deepCopy() : nullptr; - return node.notNull(); + node = it->second->deepCopy(); + return true; } // static @@ -676,7 +678,11 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML if (cacheable) { if (loadFromCache(filename, node)) + { + node->setDefault(defaults_tree); + node->updateDefault(); return true; + } } std::string xml = gDirUtilp->getFileContents(filename); @@ -684,12 +690,14 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML { LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL; } - else if (parseBuffer(xml.data(), xml.size(), node, defaults_tree)) + else if (parseBuffer(xml.data(), xml.size(), node)) { if (cacheable) { saveToCache(filename, node); } + node->setDefault(defaults_tree); + node->updateDefault(); return true; } @@ -697,12 +705,27 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML return false; } +// static +bool LLXMLNode::parseBuffer( + const char* buffer, + U32 length, + LLXMLNodePtr& node, + LLXMLNode* defaults) +{ + if (parseBuffer(buffer, length, node)) + { + node->setDefault(defaults); + node->updateDefault(); + return true; + } + return false; +} + // static bool LLXMLNode::parseBuffer( const char* buffer, U32 length, - LLXMLNodePtr& node, - LLXMLNode* defaults) + LLXMLNodePtr& node) { // Init XML_Parser my_parser = XML_ParserCreate(NULL); @@ -739,9 +762,6 @@ bool LLXMLNode::parseBuffer( LLXMLNode *return_node = file_node->mChildren->map.begin()->second; - return_node->setDefault(defaults); - return_node->updateDefault(); - node = return_node; return true; } -- cgit v1.2.3 From 2008f87f10d51a2f9372aa4a4d72e86ac94e1e81 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 13 May 2024 18:26:53 +0300 Subject: Revert "viewer#819 Avoid reading the same XML file multiple times" This reverts commit a865d423974ea06dffa47798c81e98e7570b02ec. Reason for revert: viewer#1420, reverting to not hold maint-A (is deepCopy not full?) --- indra/llxml/llxmlnode.cpp | 114 ++++++++++++++-------------------------------- 1 file changed, 35 insertions(+), 79 deletions(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index dc60b1aa66..9c7ac66f01 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -137,19 +137,19 @@ LLXMLNode::LLXMLNode(const LLXMLNode& rhs) : } // returns a new copy of this node and all its children -LLXMLNodePtr LLXMLNode::deepCopy() const +LLXMLNodePtr LLXMLNode::deepCopy() { LLXMLNodePtr newnode = LLXMLNodePtr(new LLXMLNode(*this)); if (mChildren.notNull()) { - for (LLXMLChildList::const_iterator iter = mChildren->map.begin(); + for (LLXMLChildList::iterator iter = mChildren->map.begin(); iter != mChildren->map.end(); ++iter) { LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); newnode->addChild(temp_ptr_for_gcc); } } - for (LLXMLAttribList::const_iterator iter = mAttributes.begin(); + for (LLXMLAttribList::iterator iter = mAttributes.begin(); iter != mAttributes.end(); ++iter) { LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); @@ -650,82 +650,37 @@ bool LLXMLNode::updateNode( return true; } -static std::map sXMLCache; -static LLSharedMutex sXMLCacheMutex; - -static void saveToCache(const std::string& filename, const LLXMLNodePtr& node) -{ - LLXMLNodePtr node_copy = node->deepCopy(); - - LLExclusiveMutexLock lock(&sXMLCacheMutex); - sXMLCache.emplace(filename, node_copy); -} - -static bool loadFromCache(const std::string& filename, LLXMLNodePtr& node) +// static +bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree) { - LLSharedMutexLock lock(&sXMLCacheMutex); - auto it = sXMLCache.find(filename); - if (it == sXMLCache.end()) - return false; - node = it->second->deepCopy(); - return true; -} + // Read file + LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL; + LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ + if (fp == NULL) + { + node = NULL ; + return false; + } + fseek(fp, 0, SEEK_END); + U32 length = ftell(fp); + fseek(fp, 0, SEEK_SET); -// static -bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree, bool cacheable) -{ - // Try to read from cache - if (cacheable) - { - if (loadFromCache(filename, node)) - { - node->setDefault(defaults_tree); - node->updateDefault(); - return true; - } - } - - std::string xml = gDirUtilp->getFileContents(filename); - if (xml.empty()) - { - LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL; - } - else if (parseBuffer(xml.data(), xml.size(), node)) - { - if (cacheable) - { - saveToCache(filename, node); - } - node->setDefault(defaults_tree); - node->updateDefault(); - return true; - } - - node = nullptr; - return false; -} + U8* buffer = new U8[length+1]; + size_t nread = fread(buffer, 1, length, fp); + buffer[nread] = 0; + fclose(fp); -// static -bool LLXMLNode::parseBuffer( - const char* buffer, - U32 length, - LLXMLNodePtr& node, - LLXMLNode* defaults) -{ - if (parseBuffer(buffer, length, node)) - { - node->setDefault(defaults); - node->updateDefault(); - return true; - } - return false; + bool rv = parseBuffer(buffer, nread, node, defaults_tree); + delete [] buffer; + return rv; } // static bool LLXMLNode::parseBuffer( - const char* buffer, + U8* buffer, U32 length, - LLXMLNodePtr& node) + LLXMLNodePtr& node, + LLXMLNode* defaults) { // Init XML_Parser my_parser = XML_ParserCreate(NULL); @@ -741,7 +696,7 @@ bool LLXMLNode::parseBuffer( XML_SetUserData(my_parser, (void *)file_node_ptr); // Do the parsing - if (XML_Parse(my_parser, buffer, length, true) != XML_STATUS_OK) + if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK) { LL_WARNS() << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) @@ -762,6 +717,9 @@ bool LLXMLNode::parseBuffer( LLXMLNode *return_node = file_node->mChildren->map.begin()->second; + return_node->setDefault(defaults); + return_node->updateDefault(); + node = return_node; return true; } @@ -866,20 +824,18 @@ bool LLXMLNode::isFullyDefault() } // static -bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, const std::vector& paths, bool cacheable) +bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, + const std::vector& paths) { - if (paths.empty()) - { - return false; - } + if (paths.empty()) return false; std::string filename = paths.front(); if (filename.empty()) { return false; } - - if (!LLXMLNode::parseFile(filename, root, nullptr, cacheable)) + + if (!LLXMLNode::parseFile(filename, root, NULL)) { LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL; return false; -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/llxml/llxmlnode.cpp | 6536 ++++++++++++++++++++++----------------------- 1 file changed, 3268 insertions(+), 3268 deletions(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index e7ea5a9fad..5e98af8412 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -1,3268 +1,3268 @@ -/** - * @file llxmlnode.cpp - * @author Tom Yedwab - * @brief LLXMLNode implementation - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include -#include - -#include "llxmlnode.h" - -#include "v3color.h" -#include "v4color.h" -#include "v4coloru.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4math.h" -#include "llquaternion.h" -#include "llstring.h" -#include "lluuid.h" -#include "lldir.h" - -// static -bool LLXMLNode::sStripEscapedStrings = true; -bool LLXMLNode::sStripWhitespaceValues = false; - -LLXMLNode::LLXMLNode() : - mID(""), - mParser(NULL), - mIsAttribute(false), - mVersionMajor(0), - mVersionMinor(0), - mLength(0), - mPrecision(64), - mType(TYPE_CONTAINER), - mEncoding(ENCODING_DEFAULT), - mLineNumber(-1), - mParent(NULL), - mChildren(NULL), - mAttributes(), - mPrev(NULL), - mNext(NULL), - mName(NULL), - mValue(""), - mDefault(NULL) -{ -} - -LLXMLNode::LLXMLNode(const char* name, bool is_attribute) : - mID(""), - mParser(NULL), - mIsAttribute(is_attribute), - mVersionMajor(0), - mVersionMinor(0), - mLength(0), - mPrecision(64), - mType(TYPE_CONTAINER), - mEncoding(ENCODING_DEFAULT), - mLineNumber(-1), - mParent(NULL), - mChildren(NULL), - mAttributes(), - mPrev(NULL), - mNext(NULL), - mValue(""), - mDefault(NULL) -{ - mName = gStringTable.addStringEntry(name); -} - -LLXMLNode::LLXMLNode(LLStringTableEntry* name, bool is_attribute) : - mID(""), - mParser(NULL), - mIsAttribute(is_attribute), - mVersionMajor(0), - mVersionMinor(0), - mLength(0), - mPrecision(64), - mType(TYPE_CONTAINER), - mEncoding(ENCODING_DEFAULT), - mLineNumber(-1), - 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), - mLineNumber(0), - mParser(NULL), - 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) - { - LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); - newnode->addChild(temp_ptr_for_gcc); - } - } - for (LLXMLAttribList::iterator iter = mAttributes.begin(); - iter != mAttributes.end(); ++iter) - { - LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); - newnode->addChild(temp_ptr_for_gcc); - } - - return newnode; -} - -// virtual -LLXMLNode::~LLXMLNode() -{ - // Strictly speaking none of this should be required execept 'delete 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) - { - LLXMLNodePtr child = iter->second; - child->mParent = NULL; - child->mNext = NULL; - child->mPrev = NULL; - } - mChildren->map.clear(); - mChildren->head = NULL; - mChildren->tail = NULL; - mChildren = NULL; - } - for (LLXMLAttribList::iterator iter = mAttributes.begin(); - iter != mAttributes.end(); ++iter) - { - LLXMLNodePtr attr = iter->second; - attr->mParent = NULL; - attr->mNext = NULL; - attr->mPrev = NULL; - } - llassert(mParent == NULL); - mDefault = NULL; -} - -bool LLXMLNode::isNull() -{ - return (mName == NULL); -} - -// protected -bool LLXMLNode::removeChild(LLXMLNode *target_child) -{ - if (!target_child) - { - return false; - } - if (target_child->mIsAttribute) - { - LLXMLAttribList::iterator children_itr = mAttributes.find(target_child->mName); - if (children_itr != mAttributes.end()) - { - target_child->mParent = NULL; - mAttributes.erase(children_itr); - return true; - } - } - else if (mChildren.notNull()) - { - LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName); - while (children_itr != mChildren->map.end()) - { - if (target_child == children_itr->second) - { - if (target_child == mChildren->head) - { - 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; - if (prev.notNull()) prev->mNext = next; - if (next.notNull()) next->mPrev = prev; - - target_child->mPrev = NULL; - target_child->mNext = NULL; - target_child->mParent = NULL; - mChildren->map.erase(children_itr); - if (mChildren->map.empty()) - { - mChildren = NULL; - } - return true; - } - else if (children_itr->first != target_child->mName) - { - break; - } - else - { - ++children_itr; - } - } - } - return false; -} - -void LLXMLNode::addChild(LLXMLNodePtr& new_child) -{ - if (new_child->mParent != NULL) - { - if (new_child->mParent == this) - { - return; - } - new_child->mParent->removeChild(new_child); - } - - new_child->mParent = this; - if (new_child->mIsAttribute) - { - LLXMLAttribList::iterator found_it = mAttributes.find(new_child->mName); - if (found_it != mAttributes.end()) - { - removeChild(found_it->second); - } - mAttributes.insert(std::make_pair(new_child->mName, new_child)); - } - else - { - if (mChildren.isNull()) - { - mChildren = new LLXMLChildren(); - mChildren->head = new_child; - mChildren->tail = new_child; - } - mChildren->map.insert(std::make_pair(new_child->mName, new_child)); - - if (mChildren->tail != new_child) - { - mChildren->tail->mNext = new_child; - new_child->mPrev = mChildren->tail; - mChildren->tail = new_child; - } - } - - new_child->updateDefault(); -} - -// virtual -LLXMLNodePtr LLXMLNode::createChild(const char* name, bool is_attribute) -{ - return createChild(gStringTable.addStringEntry(name), is_attribute); -} - -// virtual -LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, bool is_attribute) -{ - LLXMLNodePtr ret(new LLXMLNode(name, is_attribute)); - ret->mID.clear(); - - addChild(ret); - return ret; -} - -bool LLXMLNode::deleteChild(LLXMLNode *child) -{ - if (removeChild(child)) - { - return true; - } - return false; -} - -void LLXMLNode::setParent(LLXMLNodePtr& new_parent) -{ - if (new_parent.notNull()) - { - LLXMLNodePtr this_ptr(this); - new_parent->addChild(this_ptr); - } - else - { - if (mParent != NULL) - { - LLXMLNodePtr old_parent = mParent; - mParent = NULL; - old_parent->removeChild(this); - } - } -} - - -void LLXMLNode::updateDefault() -{ - if (mParent != NULL && !mParent->mDefault.isNull()) - { - mDefault = NULL; - - // Find default value in parent's default tree - if (!mParent->mDefault.isNull()) - { - findDefault(mParent->mDefault); - } - } - - if (mChildren.notNull()) - { - LLXMLChildList::const_iterator children_itr; - LLXMLChildList::const_iterator children_end = mChildren->map.end(); - for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) - { - LLXMLNodePtr child = (*children_itr).second; - child->updateDefault(); - } - } -} - -void XMLCALL StartXMLNode(void *userData, - const XML_Char *name, - const XML_Char **atts) -{ - // 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; - - // Set the parent-child relationship with the current active node - LLXMLNode* parent = (LLXMLNode *)userData; - - if (NULL == parent) - { - LL_WARNS() << "parent (userData) is NULL; aborting function" << LL_ENDL; - return; - } - - 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); - - // Parse attributes - U32 pos = 0; - while (atts[pos] != NULL) - { - std::string attr_name = atts[pos]; - std::string attr_value = atts[pos+1]; - - // Special cases - if ('i' == attr_name[0] && "id" == attr_name) - { - new_node->mID = attr_value; - } - else if ('v' == attr_name[0] && "version" == attr_name) - { - U32 version_major = 0; - U32 version_minor = 0; - if (sscanf(attr_value.c_str(), "%d.%d", &version_major, &version_minor) > 0) - { - new_node->mVersionMajor = version_major; - new_node->mVersionMinor = version_minor; - } - } - else if (('s' == attr_name[0] && "size" == attr_name) || ('l' == attr_name[0] && "length" == attr_name)) - { - U32 length; - if (sscanf(attr_value.c_str(), "%d", &length) > 0) - { - new_node->mLength = length; - } - } - else if ('p' == attr_name[0] && "precision" == attr_name) - { - U32 precision; - if (sscanf(attr_value.c_str(), "%d", &precision) > 0) - { - new_node->mPrecision = precision; - } - } - else if ('t' == attr_name[0] && "type" == attr_name) - { - if ("boolean" == attr_value) - { - new_node->mType = LLXMLNode::TYPE_BOOLEAN; - } - else if ("integer" == attr_value) - { - new_node->mType = LLXMLNode::TYPE_INTEGER; - } - else if ("float" == attr_value) - { - new_node->mType = LLXMLNode::TYPE_FLOAT; - } - else if ("string" == attr_value) - { - new_node->mType = LLXMLNode::TYPE_STRING; - } - else if ("uuid" == attr_value) - { - new_node->mType = LLXMLNode::TYPE_UUID; - } - else if ("noderef" == attr_value) - { - new_node->mType = LLXMLNode::TYPE_NODEREF; - } - } - else if ('e' == attr_name[0] && "encoding" == attr_name) - { - if ("decimal" == attr_value) - { - new_node->mEncoding = LLXMLNode::ENCODING_DECIMAL; - } - else if ("hex" == attr_value) - { - new_node->mEncoding = LLXMLNode::ENCODING_HEX; - } - /*else if (attr_value == "base32") - { - new_node->mEncoding = LLXMLNode::ENCODING_BASE32; - }*/ - } - - // only one attribute child per description - LLXMLNodePtr attr_node; - 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); - - pos += 2; - } - - if (parent) - { - parent->addChild(new_node); - } -} - -void XMLCALL EndXMLNode(void *userData, - const XML_Char *name) -{ - // [FUGLY] Set the current active node to the current node's parent - LLXMLNode *node = (LLXMLNode *)userData; - XML_Parser *parser = node->mParser; - XML_SetUserData(*parser, (void *)node->mParent); - // SJB: total hack: - if (LLXMLNode::sStripWhitespaceValues) - { - std::string value = node->getValue(); - bool is_empty = true; - for (std::string::size_type s = 0; s < value.length(); s++) - { - char c = value[s]; - if (c != ' ' && c != '\t' && c != '\n') - { - is_empty = false; - break; - } - } - if (is_empty) - { - value.clear(); - node->setValue(value); - } - } -} - -void XMLCALL XMLData(void *userData, - const XML_Char *s, - int len) -{ - LLXMLNode* current_node = (LLXMLNode *)userData; - std::string value = current_node->getValue(); - if (LLXMLNode::sStripEscapedStrings) - { - if (s[0] == '\"' && s[len-1] == '\"') - { - // Special-case: Escaped string. - std::string unescaped_string; - for (S32 pos=1; possetValue(value); - return; - } - } - value.append(std::string(s, len)); - current_node->setValue(value); -} - - - -// static -bool LLXMLNode::updateNode( - LLXMLNodePtr& node, - LLXMLNodePtr& update_node) -{ - - if (!node || !update_node) - { - LL_WARNS() << "Node invalid" << LL_ENDL; - return false; - } - - //update the node value - node->mValue = update_node->mValue; - - //update all attribute values - LLXMLAttribList::const_iterator itor; - - for(itor = update_node->mAttributes.begin(); itor != update_node->mAttributes.end(); ++itor) - { - const LLStringTableEntry* attribNameEntry = (*itor).first; - LLXMLNodePtr updateAttribNode = (*itor).second; - - LLXMLNodePtr attribNode; - - node->getAttribute(attribNameEntry, attribNode, 0); - - if (attribNode) - { - attribNode->mValue = updateAttribNode->mValue; - } - } - - //update all of node's children with updateNodes children that match name - LLXMLNodePtr child = node->getFirstChild(); - LLXMLNodePtr last_child = child; - LLXMLNodePtr updateChild; - - for (updateChild = update_node->getFirstChild(); updateChild.notNull(); - updateChild = updateChild->getNextSibling()) - { - while(child.notNull()) - { - std::string nodeName; - std::string updateName; - - updateChild->getAttributeString("name", updateName); - child->getAttributeString("name", nodeName); - - - //if it's a combobox there's no name, but there is a value - if (updateName.empty()) - { - updateChild->getAttributeString("value", updateName); - child->getAttributeString("value", nodeName); - } - - if ((nodeName != "") && (updateName == nodeName)) - { - updateNode(child, updateChild); - last_child = child; - child = child->getNextSibling(); - if (child.isNull()) - { - child = node->getFirstChild(); - } - break; - } - - child = child->getNextSibling(); - if (child.isNull()) - { - child = node->getFirstChild(); - } - if (child == last_child) - { - break; - } - } - } - - return true; -} - -// static -bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree) -{ - // Read file - LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL; - LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ - if (fp == NULL) - { - node = NULL ; - return false; - } - fseek(fp, 0, SEEK_END); - U32 length = ftell(fp); - fseek(fp, 0, SEEK_SET); - - U8* buffer = new U8[length+1]; - size_t nread = fread(buffer, 1, length, fp); - buffer[nread] = 0; - fclose(fp); - - bool rv = parseBuffer(buffer, nread, node, defaults_tree); - delete [] buffer; - return rv; -} - -// static -bool LLXMLNode::parseBuffer( - U8* buffer, - U32 length, - LLXMLNodePtr& node, - LLXMLNode* defaults) -{ - // Init - XML_Parser my_parser = XML_ParserCreate(NULL); - XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode); - XML_SetCharacterDataHandler(my_parser, XMLData); - - // Create a root node - LLXMLNode *file_node_ptr = new LLXMLNode("XML", false); - LLXMLNodePtr file_node = file_node_ptr; - - file_node->mParser = &my_parser; - - XML_SetUserData(my_parser, (void *)file_node_ptr); - - // Do the parsing - if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK) - { - LL_WARNS() << "Error parsing xml error code: " - << XML_ErrorString(XML_GetErrorCode(my_parser)) - << " on line " << XML_GetCurrentLineNumber(my_parser) - << LL_ENDL; - } - - // Deinit - XML_ParserFree(my_parser); - - if (!file_node->mChildren || file_node->mChildren->map.size() != 1) - { - LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." - << LL_ENDL; - node = NULL ; - return false; - } - - LLXMLNode *return_node = file_node->mChildren->map.begin()->second; - - return_node->setDefault(defaults); - return_node->updateDefault(); - - node = return_node; - return true; -} - -// static -bool LLXMLNode::parseStream( - std::istream& str, - LLXMLNodePtr& node, - LLXMLNode* defaults) -{ - // Init - XML_Parser my_parser = XML_ParserCreate(NULL); - XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode); - XML_SetCharacterDataHandler(my_parser, XMLData); - - // Create a root node - LLXMLNode *file_node_ptr = new LLXMLNode("XML", false); - LLXMLNodePtr file_node = file_node_ptr; - - file_node->mParser = &my_parser; - - XML_SetUserData(my_parser, (void *)file_node_ptr); - - const int BUFSIZE = 1024; - U8* buffer = new U8[BUFSIZE]; - - while(str.good()) - { - str.read((char*)buffer, BUFSIZE); - int count = (int)str.gcount(); - - if (XML_Parse(my_parser, (const char *)buffer, count, !str.good()) != XML_STATUS_OK) - { - LL_WARNS() << "Error parsing xml error code: " - << XML_ErrorString(XML_GetErrorCode(my_parser)) - << " on lne " << XML_GetCurrentLineNumber(my_parser) - << LL_ENDL; - break; - } - } - - delete [] buffer; - - // Deinit - XML_ParserFree(my_parser); - - if (!file_node->mChildren || file_node->mChildren->map.size() != 1) - { - LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." - << LL_ENDL; - node = NULL; - return false; - } - - LLXMLNode *return_node = file_node->mChildren->map.begin()->second; - - return_node->setDefault(defaults); - return_node->updateDefault(); - - node = return_node; - return true; -} - - -bool LLXMLNode::isFullyDefault() -{ - if (mDefault.isNull()) - { - return false; - } - bool has_default_value = (mValue == mDefault->mValue); - bool has_default_attribute = (mIsAttribute == mDefault->mIsAttribute); - bool has_default_type = mIsAttribute || (mType == mDefault->mType); - bool has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding); - bool has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision); - bool has_default_length = mIsAttribute || (mLength == mDefault->mLength); - - if (has_default_value - && has_default_type - && has_default_encoding - && has_default_precision - && has_default_length - && has_default_attribute) - { - if (mChildren.notNull()) - { - LLXMLChildList::const_iterator children_itr; - LLXMLChildList::const_iterator children_end = mChildren->map.end(); - for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) - { - LLXMLNodePtr child = (*children_itr).second; - if (!child->isFullyDefault()) - { - return false; - } - } - } - return true; - } - - return false; -} - -// static -bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, - const std::vector& paths) -{ - if (paths.empty()) return false; - - std::string filename = paths.front(); - if (filename.empty()) - { - return false; - } - - if (!LLXMLNode::parseFile(filename, root, NULL)) - { - LL_WARNS() << "Problem reading UI description file: " << filename << " " << errno << LL_ENDL; - return false; - } - - LLXMLNodePtr updateRoot; - - std::vector::const_iterator itor; - - // We've already dealt with the first item, skip that one - for (itor = paths.begin() + 1; itor != paths.end(); ++itor) - { - std::string layer_filename = *itor; - if(layer_filename.empty() || layer_filename == filename) - { - // no localized version of this file, that's ok, keep looking - continue; - } - - if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL)) - { - LL_WARNS() << "Problem reading localized UI description file: " << layer_filename << LL_ENDL; - return false; - } - - std::string nodeName; - std::string updateName; - - updateRoot->getAttributeString("name", updateName); - root->getAttributeString("name", nodeName); - - if (updateName == nodeName) - { - LLXMLNode::updateNode(root, updateRoot); - } - } - - return true; -} - -// static -void LLXMLNode::writeHeaderToFile(LLFILE *out_file) -{ - fprintf(out_file, "\n"); -} - -void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations) -{ - if (isFullyDefault()) - { - // Don't write out nodes that are an exact match to defaults - return; - } - - std::ostringstream ostream; - writeToOstream(ostream, indent, use_type_decorations); - std::string outstring = ostream.str(); - size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file); - if (written != outstring.length()) - { - LL_WARNS() << "Short write" << LL_ENDL; - } -} - -void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent, bool use_type_decorations) -{ - if (isFullyDefault()) - { - // Don't write out nodes that are an exact match to defaults - return; - } - - bool has_default_type = mDefault.isNull()?false:(mType == mDefault->mType); - bool has_default_encoding = mDefault.isNull()?false:(mEncoding == mDefault->mEncoding); - bool has_default_precision = mDefault.isNull()?false:(mPrecision == mDefault->mPrecision); - bool has_default_length = mDefault.isNull()?false:(mLength == mDefault->mLength); - - // stream the name - output_stream << indent << "<" << mName->mString << "\n"; - - if (use_type_decorations) - { - // ID - if (mID != "") - { - output_stream << indent << " id=\"" << mID << "\"\n"; - } - - // Type - if (!has_default_type) - { - 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) - { - 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 << indent << " precision=\"" << mPrecision << "\"\n"; - } - - // Version - if (mVersionMajor > 0 || mVersionMinor > 0) - { - output_stream << indent << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"\n"; - } - - // Array length - if (!has_default_length && mLength > 0) - { - output_stream << indent << " length=\"" << mLength << "\"\n"; - } - } - - { - // Write out attributes - LLXMLAttribList::const_iterator attr_itr; - LLXMLAttribList::const_iterator attr_end = mAttributes.end(); - for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr) - { - LLXMLNodePtr child = (*attr_itr).second; - if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue) - { - std::string attr = child->mName->mString; - if (use_type_decorations - && (attr == "id" || - attr == "type" || - attr == "encoding" || - attr == "precision" || - attr == "version" || - attr == "length")) - { - continue; // skip built-in attributes - } - - std::string attr_str = llformat(" %s=\"%s\"", - attr.c_str(), - escapeXML(child->mValue).c_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"; - return; - } - else - { - output_stream << ">\n"; - if (mChildren.notNull()) - { - // stream non-attributes - std::string next_indent = indent + " "; - for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling()) - { - child->writeToOstream(output_stream, next_indent, use_type_decorations); - } - } - if (!mValue.empty()) - { - std::string contents = getTextContents(); - output_stream << indent << " " << escapeXML(contents) << "\n"; - } - output_stream << indent << "mString << ">\n"; - } -} - -void LLXMLNode::findName(const std::string& name, LLXMLNodeList &results) -{ - LLStringTableEntry* name_entry = gStringTable.checkStringEntry(name); - if (name_entry == mName) - { - results.insert(std::make_pair(this->mName->mString, this)); - return; - } - if (mChildren.notNull()) - { - LLXMLChildList::const_iterator children_itr; - LLXMLChildList::const_iterator children_end = mChildren->map.end(); - for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) - { - LLXMLNodePtr child = (*children_itr).second; - child->findName(name_entry, results); - } - } -} - -void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results) -{ - if (name == mName) - { - results.insert(std::make_pair(this->mName->mString, this)); - return; - } - if (mChildren.notNull()) - { - LLXMLChildList::const_iterator children_itr; - LLXMLChildList::const_iterator children_end = mChildren->map.end(); - for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) - { - LLXMLNodePtr child = (*children_itr).second; - child->findName(name, results); - } - } -} - -void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results) -{ - if (id == mID) - { - results.insert(std::make_pair(this->mName->mString, this)); - return; - } - if (mChildren.notNull()) - { - LLXMLChildList::const_iterator children_itr; - LLXMLChildList::const_iterator children_end = mChildren->map.end(); - for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) - { - LLXMLNodePtr child = (*children_itr).second; - child->findID(id, results); - } - } -} - -void LLXMLNode::scrubToTree(LLXMLNode *tree) -{ - if (!tree || tree->mChildren.isNull()) - { - return; - } - if (mChildren.notNull()) - { - std::vector to_delete_list; - LLXMLChildList::iterator itor = mChildren->map.begin(); - while (itor != mChildren->map.end()) - { - LLXMLNodePtr child = itor->second; - LLXMLNodePtr child_tree = NULL; - // Look for this child in the default's children - bool found = false; - LLXMLChildList::iterator itor2 = tree->mChildren->map.begin(); - while (itor2 != tree->mChildren->map.end()) - { - if (child->mName == itor2->second->mName) - { - child_tree = itor2->second; - found = true; - } - ++itor2; - } - if (!found) - { - to_delete_list.push_back(child); - } - else - { - child->scrubToTree(child_tree); - } - ++itor; - } - std::vector::iterator itor3; - for (itor3=to_delete_list.begin(); itor3!=to_delete_list.end(); ++itor3) - { - LLXMLNodePtr ptr; - (*itor3)->setParent(ptr); - } - } -} - -bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, bool use_default_if_missing) -{ - return getChild(gStringTable.checkStringEntry(name), node, use_default_if_missing); -} - -bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) -{ - if (mChildren.notNull()) - { - LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); - if (child_itr != mChildren->map.end()) - { - node = (*child_itr).second; - return true; - } - } - if (use_default_if_missing && !mDefault.isNull()) - { - return mDefault->getChild(name, node, false); - } - node = NULL; - return false; -} - -void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, bool use_default_if_missing) const -{ - getChildren(gStringTable.checkStringEntry(name), children, use_default_if_missing); -} - -void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, bool use_default_if_missing) const -{ - if (mChildren.notNull()) - { - LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); - if (child_itr != mChildren->map.end()) - { - LLXMLChildList::const_iterator children_end = mChildren->map.end(); - while (child_itr != children_end) - { - LLXMLNodePtr child = (*child_itr).second; - if (name != child->mName) - { - break; - } - children.insert(std::make_pair(child->mName->mString, child)); - child_itr++; - } - } - } - if (children.size() == 0 && use_default_if_missing && !mDefault.isNull()) - { - mDefault->getChildren(name, children, false); - } -} - -// 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); -} - -bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) -{ - LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); - if (child_itr != mAttributes.end()) - { - node = (*child_itr).second; - return true; - } - if (use_default_if_missing && !mDefault.isNull()) - { - return mDefault->getAttribute(name, node, false); - } - - return false; -} - -bool LLXMLNode::setAttributeString(const char* attr, const std::string& value) -{ - LLStringTableEntry* name = gStringTable.checkStringEntry(attr); - LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); - if (child_itr != mAttributes.end()) - { - LLXMLNodePtr node = (*child_itr).second; - node->setValue(value); - return true; - } - return false; -} - -bool LLXMLNode::hasAttribute(const char* name ) -{ - LLXMLNodePtr node; - return getAttribute(name, node); -} - -bool LLXMLNode::getAttributeBOOL(const char* name, bool& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getBoolValue(1, &value)); -} - -bool LLXMLNode::getAttributeU8(const char* name, U8& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getByteValue(1, &value)); -} - -bool LLXMLNode::getAttributeS8(const char* name, S8& value ) -{ - LLXMLNodePtr node; - S32 val; - if (!(getAttribute(name, node) && node->getIntValue(1, &val))) - { - return false; - } - value = val; - return true; -} - -bool LLXMLNode::getAttributeU16(const char* name, U16& value ) -{ - LLXMLNodePtr node; - U32 val; - if (!(getAttribute(name, node) && node->getUnsignedValue(1, &val))) - { - return false; - } - value = val; - return true; -} - -bool LLXMLNode::getAttributeS16(const char* name, S16& value ) -{ - LLXMLNodePtr node; - S32 val; - if (!(getAttribute(name, node) && node->getIntValue(1, &val))) - { - return false; - } - value = val; - return true; -} - -bool LLXMLNode::getAttributeU32(const char* name, U32& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getUnsignedValue(1, &value)); -} - -bool LLXMLNode::getAttributeS32(const char* name, S32& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getIntValue(1, &value)); -} - -bool LLXMLNode::getAttributeF32(const char* name, F32& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getFloatValue(1, &value)); -} - -bool LLXMLNode::getAttributeF64(const char* name, F64& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getDoubleValue(1, &value)); -} - -bool LLXMLNode::getAttributeColor(const char* name, LLColor4& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getFloatValue(4, value.mV)); -} - -bool LLXMLNode::getAttributeColor4(const char* name, LLColor4& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getFloatValue(4, value.mV)); -} - -bool LLXMLNode::getAttributeColor4U(const char* name, LLColor4U& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getByteValue(4, value.mV)); -} - -bool LLXMLNode::getAttributeVector3(const char* name, LLVector3& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getFloatValue(3, value.mV)); -} - -bool LLXMLNode::getAttributeVector3d(const char* name, LLVector3d& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getDoubleValue(3, value.mdV)); -} - -bool LLXMLNode::getAttributeQuat(const char* name, LLQuaternion& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getFloatValue(4, value.mQ)); -} - -bool LLXMLNode::getAttributeUUID(const char* name, LLUUID& value ) -{ - LLXMLNodePtr node; - return (getAttribute(name, node) && node->getUUIDValue(1, &value)); -} - -bool LLXMLNode::getAttributeString(const char* name, std::string& value ) -{ - LLXMLNodePtr node; - if (!getAttribute(name, node)) - { - return false; - } - value = node->getValue(); - return true; -} - -LLXMLNodePtr LLXMLNode::getRoot() -{ - if (mParent == NULL) - { - return this; - } - return mParent->getRoot(); -} - -/*static */ -const char *LLXMLNode::skipWhitespace(const char *str) -{ - // skip whitespace characters - while (str[0] == ' ' || str[0] == '\t' || str[0] == '\n') ++str; - return str; -} - -/*static */ -const char *LLXMLNode::skipNonWhitespace(const char *str) -{ - // skip non-whitespace characters - while (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != 0) ++str; - return str; -} - -/*static */ -const char *LLXMLNode::parseInteger(const char *str, U64 *dest, bool *is_negative, U32 precision, Encoding encoding) -{ - *dest = 0; - *is_negative = false; - - str = skipWhitespace(str); - - if (str[0] == 0) return NULL; - - if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT) - { - if (str[0] == '+') - { - ++str; - } - if (str[0] == '-') - { - *is_negative = true; - ++str; - } - - str = skipWhitespace(str); - - U64 ret = 0; - while (str[0] >= '0' && str[0] <= '9') - { - ret *= 10; - ret += str[0] - '0'; - ++str; - } - - if (str[0] == '.') - { - // If there is a fractional part, skip it - str = skipNonWhitespace(str); - } - - *dest = ret; - return str; - } - if (encoding == ENCODING_HEX) - { - U64 ret = 0; - str = skipWhitespace(str); - for (U32 pos=0; pos<(precision/4); ++pos) - { - ret <<= 4; - str = skipWhitespace(str); - if (str[0] >= '0' && str[0] <= '9') - { - ret += str[0] - '0'; - } - else if (str[0] >= 'a' && str[0] <= 'f') - { - ret += str[0] - 'a' + 10; - } - else if (str[0] >= 'A' && str[0] <= 'F') - { - ret += str[0] - 'A' + 10; - } - else - { - return NULL; - } - ++str; - } - - *dest = ret; - return str; - } - return NULL; -} - -// 25 elements - decimal expansions of 1/(2^n), multiplied by 10 each iteration -const U64 float_coeff_table[] = - { 5, 25, 125, 625, 3125, - 15625, 78125, 390625, 1953125, 9765625, - 48828125, 244140625, 1220703125, 6103515625LL, 30517578125LL, - 152587890625LL, 762939453125LL, 3814697265625LL, 19073486328125LL, 95367431640625LL, - 476837158203125LL, 2384185791015625LL, 11920928955078125LL, 59604644775390625LL, 298023223876953125LL }; - -// 36 elements - decimal expansions of 1/(2^n) after the last 28, truncated, no multiply each iteration -const U64 float_coeff_table_2[] = - { 149011611938476562LL,74505805969238281LL, - 37252902984619140LL, 18626451492309570LL, 9313225746154785LL, 4656612873077392LL, - 2328306436538696LL, 1164153218269348LL, 582076609134674LL, 291038304567337LL, - 145519152283668LL, 72759576141834LL, 36379788070917LL, 18189894035458LL, - 9094947017729LL, 4547473508864LL, 2273736754432LL, 1136868377216LL, - 568434188608LL, 284217094304LL, 142108547152LL, 71054273576LL, - 35527136788LL, 17763568394LL, 8881784197LL, 4440892098LL, - 2220446049LL, 1110223024LL, 555111512LL, 277555756LL, - 138777878, 69388939, 34694469, 17347234, - 8673617, 4336808, 2168404, 1084202, - 542101, 271050, 135525, 67762, - }; - -/*static */ -const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding) -{ - str = skipWhitespace(str); - - if (str[0] == 0) return NULL; - - if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT) - { - str = skipWhitespace(str); - - if (memcmp(str, "inf", 3) == 0) - { - *(U64 *)dest = 0x7FF0000000000000ll; - return str + 3; - } - if (memcmp(str, "-inf", 4) == 0) - { - *(U64 *)dest = 0xFFF0000000000000ll; - return str + 4; - } - if (memcmp(str, "1.#INF", 6) == 0) - { - *(U64 *)dest = 0x7FF0000000000000ll; - return str + 6; - } - if (memcmp(str, "-1.#INF", 7) == 0) - { - *(U64 *)dest = 0xFFF0000000000000ll; - return str + 7; - } - - F64 negative = 1.0f; - if (str[0] == '+') - { - ++str; - } - if (str[0] == '-') - { - negative = -1.0f; - ++str; - } - - const char* base_str = str; - str = skipWhitespace(str); - - // Parse the integer part of the expression - U64 int_part = 0; - while (str[0] >= '0' && str[0] <= '9') - { - int_part *= 10; - int_part += U64(str[0] - '0'); - ++str; - } - - U64 f_part = 0;//, f_decimal = 1; - if (str[0] == '.') - { - ++str; - U64 remainder = 0; - U32 pos = 0; - // Parse the decimal part of the expression - while (str[0] >= '0' && str[0] <= '9' && pos < 25) - { - remainder = (remainder*10) + U64(str[0] - '0'); - f_part <<= 1; - //f_decimal <<= 1; - // Check the n'th bit - if (remainder >= float_coeff_table[pos]) - { - remainder -= float_coeff_table[pos]; - f_part |= 1; - } - ++pos; - ++str; - } - if (pos == 25) - { - // Drop any excessive digits - while (str[0] >= '0' && str[0] <= '9') - { - ++str; - } - } - else - { - while (pos < 25) - { - remainder *= 10; - f_part <<= 1; - //f_decimal <<= 1; - // Check the n'th bit - if (remainder >= float_coeff_table[pos]) - { - remainder -= float_coeff_table[pos]; - f_part |= 1; - } - ++pos; - } - } - pos = 0; - while (pos < 36) - { - f_part <<= 1; - //f_decimal <<= 1; - if (remainder >= float_coeff_table_2[pos]) - { - remainder -= float_coeff_table_2[pos]; - f_part |= 1; - } - ++pos; - } - } - - F64 ret = F64(int_part) + (F64(f_part)/F64(1LL<<61)); - - F64 exponent = 1.f; - if (str[0] == 'e') - { - // Scientific notation! - ++str; - U64 exp; - bool is_negative; - str = parseInteger(str, &exp, &is_negative, 64, ENCODING_DECIMAL); - if (str == NULL) - { - exp = 1; - } - F64 exp_d = F64(exp) * (is_negative?-1:1); - exponent = pow(10.0, exp_d); - } - - if (str == base_str) - { - // no digits parsed - return NULL; - } - else - { - *dest = ret*negative*exponent; - return str; - } - } - if (encoding == ENCODING_HEX) - { - U64 bytes_dest; - bool is_negative; - str = parseInteger(str, (U64 *)&bytes_dest, &is_negative, precision, ENCODING_HEX); - // Upcast to F64 - switch (precision) - { - case 32: - { - U32 short_dest = (U32)bytes_dest; - F32 ret_val = *(F32 *)&short_dest; - *dest = ret_val; - } - break; - case 64: - *dest = *(F64 *)&bytes_dest; - break; - default: - return NULL; - } - return str; - } - return NULL; -} - -U32 LLXMLNode::getBoolValue(U32 expected_length, bool *array) -{ - llassert(array); - - // Check type - accept booleans or strings - if (mType != TYPE_BOOLEAN && mType != TYPE_STRING && mType != TYPE_UNKNOWN) - { - return 0; - } - - std::string *str_array = new std::string[expected_length]; - - U32 length = getStringValue(expected_length, str_array); - - U32 ret_length = 0; - for (U32 i=0; imString << "' -- expected " << expected_length << " but " - << "only found " << ret_length << LL_ENDL; - } -#endif - return ret_length; -} - -U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding) -{ - llassert(array); - - // Check type - accept bytes or integers (below 256 only) - if (mType != TYPE_INTEGER - && mType != TYPE_UNKNOWN) - { - return 0; - } - - if (mLength > 0 && mLength != expected_length) - { - LL_WARNS() << "XMLNode::getByteValue asked for " << expected_length - << " elements, while node has " << mLength << LL_ENDL; - return 0; - } - - if (encoding == ENCODING_DEFAULT) - { - encoding = mEncoding; - } - - const char *value_string = mValue.c_str(); - - U32 i; - for (i=0; i 255 || is_negative) - { - LL_WARNS() << "getByteValue: Value outside of valid range." << LL_ENDL; - break; - } - array[i] = U8(value); - } -#if LL_DEBUG - if (i != expected_length) - { - LL_DEBUGS() << "LLXMLNode::getByteValue() failed for node named '" - << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << LL_ENDL; - } -#endif - return i; -} - -U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding) -{ - llassert(array); - - // Check type - accept bytes or integers - if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) - { - return 0; - } - - if (mLength > 0 && mLength != expected_length) - { - LL_WARNS() << "XMLNode::getIntValue asked for " << expected_length - << " elements, while node has " << mLength << LL_ENDL; - return 0; - } - - if (encoding == ENCODING_DEFAULT) - { - encoding = mEncoding; - } - - const char *value_string = mValue.c_str(); - - U32 i = 0; - for (i=0; i 0x7fffffff) - { - LL_WARNS() << "getIntValue: Value outside of valid range." << LL_ENDL; - break; - } - array[i] = S32(value) * (is_negative?-1:1); - } - -#if LL_DEBUG - if (i != expected_length) - { - LL_DEBUGS() << "LLXMLNode::getIntValue() failed for node named '" - << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << LL_ENDL; - } -#endif - return i; -} - -U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding) -{ - llassert(array); - - // Check type - accept bytes or integers - if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) - { - return 0; - } - - if (mLength > 0 && mLength != expected_length) - { - LL_WARNS() << "XMLNode::getUnsignedValue asked for " << expected_length - << " elements, while node has " << mLength << LL_ENDL; - return 0; - } - - if (encoding == ENCODING_DEFAULT) - { - encoding = mEncoding; - } - - const char *value_string = mValue.c_str(); - - U32 i = 0; - // Int type - for (i=0; i 0xffffffff) - { - LL_WARNS() << "getUnsignedValue: Value outside of valid range." << LL_ENDL; - break; - } - array[i] = U32(value); - } - -#if LL_DEBUG - if (i != expected_length) - { - LL_DEBUGS() << "LLXMLNode::getUnsignedValue() failed for node named '" - << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << LL_ENDL; - } -#endif - - return i; -} - -U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding) -{ - llassert(array); - - // Check type - accept bytes or integers - if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) - { - return 0; - } - - if (mLength > 0 && mLength != expected_length) - { - LL_WARNS() << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; - return 0; - } - - if (encoding == ENCODING_DEFAULT) - { - encoding = mEncoding; - } - - const char *value_string = mValue.c_str(); - - U32 i = 0; - // Int type - for (i=0; imString << "' -- expected " << expected_length << " but " - << "only found " << i << LL_ENDL; - } -#endif - - return i; -} - -U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding) -{ - llassert(array); - - // Check type - accept only floats or doubles - if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN) - { - return 0; - } - - if (mLength > 0 && mLength != expected_length) - { - LL_WARNS() << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; - return 0; - } - - if (encoding == ENCODING_DEFAULT) - { - encoding = mEncoding; - } - - const char *value_string = mValue.c_str(); - - U32 i; - for (i=0; imString << "' -- expected " << expected_length << " but " - << "only found " << i << LL_ENDL; - } -#endif - return i; -} - -U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding) -{ - llassert(array); - - // Check type - accept only floats or doubles - if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN) - { - return 0; - } - - if (mLength > 0 && mLength != expected_length) - { - LL_WARNS() << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; - return 0; - } - - if (encoding == ENCODING_DEFAULT) - { - encoding = mEncoding; - } - - const char *value_string = mValue.c_str(); - - U32 i; - for (i=0; imString << "' -- expected " << expected_length << " but " - << "only found " << i << LL_ENDL; - } -#endif - return i; -} - -U32 LLXMLNode::getStringValue(U32 expected_length, std::string *array) -{ - llassert(array); - - // Can always return any value as a string - - if (mLength > 0 && mLength != expected_length) - { - LL_WARNS() << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; - return 0; - } - - U32 num_returned_strings = 0; - - // Array of strings is whitespace-separated - const std::string sep(" \n\t"); - - std::string::size_type n = 0; - std::string::size_type m = 0; - while(1) - { - if (num_returned_strings >= expected_length) - { - break; - } - n = mValue.find_first_not_of(sep, m); - m = mValue.find_first_of(sep, n); - if (m == std::string::npos) - { - break; - } - array[num_returned_strings++] = mValue.substr(n,m-n); - } - if (n != std::string::npos && num_returned_strings < expected_length) - { - array[num_returned_strings++] = mValue.substr(n); - } -#if LL_DEBUG - if (num_returned_strings != expected_length) - { - LL_DEBUGS() << "LLXMLNode::getStringValue() failed for node named '" - << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << num_returned_strings << LL_ENDL; - } -#endif - - return num_returned_strings; -} - -U32 LLXMLNode::getUUIDValue(U32 expected_length, LLUUID *array) -{ - llassert(array); - - // Check type - if (mType != TYPE_UUID && mType != TYPE_UNKNOWN) - { - return 0; - } - - const char *value_string = mValue.c_str(); - - U32 i; - for (i=0; imString << "' -- expected " << expected_length << " but " - << "only found " << i << LL_ENDL; - } -#endif - return i; -} - -U32 LLXMLNode::getNodeRefValue(U32 expected_length, LLXMLNode **array) -{ - llassert(array); - - // Check type - if (mType != TYPE_NODEREF && mType != TYPE_UNKNOWN) - { - return 0; - } - - std::string *string_array = new std::string[expected_length]; - - U32 num_strings = getStringValue(expected_length, string_array); - - U32 num_returned_refs = 0; - - LLXMLNodePtr root = getRoot(); - for (U32 strnum=0; strnumfindID(string_array[strnum], node_list); - if (node_list.empty()) - { - LL_WARNS() << "XML: Could not find node ID: " << string_array[strnum] << LL_ENDL; - } - else if (node_list.size() > 1) - { - LL_WARNS() << "XML: Node ID not unique: " << string_array[strnum] << LL_ENDL; - } - else - { - LLXMLNodeList::const_iterator list_itr = node_list.begin(); - if (list_itr != node_list.end()) - { - LLXMLNode* child = (*list_itr).second; - - array[num_returned_refs++] = child; - } - } - } - - delete[] string_array; - - return num_returned_refs; -} - -void LLXMLNode::setBoolValue(U32 length, const bool *array) -{ - if (length == 0) return; - - std::string new_value; - for (U32 pos=0; pos 0) - { - new_value = llformat("%s %s", new_value.c_str(), array[pos]?"true":"false"); - } - else - { - new_value = array[pos]?"true":"false"; - } - } - - mValue = new_value; - mEncoding = ENCODING_DEFAULT; - mLength = length; - mType = TYPE_BOOLEAN; -} - -void LLXMLNode::setByteValue(U32 length, const U8* const array, Encoding encoding) -{ - if (length == 0) return; - - std::string new_value; - if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) - { - for (U32 pos=0; pos 0) - { - new_value.append(llformat(" %u", array[pos])); - } - else - { - new_value = llformat("%u", array[pos]); - } - } - } - if (encoding == ENCODING_HEX) - { - for (U32 pos=0; pos 0 && pos % 16 == 0) - { - new_value.append(llformat(" %02X", array[pos])); - } - else - { - new_value.append(llformat("%02X", array[pos])); - } - } - } - // TODO -- Handle Base32 - - mValue = new_value; - mEncoding = encoding; - mLength = length; - mType = TYPE_INTEGER; - mPrecision = 8; -} - - -void LLXMLNode::setIntValue(U32 length, const S32 *array, Encoding encoding) -{ - if (length == 0) return; - - std::string new_value; - if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) - { - for (U32 pos=0; pos 0) - { - new_value.append(llformat(" %d", array[pos])); - } - else - { - new_value = llformat("%d", array[pos]); - } - } - mValue = new_value; - } - else if (encoding == ENCODING_HEX) - { - for (U32 pos=0; pos 0 && pos % 16 == 0) - { - new_value.append(llformat(" %08X", ((U32 *)array)[pos])); - } - else - { - new_value.append(llformat("%08X", ((U32 *)array)[pos])); - } - } - mValue = new_value; - } - else - { - mValue = new_value; - } - // TODO -- Handle Base32 - - mEncoding = encoding; - mLength = length; - mType = TYPE_INTEGER; - mPrecision = 32; -} - -void LLXMLNode::setUnsignedValue(U32 length, const U32* array, Encoding encoding) -{ - if (length == 0) return; - - std::string new_value; - if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) - { - for (U32 pos=0; pos 0) - { - new_value.append(llformat(" %u", array[pos])); - } - else - { - new_value = llformat("%u", array[pos]); - } - } - } - if (encoding == ENCODING_HEX) - { - for (U32 pos=0; pos 0 && pos % 16 == 0) - { - new_value.append(llformat(" %08X", array[pos])); - } - else - { - new_value.append(llformat("%08X", array[pos])); - } - } - mValue = new_value; - } - // TODO -- Handle Base32 - - mValue = new_value; - mEncoding = encoding; - mLength = length; - mType = TYPE_INTEGER; - mPrecision = 32; -} - -#if LL_WINDOWS -#define PU64 "I64u" -#else -#define PU64 "llu" -#endif - -void LLXMLNode::setLongValue(U32 length, const U64* array, Encoding encoding) -{ - if (length == 0) return; - - std::string new_value; - if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) - { - for (U32 pos=0; pos 0) - { - new_value.append(llformat(" %" PU64, array[pos])); - } - else - { - new_value = llformat("%" PU64, array[pos]); - } - } - mValue = new_value; - } - if (encoding == ENCODING_HEX) - { - for (U32 pos=0; pos>32); - U32 lower_32 = U32(array[pos]&0xffffffff); - if (pos > 0 && pos % 8 == 0) - { - new_value.append(llformat(" %08X%08X", upper_32, lower_32)); - } - else - { - new_value.append(llformat("%08X%08X", upper_32, lower_32)); - } - } - mValue = new_value; - } - else - { - mValue = new_value; - } - // TODO -- Handle Base32 - - mEncoding = encoding; - mLength = length; - mType = TYPE_INTEGER; - mPrecision = 64; -} - -void LLXMLNode::setFloatValue(U32 length, const F32 *array, Encoding encoding, U32 precision) -{ - if (length == 0) return; - - std::string new_value; - if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) - { - std::string format_string; - if (precision > 0) - { - if (precision > 25) - { - precision = 25; - } - format_string = llformat( "%%.%dg", precision); - } - else - { - format_string = llformat( "%%g"); - } - - for (U32 pos=0; pos 0) - { - new_value.append(" "); - new_value.append(llformat(format_string.c_str(), array[pos])); - } - else - { - new_value.assign(llformat(format_string.c_str(), array[pos])); - } - } - mValue = new_value; - } - else if (encoding == ENCODING_HEX) - { - U32 *byte_array = (U32 *)array; - setUnsignedValue(length, byte_array, ENCODING_HEX); - } - else - { - mValue = new_value; - } - - mEncoding = encoding; - mLength = length; - mType = TYPE_FLOAT; - mPrecision = 32; -} - -void LLXMLNode::setDoubleValue(U32 length, const F64 *array, Encoding encoding, U32 precision) -{ - if (length == 0) return; - - std::string new_value; - if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) - { - std::string format_string; - if (precision > 0) - { - if (precision > 25) - { - precision = 25; - } - format_string = llformat( "%%.%dg", precision); - } - else - { - format_string = llformat( "%%g"); - } - for (U32 pos=0; pos 0) - { - new_value.append(" "); - new_value.append(llformat(format_string.c_str(), array[pos])); - } - else - { - new_value.assign(llformat(format_string.c_str(), array[pos])); - } - } - mValue = new_value; - } - if (encoding == ENCODING_HEX) - { - U64 *byte_array = (U64 *)array; - setLongValue(length, byte_array, ENCODING_HEX); - } - else - { - mValue = new_value; - } - // TODO -- Handle Base32 - - mEncoding = encoding; - mLength = length; - mType = TYPE_FLOAT; - mPrecision = 64; -} - -// static -std::string LLXMLNode::escapeXML(const std::string& xml) -{ - std::string out; - for (std::string::size_type i = 0; i < xml.size(); ++i) - { - char c = xml[i]; - switch(c) - { - case '"': out.append("""); break; - case '\'': out.append("'"); break; - case '&': out.append("&"); break; - case '<': out.append("<"); break; - case '>': out.append(">"); break; - default: out.push_back(c); break; - } - } - return out; -} - -void LLXMLNode::setStringValue(U32 length, const std::string *strings) -{ - if (length == 0) return; - - std::string new_value; - for (U32 pos=0; posmID != "") - { - new_value.append(array[pos]->mID); - } - else - { - new_value.append("(null)"); - } - if (pos < length-1) new_value.append(" "); - } - - mValue = new_value; - mEncoding = ENCODING_DEFAULT; - mLength = length; - mType = TYPE_NODEREF; -} - -void LLXMLNode::setValue(const std::string& value) -{ - if (TYPE_CONTAINER == mType) - { - mType = TYPE_UNKNOWN; - } - mValue = value; -} - -void LLXMLNode::setDefault(LLXMLNode *default_node) -{ - mDefault = default_node; -} - -void LLXMLNode::findDefault(LLXMLNode *defaults_list) -{ - if (defaults_list) - { - LLXMLNodeList children; - defaults_list->getChildren(mName->mString, children); - - LLXMLNodeList::const_iterator children_itr; - LLXMLNodeList::const_iterator children_end = children.end(); - for (children_itr = children.begin(); children_itr != children_end; ++children_itr) - { - LLXMLNode* child = (*children_itr).second; - if (child->mVersionMajor == mVersionMajor && - child->mVersionMinor == mVersionMinor) - { - mDefault = child; - return; - } - } - } - mDefault = NULL; -} - -bool LLXMLNode::deleteChildren(const std::string& name) -{ - U32 removed_count = 0; - LLXMLNodeList node_list; - findName(name, node_list); - if (!node_list.empty()) - { - // TODO -- use multimap::find() - // TODO -- need to watch out for invalid iterators - LLXMLNodeList::iterator children_itr; - for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr) - { - LLXMLNode* child = (*children_itr).second; - if (deleteChild(child)) - { - removed_count++; - } - } - } - return removed_count > 0; -} - -bool LLXMLNode::deleteChildren(LLStringTableEntry* name) -{ - U32 removed_count = 0; - LLXMLNodeList node_list; - findName(name, node_list); - if (!node_list.empty()) - { - // TODO -- use multimap::find() - // TODO -- need to watch out for invalid iterators - LLXMLNodeList::iterator children_itr; - for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr) - { - LLXMLNode* child = (*children_itr).second; - if (deleteChild(child)) - { - removed_count++; - } - } - } - return removed_count > 0; -} - -void LLXMLNode::setAttributes(LLXMLNode::ValueType type, U32 precision, LLXMLNode::Encoding encoding, U32 length) -{ - mType = type; - mEncoding = encoding; - mPrecision = precision; - mLength = length; -} - -void LLXMLNode::setName(const std::string& name) -{ - setName(gStringTable.addStringEntry(name)); -} - -void LLXMLNode::setName(LLStringTableEntry* name) -{ - LLXMLNode* old_parent = mParent; - if (mParent) - { - // we need to remove and re-add to the parent so that - // the multimap key agrees with this node's name - mParent->removeChild(this); - } - mName = name; - if (old_parent) - { - LLXMLNodePtr this_ptr(this); - old_parent->addChild(this_ptr); - } -} - -// Unused -// void LLXMLNode::appendValue(const std::string& value) -// { -// mValue.append(value); -// } - -U32 LLXMLNode::getChildCount() const -{ - if (mChildren.notNull()) - { - return mChildren->map.size(); - } - return 0; -} - -//*************************************************** -// UNIT TESTING -//*************************************************** - -U32 get_rand(U32 max_value) -{ - U32 random_num = rand() + ((U32)rand() << 16); - return (random_num % max_value); -} - -LLXMLNode *get_rand_node(LLXMLNode *node) -{ - if (node->mChildren.notNull()) - { - U32 num_children = node->mChildren->map.size(); - if (get_rand(2) == 0) - { - while (true) - { - S32 child_num = S32(get_rand(num_children*2)) - num_children; - LLXMLChildList::iterator itor = node->mChildren->map.begin(); - while (child_num > 0) - { - --child_num; - ++itor; - } - if (!itor->second->mIsAttribute) - { - return get_rand_node(itor->second); - } - } - } - } - return node; -} - -void LLXMLNode::createUnitTest(S32 max_num_children) -{ - // Random ID - std::string rand_id; - U32 rand_id_len = get_rand(10)+5; - for (U32 pos = 0; posmID = child_id; - - // Random Length - U32 array_size = get_rand(28)+1; - - // Random Encoding - Encoding new_encoding = get_rand(2)?ENCODING_DECIMAL:ENCODING_HEX; - - // Random Type - int type = get_rand(8); - switch (type) - { - case 0: // TYPE_CONTAINER - new_child->createUnitTest(max_num_children/2); - break; - case 1: // TYPE_BOOLEAN - { - bool random_bool_values[30]; - for (U32 value=0; valuesetBoolValue(array_size, random_bool_values); - } - break; - case 2: // TYPE_INTEGER (32-bit) - { - U32 random_int_values[30]; - for (U32 value=0; valuesetUnsignedValue(array_size, random_int_values, new_encoding); - } - break; - case 3: // TYPE_INTEGER (64-bit) - { - U64 random_int_values[30]; - for (U64 value=0; valuesetLongValue(array_size, random_int_values, new_encoding); - } - break; - case 4: // TYPE_FLOAT (32-bit) - { - F32 random_float_values[30]; - for (U32 value=0; valuesetFloatValue(array_size, random_float_values, new_encoding, 12); - } - break; - case 5: // TYPE_FLOAT (64-bit) - { - F64 random_float_values[30]; - for (U32 value=0; value> 32); - } - new_child->setDoubleValue(array_size, random_float_values, new_encoding, 12); - } - break; - case 6: // TYPE_UUID - { - LLUUID random_uuid_values[30]; - for (U32 value=0; valuesetUUIDValue(array_size, random_uuid_values); - } - break; - case 7: // TYPE_NODEREF - { - LLXMLNode *random_node_array[30]; - LLXMLNode *root = getRoot(); - for (U32 value=0; valuemName->mString; - for (U32 pos=0; possetNodeRefValue(array_size, (const LLXMLNode **)random_node_array); - } - break; - } - } - - createChild("integer_checksum", true)->setUnsignedValue(1, &integer_checksum, LLXMLNode::ENCODING_HEX); - createChild("long_checksum", true)->setLongValue(1, &long_checksum, LLXMLNode::ENCODING_HEX); - createChild("bool_true_count", true)->setUnsignedValue(1, &bool_true_count, LLXMLNode::ENCODING_HEX); - createChild("uuid_checksum", true)->setUUIDValue(1, &uuid_checksum); - createChild("noderef_checksum", true)->setUnsignedValue(1, &noderef_checksum, LLXMLNode::ENCODING_HEX); - createChild("float_checksum", true)->setUnsignedValue(1, &float_checksum, LLXMLNode::ENCODING_HEX); -} - -bool LLXMLNode::performUnitTest(std::string &error_buffer) -{ - if (mChildren.isNull()) - { - error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString)); - return false; - } - - // Checksums - U32 integer_checksum = 0; - U32 bool_true_count = 0; - LLUUID uuid_checksum; - U32 noderef_checksum = 0; - U32 float_checksum = 0; - U64 long_checksum = 0; - - LLXMLChildList::iterator itor; - for (itor=mChildren->map.begin(); itor!=mChildren->map.end(); ++itor) - { - LLXMLNode *node = itor->second; - if (node->mIsAttribute) - { - continue; - } - if (node->mType == TYPE_CONTAINER) - { - if (!node->performUnitTest(error_buffer)) - { - error_buffer.append(llformat("Child test failed for %s.\n", mName->mString)); - //return false; - } - continue; - } - if (node->mLength < 1 || node->mLength > 30) - { - error_buffer.append(llformat("ERROR Node %s: Invalid array length %d, child %s.\n", mName->mString, node->mLength, node->mName->mString)); - return false; - } - switch (node->mType) - { - case TYPE_CONTAINER: - case TYPE_UNKNOWN: - break; - case TYPE_BOOLEAN: - { - bool bool_array[30]; - if (node->getBoolValue(node->mLength, bool_array) < node->mLength) - { - error_buffer.append(llformat("ERROR Node %s: Could not read boolean array, child %s.\n", mName->mString, node->mName->mString)); - return false; - } - for (U32 pos=0; pos<(U32)node->mLength; ++pos) - { - if (bool_array[pos]) - { - ++bool_true_count; - } - } - } - break; - case TYPE_INTEGER: - { - if (node->mPrecision == 32) - { - U32 integer_array[30]; - if (node->getUnsignedValue(node->mLength, integer_array, node->mEncoding) < node->mLength) - { - error_buffer.append(llformat("ERROR Node %s: Could not read integer array, child %s.\n", mName->mString, node->mName->mString)); - return false; - } - for (U32 pos=0; pos<(U32)node->mLength; ++pos) - { - integer_checksum ^= integer_array[pos]; - } - } - else - { - U64 integer_array[30]; - if (node->getLongValue(node->mLength, integer_array, node->mEncoding) < node->mLength) - { - error_buffer.append(llformat("ERROR Node %s: Could not read long integer array, child %s.\n", mName->mString, node->mName->mString)); - return false; - } - for (U32 pos=0; pos<(U32)node->mLength; ++pos) - { - long_checksum ^= integer_array[pos]; - } - } - } - break; - case TYPE_FLOAT: - { - if (node->mPrecision == 32) - { - F32 float_array[30]; - if (node->getFloatValue(node->mLength, float_array, node->mEncoding) < node->mLength) - { - error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString)); - return false; - } - for (U32 pos=0; pos<(U32)node->mLength; ++pos) - { - U32 float_bits = ((U32 *)float_array)[pos]; - float_checksum ^= (float_bits & 0xfffff000); - } - } - else - { - F64 float_array[30]; - if (node->getDoubleValue(node->mLength, float_array, node->mEncoding) < node->mLength) - { - error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString)); - return false; - } - for (U32 pos=0; pos<(U32)node->mLength; ++pos) - { - U64 float_bits = ((U64 *)float_array)[pos]; - float_checksum ^= ((float_bits & 0xfffffff000000000ll) >> 32); - } - } - } - break; - case TYPE_STRING: - break; - case TYPE_UUID: - { - LLUUID uuid_array[30]; - if (node->getUUIDValue(node->mLength, uuid_array) < node->mLength) - { - error_buffer.append(llformat("ERROR Node %s: Could not read uuid array, child %s.\n", mName->mString, node->mName->mString)); - return false; - } - for (U32 pos=0; pos<(U32)node->mLength; ++pos) - { - for (S32 byte=0; bytegetNodeRefValue(node->mLength, node_array) < node->mLength) - { - error_buffer.append(llformat("ERROR Node %s: Could not read node ref array, child %s.\n", mName->mString, node->mName->mString)); - return false; - } - for (U32 pos=0; posmLength; ++pos) - { - const char *node_name = node_array[pos]->mName->mString; - for (U32 pos2=0; pos2getUnsignedValue(1, &node_integer_checksum, ENCODING_HEX) != 1) - { - error_buffer.append(llformat("ERROR Node %s: Integer checksum missing.\n", mName->mString)); - return false; - } - if (node_integer_checksum != integer_checksum) - { - error_buffer.append(llformat("ERROR Node %s: Integer checksum mismatch: read %X / calc %X.\n", mName->mString, node_integer_checksum, integer_checksum)); - return false; - } - } - - { - U64 node_long_checksum = 0; - if (!getAttribute("long_checksum", checksum_node, false) || - checksum_node->getLongValue(1, &node_long_checksum, ENCODING_HEX) != 1) - { - error_buffer.append(llformat("ERROR Node %s: Long Integer checksum missing.\n", mName->mString)); - return false; - } - if (node_long_checksum != long_checksum) - { - U32 *pp1 = (U32 *)&node_long_checksum; - U32 *pp2 = (U32 *)&long_checksum; - 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])); - return false; - } - } - - { - U32 node_bool_true_count = 0; - if (!getAttribute("bool_true_count", checksum_node, false) || - checksum_node->getUnsignedValue(1, &node_bool_true_count, ENCODING_HEX) != 1) - { - error_buffer.append(llformat("ERROR Node %s: Boolean checksum missing.\n", mName->mString)); - return false; - } - if (node_bool_true_count != bool_true_count) - { - error_buffer.append(llformat("ERROR Node %s: Boolean checksum mismatch: read %X / calc %X.\n", mName->mString, node_bool_true_count, bool_true_count)); - return false; - } - } - - { - LLUUID node_uuid_checksum; - if (!getAttribute("uuid_checksum", checksum_node, false) || - checksum_node->getUUIDValue(1, &node_uuid_checksum) != 1) - { - error_buffer.append(llformat("ERROR Node %s: UUID checksum missing.\n", mName->mString)); - return false; - } - if (node_uuid_checksum != uuid_checksum) - { - error_buffer.append(llformat("ERROR Node %s: UUID checksum mismatch: read %s / calc %s.\n", mName->mString, node_uuid_checksum.asString().c_str(), uuid_checksum.asString().c_str())); - return false; - } - } - - { - U32 node_noderef_checksum = 0; - if (!getAttribute("noderef_checksum", checksum_node, false) || - checksum_node->getUnsignedValue(1, &node_noderef_checksum, ENCODING_HEX) != 1) - { - error_buffer.append(llformat("ERROR Node %s: Node Ref checksum missing.\n", mName->mString)); - return false; - } - if (node_noderef_checksum != noderef_checksum) - { - error_buffer.append(llformat("ERROR Node %s: Node Ref checksum mismatch: read %X / calc %X.\n", mName->mString, node_noderef_checksum, noderef_checksum)); - return false; - } - } - - { - U32 node_float_checksum = 0; - if (!getAttribute("float_checksum", checksum_node, false) || - checksum_node->getUnsignedValue(1, &node_float_checksum, ENCODING_HEX) != 1) - { - error_buffer.append(llformat("ERROR Node %s: Float checksum missing.\n", mName->mString)); - return false; - } - if (node_float_checksum != float_checksum) - { - error_buffer.append(llformat("ERROR Node %s: Float checksum mismatch: read %X / calc %X.\n", mName->mString, node_float_checksum, float_checksum)); - return false; - } - } - - return true; -} - -LLXMLNodePtr LLXMLNode::getFirstChild() const -{ - if (mChildren.isNull()) return NULL; - LLXMLNodePtr ret = mChildren->head; - return ret; -} - -LLXMLNodePtr LLXMLNode::getNextSibling() const -{ - LLXMLNodePtr ret = mNext; - return ret; -} - -std::string LLXMLNode::getSanitizedValue() const -{ - if (mIsAttribute) - { - return getValue() ; - } - else - { - return getTextContents(); - } -} - - -std::string LLXMLNode::getTextContents() const -{ - std::string msg; - std::string contents = mValue; - std::string::size_type n = contents.find_first_not_of(" \t\n"); - if (n != std::string::npos && contents[n] == '\"') - { - // Case 1: node has quoted text - S32 num_lines = 0; - while(1) - { - // mContents[n] == '"' - ++n; - std::string::size_type t = n; - std::string::size_type m = 0; - // fix-up escaped characters - while(1) - { - m = contents.find_first_of("\\\"", t); // find first \ or " - if ((m == std::string::npos) || (contents[m] == '\"')) - { - break; - } - contents.erase(m,1); - t = m+1; - } - if (m == std::string::npos) - { - break; - } - // mContents[m] == '"' - num_lines++; - msg += contents.substr(n,m-n) + "\n"; - n = contents.find_first_of("\"", m+1); - if (n == std::string::npos) - { - if (num_lines == 1) - { - msg.erase(msg.size()-1); // remove "\n" if only one line - } - break; - } - } - } - else - { - // Case 2: node has embedded text (beginning and trailing whitespace trimmed) - std::string::size_type start = mValue.find_first_not_of(" \t\n"); - if (start != mValue.npos) - { - std::string::size_type end = mValue.find_last_not_of(" \t\n"); - if (end != mValue.npos) - { - msg = mValue.substr(start, end+1-start); - } - else - { - msg = mValue.substr(start); - } - } - // Convert any internal CR to LF - msg = utf8str_removeCRLF(msg); - } - return msg; -} - -void LLXMLNode::setLineNumber(S32 line_number) -{ - mLineNumber = line_number; -} - -S32 LLXMLNode::getLineNumber() -{ - return mLineNumber; -} +/** + * @file llxmlnode.cpp + * @author Tom Yedwab + * @brief LLXMLNode implementation + * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include +#include + +#include "llxmlnode.h" + +#include "v3color.h" +#include "v4color.h" +#include "v4coloru.h" +#include "v3math.h" +#include "v3dmath.h" +#include "v4math.h" +#include "llquaternion.h" +#include "llstring.h" +#include "lluuid.h" +#include "lldir.h" + +// static +bool LLXMLNode::sStripEscapedStrings = true; +bool LLXMLNode::sStripWhitespaceValues = false; + +LLXMLNode::LLXMLNode() : + mID(""), + mParser(NULL), + mIsAttribute(false), + mVersionMajor(0), + mVersionMinor(0), + mLength(0), + mPrecision(64), + mType(TYPE_CONTAINER), + mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), + mParent(NULL), + mChildren(NULL), + mAttributes(), + mPrev(NULL), + mNext(NULL), + mName(NULL), + mValue(""), + mDefault(NULL) +{ +} + +LLXMLNode::LLXMLNode(const char* name, bool is_attribute) : + mID(""), + mParser(NULL), + mIsAttribute(is_attribute), + mVersionMajor(0), + mVersionMinor(0), + mLength(0), + mPrecision(64), + mType(TYPE_CONTAINER), + mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), + mParent(NULL), + mChildren(NULL), + mAttributes(), + mPrev(NULL), + mNext(NULL), + mValue(""), + mDefault(NULL) +{ + mName = gStringTable.addStringEntry(name); +} + +LLXMLNode::LLXMLNode(LLStringTableEntry* name, bool is_attribute) : + mID(""), + mParser(NULL), + mIsAttribute(is_attribute), + mVersionMajor(0), + mVersionMinor(0), + mLength(0), + mPrecision(64), + mType(TYPE_CONTAINER), + mEncoding(ENCODING_DEFAULT), + mLineNumber(-1), + 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), + mLineNumber(0), + mParser(NULL), + 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) + { + LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); + newnode->addChild(temp_ptr_for_gcc); + } + } + for (LLXMLAttribList::iterator iter = mAttributes.begin(); + iter != mAttributes.end(); ++iter) + { + LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); + newnode->addChild(temp_ptr_for_gcc); + } + + return newnode; +} + +// virtual +LLXMLNode::~LLXMLNode() +{ + // Strictly speaking none of this should be required execept 'delete 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) + { + LLXMLNodePtr child = iter->second; + child->mParent = NULL; + child->mNext = NULL; + child->mPrev = NULL; + } + mChildren->map.clear(); + mChildren->head = NULL; + mChildren->tail = NULL; + mChildren = NULL; + } + for (LLXMLAttribList::iterator iter = mAttributes.begin(); + iter != mAttributes.end(); ++iter) + { + LLXMLNodePtr attr = iter->second; + attr->mParent = NULL; + attr->mNext = NULL; + attr->mPrev = NULL; + } + llassert(mParent == NULL); + mDefault = NULL; +} + +bool LLXMLNode::isNull() +{ + return (mName == NULL); +} + +// protected +bool LLXMLNode::removeChild(LLXMLNode *target_child) +{ + if (!target_child) + { + return false; + } + if (target_child->mIsAttribute) + { + LLXMLAttribList::iterator children_itr = mAttributes.find(target_child->mName); + if (children_itr != mAttributes.end()) + { + target_child->mParent = NULL; + mAttributes.erase(children_itr); + return true; + } + } + else if (mChildren.notNull()) + { + LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName); + while (children_itr != mChildren->map.end()) + { + if (target_child == children_itr->second) + { + if (target_child == mChildren->head) + { + 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; + if (prev.notNull()) prev->mNext = next; + if (next.notNull()) next->mPrev = prev; + + target_child->mPrev = NULL; + target_child->mNext = NULL; + target_child->mParent = NULL; + mChildren->map.erase(children_itr); + if (mChildren->map.empty()) + { + mChildren = NULL; + } + return true; + } + else if (children_itr->first != target_child->mName) + { + break; + } + else + { + ++children_itr; + } + } + } + return false; +} + +void LLXMLNode::addChild(LLXMLNodePtr& new_child) +{ + if (new_child->mParent != NULL) + { + if (new_child->mParent == this) + { + return; + } + new_child->mParent->removeChild(new_child); + } + + new_child->mParent = this; + if (new_child->mIsAttribute) + { + LLXMLAttribList::iterator found_it = mAttributes.find(new_child->mName); + if (found_it != mAttributes.end()) + { + removeChild(found_it->second); + } + mAttributes.insert(std::make_pair(new_child->mName, new_child)); + } + else + { + if (mChildren.isNull()) + { + mChildren = new LLXMLChildren(); + mChildren->head = new_child; + mChildren->tail = new_child; + } + mChildren->map.insert(std::make_pair(new_child->mName, new_child)); + + if (mChildren->tail != new_child) + { + mChildren->tail->mNext = new_child; + new_child->mPrev = mChildren->tail; + mChildren->tail = new_child; + } + } + + new_child->updateDefault(); +} + +// virtual +LLXMLNodePtr LLXMLNode::createChild(const char* name, bool is_attribute) +{ + return createChild(gStringTable.addStringEntry(name), is_attribute); +} + +// virtual +LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, bool is_attribute) +{ + LLXMLNodePtr ret(new LLXMLNode(name, is_attribute)); + ret->mID.clear(); + + addChild(ret); + return ret; +} + +bool LLXMLNode::deleteChild(LLXMLNode *child) +{ + if (removeChild(child)) + { + return true; + } + return false; +} + +void LLXMLNode::setParent(LLXMLNodePtr& new_parent) +{ + if (new_parent.notNull()) + { + LLXMLNodePtr this_ptr(this); + new_parent->addChild(this_ptr); + } + else + { + if (mParent != NULL) + { + LLXMLNodePtr old_parent = mParent; + mParent = NULL; + old_parent->removeChild(this); + } + } +} + + +void LLXMLNode::updateDefault() +{ + if (mParent != NULL && !mParent->mDefault.isNull()) + { + mDefault = NULL; + + // Find default value in parent's default tree + if (!mParent->mDefault.isNull()) + { + findDefault(mParent->mDefault); + } + } + + if (mChildren.notNull()) + { + LLXMLChildList::const_iterator children_itr; + LLXMLChildList::const_iterator children_end = mChildren->map.end(); + for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) + { + LLXMLNodePtr child = (*children_itr).second; + child->updateDefault(); + } + } +} + +void XMLCALL StartXMLNode(void *userData, + const XML_Char *name, + const XML_Char **atts) +{ + // 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; + + // Set the parent-child relationship with the current active node + LLXMLNode* parent = (LLXMLNode *)userData; + + if (NULL == parent) + { + LL_WARNS() << "parent (userData) is NULL; aborting function" << LL_ENDL; + return; + } + + 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); + + // Parse attributes + U32 pos = 0; + while (atts[pos] != NULL) + { + std::string attr_name = atts[pos]; + std::string attr_value = atts[pos+1]; + + // Special cases + if ('i' == attr_name[0] && "id" == attr_name) + { + new_node->mID = attr_value; + } + else if ('v' == attr_name[0] && "version" == attr_name) + { + U32 version_major = 0; + U32 version_minor = 0; + if (sscanf(attr_value.c_str(), "%d.%d", &version_major, &version_minor) > 0) + { + new_node->mVersionMajor = version_major; + new_node->mVersionMinor = version_minor; + } + } + else if (('s' == attr_name[0] && "size" == attr_name) || ('l' == attr_name[0] && "length" == attr_name)) + { + U32 length; + if (sscanf(attr_value.c_str(), "%d", &length) > 0) + { + new_node->mLength = length; + } + } + else if ('p' == attr_name[0] && "precision" == attr_name) + { + U32 precision; + if (sscanf(attr_value.c_str(), "%d", &precision) > 0) + { + new_node->mPrecision = precision; + } + } + else if ('t' == attr_name[0] && "type" == attr_name) + { + if ("boolean" == attr_value) + { + new_node->mType = LLXMLNode::TYPE_BOOLEAN; + } + else if ("integer" == attr_value) + { + new_node->mType = LLXMLNode::TYPE_INTEGER; + } + else if ("float" == attr_value) + { + new_node->mType = LLXMLNode::TYPE_FLOAT; + } + else if ("string" == attr_value) + { + new_node->mType = LLXMLNode::TYPE_STRING; + } + else if ("uuid" == attr_value) + { + new_node->mType = LLXMLNode::TYPE_UUID; + } + else if ("noderef" == attr_value) + { + new_node->mType = LLXMLNode::TYPE_NODEREF; + } + } + else if ('e' == attr_name[0] && "encoding" == attr_name) + { + if ("decimal" == attr_value) + { + new_node->mEncoding = LLXMLNode::ENCODING_DECIMAL; + } + else if ("hex" == attr_value) + { + new_node->mEncoding = LLXMLNode::ENCODING_HEX; + } + /*else if (attr_value == "base32") + { + new_node->mEncoding = LLXMLNode::ENCODING_BASE32; + }*/ + } + + // only one attribute child per description + LLXMLNodePtr attr_node; + 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); + + pos += 2; + } + + if (parent) + { + parent->addChild(new_node); + } +} + +void XMLCALL EndXMLNode(void *userData, + const XML_Char *name) +{ + // [FUGLY] Set the current active node to the current node's parent + LLXMLNode *node = (LLXMLNode *)userData; + XML_Parser *parser = node->mParser; + XML_SetUserData(*parser, (void *)node->mParent); + // SJB: total hack: + if (LLXMLNode::sStripWhitespaceValues) + { + std::string value = node->getValue(); + bool is_empty = true; + for (std::string::size_type s = 0; s < value.length(); s++) + { + char c = value[s]; + if (c != ' ' && c != '\t' && c != '\n') + { + is_empty = false; + break; + } + } + if (is_empty) + { + value.clear(); + node->setValue(value); + } + } +} + +void XMLCALL XMLData(void *userData, + const XML_Char *s, + int len) +{ + LLXMLNode* current_node = (LLXMLNode *)userData; + std::string value = current_node->getValue(); + if (LLXMLNode::sStripEscapedStrings) + { + if (s[0] == '\"' && s[len-1] == '\"') + { + // Special-case: Escaped string. + std::string unescaped_string; + for (S32 pos=1; possetValue(value); + return; + } + } + value.append(std::string(s, len)); + current_node->setValue(value); +} + + + +// static +bool LLXMLNode::updateNode( + LLXMLNodePtr& node, + LLXMLNodePtr& update_node) +{ + + if (!node || !update_node) + { + LL_WARNS() << "Node invalid" << LL_ENDL; + return false; + } + + //update the node value + node->mValue = update_node->mValue; + + //update all attribute values + LLXMLAttribList::const_iterator itor; + + for(itor = update_node->mAttributes.begin(); itor != update_node->mAttributes.end(); ++itor) + { + const LLStringTableEntry* attribNameEntry = (*itor).first; + LLXMLNodePtr updateAttribNode = (*itor).second; + + LLXMLNodePtr attribNode; + + node->getAttribute(attribNameEntry, attribNode, 0); + + if (attribNode) + { + attribNode->mValue = updateAttribNode->mValue; + } + } + + //update all of node's children with updateNodes children that match name + LLXMLNodePtr child = node->getFirstChild(); + LLXMLNodePtr last_child = child; + LLXMLNodePtr updateChild; + + for (updateChild = update_node->getFirstChild(); updateChild.notNull(); + updateChild = updateChild->getNextSibling()) + { + while(child.notNull()) + { + std::string nodeName; + std::string updateName; + + updateChild->getAttributeString("name", updateName); + child->getAttributeString("name", nodeName); + + + //if it's a combobox there's no name, but there is a value + if (updateName.empty()) + { + updateChild->getAttributeString("value", updateName); + child->getAttributeString("value", nodeName); + } + + if ((nodeName != "") && (updateName == nodeName)) + { + updateNode(child, updateChild); + last_child = child; + child = child->getNextSibling(); + if (child.isNull()) + { + child = node->getFirstChild(); + } + break; + } + + child = child->getNextSibling(); + if (child.isNull()) + { + child = node->getFirstChild(); + } + if (child == last_child) + { + break; + } + } + } + + return true; +} + +// static +bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree) +{ + // Read file + LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL; + LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ + if (fp == NULL) + { + node = NULL ; + return false; + } + fseek(fp, 0, SEEK_END); + U32 length = ftell(fp); + fseek(fp, 0, SEEK_SET); + + U8* buffer = new U8[length+1]; + size_t nread = fread(buffer, 1, length, fp); + buffer[nread] = 0; + fclose(fp); + + bool rv = parseBuffer(buffer, nread, node, defaults_tree); + delete [] buffer; + return rv; +} + +// static +bool LLXMLNode::parseBuffer( + U8* buffer, + U32 length, + LLXMLNodePtr& node, + LLXMLNode* defaults) +{ + // Init + XML_Parser my_parser = XML_ParserCreate(NULL); + XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode); + XML_SetCharacterDataHandler(my_parser, XMLData); + + // Create a root node + LLXMLNode *file_node_ptr = new LLXMLNode("XML", false); + LLXMLNodePtr file_node = file_node_ptr; + + file_node->mParser = &my_parser; + + XML_SetUserData(my_parser, (void *)file_node_ptr); + + // Do the parsing + if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK) + { + LL_WARNS() << "Error parsing xml error code: " + << XML_ErrorString(XML_GetErrorCode(my_parser)) + << " on line " << XML_GetCurrentLineNumber(my_parser) + << LL_ENDL; + } + + // Deinit + XML_ParserFree(my_parser); + + if (!file_node->mChildren || file_node->mChildren->map.size() != 1) + { + LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." + << LL_ENDL; + node = NULL ; + return false; + } + + LLXMLNode *return_node = file_node->mChildren->map.begin()->second; + + return_node->setDefault(defaults); + return_node->updateDefault(); + + node = return_node; + return true; +} + +// static +bool LLXMLNode::parseStream( + std::istream& str, + LLXMLNodePtr& node, + LLXMLNode* defaults) +{ + // Init + XML_Parser my_parser = XML_ParserCreate(NULL); + XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode); + XML_SetCharacterDataHandler(my_parser, XMLData); + + // Create a root node + LLXMLNode *file_node_ptr = new LLXMLNode("XML", false); + LLXMLNodePtr file_node = file_node_ptr; + + file_node->mParser = &my_parser; + + XML_SetUserData(my_parser, (void *)file_node_ptr); + + const int BUFSIZE = 1024; + U8* buffer = new U8[BUFSIZE]; + + while(str.good()) + { + str.read((char*)buffer, BUFSIZE); + int count = (int)str.gcount(); + + if (XML_Parse(my_parser, (const char *)buffer, count, !str.good()) != XML_STATUS_OK) + { + LL_WARNS() << "Error parsing xml error code: " + << XML_ErrorString(XML_GetErrorCode(my_parser)) + << " on lne " << XML_GetCurrentLineNumber(my_parser) + << LL_ENDL; + break; + } + } + + delete [] buffer; + + // Deinit + XML_ParserFree(my_parser); + + if (!file_node->mChildren || file_node->mChildren->map.size() != 1) + { + LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." + << LL_ENDL; + node = NULL; + return false; + } + + LLXMLNode *return_node = file_node->mChildren->map.begin()->second; + + return_node->setDefault(defaults); + return_node->updateDefault(); + + node = return_node; + return true; +} + + +bool LLXMLNode::isFullyDefault() +{ + if (mDefault.isNull()) + { + return false; + } + bool has_default_value = (mValue == mDefault->mValue); + bool has_default_attribute = (mIsAttribute == mDefault->mIsAttribute); + bool has_default_type = mIsAttribute || (mType == mDefault->mType); + bool has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding); + bool has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision); + bool has_default_length = mIsAttribute || (mLength == mDefault->mLength); + + if (has_default_value + && has_default_type + && has_default_encoding + && has_default_precision + && has_default_length + && has_default_attribute) + { + if (mChildren.notNull()) + { + LLXMLChildList::const_iterator children_itr; + LLXMLChildList::const_iterator children_end = mChildren->map.end(); + for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) + { + LLXMLNodePtr child = (*children_itr).second; + if (!child->isFullyDefault()) + { + return false; + } + } + } + return true; + } + + return false; +} + +// static +bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, + const std::vector& paths) +{ + if (paths.empty()) return false; + + std::string filename = paths.front(); + if (filename.empty()) + { + return false; + } + + if (!LLXMLNode::parseFile(filename, root, NULL)) + { + LL_WARNS() << "Problem reading UI description file: " << filename << " " << errno << LL_ENDL; + return false; + } + + LLXMLNodePtr updateRoot; + + std::vector::const_iterator itor; + + // We've already dealt with the first item, skip that one + for (itor = paths.begin() + 1; itor != paths.end(); ++itor) + { + std::string layer_filename = *itor; + if(layer_filename.empty() || layer_filename == filename) + { + // no localized version of this file, that's ok, keep looking + continue; + } + + if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL)) + { + LL_WARNS() << "Problem reading localized UI description file: " << layer_filename << LL_ENDL; + return false; + } + + std::string nodeName; + std::string updateName; + + updateRoot->getAttributeString("name", updateName); + root->getAttributeString("name", nodeName); + + if (updateName == nodeName) + { + LLXMLNode::updateNode(root, updateRoot); + } + } + + return true; +} + +// static +void LLXMLNode::writeHeaderToFile(LLFILE *out_file) +{ + fprintf(out_file, "\n"); +} + +void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations) +{ + if (isFullyDefault()) + { + // Don't write out nodes that are an exact match to defaults + return; + } + + std::ostringstream ostream; + writeToOstream(ostream, indent, use_type_decorations); + std::string outstring = ostream.str(); + size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file); + if (written != outstring.length()) + { + LL_WARNS() << "Short write" << LL_ENDL; + } +} + +void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent, bool use_type_decorations) +{ + if (isFullyDefault()) + { + // Don't write out nodes that are an exact match to defaults + return; + } + + bool has_default_type = mDefault.isNull()?false:(mType == mDefault->mType); + bool has_default_encoding = mDefault.isNull()?false:(mEncoding == mDefault->mEncoding); + bool has_default_precision = mDefault.isNull()?false:(mPrecision == mDefault->mPrecision); + bool has_default_length = mDefault.isNull()?false:(mLength == mDefault->mLength); + + // stream the name + output_stream << indent << "<" << mName->mString << "\n"; + + if (use_type_decorations) + { + // ID + if (mID != "") + { + output_stream << indent << " id=\"" << mID << "\"\n"; + } + + // Type + if (!has_default_type) + { + 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) + { + 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 << indent << " precision=\"" << mPrecision << "\"\n"; + } + + // Version + if (mVersionMajor > 0 || mVersionMinor > 0) + { + output_stream << indent << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"\n"; + } + + // Array length + if (!has_default_length && mLength > 0) + { + output_stream << indent << " length=\"" << mLength << "\"\n"; + } + } + + { + // Write out attributes + LLXMLAttribList::const_iterator attr_itr; + LLXMLAttribList::const_iterator attr_end = mAttributes.end(); + for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr) + { + LLXMLNodePtr child = (*attr_itr).second; + if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue) + { + std::string attr = child->mName->mString; + if (use_type_decorations + && (attr == "id" || + attr == "type" || + attr == "encoding" || + attr == "precision" || + attr == "version" || + attr == "length")) + { + continue; // skip built-in attributes + } + + std::string attr_str = llformat(" %s=\"%s\"", + attr.c_str(), + escapeXML(child->mValue).c_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"; + return; + } + else + { + output_stream << ">\n"; + if (mChildren.notNull()) + { + // stream non-attributes + std::string next_indent = indent + " "; + for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling()) + { + child->writeToOstream(output_stream, next_indent, use_type_decorations); + } + } + if (!mValue.empty()) + { + std::string contents = getTextContents(); + output_stream << indent << " " << escapeXML(contents) << "\n"; + } + output_stream << indent << "mString << ">\n"; + } +} + +void LLXMLNode::findName(const std::string& name, LLXMLNodeList &results) +{ + LLStringTableEntry* name_entry = gStringTable.checkStringEntry(name); + if (name_entry == mName) + { + results.insert(std::make_pair(this->mName->mString, this)); + return; + } + if (mChildren.notNull()) + { + LLXMLChildList::const_iterator children_itr; + LLXMLChildList::const_iterator children_end = mChildren->map.end(); + for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) + { + LLXMLNodePtr child = (*children_itr).second; + child->findName(name_entry, results); + } + } +} + +void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results) +{ + if (name == mName) + { + results.insert(std::make_pair(this->mName->mString, this)); + return; + } + if (mChildren.notNull()) + { + LLXMLChildList::const_iterator children_itr; + LLXMLChildList::const_iterator children_end = mChildren->map.end(); + for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) + { + LLXMLNodePtr child = (*children_itr).second; + child->findName(name, results); + } + } +} + +void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results) +{ + if (id == mID) + { + results.insert(std::make_pair(this->mName->mString, this)); + return; + } + if (mChildren.notNull()) + { + LLXMLChildList::const_iterator children_itr; + LLXMLChildList::const_iterator children_end = mChildren->map.end(); + for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) + { + LLXMLNodePtr child = (*children_itr).second; + child->findID(id, results); + } + } +} + +void LLXMLNode::scrubToTree(LLXMLNode *tree) +{ + if (!tree || tree->mChildren.isNull()) + { + return; + } + if (mChildren.notNull()) + { + std::vector to_delete_list; + LLXMLChildList::iterator itor = mChildren->map.begin(); + while (itor != mChildren->map.end()) + { + LLXMLNodePtr child = itor->second; + LLXMLNodePtr child_tree = NULL; + // Look for this child in the default's children + bool found = false; + LLXMLChildList::iterator itor2 = tree->mChildren->map.begin(); + while (itor2 != tree->mChildren->map.end()) + { + if (child->mName == itor2->second->mName) + { + child_tree = itor2->second; + found = true; + } + ++itor2; + } + if (!found) + { + to_delete_list.push_back(child); + } + else + { + child->scrubToTree(child_tree); + } + ++itor; + } + std::vector::iterator itor3; + for (itor3=to_delete_list.begin(); itor3!=to_delete_list.end(); ++itor3) + { + LLXMLNodePtr ptr; + (*itor3)->setParent(ptr); + } + } +} + +bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, bool use_default_if_missing) +{ + return getChild(gStringTable.checkStringEntry(name), node, use_default_if_missing); +} + +bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) +{ + if (mChildren.notNull()) + { + LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); + if (child_itr != mChildren->map.end()) + { + node = (*child_itr).second; + return true; + } + } + if (use_default_if_missing && !mDefault.isNull()) + { + return mDefault->getChild(name, node, false); + } + node = NULL; + return false; +} + +void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, bool use_default_if_missing) const +{ + getChildren(gStringTable.checkStringEntry(name), children, use_default_if_missing); +} + +void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, bool use_default_if_missing) const +{ + if (mChildren.notNull()) + { + LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); + if (child_itr != mChildren->map.end()) + { + LLXMLChildList::const_iterator children_end = mChildren->map.end(); + while (child_itr != children_end) + { + LLXMLNodePtr child = (*child_itr).second; + if (name != child->mName) + { + break; + } + children.insert(std::make_pair(child->mName->mString, child)); + child_itr++; + } + } + } + if (children.size() == 0 && use_default_if_missing && !mDefault.isNull()) + { + mDefault->getChildren(name, children, false); + } +} + +// 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); +} + +bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) +{ + LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); + if (child_itr != mAttributes.end()) + { + node = (*child_itr).second; + return true; + } + if (use_default_if_missing && !mDefault.isNull()) + { + return mDefault->getAttribute(name, node, false); + } + + return false; +} + +bool LLXMLNode::setAttributeString(const char* attr, const std::string& value) +{ + LLStringTableEntry* name = gStringTable.checkStringEntry(attr); + LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); + if (child_itr != mAttributes.end()) + { + LLXMLNodePtr node = (*child_itr).second; + node->setValue(value); + return true; + } + return false; +} + +bool LLXMLNode::hasAttribute(const char* name ) +{ + LLXMLNodePtr node; + return getAttribute(name, node); +} + +bool LLXMLNode::getAttributeBOOL(const char* name, bool& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getBoolValue(1, &value)); +} + +bool LLXMLNode::getAttributeU8(const char* name, U8& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getByteValue(1, &value)); +} + +bool LLXMLNode::getAttributeS8(const char* name, S8& value ) +{ + LLXMLNodePtr node; + S32 val; + if (!(getAttribute(name, node) && node->getIntValue(1, &val))) + { + return false; + } + value = val; + return true; +} + +bool LLXMLNode::getAttributeU16(const char* name, U16& value ) +{ + LLXMLNodePtr node; + U32 val; + if (!(getAttribute(name, node) && node->getUnsignedValue(1, &val))) + { + return false; + } + value = val; + return true; +} + +bool LLXMLNode::getAttributeS16(const char* name, S16& value ) +{ + LLXMLNodePtr node; + S32 val; + if (!(getAttribute(name, node) && node->getIntValue(1, &val))) + { + return false; + } + value = val; + return true; +} + +bool LLXMLNode::getAttributeU32(const char* name, U32& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getUnsignedValue(1, &value)); +} + +bool LLXMLNode::getAttributeS32(const char* name, S32& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getIntValue(1, &value)); +} + +bool LLXMLNode::getAttributeF32(const char* name, F32& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getFloatValue(1, &value)); +} + +bool LLXMLNode::getAttributeF64(const char* name, F64& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getDoubleValue(1, &value)); +} + +bool LLXMLNode::getAttributeColor(const char* name, LLColor4& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getFloatValue(4, value.mV)); +} + +bool LLXMLNode::getAttributeColor4(const char* name, LLColor4& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getFloatValue(4, value.mV)); +} + +bool LLXMLNode::getAttributeColor4U(const char* name, LLColor4U& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getByteValue(4, value.mV)); +} + +bool LLXMLNode::getAttributeVector3(const char* name, LLVector3& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getFloatValue(3, value.mV)); +} + +bool LLXMLNode::getAttributeVector3d(const char* name, LLVector3d& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getDoubleValue(3, value.mdV)); +} + +bool LLXMLNode::getAttributeQuat(const char* name, LLQuaternion& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getFloatValue(4, value.mQ)); +} + +bool LLXMLNode::getAttributeUUID(const char* name, LLUUID& value ) +{ + LLXMLNodePtr node; + return (getAttribute(name, node) && node->getUUIDValue(1, &value)); +} + +bool LLXMLNode::getAttributeString(const char* name, std::string& value ) +{ + LLXMLNodePtr node; + if (!getAttribute(name, node)) + { + return false; + } + value = node->getValue(); + return true; +} + +LLXMLNodePtr LLXMLNode::getRoot() +{ + if (mParent == NULL) + { + return this; + } + return mParent->getRoot(); +} + +/*static */ +const char *LLXMLNode::skipWhitespace(const char *str) +{ + // skip whitespace characters + while (str[0] == ' ' || str[0] == '\t' || str[0] == '\n') ++str; + return str; +} + +/*static */ +const char *LLXMLNode::skipNonWhitespace(const char *str) +{ + // skip non-whitespace characters + while (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != 0) ++str; + return str; +} + +/*static */ +const char *LLXMLNode::parseInteger(const char *str, U64 *dest, bool *is_negative, U32 precision, Encoding encoding) +{ + *dest = 0; + *is_negative = false; + + str = skipWhitespace(str); + + if (str[0] == 0) return NULL; + + if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT) + { + if (str[0] == '+') + { + ++str; + } + if (str[0] == '-') + { + *is_negative = true; + ++str; + } + + str = skipWhitespace(str); + + U64 ret = 0; + while (str[0] >= '0' && str[0] <= '9') + { + ret *= 10; + ret += str[0] - '0'; + ++str; + } + + if (str[0] == '.') + { + // If there is a fractional part, skip it + str = skipNonWhitespace(str); + } + + *dest = ret; + return str; + } + if (encoding == ENCODING_HEX) + { + U64 ret = 0; + str = skipWhitespace(str); + for (U32 pos=0; pos<(precision/4); ++pos) + { + ret <<= 4; + str = skipWhitespace(str); + if (str[0] >= '0' && str[0] <= '9') + { + ret += str[0] - '0'; + } + else if (str[0] >= 'a' && str[0] <= 'f') + { + ret += str[0] - 'a' + 10; + } + else if (str[0] >= 'A' && str[0] <= 'F') + { + ret += str[0] - 'A' + 10; + } + else + { + return NULL; + } + ++str; + } + + *dest = ret; + return str; + } + return NULL; +} + +// 25 elements - decimal expansions of 1/(2^n), multiplied by 10 each iteration +const U64 float_coeff_table[] = + { 5, 25, 125, 625, 3125, + 15625, 78125, 390625, 1953125, 9765625, + 48828125, 244140625, 1220703125, 6103515625LL, 30517578125LL, + 152587890625LL, 762939453125LL, 3814697265625LL, 19073486328125LL, 95367431640625LL, + 476837158203125LL, 2384185791015625LL, 11920928955078125LL, 59604644775390625LL, 298023223876953125LL }; + +// 36 elements - decimal expansions of 1/(2^n) after the last 28, truncated, no multiply each iteration +const U64 float_coeff_table_2[] = + { 149011611938476562LL,74505805969238281LL, + 37252902984619140LL, 18626451492309570LL, 9313225746154785LL, 4656612873077392LL, + 2328306436538696LL, 1164153218269348LL, 582076609134674LL, 291038304567337LL, + 145519152283668LL, 72759576141834LL, 36379788070917LL, 18189894035458LL, + 9094947017729LL, 4547473508864LL, 2273736754432LL, 1136868377216LL, + 568434188608LL, 284217094304LL, 142108547152LL, 71054273576LL, + 35527136788LL, 17763568394LL, 8881784197LL, 4440892098LL, + 2220446049LL, 1110223024LL, 555111512LL, 277555756LL, + 138777878, 69388939, 34694469, 17347234, + 8673617, 4336808, 2168404, 1084202, + 542101, 271050, 135525, 67762, + }; + +/*static */ +const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding) +{ + str = skipWhitespace(str); + + if (str[0] == 0) return NULL; + + if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT) + { + str = skipWhitespace(str); + + if (memcmp(str, "inf", 3) == 0) + { + *(U64 *)dest = 0x7FF0000000000000ll; + return str + 3; + } + if (memcmp(str, "-inf", 4) == 0) + { + *(U64 *)dest = 0xFFF0000000000000ll; + return str + 4; + } + if (memcmp(str, "1.#INF", 6) == 0) + { + *(U64 *)dest = 0x7FF0000000000000ll; + return str + 6; + } + if (memcmp(str, "-1.#INF", 7) == 0) + { + *(U64 *)dest = 0xFFF0000000000000ll; + return str + 7; + } + + F64 negative = 1.0f; + if (str[0] == '+') + { + ++str; + } + if (str[0] == '-') + { + negative = -1.0f; + ++str; + } + + const char* base_str = str; + str = skipWhitespace(str); + + // Parse the integer part of the expression + U64 int_part = 0; + while (str[0] >= '0' && str[0] <= '9') + { + int_part *= 10; + int_part += U64(str[0] - '0'); + ++str; + } + + U64 f_part = 0;//, f_decimal = 1; + if (str[0] == '.') + { + ++str; + U64 remainder = 0; + U32 pos = 0; + // Parse the decimal part of the expression + while (str[0] >= '0' && str[0] <= '9' && pos < 25) + { + remainder = (remainder*10) + U64(str[0] - '0'); + f_part <<= 1; + //f_decimal <<= 1; + // Check the n'th bit + if (remainder >= float_coeff_table[pos]) + { + remainder -= float_coeff_table[pos]; + f_part |= 1; + } + ++pos; + ++str; + } + if (pos == 25) + { + // Drop any excessive digits + while (str[0] >= '0' && str[0] <= '9') + { + ++str; + } + } + else + { + while (pos < 25) + { + remainder *= 10; + f_part <<= 1; + //f_decimal <<= 1; + // Check the n'th bit + if (remainder >= float_coeff_table[pos]) + { + remainder -= float_coeff_table[pos]; + f_part |= 1; + } + ++pos; + } + } + pos = 0; + while (pos < 36) + { + f_part <<= 1; + //f_decimal <<= 1; + if (remainder >= float_coeff_table_2[pos]) + { + remainder -= float_coeff_table_2[pos]; + f_part |= 1; + } + ++pos; + } + } + + F64 ret = F64(int_part) + (F64(f_part)/F64(1LL<<61)); + + F64 exponent = 1.f; + if (str[0] == 'e') + { + // Scientific notation! + ++str; + U64 exp; + bool is_negative; + str = parseInteger(str, &exp, &is_negative, 64, ENCODING_DECIMAL); + if (str == NULL) + { + exp = 1; + } + F64 exp_d = F64(exp) * (is_negative?-1:1); + exponent = pow(10.0, exp_d); + } + + if (str == base_str) + { + // no digits parsed + return NULL; + } + else + { + *dest = ret*negative*exponent; + return str; + } + } + if (encoding == ENCODING_HEX) + { + U64 bytes_dest; + bool is_negative; + str = parseInteger(str, (U64 *)&bytes_dest, &is_negative, precision, ENCODING_HEX); + // Upcast to F64 + switch (precision) + { + case 32: + { + U32 short_dest = (U32)bytes_dest; + F32 ret_val = *(F32 *)&short_dest; + *dest = ret_val; + } + break; + case 64: + *dest = *(F64 *)&bytes_dest; + break; + default: + return NULL; + } + return str; + } + return NULL; +} + +U32 LLXMLNode::getBoolValue(U32 expected_length, bool *array) +{ + llassert(array); + + // Check type - accept booleans or strings + if (mType != TYPE_BOOLEAN && mType != TYPE_STRING && mType != TYPE_UNKNOWN) + { + return 0; + } + + std::string *str_array = new std::string[expected_length]; + + U32 length = getStringValue(expected_length, str_array); + + U32 ret_length = 0; + for (U32 i=0; imString << "' -- expected " << expected_length << " but " + << "only found " << ret_length << LL_ENDL; + } +#endif + return ret_length; +} + +U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding) +{ + llassert(array); + + // Check type - accept bytes or integers (below 256 only) + if (mType != TYPE_INTEGER + && mType != TYPE_UNKNOWN) + { + return 0; + } + + if (mLength > 0 && mLength != expected_length) + { + LL_WARNS() << "XMLNode::getByteValue asked for " << expected_length + << " elements, while node has " << mLength << LL_ENDL; + return 0; + } + + if (encoding == ENCODING_DEFAULT) + { + encoding = mEncoding; + } + + const char *value_string = mValue.c_str(); + + U32 i; + for (i=0; i 255 || is_negative) + { + LL_WARNS() << "getByteValue: Value outside of valid range." << LL_ENDL; + break; + } + array[i] = U8(value); + } +#if LL_DEBUG + if (i != expected_length) + { + LL_DEBUGS() << "LLXMLNode::getByteValue() failed for node named '" + << mName->mString << "' -- expected " << expected_length << " but " + << "only found " << i << LL_ENDL; + } +#endif + return i; +} + +U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding) +{ + llassert(array); + + // Check type - accept bytes or integers + if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) + { + return 0; + } + + if (mLength > 0 && mLength != expected_length) + { + LL_WARNS() << "XMLNode::getIntValue asked for " << expected_length + << " elements, while node has " << mLength << LL_ENDL; + return 0; + } + + if (encoding == ENCODING_DEFAULT) + { + encoding = mEncoding; + } + + const char *value_string = mValue.c_str(); + + U32 i = 0; + for (i=0; i 0x7fffffff) + { + LL_WARNS() << "getIntValue: Value outside of valid range." << LL_ENDL; + break; + } + array[i] = S32(value) * (is_negative?-1:1); + } + +#if LL_DEBUG + if (i != expected_length) + { + LL_DEBUGS() << "LLXMLNode::getIntValue() failed for node named '" + << mName->mString << "' -- expected " << expected_length << " but " + << "only found " << i << LL_ENDL; + } +#endif + return i; +} + +U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding) +{ + llassert(array); + + // Check type - accept bytes or integers + if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) + { + return 0; + } + + if (mLength > 0 && mLength != expected_length) + { + LL_WARNS() << "XMLNode::getUnsignedValue asked for " << expected_length + << " elements, while node has " << mLength << LL_ENDL; + return 0; + } + + if (encoding == ENCODING_DEFAULT) + { + encoding = mEncoding; + } + + const char *value_string = mValue.c_str(); + + U32 i = 0; + // Int type + for (i=0; i 0xffffffff) + { + LL_WARNS() << "getUnsignedValue: Value outside of valid range." << LL_ENDL; + break; + } + array[i] = U32(value); + } + +#if LL_DEBUG + if (i != expected_length) + { + LL_DEBUGS() << "LLXMLNode::getUnsignedValue() failed for node named '" + << mName->mString << "' -- expected " << expected_length << " but " + << "only found " << i << LL_ENDL; + } +#endif + + return i; +} + +U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding) +{ + llassert(array); + + // Check type - accept bytes or integers + if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) + { + return 0; + } + + if (mLength > 0 && mLength != expected_length) + { + LL_WARNS() << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; + return 0; + } + + if (encoding == ENCODING_DEFAULT) + { + encoding = mEncoding; + } + + const char *value_string = mValue.c_str(); + + U32 i = 0; + // Int type + for (i=0; imString << "' -- expected " << expected_length << " but " + << "only found " << i << LL_ENDL; + } +#endif + + return i; +} + +U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding) +{ + llassert(array); + + // Check type - accept only floats or doubles + if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN) + { + return 0; + } + + if (mLength > 0 && mLength != expected_length) + { + LL_WARNS() << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; + return 0; + } + + if (encoding == ENCODING_DEFAULT) + { + encoding = mEncoding; + } + + const char *value_string = mValue.c_str(); + + U32 i; + for (i=0; imString << "' -- expected " << expected_length << " but " + << "only found " << i << LL_ENDL; + } +#endif + return i; +} + +U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding) +{ + llassert(array); + + // Check type - accept only floats or doubles + if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN) + { + return 0; + } + + if (mLength > 0 && mLength != expected_length) + { + LL_WARNS() << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; + return 0; + } + + if (encoding == ENCODING_DEFAULT) + { + encoding = mEncoding; + } + + const char *value_string = mValue.c_str(); + + U32 i; + for (i=0; imString << "' -- expected " << expected_length << " but " + << "only found " << i << LL_ENDL; + } +#endif + return i; +} + +U32 LLXMLNode::getStringValue(U32 expected_length, std::string *array) +{ + llassert(array); + + // Can always return any value as a string + + if (mLength > 0 && mLength != expected_length) + { + LL_WARNS() << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; + return 0; + } + + U32 num_returned_strings = 0; + + // Array of strings is whitespace-separated + const std::string sep(" \n\t"); + + std::string::size_type n = 0; + std::string::size_type m = 0; + while(1) + { + if (num_returned_strings >= expected_length) + { + break; + } + n = mValue.find_first_not_of(sep, m); + m = mValue.find_first_of(sep, n); + if (m == std::string::npos) + { + break; + } + array[num_returned_strings++] = mValue.substr(n,m-n); + } + if (n != std::string::npos && num_returned_strings < expected_length) + { + array[num_returned_strings++] = mValue.substr(n); + } +#if LL_DEBUG + if (num_returned_strings != expected_length) + { + LL_DEBUGS() << "LLXMLNode::getStringValue() failed for node named '" + << mName->mString << "' -- expected " << expected_length << " but " + << "only found " << num_returned_strings << LL_ENDL; + } +#endif + + return num_returned_strings; +} + +U32 LLXMLNode::getUUIDValue(U32 expected_length, LLUUID *array) +{ + llassert(array); + + // Check type + if (mType != TYPE_UUID && mType != TYPE_UNKNOWN) + { + return 0; + } + + const char *value_string = mValue.c_str(); + + U32 i; + for (i=0; imString << "' -- expected " << expected_length << " but " + << "only found " << i << LL_ENDL; + } +#endif + return i; +} + +U32 LLXMLNode::getNodeRefValue(U32 expected_length, LLXMLNode **array) +{ + llassert(array); + + // Check type + if (mType != TYPE_NODEREF && mType != TYPE_UNKNOWN) + { + return 0; + } + + std::string *string_array = new std::string[expected_length]; + + U32 num_strings = getStringValue(expected_length, string_array); + + U32 num_returned_refs = 0; + + LLXMLNodePtr root = getRoot(); + for (U32 strnum=0; strnumfindID(string_array[strnum], node_list); + if (node_list.empty()) + { + LL_WARNS() << "XML: Could not find node ID: " << string_array[strnum] << LL_ENDL; + } + else if (node_list.size() > 1) + { + LL_WARNS() << "XML: Node ID not unique: " << string_array[strnum] << LL_ENDL; + } + else + { + LLXMLNodeList::const_iterator list_itr = node_list.begin(); + if (list_itr != node_list.end()) + { + LLXMLNode* child = (*list_itr).second; + + array[num_returned_refs++] = child; + } + } + } + + delete[] string_array; + + return num_returned_refs; +} + +void LLXMLNode::setBoolValue(U32 length, const bool *array) +{ + if (length == 0) return; + + std::string new_value; + for (U32 pos=0; pos 0) + { + new_value = llformat("%s %s", new_value.c_str(), array[pos]?"true":"false"); + } + else + { + new_value = array[pos]?"true":"false"; + } + } + + mValue = new_value; + mEncoding = ENCODING_DEFAULT; + mLength = length; + mType = TYPE_BOOLEAN; +} + +void LLXMLNode::setByteValue(U32 length, const U8* const array, Encoding encoding) +{ + if (length == 0) return; + + std::string new_value; + if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) + { + for (U32 pos=0; pos 0) + { + new_value.append(llformat(" %u", array[pos])); + } + else + { + new_value = llformat("%u", array[pos]); + } + } + } + if (encoding == ENCODING_HEX) + { + for (U32 pos=0; pos 0 && pos % 16 == 0) + { + new_value.append(llformat(" %02X", array[pos])); + } + else + { + new_value.append(llformat("%02X", array[pos])); + } + } + } + // TODO -- Handle Base32 + + mValue = new_value; + mEncoding = encoding; + mLength = length; + mType = TYPE_INTEGER; + mPrecision = 8; +} + + +void LLXMLNode::setIntValue(U32 length, const S32 *array, Encoding encoding) +{ + if (length == 0) return; + + std::string new_value; + if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) + { + for (U32 pos=0; pos 0) + { + new_value.append(llformat(" %d", array[pos])); + } + else + { + new_value = llformat("%d", array[pos]); + } + } + mValue = new_value; + } + else if (encoding == ENCODING_HEX) + { + for (U32 pos=0; pos 0 && pos % 16 == 0) + { + new_value.append(llformat(" %08X", ((U32 *)array)[pos])); + } + else + { + new_value.append(llformat("%08X", ((U32 *)array)[pos])); + } + } + mValue = new_value; + } + else + { + mValue = new_value; + } + // TODO -- Handle Base32 + + mEncoding = encoding; + mLength = length; + mType = TYPE_INTEGER; + mPrecision = 32; +} + +void LLXMLNode::setUnsignedValue(U32 length, const U32* array, Encoding encoding) +{ + if (length == 0) return; + + std::string new_value; + if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) + { + for (U32 pos=0; pos 0) + { + new_value.append(llformat(" %u", array[pos])); + } + else + { + new_value = llformat("%u", array[pos]); + } + } + } + if (encoding == ENCODING_HEX) + { + for (U32 pos=0; pos 0 && pos % 16 == 0) + { + new_value.append(llformat(" %08X", array[pos])); + } + else + { + new_value.append(llformat("%08X", array[pos])); + } + } + mValue = new_value; + } + // TODO -- Handle Base32 + + mValue = new_value; + mEncoding = encoding; + mLength = length; + mType = TYPE_INTEGER; + mPrecision = 32; +} + +#if LL_WINDOWS +#define PU64 "I64u" +#else +#define PU64 "llu" +#endif + +void LLXMLNode::setLongValue(U32 length, const U64* array, Encoding encoding) +{ + if (length == 0) return; + + std::string new_value; + if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) + { + for (U32 pos=0; pos 0) + { + new_value.append(llformat(" %" PU64, array[pos])); + } + else + { + new_value = llformat("%" PU64, array[pos]); + } + } + mValue = new_value; + } + if (encoding == ENCODING_HEX) + { + for (U32 pos=0; pos>32); + U32 lower_32 = U32(array[pos]&0xffffffff); + if (pos > 0 && pos % 8 == 0) + { + new_value.append(llformat(" %08X%08X", upper_32, lower_32)); + } + else + { + new_value.append(llformat("%08X%08X", upper_32, lower_32)); + } + } + mValue = new_value; + } + else + { + mValue = new_value; + } + // TODO -- Handle Base32 + + mEncoding = encoding; + mLength = length; + mType = TYPE_INTEGER; + mPrecision = 64; +} + +void LLXMLNode::setFloatValue(U32 length, const F32 *array, Encoding encoding, U32 precision) +{ + if (length == 0) return; + + std::string new_value; + if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) + { + std::string format_string; + if (precision > 0) + { + if (precision > 25) + { + precision = 25; + } + format_string = llformat( "%%.%dg", precision); + } + else + { + format_string = llformat( "%%g"); + } + + for (U32 pos=0; pos 0) + { + new_value.append(" "); + new_value.append(llformat(format_string.c_str(), array[pos])); + } + else + { + new_value.assign(llformat(format_string.c_str(), array[pos])); + } + } + mValue = new_value; + } + else if (encoding == ENCODING_HEX) + { + U32 *byte_array = (U32 *)array; + setUnsignedValue(length, byte_array, ENCODING_HEX); + } + else + { + mValue = new_value; + } + + mEncoding = encoding; + mLength = length; + mType = TYPE_FLOAT; + mPrecision = 32; +} + +void LLXMLNode::setDoubleValue(U32 length, const F64 *array, Encoding encoding, U32 precision) +{ + if (length == 0) return; + + std::string new_value; + if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) + { + std::string format_string; + if (precision > 0) + { + if (precision > 25) + { + precision = 25; + } + format_string = llformat( "%%.%dg", precision); + } + else + { + format_string = llformat( "%%g"); + } + for (U32 pos=0; pos 0) + { + new_value.append(" "); + new_value.append(llformat(format_string.c_str(), array[pos])); + } + else + { + new_value.assign(llformat(format_string.c_str(), array[pos])); + } + } + mValue = new_value; + } + if (encoding == ENCODING_HEX) + { + U64 *byte_array = (U64 *)array; + setLongValue(length, byte_array, ENCODING_HEX); + } + else + { + mValue = new_value; + } + // TODO -- Handle Base32 + + mEncoding = encoding; + mLength = length; + mType = TYPE_FLOAT; + mPrecision = 64; +} + +// static +std::string LLXMLNode::escapeXML(const std::string& xml) +{ + std::string out; + for (std::string::size_type i = 0; i < xml.size(); ++i) + { + char c = xml[i]; + switch(c) + { + case '"': out.append("""); break; + case '\'': out.append("'"); break; + case '&': out.append("&"); break; + case '<': out.append("<"); break; + case '>': out.append(">"); break; + default: out.push_back(c); break; + } + } + return out; +} + +void LLXMLNode::setStringValue(U32 length, const std::string *strings) +{ + if (length == 0) return; + + std::string new_value; + for (U32 pos=0; posmID != "") + { + new_value.append(array[pos]->mID); + } + else + { + new_value.append("(null)"); + } + if (pos < length-1) new_value.append(" "); + } + + mValue = new_value; + mEncoding = ENCODING_DEFAULT; + mLength = length; + mType = TYPE_NODEREF; +} + +void LLXMLNode::setValue(const std::string& value) +{ + if (TYPE_CONTAINER == mType) + { + mType = TYPE_UNKNOWN; + } + mValue = value; +} + +void LLXMLNode::setDefault(LLXMLNode *default_node) +{ + mDefault = default_node; +} + +void LLXMLNode::findDefault(LLXMLNode *defaults_list) +{ + if (defaults_list) + { + LLXMLNodeList children; + defaults_list->getChildren(mName->mString, children); + + LLXMLNodeList::const_iterator children_itr; + LLXMLNodeList::const_iterator children_end = children.end(); + for (children_itr = children.begin(); children_itr != children_end; ++children_itr) + { + LLXMLNode* child = (*children_itr).second; + if (child->mVersionMajor == mVersionMajor && + child->mVersionMinor == mVersionMinor) + { + mDefault = child; + return; + } + } + } + mDefault = NULL; +} + +bool LLXMLNode::deleteChildren(const std::string& name) +{ + U32 removed_count = 0; + LLXMLNodeList node_list; + findName(name, node_list); + if (!node_list.empty()) + { + // TODO -- use multimap::find() + // TODO -- need to watch out for invalid iterators + LLXMLNodeList::iterator children_itr; + for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr) + { + LLXMLNode* child = (*children_itr).second; + if (deleteChild(child)) + { + removed_count++; + } + } + } + return removed_count > 0; +} + +bool LLXMLNode::deleteChildren(LLStringTableEntry* name) +{ + U32 removed_count = 0; + LLXMLNodeList node_list; + findName(name, node_list); + if (!node_list.empty()) + { + // TODO -- use multimap::find() + // TODO -- need to watch out for invalid iterators + LLXMLNodeList::iterator children_itr; + for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr) + { + LLXMLNode* child = (*children_itr).second; + if (deleteChild(child)) + { + removed_count++; + } + } + } + return removed_count > 0; +} + +void LLXMLNode::setAttributes(LLXMLNode::ValueType type, U32 precision, LLXMLNode::Encoding encoding, U32 length) +{ + mType = type; + mEncoding = encoding; + mPrecision = precision; + mLength = length; +} + +void LLXMLNode::setName(const std::string& name) +{ + setName(gStringTable.addStringEntry(name)); +} + +void LLXMLNode::setName(LLStringTableEntry* name) +{ + LLXMLNode* old_parent = mParent; + if (mParent) + { + // we need to remove and re-add to the parent so that + // the multimap key agrees with this node's name + mParent->removeChild(this); + } + mName = name; + if (old_parent) + { + LLXMLNodePtr this_ptr(this); + old_parent->addChild(this_ptr); + } +} + +// Unused +// void LLXMLNode::appendValue(const std::string& value) +// { +// mValue.append(value); +// } + +U32 LLXMLNode::getChildCount() const +{ + if (mChildren.notNull()) + { + return mChildren->map.size(); + } + return 0; +} + +//*************************************************** +// UNIT TESTING +//*************************************************** + +U32 get_rand(U32 max_value) +{ + U32 random_num = rand() + ((U32)rand() << 16); + return (random_num % max_value); +} + +LLXMLNode *get_rand_node(LLXMLNode *node) +{ + if (node->mChildren.notNull()) + { + U32 num_children = node->mChildren->map.size(); + if (get_rand(2) == 0) + { + while (true) + { + S32 child_num = S32(get_rand(num_children*2)) - num_children; + LLXMLChildList::iterator itor = node->mChildren->map.begin(); + while (child_num > 0) + { + --child_num; + ++itor; + } + if (!itor->second->mIsAttribute) + { + return get_rand_node(itor->second); + } + } + } + } + return node; +} + +void LLXMLNode::createUnitTest(S32 max_num_children) +{ + // Random ID + std::string rand_id; + U32 rand_id_len = get_rand(10)+5; + for (U32 pos = 0; posmID = child_id; + + // Random Length + U32 array_size = get_rand(28)+1; + + // Random Encoding + Encoding new_encoding = get_rand(2)?ENCODING_DECIMAL:ENCODING_HEX; + + // Random Type + int type = get_rand(8); + switch (type) + { + case 0: // TYPE_CONTAINER + new_child->createUnitTest(max_num_children/2); + break; + case 1: // TYPE_BOOLEAN + { + bool random_bool_values[30]; + for (U32 value=0; valuesetBoolValue(array_size, random_bool_values); + } + break; + case 2: // TYPE_INTEGER (32-bit) + { + U32 random_int_values[30]; + for (U32 value=0; valuesetUnsignedValue(array_size, random_int_values, new_encoding); + } + break; + case 3: // TYPE_INTEGER (64-bit) + { + U64 random_int_values[30]; + for (U64 value=0; valuesetLongValue(array_size, random_int_values, new_encoding); + } + break; + case 4: // TYPE_FLOAT (32-bit) + { + F32 random_float_values[30]; + for (U32 value=0; valuesetFloatValue(array_size, random_float_values, new_encoding, 12); + } + break; + case 5: // TYPE_FLOAT (64-bit) + { + F64 random_float_values[30]; + for (U32 value=0; value> 32); + } + new_child->setDoubleValue(array_size, random_float_values, new_encoding, 12); + } + break; + case 6: // TYPE_UUID + { + LLUUID random_uuid_values[30]; + for (U32 value=0; valuesetUUIDValue(array_size, random_uuid_values); + } + break; + case 7: // TYPE_NODEREF + { + LLXMLNode *random_node_array[30]; + LLXMLNode *root = getRoot(); + for (U32 value=0; valuemName->mString; + for (U32 pos=0; possetNodeRefValue(array_size, (const LLXMLNode **)random_node_array); + } + break; + } + } + + createChild("integer_checksum", true)->setUnsignedValue(1, &integer_checksum, LLXMLNode::ENCODING_HEX); + createChild("long_checksum", true)->setLongValue(1, &long_checksum, LLXMLNode::ENCODING_HEX); + createChild("bool_true_count", true)->setUnsignedValue(1, &bool_true_count, LLXMLNode::ENCODING_HEX); + createChild("uuid_checksum", true)->setUUIDValue(1, &uuid_checksum); + createChild("noderef_checksum", true)->setUnsignedValue(1, &noderef_checksum, LLXMLNode::ENCODING_HEX); + createChild("float_checksum", true)->setUnsignedValue(1, &float_checksum, LLXMLNode::ENCODING_HEX); +} + +bool LLXMLNode::performUnitTest(std::string &error_buffer) +{ + if (mChildren.isNull()) + { + error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString)); + return false; + } + + // Checksums + U32 integer_checksum = 0; + U32 bool_true_count = 0; + LLUUID uuid_checksum; + U32 noderef_checksum = 0; + U32 float_checksum = 0; + U64 long_checksum = 0; + + LLXMLChildList::iterator itor; + for (itor=mChildren->map.begin(); itor!=mChildren->map.end(); ++itor) + { + LLXMLNode *node = itor->second; + if (node->mIsAttribute) + { + continue; + } + if (node->mType == TYPE_CONTAINER) + { + if (!node->performUnitTest(error_buffer)) + { + error_buffer.append(llformat("Child test failed for %s.\n", mName->mString)); + //return false; + } + continue; + } + if (node->mLength < 1 || node->mLength > 30) + { + error_buffer.append(llformat("ERROR Node %s: Invalid array length %d, child %s.\n", mName->mString, node->mLength, node->mName->mString)); + return false; + } + switch (node->mType) + { + case TYPE_CONTAINER: + case TYPE_UNKNOWN: + break; + case TYPE_BOOLEAN: + { + bool bool_array[30]; + if (node->getBoolValue(node->mLength, bool_array) < node->mLength) + { + error_buffer.append(llformat("ERROR Node %s: Could not read boolean array, child %s.\n", mName->mString, node->mName->mString)); + return false; + } + for (U32 pos=0; pos<(U32)node->mLength; ++pos) + { + if (bool_array[pos]) + { + ++bool_true_count; + } + } + } + break; + case TYPE_INTEGER: + { + if (node->mPrecision == 32) + { + U32 integer_array[30]; + if (node->getUnsignedValue(node->mLength, integer_array, node->mEncoding) < node->mLength) + { + error_buffer.append(llformat("ERROR Node %s: Could not read integer array, child %s.\n", mName->mString, node->mName->mString)); + return false; + } + for (U32 pos=0; pos<(U32)node->mLength; ++pos) + { + integer_checksum ^= integer_array[pos]; + } + } + else + { + U64 integer_array[30]; + if (node->getLongValue(node->mLength, integer_array, node->mEncoding) < node->mLength) + { + error_buffer.append(llformat("ERROR Node %s: Could not read long integer array, child %s.\n", mName->mString, node->mName->mString)); + return false; + } + for (U32 pos=0; pos<(U32)node->mLength; ++pos) + { + long_checksum ^= integer_array[pos]; + } + } + } + break; + case TYPE_FLOAT: + { + if (node->mPrecision == 32) + { + F32 float_array[30]; + if (node->getFloatValue(node->mLength, float_array, node->mEncoding) < node->mLength) + { + error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString)); + return false; + } + for (U32 pos=0; pos<(U32)node->mLength; ++pos) + { + U32 float_bits = ((U32 *)float_array)[pos]; + float_checksum ^= (float_bits & 0xfffff000); + } + } + else + { + F64 float_array[30]; + if (node->getDoubleValue(node->mLength, float_array, node->mEncoding) < node->mLength) + { + error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString)); + return false; + } + for (U32 pos=0; pos<(U32)node->mLength; ++pos) + { + U64 float_bits = ((U64 *)float_array)[pos]; + float_checksum ^= ((float_bits & 0xfffffff000000000ll) >> 32); + } + } + } + break; + case TYPE_STRING: + break; + case TYPE_UUID: + { + LLUUID uuid_array[30]; + if (node->getUUIDValue(node->mLength, uuid_array) < node->mLength) + { + error_buffer.append(llformat("ERROR Node %s: Could not read uuid array, child %s.\n", mName->mString, node->mName->mString)); + return false; + } + for (U32 pos=0; pos<(U32)node->mLength; ++pos) + { + for (S32 byte=0; bytegetNodeRefValue(node->mLength, node_array) < node->mLength) + { + error_buffer.append(llformat("ERROR Node %s: Could not read node ref array, child %s.\n", mName->mString, node->mName->mString)); + return false; + } + for (U32 pos=0; posmLength; ++pos) + { + const char *node_name = node_array[pos]->mName->mString; + for (U32 pos2=0; pos2getUnsignedValue(1, &node_integer_checksum, ENCODING_HEX) != 1) + { + error_buffer.append(llformat("ERROR Node %s: Integer checksum missing.\n", mName->mString)); + return false; + } + if (node_integer_checksum != integer_checksum) + { + error_buffer.append(llformat("ERROR Node %s: Integer checksum mismatch: read %X / calc %X.\n", mName->mString, node_integer_checksum, integer_checksum)); + return false; + } + } + + { + U64 node_long_checksum = 0; + if (!getAttribute("long_checksum", checksum_node, false) || + checksum_node->getLongValue(1, &node_long_checksum, ENCODING_HEX) != 1) + { + error_buffer.append(llformat("ERROR Node %s: Long Integer checksum missing.\n", mName->mString)); + return false; + } + if (node_long_checksum != long_checksum) + { + U32 *pp1 = (U32 *)&node_long_checksum; + U32 *pp2 = (U32 *)&long_checksum; + 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])); + return false; + } + } + + { + U32 node_bool_true_count = 0; + if (!getAttribute("bool_true_count", checksum_node, false) || + checksum_node->getUnsignedValue(1, &node_bool_true_count, ENCODING_HEX) != 1) + { + error_buffer.append(llformat("ERROR Node %s: Boolean checksum missing.\n", mName->mString)); + return false; + } + if (node_bool_true_count != bool_true_count) + { + error_buffer.append(llformat("ERROR Node %s: Boolean checksum mismatch: read %X / calc %X.\n", mName->mString, node_bool_true_count, bool_true_count)); + return false; + } + } + + { + LLUUID node_uuid_checksum; + if (!getAttribute("uuid_checksum", checksum_node, false) || + checksum_node->getUUIDValue(1, &node_uuid_checksum) != 1) + { + error_buffer.append(llformat("ERROR Node %s: UUID checksum missing.\n", mName->mString)); + return false; + } + if (node_uuid_checksum != uuid_checksum) + { + error_buffer.append(llformat("ERROR Node %s: UUID checksum mismatch: read %s / calc %s.\n", mName->mString, node_uuid_checksum.asString().c_str(), uuid_checksum.asString().c_str())); + return false; + } + } + + { + U32 node_noderef_checksum = 0; + if (!getAttribute("noderef_checksum", checksum_node, false) || + checksum_node->getUnsignedValue(1, &node_noderef_checksum, ENCODING_HEX) != 1) + { + error_buffer.append(llformat("ERROR Node %s: Node Ref checksum missing.\n", mName->mString)); + return false; + } + if (node_noderef_checksum != noderef_checksum) + { + error_buffer.append(llformat("ERROR Node %s: Node Ref checksum mismatch: read %X / calc %X.\n", mName->mString, node_noderef_checksum, noderef_checksum)); + return false; + } + } + + { + U32 node_float_checksum = 0; + if (!getAttribute("float_checksum", checksum_node, false) || + checksum_node->getUnsignedValue(1, &node_float_checksum, ENCODING_HEX) != 1) + { + error_buffer.append(llformat("ERROR Node %s: Float checksum missing.\n", mName->mString)); + return false; + } + if (node_float_checksum != float_checksum) + { + error_buffer.append(llformat("ERROR Node %s: Float checksum mismatch: read %X / calc %X.\n", mName->mString, node_float_checksum, float_checksum)); + return false; + } + } + + return true; +} + +LLXMLNodePtr LLXMLNode::getFirstChild() const +{ + if (mChildren.isNull()) return NULL; + LLXMLNodePtr ret = mChildren->head; + return ret; +} + +LLXMLNodePtr LLXMLNode::getNextSibling() const +{ + LLXMLNodePtr ret = mNext; + return ret; +} + +std::string LLXMLNode::getSanitizedValue() const +{ + if (mIsAttribute) + { + return getValue() ; + } + else + { + return getTextContents(); + } +} + + +std::string LLXMLNode::getTextContents() const +{ + std::string msg; + std::string contents = mValue; + std::string::size_type n = contents.find_first_not_of(" \t\n"); + if (n != std::string::npos && contents[n] == '\"') + { + // Case 1: node has quoted text + S32 num_lines = 0; + while(1) + { + // mContents[n] == '"' + ++n; + std::string::size_type t = n; + std::string::size_type m = 0; + // fix-up escaped characters + while(1) + { + m = contents.find_first_of("\\\"", t); // find first \ or " + if ((m == std::string::npos) || (contents[m] == '\"')) + { + break; + } + contents.erase(m,1); + t = m+1; + } + if (m == std::string::npos) + { + break; + } + // mContents[m] == '"' + num_lines++; + msg += contents.substr(n,m-n) + "\n"; + n = contents.find_first_of("\"", m+1); + if (n == std::string::npos) + { + if (num_lines == 1) + { + msg.erase(msg.size()-1); // remove "\n" if only one line + } + break; + } + } + } + else + { + // Case 2: node has embedded text (beginning and trailing whitespace trimmed) + std::string::size_type start = mValue.find_first_not_of(" \t\n"); + if (start != mValue.npos) + { + std::string::size_type end = mValue.find_last_not_of(" \t\n"); + if (end != mValue.npos) + { + msg = mValue.substr(start, end+1-start); + } + else + { + msg = mValue.substr(start); + } + } + // Convert any internal CR to LF + msg = utf8str_removeCRLF(msg); + } + return msg; +} + +void LLXMLNode::setLineNumber(S32 line_number) +{ + mLineNumber = line_number; +} + +S32 LLXMLNode::getLineNumber() +{ + return mLineNumber; +} -- cgit v1.2.3 From b42f9d836b4c0f7fbd4bdae1734021e2a09fdbe8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 1 Jun 2024 15:49:26 +0200 Subject: Re-enable a lot of compiler warnings for MSVC and address the C4267 "possible loss of precision" warnings --- indra/llxml/llxmlnode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 5e98af8412..0fd4516844 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -670,7 +670,7 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML buffer[nread] = 0; fclose(fp); - bool rv = parseBuffer(buffer, nread, node, defaults_tree); + bool rv = parseBuffer(buffer, static_cast(nread), node, defaults_tree); delete [] buffer; return rv; } @@ -2681,7 +2681,7 @@ U32 LLXMLNode::getChildCount() const { if (mChildren.notNull()) { - return mChildren->map.size(); + return static_cast(mChildren->map.size()); } return 0; } @@ -2700,7 +2700,7 @@ LLXMLNode *get_rand_node(LLXMLNode *node) { if (node->mChildren.notNull()) { - U32 num_children = node->mChildren->map.size(); + U32 num_children = static_cast(node->mChildren->map.size()); if (get_rand(2) == 0) { while (true) -- cgit v1.2.3 From 2ea5ac0c43e3e28d2b1774f5367d099271a1da32 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 1 Jul 2024 13:34:50 +0200 Subject: #1111 Remove xmlrpc-epi --- indra/llxml/llxmlnode.cpp | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 0fd4516844..7f6b8093fc 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -653,32 +653,24 @@ bool LLXMLNode::updateNode( // static bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree) { - // Read file - LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL; - LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ - if (fp == NULL) + std::string xml = LLFile::getContents(filename); + if (xml.empty()) { - node = NULL ; - return false; + LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL; + } + else if (parseBuffer(xml.data(), xml.size(), node, defaults_tree)) + { + return true; } - fseek(fp, 0, SEEK_END); - U32 length = ftell(fp); - fseek(fp, 0, SEEK_SET); - - U8* buffer = new U8[length+1]; - size_t nread = fread(buffer, 1, length, fp); - buffer[nread] = 0; - fclose(fp); - bool rv = parseBuffer(buffer, static_cast(nread), node, defaults_tree); - delete [] buffer; - return rv; + node = nullptr; + return false; } // static bool LLXMLNode::parseBuffer( - U8* buffer, - U32 length, + const char* buffer, + U64 length, LLXMLNodePtr& node, LLXMLNode* defaults) { @@ -693,20 +685,25 @@ bool LLXMLNode::parseBuffer( file_node->mParser = &my_parser; - XML_SetUserData(my_parser, (void *)file_node_ptr); + XML_SetUserData(my_parser, file_node_ptr); // Do the parsing - if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK) + bool success = XML_STATUS_OK == XML_Parse(my_parser, buffer, (int)length, true); + if (!success) { LL_WARNS() << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) << " on line " << XML_GetCurrentLineNumber(my_parser) + << ", column " << XML_GetCurrentColumnNumber(my_parser) << LL_ENDL; } // Deinit XML_ParserFree(my_parser); + if (!success) + return false; + if (!file_node->mChildren || file_node->mChildren->map.size() != 1) { LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." -- cgit v1.2.3 From 989cfe2f70441fe02222d369e84118a94dc96890 Mon Sep 17 00:00:00 2001 From: Henri Beauchamp Date: Mon, 8 Jul 2024 23:18:02 +0200 Subject: Fix for crash in XMLRPC reply decoding on login with large inventories Commit 2ea5ac0c43e3e28d2b1774f5367d099271a1da32 introduced a crash bug due to the recursive construction of the XMLTreeNode wrapper class. The constructor of the said class typically recurses twice as many times as there are entries in the user's inventory list. This commit: - Moves the fromXMLRPCValue() method and its helper functions from the LLSD class/module to the LLXMLNode class, where it belongs, thus making LLSD::TreeNode (which was a wrapper class to avoid making llcommon dependant on llxml, which is still the case after this commit) totally moot; the fromXMLRPCValue() call is now done directly on the LLXMLNode. - Moves the XML and XMLRPC decoding code out of the HTTP coroutine LLXMLRPCTransaction::Handler (coroutines got an even smaller and fixed stack), and into LLXMLRPCTransaction::Impl::process(). - Removes XMLTreeNode entirely, fixing the crash as a result. --- indra/llxml/llxmlnode.cpp | 172 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 7f6b8093fc..8eb4556828 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -38,7 +38,9 @@ #include "v3math.h" #include "v3dmath.h" #include "v4math.h" +#include "llbase64.h" #include "llquaternion.h" +#include "llsd.h" #include "llstring.h" #include "lluuid.h" #include "lldir.h" @@ -3263,3 +3265,173 @@ S32 LLXMLNode::getLineNumber() { return mLineNumber; } + +bool LLXMLNode::parseXmlRpcArrayValue(LLSD& target) +{ + LLXMLNode* datap = getFirstChild().get(); + if (!datap) + { + LL_WARNS() << "No inner XML element." << LL_ENDL; + return false; + } + if (!datap->hasName("data")) + { + LL_WARNS() << "No inner XML element ( expected, got: " + << datap->mName->mString << ")" << LL_ENDL; + return false; + } + if (datap->getNextSibling().get()) + { + LL_WARNS() << "Multiple inner XML elements (single expected)" + << LL_ENDL; + return false; + } + U32 i = 0; + for (LLXMLNode* itemp = datap->getFirstChild().get(); itemp; + itemp = itemp->getNextSibling().get()) + { + LLSD value; + if (!itemp->fromXMLRPCValue(value)) + { + return false; + } + target.append(value); + ++i; + } + return true; +} + +bool LLXMLNode::parseXmlRpcStructValue(LLSD& target) +{ + std::string name; + LLSD value; + for (LLXMLNode* itemp = getFirstChild().get(); itemp; + itemp = itemp->getNextSibling().get()) + { + if (!itemp->hasName("member")) + { + LL_WARNS() << "Invalid inner XML element ( expected, got: <" + << itemp->mName->mString << ">" << LL_ENDL; + return false; + } + name.clear(); + value.clear(); + for (LLXMLNode* chilp = itemp->getFirstChild().get(); chilp; + chilp = chilp->getNextSibling().get()) + { + if (chilp->hasName("name")) + { + name = LLStringFn::xml_decode(chilp->getTextContents()); + } + else if (!chilp->fromXMLRPCValue(value)) + { + return false; + } + } + if (name.empty()) + { + LL_WARNS() << "Empty struct member name" << LL_ENDL; + return false; + } + target.insert(name, value); + } + return true; +} + +bool LLXMLNode::fromXMLRPCValue(LLSD& target) +{ + target.clear(); + + if (!hasName("value")) + { + LL_WARNS() << "Invalid XML element ( expected), got: <" + << mName->mString << ">" << LL_ENDL; + return false; + } + + LLXMLNode* childp = getFirstChild().get(); + if (!childp) + { + LL_WARNS() << "No inner XML element (value type expected)" << LL_ENDL; + // Value with no type qualifier is treated as string + target.assign(LLStringFn::xml_decode(getTextContents())); + return true; + } + + if (childp->getNextSibling()) + { + LL_WARNS() << "Multiple inner XML elements (single expected)" + << LL_ENDL; + return false; + } + + if (childp->hasName("string")) + { + target.assign(LLStringFn::xml_decode(childp->getTextContents())); + return true; + } + + if (childp->hasName("int") || childp->hasName("i4")) + { + target.assign(std::stoi(childp->getTextContents())); + return true; + } + + if (childp->hasName("double")) + { + target.assign(std::stod(childp->getTextContents())); + return true; + } + + if (childp->hasName("boolean")) + { + target.assign(std::stoi(childp->getTextContents()) != 0); + return true; + } + + if (childp->hasName("dateTime.iso8601")) + { + target.assign(LLSD::Date(childp->getTextContents())); + return true; + } + + if (childp->hasName("base64")) + { + std::string decoded = + LLBase64::decodeAsString(inner->getTextContents()); + size_t size = decoded.size(); + LLSD::Binary binary(size); + if (size) + { + memcpy((void*)binary.data(), (void*)decoded.data(), size); + } + target.assign(binary); + return true; + } + + if (childp->hasName("array")) + { + if (!childp->parseXmlRpcArrayValue(target)) + { + target.clear(); + return false; + } + return true; + } + + if (childp->hasName("struct")) + { + if (!childp->parseXmlRpcStructValue(target)) + { + target.clear(); + return false; + } + return true; + } + + LL_WARNS() << "Unknown inner XML element (known value type expected)" + << LL_ENDL; + // Value with unknown type qualifier is treated as string + target.assign(LLStringFn::xml_decode(childp->getTextContents())); + return true; +} -- cgit v1.2.3 From 0df35799a39b8a76d13ccb4c1ab4d57a0ab6d129 Mon Sep 17 00:00:00 2001 From: Henri Beauchamp Date: Mon, 8 Jul 2024 23:31:43 +0200 Subject: Remove a remnant of debug code. --- indra/llxml/llxmlnode.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 8eb4556828..d6f9a56c9d 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -3286,7 +3286,6 @@ bool LLXMLNode::parseXmlRpcArrayValue(LLSD& target) << LL_ENDL; return false; } - U32 i = 0; for (LLXMLNode* itemp = datap->getFirstChild().get(); itemp; itemp = itemp->getNextSibling().get()) { @@ -3296,7 +3295,6 @@ bool LLXMLNode::parseXmlRpcArrayValue(LLSD& target) return false; } target.append(value); - ++i; } return true; } -- cgit v1.2.3 From 89c1767bd38ae97c9ca3ba120d8d5c0f94373c1b Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 9 Jul 2024 02:59:49 +0200 Subject: Fix build error in llxmlnode.cpp --- indra/llxml/llxmlnode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llxml/llxmlnode.cpp') diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index d6f9a56c9d..e695035461 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -3396,7 +3396,7 @@ bool LLXMLNode::fromXMLRPCValue(LLSD& target) if (childp->hasName("base64")) { std::string decoded = - LLBase64::decodeAsString(inner->getTextContents()); + LLBase64::decodeAsString(childp->getTextContents()); size_t size = decoded.size(); LLSD::Binary binary(size); if (size) -- cgit v1.2.3