From 7e6e3d20f334547d8cea78e8e0b37106efebe028 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 8 Nov 2011 13:48:38 -0800
Subject: added Lazy modifier to params to support recursion ChoiceBlock can
 now derive from another param block Params with name/value support can be
 assigned directly in C++ code using param = "named_value"

---
 indra/llxuixml/llinitparam.h   | 426 +++++++++++++++++++++++++++++++----------
 indra/llxuixml/llxuiparser.cpp | 258 +++++++++++++++++++------
 2 files changed, 524 insertions(+), 160 deletions(-)

(limited to 'indra')

diff --git a/indra/llxuixml/llinitparam.h b/indra/llxuixml/llinitparam.h
index 183472450d..169a724bca 100644
--- a/indra/llxuixml/llinitparam.h
+++ b/indra/llxuixml/llinitparam.h
@@ -51,7 +51,7 @@ namespace LLInitParam
 			return a == b;
 		}
     };
-    
+
 	// boost function types are not comparable
 	template<typename T>
 	struct ParamCompare<T, true>
@@ -74,6 +74,7 @@ namespace LLInitParam
 		static bool equals(const Flag& a, const Flag& b) { return false; }
 	};
 
+
 	// helper functions and classes
 	typedef ptrdiff_t param_handle_t;
 
@@ -82,8 +83,11 @@ namespace LLInitParam
 	template <typename T>
 	class TypeValues
 	{
+	private:
+		struct Inaccessable{};
 	public:
 		typedef std::map<std::string, T> value_name_map_t;
+		typedef Inaccessable name_t;
 
 		void setValueName(const std::string& key) {}
 		std::string getValueName() const { return ""; }
@@ -113,6 +117,7 @@ namespace LLInitParam
 	{
 	public:
 		typedef typename std::map<std::string, T> value_name_map_t;
+		typedef std::string name_t;
 
 		//TODO: cache key by index to save on param block size
 		void setValueName(const std::string& value_name) 
@@ -293,36 +298,7 @@ namespace LLInitParam
 		parser_inspect_func_map_t*	mParserInspectFuncs;
 	};
 
-	class BaseBlock;
-
-	class Param
-	{
-	public:
-		// public to allow choice blocks to clear provided flag on stale choices
-		void setProvided(bool is_provided) { mIsProvided = is_provided; }
-
-	protected:
-		bool anyProvided() const { return mIsProvided; }
-
-		Param(BaseBlock* enclosing_block);
-
-		// store pointer to enclosing block as offset to reduce space and allow for quick copying
-		BaseBlock& enclosingBlock() const
-		{ 
-			const U8* my_addr = reinterpret_cast<const U8*>(this);
-			// get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class
-			return *const_cast<BaseBlock*>
-				(reinterpret_cast<const BaseBlock*>
-					(my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset));
-		}
-
-	private:
-		friend class BaseBlock;
-
-		U32		mEnclosingBlockOffset:31;
-		U32		mIsProvided:1;
-
-	};
+	class Param;
 
 	// various callbacks and constraints associated with an individual param
 	struct ParamDescriptor
@@ -390,12 +366,91 @@ namespace LLInitParam
 		all_params_list_t				mAllParams;				// all parameters, owns descriptors
 		size_t							mMaxParamOffset;
 		EInitializationState			mInitializationState;	// whether or not static block data has been initialized
-		BaseBlock*						mCurrentBlockPtr;		// pointer to block currently being constructed
+		class BaseBlock*				mCurrentBlockPtr;		// pointer to block currently being constructed
 	};
 
 	class BaseBlock
 	{
 	public:
+		//TODO: implement in terms of owned_ptr
+		template<typename T>
+		class Lazy
+		{
+		public:
+			Lazy()
+				: mPtr(NULL)
+			{}
+
+			~Lazy()
+			{
+				delete mPtr;
+			}
+
+			Lazy(const Lazy& other)
+			{
+				if (other.mPtr)
+				{
+					mPtr = new T(*other.mPtr);
+				}
+				else
+				{
+					mPtr = NULL;
+				}
+			}
+
+			Lazy<T>& operator = (const Lazy<T>& other)
+			{
+				if (other.mPtr)
+				{
+					mPtr = new T(*other.mPtr);
+				}
+				else
+				{
+					mPtr = NULL;
+				}
+				return *this;
+			}
+
+			bool empty() const
+			{
+				return mPtr == NULL;
+			}
+
+			void set(const T& other)
+			{
+				delete mPtr;
+				mPtr = new T(other);
+			}
+
+			const T& get() const
+			{
+				return ensureInstance();
+			}
+
+			T& get()
+			{
+				return ensureInstance();
+			}
+
+		private:
+			// lazily allocate an instance of T
+			T* ensureInstance() const
+			{
+				if (mPtr == NULL)
+				{
+					mPtr = new T();
+				}
+				return mPtr;
+			}
+
+		private:
+			// if you get a compilation error with this, that means you are using a forward declared struct for T
+			// unfortunately, the type traits we rely on don't work with forward declared typed
+			//static const int dummy = sizeof(T);
+
+			mutable T* mPtr;
+		};
+
 		// "Multiple" constraint types, put here in root class to avoid ambiguity during use
 		struct AnyAmount
 		{
@@ -511,6 +566,44 @@ namespace LLInitParam
 		const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
 	};
 
+	template<typename T>
+	struct ParamCompare<BaseBlock::Lazy<T>, false >
+	{
+		static bool equals(const BaseBlock::Lazy<T>& a, const BaseBlock::Lazy<T>& b) { return !a.empty() || !b.empty(); }
+	};
+
+		class Param
+	{
+	public:
+		void setProvided(bool is_provided = true)
+		{
+			mIsProvided = is_provided;
+			enclosingBlock().paramChanged(*this, is_provided);
+		}
+	protected:
+
+		bool anyProvided() const { return mIsProvided; }
+
+		Param(BaseBlock* enclosing_block);
+
+		// store pointer to enclosing block as offset to reduce space and allow for quick copying
+		BaseBlock& enclosingBlock() const
+		{ 
+			const U8* my_addr = reinterpret_cast<const U8*>(this);
+			// get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class
+			return *const_cast<BaseBlock*>
+				(reinterpret_cast<const BaseBlock*>
+					(my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset));
+		}
+
+	private:
+		friend class BaseBlock;
+
+		U32		mEnclosingBlockOffset:31;
+		U32		mIsProvided:1;
+
+	};
+
 	// these templates allow us to distinguish between template parameters
 	// that derive from BaseBlock and those that don't
 	template<typename T, typename Void = void>
@@ -530,6 +623,7 @@ namespace LLInitParam
 	{
 	public:
 		typedef const T&							value_assignment_t;
+		typedef ParamValue<T, NAME_VALUE_LOOKUP, VALUE_IS_BLOCK>	self_t;
 
 		ParamValue(): mValue() {}
 		ParamValue(value_assignment_t other) : mValue(other) {}
@@ -559,6 +653,25 @@ namespace LLInitParam
 			return mValue;
 		}
 
+		void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name)
+		{
+			*this = name;
+		}
+
+		self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
+		{
+			if (NAME_VALUE_LOOKUP::getValueFromName(name, mValue))
+			{
+				setValueName(name);
+			}
+
+			return *this;
+		}
+
+		self_t& operator =(const self_t& other)
+		{
+			mValue = other.mValue;
+		}
 
 	private:
 		T mValue;
