diff options
Diffstat (limited to 'indra/llui')
| -rw-r--r-- | indra/llui/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | indra/llui/llcontainerview.cpp | 18 | ||||
| -rw-r--r-- | indra/llui/llmultifloater.cpp | 2 | ||||
| -rw-r--r-- | indra/llui/llnotifications.cpp | 11 | ||||
| -rw-r--r-- | indra/llui/llnotifications.h | 1 | ||||
| -rw-r--r-- | indra/llui/llnotificationtemplate.h | 19 | ||||
| -rw-r--r-- | indra/llui/llsdparam.cpp | 342 | ||||
| -rw-r--r-- | indra/llui/llsdparam.h | 126 | ||||
| -rw-r--r-- | indra/llui/llstatbar.cpp | 2 | ||||
| -rw-r--r-- | indra/llui/lltrans.cpp | 295 | ||||
| -rw-r--r-- | indra/llui/lltrans.h | 133 | ||||
| -rw-r--r-- | indra/llui/lluicolor.cpp | 87 | ||||
| -rw-r--r-- | indra/llui/lluicolor.h | 71 | ||||
| -rw-r--r-- | indra/llui/llxuiparser.cpp | 1756 | ||||
| -rw-r--r-- | indra/llui/llxuiparser.h | 242 | ||||
| -rw-r--r-- | indra/llui/tests/llurlentry_stub.cpp | 22 | ||||
| -rw-r--r-- | indra/llui/tests/llurlentry_test.cpp | 15 | ||||
| -rw-r--r-- | indra/llui/tests/llurlmatch_test.cpp | 34 | 
18 files changed, 2630 insertions, 556 deletions
| diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 772f173f17..20c3456a56 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -12,7 +12,6 @@ include(LLRender)  include(LLWindow)  include(LLVFS)  include(LLXML) -include(LLXUIXML)  include_directories(      ${LLCOMMON_INCLUDE_DIRS} @@ -24,7 +23,6 @@ include_directories(      ${LLWINDOW_INCLUDE_DIRS}      ${LLVFS_INCLUDE_DIRS}      ${LLXML_INCLUDE_DIRS} -    ${LLXUIXML_INCLUDE_DIRS}      )  set(llui_SOURCE_FILES @@ -83,7 +81,6 @@ set(llui_SOURCE_FILES      llscrolllistcolumn.cpp      llscrolllistctrl.cpp      llscrolllistitem.cpp -    llsdparam.cpp      llsearcheditor.cpp      llslider.cpp      llsliderctrl.cpp @@ -100,11 +97,13 @@ set(llui_SOURCE_FILES      lltextutil.cpp      lltextvalidate.cpp      lltimectrl.cpp +    lltrans.cpp      lltransutil.cpp      lltoggleablemenu.cpp      lltoolbar.cpp      lltooltip.cpp      llui.cpp +    lluicolor.cpp      lluicolortable.cpp      lluictrl.cpp      lluictrlfactory.cpp @@ -121,6 +120,7 @@ set(llui_SOURCE_FILES      llview.cpp      llviewquery.cpp      llwindowshade.cpp +    llxuiparser.cpp      )  set(llui_HEADER_FILES @@ -189,7 +189,6 @@ set(llui_HEADER_FILES      llscrolllistcolumn.h      llscrolllistctrl.h      llscrolllistitem.h -    llsdparam.h      llsliderctrl.h      llslider.h      llspinctrl.h @@ -208,6 +207,7 @@ set(llui_HEADER_FILES      lltoggleablemenu.h      lltoolbar.h      lltooltip.h +    lltrans.h      lltransutil.h      lluicolortable.h      lluiconstants.h @@ -215,6 +215,7 @@ set(llui_HEADER_FILES      lluictrl.h      lluifwd.h      llui.h +    lluicolor.h      lluiimage.h      lluistring.h      llundo.h @@ -228,6 +229,7 @@ set(llui_HEADER_FILES      llview.h      llviewquery.h      llwindowshade.h +    llxuiparser.h      )  set_source_files_properties(${llui_HEADER_FILES} diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp index e01e331acf..e08ccb0b78 100644 --- a/indra/llui/llcontainerview.cpp +++ b/indra/llui/llcontainerview.cpp @@ -196,24 +196,24 @@ void LLContainerView::arrange(S32 width, S32 height, BOOL called_from_parent)  	if (total_height < height)  		total_height = height; +	LLRect my_rect = getRect();  	if (followsTop())  	{ -		// HACK: casting away const. Should use setRect or some helper function instead. -		const_cast<LLRect&>(getRect()).mBottom = getRect().mTop - total_height; +		my_rect.mBottom = my_rect.mTop - total_height;  	}  	else  	{ -		// HACK: casting away const. Should use setRect or some helper function instead. -		const_cast<LLRect&>(getRect()).mTop = getRect().mBottom + total_height; +		my_rect.mTop = my_rect.mBottom + total_height;  	} -	// HACK: casting away const. Should use setRect or some helper function instead. -		const_cast<LLRect&>(getRect()).mRight = getRect().mLeft + width; + +	my_rect.mRight = my_rect.mLeft + width; +	setRect(my_rect);  	top = total_height;  	if (mShowLabel) -		{ -			top -= 20; -		} +	{ +		top -= 20; +	}  	bottom = top; diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index f3a48835b1..aa5f577897 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -349,7 +349,7 @@ void LLMultiFloater::setVisible(BOOL visible)  BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)  { -	if (key == 'W' && mask == (MASK_CONTROL|MASK_SHIFT)) +	if (key == 'W' && mask == MASK_CONTROL)  	{  		LLFloater* floater = getActiveFloater();  		// is user closeable and is system closeable diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 83fa6da863..629eef2c3b 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -399,6 +399,7 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par  :	mName(p.name),  	mType(p.type),  	mMessage(p.value), +	mFooter(p.footer.value),  	mLabel(p.label),  	mIcon(p.icon),  	mURL(p.url.value), @@ -870,6 +871,16 @@ std::string LLNotification::getMessage() const  	return message;  } +std::string LLNotification::getFooter() const +{ +	if (!mTemplatep) +		return std::string(); + +	std::string footer = mTemplatep->mFooter; +	LLStringUtil::format(footer, mSubstitutions); +	return footer; +} +  std::string LLNotification::getLabel() const  {  	std::string label = mTemplatep->mLabel; diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 3df2efcac3..4ae02b943f 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -509,6 +509,7 @@ public:  	std::string getType() const;  	std::string getMessage() const; +	std::string getFooter() const;  	std::string getLabel() const;  	std::string getURL() const;  	S32 getURLOption() const; diff --git a/indra/llui/llnotificationtemplate.h b/indra/llui/llnotificationtemplate.h index 56b18eb81a..b3b0bae862 100644 --- a/indra/llui/llnotificationtemplate.h +++ b/indra/llui/llnotificationtemplate.h @@ -169,6 +169,17 @@ struct LLNotificationTemplate  		{}  	}; +	struct Footer : public LLInitParam::Block<Footer> +	{ +		Mandatory<std::string> value; + +		Footer() +		:	value("value") +		{ +			addSynonym(value, ""); +		} +	}; +  	struct Params : public LLInitParam::Block<Params>  	{  		Mandatory<std::string>			name; @@ -186,7 +197,8 @@ struct LLNotificationTemplate  		Optional<FormRef>				form_ref;  		Optional<ENotificationPriority,   			NotificationPriorityValues> priority; -		Multiple<Tag>		tags; +		Multiple<Tag>					tags; +		Optional<Footer>				footer;  		Params() @@ -204,7 +216,8 @@ struct LLNotificationTemplate  			url("url"),  			unique("unique"),  			form_ref(""), -			tags("tag") +			tags("tag"), +			footer("footer")  		{}  	}; @@ -233,6 +246,8 @@ struct LLNotificationTemplate      // The text used to display the notification. Replaceable parameters      // are enclosed in square brackets like this [].      std::string mMessage; +    // The text used to display the notification, but under the form. +    std::string mFooter;  	// The label for the notification; used for   	// certain classes of notification (those with a window and a window title).   	// Also used when a notification pops up underneath the current one. diff --git a/indra/llui/llsdparam.cpp b/indra/llui/llsdparam.cpp deleted file mode 100644 index 0e29873bb0..0000000000 --- a/indra/llui/llsdparam.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/**  - * @file llsdparam.cpp - * @brief parameter block abstraction for creating complex objects and  - * parsing construction parameters from xml and LLSD - * - * $LicenseInfo:firstyear=2008&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" - -// Project includes -#include "llsdparam.h" -#include "llsdutil.h" - -static 	LLInitParam::Parser::parser_read_func_map_t sReadFuncs; -static 	LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; -static 	LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; -static const LLSD NO_VALUE_MARKER; - -LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); - -// -// LLParamSDParser -// -LLParamSDParser::LLParamSDParser() -: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs) -{ -	using boost::bind; - -	if (sReadFuncs.empty()) -	{ -		registerParserFuncs<LLInitParam::Flag>(readFlag, &LLParamSDParser::writeFlag); -		registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>); -		registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param); -		registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>); -		registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>); -		registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>); -		registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>); -		registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>); -		registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>); -		registerParserFuncs<LLURI>(readURI, &LLParamSDParser::writeTypedValue<LLURI>); -		registerParserFuncs<LLSD>(readSD, &LLParamSDParser::writeTypedValue<LLSD>); -	} -} - -// special case handling of U32 due to ambiguous LLSD::assign overload -bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) -{ -	LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); -	if (!sdparser.mWriteRootSD) return false; -	 -	parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); -	LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); -	sd_to_write.assign((S32)*((const U32*)val_ptr)); - -	return true; -} - -bool LLParamSDParser::writeFlag(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) -{ -	LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); -	if (!sdparser.mWriteRootSD) return false; - -	parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); -	LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - -	return true; -} - -void LLParamSDParser::submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack) -{ -	mCurReadSD = &sd; -	block.submitValue(name_stack, *this); -} - -void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent) -{ -	mCurReadSD = NULL; -	mNameStack.clear(); -	setParseSilently(silent); - -	LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); -	//readSDValues(sd, block); -} - -void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block) -{ -	mNameStack.clear(); -	mWriteRootSD = &sd; - -	name_stack_t name_stack; -	block.serializeBlock(*this, name_stack); -} - -/*virtual*/ std::string LLParamSDParser::getCurrentElementName() -{ -	std::string full_name = "sd"; -	for (name_stack_t::iterator it = mNameStack.begin();	 -		it != mNameStack.end(); -		++it) -	{ -		full_name += llformat("[%s]", it->first.c_str()); -	} - -	return full_name; -} - - -bool LLParamSDParser::readFlag(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); -	return self.mCurReadSD == &NO_VALUE_MARKER; -} - - -bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((S32*)val_ptr) = self.mCurReadSD->asInteger(); -    return true; -} - -bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((U32*)val_ptr) = self.mCurReadSD->asInteger(); -    return true; -} - -bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((F32*)val_ptr) = self.mCurReadSD->asReal(); -    return true; -} - -bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((F64*)val_ptr) = self.mCurReadSD->asReal(); -    return true; -} - -bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -    *((bool*)val_ptr) = self.mCurReadSD->asBoolean(); -    return true; -} - -bool LLParamSDParser::readString(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((std::string*)val_ptr) = self.mCurReadSD->asString(); -    return true; -} - -bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); -    return true; -} - -bool LLParamSDParser::readDate(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((LLDate*)val_ptr) = self.mCurReadSD->asDate(); -    return true; -} - -bool LLParamSDParser::readURI(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((LLURI*)val_ptr) = self.mCurReadSD->asURI(); -    return true; -} - -bool LLParamSDParser::readSD(Parser& parser, void* val_ptr) -{ -	LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - -	*((LLSD*)val_ptr) = *self.mCurReadSD; -    return true; -} - -// static -LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range) -{ -	LLSD* sd_to_write = &input; -	 -	for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; -		it != name_stack_range.second; -		++it) -	{ -		bool new_traversal = it->second; - -		LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; - -		if (child_sd->isArray()) -		{ -			if (new_traversal) -			{ -				// write to new element at end -				sd_to_write = &(*child_sd)[child_sd->size()]; -			} -			else -			{ -				// write to last of existing elements, or first element if empty -				sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; -			} -		} -		else -		{ -			if (new_traversal  -				&& child_sd->isDefined()  -				&& !child_sd->isArray()) -			{ -				// copy child contents into first element of an array -				LLSD new_array = LLSD::emptyArray(); -				new_array.append(*child_sd); -				// assign array to slot that previously held the single value -				*child_sd = new_array; -				// return next element in that array -				sd_to_write = &((*child_sd)[1]); -			} -			else -			{ -				sd_to_write = child_sd; -			} -		} -		it->second = false; -	} -	 -	return *sd_to_write; -} - -//static -void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack) -{ -	if (sd.isMap()) -	{ -		for (LLSD::map_const_iterator it = sd.beginMap(); -			it != sd.endMap(); -			++it) -		{ -			stack.push_back(make_pair(it->first, true)); -			readSDValues(cb, it->second, stack); -			stack.pop_back(); -		} -	} -	else if (sd.isArray()) -	{ -		for (LLSD::array_const_iterator it = sd.beginArray(); -			it != sd.endArray(); -			++it) -		{ -			stack.back().second = true; -			readSDValues(cb, *it, stack); -		} -	} -	else if (sd.isUndefined()) -	{ -		if (!cb.empty()) -		{ -			cb(NO_VALUE_MARKER, stack); -		} -	} -	else -	{ -		if (!cb.empty()) -		{ -			cb(sd, stack); -		} -	} -} - -//static -void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) -{ -	LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); -	readSDValues(cb, sd, stack); -} -namespace LLInitParam -{ -	// LLSD specialization -	// block param interface -	bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name) -	{ -		LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); - -		LLSD::String string; - -		if (p.readValue<LLSD::String>(string)) -		{ -			sd = string; -			return true; -		} -		return false; -	} - -	//static -	void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) -	{ -		p.writeValue<LLSD::String>(sd.asString(), name_stack); -	} - -	void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const -	{ -		// read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) -		Parser::name_stack_t stack; -		LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); -	} -} diff --git a/indra/llui/llsdparam.h b/indra/llui/llsdparam.h deleted file mode 100644 index 3dfc6d020e..0000000000 --- a/indra/llui/llsdparam.h +++ /dev/null @@ -1,126 +0,0 @@ -/**  - * @file llsdparam.h - * @brief parameter block abstraction for creating complex objects and  - * parsing construction parameters from xml and LLSD - * - * $LicenseInfo:firstyear=2008&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$ - */ - -#ifndef LL_LLSDPARAM_H -#define LL_LLSDPARAM_H - -#include "llinitparam.h" -#include "boost/function.hpp" - -struct LLParamSDParserUtilities -{ -	static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); - -	typedef boost::function<void (const LLSD&, LLInitParam::Parser::name_stack_t&)> read_sd_cb_t; -	static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); -	static void readSDValues(read_sd_cb_t cb, const LLSD& sd); -}; - -class LLParamSDParser  -:	public LLInitParam::Parser -{ -LOG_CLASS(LLParamSDParser); - -typedef LLInitParam::Parser parser_t; - -public: -	LLParamSDParser(); -	void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); -	void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block); - -	/*virtual*/ std::string getCurrentElementName(); - -private: -	void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); - -	template<typename T> -	static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) -	{ -		LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); -		if (!sdparser.mWriteRootSD) return false; -		 -		LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); -		LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - -		sd_to_write.assign(*((const T*)val_ptr)); -		return true; -	} - -	static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); -	static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); - -	static bool readFlag(Parser& parser, void* val_ptr); -	static bool readS32(Parser& parser, void* val_ptr); -	static bool readU32(Parser& parser, void* val_ptr); -	static bool readF32(Parser& parser, void* val_ptr); -	static bool readF64(Parser& parser, void* val_ptr); -	static bool readBool(Parser& parser, void* val_ptr); -	static bool readString(Parser& parser, void* val_ptr); -	static bool readUUID(Parser& parser, void* val_ptr); -	static bool readDate(Parser& parser, void* val_ptr); -	static bool readURI(Parser& parser, void* val_ptr); -	static bool readSD(Parser& parser, void* val_ptr); - -	Parser::name_stack_t	mNameStack; -	const LLSD*				mCurReadSD; -	LLSD*					mWriteRootSD; -	LLSD*					mCurWriteSD; -}; - - -extern LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR; -template<typename T> -class LLSDParamAdapter : public T -{ -public: -	LLSDParamAdapter() {} -	LLSDParamAdapter(const LLSD& sd) -	{ -		LLFastTimer _(FTM_SD_PARAM_ADAPTOR); -		LLParamSDParser parser; -		// don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it -		bool parse_silently = true; -		parser.readSD(sd, *this, parse_silently); -	} - -	operator LLSD() const -	{ -		LLParamSDParser parser; -		LLSD sd; -		parser.writeSD(sd, *this); -		return sd; -	} -		 -	LLSDParamAdapter(const T& val) -	: T(val) -	{ -		T::operator=(val); -	} -}; - -#endif // LL_LLSDPARAM_H - diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index ec4db14790..04cce7878e 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -272,7 +272,7 @@ LLRect LLStatBar::getRequiredRect()  	{  		if (mDisplayHistory)  		{ -			rect.mTop = 67; +			rect.mTop = 35 + mStatp->getNumBins();  		}  		else  		{ diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp new file mode 100644 index 0000000000..5388069c24 --- /dev/null +++ b/indra/llui/lltrans.cpp @@ -0,0 +1,295 @@ +/** + * @file lltrans.cpp + * @brief LLTrans implementation + * + * $LicenseInfo:firstyear=2000&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 "lltrans.h" + +#include "llfasttimer.h"	// for call count statistics +#include "llxuiparser.h" +#include "llsd.h" +#include "llxmlnode.h" + +#include <map> + +LLTrans::template_map_t LLTrans::sStringTemplates; +LLStringUtil::format_map_t LLTrans::sDefaultArgs; + +struct StringDef : public LLInitParam::Block<StringDef> +{ +	Mandatory<std::string> name; +	Mandatory<std::string> value; + +	StringDef() +	:	name("name"), +		value("value") +	{} +}; + +struct StringTable : public LLInitParam::Block<StringTable> +{ +	Multiple<StringDef> strings; +	StringTable() +	:	strings("string") +	{} +}; + +//static  +bool LLTrans::parseStrings(LLXMLNodePtr &root, const std::set<std::string>& default_args) +{ +	std::string xml_filename = "(strings file)"; +	if (!root->hasName("strings")) +	{ +		llerrs << "Invalid root node name in " << xml_filename  +			<< ": was " << root->getName() << ", expected \"strings\"" << llendl; +	} + +	StringTable string_table; +	LLXUIParser parser; +	parser.readXUI(root, string_table, xml_filename); + +	if (!string_table.validateBlock()) +	{ +		llerrs << "Problem reading strings: " << xml_filename << llendl; +		return false; +	} +	 +	sStringTemplates.clear(); +	sDefaultArgs.clear(); +	 +	for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin(); +		it != string_table.strings.end(); +		++it) +	{ +		LLTransTemplate xml_template(it->name, it->value); +		sStringTemplates[xml_template.mName] = xml_template; +		 +		std::set<std::string>::const_iterator iter = default_args.find(xml_template.mName); +		if (iter != default_args.end()) +		{ +			std::string name = *iter; +			if (name[0] != '[') +				name = llformat("[%s]",name.c_str()); +			sDefaultArgs[name] = xml_template.mText; +		} +	} + +	return true; +} + + +//static +bool LLTrans::parseLanguageStrings(LLXMLNodePtr &root) +{ +	std::string xml_filename = "(language strings file)"; +	if (!root->hasName("strings")) +	{ +		llerrs << "Invalid root node name in " << xml_filename  +		<< ": was " << root->getName() << ", expected \"strings\"" << llendl; +	} +	 +	StringTable string_table; +	LLXUIParser parser; +	parser.readXUI(root, string_table, xml_filename); +	 +	if (!string_table.validateBlock()) +	{ +		llerrs << "Problem reading strings: " << xml_filename << llendl; +		return false; +	} +		 +	for(LLInitParam::ParamIterator<StringDef>::const_iterator it = string_table.strings.begin(); +		it != string_table.strings.end(); +		++it) +	{ +		// share the same map with parseStrings() so we can search the strings using the same getString() function.- angela +		LLTransTemplate xml_template(it->name, it->value); +		sStringTemplates[xml_template.mName] = xml_template; +	} +	 +	return true; +} + + + +static LLFastTimer::DeclareTimer FTM_GET_TRANS("Translate string"); + +//static  +std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) +{ +	// Don't care about time as much as call count.  Make sure we're not +	// calling LLTrans::getString() in an inner loop. JC +	LLFastTimer timer(FTM_GET_TRANS); +	 +	template_map_t::iterator iter = sStringTemplates.find(xml_desc); +	if (iter != sStringTemplates.end()) +	{ +		std::string text = iter->second.mText; +		LLStringUtil::format_map_t args = sDefaultArgs; +		args.insert(msg_args.begin(), msg_args.end()); +		LLStringUtil::format(text, args); +		 +		return text; +	} +	else +	{ +		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; +		return "MissingString("+xml_desc+")"; +	} +} + +//static +std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args) +{ +	// Don't care about time as much as call count.  Make sure we're not +	// calling LLTrans::getString() in an inner loop. JC +	LLFastTimer timer(FTM_GET_TRANS); + +	template_map_t::iterator iter = sStringTemplates.find(xml_desc); +	if (iter != sStringTemplates.end()) +	{ +		std::string text = iter->second.mText; +		LLStringUtil::format(text, msg_args); +		return text; +	} +	else +	{ +		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL; +		return "MissingString("+xml_desc+")"; +	} +} + +//static  +bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) +{ +	LLFastTimer timer(FTM_GET_TRANS); +	 +	template_map_t::iterator iter = sStringTemplates.find(xml_desc); +	if (iter != sStringTemplates.end()) +	{ +		std::string text = iter->second.mText; +		LLStringUtil::format_map_t args = sDefaultArgs; +		args.insert(msg_args.begin(), msg_args.end()); +		LLStringUtil::format(text, args); +		result = text; +		return true; +	} +	else +	{ +		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;	 +		return false; +	} +} + +//static +bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args) +{ +	LLFastTimer timer(FTM_GET_TRANS); + +	template_map_t::iterator iter = sStringTemplates.find(xml_desc); +	if (iter != sStringTemplates.end()) +	{ +		std::string text = iter->second.mText; +		LLStringUtil::format(text, msg_args); +		result = text; +		return true; +	} +	else +	{ +		LL_WARNS_ONCE("configuration") << "Missing String in strings.xml: [" << xml_desc << "]" << LL_ENDL;	 +		return false; +	} +} + +//static +std::string LLTrans::getCountString(const std::string& language, const std::string& xml_desc, S32 count) +{ +	// Compute which string identifier to use +	const char* form = ""; +	if (language == "ru") // Russian +	{ +		// From GNU ngettext() +		// Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; +		if (count % 10 == 1 +			&& count % 100 != 11) +		{ +			// singular, "1 item" +			form = "A"; +		} +		else if (count % 10 >= 2 +			&& count % 10 <= 4 +			&& (count % 100 < 10 || count % 100 >= 20) ) +		{ +			// special case "2 items", "23 items", but not "13 items" +			form = "B"; +		} +		else +		{ +			// English-style plural, "5 items" +			form = "C"; +		} +	} +	else if (language == "fr" || language == "pt") // French, Brazilian Portuguese +	{ +		// French and Portuguese treat zero as a singular "0 item" not "0 items" +		if (count == 0 || count == 1) +		{ +			form = "A"; +		} +		else +		{ +			// English-style plural +			form = "B"; +		} +	} +	else // default +	{ +		// languages like English with 2 forms, singular and plural +		if (count == 1) +		{ +			// "1 item" +			form = "A"; +		} +		else +		{ +			// "2 items", also use plural for "0 items" +			form = "B"; +		} +	} + +	// Translate that string +	LLStringUtil::format_map_t args; +	args["[COUNT]"] = llformat("%d", count); + +	// Look up "AgeYearsB" or "AgeWeeksC" including the "form" +	std::string key = llformat("%s%s", xml_desc.c_str(), form); +	return getString(key, args); +} + +void LLTrans::setDefaultArg(const std::string& name, const std::string& value) +{ +	sDefaultArgs[name] = value; +} diff --git a/indra/llui/lltrans.h b/indra/llui/lltrans.h new file mode 100644 index 0000000000..128b51d383 --- /dev/null +++ b/indra/llui/lltrans.h @@ -0,0 +1,133 @@ +/** + * @file lltrans.h + * @brief LLTrans definition + * + * $LicenseInfo:firstyear=2000&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$ + */ + +#ifndef LL_TRANS_H +#define LL_TRANS_H + +#include <map> + +#include "llpointer.h" +#include "llstring.h" + +class LLXMLNode; + +class LLSD; + +/** + * @brief String template loaded from strings.xml + */ +class LLTransTemplate +{ +public: +	LLTransTemplate(const std::string& name = LLStringUtil::null, const std::string& text = LLStringUtil::null) : mName(name), mText(text) {} + +	std::string mName; +	std::string mText; +}; + +/** + * @brief Localized strings class + * This class is used to retrieve translations of strings used to build larger ones, as well as + * strings with a general usage that don't belong to any specific floater. For example, + * "Owner:", "Retrieving..." used in the place of a not yet known name, etc. + */ +class LLTrans +{ +public: +	LLTrans(); + +	/** +	 * @brief Parses the xml root that holds the strings. Used once on startup +// *FIXME	 * @param xml_filename Filename to parse +	 * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" +	 * @returns true if the file was parsed successfully, true if something went wrong +	 */ +	static bool parseStrings(LLPointer<LLXMLNode> & root, const std::set<std::string>& default_args); + +	static bool parseLanguageStrings(LLPointer<LLXMLNode> & root); + +	/** +	 * @brief Returns a translated string +	 * @param xml_desc String's description +	 * @param args A list of substrings to replace in the string +	 * @returns Translated string +	 */ +	static std::string getString(const std::string &xml_desc, const LLStringUtil::format_map_t& args); +	static std::string getString(const std::string &xml_desc, const LLSD& args); +	static bool findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& args); +	static bool findString(std::string &result, const std::string &xml_desc, const LLSD& args); + +	// Returns translated string with [COUNT] replaced with a number, following +	// special per-language logic for plural nouns.  For example, some languages +	// may have different plurals for 0, 1, 2 and > 2. +	// See "AgeWeeksA", "AgeWeeksB", etc. in strings.xml for examples. +	static std::string getCountString(const std::string& language, const std::string& xml_desc, S32 count); + +	/** +	 * @brief Returns a translated string +	 * @param xml_desc String's description +	 * @returns Translated string +	 */ +	static std::string getString(const std::string &xml_desc) +	{ +		LLStringUtil::format_map_t empty; +		return getString(xml_desc, empty); +	} + +	static bool findString(std::string &result, const std::string &xml_desc) +	{ +		LLStringUtil::format_map_t empty; +		return findString(result, xml_desc, empty); +	} + +	static std::string getKeyboardString(const char* keystring) +	{ +		std::string key_str(keystring); +		std::string trans_str; +		return findString(trans_str, key_str) ? trans_str : key_str;  +	} + +	// get the default args +	static const LLStringUtil::format_map_t& getDefaultArgs() +	{ +		return sDefaultArgs; +	} + +	static void setDefaultArg(const std::string& name, const std::string& value); + +	// insert default args into an arg list +	static void getArgs(LLStringUtil::format_map_t& args) +	{ +		args.insert(sDefaultArgs.begin(), sDefaultArgs.end()); +	} +	 +private: +	typedef std::map<std::string, LLTransTemplate > template_map_t; +	static template_map_t sStringTemplates; +	static LLStringUtil::format_map_t sDefaultArgs; +}; + +#endif diff --git a/indra/llui/lluicolor.cpp b/indra/llui/lluicolor.cpp new file mode 100644 index 0000000000..f9bb80f8c5 --- /dev/null +++ b/indra/llui/lluicolor.cpp @@ -0,0 +1,87 @@ +/**  + * @file lluicolor.cpp + * @brief brief LLUIColor class implementation file + * + * $LicenseInfo:firstyear=2009&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 "lluicolor.h" + +LLUIColor::LLUIColor() +	:mColorPtr(NULL) +{ +} + + +LLUIColor::LLUIColor(const LLColor4& color) +:	mColor(color),  +	mColorPtr(NULL) +{ +} + +LLUIColor::LLUIColor(const LLUIColor* color) +:	mColorPtr(color) +{ +} + +void LLUIColor::set(const LLColor4& color) +{ +	mColor = color; +	mColorPtr = NULL; +} + +void LLUIColor::set(const LLUIColor* color) +{ +	mColorPtr = color; +} + +const LLColor4& LLUIColor::get() const +{ +	return (mColorPtr == NULL ? mColor : mColorPtr->get()); +} + +LLUIColor::operator const LLColor4& () const +{ +	return get(); +} + +const LLColor4& LLUIColor::operator()() const +{ +	return get(); +} + +bool LLUIColor::isReference() const +{ +	return mColorPtr != NULL; +} + +namespace LLInitParam +{ +	// used to detect equivalence with default values on export +	bool ParamCompare<LLUIColor, false>::equals(const LLUIColor &a, const LLUIColor &b) +	{ +		// do not detect value equivalence, treat pointers to colors as distinct from color values +		return (a.mColorPtr == NULL && b.mColorPtr == NULL ? a.mColor == b.mColor : a.mColorPtr == b.mColorPtr); +	} +} diff --git a/indra/llui/lluicolor.h b/indra/llui/lluicolor.h new file mode 100644 index 0000000000..97ebea854a --- /dev/null +++ b/indra/llui/lluicolor.h @@ -0,0 +1,71 @@ +/**  + * @file lluicolor.h + * @brief brief LLUIColor class header file + * + * $LicenseInfo:firstyear=2009&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$ + */ + +#ifndef LL_LLUICOLOR_H_ +#define LL_LLUICOLOR_H_ + +#include "v4color.h" + +namespace LLInitParam +{ +	template<typename T, bool> +	struct ParamCompare; +} + +class LLUIColor +{ +public: +	LLUIColor(); +	LLUIColor(const LLColor4& color); +	LLUIColor(const LLUIColor* color); + +	void set(const LLColor4& color); +	void set(const LLUIColor* color); + +	const LLColor4& get() const; + +	operator const LLColor4& () const; +	const LLColor4& operator()() const; + +	bool isReference() const; + +private: +	friend struct LLInitParam::ParamCompare<LLUIColor, false>; + +	const LLUIColor* mColorPtr; +	LLColor4 mColor; +}; + +namespace LLInitParam +{ +	template<> +	struct ParamCompare<LLUIColor, false> +	{ +		static bool equals(const LLUIColor& a, const LLUIColor& b); +	}; +} + +#endif diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp new file mode 100644 index 0000000000..afc76024d1 --- /dev/null +++ b/indra/llui/llxuiparser.cpp @@ -0,0 +1,1756 @@ +/**  + * @file llxuiparser.cpp + * @brief Utility functions for handling XUI structures in XML + * + * $LicenseInfo:firstyear=2003&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 "llxuiparser.h" + +#include "llxmlnode.h" + +#ifdef LL_STANDALONE +#include <expat.h> +#else +#include "expat/expat.h" +#endif + +#include <fstream> +#include <boost/tokenizer.hpp> +//#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/classic_core.hpp> + +#include "lluicolor.h" + +using namespace BOOST_SPIRIT_CLASSIC_NS; + +const S32 MAX_STRING_ATTRIBUTE_SIZE = 40; + +static 	LLInitParam::Parser::parser_read_func_map_t sXSDReadFuncs; +static 	LLInitParam::Parser::parser_write_func_map_t sXSDWriteFuncs; +static 	LLInitParam::Parser::parser_inspect_func_map_t sXSDInspectFuncs; + +static 	LLInitParam::Parser::parser_read_func_map_t sSimpleXUIReadFuncs; +static 	LLInitParam::Parser::parser_write_func_map_t sSimpleXUIWriteFuncs; +static 	LLInitParam::Parser::parser_inspect_func_map_t sSimpleXUIInspectFuncs; + +const char* NO_VALUE_MARKER = "no_value"; + +const S32 LINE_NUMBER_HERE = 0; + +struct MaxOccursValues : public LLInitParam::TypeValuesHelper<U32, MaxOccursValues> +{ +	static void declareValues() +	{ +		declare("unbounded", U32_MAX); +	} +}; + +struct Occurs : public LLInitParam::Block<Occurs> +{ +	Optional<U32>					minOccurs; +	Optional<U32, MaxOccursValues>	maxOccurs; + +	Occurs() +	:	minOccurs("minOccurs", 0), +		maxOccurs("maxOccurs", U32_MAX) + +	{} +}; + + +typedef enum +{ +	USE_REQUIRED, +	USE_OPTIONAL +} EUse; + +namespace LLInitParam +{ +	template<> +	struct TypeValues<EUse> : public TypeValuesHelper<EUse> +	{ +		static void declareValues() +		{ +			declare("required", USE_REQUIRED); +			declare("optional", USE_OPTIONAL); +		} +	}; +} + +struct Element; +struct Group; +struct Choice; +struct Sequence; +struct Any; + +struct Attribute : public LLInitParam::Block<Attribute> +{ +	Mandatory<std::string>	name; +	Mandatory<std::string>	type; +	Mandatory<EUse>			use; +	 +	Attribute() +	:	name("name"), +		type("type"), +		use("use") +	{} +}; + +struct Any : public LLInitParam::Block<Any, Occurs> +{ +	Optional<std::string> _namespace; + +	Any() +	:	_namespace("namespace") +	{} +}; + +struct All : public LLInitParam::Block<All, Occurs> +{ +	Multiple< Lazy<Element> > elements; + +	All() +	:	elements("element") +	{ +		maxOccurs = 1; +	} +}; + +struct Choice : public LLInitParam::ChoiceBlock<Choice, Occurs> +{ +	Alternative< Lazy<Element> >	element; +	Alternative< Lazy<Group> >		group; +	Alternative< Lazy<Choice> >		choice; +	Alternative< Lazy<Sequence> >	sequence; +	Alternative< Lazy<Any> >		any; + +	Choice() +	:	element("element"), +		group("group"), +		choice("choice"), +		sequence("sequence"), +		any("any") +	{} + +}; + +struct Sequence : public LLInitParam::ChoiceBlock<Sequence, Occurs> +{ +	Alternative< Lazy<Element> >	element; +	Alternative< Lazy<Group> >		group; +	Alternative< Lazy<Choice> >		choice; +	Alternative< Lazy<Sequence> >	sequence; +	Alternative< Lazy<Any> >		any; +}; + +struct GroupContents : public LLInitParam::ChoiceBlock<GroupContents, Occurs> +{ +	Alternative<All>		all; +	Alternative<Choice>		choice; +	Alternative<Sequence>	sequence; + +	GroupContents() +	:	all("all"), +		choice("choice"), +		sequence("sequence") +	{} +}; + +struct Group : public LLInitParam::Block<Group, GroupContents> +{ +	Optional<std::string>	name, +							ref; + +	Group() +	:	name("name"), +		ref("ref") +	{} +}; + +struct Restriction : public LLInitParam::Block<Restriction> +{ +}; + +struct Extension : public LLInitParam::Block<Extension> +{ +}; + +struct SimpleContent : public LLInitParam::ChoiceBlock<SimpleContent> +{ +	Alternative<Restriction> restriction; +	Alternative<Extension> extension; + +	SimpleContent() +	:	restriction("restriction"), +		extension("extension") +	{} +}; + +struct SimpleType : public LLInitParam::Block<SimpleType> +{ +	// TODO +}; + +struct ComplexContent : public LLInitParam::Block<ComplexContent, SimpleContent> +{ +	Optional<bool> mixed; + +	ComplexContent() +	:	mixed("mixed", true) +	{} +}; + +struct ComplexTypeContents : public LLInitParam::ChoiceBlock<ComplexTypeContents> +{ +	Alternative<SimpleContent>	simple_content; +	Alternative<ComplexContent> complex_content; +	Alternative<Group>			group; +	Alternative<All>			all; +	Alternative<Choice>			choice; +	Alternative<Sequence>		sequence; + +	ComplexTypeContents() +	:	simple_content("simpleContent"), +		complex_content("complexContent"), +		group("group"), +		all("all"), +		choice("choice"), +		sequence("sequence") +	{} +}; + +struct ComplexType : public LLInitParam::Block<ComplexType, ComplexTypeContents> +{ +	Optional<std::string>			name; +	Optional<bool>					mixed; + +	Multiple<Attribute>				attribute; +	Multiple< Lazy<Element> >			elements; + +	ComplexType() +	:	name("name"), +		attribute("xs:attribute"), +		elements("xs:element"), +		mixed("mixed") +	{ +	} +}; + +struct ElementContents : public LLInitParam::ChoiceBlock<ElementContents, Occurs> +{ +	Alternative<SimpleType>		simpleType; +	Alternative<ComplexType>	complexType; + +	ElementContents() +	:	simpleType("simpleType"), +		complexType("complexType") +	{} +}; + +struct Element : public LLInitParam::Block<Element, ElementContents> +{ +	Optional<std::string>	name, +							ref, +							type; + +	Element() +	:	name("xs:name"), +		ref("xs:ref"), +		type("xs:type") +	{} +}; + +struct Schema : public LLInitParam::Block<Schema> +{ +private: +	Mandatory<std::string>	targetNamespace, +							xmlns, +							xs; + +public: +	Optional<std::string>	attributeFormDefault, +							elementFormDefault; + +	Mandatory<Element>		root_element; +	 +	void setNameSpace(const std::string& ns) {targetNamespace = ns; xmlns = ns;} + +	Schema(const std::string& ns = LLStringUtil::null) +	:	attributeFormDefault("attributeFormDefault"), +		elementFormDefault("elementFormDefault"), +		xs("xmlns:xs"), +		targetNamespace("targetNamespace"), +		xmlns("xmlns"), +		root_element("xs:element") +	{ +		attributeFormDefault = "unqualified"; +		elementFormDefault = "qualified"; +		xs = "http://www.w3.org/2001/XMLSchema"; +		if (!ns.empty()) +		{ +			setNameSpace(ns); +		}; +	} + +}; + +// +// LLXSDWriter +// +LLXSDWriter::LLXSDWriter() +: Parser(sXSDReadFuncs, sXSDWriteFuncs, sXSDInspectFuncs) +{ +	registerInspectFunc<bool>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:boolean", _1, _2, _3, _4)); +	registerInspectFunc<std::string>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +	registerInspectFunc<U8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedByte", _1, _2, _3, _4)); +	registerInspectFunc<S8>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedByte", _1, _2, _3, _4)); +	registerInspectFunc<U16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedShort", _1, _2, _3, _4)); +	registerInspectFunc<S16>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:signedShort", _1, _2, _3, _4)); +	registerInspectFunc<U32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:unsignedInt", _1, _2, _3, _4)); +	registerInspectFunc<S32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:integer", _1, _2, _3, _4)); +	registerInspectFunc<F32>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:float", _1, _2, _3, _4)); +	registerInspectFunc<F64>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:double", _1, _2, _3, _4)); +	registerInspectFunc<LLColor4>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +	registerInspectFunc<LLUIColor>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +	registerInspectFunc<LLUUID>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +	registerInspectFunc<LLSD>(boost::bind(&LLXSDWriter::writeAttribute, this, "xs:string", _1, _2, _3, _4)); +} + +void LLXSDWriter::writeXSD(const std::string& type_name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace) +{ +	Schema schema(xml_namespace); + +	schema.root_element.name = type_name; +	Choice& choice = schema.root_element.complexType.choice; + +	choice.minOccurs = 0; +	choice.maxOccurs = "unbounded"; + +	mSchemaNode = node; +	//node->setName("xs:schema"); +	//node->createChild("attributeFormDefault", true)->setStringValue("unqualified"); +	//node->createChild("elementFormDefault", true)->setStringValue("qualified"); +	//node->createChild("targetNamespace", true)->setStringValue(xml_namespace); +	//node->createChild("xmlns:xs", true)->setStringValue("http://www.w3.org/2001/XMLSchema"); +	//node->createChild("xmlns", true)->setStringValue(xml_namespace); + +	//node = node->createChild("xs:complexType", false); +	//node->createChild("name", true)->setStringValue(type_name); +	//node->createChild("mixed", true)->setStringValue("true"); + +	//mAttributeNode = node; +	//mElementNode = node->createChild("xs:choice", false); +	//mElementNode->createChild("minOccurs", true)->setStringValue("0"); +	//mElementNode->createChild("maxOccurs", true)->setStringValue("unbounded"); +	block.inspectBlock(*this); + +	// duplicate element choices +	LLXMLNodeList children; +	mElementNode->getChildren("xs:element", children, FALSE); +	for (LLXMLNodeList::iterator child_it = children.begin(); child_it != children.end(); ++child_it) +	{ +		LLXMLNodePtr child_copy = child_it->second->deepCopy(); +		std::string child_name; +		child_copy->getAttributeString("name", child_name); +		child_copy->setAttributeString("name", type_name + "." + child_name); +		mElementNode->addChild(child_copy); +	} + +	LLXMLNodePtr element_declaration_node = mSchemaNode->createChild("xs:element", false); +	element_declaration_node->createChild("name", true)->setStringValue(type_name); +	element_declaration_node->createChild("type", true)->setStringValue(type_name); +} + +void LLXSDWriter::writeAttribute(const std::string& type, const Parser::name_stack_t& stack, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values) +{ +	name_stack_t non_empty_names; +	std::string attribute_name; +	for (name_stack_t::const_iterator it = stack.begin(); +		it != stack.end(); +		++it) +	{ +		const std::string& name = it->first; +		if (!name.empty()) +		{ +			non_empty_names.push_back(*it); +		} +	} + +	for (name_stack_t::const_iterator it = non_empty_names.begin(); +		it != non_empty_names.end(); +		++it) +	{ +		if (!attribute_name.empty()) +		{ +			attribute_name += "."; +		} +		attribute_name += it->first; +	} + +	// only flag non-nested attributes as mandatory, nested attributes have variant syntax +	// that can't be properly constrained in XSD +	// e.g. <foo mandatory.value="bar"/> vs <foo><mandatory value="bar"/></foo> +	bool attribute_mandatory = min_count == 1 && max_count == 1 && non_empty_names.size() == 1; + +	// don't bother supporting "Multiple" params as xml attributes +	if (max_count <= 1) +	{ +		// add compound attribute to root node +		addAttributeToSchema(mAttributeNode, attribute_name, type, attribute_mandatory, possible_values); +	} + +	// now generated nested elements for compound attributes +	if (non_empty_names.size() > 1 && !attribute_mandatory) +	{ +		std::string element_name; + +		// traverse all but last element, leaving that as an attribute name +		name_stack_t::const_iterator end_it = non_empty_names.end(); +		end_it--; + +		for (name_stack_t::const_iterator it = non_empty_names.begin(); +			it != end_it; +			++it) +		{ +			if (it != non_empty_names.begin()) +			{ +				element_name += "."; +			} +			element_name += it->first; +		} + +		std::string short_attribute_name = non_empty_names.back().first; + +		LLXMLNodePtr complex_type_node; + +		// find existing element node here, starting at tail of child list +		if (mElementNode->mChildren.notNull()) +		{ +			for(LLXMLNodePtr element = mElementNode->mChildren->tail; +				element.notNull();  +				element = element->mPrev) +			{ +				std::string name; +				if(element->getAttributeString("name", name) && name == element_name) +				{ +					complex_type_node = element->mChildren->head; +					break; +				} +			} +		} +		//create complex_type node +		// +		//<xs:element +        //    maxOccurs="1" +        //    minOccurs="0" +        //    name="name"> +        //       <xs:complexType> +        //       </xs:complexType> +        //</xs:element> +		if(complex_type_node.isNull()) +		{ +			complex_type_node = mElementNode->createChild("xs:element", false); + +			complex_type_node->createChild("minOccurs", true)->setIntValue(min_count); +			complex_type_node->createChild("maxOccurs", true)->setIntValue(max_count); +			complex_type_node->createChild("name",		true)->setStringValue(element_name); +			complex_type_node = complex_type_node->createChild("xs:complexType", false); +		} + +		addAttributeToSchema(complex_type_node, short_attribute_name, type, false, possible_values); +	} +} + +void LLXSDWriter::addAttributeToSchema(LLXMLNodePtr type_declaration_node, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values) +{ +	if (!attribute_name.empty()) +	{ +		LLXMLNodePtr new_enum_type_node; +		if (possible_values != NULL) +		{ +			// custom attribute type, for example +			//<xs:simpleType> +			 // <xs:restriction +			 //    base="xs:string"> +			 //     <xs:enumeration +			 //      value="a" /> +			 //     <xs:enumeration +			 //      value="b" /> +			 //   </xs:restriction> +			 // </xs:simpleType> +			new_enum_type_node = new LLXMLNode("xs:simpleType", false); + +			LLXMLNodePtr restriction_node = new_enum_type_node->createChild("xs:restriction", false); +			restriction_node->createChild("base", true)->setStringValue("xs:string"); + +			for (std::vector<std::string>::const_iterator it = possible_values->begin(); +				it != possible_values->end(); +				++it) +			{ +				LLXMLNodePtr enum_node = restriction_node->createChild("xs:enumeration", false); +				enum_node->createChild("value", true)->setStringValue(*it); +			} +		} + +		string_set_t& attributes_written = mAttributesWritten[type_declaration_node]; + +		string_set_t::iterator found_it = attributes_written.lower_bound(attribute_name); + +		// attribute not yet declared +		if (found_it == attributes_written.end() || attributes_written.key_comp()(attribute_name, *found_it)) +		{ +			attributes_written.insert(found_it, attribute_name); + +			LLXMLNodePtr attribute_node = type_declaration_node->createChild("xs:attribute", false); + +			// attribute name +			attribute_node->createChild("name", true)->setStringValue(attribute_name); + +			if (new_enum_type_node.notNull()) +			{ +				attribute_node->addChild(new_enum_type_node); +			} +			else +			{ +				// simple attribute type +				attribute_node->createChild("type", true)->setStringValue(type); +			} + +			// required or optional +			attribute_node->createChild("use", true)->setStringValue(mandatory ? "required" : "optional"); +		} +		 // attribute exists...handle collision of same name attributes with potentially different types +		else +		{ +			LLXMLNodePtr attribute_declaration; +			if (type_declaration_node.notNull()) +			{ +				for(LLXMLNodePtr node = type_declaration_node->mChildren->tail;  +					node.notNull();  +					node = node->mPrev) +				{ +					std::string name; +					if (node->getAttributeString("name", name) && name == attribute_name) +					{ +						attribute_declaration = node; +						break; +					} +				} +			} + +			bool new_type_is_enum = new_enum_type_node.notNull(); +			bool existing_type_is_enum = !attribute_declaration->hasAttribute("type"); + +			// either type is enum, revert to string in collision +			// don't bother to check for enum equivalence +			if (new_type_is_enum || existing_type_is_enum) +			{ +				if (attribute_declaration->hasAttribute("type")) +				{ +					attribute_declaration->setAttributeString("type", "xs:string"); +				} +				else +				{ +					attribute_declaration->createChild("type", true)->setStringValue("xs:string"); +				} +				attribute_declaration->deleteChildren("xs:simpleType"); +			} +			else  +			{ +				// check for collision of different standard types +				std::string existing_type; +				attribute_declaration->getAttributeString("type", existing_type); +				// if current type is not the same as the new type, revert to strnig +				if (existing_type != type) +				{ +					// ...than use most general type, string +					attribute_declaration->setAttributeString("type", "string"); +				} +			} +		} +	} +} + +// +// LLXUIXSDWriter +// +void LLXUIXSDWriter::writeXSD(const std::string& type_name, const std::string& path, const LLInitParam::BaseBlock& block) +{ +	std::string file_name(path); +	file_name += type_name + ".xsd"; +	LLXMLNodePtr root_nodep = new LLXMLNode(); + +	LLXSDWriter::writeXSD(type_name, root_nodep, block, "http://www.lindenlab.com/xui"); + +	// add includes for all possible children +	const std::type_info* type = *LLWidgetTypeRegistry::instance().getValue(type_name); +	const widget_registry_t* widget_registryp = LLChildRegistryRegistry::instance().getValue(type); + +	// add choices for valid children +	if (widget_registryp) +	{ +		// add include declarations for all valid children +		for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); +		     it != widget_registryp->currentRegistrar().endItems(); +		     ++it) +		{ +			std::string widget_name = it->first; +			if (widget_name == type_name) +			{ +				continue; +			} +			LLXMLNodePtr nodep = new LLXMLNode("xs:include", false); +			nodep->createChild("schemaLocation", true)->setStringValue(widget_name + ".xsd"); +			 +			// add to front of schema +			mSchemaNode->addChild(nodep, mSchemaNode); +		} + +		for (widget_registry_t::Registrar::registry_map_t::const_iterator it = widget_registryp->currentRegistrar().beginItems(); +			it != widget_registryp->currentRegistrar().endItems(); +			++it) +		{ +			std::string widget_name = it->first; +			//<xs:element name="widget_name" type="widget_name"> +			LLXMLNodePtr widget_node = mElementNode->createChild("xs:element", false); +			widget_node->createChild("name", true)->setStringValue(widget_name); +			widget_node->createChild("type", true)->setStringValue(widget_name); +		} +	} + +	LLFILE* xsd_file = LLFile::fopen(file_name.c_str(), "w"); +	LLXMLNode::writeHeaderToFile(xsd_file); +	root_nodep->writeToFile(xsd_file); +	fclose(xsd_file); +} + +static 	LLInitParam::Parser::parser_read_func_map_t sXUIReadFuncs; +static 	LLInitParam::Parser::parser_write_func_map_t sXUIWriteFuncs; +static 	LLInitParam::Parser::parser_inspect_func_map_t sXUIInspectFuncs; + +// +// LLXUIParser +// +LLXUIParser::LLXUIParser() +:	Parser(sXUIReadFuncs, sXUIWriteFuncs, sXUIInspectFuncs), +	mCurReadDepth(0) +{ +	if (sXUIReadFuncs.empty()) +	{ +		registerParserFuncs<LLInitParam::Flag>(readFlag, writeFlag); +		registerParserFuncs<bool>(readBoolValue, writeBoolValue); +		registerParserFuncs<std::string>(readStringValue, writeStringValue); +		registerParserFuncs<U8>(readU8Value, writeU8Value); +		registerParserFuncs<S8>(readS8Value, writeS8Value); +		registerParserFuncs<U16>(readU16Value, writeU16Value); +		registerParserFuncs<S16>(readS16Value, writeS16Value); +		registerParserFuncs<U32>(readU32Value, writeU32Value); +		registerParserFuncs<S32>(readS32Value, writeS32Value); +		registerParserFuncs<F32>(readF32Value, writeF32Value); +		registerParserFuncs<F64>(readF64Value, writeF64Value); +		registerParserFuncs<LLColor4>(readColor4Value, writeColor4Value); +		registerParserFuncs<LLUIColor>(readUIColorValue, writeUIColorValue); +		registerParserFuncs<LLUUID>(readUUIDValue, writeUUIDValue); +		registerParserFuncs<LLSD>(readSDValue, writeSDValue); +	} +} + +static LLFastTimer::DeclareTimer FTM_PARSE_XUI("XUI Parsing"); +const LLXMLNodePtr DUMMY_NODE = new LLXMLNode(); + +void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename, bool silent) +{ +	LLFastTimer timer(FTM_PARSE_XUI); +	mNameStack.clear(); +	mRootNodeName = node->getName()->mString; +	mCurFileName = filename; +	mCurReadDepth = 0; +	setParseSilently(silent); + +	if (node.isNull()) +	{ +		parserWarning("Invalid node"); +	} +	else +	{ +		readXUIImpl(node, block); +	} +} + +bool LLXUIParser::readXUIImpl(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	boost::char_separator<char> sep("."); + +	bool values_parsed = false; +	bool silent = mCurReadDepth > 0; + +	if (nodep->getFirstChild().isNull()  +		&& nodep->mAttributes.empty()  +		&& nodep->getSanitizedValue().empty()) +	{ +		// empty node, just parse as flag +		mCurReadNode = DUMMY_NODE; +		return block.submitValue(mNameStack, *this, silent); +	} + +	// submit attributes for current node +	values_parsed |= readAttributes(nodep, block); + +	// treat text contents of xml node as "value" parameter +	std::string text_contents = nodep->getSanitizedValue(); +	if (!text_contents.empty()) +	{ +		mCurReadNode = nodep; +		mNameStack.push_back(std::make_pair(std::string("value"), true)); +		// child nodes are not necessarily valid parameters (could be a child widget) +		// so don't complain once we've recursed +		if (!block.submitValue(mNameStack, *this, true)) +		{ +			mNameStack.pop_back(); +			block.submitValue(mNameStack, *this, silent); +		} +		else +		{ +			mNameStack.pop_back(); +		} +	} + +	// then traverse children +	// child node must start with last name of parent node (our "scope") +	// for example: "<button><button.param nested_param1="foo"><param.nested_param2 nested_param3="bar"/></button.param></button>" +	// which equates to the following nesting: +	// button +	//     param +	//         nested_param1 +	//         nested_param2 +	//             nested_param3	 +	mCurReadDepth++; +	for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) +	{ +		std::string child_name(childp->getName()->mString); +		S32 num_tokens_pushed = 0; + +		// 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. <button><rect left="10"/></button> will interpret <rect> 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, true)); +			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())  +			{ +				childp = childp->getNextSibling(); +				continue; +			} + +			// check for proper nesting +			if (mNameStack.empty()) +			{ +				if (*name_token_it != mRootNodeName) +				{ +					childp = childp->getNextSibling(); +					continue; +				} +			} +			else if(mNameStack.back().first != *name_token_it) +			{ +				childp = childp->getNextSibling(); +				continue; +			} + +			// 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, true)); +				num_tokens_pushed++; +			} +		} + +		// recurse and visit children XML nodes +		if(readXUIImpl(childp, block)) +		{ +			// child node successfully parsed, remove from DOM + +			values_parsed = true; +			LLXMLNodePtr node_to_remove = childp; +			childp = childp->getNextSibling(); + +			nodep->deleteChild(node_to_remove); +		} +		else +		{ +			childp = childp->getNextSibling(); +		} + +		while(num_tokens_pushed-- > 0) +		{ +			mNameStack.pop_back(); +		} +	} +	mCurReadDepth--; +	return values_parsed; +} + +bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	boost::char_separator<char> sep("."); + +	bool any_parsed = false; +	bool silent = mCurReadDepth > 0; + +	for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin();  +		attribute_it != nodep->mAttributes.end();  +		++attribute_it) +	{ +		S32 num_tokens_pushed = 0; +		std::string attribute_name(attribute_it->first->mString); +		mCurReadNode = attribute_it->second; + +		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, true)); +			num_tokens_pushed++; +		} + +		// child nodes are not necessarily valid attributes, so don't complain once we've recursed +		any_parsed |= block.submitValue(mNameStack, *this, silent); +		 +		while(num_tokens_pushed-- > 0) +		{ +			mNameStack.pop_back(); +		} +	} + +	return any_parsed; +} + +void LLXUIParser::writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::BaseBlock* diff_block) +{ +	mWriteRootNode = node; +	name_stack_t name_stack = Parser::name_stack_t(); +	block.serializeBlock(*this, name_stack, diff_block); +	mOutNodes.clear(); +} + +// go from a stack of names to a specific XML node +LLXMLNodePtr LLXUIParser::getNode(name_stack_t& stack) +{ +	LLXMLNodePtr out_node = mWriteRootNode; + +	name_stack_t::iterator next_it = stack.begin(); +	for (name_stack_t::iterator it = stack.begin(); +		it != stack.end(); +		it = next_it) +	{ +		++next_it; +		if (it->first.empty()) +		{ +			it->second = false; +			continue; +		} + +		out_nodes_t::iterator found_it = mOutNodes.find(it->first); + +		// node with this name not yet written +		if (found_it == mOutNodes.end() || it->second) +		{ +			// make an attribute if we are the last element on the name stack +			bool is_attribute = next_it == stack.end(); +			LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute); +			out_node->addChild(new_node); +			mOutNodes[it->first] = new_node; +			out_node = new_node; +			it->second = false; +		} +		else +		{ +			out_node = found_it->second; +		} +	} + +	return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node); +} + +bool LLXUIParser::readFlag(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode == DUMMY_NODE; +} + +bool LLXUIParser::writeFlag(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	// just create node +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	return node.notNull(); +} + +bool LLXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ +	S32 value; +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	bool success = self.mCurReadNode->getBoolValue(1, &value); +	*((bool*)val_ptr) = (value != FALSE); +	return success; +} + +bool LLXUIParser::writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setBoolValue(*((bool*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	*((std::string*)val_ptr) = self.mCurReadNode->getSanitizedValue(); +	return true; +} + +bool LLXUIParser::writeStringValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		const std::string* string_val = reinterpret_cast<const std::string*>(val_ptr); +		if (string_val->find('\n') != std::string::npos  +			|| string_val->size() > MAX_STRING_ATTRIBUTE_SIZE) +		{ +			// don't write strings with newlines into attributes +			std::string attribute_name = node->getName()->mString; +			LLXMLNodePtr parent_node = node->mParent; +			parent_node->deleteChild(node); +			// write results in text contents of node +			if (attribute_name == "value") +			{ +				// "value" is implicit, just write to parent +				node = parent_node; +			} +			else +			{ +				// create a child that is not an attribute, but with same name +				node = parent_node->createChild(attribute_name.c_str(), false); +			} +		} +		node->setStringValue(*string_val); +		return true; +	} +	return false; +} + +bool LLXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getByteValue(1, (U8*)val_ptr); +} + +bool LLXUIParser::writeU8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setUnsignedValue(*((U8*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	S32 value; +	if(self.mCurReadNode->getIntValue(1, &value)) +	{ +		*((S8*)val_ptr) = value; +		return true; +	} +	return false; +} + +bool LLXUIParser::writeS8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setIntValue(*((S8*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	U32 value; +	if(self.mCurReadNode->getUnsignedValue(1, &value)) +	{ +		*((U16*)val_ptr) = value; +		return true; +	} +	return false; +} + +bool LLXUIParser::writeU16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setUnsignedValue(*((U16*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	S32 value; +	if(self.mCurReadNode->getIntValue(1, &value)) +	{ +		*((S16*)val_ptr) = value; +		return true; +	} +	return false; +} + +bool LLXUIParser::writeS16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setIntValue(*((S16*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); +} + +bool LLXUIParser::writeU32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setUnsignedValue(*((U32*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getIntValue(1, (S32*)val_ptr); +} + +bool LLXUIParser::writeS32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setIntValue(*((S32*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getFloatValue(1, (F32*)val_ptr); +} + +bool LLXUIParser::writeF32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setFloatValue(*((F32*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	return self.mCurReadNode->getDoubleValue(1, (F64*)val_ptr); +} + +bool LLXUIParser::writeF64Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setDoubleValue(*((F64*)val_ptr)); +		return true; +	} +	return false; +} + +bool LLXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLColor4* colorp = (LLColor4*)val_ptr; +	if(self.mCurReadNode->getFloatValue(4, colorp->mV) >= 3) +	{ +		return true; +	} + +	return false; +} + +bool LLXUIParser::writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		LLColor4 color = *((LLColor4*)val_ptr); +		node->setFloatValue(4, color.mV); +		return true; +	} +	return false; +} + +bool LLXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLUIColor* param = (LLUIColor*)val_ptr; +	LLColor4 color; +	bool success =  self.mCurReadNode->getFloatValue(4, color.mV) >= 3; +	if (success) +	{ +		param->set(color); +		return true; +	} +	return false; +} + +bool LLXUIParser::writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		LLUIColor color = *((LLUIColor*)val_ptr); +		//RN: don't write out the color that is represented by a function +		// rely on param block exporting to get the reference to the color settings +		if (color.isReference()) return false; +		node->setFloatValue(4, color.get().mV); +		return true; +	} +	return false; +} + +bool LLXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLUUID temp_id; +	// LLUUID::set is destructive, so use temporary value +	if (temp_id.set(self.mCurReadNode->getSanitizedValue())) +	{ +		*(LLUUID*)(val_ptr) = temp_id; +		return true; +	} +	return false; +} + +bool LLXUIParser::writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		node->setStringValue(((LLUUID*)val_ptr)->asString()); +		return true; +	} +	return false; +} + +bool LLXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); +	*((LLSD*)val_ptr) = LLSD(self.mCurReadNode->getSanitizedValue()); +	return true; +} + +bool LLXUIParser::writeSDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ +	LLXUIParser& self = static_cast<LLXUIParser&>(parser); + +	LLXMLNodePtr node = self.getNode(stack); +	if (node.notNull()) +	{ +		std::string string_val = ((LLSD*)val_ptr)->asString(); +		if (string_val.find('\n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE) +		{ +			// don't write strings with newlines into attributes +			std::string attribute_name = node->getName()->mString; +			LLXMLNodePtr parent_node = node->mParent; +			parent_node->deleteChild(node); +			// write results in text contents of node +			if (attribute_name == "value") +			{ +				// "value" is implicit, just write to parent +				node = parent_node; +			} +			else +			{ +				node = parent_node->createChild(attribute_name.c_str(), false); +			} +		} + +		node->setStringValue(string_val); +		return true; +	} +	return false; +} + +/*virtual*/ std::string LLXUIParser::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; +} + +void LLXUIParser::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(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); +	utf16str += '\n'; +	OutputDebugString(utf16str.c_str()); +#else +	Parser::parserWarning(message); +#endif +} + +void LLXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS +	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); +	utf16str += '\n'; +	OutputDebugString(utf16str.c_str()); +#else +	Parser::parserError(message); +#endif +} + + +// +// LLSimpleXUIParser +// + +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; +}; +LLSimpleXUIParser::LLSimpleXUIParser(LLSimpleXUIParser::element_start_callback_t element_cb) +:	Parser(sSimpleXUIReadFuncs, sSimpleXUIWriteFuncs, sSimpleXUIInspectFuncs), +	mCurReadDepth(0), +	mElementCB(element_cb) +{ +	if (sSimpleXUIReadFuncs.empty()) +	{ +		registerParserFuncs<LLInitParam::Flag>(readFlag); +		registerParserFuncs<bool>(readBoolValue); +		registerParserFuncs<std::string>(readStringValue); +		registerParserFuncs<U8>(readU8Value); +		registerParserFuncs<S8>(readS8Value); +		registerParserFuncs<U16>(readU16Value); +		registerParserFuncs<S16>(readS16Value); +		registerParserFuncs<U32>(readU32Value); +		registerParserFuncs<S32>(readS32Value); +		registerParserFuncs<F32>(readF32Value); +		registerParserFuncs<F64>(readF64Value); +		registerParserFuncs<LLColor4>(readColor4Value); +		registerParserFuncs<LLUIColor>(readUIColorValue); +		registerParserFuncs<LLUUID>(readUUIDValue); +		registerParserFuncs<LLSD>(readSDValue); +	} +} + +LLSimpleXUIParser::~LLSimpleXUIParser() +{ +} + + +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); + +	mOutputStack.push_back(std::make_pair(&block, 0)); +	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; +		XML_ParserFree( mParser ); +		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; +	} +	 +	mEmptyLeafNode.push_back(false); + +	if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) ) +	{ +		LL_WARNS("ReadXUI") << "Error while parsing file  " << filename << LL_ENDL; +		XML_ParserFree( mParser ); +		return false; +	} + +	mEmptyLeafNode.pop_back(); + +	XML_ParserFree( mParser ); +	return true; +} + +void LLSimpleXUIParser::startElementHandler(void *userData, const char *name, const char **atts) +{ +	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); +	self->startElement(name, atts); +} + +void LLSimpleXUIParser::endElementHandler(void *userData, const char *name) +{ +	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); +	self->endElement(name); +} + +void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int len) +{ +	LLSimpleXUIParser* self = reinterpret_cast<LLSimpleXUIParser*>(userData); +	self->characterData(s, len); +} + +void LLSimpleXUIParser::characterData(const char *s, int len) +{ +	mTextContents += std::string(s, len); +} + +void LLSimpleXUIParser::startElement(const char *name, const char **atts) +{ +	processText(); + +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	boost::char_separator<char> sep("."); + +	if (mElementCB)  +	{ +		LLInitParam::BaseBlock* blockp = mElementCB(*this, name); +		if (blockp) +		{ +			mOutputStack.push_back(std::make_pair(blockp, 0)); +		} +	} + +	mOutputStack.back().second++; +	S32 num_tokens_pushed = 0; +	std::string child_name(name); + +	if (mOutputStack.back().second == 1) +	{	// root node for this block +		mScope.push_back(child_name); +	} +	else +	{	// compound attribute +		if (child_name.find(".") == std::string::npos)  +		{ +			mNameStack.push_back(std::make_pair(child_name, true)); +			num_tokens_pushed++; +			mScope.push_back(child_name); +		} +		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, true)); +				num_tokens_pushed++; +			} +			mScope.push_back(mNameStack.back().first); +		} +	} + +	// parent node is not empty +	mEmptyLeafNode.back() = false; +	// we are empty if we have no attributes +	mEmptyLeafNode.push_back(atts[0] == NULL); + +	mTokenSizeStack.push_back(num_tokens_pushed); +	readAttributes(atts); + +} + +void LLSimpleXUIParser::endElement(const char *name) +{ +	bool has_text = processText(); + +	// no text, attributes, or children +	if (!has_text && mEmptyLeafNode.back()) +	{ +		// submit this as a valueless name (even though there might be text contents we haven't seen yet) +		mCurAttributeValueBegin = NO_VALUE_MARKER; +		mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); +	} + +	if (--mOutputStack.back().second == 0) +	{ +		if (mOutputStack.empty()) +		{ +			LL_ERRS("ReadXUI") << "Parameter block output stack popped while empty." << LL_ENDL; +		} +		mOutputStack.pop_back(); +	} + +	S32 num_tokens_to_pop = mTokenSizeStack.back(); +	mTokenSizeStack.pop_back(); +	while(num_tokens_to_pop-- > 0) +	{ +		mNameStack.pop_back(); +	} +	mScope.pop_back(); +	mEmptyLeafNode.pop_back(); +} + +bool LLSimpleXUIParser::readAttributes(const char **atts) +{ +	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +	boost::char_separator<char> 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, true)); +			num_tokens_pushed++; +		} + +		// child nodes are not necessarily valid attributes, so don't complain once we've recursed +		any_parsed |= mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); +		 +		while(num_tokens_pushed-- > 0) +		{ +			mNameStack.pop_back(); +		} +	} +	return any_parsed; +} + +bool LLSimpleXUIParser::processText() +{ +	if (!mTextContents.empty()) +	{ +		LLStringUtil::trim(mTextContents); +		if (!mTextContents.empty()) +		{ +			mNameStack.push_back(std::make_pair(std::string("value"), true)); +			mCurAttributeValueBegin = mTextContents.c_str(); +			mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); +			mNameStack.pop_back(); +		} +		mTextContents.clear(); +		return true; +	} +	return false; +} + +/*virtual*/ std::string LLSimpleXUIParser::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; +} + +void LLSimpleXUIParser::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 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()); +	utf16str += '\n'; +	OutputDebugString(utf16str.c_str()); +#else +	Parser::parserError(message); +#endif +} + +bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return self.mCurAttributeValueBegin == NO_VALUE_MARKER; +} + +bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(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 LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	*((std::string*)val_ptr) = self.mCurAttributeValueBegin; +	return true; +} + +bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; +} +	 +bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(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 LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(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 LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	LLUUID temp_id; +	// LLUUID::set is destructive, so use temporary value +	if (temp_id.set(std::string(self.mCurAttributeValueBegin))) +	{ +		*(LLUUID*)(val_ptr) = temp_id; +		return true; +	} +	return false; +} + +bool LLSimpleXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ +	LLSimpleXUIParser& self = static_cast<LLSimpleXUIParser&>(parser); +	*((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); +	return true; +} diff --git a/indra/llui/llxuiparser.h b/indra/llui/llxuiparser.h new file mode 100644 index 0000000000..d7cd256967 --- /dev/null +++ b/indra/llui/llxuiparser.h @@ -0,0 +1,242 @@ +/**  + * @file llxuiparser.h + * @brief Utility functions for handling XUI structures in XML + * + * $LicenseInfo:firstyear=2003&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$ + */ + +#ifndef LLXUIPARSER_H +#define LLXUIPARSER_H + +#include "llinitparam.h" +#include "llregistry.h" +#include "llpointer.h" + +#include <boost/function.hpp> +#include <iosfwd> +#include <stack> +#include <set> + + + +class LLView; + + +typedef LLPointer<class LLXMLNode> LLXMLNodePtr; + + +// lookup widget type by name +class LLWidgetTypeRegistry +:	public LLRegistrySingleton<std::string, const std::type_info*, LLWidgetTypeRegistry> +{}; + + +// global static instance for registering all widget types +typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc; + +typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t; + +class LLChildRegistryRegistry +: public LLRegistrySingleton<const std::type_info*, widget_registry_t, LLChildRegistryRegistry> +{}; + + + +class LLXSDWriter : public LLInitParam::Parser +{ +	LOG_CLASS(LLXSDWriter); +public: +	void writeXSD(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); + +	/*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } + +	LLXSDWriter(); + +protected: +	void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector<std::string>* possible_values); +	void addAttributeToSchema(LLXMLNodePtr nodep, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector<std::string>* possible_values); +	LLXMLNodePtr mAttributeNode; +	LLXMLNodePtr mElementNode; +	LLXMLNodePtr mSchemaNode; + +	typedef std::set<std::string> string_set_t; +	typedef std::map<LLXMLNodePtr, string_set_t> attributes_map_t; +	attributes_map_t	mAttributesWritten; +}; + + + +// NOTE: DOES NOT WORK YET +// should support child widgets for XUI +class LLXUIXSDWriter : public LLXSDWriter +{ +public: +	void writeXSD(const std::string& name, const std::string& path, const LLInitParam::BaseBlock& block); +}; + + +class LLXUIParserImpl; + +class LLXUIParser : public LLInitParam::Parser +{ +LOG_CLASS(LLXUIParser); + +public: +	LLXUIParser(); +	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); + +	void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename = LLStringUtil::null, bool silent=false); +	void writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const LLInitParam::BaseBlock* diff_block = NULL); + +private: +	bool readXUIImpl(LLXMLNodePtr node, LLInitParam::BaseBlock& block); +	bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); + +	//reader helper functions +	static bool readFlag(Parser& parser, 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 +	static bool writeFlag(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeStringValue(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeU8Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeS8Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeU16Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeS16Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeU32Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeS32Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeF32Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeF64Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t&); +	static bool writeSDValue(Parser& parser, const void* val_ptr, name_stack_t&); + +	LLXMLNodePtr getNode(name_stack_t& stack); + +private: +	Parser::name_stack_t			mNameStack; +	LLXMLNodePtr					mCurReadNode; +	// Root of the widget XML sub-tree, for example, "line_editor" +	LLXMLNodePtr					mWriteRootNode; +	 +	typedef std::map<std::string, LLXMLNodePtr>	out_nodes_t; +	out_nodes_t						mOutNodes; +	LLXMLNodePtr					mLastWrittenChild; +	S32								mCurReadDepth; +	std::string						mCurFileName; +	std::string						mRootNodeName; +}; + +// 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 LLSimpleXUIParserImpl; + +class LLSimpleXUIParser : public LLInitParam::Parser +{ +LOG_CLASS(LLSimpleXUIParser); +public: +	typedef LLInitParam::Parser::name_stack_t name_stack_t; +	typedef LLInitParam::BaseBlock* (*element_start_callback_t)(LLSimpleXUIParser&, const char* block_name); + +	LLSimpleXUIParser(element_start_callback_t element_cb = NULL); +	virtual ~LLSimpleXUIParser(); + +	/*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 readFlag(Parser&, void* val_ptr); +	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); +	bool processText(); + +	Parser::name_stack_t			mNameStack; +	struct XML_ParserStruct*		mParser; +	LLXMLNodePtr					mLastWrittenChild; +	S32								mCurReadDepth; +	std::string						mCurFileName; +	std::string						mTextContents; +	const char*						mCurAttributeValueBegin; +	std::vector<S32>				mTokenSizeStack; +	std::vector<std::string>		mScope; +	std::vector<bool>				mEmptyLeafNode; +	element_start_callback_t		mElementCB; + +	std::vector<std::pair<LLInitParam::BaseBlock*, S32> > mOutputStack; +}; + + +#endif //LLXUIPARSER_H diff --git a/indra/llui/tests/llurlentry_stub.cpp b/indra/llui/tests/llurlentry_stub.cpp index c75df86891..cb3b7abb14 100644 --- a/indra/llui/tests/llurlentry_stub.cpp +++ b/indra/llui/tests/llurlentry_stub.cpp @@ -105,28 +105,6 @@ LLStyle::Params::Params()  namespace LLInitParam  { -	Param::Param(BaseBlock* enclosing_block) -	:	mIsProvided(false) -	{ -		const U8* my_addr = reinterpret_cast<const U8*>(this); -		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); -		mEnclosingBlockOffset = (U16)(my_addr - block_addr); -	} - -	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){} -	void BaseBlock::addSynonym(Param& param, const std::string& synonym) {} -	param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;} -	 -	void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) -	{ -		descriptor.mCurrentBlockPtr = this; -	} -	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name){ return true; } -	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const {} -	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_value, S32 max_value) const { return true; } -	bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; } -	bool BaseBlock::validateBlock(bool emit_errors) const { return true; } -  	ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)  	:	super_t(color)  	{} diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index c1fb050206..8f0a48018f 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -70,21 +70,6 @@ S32 LLUIImage::getHeight() const  	return 0;  } -namespace LLInitParam -{ -	BlockDescriptor::BlockDescriptor() {} -	ParamDescriptor::ParamDescriptor(param_handle_t p,  -						merge_func_t merge_func,  -						deserialize_func_t deserialize_func,  -						serialize_func_t serialize_func, -						validation_func_t validation_func, -						inspect_func_t inspect_func, -						S32 min_count, -						S32 max_count){} -	ParamDescriptor::~ParamDescriptor() {} - -} -  namespace tut  {  	struct LLUrlEntryData diff --git a/indra/llui/tests/llurlmatch_test.cpp b/indra/llui/tests/llurlmatch_test.cpp index 7183413463..963473c92a 100644 --- a/indra/llui/tests/llurlmatch_test.cpp +++ b/indra/llui/tests/llurlmatch_test.cpp @@ -63,40 +63,6 @@ S32 LLUIImage::getHeight() const  namespace LLInitParam  { -	BlockDescriptor::BlockDescriptor() {} -	ParamDescriptor::ParamDescriptor(param_handle_t p,  -						merge_func_t merge_func,  -						deserialize_func_t deserialize_func,  -						serialize_func_t serialize_func, -						validation_func_t validation_func, -						inspect_func_t inspect_func, -						S32 min_count, -						S32 max_count){} -	ParamDescriptor::~ParamDescriptor() {} - -	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name){} -	param_handle_t BaseBlock::getHandleFromParam(const Param* param) const {return 0;} -	void BaseBlock::addSynonym(Param& param, const std::string& synonym) {} - -	void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) -	{ -		descriptor.mCurrentBlockPtr = this; -	} - -	Param::Param(BaseBlock* enclosing_block) -	:	mIsProvided(false) -	{ -		const U8* my_addr = reinterpret_cast<const U8*>(this); -		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); -		mEnclosingBlockOffset = 0x7FFFffff & ((U32)(my_addr - block_addr)); -	} - -	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name){ return true; } -	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const {} -	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const { return true; } -	bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) { return true; } -	bool BaseBlock::validateBlock(bool emit_errors) const { return true; } -  	ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)  	:	super_t(color)  	{} | 
