From b2028085fdfddfd5a7ac0f52d9f34b84457b3b98 Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Wed, 4 Aug 2010 19:02:30 -0700 Subject: first pass at faster XUI parsing (no recursion support yet) also made LLSD->param block parsing faster --- indra/llxuixml/llinitparam.h | 13 +- indra/llxuixml/llxuiparser.cpp | 511 ++++++++++++++++++++++++++++++++++++----- indra/llxuixml/llxuiparser.h | 86 +++++-- 3 files changed, 532 insertions(+), 78 deletions(-) (limited to 'indra/llxuixml') diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h index b645c4be7c..1cc7d06b73 100644 --- a/indra/llxuixml/llinitparam.h +++ b/indra/llxuixml/llinitparam.h @@ -40,6 +40,7 @@ f * @file llinitparam.h #include #include #include +#include #include "llregistry.h" #include "llmemory.h" @@ -202,13 +203,13 @@ namespace LLInitParam typedef std::pair name_stack_range_t; typedef std::vector possible_values_t; - typedef boost::function parser_read_func_t; + typedef bool (*parser_read_func_t)(Parser& parser, void* output); typedef boost::function parser_write_func_t; typedef boost::function parser_inspect_func_t; - typedef std::map parser_read_func_map_t; - typedef std::map parser_write_func_map_t; - typedef std::map parser_inspect_func_map_t; + typedef boost::unordered_map parser_read_func_map_t; + typedef boost::unordered_map parser_write_func_map_t; + typedef boost::unordered_map parser_inspect_func_map_t; Parser() : mParseSilently(false), @@ -221,7 +222,7 @@ namespace LLInitParam parser_read_func_map_t::iterator found_it = mParserReadFuncs.find(&typeid(T)); if (found_it != mParserReadFuncs.end()) { - return found_it->second((void*)¶m); + return found_it->second(*this, (void*)¶m); } return false; } @@ -386,7 +387,7 @@ namespace LLInitParam void aggregateBlockData(BlockDescriptor& src_block_data); public: - typedef std::map param_map_t; // references param descriptors stored in mAllParams + typedef boost::unordered_map param_map_t; // references param descriptors stored in mAllParams typedef std::vector param_list_t; typedef std::list all_params_list_t;// references param descriptors stored in mAllParams diff --git a/indra/llxuixml/llxuiparser.cpp b/indra/llxuixml/llxuiparser.cpp index dbc20a5a1e..00128c978a 100644 --- a/indra/llxuixml/llxuiparser.cpp +++ b/indra/llxuixml/llxuiparser.cpp @@ -35,11 +35,16 @@ #include "llxuiparser.h" #include "llxmlnode.h" +#include "expat/expat.h" #include #include +//#include +#include #include "lluicolor.h" +using namespace BOOST_SPIRIT_CLASSIC_NS; + const S32 MAX_STRING_ATTRIBUTE_SIZE = 40; // @@ -370,34 +375,20 @@ LLXUIParser::LLXUIParser() : mLastWriteGeneration(-1), mCurReadDepth(0) { - registerParserFuncs(boost::bind(&LLXUIParser::readBoolValue, this, _1), - boost::bind(&LLXUIParser::writeBoolValue, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readStringValue, this, _1), - boost::bind(&LLXUIParser::writeStringValue, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readU8Value, this, _1), - boost::bind(&LLXUIParser::writeU8Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readS8Value, this, _1), - boost::bind(&LLXUIParser::writeS8Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readU16Value, this, _1), - boost::bind(&LLXUIParser::writeU16Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readS16Value, this, _1), - boost::bind(&LLXUIParser::writeS16Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readU32Value, this, _1), - boost::bind(&LLXUIParser::writeU32Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readS32Value, this, _1), - boost::bind(&LLXUIParser::writeS32Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readF32Value, this, _1), - boost::bind(&LLXUIParser::writeF32Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readF64Value, this, _1), - boost::bind(&LLXUIParser::writeF64Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readColor4Value, this, _1), - boost::bind(&LLXUIParser::writeColor4Value, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readUIColorValue, this, _1), - boost::bind(&LLXUIParser::writeUIColorValue, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readUUIDValue, this, _1), - boost::bind(&LLXUIParser::writeUUIDValue, this, _1, _2)); - registerParserFuncs(boost::bind(&LLXUIParser::readSDValue, this, _1), - boost::bind(&LLXUIParser::writeSDValue, this, _1, _2)); + registerParserFuncs(readBoolValue, boost::bind(&LLXUIParser::writeBoolValue, this, _1, _2)); + registerParserFuncs(readStringValue, boost::bind(&LLXUIParser::writeStringValue, this, _1, _2)); + registerParserFuncs(readU8Value, boost::bind(&LLXUIParser::writeU8Value, this, _1, _2)); + registerParserFuncs(readS8Value, boost::bind(&LLXUIParser::writeS8Value, this, _1, _2)); + registerParserFuncs(readU16Value, boost::bind(&LLXUIParser::writeU16Value, this, _1, _2)); + registerParserFuncs(readS16Value, boost::bind(&LLXUIParser::writeS16Value, this, _1, _2)); + registerParserFuncs(readU32Value, boost::bind(&LLXUIParser::writeU32Value, this, _1, _2)); + registerParserFuncs(readS32Value, boost::bind(&LLXUIParser::writeS32Value, this, _1, _2)); + registerParserFuncs(readF32Value, boost::bind(&LLXUIParser::writeF32Value, this, _1, _2)); + registerParserFuncs(readF64Value, boost::bind(&LLXUIParser::writeF64Value, this, _1, _2)); + registerParserFuncs(readColor4Value, boost::bind(&LLXUIParser::writeColor4Value, this, _1, _2)); + registerParserFuncs(readUIColorValue, boost::bind(&LLXUIParser::writeUIColorValue, this, _1, _2)); + registerParserFuncs(readUUIDValue, boost::bind(&LLXUIParser::writeUUIDValue, this, _1, _2)); + registerParserFuncs(readSDValue, boost::bind(&LLXUIParser::writeSDValue, this, _1, _2)); } static LLFastTimer::DeclareTimer FTM_PARSE_XUI("XUI Parsing"); @@ -621,10 +612,11 @@ LLXMLNodePtr LLXUIParser::getNode(const name_stack_t& stack) } -bool LLXUIParser::readBoolValue(void* val_ptr) +bool LLXUIParser::readBoolValue(Parser& parser, void* val_ptr) { S32 value; - bool success = mCurReadNode->getBoolValue(1, &value); + LLXUIParser& self = static_cast(parser); + bool success = self.mCurReadNode->getBoolValue(1, &value); *((bool*)val_ptr) = (value != FALSE); return success; } @@ -640,9 +632,10 @@ bool LLXUIParser::writeBoolValue(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readStringValue(void* val_ptr) +bool LLXUIParser::readStringValue(Parser& parser, void* val_ptr) { - *((std::string*)val_ptr) = mCurReadNode->getSanitizedValue(); + LLXUIParser& self = static_cast(parser); + *((std::string*)val_ptr) = self.mCurReadNode->getSanitizedValue(); return true; } @@ -677,9 +670,10 @@ bool LLXUIParser::writeStringValue(const void* val_ptr, const name_stack_t& stac return false; } -bool LLXUIParser::readU8Value(void* val_ptr) +bool LLXUIParser::readU8Value(Parser& parser, void* val_ptr) { - return mCurReadNode->getByteValue(1, (U8*)val_ptr); + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getByteValue(1, (U8*)val_ptr); } bool LLXUIParser::writeU8Value(const void* val_ptr, const name_stack_t& stack) @@ -693,10 +687,11 @@ bool LLXUIParser::writeU8Value(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readS8Value(void* val_ptr) +bool LLXUIParser::readS8Value(Parser& parser, void* val_ptr) { + LLXUIParser& self = static_cast(parser); S32 value; - if(mCurReadNode->getIntValue(1, &value)) + if(self.mCurReadNode->getIntValue(1, &value)) { *((S8*)val_ptr) = value; return true; @@ -715,10 +710,11 @@ bool LLXUIParser::writeS8Value(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readU16Value(void* val_ptr) +bool LLXUIParser::readU16Value(Parser& parser, void* val_ptr) { + LLXUIParser& self = static_cast(parser); U32 value; - if(mCurReadNode->getUnsignedValue(1, &value)) + if(self.mCurReadNode->getUnsignedValue(1, &value)) { *((U16*)val_ptr) = value; return true; @@ -737,10 +733,11 @@ bool LLXUIParser::writeU16Value(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readS16Value(void* val_ptr) +bool LLXUIParser::readS16Value(Parser& parser, void* val_ptr) { + LLXUIParser& self = static_cast(parser); S32 value; - if(mCurReadNode->getIntValue(1, &value)) + if(self.mCurReadNode->getIntValue(1, &value)) { *((S16*)val_ptr) = value; return true; @@ -759,9 +756,10 @@ bool LLXUIParser::writeS16Value(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readU32Value(void* val_ptr) +bool LLXUIParser::readU32Value(Parser& parser, void* val_ptr) { - return mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); } bool LLXUIParser::writeU32Value(const void* val_ptr, const name_stack_t& stack) @@ -775,9 +773,10 @@ bool LLXUIParser::writeU32Value(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readS32Value(void* val_ptr) +bool LLXUIParser::readS32Value(Parser& parser, void* val_ptr) { - return mCurReadNode->getIntValue(1, (S32*)val_ptr); + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getIntValue(1, (S32*)val_ptr); } bool LLXUIParser::writeS32Value(const void* val_ptr, const name_stack_t& stack) @@ -791,9 +790,10 @@ bool LLXUIParser::writeS32Value(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readF32Value(void* val_ptr) +bool LLXUIParser::readF32Value(Parser& parser, void* val_ptr) { - return mCurReadNode->getFloatValue(1, (F32*)val_ptr); + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getFloatValue(1, (F32*)val_ptr); } bool LLXUIParser::writeF32Value(const void* val_ptr, const name_stack_t& stack) @@ -807,9 +807,10 @@ bool LLXUIParser::writeF32Value(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readF64Value(void* val_ptr) +bool LLXUIParser::readF64Value(Parser& parser, void* val_ptr) { - return mCurReadNode->getDoubleValue(1, (F64*)val_ptr); + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getDoubleValue(1, (F64*)val_ptr); } bool LLXUIParser::writeF64Value(const void* val_ptr, const name_stack_t& stack) @@ -823,10 +824,11 @@ bool LLXUIParser::writeF64Value(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readColor4Value(void* val_ptr) +bool LLXUIParser::readColor4Value(Parser& parser, void* val_ptr) { + LLXUIParser& self = static_cast(parser); LLColor4* colorp = (LLColor4*)val_ptr; - if(mCurReadNode->getFloatValue(4, colorp->mV) >= 3) + if(self.mCurReadNode->getFloatValue(4, colorp->mV) >= 3) { return true; } @@ -846,11 +848,12 @@ bool LLXUIParser::writeColor4Value(const void* val_ptr, const name_stack_t& stac return false; } -bool LLXUIParser::readUIColorValue(void* val_ptr) +bool LLXUIParser::readUIColorValue(Parser& parser, void* val_ptr) { + LLXUIParser& self = static_cast(parser); LLUIColor* param = (LLUIColor*)val_ptr; LLColor4 color; - bool success = mCurReadNode->getFloatValue(4, color.mV) >= 3; + bool success = self.mCurReadNode->getFloatValue(4, color.mV) >= 3; if (success) { param->set(color); @@ -874,11 +877,12 @@ bool LLXUIParser::writeUIColorValue(const void* val_ptr, const name_stack_t& sta return false; } -bool LLXUIParser::readUUIDValue(void* val_ptr) +bool LLXUIParser::readUUIDValue(Parser& parser, void* val_ptr) { + LLXUIParser& self = static_cast(parser); LLUUID temp_id; // LLUUID::set is destructive, so use temporary value - if (temp_id.set(mCurReadNode->getSanitizedValue())) + if (temp_id.set(self.mCurReadNode->getSanitizedValue())) { *(LLUUID*)(val_ptr) = temp_id; return true; @@ -897,9 +901,10 @@ bool LLXUIParser::writeUUIDValue(const void* val_ptr, const name_stack_t& stack) return false; } -bool LLXUIParser::readSDValue(void* val_ptr) +bool LLXUIParser::readSDValue(Parser& parser, void* val_ptr) { - *((LLSD*)val_ptr) = LLSD(mCurReadNode->getSanitizedValue()); + LLXUIParser& self = static_cast(parser); + *((LLSD*)val_ptr) = LLSD(self.mCurReadNode->getSanitizedValue()); return true; } @@ -968,3 +973,397 @@ void LLXUIParser::parserError(const std::string& message) Parser::parserError(message); #endif } + + +// +// LLFastXUIParser +// + +struct ScopedFile +{ + ScopedFile( const std::string& filename, const char* accessmode ) + { + mFile = LLFile::fopen(filename, accessmode); + } + + ~ScopedFile() + { + fclose(mFile); + mFile = NULL; + } + + S32 getRemainingBytes() + { + if (!isOpen()) return 0; + + S32 cur_pos = ftell(mFile); + fseek(mFile, 0L, SEEK_END); + S32 file_size = ftell(mFile); + fseek(mFile, cur_pos, SEEK_SET); + return file_size - cur_pos; + } + + bool isOpen() { return mFile != NULL; } + + LLFILE* mFile; +}; + +LLFastXUIParser::LLFastXUIParser() +: mLastWriteGeneration(-1), + mCurReadDepth(0) +{ + registerParserFuncs(readBoolValue, NULL); + registerParserFuncs(readStringValue, NULL); + registerParserFuncs(readU8Value, NULL); + registerParserFuncs(readS8Value, NULL); + registerParserFuncs(readU16Value, NULL); + registerParserFuncs(readS16Value, NULL); + registerParserFuncs(readU32Value, NULL); + registerParserFuncs(readS32Value, NULL); + registerParserFuncs(readF32Value, NULL); + registerParserFuncs(readF64Value, NULL); + registerParserFuncs(readColor4Value, NULL); + registerParserFuncs(readUIColorValue, NULL); + registerParserFuncs(readUUIDValue, NULL); + registerParserFuncs(readSDValue, NULL); +} + +LLFastXUIParser::~LLFastXUIParser() +{ +} + + +bool LLFastXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent) +{ + LLFastTimer timer(FTM_PARSE_XUI); + + mParser = XML_ParserCreate(NULL); + XML_SetUserData(mParser, this); + XML_SetElementHandler( mParser, startElementHandler, endElementHandler); + XML_SetCharacterDataHandler( mParser, characterDataHandler); + + mBlock = █ + mNameStack.clear(); + mCurFileName = filename; + mCurReadDepth = 0; + setParseSilently(silent); + + ScopedFile file(filename, "rb"); + if( !file.isOpen() ) + { + LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; + return false; + } + + S32 bytes_read = 0; + + S32 buffer_size = file.getRemainingBytes(); + void* buffer = XML_GetBuffer(mParser, buffer_size); + if( !buffer ) + { + LL_WARNS("ReadXUI") << "Unable to allocate XML buffer while reading file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + bytes_read = (S32)fread(buffer, 1, buffer_size, file.mFile); + if( bytes_read <= 0 ) + { + LL_WARNS("ReadXUI") << "Error while reading file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) ) + { + LL_WARNS("ReadXUI") << "Error while parsing file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + XML_ParserFree( mParser ); + return true; +} + +void LLFastXUIParser::startElementHandler(void *userData, const char *name, const char **atts) +{ + LLFastXUIParser* self = reinterpret_cast(userData); + self->startElement(name, atts); +} + +void LLFastXUIParser::endElementHandler(void *userData, const char *name) +{ + LLFastXUIParser* self = reinterpret_cast(userData); + self->endElement(name); +} + +void LLFastXUIParser::characterDataHandler(void *userData, const char *s, int len) +{ + LLFastXUIParser* self = reinterpret_cast(userData); + self->characterData(s, len); +} + +void LLFastXUIParser::startElement(const char *name, const char **atts) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + mCurReadDepth++; + S32 num_tokens_pushed = 0; + std::string child_name(name); + + if (mCurReadDepth > 1) + { + // for non "dotted" child nodes check to see if child node maps to another widget type + // and if not, treat as a child element of the current node + // e.g. will interpret as "button.rect" + // since there is no widget named "rect" + if (child_name.find(".") == std::string::npos) + { + mNameStack.push_back(std::make_pair(child_name, newParseGeneration())); + num_tokens_pushed++; + } + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + return; + } + + // check for proper nesting + if(!mScope.empty() && *name_token_it != mScope.back()) + { + return; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration())); + num_tokens_pushed++; + } + mScope.push_back(mNameStack.back().first); + } + } + else + { + mScope.push_back(name); + } + + mTokenSizeStack.push_back(num_tokens_pushed); + readAttributes(atts); +} + +bool LLFastXUIParser::readAttributes(const char **atts) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + bool any_parsed = false; + for(S32 i = 0; atts[i] && atts[i+1]; i += 2 ) + { + std::string attribute_name(atts[i]); + mCurAttributeValueBegin = atts[i+1]; + + S32 num_tokens_pushed = 0; + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration())); + num_tokens_pushed++; + } + + // child nodes are not necessarily valid attributes, so don't complain once we've recursed + bool silent = mCurReadDepth > 1; + any_parsed |= mBlock->submitValue(mNameStack, *this, silent); + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + return any_parsed; +} + + +void LLFastXUIParser::endElement(const char *name) +{ + mCurReadDepth--; + S32 num_tokens_to_pop = mTokenSizeStack.back(); + mTokenSizeStack.pop_back(); + while(num_tokens_to_pop-- > 0) + { + mNameStack.pop_back(); + } + mScope.pop_back(); +} + +void LLFastXUIParser::characterData(const char *s, int len) +{ +} + + +/*virtual*/ std::string LLFastXUIParser::getCurrentElementName() +{ + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } + + return full_name; +} + +const S32 LINE_NUMBER_HERE = 0; + +void LLFastXUIParser::parserWarning(const std::string& message) +{ +#ifdef LL_WINDOWS + // use Visual Studo friendly formatting of output message for easy access to originating xml + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserWarning(message); +#endif +} + +void LLFastXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserError(message); +#endif +} + +bool LLFastXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + if (!strcmp(self.mCurAttributeValueBegin, "true")) + { + *((bool*)val_ptr) = true; + return true; + } + else if (!strcmp(self.mCurAttributeValueBegin, "false")) + { + *((bool*)val_ptr) = false; + return true; + } + + return false; +} + +bool LLFastXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + *((std::string*)val_ptr) = self.mCurAttributeValueBegin; + return true; +} + +bool LLFastXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; +} + +bool LLFastXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; +} + +bool LLFastXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; +} + +bool LLFastXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; +} + +bool LLFastXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; +} + +bool LLFastXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; +} + +bool LLFastXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; +} + +bool LLFastXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; +} + +bool LLFastXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + LLColor4 value; + + if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + { + *(LLColor4*)(val_ptr) = value; + return true; + } + return false; +} + +bool LLFastXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + LLColor4 value; + LLUIColor* colorp = (LLUIColor*)val_ptr; + + if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + { + colorp->set(value); + return true; + } + return false; +} + +bool LLFastXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(self.mCurAttributeValueBegin)) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; +} + +bool LLFastXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ + LLFastXUIParser& self = static_cast(parser); + *((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); + return true; +} \ No newline at end of file diff --git a/indra/llxuixml/llxuiparser.h b/indra/llxuixml/llxuiparser.h index 884f4f7578..4deb083e1c 100644 --- a/indra/llxuixml/llxuiparser.h +++ b/indra/llxuixml/llxuiparser.h @@ -120,26 +120,24 @@ public: void writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const LLInitParam::BaseBlock* diff_block = NULL); private: - typedef std::list > token_list_t; - bool readXUIImpl(LLXMLNodePtr node, const std::string& scope, LLInitParam::BaseBlock& block); bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); //reader helper functions - bool readBoolValue(void* val_ptr); - bool readStringValue(void* val_ptr); - bool readU8Value(void* val_ptr); - bool readS8Value(void* val_ptr); - bool readU16Value(void* val_ptr); - bool readS16Value(void* val_ptr); - bool readU32Value(void* val_ptr); - bool readS32Value(void* val_ptr); - bool readF32Value(void* val_ptr); - bool readF64Value(void* val_ptr); - bool readColor4Value(void* val_ptr); - bool readUIColorValue(void* val_ptr); - bool readUUIDValue(void* val_ptr); - bool readSDValue(void* val_ptr); + static bool readBoolValue(Parser& parser, void* val_ptr); + static bool readStringValue(Parser& parser, void* val_ptr); + static bool readU8Value(Parser& parser, void* val_ptr); + static bool readS8Value(Parser& parser, void* val_ptr); + static bool readU16Value(Parser& parser, void* val_ptr); + static bool readS16Value(Parser& parser, void* val_ptr); + static bool readU32Value(Parser& parser, void* val_ptr); + static bool readS32Value(Parser& parser, void* val_ptr); + static bool readF32Value(Parser& parser, void* val_ptr); + static bool readF64Value(Parser& parser, void* val_ptr); + static bool readColor4Value(Parser& parser, void* val_ptr); + static bool readUIColorValue(Parser& parser, void* val_ptr); + static bool readUUIDValue(Parser& parser, void* val_ptr); + static bool readSDValue(Parser& parser, void* val_ptr); //writer helper functions bool writeBoolValue(const void* val_ptr, const name_stack_t&); @@ -173,5 +171,61 @@ private: std::string mCurFileName; }; +class LLFastXUIParser : public LLInitParam::Parser, public LLSingleton +{ +LOG_CLASS(LLFastXUIParser); + +protected: + LLFastXUIParser(); + virtual ~LLFastXUIParser(); + friend class LLSingleton; +public: + typedef LLInitParam::Parser::name_stack_t name_stack_t; + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); + + bool readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent=false); + +private: + //reader helper functions + static bool readBoolValue(Parser&, void* val_ptr); + static bool readStringValue(Parser&, void* val_ptr); + static bool readU8Value(Parser&, void* val_ptr); + static bool readS8Value(Parser&, void* val_ptr); + static bool readU16Value(Parser&, void* val_ptr); + static bool readS16Value(Parser&, void* val_ptr); + static bool readU32Value(Parser&, void* val_ptr); + static bool readS32Value(Parser&, void* val_ptr); + static bool readF32Value(Parser&, void* val_ptr); + static bool readF64Value(Parser&, void* val_ptr); + static bool readColor4Value(Parser&, void* val_ptr); + static bool readUIColorValue(Parser&, void* val_ptr); + static bool readUUIDValue(Parser&, void* val_ptr); + static bool readSDValue(Parser&, void* val_ptr); + +private: + static void startElementHandler(void *userData, const char *name, const char **atts); + static void endElementHandler(void *userData, const char *name); + static void characterDataHandler(void *userData, const char *s, int len); + + void startElement(const char *name, const char **atts); + void endElement(const char *name); + void characterData(const char *s, int len); + bool readAttributes(const char **atts); + + LLInitParam::BaseBlock* mBlock; + Parser::name_stack_t mNameStack; + struct XML_ParserStruct* mParser; + S32 mLastWriteGeneration; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; + std::string mCurFileName; + const char* mCurAttributeValueBegin; + std::vector mTokenSizeStack; + std::vector mScope; +}; + #endif //LLXUIPARSER_H -- cgit v1.2.3 From 52936c4ffe97172a5d4926e252f2a25515c47895 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Thu, 5 Aug 2010 13:15:22 -0700 Subject: reverted unportable use of typeinfo* as hash key --- indra/llxuixml/llinitparam.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llxuixml') diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h index 1cc7d06b73..9890bacea4 100644 --- a/indra/llxuixml/llinitparam.h +++ b/indra/llxuixml/llinitparam.h @@ -207,9 +207,9 @@ namespace LLInitParam typedef boost::function parser_write_func_t; typedef boost::function parser_inspect_func_t; - typedef boost::unordered_map parser_read_func_map_t; - typedef boost::unordered_map parser_write_func_map_t; - typedef boost::unordered_map parser_inspect_func_map_t; + typedef std::map parser_read_func_map_t; + typedef std::map parser_write_func_map_t; + typedef std::map parser_inspect_func_map_t; Parser() : mParseSilently(false), -- cgit v1.2.3 From d26e380a06b343bc46010922de46e9664831e3b4 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Thu, 5 Aug 2010 13:19:19 -0700 Subject: added newlines at end to make Linux builds happy --- indra/llxuixml/llxuiparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llxuixml') diff --git a/indra/llxuixml/llxuiparser.cpp b/indra/llxuixml/llxuiparser.cpp index 00128c978a..16571a9969 100644 --- a/indra/llxuixml/llxuiparser.cpp +++ b/indra/llxuixml/llxuiparser.cpp @@ -1366,4 +1366,4 @@ bool LLFastXUIParser::readSDValue(Parser& parser, void* val_ptr) LLFastXUIParser& self = static_cast(parser); *((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); return true; -} \ No newline at end of file +} -- cgit v1.2.3 From a974ed98d04d05d9c682e85d3b25cf591d2b58c0 Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Thu, 5 Aug 2010 14:18:55 -0700 Subject: Fix for a crash on startup. Richard sent me the diff for this one, just pushing it on his behalf. --- indra/llxuixml/llxuiparser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/llxuixml') diff --git a/indra/llxuixml/llxuiparser.cpp b/indra/llxuixml/llxuiparser.cpp index 16571a9969..fe85ac41cc 100644 --- a/indra/llxuixml/llxuiparser.cpp +++ b/indra/llxuixml/llxuiparser.cpp @@ -1122,6 +1122,7 @@ void LLFastXUIParser::startElement(const char *name, const char **atts) { mNameStack.push_back(std::make_pair(child_name, newParseGeneration())); num_tokens_pushed++; + mScope.push_back(child_name); } else { @@ -1154,7 +1155,7 @@ void LLFastXUIParser::startElement(const char *name, const char **atts) } else { - mScope.push_back(name); + mScope.push_back(child_name); } mTokenSizeStack.push_back(num_tokens_pushed); -- cgit v1.2.3 From 9609b2c81c1efc43c152e379ca56191c7295973a Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Fri, 6 Aug 2010 11:03:15 -0700 Subject: renamed LLFastXUIParser to LLSimpleXUIParser and added support for parsing xml node text contents --- indra/llxuixml/llxuiparser.cpp | 108 ++++++++++++++++++++++------------------- indra/llxuixml/llxuiparser.h | 23 +++++++-- 2 files changed, 77 insertions(+), 54 deletions(-) (limited to 'indra/llxuixml') diff --git a/indra/llxuixml/llxuiparser.cpp b/indra/llxuixml/llxuiparser.cpp index 00128c978a..e010b4c125 100644 --- a/indra/llxuixml/llxuiparser.cpp +++ b/indra/llxuixml/llxuiparser.cpp @@ -976,7 +976,7 @@ void LLXUIParser::parserError(const std::string& message) // -// LLFastXUIParser +// LLSimpleXUIParser // struct ScopedFile @@ -1008,7 +1008,7 @@ struct ScopedFile LLFILE* mFile; }; -LLFastXUIParser::LLFastXUIParser() +LLSimpleXUIParser::LLSimpleXUIParser() : mLastWriteGeneration(-1), mCurReadDepth(0) { @@ -1028,19 +1028,19 @@ LLFastXUIParser::LLFastXUIParser() registerParserFuncs(readSDValue, NULL); } -LLFastXUIParser::~LLFastXUIParser() +LLSimpleXUIParser::~LLSimpleXUIParser() { } -bool LLFastXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent) +bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent) { LLFastTimer timer(FTM_PARSE_XUI); mParser = XML_ParserCreate(NULL); XML_SetUserData(mParser, this); - XML_SetElementHandler( mParser, startElementHandler, endElementHandler); - XML_SetCharacterDataHandler( mParser, characterDataHandler); + XML_SetElementHandler( mParser, startElementHandler, endElementHandler); + XML_SetCharacterDataHandler( mParser, characterDataHandler); mBlock = █ mNameStack.clear(); @@ -1085,25 +1085,25 @@ bool LLFastXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBloc return true; } -void LLFastXUIParser::startElementHandler(void *userData, const char *name, const char **atts) +void LLSimpleXUIParser::startElementHandler(void *userData, const char *name, const char **atts) { - LLFastXUIParser* self = reinterpret_cast(userData); + LLSimpleXUIParser* self = reinterpret_cast(userData); self->startElement(name, atts); } -void LLFastXUIParser::endElementHandler(void *userData, const char *name) +void LLSimpleXUIParser::endElementHandler(void *userData, const char *name) { - LLFastXUIParser* self = reinterpret_cast(userData); + LLSimpleXUIParser* self = reinterpret_cast(userData); self->endElement(name); } -void LLFastXUIParser::characterDataHandler(void *userData, const char *s, int len) +void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int len) { - LLFastXUIParser* self = reinterpret_cast(userData); + LLSimpleXUIParser* self = reinterpret_cast(userData); self->characterData(s, len); } -void LLFastXUIParser::startElement(const char *name, const char **atts) +void LLSimpleXUIParser::startElement(const char *name, const char **atts) { typedef boost::tokenizer > tokenizer; boost::char_separator sep("."); @@ -1122,6 +1122,7 @@ void LLFastXUIParser::startElement(const char *name, const char **atts) { mNameStack.push_back(std::make_pair(child_name, newParseGeneration())); num_tokens_pushed++; + mScope.push_back(child_name); } else { @@ -1154,14 +1155,14 @@ void LLFastXUIParser::startElement(const char *name, const char **atts) } else { - mScope.push_back(name); + mScope.push_back(child_name); } mTokenSizeStack.push_back(num_tokens_pushed); readAttributes(atts); } -bool LLFastXUIParser::readAttributes(const char **atts) +bool LLSimpleXUIParser::readAttributes(const char **atts) { typedef boost::tokenizer > tokenizer; boost::char_separator sep("."); @@ -1194,8 +1195,16 @@ bool LLFastXUIParser::readAttributes(const char **atts) } -void LLFastXUIParser::endElement(const char *name) +void LLSimpleXUIParser::endElement(const char *name) { + if (!mTextContents.empty()) + { + mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration())); + mCurAttributeValueBegin = mTextContents.c_str(); + mBlock->submitValue(mNameStack, *this); + mNameStack.pop_back(); + mTextContents.clear(); + } mCurReadDepth--; S32 num_tokens_to_pop = mTokenSizeStack.back(); mTokenSizeStack.pop_back(); @@ -1206,12 +1215,13 @@ void LLFastXUIParser::endElement(const char *name) mScope.pop_back(); } -void LLFastXUIParser::characterData(const char *s, int len) +void LLSimpleXUIParser::characterData(const char *s, int len) { + mTextContents += std::string(s, len); } -/*virtual*/ std::string LLFastXUIParser::getCurrentElementName() +/*virtual*/ std::string LLSimpleXUIParser::getCurrentElementName() { std::string full_name; for (name_stack_t::iterator it = mNameStack.begin(); @@ -1226,7 +1236,7 @@ void LLFastXUIParser::characterData(const char *s, int len) const S32 LINE_NUMBER_HERE = 0; -void LLFastXUIParser::parserWarning(const std::string& message) +void LLSimpleXUIParser::parserWarning(const std::string& message) { #ifdef LL_WINDOWS // use Visual Studo friendly formatting of output message for easy access to originating xml @@ -1238,7 +1248,7 @@ void LLFastXUIParser::parserWarning(const std::string& message) #endif } -void LLFastXUIParser::parserError(const std::string& message) +void LLSimpleXUIParser::parserError(const std::string& message) { #ifdef LL_WINDOWS llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str()); @@ -1249,9 +1259,9 @@ void LLFastXUIParser::parserError(const std::string& message) #endif } -bool LLFastXUIParser::readBoolValue(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); if (!strcmp(self.mCurAttributeValueBegin, "true")) { *((bool*)val_ptr) = true; @@ -1266,64 +1276,64 @@ bool LLFastXUIParser::readBoolValue(Parser& parser, void* val_ptr) return false; } -bool LLFastXUIParser::readStringValue(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); *((std::string*)val_ptr) = self.mCurAttributeValueBegin; return true; } -bool LLFastXUIParser::readU8Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; } -bool LLFastXUIParser::readS8Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; } -bool LLFastXUIParser::readU16Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; } -bool LLFastXUIParser::readS16Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; } -bool LLFastXUIParser::readU32Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; } -bool LLFastXUIParser::readS32Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; } -bool LLFastXUIParser::readF32Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; } -bool LLFastXUIParser::readF64Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; } -bool LLFastXUIParser::readColor4Value(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); LLColor4 value; if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) @@ -1334,9 +1344,9 @@ bool LLFastXUIParser::readColor4Value(Parser& parser, void* val_ptr) return false; } -bool LLFastXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); LLColor4 value; LLUIColor* colorp = (LLUIColor*)val_ptr; @@ -1348,12 +1358,12 @@ bool LLFastXUIParser::readUIColorValue(Parser& parser, void* val_ptr) return false; } -bool LLFastXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); LLUUID temp_id; // LLUUID::set is destructive, so use temporary value - if (temp_id.set(self.mCurAttributeValueBegin)) + if (temp_id.set(std::string(self.mCurAttributeValueBegin))) { *(LLUUID*)(val_ptr) = temp_id; return true; @@ -1361,9 +1371,9 @@ bool LLFastXUIParser::readUUIDValue(Parser& parser, void* val_ptr) return false; } -bool LLFastXUIParser::readSDValue(Parser& parser, void* val_ptr) +bool LLSimpleXUIParser::readSDValue(Parser& parser, void* val_ptr) { - LLFastXUIParser& self = static_cast(parser); + LLSimpleXUIParser& self = static_cast(parser); *((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); return true; } \ No newline at end of file diff --git a/indra/llxuixml/llxuiparser.h b/indra/llxuixml/llxuiparser.h index 4deb083e1c..eb7147f49e 100644 --- a/indra/llxuixml/llxuiparser.h +++ b/indra/llxuixml/llxuiparser.h @@ -171,14 +171,25 @@ private: std::string mCurFileName; }; -class LLFastXUIParser : public LLInitParam::Parser, public LLSingleton +// LLSimpleXUIParser is a streamlined SAX-based XUI parser that does not support localization +// or parsing of a tree of independent param blocks, such as child widgets. +// Use this for reading non-localized files that only need a single param block as a result. +// +// NOTE: In order to support nested block parsing, we need callbacks for start element that +// push new blocks contexts on the mScope stack. +// NOTE: To support localization without building a DOM, we need to enforce consistent +// ordering of child elements from base file to localized diff file. Then we can use a pair +// of coroutines to perform matching of xml nodes during parsing. Not sure if the overhead +// of coroutines would offset the gain from SAX parsing + +class LLSimpleXUIParser : public LLInitParam::Parser, public LLSingleton { -LOG_CLASS(LLFastXUIParser); +LOG_CLASS(LLSimpleXUIParser); protected: - LLFastXUIParser(); - virtual ~LLFastXUIParser(); - friend class LLSingleton; + LLSimpleXUIParser(); + virtual ~LLSimpleXUIParser(); + friend class LLSingleton; public: typedef LLInitParam::Parser::name_stack_t name_stack_t; @@ -187,6 +198,7 @@ public: /*virtual*/ void parserError(const std::string& message); bool readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent=false); + void setBlock(LLInitParam::BaseBlock* block); private: //reader helper functions @@ -222,6 +234,7 @@ private: LLXMLNodePtr mLastWrittenChild; S32 mCurReadDepth; std::string mCurFileName; + std::string mTextContents; const char* mCurAttributeValueBegin; std::vector mTokenSizeStack; std::vector mScope; -- cgit v1.2.3 From 7b41819377ec1c6ffc835a0a05a1acf571f46aad Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Fri, 6 Aug 2010 11:49:43 -0700 Subject: removed spurious parsing of empty text contents --- indra/llxuixml/llxuiparser.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'indra/llxuixml') diff --git a/indra/llxuixml/llxuiparser.cpp b/indra/llxuixml/llxuiparser.cpp index e010b4c125..b3cb71cd61 100644 --- a/indra/llxuixml/llxuiparser.cpp +++ b/indra/llxuixml/llxuiparser.cpp @@ -1199,11 +1199,15 @@ void LLSimpleXUIParser::endElement(const char *name) { if (!mTextContents.empty()) { - mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration())); - mCurAttributeValueBegin = mTextContents.c_str(); - mBlock->submitValue(mNameStack, *this); - mNameStack.pop_back(); - mTextContents.clear(); + LLStringUtil::trim(mTextContents); + if (!mTextContents.empty()) + { + mNameStack.push_back(std::make_pair(std::string("value"), newParseGeneration())); + mCurAttributeValueBegin = mTextContents.c_str(); + mBlock->submitValue(mNameStack, *this, false); + mNameStack.pop_back(); + mTextContents.clear(); + } } mCurReadDepth--; S32 num_tokens_to_pop = mTokenSizeStack.back(); -- cgit v1.2.3