@@ -571,17 +684,16 @@ namespace LLInitParam
 	{
 	public:
 		typedef const T&							value_assignment_t;
+		typedef ParamValue<T, NAME_VALUE_LOOKUP, true>	self_t;
 
 		ParamValue() 
 		:	T(),
-			mKeyVersion(0),
 			mValidatedVersion(-1),
 			mValidated(false)
 		{}
 
 		ParamValue(value_assignment_t other)
 		:	T(other),
-			mKeyVersion(0),
 			mValidatedVersion(-1),
 			mValidated(false)
 		{}
@@ -611,8 +723,25 @@ namespace LLInitParam
 			return *this;
 		}
 
-		S32 			mKeyVersion;
+		void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name)
+		{
+			*this = name;
+		}
 
+		self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
+		{
+			if (NAME_VALUE_LOOKUP::getValueFromName(name, mValue))
+			{
+				setValueName(name);
+			}
+
+			return *this;
+		}
+
+		self_t& operator =(const self_t& other)
+		{
+			*(static_cast<T*>(this)) = other;
+		}
 	protected:
 		mutable S32 	mValidatedVersion;
 		mutable bool 	mValidated; // lazy validation flag
@@ -671,8 +800,7 @@ namespace LLInitParam
 				if (parser.readValue(typed_param.getValue()))
 				{
 					typed_param.clearValueName();
-					typed_param.setProvided(true);
-					typed_param.enclosingBlock().paramChanged(param, true);
+					typed_param.setProvided();
 					return true;
 				}
 				
