PageRenderTime 46ms CodeModel.GetById 11ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llxuixml/llinitparam.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 469 lines | 352 code | 51 blank | 66 comment | 60 complexity | 6411e9d6c3cc83b453f16a1449cff485 MD5 | raw file
  1/** 
  2 * @file llinitparam.cpp
  3 * @brief parameter block abstraction for creating complex objects and 
  4 * parsing construction parameters from xml and LLSD
  5 *
  6 * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  7 * Second Life Viewer Source Code
  8 * Copyright (C) 2010, Linden Research, Inc.
  9 * 
 10 * This library is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU Lesser General Public
 12 * License as published by the Free Software Foundation;
 13 * version 2.1 of the License only.
 14 * 
 15 * This library is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18 * Lesser General Public License for more details.
 19 * 
 20 * You should have received a copy of the GNU Lesser General Public
 21 * License along with this library; if not, write to the Free Software
 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 23 * 
 24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 25 * $/LicenseInfo$
 26 */
 27
 28#include "linden_common.h"
 29
 30#include "llinitparam.h"
 31
 32
 33namespace LLInitParam
 34{
 35	//
 36	// Param
 37	//
 38	Param::Param(BaseBlock* enclosing_block)
 39	:	mIsProvided(false)
 40	{
 41		const U8* my_addr = reinterpret_cast<const U8*>(this);
 42		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
 43		mEnclosingBlockOffset = 0x7FFFffff & (U32)(my_addr - block_addr);
 44	}
 45
 46	//
 47	// ParamDescriptor
 48	//
 49	ParamDescriptor::ParamDescriptor(param_handle_t p, 
 50									merge_func_t merge_func, 
 51									deserialize_func_t deserialize_func, 
 52									serialize_func_t serialize_func,
 53									validation_func_t validation_func,
 54									inspect_func_t inspect_func,
 55									S32 min_count,
 56									S32 max_count)
 57	:	mParamHandle(p),
 58		mMergeFunc(merge_func),
 59		mDeserializeFunc(deserialize_func),
 60		mSerializeFunc(serialize_func),
 61		mValidationFunc(validation_func),
 62		mInspectFunc(inspect_func),
 63		mMinCount(min_count),
 64		mMaxCount(max_count),
 65		mUserData(NULL)
 66	{}
 67
 68	ParamDescriptor::ParamDescriptor()
 69	:	mParamHandle(0),
 70		mMergeFunc(NULL),
 71		mDeserializeFunc(NULL),
 72		mSerializeFunc(NULL),
 73		mValidationFunc(NULL),
 74		mInspectFunc(NULL),
 75		mMinCount(0),
 76		mMaxCount(0),
 77		mUserData(NULL)
 78	{}
 79
 80	ParamDescriptor::~ParamDescriptor()
 81	{
 82		delete mUserData;
 83	}
 84
 85	//
 86	// Parser
 87	//
 88	Parser::~Parser()
 89	{}
 90
 91	void Parser::parserWarning(const std::string& message)
 92	{
 93		if (mParseSilently) return;
 94		llwarns << message << llendl;
 95	}
 96	
 97	void Parser::parserError(const std::string& message)
 98	{
 99		if (mParseSilently) return;
100		llerrs << message << llendl;
101	}
102
103
104	//
105	// BlockDescriptor
106	//
107	void BlockDescriptor::aggregateBlockData(BlockDescriptor& src_block_data) 
108	{
109		mNamedParams.insert(src_block_data.mNamedParams.begin(), src_block_data.mNamedParams.end());
110		std::copy(src_block_data.mUnnamedParams.begin(), src_block_data.mUnnamedParams.end(), std::back_inserter(mUnnamedParams));
111		std::copy(src_block_data.mValidationList.begin(), src_block_data.mValidationList.end(), std::back_inserter(mValidationList));
112		std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams));
113	}
114
115	BlockDescriptor::BlockDescriptor()
116	:	mMaxParamOffset(0),
117		mInitializationState(UNINITIALIZED),
118		mCurrentBlockPtr(NULL)
119	{}
120
121	// called by each derived class in least to most derived order
122	void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size)
123	{
124		descriptor.mCurrentBlockPtr = this;
125		descriptor.mMaxParamOffset = block_size;
126
127		switch(descriptor.mInitializationState)
128		{
129		case BlockDescriptor::UNINITIALIZED:
130			// copy params from base class here
131			descriptor.aggregateBlockData(base_descriptor);
132
133			descriptor.mInitializationState = BlockDescriptor::INITIALIZING;
134			break;
135		case BlockDescriptor::INITIALIZING:
136			descriptor.mInitializationState = BlockDescriptor::INITIALIZED;
137			break;
138		case BlockDescriptor::INITIALIZED:
139			// nothing to do
140			break;
141		}
142	}
143
144	param_handle_t BaseBlock::getHandleFromParam(const Param* param) const
145	{
146		const U8* param_address = reinterpret_cast<const U8*>(param);
147		const U8* baseblock_address = reinterpret_cast<const U8*>(this);
148		return (param_address - baseblock_address);
149	}
150
151	bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent)
152	{
153		if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end()), true))
154		{
155			if (!silent)
156			{
157				p.parserWarning(llformat("Failed to parse parameter \"%s\"", p.getCurrentElementName().c_str()));
158			}
159			return false;
160		}
161		return true;
162	}
163
164
165	bool BaseBlock::validateBlock(bool emit_errors) const
166	{
167		const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
168		for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it)
169		{
170			const Param* param = getParamFromHandle(it->first);
171			if (!it->second(param))
172			{
173				if (emit_errors)
174				{
175					llwarns << "Invalid param \"" << getParamName(block_data, param) << "\"" << llendl;
176				}
177				return false;
178			}
179		}
180		return true;
181	}
182
183	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const
184	{
185		// named param is one like LLView::Params::follows
186		// unnamed param is like LLView::Params::rect - implicit
187		const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
188
189		for (BlockDescriptor::param_list_t::const_iterator it = block_data.mUnnamedParams.begin(); 
190			it != block_data.mUnnamedParams.end(); 
191			++it)
192		{
193			param_handle_t param_handle = (*it)->mParamHandle;
194			const Param* param = getParamFromHandle(param_handle);
195			ParamDescriptor::serialize_func_t serialize_func = (*it)->mSerializeFunc;
196			if (serialize_func)
197			{
198				const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
199				// each param descriptor remembers its serial number
200				// so we can inspect the same param under different names
201				// and see that it has the same number
202				name_stack.push_back(std::make_pair("", true));
203				serialize_func(*param, parser, name_stack, diff_param);
204				name_stack.pop_back();
205			}
206		}
207
208		for(BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin();
209			it != block_data.mNamedParams.end();
210			++it)
211		{
212			param_handle_t param_handle = it->second->mParamHandle;
213			const Param* param = getParamFromHandle(param_handle);
214			ParamDescriptor::serialize_func_t serialize_func = it->second->mSerializeFunc;
215			if (serialize_func && param->anyProvided())
216			{
217				// Ensure this param has not already been serialized
218				// Prevents <rect> from being serialized as its own tag.
219				bool duplicate = false;
220				for (BlockDescriptor::param_list_t::const_iterator it2 = block_data.mUnnamedParams.begin(); 
221					it2 != block_data.mUnnamedParams.end(); 
222					++it2)
223				{
224					if (param_handle == (*it2)->mParamHandle)
225					{
226						duplicate = true;
227						break;
228					}
229				}
230
231				//FIXME: for now, don't attempt to serialize values under synonyms, as current parsers
232				// don't know how to detect them
233				if (duplicate) 
234				{
235					continue;
236				}
237
238				name_stack.push_back(std::make_pair(it->first, !duplicate));
239				const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
240				serialize_func(*param, parser, name_stack, diff_param);
241				name_stack.pop_back();
242			}
243		}
244	}
245
246	bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const
247	{
248		// named param is one like LLView::Params::follows
249		// unnamed param is like LLView::Params::rect - implicit
250		const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
251
252		for (BlockDescriptor::param_list_t::const_iterator it = block_data.mUnnamedParams.begin(); 
253			it != block_data.mUnnamedParams.end(); 
254			++it)
255		{
256			param_handle_t param_handle = (*it)->mParamHandle;
257			const Param* param = getParamFromHandle(param_handle);
258			ParamDescriptor::inspect_func_t inspect_func = (*it)->mInspectFunc;
259			if (inspect_func)
260			{
261				name_stack.push_back(std::make_pair("", true));
262				inspect_func(*param, parser, name_stack, (*it)->mMinCount, (*it)->mMaxCount);
263				name_stack.pop_back();
264			}
265		}
266
267		for(BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin();
268			it != block_data.mNamedParams.end();
269			++it)
270		{
271			param_handle_t param_handle = it->second->mParamHandle;
272			const Param* param = getParamFromHandle(param_handle);
273			ParamDescriptor::inspect_func_t inspect_func = it->second->mInspectFunc;
274			if (inspect_func)
275			{
276				// Ensure this param has not already been inspected
277				bool duplicate = false;
278				for (BlockDescriptor::param_list_t::const_iterator it2 = block_data.mUnnamedParams.begin(); 
279					it2 != block_data.mUnnamedParams.end(); 
280					++it2)
281				{
282					if (param_handle == (*it2)->mParamHandle)
283					{
284						duplicate = true;
285						break;
286					}
287				}
288
289				name_stack.push_back(std::make_pair(it->first, !duplicate));
290				inspect_func(*param, parser, name_stack, it->second->mMinCount, it->second->mMaxCount);
291				name_stack.pop_back();
292			}
293		}
294
295		return true;
296	}
297
298	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool ignored)
299	{
300		BlockDescriptor& block_data = mostDerivedBlockDescriptor();
301		bool names_left = name_stack_range.first != name_stack_range.second;
302
303		bool new_name = names_left
304						? name_stack_range.first->second
305						: true;
306
307		if (names_left)
308		{
309			const std::string& top_name = name_stack_range.first->first;
310
311			ParamDescriptor::deserialize_func_t deserialize_func = NULL;
312			Param* paramp = NULL;
313
314			BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name);
315			if (found_it != block_data.mNamedParams.end())
316			{
317				// find pointer to member parameter from offset table
318				paramp = getParamFromHandle(found_it->second->mParamHandle);
319				deserialize_func = found_it->second->mDeserializeFunc;
320					
321				Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second);
322				++new_name_stack.first;
323				if (deserialize_func(*paramp, p, new_name_stack, new_name))
324				{
325					// value is no longer new, we know about it now
326					name_stack_range.first->second = false;
327					return true;
328				}
329				else
330				{
331					return false;
332				}
333			}
334		}
335
336		// try to parse unnamed parameters, in declaration order
337		for ( BlockDescriptor::param_list_t::iterator it = block_data.mUnnamedParams.begin(); 
338			it != block_data.mUnnamedParams.end(); 
339			++it)
340		{
341			Param* paramp = getParamFromHandle((*it)->mParamHandle);
342			ParamDescriptor::deserialize_func_t deserialize_func = (*it)->mDeserializeFunc;
343
344			if (deserialize_func && deserialize_func(*paramp, p, name_stack_range, new_name))
345			{
346				return true;
347			}
348		}
349
350		// if no match, and no names left on stack, this is just an existence assertion of this block
351		// verify by calling readValue with NoParamValue type, an inherently unparseable type
352		if (!names_left)
353		{
354			Flag no_value;
355			return p.readValue(no_value);
356		}
357
358		return false;
359	}
360
361	//static 
362	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name)
363	{
364		// create a copy of the param descriptor in mAllParams
365		// so other data structures can store a pointer to it
366		block_data.mAllParams.push_back(in_param);
367		ParamDescriptorPtr param(block_data.mAllParams.back());
368
369		std::string name(char_name);
370		if ((size_t)param->mParamHandle > block_data.mMaxParamOffset)
371		{
372			llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl;
373		}
374
375		if (name.empty())
376		{
377			block_data.mUnnamedParams.push_back(param);
378		}
379		else
380		{
381			// don't use insert, since we want to overwrite existing entries
382			block_data.mNamedParams[name] = param;
383		}
384
385		if (param->mValidationFunc)
386		{
387			block_data.mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc));
388		}
389	}
390
391	void BaseBlock::addSynonym(Param& param, const std::string& synonym)
392	{
393		BlockDescriptor& block_data = mostDerivedBlockDescriptor();
394		if (block_data.mInitializationState == BlockDescriptor::INITIALIZING)
395		{
396			param_handle_t handle = getHandleFromParam(&param);
397			
398			// check for invalid derivation from a paramblock (i.e. without using
399			// Block<T, Base_Class>
400			if ((size_t)handle > block_data.mMaxParamOffset)
401			{
402				llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl;
403			}
404
405			ParamDescriptorPtr param_descriptor = findParamDescriptor(param);
406			if (param_descriptor)
407			{
408				if (synonym.empty())
409				{
410					block_data.mUnnamedParams.push_back(param_descriptor);
411				}
412				else
413				{
414					block_data.mNamedParams[synonym] = param_descriptor;
415				}
416			}
417		}
418	}
419
420	const std::string& BaseBlock::getParamName(const BlockDescriptor& block_data, const Param* paramp) const
421	{
422		param_handle_t handle = getHandleFromParam(paramp);
423		for (BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin(); it != block_data.mNamedParams.end(); ++it)
424		{
425			if (it->second->mParamHandle == handle)
426			{
427				return it->first;
428			}
429		}
430
431		return LLStringUtil::null;
432	}
433
434	ParamDescriptorPtr BaseBlock::findParamDescriptor(const Param& param)
435	{
436		param_handle_t handle = getHandleFromParam(&param);
437		BlockDescriptor& descriptor = mostDerivedBlockDescriptor();
438		BlockDescriptor::all_params_list_t::iterator end_it = descriptor.mAllParams.end();
439		for (BlockDescriptor::all_params_list_t::iterator it = descriptor.mAllParams.begin();
440			it != end_it;
441			++it)
442		{
443			if ((*it)->mParamHandle == handle) return *it;
444		}
445		return ParamDescriptorPtr();
446	}
447
448	// take all provided params from other and apply to self
449	// NOTE: this requires that "other" is of the same derived type as this
450	bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite)
451	{
452		bool some_param_changed = false;
453		BlockDescriptor::all_params_list_t::const_iterator end_it = block_data.mAllParams.end();
454		for (BlockDescriptor::all_params_list_t::const_iterator it = block_data.mAllParams.begin();
455			it != end_it;
456			++it)
457		{
458			const Param* other_paramp = other.getParamFromHandle((*it)->mParamHandle);
459			ParamDescriptor::merge_func_t merge_func = (*it)->mMergeFunc;
460			if (merge_func)
461			{
462				Param* paramp = getParamFromHandle((*it)->mParamHandle);
463				llassert(paramp->mEnclosingBlockOffset == (*it)->mParamHandle);
464				some_param_changed |= merge_func(*paramp, *other_paramp, overwrite);
465			}
466		}
467		return some_param_changed;
468	}
469}