@@ -687,8 +815,7 @@ namespace LLInitParam
 						if (name_value_lookup_t::getValueFromName(name, typed_param.getValue()))
 						{
 							typed_param.setValueName(name);
-							typed_param.setProvided(true);
-							typed_param.enclosingBlock().paramChanged(param, true);
+							typed_param.setProvided();
 							return true;
 						}
 
@@ -744,12 +871,22 @@ namespace LLInitParam
 			}
 		}
 
+		self_t& operator =(typename const name_value_lookup_t::name_t& name)
+		{
+			if (name_value_lookup_t::getValueFromName(name, getValue()))
+			{
+				setValueName(name);
+				setProvided();
+			}
+
+			return *this;
+		}
+
 		void set(value_assignment_t val, bool flag_as_provided = true)
 		{
 			setValue(val);
 			param_value_t::clearValueName();
 			setProvided(flag_as_provided);
-			Param::enclosingBlock().paramChanged(*this, flag_as_provided);
 		}
 
 	protected:
@@ -808,8 +945,7 @@ namespace LLInitParam
 			if(typed_param.deserializeBlock(parser, name_stack_range, new_name))
 			{
 				typed_param.clearValueName();
-				typed_param.enclosingBlock().paramChanged(param, true);
-				typed_param.setProvided(true);
+				typed_param.setProvided();
 				return true;
 			}
 
@@ -822,10 +958,8 @@ namespace LLInitParam
 					// try to parse a per type named value
 					if (name_value_lookup_t::getValueFromName(name, typed_param.getValue()))
 					{
-						typed_param.enclosingBlock().paramChanged(param, true);
 						typed_param.setValueName(name);
-						typed_param.setProvided(true);
-						typed_param.mKeyVersion = typed_param.getLastChangeVersion();
+						typed_param.setProvided();
 						return true;
 					}
 
@@ -845,7 +979,7 @@ namespace LLInitParam
 			}
 
 			std::string key = typed_param.getValueName();
-			if (!key.empty() && typed_param.mKeyVersion == typed_param.getLastChangeVersion())
+			if (!key.empty())
 			{
 				if (!parser.writeValue(key, name_stack))
 				{
@@ -888,19 +1022,33 @@ namespace LLInitParam
 			// next call to isProvided() will update provision status based on validity
 			param_value_t::mValidatedVersion = -1;
 			setProvided(flag_as_provided);
-			Param::enclosingBlock().paramChanged(*this, flag_as_provided);
+		}
+
+		self_t& operator =(typename const name_value_lookup_t::name_t& name)
+		{
+			if (name_value_lookup_t::getValueFromName(name, getValue()))
+			{
+				setValueName(name);
+				setProvided();
+			}
+
+			return *this;
 		}
 
 		// propagate changed status up to enclosing block
 		/*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
 		{ 
 			param_value_t::paramChanged(changed_param, user_provided);
-			Param::enclosingBlock().paramChanged(*this, user_provided);
 			if (user_provided)
 			{
 				// a child param has been explicitly changed
 				// so *some* aspect of this block is now provided
-				setProvided(true);
+				setProvided();
+				param_value_t::clearValueName();
+			}
+			else
+			{
+				Param::enclosingBlock().paramChanged(*this, user_provided);
 			}
 		}
 
@@ -917,7 +1065,6 @@ namespace LLInitParam
 				{
 					dst_typed_param.clearValueName();
 					dst_typed_param.setProvided(true);
-					dst_typed_param.enclosingBlock().paramChanged(dst_typed_param, true);
 					return true;
 				}
 			}
@@ -1004,7 +1151,7 @@ namespace LLInitParam
 				it != end_it;
 				++it)
 			{
-				std::string key = it->getValue();
+				std::string key = it->getValueName();
 				name_stack.back().second = true;
 
 				if(key.empty())
@@ -1013,7 +1160,7 @@ namespace LLInitParam
 					bool value_written = parser.writeValue(*it, name_stack);
 					if (!value_written)
 					{
-						std::string calculated_key = it->calcValueName(key);
+						std::string calculated_key = it->calcValueName(it->getValue());
 						if (!parser.writeValue(calculated_key, name_stack))
 						{
 							break;
@@ -1043,22 +1190,31 @@ namespace LLInitParam
 		{
 			mValues = val;
 			setProvided(flag_as_provided);
-			Param::enclosingBlock().paramChanged(*this, flag_as_provided);
 		}
 
-		value_t& add()
+		param_value_t& add()
 		{
 			mValues.push_back(param_value_t(value_t()));
-			setProvided(true);
-			Param::enclosingBlock().paramChanged(*this, true);
+			Param::setProvided();
 			return mValues.back();
 		}
 
 		void add(const value_t& item)
 		{
 			mValues.push_back(param_value_t(item));
-			setProvided(true);
-			Param::enclosingBlock().paramChanged(*this, true);
+			setProvided();
+		}
+
+		void add(typename const name_value_lookup_t::name_t& name)
+		{
+			value_t value;
+
+			// try to parse a per type named value
+			if (name_value_lookup_t::getValueFromName(name, value))
+			{
+				add(value);
+				mValues.back().setValueName(name);
+			}
 		}
 
 		// implicit conversion
@@ -1099,8 +1255,7 @@ namespace LLInitParam
 
 			if (src_typed_param.begin() != src_typed_param.end())
 			{
-				dst_typed_param.setProvided(true);
-				dst_typed_param.enclosingBlock().paramChanged(dst_typed_param, true);
+				dst_typed_param.setProvided();
 			}
 			return true;
 		}
@@ -1116,7 +1271,7 @@ namespace LLInitParam
 	public:
 		typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true>	self_t;
 		typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP>				param_value_t;
-		typedef typename std::vector<param_value_t>				container_t;
+		typedef typename std::vector<param_value_t>						container_t;
 		typedef const container_t&										value_assignment_t;
 		typedef VALUE_TYPE												value_t;
 		typedef NAME_VALUE_LOOKUP										name_value_lookup_t;
@@ -1158,8 +1313,7 @@ namespace LLInitParam
 			// attempt to parse block...
 			if(value.deserializeBlock(parser, name_stack_range, new_name))
 			{
-				typed_param.enclosingBlock().paramChanged(param, true);
-				typed_param.setProvided(true);
+				typed_param.setProvided();
 				return true;
 			}
 			else if(name_value_lookup_t::valueNamesExist())
@@ -1172,9 +1326,7 @@ namespace LLInitParam
 					if (name_value_lookup_t::getValueFromName(name, value.getValue()))
 					{
 						typed_param.mValues.back().setValueName(name);
-						typed_param.mValues.back().mKeyVersion = value.getLastChangeVersion();
-						typed_param.enclosingBlock().paramChanged(param, true);
-						typed_param.setProvided(true);
+						typed_param.setProvided();
 						return true;
 					}
 
@@ -1201,7 +1353,7 @@ namespace LLInitParam
 				name_stack.back().second = true;
 
 				std::string key = it->getValueName();
-				if (!key.empty() && it->mKeyVersion == it->getLastChangeVersion())
+				if (!key.empty())
 				{
 					parser.writeValue(key, name_stack);
 				}
@@ -1224,22 +1376,31 @@ namespace LLInitParam
 		{
 			mValues = val;
 			setProvided(flag_as_provided);
-			Param::enclosingBlock().paramChanged(*this, flag_as_provided);
 		}
 
-		value_t& add()
+		param_value_t& add()
 		{
 			mValues.push_back(value_t());
-			setProvided(true);
-			Param::enclosingBlock().paramChanged(*this, true);
+			setProvided();
 			return mValues.back();
 		}
 
 		void add(const value_t& item)
 		{
 			mValues.push_back(item);
-			setProvided(true);
-			Param::enclosingBlock().paramChanged(*this, true);
+			setProvided();
+		}
+
+		void add(typename const name_value_lookup_t::name_t& name)
+		{
+			value_t value;
+
+			// try to parse a per type named value
+			if (name_value_lookup_t::getValueFromName(name, value))
+			{
+				add(value);
+				mValues.back().setValueName(name);
+			}
 		}
 
 		// implicit conversion
@@ -1288,8 +1449,7 @@ namespace LLInitParam
 
 			if (src_typed_param.begin() != src_typed_param.end())
 			{
-				dst_typed_param.setProvided(true);
-				dst_typed_param.enclosingBlock().paramChanged(dst_typed_param, true);
+				dst_typed_param.setProvided();
 			}
 
 			return true;
@@ -1298,24 +1458,25 @@ namespace LLInitParam
 		container_t			mValues;
 	};
 
-	template <typename DERIVED_BLOCK>
-	class ChoiceBlock : public BaseBlock
+	template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
+	class ChoiceBlock : public BASE_BLOCK
 	{
-		typedef ChoiceBlock<DERIVED_BLOCK>	self_t;
-		typedef ChoiceBlock<DERIVED_BLOCK>	enclosing_block_t;
+		typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK>	self_t;
+		typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK>	enclosing_block_t;
+		typedef BASE_BLOCK								base_block_t;
 		
 		LOG_CLASS(self_t);
 	public:
 		// take all provided params from other and apply to self
 		bool overwriteFrom(const self_t& other)
 		{
-			return mergeBlock(selfBlockDescriptor(), other, true);
+			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, true);
 		}
 
 		// take all provided params that are not already provided, and apply to self
 		bool fillFrom(const self_t& other)
 		{
-			return mergeBlock(selfBlockDescriptor(), other, false);
+			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, false);
 		}
 
 		bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)
@@ -1333,25 +1494,25 @@ namespace LLInitParam
 		bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite)
 		{
 			mCurChoice = other.mCurChoice;
-			return BaseBlock::mergeBlock(selfBlockDescriptor(), other, overwrite);
+			return base_block_t::mergeBlock(selfBlockDescriptor(), other, overwrite);
 		}
 
 		// clear out old choice when param has changed
 		/*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
 		{ 
-			param_handle_t changed_param_handle = BaseBlock::getHandleFromParam(&changed_param);
+			param_handle_t changed_param_handle = base_block_t::getHandleFromParam(&changed_param);
 			// if we have a new choice...
 			if (changed_param_handle != mCurChoice)
 			{
 				// clear provided flag on previous choice
-				Param* previous_choice = BaseBlock::getParamFromHandle(mCurChoice);
+				Param* previous_choice = base_block_t::getParamFromHandle(mCurChoice);
 				if (previous_choice) 
 				{
 					previous_choice->setProvided(false);
 				}
 				mCurChoice = changed_param_handle;
 			}
-			BaseBlock::paramChanged(changed_param, user_provided);
+			base_block_t::paramChanged(changed_param, user_provided);
 		}
 
 		virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
@@ -1361,7 +1522,7 @@ namespace LLInitParam
 		ChoiceBlock()
 		:	mCurChoice(0)
 		{
-			BaseBlock::init(selfBlockDescriptor(), BaseBlock::selfBlockDescriptor(), sizeof(DERIVED_BLOCK));
+			BaseBlock::init(selfBlockDescriptor(), base_block_t::selfBlockDescriptor(), sizeof(DERIVED_BLOCK));
 		}
 
 		// Alternatives are mutually exclusive wrt other Alternatives in the same block.  
@@ -1447,7 +1608,7 @@ namespace LLInitParam
 
 		const Param* getCurrentChoice() const
 		{
-			return BaseBlock::getParamFromHandle(mCurChoice);
+			return base_block_t::getParamFromHandle(mCurChoice);
 		}
 	};
 
@@ -1493,6 +1654,9 @@ namespace LLInitParam
 			typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value>		super_t;
 			typedef typename super_t::value_assignment_t								value_assignment_t;
 
+			using super_t::operator();
+			using super_t::operator=;
+
 			explicit Optional(const char* name = "", value_assignment_t val = defaultValue<T>())
 			:	super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1)
 			{
@@ -1510,7 +1674,6 @@ namespace LLInitParam
 				super_t::set(val);
 				return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
 			}
-			using super_t::operator();
 		};
 
 		template <typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
@@ -1521,6 +1684,9 @@ namespace LLInitParam
 			typedef Mandatory<T, NAME_VALUE_LOOKUP>										self_t;
 			typedef typename super_t::value_assignment_t								value_assignment_t;
 
+			using super_t::operator();
+			using super_t::operator=;
+
 			// mandatory parameters require a name to be parseable
 			explicit Mandatory(const char* name = "", value_assignment_t val = defaultValue<T>())
 			:	super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, 1, 1)
@@ -1537,7 +1703,6 @@ namespace LLInitParam
 				super_t::set(val);
 				return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
 			}
-			using super_t::operator();
 
 			static bool validate(const Param* p)
 			{
@@ -1693,14 +1858,12 @@ namespace LLInitParam
 
 		ParamValue()
 		:	block_t(),
-			mKeyVersion(0),
 			mValidatedVersion(-1),
 			mValidated(false)
 		{}
 
 		ParamValue(value_assignment_t other)
 		:	block_t(other),
-			mKeyVersion(0),
 			mValidatedVersion(-1),
 			mValidated(false)
 		{
@@ -1731,11 +1894,82 @@ namespace LLInitParam
 			return *this;
 		}
 
-		S32 			mKeyVersion;
+	protected:
+		mutable S32 	mValidatedVersion;
+		mutable bool 	mValidated; // lazy validation flag
+	};
+
+	template<typename T>
+	class ParamValue <BaseBlock::Lazy<T>,
+					TypeValues<T>,
+					false>
+	{
+	public:
+		typedef ParamValue <BaseBlock::Lazy<T>, TypeValues<T>, false> self_t;
+		typedef const T& value_assignment_t;
+	
+		ParamValue()
+		:	mValue(),
+			mValidatedVersion(-1),
+			mValidated(false)
+		{}
+
+		ParamValue(value_assignment_t other)
+		:	mValue(other),
+			mValidatedVersion(-1),
+			mValidated(false)
+		{}
+
+		void setValue(value_assignment_t val)
+		{
+			mValue.set(val);
+		}
+
+		value_assignment_t getValue() const
+		{
+			return mValue.get();
+		}
+
+		T& getValue()
+		{
+			return mValue.get();
+		}
+
+		operator value_assignment_t() const
+		{
+			return mValue.get();
+		}
+
+		value_assignment_t operator()() const
+		{
+			return mValue.get();
+		}
+
+		bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name)
+		{
+			return mValue.get().deserializeBlock(p, name_stack_range, new_name);
+		}
+
+		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const
+		{
+			if (mValue.empty()) return;
+			
+			mValue.get().serializeBlock(p, name_stack, diff_block);
+		}
+
+		bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
+		{
+			if (mValue.empty()) return false;
+
+			return mValue.get().inspectBlock(p, name_stack, min_count, max_count);
+		}
 
 	protected:
 		mutable S32 	mValidatedVersion;
 		mutable bool 	mValidated; // lazy validation flag
+
+	private:
+		BaseBlock::Lazy<T>	mValue;
 	};
 
 	template <>
@@ -1750,14 +1984,12 @@ namespace LLInitParam
 		typedef const LLSD&	value_assignment_t;
 
 		ParamValue()
-		:	mKeyVersion(0),
-			mValidatedVersion(-1),
+		:	mValidatedVersion(-1),
 			mValidated(false)
 		{}
 
 		ParamValue(value_assignment_t other)
 		:	mValue(other),
-			mKeyVersion(0),
 			mValidatedVersion(-1),
 			mValidated(false)
 		{}
@@ -1770,7 +2002,6 @@ namespace LLInitParam
 		operator value_assignment_t() const { return mValue; }
 		value_assignment_t operator()() const { return mValue; }
 		
-		S32 			mKeyVersion;
 
 		// block param interface
 		bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
@@ -1812,7 +2043,6 @@ namespace LLInitParam
 		CustomParamValue(const T& value = T())
 		:	mValue(value),
 			mValueAge(VALUE_AUTHORITATIVE),
-			mKeyVersion(0),
 			mValidatedVersion(-1),
 			mValidated(false)
 		{}
@@ -1966,8 +2196,6 @@ namespace LLInitParam
 			return getValue();
 		}
 
-		S32 				mKeyVersion;
-
 	protected:
 
 		// use this from within updateValueFromBlock() to set the value without making it authoritative
diff --git a/indra/llxuixml/llxuiparser.cpp b/indra/llxuixml/llxuiparser.cpp
index 878f992178..cdf578113a 100644
--- a/indra/llxuixml/llxuiparser.cpp
+++ b/indra/llxuixml/llxuiparser.cpp
@@ -59,28 +59,26 @@ const char* NO_VALUE_MARKER = "no_value";
 
 const S32 LINE_NUMBER_HERE = 0;
 
-struct MaxOccur : public LLInitParam::ChoiceBlock<MaxOccur>
+struct MaxOccursValues : public LLInitParam::TypeValuesHelper<U32, MaxOccursValues>
 {
-	Alternative<int> count;
-	Alternative<std::string> unbounded;
-
-	MaxOccur()
-	:	unbounded("", "unbounded")
-	{}
+	using TypeValuesHelper<U32, MaxOccursValues>::operator =;
+	typedef std::string name_t;
+	static void declareValues()
+	{
+		declare("unbounded", U32_MAX);
+	}
 };
 
 struct Occurs : public LLInitParam::Block<Occurs>
 {
-	Optional<S32>	minOccurs;
-	Optional<MaxOccur>	maxOccurs;
+	Optional<U32>					minOccurs;
+	Optional<U32, MaxOccursValues>	maxOccurs;
+	Multiple<U32, AnyAmount, MaxOccursValues> foo;
 
 	Occurs()
-	:	minOccurs("minOccurs"),
-		maxOccurs("maxOccurs")
-	{
-		minOccurs = 0;
-		maxOccurs.unbounded.choose();
-	}
+	:	minOccurs("minOccurs", 0),
+		maxOccurs("maxOccurs", U32_MAX)
+	{}
 };
 
 
@@ -103,18 +101,15 @@ namespace LLInitParam
 	};
 }
 
-struct Name : public LLInitParam::Block<Name>
-{
-	Mandatory<std::string> name;
-
-	Name()
-	:	name("name")
-	{}
-};
+struct Element;
+struct Group;
+struct Choice;
+struct Sequence;
+struct Any;
 
 struct Attribute : public LLInitParam::Block<Attribute>
 {
-	Mandatory<Name>			name;
+	Mandatory<std::string>	name;
 	Mandatory<std::string>	type;
 	Mandatory<EUse>			use;
 	
@@ -122,41 +117,170 @@ struct Attribute : public LLInitParam::Block<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 ComplexType : public LLInitParam::Block<ComplexType>
+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>
 {
-	Multiple<Attribute>			attribute;
-	//Multiple<struct Element>	elements;
-	Optional<bool>				mixed;
+	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()
-	:	attribute("xs:attribute"),
-		//elements("xs:element"),
+	:	name("name"),
+		attribute("xs:attribute"),
+		elements("xs:element"),
 		mixed("mixed")
 	{
-		mixed = true;
 	}
 };
 
-struct Element : public LLInitParam::Block<Element, Occurs>
+struct ElementContents : public LLInitParam::ChoiceBlock<ElementContents, Occurs>
 {
-	Mandatory<ComplexType>	complexType;
-	Mandatory<Name>			name;
+	Alternative<SimpleType>		simpleType;
+	Alternative<ComplexType>	complexType;
 
-	Element()
-	:	complexType("xs:complexType")
+	ElementContents()
+	:	simpleType("simpleType"),
+		complexType("complexType")
 	{}
 };
 
-struct Elements : public LLInitParam::Block<Elements, Occurs>
+struct Element : public LLInitParam::Block<Element, ElementContents>
 {
-	Multiple<Element> elements;
+	Optional<std::string>	name,
+							ref,
+							type;
 
-	Elements()
-	:	elements("xs:element")
+	Element()
+	:	name("xs:name"),
+		ref("xs:ref"),
+		type("xs:type")
 	{}
 };
 
@@ -164,28 +288,32 @@ struct Schema : public LLInitParam::Block<Schema>
 {
 private:
 	Mandatory<std::string>	targetNamespace,
-							xmlns;
+							xmlns,
+							xs;
 
 public:
 	Optional<std::string>	attributeFormDefault,
-							elementFormDefault,
-							xs;
+							elementFormDefault;
 
-	Optional<Elements>		elements;
+	Mandatory<Element>		root_element;
 	
 	void setNameSpace(const std::string& ns) {targetNamespace = ns; xmlns = ns;}
 
-	Schema()
+	Schema(const std::string& ns = LLStringUtil::null)
 	:	attributeFormDefault("attributeFormDefault"),
 		elementFormDefault("elementFormDefault"),
 		xs("xmlns:xs"),
 		targetNamespace("targetNamespace"),
 		xmlns("xmlns"),
-		elements("xs:choice")
+		root_element("xs:element")
 	{
 		attributeFormDefault = "unqualified";
 		elementFormDefault = "qualified";
 		xs = "http://www.w3.org/2001/XMLSchema";
+		if (!ns.empty())
+		{
+			setNameSpace(ns);
+		};
 	}
 
 };
@@ -214,22 +342,30 @@ LLXSDWriter::LLXSDWriter()
 
 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");
+	//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
-- 
cgit v1.2.3