diff options
Diffstat (limited to 'indra/llxml')
| -rw-r--r-- | indra/llxml/llcontrol.cpp | 3020 | ||||
| -rw-r--r-- | indra/llxml/llcontrol.h | 948 | ||||
| -rw-r--r-- | indra/llxml/llxmlnode.cpp | 6536 | ||||
| -rw-r--r-- | indra/llxml/llxmlnode.h | 670 | ||||
| -rw-r--r-- | indra/llxml/llxmlparser.cpp | 832 | ||||
| -rw-r--r-- | indra/llxml/llxmlparser.h | 266 | ||||
| -rw-r--r-- | indra/llxml/llxmltree.cpp | 1388 | ||||
| -rw-r--r-- | indra/llxml/llxmltree.h | 468 | ||||
| -rw-r--r-- | indra/llxml/tests/llcontrol_test.cpp | 308 | 
9 files changed, 7216 insertions, 7220 deletions
| diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index c0f27e2c22..beeca105bc 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -1,1512 +1,1508 @@ -/**  - * @file llcontrol.cpp - * @brief Holds global state for viewer. - * - * $LicenseInfo:firstyear=2001&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 <iostream> -#include <fstream> -#include <algorithm> - -#include "llcontrol.h" - -#include "llstl.h" - -#include "llstring.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4coloru.h" -#include "v4color.h" -#include "v3color.h" -#include "llquaternion.h" -#include "llrect.h" -#include "llxmltree.h" -#include "llsdserialize.h" -#include "llfile.h" -#include "lltimer.h" -#include "lldir.h" - -#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG -#define CONTROL_ERRS LL_ERRS("ControlErrors") -#else -#define CONTROL_ERRS LL_WARNS("ControlErrors") -#endif - - -template <> eControlType get_control_type<U32>(); -template <> eControlType get_control_type<S32>(); -template <> eControlType get_control_type<F32>(); -template <> eControlType get_control_type<bool>(); -template <> eControlType get_control_type<std::string>(); - -template <> eControlType get_control_type<LLVector3>(); -template <> eControlType get_control_type<LLVector3d>(); -template <> eControlType get_control_type<LLRect>(); -template <> eControlType get_control_type<LLColor4>(); -template <> eControlType get_control_type<LLColor3>(); -template <> eControlType get_control_type<LLColor4U>(); -template <> eControlType get_control_type<LLSD>(); - -template <> LLSD convert_to_llsd<U32>(const U32& in); -template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in); -template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in); -template <> LLSD convert_to_llsd<LLRect>(const LLRect& in); -template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in); -template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in); -template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in); - -template <> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLColor4U convert_from_llsd<LLColor4U>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name); -template <> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name); - -//this defines the current version of the settings file -const S32 CURRENT_VERSION = 101; - -// If you define the environment variable LL_SETTINGS_PROFILE to any value this will activate -// the gSavedSettings profiling code.  This code tracks the calls to get a saved (debug) setting. -// When the viewer exits the results are written to the log directory to the file specified -// by SETTINGS_PROFILE below.  Only settings with an average access rate >= 2/second are output. -typedef std::pair<std::string, U32> settings_pair_t; -typedef std::vector<settings_pair_t> settings_vec_t; -LLSD getCount; -settings_vec_t getCount_v; -F64 start_time = 0; -std::string SETTINGS_PROFILE = "settings_profile.log"; - -bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) -{ -	bool result = false; -	switch (mType) -	{ -	case TYPE_U32: -	case TYPE_S32: -		result = a.asInteger() == b.asInteger(); -		break; -	case TYPE_BOOLEAN: -		result = a.asBoolean() == b.asBoolean(); -		break; -	case TYPE_F32: -		result = a.asReal() == b.asReal(); -		break; -	case TYPE_VEC3: -	case TYPE_VEC3D: -		result = LLVector3d(a) == LLVector3d(b); -		break; -	case TYPE_QUAT: -		result = LLQuaternion(a) == LLQuaternion(b); -		break; -	case TYPE_RECT: -		result = LLRect(a) == LLRect(b); -		break; -	case TYPE_COL4: -		result = LLColor4(a) == LLColor4(b); -		break; -	case TYPE_COL3: -		result = LLColor3(a) == LLColor3(b); -		break; -	case TYPE_STRING: -		result = a.asString() == b.asString(); -		break; -	default: -		break; -	} - -	return result; -} - -LLControlVariable::LLControlVariable(const std::string& name, eControlType type, -							 LLSD initial, const std::string& comment, -							 ePersist persist, bool hidefromsettingseditor) -	: mName(name), -	  mComment(comment), -	  mType(type), -	  mPersist(persist), -	  mHideFromSettingsEditor(hidefromsettingseditor) -{ -	if ((persist != PERSIST_NO) && mComment.empty()) -	{ -		LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; -	} -	//Push back versus setValue'ing here, since we don't want to call a signal yet -	mValues.push_back(initial); -} - - - -LLControlVariable::~LLControlVariable() -{ -} - -LLSD LLControlVariable::getComparableValue(const LLSD& value) -{ -	// *FIX:MEP - The following is needed to make the LLSD::ImplString  -	// work with boolean controls... -	LLSD storable_value; -	if(TYPE_BOOLEAN == type() && value.isString()) -	{ -		bool temp; -		if(LLStringUtil::convertToBOOL(value.asString(), temp)) -		{ -			storable_value = temp; -		} -		else -		{ -			storable_value = false; -		} -	} -	else if (TYPE_LLSD == type() && value.isString()) -	{ -		LLPointer<LLSDNotationParser> parser = new LLSDNotationParser; -		LLSD result; -		std::stringstream value_stream(value.asString()); -		if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE) -		{ -			storable_value = result; -		} -		else -		{ -			storable_value = value; -		} -	} -	else -	{ -		storable_value = value; -	} - -	return storable_value; -} - -void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) -{ -	if (!mValidateSignal(this, new_value)) -	{ -		// can not set new value, exit -		return; -	} -	 -	LLSD storable_value = getComparableValue(new_value); -	LLSD original_value = getValue(); -	bool value_changed = !llsd_compare(original_value, storable_value); -	if(saved_value) -	{ -    	// If we're going to save this value, return to default but don't fire -		resetToDefault(false); -	    if (!llsd_compare(mValues.back(), storable_value)) -	    { -		    mValues.push_back(storable_value); -	    } -	} -    else -    { -        // This is an unsaved value. Its needs to reside at -        // mValues[2] (or greater). It must not affect  -        // the result of getSaveValue() -	    if (!llsd_compare(mValues.back(), storable_value)) -	    { -            while(mValues.size() > 2) -            { -                // Remove any unsaved values. -                mValues.pop_back(); -            } - -            if(mValues.size() < 2) -            { -                // Add the default to the 'save' value. -                mValues.push_back(mValues[0]); -            } - -            // Add the 'un-save' value. -            mValues.push_back(storable_value); -	    } -    } - -    if(value_changed) -    { -		firePropertyChanged(original_value); -    } -} - -void LLControlVariable::setDefaultValue(const LLSD& value) -{ -	// Set the control variables value and make it  -	// the default value. If the active value is changed, -	// send the signal. -	// *NOTE: Default values are not saved, only read. - -	LLSD comparable_value = getComparableValue(value); -	LLSD original_value = getValue(); -	bool value_changed = !llsd_compare(original_value, comparable_value); -	resetToDefault(false); -	mValues[0] = comparable_value; -	if (value_changed) -	{ -		firePropertyChanged(original_value); -	} -} - -void LLControlVariable::setPersist(ePersist state) -{ -	mPersist = state; -} - -void LLControlVariable::setHiddenFromSettingsEditor(bool hide) -{ -	mHideFromSettingsEditor = hide; -} - -void LLControlVariable::setComment(const std::string& comment) -{ -	mComment = comment; -} - -void LLControlVariable::resetToDefault(bool fire_signal) -{ -	//The first setting is always the default -	//Pop to it and fire off the listener -	LLSD originalValue = mValues.back(); - -	while(mValues.size() > 1) -	{ -		mValues.pop_back(); -	} -	 -	if(fire_signal)  -	{ -		firePropertyChanged(originalValue); -	} -} - -bool LLControlVariable::shouldSave(bool nondefault_only) -{ -	// This method is used to decide whether we should save a given -	// variable. Two of the three values of mPersist are easy. -	if (mPersist == PERSIST_NO) -		return false; - -	if (mPersist == PERSIST_ALWAYS) -		return true; - -	// PERSIST_NONDFT -	// If caller doesn't need us to filter, just save. -	if (! nondefault_only) -		return true; - -	// PERSIST_NONDFT: caller only wants us to save this variable if its value -	// differs from default. -	if (isDefault())                // never been altered -		return false; - -	// We've set at least one other value: compare it to default. Save only if -	// they differ. -	return ! llsd_compare(getSaveValue(), getDefault()); -} - -LLSD LLControlVariable::getSaveValue() const -{ -	//The first level of the stack is default -	//We assume that the second level is user preferences that should be saved -	if(mValues.size() > 1) return mValues[1]; -	return mValues[0]; -} - -LLPointer<LLControlVariable> LLControlGroup::getControl(std::string_view name) -{ -	if (mSettingsProfile) -	{ -		incrCount(name); -	} - -	ctrl_name_table_t::iterator iter = mNameTable.find(name.data()); -	return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second; -} - - -//////////////////////////////////////////////////////////////////////////// - -// Must match the type definition in llcontrol.h -const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32" -                                                             ,"S32" -                                                             ,"F32" -                                                             ,"Boolean" -                                                             ,"String" -                                                             ,"Vector3" -                                                             ,"Vector3D" -                                                             ,"Quaternion" -                                                             ,"Rect" -                                                             ,"Color4" -                                                             ,"Color3" -                                                             ,"LLSD" -                                                             }; - -LLControlGroup::LLControlGroup(const std::string& name) -:	LLInstanceTracker<LLControlGroup, std::string>(name), -	mSettingsProfile(false) -{ - -	if (NULL != getenv("LL_SETTINGS_PROFILE")) -	{ -		mSettingsProfile = true; -	} -} - -LLControlGroup::~LLControlGroup() -{ -	cleanup(); -} - -static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs) -{ -	return lhs.second > rhs.second; -}; - -void LLControlGroup::cleanup() -{ -	if(mSettingsProfile && getCount.size() != 0) -	{ -		std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); -		LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */ -		if(!out) -		{ -			LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; -		} -		else -		{ -			F64 end_time = LLTimer::getTotalSeconds(); -			U32 total_seconds = (U32)(end_time - start_time); - -			std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses   Avg. accesses/sec  Name\n", total_seconds); -			std::ostringstream data_msg; - -			data_msg << msg; -			size_t data_size = data_msg.str().size(); -			if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) -			{ -				LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL; -			} - -			for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter) -			{ -				getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger())); -			} -			sort(getCount_v.begin(), getCount_v.end(), compareRoutine); - -			for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter) -			{ -				U32 access_rate = 0; -				if (total_seconds != 0) -				{ -					access_rate = iter->second / total_seconds; -				} -				if (access_rate >= 2) -				{ -					std::ostringstream data_msg; -					msg = llformat("%13d        %7d       %s", iter->second, access_rate, iter->first.c_str()); -					data_msg << msg << "\n"; -					size_t data_size = data_msg.str().size(); -					if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) -					{ -						LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL; -					} -				} -			} -			getCount = LLSD::emptyMap(); -			fclose(out); -		} -	} - -	mNameTable.clear(); -} - -eControlType LLControlGroup::typeStringToEnum(const std::string& typestr) -{ -	for(int i = 0; i < (int)TYPE_COUNT; ++i) -	{ -		if(mTypeString[i] == typestr) return (eControlType)i; -	} -	return (eControlType)-1; -} - -std::string LLControlGroup::typeEnumToString(eControlType typeenum) -{ -	return mTypeString[typeenum]; -} - -LLControlVariable* LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, bool hidefromsettingseditor) -{ -	LLControlVariable* existing_control = getControl(name); -	if (existing_control) - 	{ -		if ((persist != LLControlVariable::PERSIST_NO) && existing_control->isType(type)) -		{ -			if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val)) -			{ -				// Sometimes we need to declare a control *after* it has been loaded from a settings file. -				LLSD cur_value = existing_control->getValue(); // get the current value -				existing_control->setDefaultValue(initial_val); // set the default to the declared value -				existing_control->setValue(cur_value); // now set to the loaded value -			} -		} -		else -		{ -			LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL; -		} - 		return existing_control; -	} - -	// if not, create the control and add it to the name table -	LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor); -	mNameTable[name] = control;	 -	return control; -} - -LLControlVariable* LLControlGroup::declareU32(const std::string& name, const U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareS32(const std::string& name, const S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_S32, initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareF32(const std::string& name, const F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_F32, initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareBOOL(const std::string& name, const bool initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareString(const std::string& name, const std::string& initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_STRING, initial_val, comment, persist); -} - -LLControlVariable* LLControlGroup::declareVec3(const std::string& name, const LLVector3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist) -{ -	return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) -{ -	return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) -{ -	return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist); -} - -LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist ) -{ -	return declareControl(name, TYPE_LLSD, initial_val, comment, persist); -} - -void LLControlGroup::incrCount(std::string_view name) -{ -	if (0.0 == start_time) -	{ -		start_time = LLTimer::getTotalSeconds(); -	} -	getCount[name.data()] = getCount[name.data()].asInteger() + 1; -} - -bool LLControlGroup::getBOOL(std::string_view name) -{ -	return get<bool>(name); -} - -S32 LLControlGroup::getS32(std::string_view name) -{ -	return get<S32>(name); -} - -U32 LLControlGroup::getU32(std::string_view name) -{ -	return get<U32>(name); -} - -F32 LLControlGroup::getF32(std::string_view name) -{ -	return get<F32>(name); -} - -std::string LLControlGroup::getString(std::string_view name) -{ -	return get<std::string>(name); -} - -LLWString LLControlGroup::getWString(std::string_view name) -{ -	return get<LLWString>(name); -} - -std::string LLControlGroup::getText(std::string_view name) -{ -	std::string utf8_string = getString(name); -	LLStringUtil::replaceChar(utf8_string, '^', '\n'); -	LLStringUtil::replaceChar(utf8_string, '%', ' '); -	return (utf8_string); -} - -LLVector3 LLControlGroup::getVector3(std::string_view name) -{ -	return get<LLVector3>(name); -} - -LLVector3d LLControlGroup::getVector3d(std::string_view name) -{ -	return get<LLVector3d>(name); -} - -LLQuaternion LLControlGroup::getQuaternion(std::string_view name) -{ -	return get<LLQuaternion>(name); -} - -LLRect LLControlGroup::getRect(std::string_view name) -{ -	return get<LLRect>(name); -} - - -LLColor4 LLControlGroup::getColor(std::string_view name) -{ -	return get<LLColor4>(name); -} - -LLColor4 LLControlGroup::getColor4(std::string_view name) -{ -	return get<LLColor4>(name); -} - -LLColor3 LLControlGroup::getColor3(std::string_view name) -{ -	return get<LLColor3>(name); -} - -LLSD LLControlGroup::getLLSD(std::string_view name) -{ -	return get<LLSD>(name); -} - -LLSD LLControlGroup::asLLSD(bool diffs_only) -{ -	// Dump all stored values as LLSD -	LLSD result = LLSD::emptyArray(); -	for (ctrl_name_table_t::iterator iter = mNameTable.begin(); -		 iter != mNameTable.end(); iter++) -	{ -		LLControlVariable *control = iter->second; -		if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault())) -		{ -			continue; -		} -		const std::string& name = iter->first; -		result[name] = getLLSD(name); -	} -	return result; -} - -bool LLControlGroup::controlExists(const std::string& name) -{ -	ctrl_name_table_t::iterator iter = mNameTable.find(name); -	return iter != mNameTable.end(); -} - - -//------------------------------------------------------------------- -// Set functions -//------------------------------------------------------------------- - -void LLControlGroup::setBOOL(std::string_view name, bool val) -{ -	set<bool>(name, val); -} - - -void LLControlGroup::setS32(std::string_view name, S32 val) -{ -	set(name, val); -} - - -void LLControlGroup::setF32(std::string_view name, F32 val) -{ -	set(name, val); -} - - -void LLControlGroup::setU32(std::string_view name, U32 val) -{ -	set(name, val); -} - - -void LLControlGroup::setString(std::string_view name, const std::string &val) -{ -	set(name, val); -} - - -void LLControlGroup::setVector3(std::string_view name, const LLVector3 &val) -{ -	set(name, val); -} - -void LLControlGroup::setVector3d(std::string_view name, const LLVector3d &val) -{ -	set(name, val); -} - -void LLControlGroup::setQuaternion(std::string_view name, const LLQuaternion &val) -{ -	set(name, val); -} - -void LLControlGroup::setRect(std::string_view name, const LLRect &val) -{ -	set(name, val); -} - -void LLControlGroup::setColor4(std::string_view name, const LLColor4 &val) -{ -	set(name, val); -} - -void LLControlGroup::setLLSD(std::string_view name, const LLSD& val) -{ -	set(name, val); -} - -void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val) -{ -	if (name.empty()) -	{ -		return; -	} - -	LLControlVariable* control = getControl(name); -	 -	if (control) -	{ -		control->setValue(val); -	} -	else -	{ -		CONTROL_ERRS << "Invalid control " << name << LL_ENDL; -	} -} - - -//--------------------------------------------------------------- -// Load and save -//--------------------------------------------------------------- - -// Returns number of controls loaded, so 0 if failure -U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require_declaration, eControlType declare_as) -{ -	std::string name; - -	LLXmlTree xml_controls; - -	if (!xml_controls.parseFile(filename)) -	{ -		LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL; -		return 0; -	} - -	LLXmlTreeNode* rootp = xml_controls.getRoot(); -	if (!rootp || !rootp->hasAttribute("version")) -	{ -		LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL; -		return 0; -	} - -	U32		validitems = 0; -	S32 version; -	 -	rootp->getAttributeS32("version", version); - -	// Check file version -	if (version != CURRENT_VERSION) -	{ -		LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL; -		return 0; -	} - -	LLXmlTreeNode* child_nodep = rootp->getFirstChild(); -	while(child_nodep) -	{ -		name = child_nodep->getName();		 -		 -		bool declared = controlExists(name); - -		if (require_declaration && !declared) -		{ -			// Declaration required, but this name not declared. -			// Complain about non-empty names. -			if (!name.empty()) -			{ -				//read in to end of line -				LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL; -			} -			child_nodep = rootp->getNextChild(); -			continue; -		} - -		// Got an item.  Load it up. -		// If not declared, assume it's a string -		if (!declared) -		{ -			switch(declare_as) -			{ -			case TYPE_COL4: -				declareColor4(name, LLColor4::white, LLStringUtil::null, LLControlVariable::PERSIST_NO); -				break; -			case TYPE_STRING: -			default: -				declareString(name, LLStringUtil::null, LLStringUtil::null, LLControlVariable::PERSIST_NO); -				break; -			} -		} - -		// Control name has been declared in code. -		LLControlVariable *control = getControl(name); - -		llassert(control); -		 -		switch(control->mType) -		{ -		case TYPE_F32: -			{ -				F32 initial = 0.f; - -				child_nodep->getAttributeF32("value", initial); - -				control->set(initial); -				validitems++; -			} -			break; -		case TYPE_S32: -			{ -				S32 initial = 0; - -				child_nodep->getAttributeS32("value", initial); - -				control->set(initial); -				validitems++; -			} -			break; -		case TYPE_U32: -			{ -				U32 initial = 0; -				child_nodep->getAttributeU32("value", initial); -				control->set((LLSD::Integer) initial); -				validitems++; -			} -			break; -		case TYPE_BOOLEAN: -			{ -				bool initial = false; - -				child_nodep->getAttributeBOOL("value", initial); -				control->set(initial); - -				validitems++; -			} -			break; -		case TYPE_STRING: -			{ -				std::string string; -				child_nodep->getAttributeString("value", string); -				control->set(string); -				validitems++; -			} -			break; -		case TYPE_VEC3: -			{ -				LLVector3 vector; - -				child_nodep->getAttributeVector3("value", vector); -				control->set(vector.getValue()); -				validitems++; -			} -			break; -		case TYPE_VEC3D: -			{ -				LLVector3d vector; - -				child_nodep->getAttributeVector3d("value", vector); - -				control->set(vector.getValue()); -				validitems++; -			} -			break; -		case TYPE_QUAT: -			{ -				LLQuaternion quat; - -				child_nodep->getAttributeQuat("value", quat); - -				control->set(quat.getValue()); -				validitems++; -			} -			break; -		case TYPE_RECT: -			{ -				//RN: hack to support reading rectangles from a string -				std::string rect_string; - -				child_nodep->getAttributeString("value", rect_string); -				std::istringstream istream(rect_string); -				S32 left, bottom, width, height; - -				istream >> left >> bottom >> width >> height; - -				LLRect rect; -				rect.setOriginAndSize(left, bottom, width, height); - -				control->set(rect.getValue()); -				validitems++; -			} -			break; -		case TYPE_COL4: -			{ -				LLColor4 color; -				 -				child_nodep->getAttributeColor4("value", color); -				control->set(color.getValue()); -				validitems++; -			} -			break; -		case TYPE_COL3: -			{ -				LLVector3 color; -				 -				child_nodep->getAttributeVector3("value", color); -				control->set(LLColor3(color.mV).getValue()); -				validitems++; -			} -			break; - -		default: -		  break; - -		} -	 -		child_nodep = rootp->getNextChild(); -	} - -	return validitems; -} - -U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only) -{ -	LLSD settings; -	int num_saved = 0; -	for (ctrl_name_table_t::iterator iter = mNameTable.begin(); -		 iter != mNameTable.end(); iter++) -	{ -		LLControlVariable* control = iter->second; -		if (!control) -		{ -			LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL; -		} -		else if( control->shouldSave(nondefault_only) ) -		{ -			settings[iter->first]["Type"] = typeEnumToString(control->type()); -			settings[iter->first]["Comment"] = control->getComment(); -			settings[iter->first]["Value"] = control->getSaveValue(); -			++num_saved; -		} -	} -	llofstream file; -	file.open(filename.c_str()); -	if (file.is_open()) -	{ -		LLSDSerialize::toPrettyXML(settings, file); -		file.close(); -		LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL; -	} -	else -	{ -        // This is a warning because sometime we want to use settings files which can't be written... -		LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL; -		return 0; -	} -	return num_saved; -} - -U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values) -{ -	LLSD settings; -	llifstream infile; -	infile.open(filename.c_str()); -	if(!infile.is_open()) -	{ -		LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL; -		return 0; -	} - -	if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile)) -	{ -		infile.close(); -		LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL; -		return loadFromFileLegacy(filename, true, TYPE_STRING); -	} - -	U32	validitems = 0; -	bool hidefromsettingseditor = false; -	 -	for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr) -	{ -		LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT; -		std::string const & name = itr->first; -		LLSD const & control_map = itr->second; -		 -		if(control_map.has("Persist"))  -		{ -			persist = control_map["Persist"].asInteger()? -					  LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO; -		} -		 -		// Sometimes we want to use the settings system to provide cheap persistence, but we -		// don't want the settings themselves to be easily manipulated in the UI because  -		// doing so can cause support problems. So we have this option: -		if(control_map.has("HideFromEditor")) -		{ -			hidefromsettingseditor = control_map["HideFromEditor"].asInteger(); -		} -		else -		{ -			hidefromsettingseditor = false; -		} -		 -		// If the control exists just set the value from the input file. -		LLControlVariable* existing_control = getControl(name); -		if(existing_control) -		{ -			// set_default_values is true when we're loading the initial, -			// immutable files from app_settings, e.g. settings.xml. -			if(set_default_values) -			{ -				// Override all previously set properties of this control. -				// ... except for type. The types must match. -				eControlType new_type = typeStringToEnum(control_map["Type"].asString()); -				if(existing_control->isType(new_type)) -				{ -					existing_control->setDefaultValue(control_map["Value"]); -					existing_control->setPersist(persist); -					existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor); -					existing_control->setComment(control_map["Comment"].asString()); -				} -				else -				{ -					LL_ERRS() << "Mismatched type of control variable '" -						   << name << "' found while loading '" -						   << filename << "'." << LL_ENDL; -				} -			} -			else if(existing_control->isPersisted()) -			{ -				// save_values is specifically false for (e.g.) -				// SessionSettingsFile and UserSessionSettingsFile -- in other -				// words, for a file that's supposed to be transient. -				existing_control->setValue(control_map["Value"], save_values); -			} -			// *NOTE: If not persisted and not setting defaults,  -			// the value should not get loaded. -		} -		else -		{ -			// We've never seen this control before. Either we're loading up -			// the initial set of default settings files (set_default_values) -			// -- or we're loading user settings last saved by a viewer that -			// supports a superset of the variables we know. -			// CHOP-962: if we're loading an unrecognized user setting, make -			// sure we save it later. If you try an experimental viewer, tweak -			// a new setting, briefly revert to an old viewer, then return to -			// the new one, we don't want the old viewer to discard the -			// setting you changed. -			if (! set_default_values) -			{ -				// Using PERSIST_ALWAYS insists that saveToFile() (which calls -				// LLControlVariable::shouldSave()) must save this control -				// variable regardless of its value. We can safely set this -				// LLControlVariable persistent because the 'persistent' flag -				// is not itself persisted! -				persist = LLControlVariable::PERSIST_ALWAYS; -				// We want to mention unrecognized user settings variables -				// (e.g. from a newer version of the viewer) in the log. But -				// we also arrive here for Boolean variables generated by -				// the notifications subsystem when the user checks "Don't -				// show me this again." These aren't declared in settings.xml; -				// they're actually named for the notification they suppress. -				// We don't want to mention those. Apologies, this is a bit of -				// a hack: we happen to know that user settings go into an -				// LLControlGroup whose name is "Global". -				if (getKey() == "Global") -				{ -					LL_INFOS("LLControlGroup") << "preserving unrecognized " << getKey() -											   << " settings variable " << name << LL_ENDL; -				} -			} - -			declareControl(name,  -						   typeStringToEnum(control_map["Type"].asString()),  -						   control_map["Value"],  -						   control_map["Comment"].asString(),  -						   persist, -						   hidefromsettingseditor -						   ); -		} - -		++validitems; -	} - -	LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL; -	return validitems; -} - -void LLControlGroup::resetToDefaults() -{ -	ctrl_name_table_t::iterator control_iter; -	for (control_iter = mNameTable.begin(); -		control_iter != mNameTable.end(); -		++control_iter) -	{ -		LLControlVariable* control = (*control_iter).second; -		control->resetToDefault(); -	} -} - -void LLControlGroup::applyToAll(ApplyFunctor* func) -{ -	for (ctrl_name_table_t::iterator iter = mNameTable.begin(); -		 iter != mNameTable.end(); iter++) -	{ -		func->apply(iter->first, iter->second); -	} -} - -//============================================================================ - -#ifdef TEST_HARNESS -void main() -{ -	F32_CONTROL foo, getfoo; - -	S32_CONTROL bar, getbar; -	 -	BOOL_CONTROL baz; - -	U32 count = gGlobals.loadFromFile("controls.ini"); -	LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL; - -	// test insertion -	foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f); -	gGlobals.addEntry("gFoo", foo); - -	bar = new LLControlVariable<S32>("gBar", 10, 2, 22); -	gGlobals.addEntry("gBar", bar); - -	baz = new LLControlVariable<bool>("gBaz", false); -	gGlobals.addEntry("gBaz", baz); - -	// test retrieval -	getfoo = (LLControlVariable<F32>*) gGlobals.resolveName("gFoo"); -	getfoo->dump(); - -	getbar = (S32_CONTROL) gGlobals.resolveName("gBar"); -	getbar->dump(); - -	// change data -	getfoo->set(10.f); -	getfoo->dump(); - -	// Failure modes - -	// ...min > max -	// badfoo = new LLControlVariable<F32>("gFoo2", 100.f, 20.f, 5.f); - -	// ...initial > max -	// badbar = new LLControlVariable<S32>("gBar2", 10, 20, 100000); - -	// ...misspelled name -	// getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled"); -	// getfoo->dump(); - -	// ...invalid data type -	getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo"); -	getfoo->set(true); -	getfoo->dump(); - -	// ...out of range data -	// getfoo->set(100000000.f); -	// getfoo->dump(); - -	// Clean Up -	delete foo; -	delete bar; -	delete baz; -} -#endif - - -template <> eControlType get_control_type<U32>()  -{  -	return TYPE_U32;  -} - -template <> eControlType get_control_type<S32>()  -{  -	return TYPE_S32;  -} - -template <> eControlType get_control_type<F32>()  -{  -	return TYPE_F32;  -} - -template <> eControlType get_control_type<bool> ()  -{  -	return TYPE_BOOLEAN;  -} - -template <> eControlType get_control_type<std::string>()  -{  -	return TYPE_STRING;  -} - -template <> eControlType get_control_type<LLVector3>()  -{  -	return TYPE_VEC3;  -} - -template <> eControlType get_control_type<LLVector3d>()  -{  -	return TYPE_VEC3D;  -} - -template <> eControlType get_control_type<LLQuaternion>() -{ -	return TYPE_QUAT; -} - -template <> eControlType get_control_type<LLRect>()  -{  -	return TYPE_RECT;  -} - -template <> eControlType get_control_type<LLColor4>()  -{  -	return TYPE_COL4;  -} - -template <> eControlType get_control_type<LLColor3>()  -{  -	return TYPE_COL3;  -} - -template <> eControlType get_control_type<LLSD>()  -{  -	return TYPE_LLSD;  -} - - -template <> LLSD convert_to_llsd<U32>(const U32& in)  -{  -	return (LLSD::Integer)in;  -} - -template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in)  -{  -	return in.getValue();  -} - -template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in)  -{  -	return in.getValue();  -} -template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in) -{ -	return in.getValue(); -} - -template <> LLSD convert_to_llsd<LLRect>(const LLRect& in)  -{  -	return in.getValue();  -} - -template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in)  -{  -	return in.getValue();  -} - -template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in)  -{  -	return in.getValue();  -} - -template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in)  -{  -	return in.getValue(); -} - - -template<> -bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_BOOLEAN) -		return sd.asBoolean(); -	else -	{ -		CONTROL_ERRS << "Invalid bool value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return false; -	} -} - -template<> -S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_S32) -		return sd.asInteger(); -	else -	{ -		CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return 0; -	} -} - -template<> -U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_U32)	 -		return sd.asInteger(); -	else -	{ -		CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return 0; -	} -} - -template<> -F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_F32) -		return (F32) sd.asReal(); -	else -	{ -		CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return 0.0f; -	} -} - -template<> -std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_STRING) -		return sd.asString(); -	else -	{ -		CONTROL_ERRS << "Invalid string value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return LLStringUtil::null; -	} -} - -template<> -LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	return utf8str_to_wstring(convert_from_llsd<std::string>(sd, type, control_name)); -} - -template<> -LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_VEC3) -		return (LLVector3)sd; -	else -	{ -		CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return LLVector3::zero; -	} -} - -template<> -LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_VEC3D) -		return (LLVector3d)sd; -	else -	{ -		CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return LLVector3d::zero; -	} -} - -template<> -LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_QUAT) -		return (LLQuaternion)sd; -	else -	{ -		CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return LLQuaternion(); -	} -} - -template<> -LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_RECT) -		return LLRect(sd); -	else -	{ -		CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return LLRect::null; -	} -} - - -template<> -LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_COL4) -	{ -		LLColor4 color(sd); -		if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) -		{ -			LL_WARNS("Settings") << "Color " << control_name << " red value out of range: " << color << LL_ENDL; -		} -		else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f) -		{ -			LL_WARNS("Settings") << "Color " << control_name << " green value out of range: " << color << LL_ENDL; -		} -		else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f) -		{ -			LL_WARNS("Settings") << "Color " << control_name << " blue value out of range: " << color << LL_ENDL; -		} -		else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f) -		{ -			LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL; -		} - -		return LLColor4(sd); -	} -	else -	{ -		CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL; -		return LLColor4::white; -	} -} - -template<> -LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	if (type == TYPE_COL3) -		return sd; -	else -	{ -		CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL; -		return LLColor3::white; -	} -} - -template<> -LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	return sd; -} - - -#if TEST_CACHED_CONTROL - -#define DECL_LLCC(T, V) static LLCachedControl<T> mySetting_##T("TestCachedControl"#T, V) -DECL_LLCC(U32, (U32)666); -DECL_LLCC(S32, (S32)-666); -DECL_LLCC(F32, (F32)-666.666); -DECL_LLCC(bool, true); -static LLCachedControl<std::string> mySetting_string("TestCachedControlstring", "Default String Value"); -DECL_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); -DECL_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); -DECL_LLCC(LLRect, LLRect(0, 0, 100, 500)); -DECL_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f)); -DECL_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); -DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); - -LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"]; -DECL_LLCC(LLSD, test_llsd); - -static LLCachedControl<std::string> test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment"); - -void test_cached_control() -{ -#define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL -	TEST_LLCC(U32, 666); -	TEST_LLCC(S32, (S32)-666); -	TEST_LLCC(F32, (F32)-666.666); -	TEST_LLCC(bool, true); -	if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL; -	TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); -	TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); -	TEST_LLCC(LLRect, LLRect(0, 0, 100, 500)); -	TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f)); -	TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); -	TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255)); -//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd);  - -	if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; -} -#endif // TEST_CACHED_CONTROL - +/**
 + * @file llcontrol.cpp
 + * @brief Holds global state for viewer.
 + *
 + * $LicenseInfo:firstyear=2001&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 <iostream>
 +#include <fstream>
 +#include <algorithm>
 +
 +#include "llcontrol.h"
 +
 +#include "llstl.h"
 +
 +#include "llstring.h"
 +#include "v3math.h"
 +#include "v3dmath.h"
 +#include "v4coloru.h"
 +#include "v4color.h"
 +#include "v3color.h"
 +#include "llquaternion.h"
 +#include "llrect.h"
 +#include "llxmltree.h"
 +#include "llsdserialize.h"
 +#include "llfile.h"
 +#include "lltimer.h"
 +#include "lldir.h"
 +
 +#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
 +#define CONTROL_ERRS LL_ERRS("ControlErrors")
 +#else
 +#define CONTROL_ERRS LL_WARNS("ControlErrors")
 +#endif
 +
 +
 +template <> eControlType get_control_type<U32>();
 +template <> eControlType get_control_type<S32>();
 +template <> eControlType get_control_type<F32>();
 +template <> eControlType get_control_type<bool>();
 +template <> eControlType get_control_type<std::string>();
 +
 +template <> eControlType get_control_type<LLVector3>();
 +template <> eControlType get_control_type<LLVector3d>();
 +template <> eControlType get_control_type<LLRect>();
 +template <> eControlType get_control_type<LLColor4>();
 +template <> eControlType get_control_type<LLColor3>();
 +template <> eControlType get_control_type<LLColor4U>();
 +template <> eControlType get_control_type<LLSD>();
 +
 +template <> LLSD convert_to_llsd<U32>(const U32& in);
 +template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
 +template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
 +template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
 +template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
 +template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in);
 +template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in);
 +
 +template <> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> LLColor4U convert_from_llsd<LLColor4U>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template <> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name);
 +
 +//this defines the current version of the settings file
 +const S32 CURRENT_VERSION = 101;
 +
 +// If you define the environment variable LL_SETTINGS_PROFILE to any value this will activate
 +// the gSavedSettings profiling code.  This code tracks the calls to get a saved (debug) setting.
 +// When the viewer exits the results are written to the log directory to the file specified
 +// by SETTINGS_PROFILE below.  Only settings with an average access rate >= 2/second are output.
 +typedef std::pair<std::string, U32> settings_pair_t;
 +typedef std::vector<settings_pair_t> settings_vec_t;
 +LLSD getCount;
 +settings_vec_t getCount_v;
 +F64 start_time = 0;
 +std::string SETTINGS_PROFILE = "settings_profile.log";
 +
 +bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b)
 +{
 +    bool result = false;
 +    switch (mType)
 +    {
 +    case TYPE_U32:
 +    case TYPE_S32:
 +        result = a.asInteger() == b.asInteger();
 +        break;
 +    case TYPE_BOOLEAN:
 +        result = a.asBoolean() == b.asBoolean();
 +        break;
 +    case TYPE_F32:
 +        result = a.asReal() == b.asReal();
 +        break;
 +    case TYPE_VEC3:
 +    case TYPE_VEC3D:
 +        result = LLVector3d(a) == LLVector3d(b);
 +        break;
 +    case TYPE_QUAT:
 +        result = LLQuaternion(a) == LLQuaternion(b);
 +        break;
 +    case TYPE_RECT:
 +        result = LLRect(a) == LLRect(b);
 +        break;
 +    case TYPE_COL4:
 +        result = LLColor4(a) == LLColor4(b);
 +        break;
 +    case TYPE_COL3:
 +        result = LLColor3(a) == LLColor3(b);
 +        break;
 +    case TYPE_STRING:
 +        result = a.asString() == b.asString();
 +        break;
 +    default:
 +        break;
 +    }
 +
 +    return result;
 +}
 +
 +LLControlVariable::LLControlVariable(const std::string& name, eControlType type,
 +                             LLSD initial, const std::string& comment,
 +                             ePersist persist, bool hidefromsettingseditor)
 +    : mName(name),
 +      mComment(comment),
 +      mType(type),
 +      mPersist(persist),
 +      mHideFromSettingsEditor(hidefromsettingseditor)
 +{
 +    if ((persist != PERSIST_NO) && mComment.empty())
 +    {
 +        LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL;
 +    }
 +    //Push back versus setValue'ing here, since we don't want to call a signal yet
 +    mValues.push_back(initial);
 +}
 +
 +
 +
 +LLControlVariable::~LLControlVariable()
 +{
 +}
 +
 +LLSD LLControlVariable::getComparableValue(const LLSD& value)
 +{
 +    // *FIX:MEP - The following is needed to make the LLSD::ImplString
 +    // work with boolean controls...
 +    LLSD storable_value;
 +    if(TYPE_BOOLEAN == type() && value.isString())
 +    {
 +        bool temp;
 +        if(LLStringUtil::convertToBOOL(value.asString(), temp))
 +        {
 +            storable_value = temp;
 +        }
 +        else
 +        {
 +            storable_value = false;
 +        }
 +    }
 +    else if (TYPE_LLSD == type() && value.isString())
 +    {
 +        LLPointer<LLSDNotationParser> parser = new LLSDNotationParser;
 +        LLSD result;
 +        std::stringstream value_stream(value.asString());
 +        if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE)
 +        {
 +            storable_value = result;
 +        }
 +        else
 +        {
 +            storable_value = value;
 +        }
 +    }
 +    else
 +    {
 +        storable_value = value;
 +    }
 +
 +    return storable_value;
 +}
 +
 +void LLControlVariable::setValue(const LLSD& new_value, bool saved_value)
 +{
 +    if (!mValidateSignal(this, new_value))
 +    {
 +        // can not set new value, exit
 +        return;
 +    }
 +
 +    LLSD storable_value = getComparableValue(new_value);
 +    LLSD original_value = getValue();
 +    bool value_changed = !llsd_compare(original_value, storable_value);
 +    if(saved_value)
 +    {
 +        // If we're going to save this value, return to default but don't fire
 +        resetToDefault(false);
 +        if (!llsd_compare(mValues.back(), storable_value))
 +        {
 +            mValues.push_back(storable_value);
 +        }
 +    }
 +    else
 +    {
 +        // This is an unsaved value. Its needs to reside at
 +        // mValues[2] (or greater). It must not affect
 +        // the result of getSaveValue()
 +        if (!llsd_compare(mValues.back(), storable_value))
 +        {
 +            while(mValues.size() > 2)
 +            {
 +                // Remove any unsaved values.
 +                mValues.pop_back();
 +            }
 +
 +            if(mValues.size() < 2)
 +            {
 +                // Add the default to the 'save' value.
 +                mValues.push_back(mValues[0]);
 +            }
 +
 +            // Add the 'un-save' value.
 +            mValues.push_back(storable_value);
 +        }
 +    }
 +
 +    if(value_changed)
 +    {
 +        firePropertyChanged(original_value);
 +    }
 +}
 +
 +void LLControlVariable::setDefaultValue(const LLSD& value)
 +{
 +    // Set the control variables value and make it
 +    // the default value. If the active value is changed,
 +    // send the signal.
 +    // *NOTE: Default values are not saved, only read.
 +
 +    LLSD comparable_value = getComparableValue(value);
 +    LLSD original_value = getValue();
 +    bool value_changed = !llsd_compare(original_value, comparable_value);
 +    resetToDefault(false);
 +    mValues[0] = comparable_value;
 +    if (value_changed)
 +    {
 +        firePropertyChanged(original_value);
 +    }
 +}
 +
 +void LLControlVariable::setPersist(ePersist state)
 +{
 +    mPersist = state;
 +}
 +
 +void LLControlVariable::setHiddenFromSettingsEditor(bool hide)
 +{
 +    mHideFromSettingsEditor = hide;
 +}
 +
 +void LLControlVariable::setComment(const std::string& comment)
 +{
 +    mComment = comment;
 +}
 +
 +void LLControlVariable::resetToDefault(bool fire_signal)
 +{
 +    //The first setting is always the default
 +    //Pop to it and fire off the listener
 +    LLSD originalValue = mValues.back();
 +
 +    while(mValues.size() > 1)
 +    {
 +        mValues.pop_back();
 +    }
 +
 +    if(fire_signal)
 +    {
 +        firePropertyChanged(originalValue);
 +    }
 +}
 +
 +bool LLControlVariable::shouldSave(bool nondefault_only)
 +{
 +    // This method is used to decide whether we should save a given
 +    // variable. Two of the three values of mPersist are easy.
 +    if (mPersist == PERSIST_NO)
 +        return false;
 +
 +    if (mPersist == PERSIST_ALWAYS)
 +        return true;
 +
 +    // PERSIST_NONDFT
 +    // If caller doesn't need us to filter, just save.
 +    if (! nondefault_only)
 +        return true;
 +
 +    // PERSIST_NONDFT: caller only wants us to save this variable if its value
 +    // differs from default.
 +    if (isDefault())                // never been altered
 +        return false;
 +
 +    // We've set at least one other value: compare it to default. Save only if
 +    // they differ.
 +    return ! llsd_compare(getSaveValue(), getDefault());
 +}
 +
 +LLSD LLControlVariable::getSaveValue() const
 +{
 +    //The first level of the stack is default
 +    //We assume that the second level is user preferences that should be saved
 +    if(mValues.size() > 1) return mValues[1];
 +    return mValues[0];
 +}
 +
 +LLPointer<LLControlVariable> LLControlGroup::getControl(std::string_view name)
 +{
 +    if (mSettingsProfile)
 +    {
 +        incrCount(name);
 +    }
 +
 +    ctrl_name_table_t::iterator iter = mNameTable.find(name.data());
 +    return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second;
 +}
 +
 +
 +////////////////////////////////////////////////////////////////////////////
 +
 +// Must match the type definition in llcontrol.h
 +const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32"
 +                                                             ,"S32"
 +                                                             ,"F32"
 +                                                             ,"Boolean"
 +                                                             ,"String"
 +                                                             ,"Vector3"
 +                                                             ,"Vector3D"
 +                                                             ,"Quaternion"
 +                                                             ,"Rect"
 +                                                             ,"Color4"
 +                                                             ,"Color3"
 +                                                             ,"LLSD"
 +                                                             };
 +
 +LLControlGroup::LLControlGroup(const std::string& name)
 +:   LLInstanceTracker<LLControlGroup, std::string>(name),
 +    mSettingsProfile(false)
 +{
 +
 +    if (NULL != getenv("LL_SETTINGS_PROFILE"))
 +    {
 +        mSettingsProfile = true;
 +    }
 +}
 +
 +LLControlGroup::~LLControlGroup()
 +{
 +    cleanup();
 +}
 +
 +static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs)
 +{
 +    return lhs.second > rhs.second;
 +};
 +
 +void LLControlGroup::cleanup()
 +{
 +    if(mSettingsProfile && getCount.size() != 0)
 +    {
 +        std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE);
 +        LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */
 +        if(!out)
 +        {
 +            LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL;
 +        }
 +        else
 +        {
 +            F64 end_time = LLTimer::getTotalSeconds();
 +            U32 total_seconds = (U32)(end_time - start_time);
 +
 +            std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses   Avg. accesses/sec  Name\n", total_seconds);
 +            std::ostringstream data_msg;
 +
 +            data_msg << msg;
 +            size_t data_size = data_msg.str().size();
 +            if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size)
 +            {
 +                LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL;
 +            }
 +
 +            for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter)
 +            {
 +                getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger()));
 +            }
 +            sort(getCount_v.begin(), getCount_v.end(), compareRoutine);
 +
 +            for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter)
 +            {
 +                U32 access_rate = 0;
 +                if (total_seconds != 0)
 +                {
 +                    access_rate = iter->second / total_seconds;
 +                }
 +                if (access_rate >= 2)
 +                {
 +                    std::ostringstream data_msg;
 +                    msg = llformat("%13d        %7d       %s", iter->second, access_rate, iter->first.c_str());
 +                    data_msg << msg << "\n";
 +                    size_t data_size = data_msg.str().size();
 +                    if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size)
 +                    {
 +                        LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL;
 +                    }
 +                }
 +            }
 +            getCount = LLSD::emptyMap();
 +            fclose(out);
 +        }
 +    }
 +
 +    mNameTable.clear();
 +}
 +
 +eControlType LLControlGroup::typeStringToEnum(const std::string& typestr)
 +{
 +    for(int i = 0; i < (int)TYPE_COUNT; ++i)
 +    {
 +        if(mTypeString[i] == typestr) return (eControlType)i;
 +    }
 +    return (eControlType)-1;
 +}
 +
 +std::string LLControlGroup::typeEnumToString(eControlType typeenum)
 +{
 +    return mTypeString[typeenum];
 +}
 +
 +LLControlVariable* LLControlGroup::declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, bool hidefromsettingseditor)
 +{
 +    LLControlVariable* existing_control = getControl(name);
 +    if (existing_control)
 +    {
 +        if ((persist != LLControlVariable::PERSIST_NO) && existing_control->isType(type))
 +        {
 +            if (!existing_control->llsd_compare(existing_control->getDefault(), initial_val))
 +            {
 +                // Sometimes we need to declare a control *after* it has been loaded from a settings file.
 +                LLSD cur_value = existing_control->getValue(); // get the current value
 +                existing_control->setDefaultValue(initial_val); // set the default to the declared value
 +                existing_control->setValue(cur_value); // now set to the loaded value
 +            }
 +        }
 +        else
 +        {
 +            LL_WARNS("Settings") << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL;
 +        }
 +        return existing_control;
 +    }
 +
 +    // if not, create the control and add it to the name table
 +    LLControlVariable* control = new LLControlVariable(name, type, initial_val, comment, persist, hidefromsettingseditor);
 +    mNameTable[name] = control;
 +    return control;
 +}
 +
 +LLControlVariable* LLControlGroup::declareU32(const std::string& name, const U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_U32, (LLSD::Integer) initial_val, comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareS32(const std::string& name, const S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_S32, initial_val, comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareF32(const std::string& name, const F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_F32, initial_val, comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareBOOL(const std::string& name, const bool initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_BOOLEAN, initial_val, comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareString(const std::string& name, const std::string& initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_STRING, initial_val, comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareVec3(const std::string& name, const LLVector3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_VEC3, initial_val.getValue(), comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_VEC3D, initial_val.getValue(), comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_QUAT, initial_val.getValue(), comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist)
 +{
 +    return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist )
 +{
 +    return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist )
 +{
 +    return declareControl(name, TYPE_COL3, initial_val.getValue(), comment, persist);
 +}
 +
 +LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist )
 +{
 +    return declareControl(name, TYPE_LLSD, initial_val, comment, persist);
 +}
 +
 +void LLControlGroup::incrCount(std::string_view name)
 +{
 +    if (0.0 == start_time)
 +    {
 +        start_time = LLTimer::getTotalSeconds();
 +    }
 +    getCount[name.data()] = getCount[name.data()].asInteger() + 1;
 +}
 +
 +bool LLControlGroup::getBOOL(std::string_view name)
 +{
 +    return get<bool>(name);
 +}
 +
 +S32 LLControlGroup::getS32(std::string_view name)
 +{
 +    return get<S32>(name);
 +}
 +
 +U32 LLControlGroup::getU32(std::string_view name)
 +{
 +    return get<U32>(name);
 +}
 +
 +F32 LLControlGroup::getF32(std::string_view name)
 +{
 +    return get<F32>(name);
 +}
 +
 +std::string LLControlGroup::getString(std::string_view name)
 +{
 +    return get<std::string>(name);
 +}
 +
 +LLWString LLControlGroup::getWString(std::string_view name)
 +{
 +    return get<LLWString>(name);
 +}
 +
 +std::string LLControlGroup::getText(std::string_view name)
 +{
 +    std::string utf8_string = getString(name);
 +    LLStringUtil::replaceChar(utf8_string, '^', '\n');
 +    LLStringUtil::replaceChar(utf8_string, '%', ' ');
 +    return (utf8_string);
 +}
 +
 +LLVector3 LLControlGroup::getVector3(std::string_view name)
 +{
 +    return get<LLVector3>(name);
 +}
 +
 +LLVector3d LLControlGroup::getVector3d(std::string_view name)
 +{
 +    return get<LLVector3d>(name);
 +}
 +
 +LLQuaternion LLControlGroup::getQuaternion(std::string_view name)
 +{
 +    return get<LLQuaternion>(name);
 +}
 +
 +LLRect LLControlGroup::getRect(std::string_view name)
 +{
 +    return get<LLRect>(name);
 +}
 +
 +
 +LLColor4 LLControlGroup::getColor(std::string_view name)
 +{
 +    return get<LLColor4>(name);
 +}
 +
 +LLColor4 LLControlGroup::getColor4(std::string_view name)
 +{
 +    return get<LLColor4>(name);
 +}
 +
 +LLColor3 LLControlGroup::getColor3(std::string_view name)
 +{
 +    return get<LLColor3>(name);
 +}
 +
 +LLSD LLControlGroup::getLLSD(std::string_view name)
 +{
 +    return get<LLSD>(name);
 +}
 +
 +LLSD LLControlGroup::asLLSD(bool diffs_only)
 +{
 +    // Dump all stored values as LLSD
 +    LLSD result = LLSD::emptyArray();
 +    for (ctrl_name_table_t::iterator iter = mNameTable.begin();
 +         iter != mNameTable.end(); iter++)
 +    {
 +        LLControlVariable *control = iter->second;
 +        if (!control || control->isType(TYPE_STRING) || (diffs_only && control->isDefault()))
 +        {
 +            continue;
 +        }
 +        const std::string& name = iter->first;
 +        result[name] = getLLSD(name);
 +    }
 +    return result;
 +}
 +
 +bool LLControlGroup::controlExists(const std::string& name)
 +{
 +    ctrl_name_table_t::iterator iter = mNameTable.find(name);
 +    return iter != mNameTable.end();
 +}
 +
 +
 +//-------------------------------------------------------------------
 +// Set functions
 +//-------------------------------------------------------------------
 +
 +void LLControlGroup::setBOOL(std::string_view name, bool val)
 +{
 +    set<bool>(name, val);
 +}
 +
 +
 +void LLControlGroup::setS32(std::string_view name, S32 val)
 +{
 +    set(name, val);
 +}
 +
 +
 +void LLControlGroup::setF32(std::string_view name, F32 val)
 +{
 +    set(name, val);
 +}
 +
 +
 +void LLControlGroup::setU32(std::string_view name, U32 val)
 +{
 +    set(name, val);
 +}
 +
 +
 +void LLControlGroup::setString(std::string_view name, const std::string &val)
 +{
 +    set(name, val);
 +}
 +
 +
 +void LLControlGroup::setVector3(std::string_view name, const LLVector3 &val)
 +{
 +    set(name, val);
 +}
 +
 +void LLControlGroup::setVector3d(std::string_view name, const LLVector3d &val)
 +{
 +    set(name, val);
 +}
 +
 +void LLControlGroup::setQuaternion(std::string_view name, const LLQuaternion &val)
 +{
 +    set(name, val);
 +}
 +
 +void LLControlGroup::setRect(std::string_view name, const LLRect &val)
 +{
 +    set(name, val);
 +}
 +
 +void LLControlGroup::setColor4(std::string_view name, const LLColor4 &val)
 +{
 +    set(name, val);
 +}
 +
 +void LLControlGroup::setLLSD(std::string_view name, const LLSD& val)
 +{
 +    set(name, val);
 +}
 +
 +void LLControlGroup::setUntypedValue(std::string_view name, const LLSD& val)
 +{
 +    if (name.empty())
 +    {
 +        return;
 +    }
 +
 +    LLControlVariable* control = getControl(name);
 +
 +    if (control)
 +    {
 +        control->setValue(val);
 +    }
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid control " << name << LL_ENDL;
 +    }
 +}
 +
 +
 +//---------------------------------------------------------------
 +// Load and save
 +//---------------------------------------------------------------
 +
 +// Returns number of controls loaded, so 0 if failure
 +U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, bool require_declaration, eControlType declare_as)
 +{
 +    std::string name;
 +
 +    LLXmlTree xml_controls;
 +
 +    if (!xml_controls.parseFile(filename))
 +    {
 +        LL_WARNS("Settings") << "Unable to open control file " << filename << LL_ENDL;
 +        return 0;
 +    }
 +
 +    LLXmlTreeNode* rootp = xml_controls.getRoot();
 +    if (!rootp || !rootp->hasAttribute("version"))
 +    {
 +        LL_WARNS("Settings") << "No valid settings header found in control file " << filename << LL_ENDL;
 +        return 0;
 +    }
 +
 +    U32     validitems = 0;
 +    S32 version;
 +
 +    rootp->getAttributeS32("version", version);
 +
 +    // Check file version
 +    if (version != CURRENT_VERSION)
 +    {
 +        LL_INFOS("Settings") << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL;
 +        return 0;
 +    }
 +
 +    LLXmlTreeNode* child_nodep = rootp->getFirstChild();
 +    while(child_nodep)
 +    {
 +        name = child_nodep->getName();
 +
 +        bool declared = controlExists(name);
 +
 +        if (require_declaration && !declared)
 +        {
 +            // Declaration required, but this name not declared.
 +            // Complain about non-empty names.
 +            if (!name.empty())
 +            {
 +                //read in to end of line
 +                LL_WARNS("Settings") << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL;
 +            }
 +            child_nodep = rootp->getNextChild();
 +            continue;
 +        }
 +
 +        // Got an item.  Load it up.
 +        // If not declared, assume it's a string
 +        if (!declared)
 +        {
 +            switch(declare_as)
 +            {
 +            case TYPE_COL4:
 +                declareColor4(name, LLColor4::white, LLStringUtil::null, LLControlVariable::PERSIST_NO);
 +                break;
 +            case TYPE_STRING:
 +            default:
 +                declareString(name, LLStringUtil::null, LLStringUtil::null, LLControlVariable::PERSIST_NO);
 +                break;
 +            }
 +        }
 +
 +        // Control name has been declared in code.
 +        LLControlVariable *control = getControl(name);
 +
 +        llassert(control);
 +
 +        switch(control->mType)
 +        {
 +        case TYPE_F32:
 +            {
 +                F32 initial = 0.f;
 +
 +                child_nodep->getAttributeF32("value", initial);
 +
 +                control->set(initial);
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_S32:
 +            {
 +                S32 initial = 0;
 +
 +                child_nodep->getAttributeS32("value", initial);
 +
 +                control->set(initial);
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_U32:
 +            {
 +                U32 initial = 0;
 +                child_nodep->getAttributeU32("value", initial);
 +                control->set((LLSD::Integer) initial);
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_BOOLEAN:
 +            {
 +                bool initial = false;
 +
 +                child_nodep->getAttributeBOOL("value", initial);
 +                control->set(initial);
 +
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_STRING:
 +            {
 +                std::string string;
 +                child_nodep->getAttributeString("value", string);
 +                control->set(string);
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_VEC3:
 +            {
 +                LLVector3 vector;
 +
 +                child_nodep->getAttributeVector3("value", vector);
 +                control->set(vector.getValue());
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_VEC3D:
 +            {
 +                LLVector3d vector;
 +
 +                child_nodep->getAttributeVector3d("value", vector);
 +
 +                control->set(vector.getValue());
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_QUAT:
 +            {
 +                LLQuaternion quat;
 +
 +                child_nodep->getAttributeQuat("value", quat);
 +
 +                control->set(quat.getValue());
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_RECT:
 +            {
 +                //RN: hack to support reading rectangles from a string
 +                std::string rect_string;
 +
 +                child_nodep->getAttributeString("value", rect_string);
 +                std::istringstream istream(rect_string);
 +                S32 left, bottom, width, height;
 +
 +                istream >> left >> bottom >> width >> height;
 +
 +                LLRect rect;
 +                rect.setOriginAndSize(left, bottom, width, height);
 +
 +                control->set(rect.getValue());
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_COL4:
 +            {
 +                LLColor4 color;
 +
 +                child_nodep->getAttributeColor4("value", color);
 +                control->set(color.getValue());
 +                validitems++;
 +            }
 +            break;
 +        case TYPE_COL3:
 +            {
 +                LLVector3 color;
 +
 +                child_nodep->getAttributeVector3("value", color);
 +                control->set(LLColor3(color.mV).getValue());
 +                validitems++;
 +            }
 +            break;
 +
 +        default:
 +          break;
 +
 +        }
 +
 +        child_nodep = rootp->getNextChild();
 +    }
 +
 +    return validitems;
 +}
 +
 +U32 LLControlGroup::saveToFile(const std::string& filename, bool nondefault_only)
 +{
 +    LLSD settings;
 +    int num_saved = 0;
 +    for (ctrl_name_table_t::iterator iter = mNameTable.begin();
 +         iter != mNameTable.end(); iter++)
 +    {
 +        LLControlVariable* control = iter->second;
 +        if (!control)
 +        {
 +            LL_WARNS("Settings") << "Tried to save invalid control: " << iter->first << LL_ENDL;
 +        }
 +        else if( control->shouldSave(nondefault_only) )
 +        {
 +            settings[iter->first]["Type"] = typeEnumToString(control->type());
 +            settings[iter->first]["Comment"] = control->getComment();
 +            settings[iter->first]["Value"] = control->getSaveValue();
 +            ++num_saved;
 +        }
 +    }
 +    llofstream file;
 +    file.open(filename.c_str());
 +    if (file.is_open())
 +    {
 +        LLSDSerialize::toPrettyXML(settings, file);
 +        file.close();
 +        LL_INFOS("Settings") << "Saved to " << filename << LL_ENDL;
 +    }
 +    else
 +    {
 +        // This is a warning because sometime we want to use settings files which can't be written...
 +        LL_WARNS("Settings") << "Unable to open settings file: " << filename << LL_ENDL;
 +        return 0;
 +    }
 +    return num_saved;
 +}
 +
 +U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values)
 +{
 +    LLSD settings;
 +    llifstream infile;
 +    infile.open(filename.c_str());
 +    if(!infile.is_open())
 +    {
 +        LL_WARNS("Settings") << "Cannot find file " << filename << " to load." << LL_ENDL;
 +        return 0;
 +    }
 +
 +    if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(settings, infile))
 +    {
 +        infile.close();
 +        LL_WARNS("Settings") << "Unable to parse LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL;
 +        return loadFromFileLegacy(filename, true, TYPE_STRING);
 +    }
 +
 +    U32 validitems = 0;
 +    bool hidefromsettingseditor = false;
 +
 +    for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr)
 +    {
 +        LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT;
 +        std::string const & name = itr->first;
 +        LLSD const & control_map = itr->second;
 +
 +        if(control_map.has("Persist"))
 +        {
 +            persist = control_map["Persist"].asInteger()?
 +                      LLControlVariable::PERSIST_NONDFT : LLControlVariable::PERSIST_NO;
 +        }
 +
 +        // Sometimes we want to use the settings system to provide cheap persistence, but we
 +        // don't want the settings themselves to be easily manipulated in the UI because
 +        // doing so can cause support problems. So we have this option:
 +        if(control_map.has("HideFromEditor"))
 +        {
 +            hidefromsettingseditor = control_map["HideFromEditor"].asInteger();
 +        }
 +        else
 +        {
 +            hidefromsettingseditor = false;
 +        }
 +
 +        // If the control exists just set the value from the input file.
 +        LLControlVariable* existing_control = getControl(name);
 +        if(existing_control)
 +        {
 +            // set_default_values is true when we're loading the initial,
 +            // immutable files from app_settings, e.g. settings.xml.
 +            if(set_default_values)
 +            {
 +                // Override all previously set properties of this control.
 +                // ... except for type. The types must match.
 +                eControlType new_type = typeStringToEnum(control_map["Type"].asString());
 +                if(existing_control->isType(new_type))
 +                {
 +                    existing_control->setDefaultValue(control_map["Value"]);
 +                    existing_control->setPersist(persist);
 +                    existing_control->setHiddenFromSettingsEditor(hidefromsettingseditor);
 +                    existing_control->setComment(control_map["Comment"].asString());
 +                }
 +                else
 +                {
 +                    LL_ERRS() << "Mismatched type of control variable '"
 +                           << name << "' found while loading '"
 +                           << filename << "'." << LL_ENDL;
 +                }
 +            }
 +            else if(existing_control->isPersisted())
 +            {
 +                // save_values is specifically false for (e.g.)
 +                // SessionSettingsFile and UserSessionSettingsFile -- in other
 +                // words, for a file that's supposed to be transient.
 +                existing_control->setValue(control_map["Value"], save_values);
 +            }
 +            // *NOTE: If not persisted and not setting defaults,
 +            // the value should not get loaded.
 +        }
 +        else
 +        {
 +            // We've never seen this control before. Either we're loading up
 +            // the initial set of default settings files (set_default_values)
 +            // -- or we're loading user settings last saved by a viewer that
 +            // supports a superset of the variables we know.
 +            // CHOP-962: if we're loading an unrecognized user setting, make
 +            // sure we save it later. If you try an experimental viewer, tweak
 +            // a new setting, briefly revert to an old viewer, then return to
 +            // the new one, we don't want the old viewer to discard the
 +            // setting you changed.
 +            if (! set_default_values)
 +            {
 +                // Using PERSIST_ALWAYS insists that saveToFile() (which calls
 +                // LLControlVariable::shouldSave()) must save this control
 +                // variable regardless of its value. We can safely set this
 +                // LLControlVariable persistent because the 'persistent' flag
 +                // is not itself persisted!
 +                persist = LLControlVariable::PERSIST_ALWAYS;
 +                // We want to mention unrecognized user settings variables
 +                // (e.g. from a newer version of the viewer) in the log. But
 +                // we also arrive here for Boolean variables generated by
 +                // the notifications subsystem when the user checks "Don't
 +                // show me this again." These aren't declared in settings.xml;
 +                // they're actually named for the notification they suppress.
 +                // We don't want to mention those. Apologies, this is a bit of
 +                // a hack: we happen to know that user settings go into an
 +                // LLControlGroup whose name is "Global".
 +                if (getKey() == "Global")
 +                {
 +                    LL_INFOS("LLControlGroup") << "preserving unrecognized " << getKey()
 +                                               << " settings variable " << name << LL_ENDL;
 +                }
 +            }
 +
 +            declareControl(name,
 +                           typeStringToEnum(control_map["Type"].asString()),
 +                           control_map["Value"],
 +                           control_map["Comment"].asString(),
 +                           persist,
 +                           hidefromsettingseditor
 +                           );
 +        }
 +
 +        ++validitems;
 +    }
 +
 +    LL_DEBUGS("Settings") << "Loaded " << validitems << " settings from " << filename << LL_ENDL;
 +    return validitems;
 +}
 +
 +void LLControlGroup::resetToDefaults()
 +{
 +    ctrl_name_table_t::iterator control_iter;
 +    for (control_iter = mNameTable.begin();
 +        control_iter != mNameTable.end();
 +        ++control_iter)
 +    {
 +        LLControlVariable* control = (*control_iter).second;
 +        control->resetToDefault();
 +    }
 +}
 +
 +void LLControlGroup::applyToAll(ApplyFunctor* func)
 +{
 +    for (ctrl_name_table_t::iterator iter = mNameTable.begin();
 +         iter != mNameTable.end(); iter++)
 +    {
 +        func->apply(iter->first, iter->second);
 +    }
 +}
 +
 +//============================================================================
 +
 +#ifdef TEST_HARNESS
 +void main()
 +{
 +    F32_CONTROL foo, getfoo;
 +
 +    S32_CONTROL bar, getbar;
 +
 +    BOOL_CONTROL baz;
 +
 +    U32 count = gGlobals.loadFromFile("controls.ini");
 +    LL_INFOS("Settings") << "Loaded " << count << " controls" << LL_ENDL;
 +
 +    // test insertion
 +    foo = new LLControlVariable<F32>("gFoo", 5.f, 1.f, 20.f);
 +    gGlobals.addEntry("gFoo", foo);
 +
 +    bar = new LLControlVariable<S32>("gBar", 10, 2, 22);
 +    gGlobals.addEntry("gBar", bar);
 +
 +    baz = new LLControlVariable<bool>("gBaz", false);
 +    gGlobals.addEntry("gBaz", baz);
 +
 +    // test retrieval
 +    getfoo = (LLControlVariable<F32>*) gGlobals.resolveName("gFoo");
 +    getfoo->dump();
 +
 +    getbar = (S32_CONTROL) gGlobals.resolveName("gBar");
 +    getbar->dump();
 +
 +    // change data
 +    getfoo->set(10.f);
 +    getfoo->dump();
 +
 +    // Failure modes
 +
 +    // ...min > max
 +    // badfoo = new LLControlVariable<F32>("gFoo2", 100.f, 20.f, 5.f);
 +
 +    // ...initial > max
 +    // badbar = new LLControlVariable<S32>("gBar2", 10, 20, 100000);
 +
 +    // ...misspelled name
 +    // getfoo = (F32_CONTROL) gGlobals.resolveName("fooMisspelled");
 +    // getfoo->dump();
 +
 +    // ...invalid data type
 +    getfoo = (F32_CONTROL) gGlobals.resolveName("gFoo");
 +    getfoo->set(true);
 +    getfoo->dump();
 +
 +    // ...out of range data
 +    // getfoo->set(100000000.f);
 +    // getfoo->dump();
 +
 +    // Clean Up
 +    delete foo;
 +    delete bar;
 +    delete baz;
 +}
 +#endif
 +
 +
 +template <> eControlType get_control_type<U32>()
 +{
 +    return TYPE_U32;
 +}
 +
 +template <> eControlType get_control_type<S32>()
 +{
 +    return TYPE_S32;
 +}
 +
 +template <> eControlType get_control_type<F32>()
 +{
 +    return TYPE_F32;
 +}
 +
 +template <> eControlType get_control_type<bool> ()
 +{
 +    return TYPE_BOOLEAN;
 +}
 +
 +template <> eControlType get_control_type<std::string>()
 +{
 +    return TYPE_STRING;
 +}
 +
 +template <> eControlType get_control_type<LLVector3>()
 +{
 +    return TYPE_VEC3;
 +}
 +
 +template <> eControlType get_control_type<LLVector3d>()
 +{
 +    return TYPE_VEC3D;
 +}
 +
 +template <> eControlType get_control_type<LLQuaternion>()
 +{
 +    return TYPE_QUAT;
 +}
 +
 +template <> eControlType get_control_type<LLRect>()
 +{
 +    return TYPE_RECT;
 +}
 +
 +template <> eControlType get_control_type<LLColor4>()
 +{
 +    return TYPE_COL4;
 +}
 +
 +template <> eControlType get_control_type<LLColor3>()
 +{
 +    return TYPE_COL3;
 +}
 +
 +template <> eControlType get_control_type<LLSD>()
 +{
 +    return TYPE_LLSD;
 +}
 +
 +
 +template <> LLSD convert_to_llsd<U32>(const U32& in)
 +{
 +    return (LLSD::Integer)in;
 +}
 +
 +template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in)
 +{
 +    return in.getValue();
 +}
 +
 +template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in)
 +{
 +    return in.getValue();
 +}
 +template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in)
 +{
 +    return in.getValue();
 +}
 +
 +template <> LLSD convert_to_llsd<LLRect>(const LLRect& in)
 +{
 +    return in.getValue();
 +}
 +
 +template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in)
 +{
 +    return in.getValue();
 +}
 +
 +template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in)
 +{
 +    return in.getValue();
 +}
 +
 +template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in)
 +{
 +    return in.getValue();
 +}
 +
 +
 +template<>
 +bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_BOOLEAN)
 +        return sd.asBoolean();
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid bool value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return false;
 +    }
 +}
 +
 +template<>
 +S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_S32)
 +        return sd.asInteger();
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return 0;
 +    }
 +}
 +
 +template<>
 +U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_U32)
 +        return sd.asInteger();
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return 0;
 +    }
 +}
 +
 +template<>
 +F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_F32)
 +        return (F32) sd.asReal();
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return 0.0f;
 +    }
 +}
 +
 +template<>
 +std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_STRING)
 +        return sd.asString();
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid string value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return LLStringUtil::null;
 +    }
 +}
 +
 +template<>
 +LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    return utf8str_to_wstring(convert_from_llsd<std::string>(sd, type, control_name));
 +}
 +
 +template<>
 +LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_VEC3)
 +        return (LLVector3)sd;
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return LLVector3::zero;
 +    }
 +}
 +
 +template<>
 +LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_VEC3D)
 +        return (LLVector3d)sd;
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return LLVector3d::zero;
 +    }
 +}
 +
 +template<>
 +LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_QUAT)
 +        return (LLQuaternion)sd;
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid LLQuaternion value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return LLQuaternion();
 +    }
 +}
 +
 +template<>
 +LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_RECT)
 +        return LLRect(sd);
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return LLRect::null;
 +    }
 +}
 +
 +
 +template<>
 +LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_COL4)
 +    {
 +        LLColor4 color(sd);
 +        if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
 +        {
 +            LL_WARNS("Settings") << "Color " << control_name << " red value out of range: " << color << LL_ENDL;
 +        }
 +        else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
 +        {
 +            LL_WARNS("Settings") << "Color " << control_name << " green value out of range: " << color << LL_ENDL;
 +        }
 +        else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
 +        {
 +            LL_WARNS("Settings") << "Color " << control_name << " blue value out of range: " << color << LL_ENDL;
 +        }
 +        else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
 +        {
 +            LL_WARNS("Settings") << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL;
 +        }
 +
 +        return LLColor4(sd);
 +    }
 +    else
 +    {
 +        CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL;
 +        return LLColor4::white;
 +    }
 +}
 +
 +template<>
 +LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    if (type == TYPE_COL3)
 +        return sd;
 +    else
 +    {
 +        CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << LLControlGroup::typeEnumToString(type) << " " << sd << LL_ENDL;
 +        return LLColor3::white;
 +    }
 +}
 +
 +template<>
 +LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    return sd;
 +}
 +
 +
 +#if TEST_CACHED_CONTROL
 +
 +#define DECL_LLCC(T, V) static LLCachedControl<T> mySetting_##T("TestCachedControl"#T, V)
 +DECL_LLCC(U32, (U32)666);
 +DECL_LLCC(S32, (S32)-666);
 +DECL_LLCC(F32, (F32)-666.666);
 +DECL_LLCC(bool, true);
 +static LLCachedControl<std::string> mySetting_string("TestCachedControlstring", "Default String Value");
 +DECL_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f));
 +DECL_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f));
 +DECL_LLCC(LLRect, LLRect(0, 0, 100, 500));
 +DECL_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f));
 +DECL_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
 +DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
 +
 +LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"];
 +DECL_LLCC(LLSD, test_llsd);
 +
 +void test_cached_control()
 +{
 +#define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL
 +    TEST_LLCC(U32, 666);
 +    TEST_LLCC(S32, (S32)-666);
 +    TEST_LLCC(F32, (F32)-666.666);
 +    TEST_LLCC(bool, true);
 +    if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL;
 +    TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f));
 +    TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f));
 +    TEST_LLCC(LLRect, LLRect(0, 0, 100, 500));
 +    TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f));
 +    TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
 +    TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
 +//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd);
 +}
 +#endif // TEST_CACHED_CONTROL
 +
 diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index a8bc584c48..f542745b44 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -1,474 +1,474 @@ -/**  - * @file llcontrol.h - * @brief A mechanism for storing "control state" for a program - * - * $LicenseInfo:firstyear=2001&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_LLCONTROL_H -#define LL_LLCONTROL_H - -#include "llboost.h" -#include "llevent.h" -#include "llstring.h" -#include "llrect.h" -#include "llrefcount.h" -#include "llinstancetracker.h" - -#include <vector> - -// *NOTE: boost::visit_each<> generates warning 4675 on .net 2003 -// Disable the warning for the boost includes. -#if LL_WINDOWS -# if (_MSC_VER >= 1300 && _MSC_VER < 1400) -#   pragma warning(push) -#   pragma warning( disable : 4675 ) -# endif -#endif - -#include <boost/bind.hpp> - -#if LL_WINDOWS -	#pragma warning (push) -	#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch -	#pragma warning (disable : 4264)  -#endif -#include <boost/signals2.hpp> -#if LL_WINDOWS -	#pragma warning (pop) -#endif - -#if LL_WINDOWS -# if (_MSC_VER >= 1300 && _MSC_VER < 1400) -#   pragma warning(pop) -# endif -#endif - -class LLVector3; -class LLVector3d; -class LLQuaternion; -class LLColor4; -class LLColor3; - -// if this is changed, also modify mTypeString in llcontrol.h -typedef enum e_control_type -{ -	TYPE_U32 = 0, -	TYPE_S32, -	TYPE_F32, -	TYPE_BOOLEAN, -	TYPE_STRING, -	TYPE_VEC3, -	TYPE_VEC3D, -	TYPE_QUAT, -	TYPE_RECT, -	TYPE_COL4, -	TYPE_COL3, -	TYPE_LLSD, -	TYPE_COUNT -} eControlType; - -class LLControlVariable : public LLRefCount -{ -	LOG_CLASS(LLControlVariable); - -	friend class LLControlGroup; -	 -public: -	typedef boost::signals2::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t; -	typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&, const LLSD&)> commit_signal_t; - -	enum ePersist -	{ -		PERSIST_NO,                 // don't save this var -		PERSIST_NONDFT,             // save this var if differs from default -		PERSIST_ALWAYS              // save this var even if has default value -	}; - -private: -	std::string		mName; -	std::string		mComment; -	eControlType	mType; -	ePersist		mPersist; -	bool			mHideFromSettingsEditor; -	std::vector<LLSD> mValues; - -	commit_signal_t mCommitSignal; -	validate_signal_t mValidateSignal; -	 -public: -	LLControlVariable(const std::string& name, eControlType type, -					  LLSD initial, const std::string& comment, -					  ePersist persist = PERSIST_NONDFT, bool hidefromsettingseditor = false); - -	virtual ~LLControlVariable(); -	 -	const std::string& getName() const { return mName; } -	const std::string& getComment() const { return mComment; } - -	eControlType type()		{ return mType; } -	bool isType(eControlType tp) { return tp == mType; } - -	void resetToDefault(bool fire_signal = false); - -	commit_signal_t* getSignal() { return &mCommitSignal; } // shorthand for commit signal -	commit_signal_t* getCommitSignal() { return &mCommitSignal; } -	validate_signal_t* getValidateSignal() { return &mValidateSignal; } - -	bool isDefault() { return (mValues.size() == 1); } -	bool shouldSave(bool nondefault_only); -	bool isPersisted() { return mPersist != PERSIST_NO; } -	bool isHiddenFromSettingsEditor() { return mHideFromSettingsEditor; } -	LLSD get()			const	{ return getValue(); } -	LLSD getValue()		const	{ return mValues.back(); } -	LLSD getDefault()	const	{ return mValues.front(); } -	LLSD getSaveValue() const; - -	void set(const LLSD& val)	{ setValue(val); } -	void setValue(const LLSD& value, bool saved_value = true); -	void setDefaultValue(const LLSD& value); -	void setPersist(ePersist); -	void setHiddenFromSettingsEditor(bool hide); -	void setComment(const std::string& comment); - -private: -	void firePropertyChanged(const LLSD &pPreviousValue) -	{ -		mCommitSignal(this, mValues.back(), pPreviousValue); -	} -	LLSD getComparableValue(const LLSD& value); -	bool llsd_compare(const LLSD& a, const LLSD & b); -}; - -typedef LLPointer<LLControlVariable> LLControlVariablePtr; - -//! Helper functions for converting between static types and LLControl values -template <class T>  -eControlType get_control_type() -{ -	LL_WARNS() << "Usupported control type: " << typeid(T).name() << "." << LL_ENDL; -	return TYPE_COUNT; -} - -template <class T>  -LLSD convert_to_llsd(const T& in) -{ -	// default implementation -	return LLSD(in); -} - -template <class T> -T convert_from_llsd(const LLSD& sd, eControlType type, std::string_view control_name) -{ -	// needs specialization -	return T(sd); -} - -//const U32 STRING_CACHE_SIZE = 10000; -class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string> -{ -	LOG_CLASS(LLControlGroup); - -protected: -	typedef std::map<std::string, LLControlVariablePtr > ctrl_name_table_t; -	ctrl_name_table_t mNameTable; -	static const std::string mTypeString[TYPE_COUNT]; - -public: -	static eControlType typeStringToEnum(const std::string& typestr); -	static std::string typeEnumToString(eControlType typeenum);	 - -	LLControlGroup(const std::string& name); -	~LLControlGroup(); -	void cleanup(); - -	LLControlVariablePtr getControl(std::string_view name); - -	struct ApplyFunctor -	{ -		virtual ~ApplyFunctor() {}; -		virtual void apply(const std::string& name, LLControlVariable* control) = 0; -	}; -	void applyToAll(ApplyFunctor* func); - -	LLControlVariable* declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, bool hidefromsettingseditor = false); -	LLControlVariable* declareU32(const std::string& name, U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareS32(const std::string& name, S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareF32(const std::string& name, F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareBOOL(const std::string& name, bool initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment,  LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); -	LLControlVariable* declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT); - -	std::string getString(std::string_view name); -	std::string getText(std::string_view name); -	bool		getBOOL(std::string_view name); -	S32			getS32(std::string_view name); -	F32			getF32(std::string_view name); -	U32			getU32(std::string_view name); -	 -	LLWString	getWString(std::string_view name); -	LLVector3	getVector3(std::string_view name); -	LLVector3d	getVector3d(std::string_view name); -	LLRect		getRect(std::string_view name); -	LLSD        getLLSD(std::string_view name); -	LLQuaternion	getQuaternion(std::string_view name); - -	LLColor4	getColor(std::string_view name); -	LLColor4	getColor4(std::string_view name); -	LLColor3	getColor3(std::string_view name); - -	LLSD		asLLSD(bool diffs_only); -	 -	// generic getter -	template<typename T> T get(std::string_view name) -	{ -        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; -		LLControlVariable* control = getControl(name); -		LLSD value; -		eControlType type = TYPE_COUNT; - -		if (control)		 -		{ -			value = control->get(); -			type = control->type(); -		} -		else -		{ -			LL_WARNS() << "Control " << name << " not found." << LL_ENDL; -			return T(); -		} -		return convert_from_llsd<T>(value, type, name); -	} - -	void	setBOOL(std::string_view name, bool val); -	void	setS32(std::string_view name, S32 val); -	void	setF32(std::string_view name, F32 val); -	void	setU32(std::string_view name, U32 val); -	void	setString(std::string_view  name, const std::string& val); -	void	setVector3(std::string_view name, const LLVector3 &val); -	void	setVector3d(std::string_view name, const LLVector3d &val); -	void	setQuaternion(std::string_view name, const LLQuaternion &val); -	void	setRect(std::string_view name, const LLRect &val); -	void	setColor4(std::string_view name, const LLColor4 &val); -	void    setLLSD(std::string_view name, const LLSD& val); - -	// type agnostic setter that takes LLSD -	void	setUntypedValue(std::string_view name, const LLSD& val); - -	// generic setter -	template<typename T> void set(std::string_view name, const T& val) -	{ -		LLControlVariable* control = getControl(name); -	 -		if (control && control->isType(get_control_type<T>())) -		{ -			control->set(convert_to_llsd(val)); -		} -		else -		{ -			LL_WARNS() << "Invalid control " << name << LL_ENDL; -		} -	} -	 -	bool    controlExists(const std::string& name); - -	// Returns number of controls loaded, 0 if failed -	// If require_declaration is false, will auto-declare controls it finds -	// as the given type. -	U32	loadFromFileLegacy(const std::string& filename, bool require_declaration = true, eControlType declare_as = TYPE_STRING); - 	U32 saveToFile(const std::string& filename, bool nondefault_only); - 	U32	loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true); -	void	resetToDefaults(); -	void	incrCount(std::string_view name); - -	bool	mSettingsProfile; -}; - - -//! Publish/Subscribe object to interact with LLControlGroups. - -//! Use an LLCachedControl instance to connect to a LLControlVariable -//! without have to manually create and bind a listener to a local -//! object. -template <class T> -class LLControlCache : public LLRefCount, public LLInstanceTracker<LLControlCache<T>, std::string> -{ -public: -	// This constructor will declare a control if it doesn't exist in the contol group -	LLControlCache(LLControlGroup& group, -					const std::string& name,  -					const T& default_value,  -					const std::string& comment) -	:	LLInstanceTracker<LLControlCache<T>, std::string >(name) -	{ -		if(!group.controlExists(name)) -		{ -			if(!declareTypedControl(group, name, default_value, comment)) -			{ -				LL_ERRS() << "The control could not be created!!!" << LL_ENDL; -			} -		} - -		bindToControl(group, name); -	} - -	LLControlCache(LLControlGroup& group, -					const std::string& name) -	:	LLInstanceTracker<LLControlCache<T>, std::string >(name) -	{ -		if(!group.controlExists(name)) -		{ -			LL_ERRS() << "Control named " << name << "not found." << LL_ENDL; -		} - -		bindToControl(group, name); -	} - -	~LLControlCache() -	{ -	} - -	const T& getValue() const { return mCachedValue; } -	 -private: -	void bindToControl(LLControlGroup& group, const std::string& name) -	{ -		LLControlVariablePtr controlp = group.getControl(name); -		mType = controlp->type(); -		mCachedValue = convert_from_llsd<T>(controlp->get(), mType, name); - -		// Add a listener to the controls signal... -		// NOTE: All listeners connected to 0 group, for guaranty that variable handlers (gSavedSettings) call last -		mConnection = controlp->getSignal()->connect(0, -			boost::bind(&LLControlCache<T>::handleValueChange, this, _2) -			); -		mType = controlp->type(); -	} -	bool declareTypedControl(LLControlGroup& group, -							const std::string& name,  -							 const T& default_value, -							 const std::string& comment) -	{ -		LLSD init_value; -		eControlType type = get_control_type<T>(); -		init_value = convert_to_llsd(default_value); -		if(type < TYPE_COUNT) -		{ -			group.declareControl(name, type, init_value, comment, LLControlVariable::PERSIST_NO); -			return true; -		} -		return false; -	} - -	bool handleValueChange(const LLSD& newvalue) -	{ -		mCachedValue = convert_from_llsd<T>(newvalue, mType, ""); -		return true; -	} - -private: -    T							mCachedValue; -	eControlType				mType; -    boost::signals2::scoped_connection	mConnection; -}; - -template <typename T> -class LLCachedControl -{ -public: -	LLCachedControl(LLControlGroup& group, -					const std::string& name, -					const T& default_value,  -					const std::string& comment = "Declared In Code") -	{ -		mCachedControlPtr = LLControlCache<T>::getInstance(name).get(); -		if (! mCachedControlPtr) -		{ -			mCachedControlPtr = new LLControlCache<T>(group, name, default_value, comment); -		} -	} - -	LLCachedControl(LLControlGroup& group, -					const std::string& name) -	{ -		mCachedControlPtr = LLControlCache<T>::getInstance(name).get(); -		if (! mCachedControlPtr) -		{ -			mCachedControlPtr = new LLControlCache<T>(group, name); -		} -	} - -	operator const T&() const { return mCachedControlPtr->getValue(); } -	operator boost::function<const T&()> () const { return boost::function<const T&()>(*this); } -	const T& operator()() { return mCachedControlPtr->getValue(); } - -private: -	LLPointer<LLControlCache<T> > mCachedControlPtr; -}; - -template <> eControlType get_control_type<U32>(); -template <> eControlType get_control_type<S32>(); -template <> eControlType get_control_type<F32>(); -template <> eControlType get_control_type<bool>();  -template <> eControlType get_control_type<std::string>(); -template <> eControlType get_control_type<LLVector3>(); -template <> eControlType get_control_type<LLVector3d>(); -template <> eControlType get_control_type<LLQuaternion>(); -template <> eControlType get_control_type<LLRect>(); -template <> eControlType get_control_type<LLColor4>(); -template <> eControlType get_control_type<LLColor3>(); -template <> eControlType get_control_type<LLSD>(); - -template <> LLSD convert_to_llsd<U32>(const U32& in); -template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in); -template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in); -template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in); -template <> LLSD convert_to_llsd<LLRect>(const LLRect& in); -template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in); -template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in); - -template<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name); -template<> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name); - -//#define TEST_CACHED_CONTROL 1 -#ifdef TEST_CACHED_CONTROL -void test_cached_control(); -#endif // TEST_CACHED_CONTROL - -#endif +/**
 + * @file llcontrol.h
 + * @brief A mechanism for storing "control state" for a program
 + *
 + * $LicenseInfo:firstyear=2001&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_LLCONTROL_H
 +#define LL_LLCONTROL_H
 +
 +#include "llboost.h"
 +#include "llevent.h"
 +#include "llstring.h"
 +#include "llrect.h"
 +#include "llrefcount.h"
 +#include "llinstancetracker.h"
 +
 +#include <vector>
 +
 +// *NOTE: boost::visit_each<> generates warning 4675 on .net 2003
 +// Disable the warning for the boost includes.
 +#if LL_WINDOWS
 +# if (_MSC_VER >= 1300 && _MSC_VER < 1400)
 +#   pragma warning(push)
 +#   pragma warning( disable : 4675 )
 +# endif
 +#endif
 +
 +#include <boost/bind.hpp>
 +
 +#if LL_WINDOWS
 +    #pragma warning (push)
 +    #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
 +    #pragma warning (disable : 4264)
 +#endif
 +#include <boost/signals2.hpp>
 +#if LL_WINDOWS
 +    #pragma warning (pop)
 +#endif
 +
 +#if LL_WINDOWS
 +# if (_MSC_VER >= 1300 && _MSC_VER < 1400)
 +#   pragma warning(pop)
 +# endif
 +#endif
 +
 +class LLVector3;
 +class LLVector3d;
 +class LLQuaternion;
 +class LLColor4;
 +class LLColor3;
 +
 +// if this is changed, also modify mTypeString in llcontrol.h
 +typedef enum e_control_type
 +{
 +    TYPE_U32 = 0,
 +    TYPE_S32,
 +    TYPE_F32,
 +    TYPE_BOOLEAN,
 +    TYPE_STRING,
 +    TYPE_VEC3,
 +    TYPE_VEC3D,
 +    TYPE_QUAT,
 +    TYPE_RECT,
 +    TYPE_COL4,
 +    TYPE_COL3,
 +    TYPE_LLSD,
 +    TYPE_COUNT
 +} eControlType;
 +
 +class LLControlVariable : public LLRefCount
 +{
 +    LOG_CLASS(LLControlVariable);
 +
 +    friend class LLControlGroup;
 +
 +public:
 +    typedef boost::signals2::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t;
 +    typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&, const LLSD&)> commit_signal_t;
 +
 +    enum ePersist
 +    {
 +        PERSIST_NO,                 // don't save this var
 +        PERSIST_NONDFT,             // save this var if differs from default
 +        PERSIST_ALWAYS              // save this var even if has default value
 +    };
 +
 +private:
 +    std::string     mName;
 +    std::string     mComment;
 +    eControlType    mType;
 +    ePersist        mPersist;
 +    bool            mHideFromSettingsEditor;
 +    std::vector<LLSD> mValues;
 +
 +    commit_signal_t mCommitSignal;
 +    validate_signal_t mValidateSignal;
 +
 +public:
 +    LLControlVariable(const std::string& name, eControlType type,
 +                      LLSD initial, const std::string& comment,
 +                      ePersist persist = PERSIST_NONDFT, bool hidefromsettingseditor = false);
 +
 +    virtual ~LLControlVariable();
 +
 +    const std::string& getName() const { return mName; }
 +    const std::string& getComment() const { return mComment; }
 +
 +    eControlType type()     { return mType; }
 +    bool isType(eControlType tp) { return tp == mType; }
 +
 +    void resetToDefault(bool fire_signal = false);
 +
 +    commit_signal_t* getSignal() { return &mCommitSignal; } // shorthand for commit signal
 +    commit_signal_t* getCommitSignal() { return &mCommitSignal; }
 +    validate_signal_t* getValidateSignal() { return &mValidateSignal; }
 +
 +    bool isDefault() { return (mValues.size() == 1); }
 +    bool shouldSave(bool nondefault_only);
 +    bool isPersisted() { return mPersist != PERSIST_NO; }
 +    bool isHiddenFromSettingsEditor() { return mHideFromSettingsEditor; }
 +    LLSD get()          const   { return getValue(); }
 +    LLSD getValue()     const   { return mValues.back(); }
 +    LLSD getDefault()   const   { return mValues.front(); }
 +    LLSD getSaveValue() const;
 +
 +    void set(const LLSD& val)   { setValue(val); }
 +    void setValue(const LLSD& value, bool saved_value = true);
 +    void setDefaultValue(const LLSD& value);
 +    void setPersist(ePersist);
 +    void setHiddenFromSettingsEditor(bool hide);
 +    void setComment(const std::string& comment);
 +
 +private:
 +    void firePropertyChanged(const LLSD &pPreviousValue)
 +    {
 +        mCommitSignal(this, mValues.back(), pPreviousValue);
 +    }
 +    LLSD getComparableValue(const LLSD& value);
 +    bool llsd_compare(const LLSD& a, const LLSD & b);
 +};
 +
 +typedef LLPointer<LLControlVariable> LLControlVariablePtr;
 +
 +//! Helper functions for converting between static types and LLControl values
 +template <class T>
 +eControlType get_control_type()
 +{
 +    LL_WARNS() << "Usupported control type: " << typeid(T).name() << "." << LL_ENDL;
 +    return TYPE_COUNT;
 +}
 +
 +template <class T>
 +LLSD convert_to_llsd(const T& in)
 +{
 +    // default implementation
 +    return LLSD(in);
 +}
 +
 +template <class T>
 +T convert_from_llsd(const LLSD& sd, eControlType type, std::string_view control_name)
 +{
 +    // needs specialization
 +    return T(sd);
 +}
 +
 +//const U32 STRING_CACHE_SIZE = 10000;
 +class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
 +{
 +    LOG_CLASS(LLControlGroup);
 +
 +protected:
 +    typedef std::map<std::string, LLControlVariablePtr > ctrl_name_table_t;
 +    ctrl_name_table_t mNameTable;
 +    static const std::string mTypeString[TYPE_COUNT];
 +
 +public:
 +    static eControlType typeStringToEnum(const std::string& typestr);
 +    static std::string typeEnumToString(eControlType typeenum);
 +
 +    LLControlGroup(const std::string& name);
 +    ~LLControlGroup();
 +    void cleanup();
 +
 +    LLControlVariablePtr getControl(std::string_view name);
 +
 +    struct ApplyFunctor
 +    {
 +        virtual ~ApplyFunctor() {};
 +        virtual void apply(const std::string& name, LLControlVariable* control) = 0;
 +    };
 +    void applyToAll(ApplyFunctor* func);
 +
 +    LLControlVariable* declareControl(const std::string& name, eControlType type, const LLSD initial_val, const std::string& comment, LLControlVariable::ePersist persist, bool hidefromsettingseditor = false);
 +    LLControlVariable* declareU32(const std::string& name, U32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareS32(const std::string& name, S32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareF32(const std::string& name, F32 initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareBOOL(const std::string& name, bool initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareString(const std::string& name, const std::string &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment,  LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareQuat(const std::string& name, const LLQuaternion &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +    LLControlVariable* declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, LLControlVariable::ePersist persist = LLControlVariable::PERSIST_NONDFT);
 +
 +    std::string getString(std::string_view name);
 +    std::string getText(std::string_view name);
 +    bool        getBOOL(std::string_view name);
 +    S32         getS32(std::string_view name);
 +    F32         getF32(std::string_view name);
 +    U32         getU32(std::string_view name);
 +
 +    LLWString   getWString(std::string_view name);
 +    LLVector3   getVector3(std::string_view name);
 +    LLVector3d  getVector3d(std::string_view name);
 +    LLRect      getRect(std::string_view name);
 +    LLSD        getLLSD(std::string_view name);
 +    LLQuaternion    getQuaternion(std::string_view name);
 +
 +    LLColor4    getColor(std::string_view name);
 +    LLColor4    getColor4(std::string_view name);
 +    LLColor3    getColor3(std::string_view name);
 +
 +    LLSD        asLLSD(bool diffs_only);
 +
 +    // generic getter
 +    template<typename T> T get(std::string_view name)
 +    {
 +        LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
 +        LLControlVariable* control = getControl(name);
 +        LLSD value;
 +        eControlType type = TYPE_COUNT;
 +
 +        if (control)
 +        {
 +            value = control->get();
 +            type = control->type();
 +        }
 +        else
 +        {
 +            LL_WARNS() << "Control " << name << " not found." << LL_ENDL;
 +            return T();
 +        }
 +        return convert_from_llsd<T>(value, type, name);
 +    }
 +
 +    void    setBOOL(std::string_view name, bool val);
 +    void    setS32(std::string_view name, S32 val);
 +    void    setF32(std::string_view name, F32 val);
 +    void    setU32(std::string_view name, U32 val);
 +    void    setString(std::string_view  name, const std::string& val);
 +    void    setVector3(std::string_view name, const LLVector3 &val);
 +    void    setVector3d(std::string_view name, const LLVector3d &val);
 +    void    setQuaternion(std::string_view name, const LLQuaternion &val);
 +    void    setRect(std::string_view name, const LLRect &val);
 +    void    setColor4(std::string_view name, const LLColor4 &val);
 +    void    setLLSD(std::string_view name, const LLSD& val);
 +
 +    // type agnostic setter that takes LLSD
 +    void    setUntypedValue(std::string_view name, const LLSD& val);
 +
 +    // generic setter
 +    template<typename T> void set(std::string_view name, const T& val)
 +    {
 +        LLControlVariable* control = getControl(name);
 +
 +        if (control && control->isType(get_control_type<T>()))
 +        {
 +            control->set(convert_to_llsd(val));
 +        }
 +        else
 +        {
 +            LL_WARNS() << "Invalid control " << name << LL_ENDL;
 +        }
 +    }
 +
 +    bool    controlExists(const std::string& name);
 +
 +    // Returns number of controls loaded, 0 if failed
 +    // If require_declaration is false, will auto-declare controls it finds
 +    // as the given type.
 +    U32 loadFromFileLegacy(const std::string& filename, bool require_declaration = true, eControlType declare_as = TYPE_STRING);
 +    U32 saveToFile(const std::string& filename, bool nondefault_only);
 +    U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true);
 +    void    resetToDefaults();
 +    void    incrCount(std::string_view name);
 +
 +    bool    mSettingsProfile;
 +};
 +
 +
 +//! Publish/Subscribe object to interact with LLControlGroups.
 +
 +//! Use an LLCachedControl instance to connect to a LLControlVariable
 +//! without have to manually create and bind a listener to a local
 +//! object.
 +template <class T>
 +class LLControlCache : public LLRefCount, public LLInstanceTracker<LLControlCache<T>, std::string>
 +{
 +public:
 +    // This constructor will declare a control if it doesn't exist in the contol group
 +    LLControlCache(LLControlGroup& group,
 +                    const std::string& name,
 +                    const T& default_value,
 +                    const std::string& comment)
 +    :   LLInstanceTracker<LLControlCache<T>, std::string >(name)
 +    {
 +        if(!group.controlExists(name))
 +        {
 +            if(!declareTypedControl(group, name, default_value, comment))
 +            {
 +                LL_ERRS() << "The control could not be created!!!" << LL_ENDL;
 +            }
 +        }
 +
 +        bindToControl(group, name);
 +    }
 +
 +    LLControlCache(LLControlGroup& group,
 +                    const std::string& name)
 +    :   LLInstanceTracker<LLControlCache<T>, std::string >(name)
 +    {
 +        if(!group.controlExists(name))
 +        {
 +            LL_ERRS() << "Control named " << name << "not found." << LL_ENDL;
 +        }
 +
 +        bindToControl(group, name);
 +    }
 +
 +    ~LLControlCache()
 +    {
 +    }
 +
 +    const T& getValue() const { return mCachedValue; }
 +
 +private:
 +    void bindToControl(LLControlGroup& group, const std::string& name)
 +    {
 +        LLControlVariablePtr controlp = group.getControl(name);
 +        mType = controlp->type();
 +        mCachedValue = convert_from_llsd<T>(controlp->get(), mType, name);
 +
 +        // Add a listener to the controls signal...
 +        // NOTE: All listeners connected to 0 group, for guaranty that variable handlers (gSavedSettings) call last
 +        mConnection = controlp->getSignal()->connect(0,
 +            boost::bind(&LLControlCache<T>::handleValueChange, this, _2)
 +            );
 +        mType = controlp->type();
 +    }
 +    bool declareTypedControl(LLControlGroup& group,
 +                            const std::string& name,
 +                             const T& default_value,
 +                             const std::string& comment)
 +    {
 +        LLSD init_value;
 +        eControlType type = get_control_type<T>();
 +        init_value = convert_to_llsd(default_value);
 +        if(type < TYPE_COUNT)
 +        {
 +            group.declareControl(name, type, init_value, comment, LLControlVariable::PERSIST_NO);
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +    bool handleValueChange(const LLSD& newvalue)
 +    {
 +        mCachedValue = convert_from_llsd<T>(newvalue, mType, "");
 +        return true;
 +    }
 +
 +private:
 +    T                           mCachedValue;
 +    eControlType                mType;
 +    boost::signals2::scoped_connection  mConnection;
 +};
 +
 +template <typename T>
 +class LLCachedControl
 +{
 +public:
 +    LLCachedControl(LLControlGroup& group,
 +                    const std::string& name,
 +                    const T& default_value,
 +                    const std::string& comment = "Declared In Code")
 +    {
 +        mCachedControlPtr = LLControlCache<T>::getInstance(name).get();
 +        if (! mCachedControlPtr)
 +        {
 +            mCachedControlPtr = new LLControlCache<T>(group, name, default_value, comment);
 +        }
 +    }
 +
 +    LLCachedControl(LLControlGroup& group,
 +                    const std::string& name)
 +    {
 +        mCachedControlPtr = LLControlCache<T>::getInstance(name).get();
 +        if (! mCachedControlPtr)
 +        {
 +            mCachedControlPtr = new LLControlCache<T>(group, name);
 +        }
 +    }
 +
 +    operator const T&() const { return mCachedControlPtr->getValue(); }
 +    operator boost::function<const T&()> () const { return boost::function<const T&()>(*this); }
 +    const T& operator()() { return mCachedControlPtr->getValue(); }
 +
 +private:
 +    LLPointer<LLControlCache<T> > mCachedControlPtr;
 +};
 +
 +template <> eControlType get_control_type<U32>();
 +template <> eControlType get_control_type<S32>();
 +template <> eControlType get_control_type<F32>();
 +template <> eControlType get_control_type<bool>();
 +template <> eControlType get_control_type<std::string>();
 +template <> eControlType get_control_type<LLVector3>();
 +template <> eControlType get_control_type<LLVector3d>();
 +template <> eControlType get_control_type<LLQuaternion>();
 +template <> eControlType get_control_type<LLRect>();
 +template <> eControlType get_control_type<LLColor4>();
 +template <> eControlType get_control_type<LLColor3>();
 +template <> eControlType get_control_type<LLSD>();
 +
 +template <> LLSD convert_to_llsd<U32>(const U32& in);
 +template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
 +template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
 +template <> LLSD convert_to_llsd<LLQuaternion>(const LLQuaternion& in);
 +template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
 +template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
 +template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in);
 +
 +template<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> LLQuaternion convert_from_llsd<LLQuaternion>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, std::string_view control_name);
 +template<> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, std::string_view control_name);
 +
 +//#define TEST_CACHED_CONTROL 1
 +#ifdef TEST_CACHED_CONTROL
 +void test_cached_control();
 +#endif // TEST_CACHED_CONTROL
 +
 +#endif
 diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 9c7ac66f01..e7ea5a9fad 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -1,3268 +1,3268 @@ -/**  - * @file llxmlnode.cpp - * @author Tom Yedwab - * @brief LLXMLNode implementation - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include <iostream> -#include <map> - -#include "llxmlnode.h" - -#include "v3color.h" -#include "v4color.h" -#include "v4coloru.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4math.h" -#include "llquaternion.h" -#include "llstring.h" -#include "lluuid.h" -#include "lldir.h" - -// static -bool LLXMLNode::sStripEscapedStrings = true; -bool LLXMLNode::sStripWhitespaceValues = false; - -LLXMLNode::LLXMLNode() :  -	mID(""), -	mParser(NULL), -	mIsAttribute(false), -	mVersionMajor(0),  -	mVersionMinor(0),  -	mLength(0),  -	mPrecision(64), -	mType(TYPE_CONTAINER), -	mEncoding(ENCODING_DEFAULT), -	mLineNumber(-1), -	mParent(NULL), -	mChildren(NULL), -	mAttributes(), -	mPrev(NULL), -	mNext(NULL), -	mName(NULL),  -	mValue(""),  -	mDefault(NULL) -{ -} - -LLXMLNode::LLXMLNode(const char* name, bool is_attribute) :  -	mID(""), -	mParser(NULL), -	mIsAttribute(is_attribute), -	mVersionMajor(0),  -	mVersionMinor(0),  -	mLength(0),  -	mPrecision(64), -	mType(TYPE_CONTAINER),  -	mEncoding(ENCODING_DEFAULT), -	mLineNumber(-1), -	mParent(NULL), -	mChildren(NULL), -	mAttributes(), -	mPrev(NULL), -	mNext(NULL), -	mValue(""),  -	mDefault(NULL) -{ -    mName = gStringTable.addStringEntry(name); -} - -LLXMLNode::LLXMLNode(LLStringTableEntry* name, bool is_attribute) :  -	mID(""), -	mParser(NULL), -	mIsAttribute(is_attribute), -	mVersionMajor(0),  -	mVersionMinor(0),  -	mLength(0),  -	mPrecision(64), -	mType(TYPE_CONTAINER),  -	mEncoding(ENCODING_DEFAULT), -	mLineNumber(-1), -	mParent(NULL), -	mChildren(NULL), -	mAttributes(), -	mPrev(NULL), -	mNext(NULL), -	mName(name), -	mValue(""),  -	mDefault(NULL) -{ -} - -// copy constructor (except for the children) -LLXMLNode::LLXMLNode(const LLXMLNode& rhs) :  -	mID(rhs.mID), -	mIsAttribute(rhs.mIsAttribute), -	mVersionMajor(rhs.mVersionMajor),  -	mVersionMinor(rhs.mVersionMinor),  -	mLength(rhs.mLength),  -	mPrecision(rhs.mPrecision), -	mType(rhs.mType), -	mEncoding(rhs.mEncoding), -	mLineNumber(0), -	mParser(NULL), -	mParent(NULL), -	mChildren(NULL), -	mAttributes(), -	mPrev(NULL), -	mNext(NULL), -	mName(rhs.mName),  -	mValue(rhs.mValue),  -	mDefault(rhs.mDefault) -{ -} - -// returns a new copy of this node and all its children -LLXMLNodePtr LLXMLNode::deepCopy() -{ -	LLXMLNodePtr newnode = LLXMLNodePtr(new LLXMLNode(*this)); -	if (mChildren.notNull()) -	{ -		for (LLXMLChildList::iterator iter = mChildren->map.begin(); -			 iter != mChildren->map.end(); ++iter)	 -		{ -			LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); -			newnode->addChild(temp_ptr_for_gcc); -		} -	} -	for (LLXMLAttribList::iterator iter = mAttributes.begin(); -		 iter != mAttributes.end(); ++iter) -	{ -		LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); -		newnode->addChild(temp_ptr_for_gcc); -	} - -	return newnode; -} - -// virtual -LLXMLNode::~LLXMLNode() -{ -	// Strictly speaking none of this should be required execept 'delete mChildren'... -	// Sadly, that's only true if we hadn't had reference-counted smart pointers linked -	// in three different directions. This entire class is a frightening, hard-to-maintain -	// mess. -	if (mChildren.notNull()) -	{ -		for (LLXMLChildList::iterator iter = mChildren->map.begin(); -			 iter != mChildren->map.end(); ++iter) -		{ -			LLXMLNodePtr child = iter->second; -			child->mParent = NULL; -			child->mNext = NULL; -			child->mPrev = NULL; -		} -		mChildren->map.clear(); -		mChildren->head = NULL; -		mChildren->tail = NULL; -		mChildren = NULL; -	} -	for (LLXMLAttribList::iterator iter = mAttributes.begin(); -		 iter != mAttributes.end(); ++iter) -	{ -		LLXMLNodePtr attr = iter->second; -		attr->mParent = NULL; -		attr->mNext = NULL; -		attr->mPrev = NULL; -	} -	llassert(mParent == NULL); -	mDefault = NULL; -} - -bool LLXMLNode::isNull() -{	 -	return (mName == NULL); -} - -// protected -bool LLXMLNode::removeChild(LLXMLNode *target_child)  -{ -	if (!target_child) -	{ -		return false; -	} -	if (target_child->mIsAttribute) -	{ -		LLXMLAttribList::iterator children_itr = mAttributes.find(target_child->mName); -		if (children_itr != mAttributes.end()) -		{ -			target_child->mParent = NULL; -			mAttributes.erase(children_itr); -			return true; -		} -	} -	else if (mChildren.notNull()) -	{ -		LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName); -		while (children_itr != mChildren->map.end()) -		{ -			if (target_child == children_itr->second) -			{ -				if (target_child == mChildren->head) -				{ -					mChildren->head = target_child->mNext; -				} -				if (target_child == mChildren->tail) -				{ -					mChildren->tail = target_child->mPrev; -				} - -				LLXMLNodePtr prev = target_child->mPrev; -				LLXMLNodePtr next = target_child->mNext; -				if (prev.notNull()) prev->mNext = next; -				if (next.notNull()) next->mPrev = prev; - -				target_child->mPrev = NULL; -				target_child->mNext = NULL; -				target_child->mParent = NULL; -				mChildren->map.erase(children_itr); -				if (mChildren->map.empty()) -				{ -					mChildren = NULL; -				} -				return true; -			} -			else if (children_itr->first != target_child->mName) -			{ -				break; -			} -			else -			{ -				++children_itr; -			} -		} -	} -	return false; -} - -void LLXMLNode::addChild(LLXMLNodePtr& new_child) -{ -	if (new_child->mParent != NULL) -	{ -		if (new_child->mParent == this) -		{ -			return; -		} -		new_child->mParent->removeChild(new_child); -	} - -	new_child->mParent = this; -	if (new_child->mIsAttribute) -	{ -		LLXMLAttribList::iterator found_it = mAttributes.find(new_child->mName); -		if (found_it != mAttributes.end()) -		{ -			removeChild(found_it->second); -		} -		mAttributes.insert(std::make_pair(new_child->mName, new_child)); -	} -	else -	{ -		if (mChildren.isNull()) -		{ -			mChildren = new LLXMLChildren(); -			mChildren->head = new_child; -			mChildren->tail = new_child; -		} -		mChildren->map.insert(std::make_pair(new_child->mName, new_child)); - -		if (mChildren->tail != new_child) -		{ -			mChildren->tail->mNext = new_child; -			new_child->mPrev = mChildren->tail; -			mChildren->tail = new_child; -		} -	} - -	new_child->updateDefault(); -} - -// virtual  -LLXMLNodePtr LLXMLNode::createChild(const char* name, bool is_attribute) -{ -	return createChild(gStringTable.addStringEntry(name), is_attribute); -} - -// virtual  -LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, bool is_attribute) -{ -	LLXMLNodePtr ret(new LLXMLNode(name, is_attribute)); -	ret->mID.clear(); -	 -	addChild(ret); -	return ret; -} - -bool LLXMLNode::deleteChild(LLXMLNode *child) -{ -	if (removeChild(child)) -	{ -		return true; -	} -	return false; -} - -void LLXMLNode::setParent(LLXMLNodePtr& new_parent) -{ -	if (new_parent.notNull()) -	{ -		LLXMLNodePtr this_ptr(this); -		new_parent->addChild(this_ptr); -	} -	else -	{ -		if (mParent != NULL) -		{ -		    LLXMLNodePtr old_parent = mParent; -			mParent = NULL; -			old_parent->removeChild(this); -		} -	} -} - - -void LLXMLNode::updateDefault() -{ -	if (mParent != NULL && !mParent->mDefault.isNull()) -	{ -		mDefault = NULL; - -		// Find default value in parent's default tree -		if (!mParent->mDefault.isNull()) -		{ -			findDefault(mParent->mDefault); -		} -	} - -	if (mChildren.notNull()) -	{ -		LLXMLChildList::const_iterator children_itr; -		LLXMLChildList::const_iterator children_end = mChildren->map.end(); -		for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) -		{ -			LLXMLNodePtr child = (*children_itr).second; -			child->updateDefault(); -		} -	} -} - -void XMLCALL StartXMLNode(void *userData, -                          const XML_Char *name, -                          const XML_Char **atts) -{ -	// Create a new node -	LLXMLNode *new_node_ptr = new LLXMLNode(name, false); - -	LLXMLNodePtr new_node = new_node_ptr; -	new_node->mID.clear(); -	LLXMLNodePtr ptr_new_node = new_node; - -	// Set the parent-child relationship with the current active node -	LLXMLNode* parent = (LLXMLNode *)userData; - -	if (NULL == parent) -	{ -		LL_WARNS() << "parent (userData) is NULL; aborting function" << LL_ENDL; -		return; -	} - -	new_node_ptr->mParser = parent->mParser; -	new_node_ptr->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); -	 -	// Set the current active node to the new node -	XML_Parser *parser = parent->mParser; -	XML_SetUserData(*parser, (void *)new_node_ptr); - -	// Parse attributes -	U32 pos = 0; -	while (atts[pos] != NULL) -	{ -		std::string attr_name = atts[pos]; -		std::string attr_value = atts[pos+1]; - -		// Special cases -		if ('i' == attr_name[0] && "id" == attr_name) -		{ -			new_node->mID = attr_value; -		} -		else if ('v' == attr_name[0] && "version" == attr_name) -		{ -			U32 version_major = 0; -			U32 version_minor = 0; -			if (sscanf(attr_value.c_str(), "%d.%d", &version_major, &version_minor) > 0) -			{ -				new_node->mVersionMajor = version_major; -				new_node->mVersionMinor = version_minor; -			} -		} -		else if (('s' == attr_name[0] && "size" == attr_name) || ('l' == attr_name[0] && "length" == attr_name)) -		{ -			U32 length; -			if (sscanf(attr_value.c_str(), "%d", &length) > 0) -			{ -				new_node->mLength = length; -			} -		} -		else if ('p' == attr_name[0] && "precision" == attr_name) -		{ -			U32 precision; -			if (sscanf(attr_value.c_str(), "%d", &precision) > 0) -			{ -				new_node->mPrecision = precision; -			} -		} -		else if ('t' == attr_name[0] && "type" == attr_name) -		{ -			if ("boolean" == attr_value) -			{ -				new_node->mType = LLXMLNode::TYPE_BOOLEAN; -			} -			else if ("integer" == attr_value) -			{ -				new_node->mType = LLXMLNode::TYPE_INTEGER; -			} -			else if ("float" == attr_value) -			{ -				new_node->mType = LLXMLNode::TYPE_FLOAT; -			} -			else if ("string" == attr_value) -			{ -				new_node->mType = LLXMLNode::TYPE_STRING; -			} -			else if ("uuid" == attr_value) -			{ -				new_node->mType = LLXMLNode::TYPE_UUID; -			} -			else if ("noderef" == attr_value) -			{ -				new_node->mType = LLXMLNode::TYPE_NODEREF; -			} -		} -		else if ('e' == attr_name[0] && "encoding" == attr_name) -		{ -			if ("decimal" == attr_value) -			{ -				new_node->mEncoding = LLXMLNode::ENCODING_DECIMAL; -			} -			else if ("hex" == attr_value) -			{ -				new_node->mEncoding = LLXMLNode::ENCODING_HEX; -			} -			/*else if (attr_value == "base32") -			{ -				new_node->mEncoding = LLXMLNode::ENCODING_BASE32; -			}*/ -		} - -		// only one attribute child per description -		LLXMLNodePtr attr_node; -		if (!new_node->getAttribute(attr_name.c_str(), attr_node, false)) -		{ -			attr_node = new LLXMLNode(attr_name.c_str(), true); -			attr_node->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser)); -		} -		attr_node->setValue(attr_value); -		new_node->addChild(attr_node); - -		pos += 2; -	} - -	if (parent) -	{ -		parent->addChild(new_node); -	} -} - -void XMLCALL EndXMLNode(void *userData, -                        const XML_Char *name) -{ -	// [FUGLY] Set the current active node to the current node's parent -	LLXMLNode *node = (LLXMLNode *)userData; -	XML_Parser *parser = node->mParser; -	XML_SetUserData(*parser, (void *)node->mParent); -	// SJB: total hack: -	if (LLXMLNode::sStripWhitespaceValues) -	{ -		std::string value = node->getValue(); -		bool is_empty = true; -		for (std::string::size_type s = 0; s < value.length(); s++) -		{ -			char c = value[s]; -			if (c != ' ' && c != '\t' && c != '\n') -			{ -				is_empty = false; -				break; -			} -		} -		if (is_empty) -		{ -			value.clear(); -			node->setValue(value); -		} -	} -} - -void XMLCALL XMLData(void *userData, -                     const XML_Char *s, -                     int len) -{ -	LLXMLNode* current_node = (LLXMLNode *)userData; -	std::string value = current_node->getValue(); -	if (LLXMLNode::sStripEscapedStrings) -	{ -		if (s[0] == '\"' && s[len-1] == '\"') -		{ -			// Special-case: Escaped string. -			std::string unescaped_string; -			for (S32 pos=1; pos<len-1; ++pos) -			{ -				if (s[pos] == '\\' && s[pos+1] == '\\') -				{ -					unescaped_string.append("\\"); -					++pos; -				} -				else if (s[pos] == '\\' && s[pos+1] == '\"') -				{ -					unescaped_string.append("\""); -					++pos; -				} -				else -				{ -					unescaped_string.append(&s[pos], 1); -				} -			} -			value.append(unescaped_string); -			current_node->setValue(value); -			return; -		} -	} -	value.append(std::string(s, len)); -	current_node->setValue(value); -} - - - -// static  -bool LLXMLNode::updateNode( -	LLXMLNodePtr& node, -	LLXMLNodePtr& update_node) -{ - -	if (!node || !update_node) -	{ -		LL_WARNS() << "Node invalid" << LL_ENDL; -		return false; -	} - -	//update the node value -	node->mValue = update_node->mValue; - -	//update all attribute values -	LLXMLAttribList::const_iterator itor; - -	for(itor = update_node->mAttributes.begin(); itor != update_node->mAttributes.end(); ++itor) -	{ -		const LLStringTableEntry* attribNameEntry = (*itor).first; -		LLXMLNodePtr updateAttribNode = (*itor).second; - -		LLXMLNodePtr attribNode; - -		node->getAttribute(attribNameEntry, attribNode, 0); - -		if (attribNode) -		{ -			attribNode->mValue = updateAttribNode->mValue; -		} -	} - -	//update all of node's children with updateNodes children that match name -	LLXMLNodePtr child = node->getFirstChild(); -	LLXMLNodePtr last_child = child; -	LLXMLNodePtr updateChild; -	 -	for (updateChild = update_node->getFirstChild(); updateChild.notNull();  -		 updateChild = updateChild->getNextSibling()) -	{ -		while(child.notNull()) -		{ -			std::string nodeName; -			std::string updateName; - -			updateChild->getAttributeString("name", updateName); -			child->getAttributeString("name", nodeName);		 - - -			//if it's a combobox there's no name, but there is a value -			if (updateName.empty()) -			{ -				updateChild->getAttributeString("value", updateName); -				child->getAttributeString("value", nodeName); -			} - -			if ((nodeName != "") && (updateName == nodeName)) -			{ -				updateNode(child, updateChild); -				last_child = child; -				child = child->getNextSibling(); -				if (child.isNull()) -				{ -					child = node->getFirstChild(); -				} -				break; -			} -			 -			child = child->getNextSibling(); -			if (child.isNull()) -			{ -				child = node->getFirstChild(); -			} -			if (child == last_child) -			{ -				break; -			} -		} -	} - -	return true; -} - -// static -bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree) -{ -	// Read file -	LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL; -	LLFILE* fp = LLFile::fopen(filename, "rb");		/* Flawfinder: ignore */ -	if (fp == NULL) -	{ -		node = NULL ; -		return false; -	} -	fseek(fp, 0, SEEK_END); -	U32 length = ftell(fp); -	fseek(fp, 0, SEEK_SET); - -	U8* buffer = new U8[length+1]; -	size_t nread = fread(buffer, 1, length, fp); -	buffer[nread] = 0; -	fclose(fp); - -	bool rv = parseBuffer(buffer, nread, node, defaults_tree); -	delete [] buffer; -	return rv; -} - -// static -bool LLXMLNode::parseBuffer( -	U8* buffer, -	U32 length, -	LLXMLNodePtr& node,  -	LLXMLNode* defaults) -{ -	// Init -	XML_Parser my_parser = XML_ParserCreate(NULL); -	XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode); -	XML_SetCharacterDataHandler(my_parser, XMLData); - -	// Create a root node -	LLXMLNode *file_node_ptr = new LLXMLNode("XML", false); -	LLXMLNodePtr file_node = file_node_ptr; - -	file_node->mParser = &my_parser; - -	XML_SetUserData(my_parser, (void *)file_node_ptr); - -	// Do the parsing -	if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK) -	{ -		LL_WARNS() << "Error parsing xml error code: " -				<< XML_ErrorString(XML_GetErrorCode(my_parser)) -				<< " on line " << XML_GetCurrentLineNumber(my_parser) -				<< LL_ENDL; -	} - -	// Deinit -	XML_ParserFree(my_parser); - -	if (!file_node->mChildren || file_node->mChildren->map.size() != 1) -	{ -		LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." -				<< LL_ENDL; -		node = NULL ; -		return false; -	} - -	LLXMLNode *return_node = file_node->mChildren->map.begin()->second; - -	return_node->setDefault(defaults); -	return_node->updateDefault(); - -	node = return_node; -	return true; -} - -// static -bool LLXMLNode::parseStream( -	std::istream& str, -	LLXMLNodePtr& node,  -	LLXMLNode* defaults) -{ -	// Init -	XML_Parser my_parser = XML_ParserCreate(NULL); -	XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode); -	XML_SetCharacterDataHandler(my_parser, XMLData); - -	// Create a root node -	LLXMLNode *file_node_ptr = new LLXMLNode("XML", false); -	LLXMLNodePtr file_node = file_node_ptr; - -	file_node->mParser = &my_parser; - -	XML_SetUserData(my_parser, (void *)file_node_ptr); - -	const int BUFSIZE = 1024;  -	U8* buffer = new U8[BUFSIZE]; - -	while(str.good()) -	{ -		str.read((char*)buffer, BUFSIZE); -		int count = (int)str.gcount(); -		 -		if (XML_Parse(my_parser, (const char *)buffer, count, !str.good()) != XML_STATUS_OK) -		{ -			LL_WARNS() << "Error parsing xml error code: " -					<< XML_ErrorString(XML_GetErrorCode(my_parser)) -					<< " on lne " << XML_GetCurrentLineNumber(my_parser) -					<< LL_ENDL; -			break; -		} -	} -	 -	delete [] buffer; - -	// Deinit -	XML_ParserFree(my_parser); - -	if (!file_node->mChildren || file_node->mChildren->map.size() != 1) -	{ -		LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." -				<< LL_ENDL; -		node = NULL; -		return false; -	} - -	LLXMLNode *return_node = file_node->mChildren->map.begin()->second; - -	return_node->setDefault(defaults); -	return_node->updateDefault(); - -	node = return_node; -	return true; -} - - -bool LLXMLNode::isFullyDefault() -{ -	if (mDefault.isNull()) -	{ -		return false; -	} -	bool has_default_value = (mValue == mDefault->mValue); -	bool has_default_attribute = (mIsAttribute == mDefault->mIsAttribute); -	bool has_default_type = mIsAttribute || (mType == mDefault->mType); -	bool has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding); -	bool has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision); -	bool has_default_length = mIsAttribute || (mLength == mDefault->mLength); - -	if (has_default_value  -		&& has_default_type  -		&& has_default_encoding  -		&& has_default_precision -		&& has_default_length -		&& has_default_attribute) -	{ -		if (mChildren.notNull()) -		{ -			LLXMLChildList::const_iterator children_itr; -			LLXMLChildList::const_iterator children_end = mChildren->map.end(); -			for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) -			{ -				LLXMLNodePtr child = (*children_itr).second; -				if (!child->isFullyDefault()) -				{ -					return false; -				} -			} -		} -		return true; -	} - -	return false; -} - -// static -bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, -								  const std::vector<std::string>& paths) -{ -	if (paths.empty()) return false; - -	std::string filename = paths.front(); -	if (filename.empty()) -	{ -		return false; -	} -	 -	if (!LLXMLNode::parseFile(filename, root, NULL)) -	{ -		LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL; -		return false; -	} - -	LLXMLNodePtr updateRoot; - -	std::vector<std::string>::const_iterator itor; - -	// We've already dealt with the first item, skip that one -	for (itor = paths.begin() + 1; itor != paths.end(); ++itor) -	{ -		std::string layer_filename = *itor; -		if(layer_filename.empty() || layer_filename == filename) -		{ -			// no localized version of this file, that's ok, keep looking -			continue; -		} - -		if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL)) -		{ -			LL_WARNS() << "Problem reading localized UI description file: " << layer_filename << LL_ENDL; -			return false; -		} - -		std::string nodeName; -		std::string updateName; - -		updateRoot->getAttributeString("name", updateName); -		root->getAttributeString("name", nodeName); - -		if (updateName == nodeName) -		{ -			LLXMLNode::updateNode(root, updateRoot); -		} -	} - -	return true; -} - -// static -void LLXMLNode::writeHeaderToFile(LLFILE *out_file) -{ -	fprintf(out_file, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n"); -} - -void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations) -{ -	if (isFullyDefault()) -	{ -		// Don't write out nodes that are an exact match to defaults -		return; -	} - -	std::ostringstream ostream; -	writeToOstream(ostream, indent, use_type_decorations); -	std::string outstring = ostream.str(); -	size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file); -	if (written != outstring.length()) -	{ -		LL_WARNS() << "Short write" << LL_ENDL; -	} -} - -void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent, bool use_type_decorations) -{ -	if (isFullyDefault()) -	{ -		// Don't write out nodes that are an exact match to defaults -		return; -	} - -	bool has_default_type = mDefault.isNull()?false:(mType == mDefault->mType); -	bool has_default_encoding = mDefault.isNull()?false:(mEncoding == mDefault->mEncoding); -	bool has_default_precision = mDefault.isNull()?false:(mPrecision == mDefault->mPrecision); -	bool has_default_length = mDefault.isNull()?false:(mLength == mDefault->mLength); - -	// stream the name -	output_stream << indent << "<" << mName->mString << "\n"; - -	if (use_type_decorations) -	{ -		// ID -		if (mID != "") -		{ -			output_stream << indent << " id=\"" << mID << "\"\n"; -		} - -		// Type -		if (!has_default_type) -		{ -			switch (mType) -			{ -			case TYPE_BOOLEAN: -				output_stream << indent << " type=\"boolean\"\n"; -				break; -			case TYPE_INTEGER: -				output_stream << indent << " type=\"integer\"\n"; -				break; -			case TYPE_FLOAT: -				output_stream << indent << " type=\"float\"\n"; -				break; -			case TYPE_STRING: -				output_stream << indent << " type=\"string\"\n"; -				break; -			case TYPE_UUID: -				output_stream << indent << " type=\"uuid\"\n"; -				break; -			case TYPE_NODEREF: -				output_stream << indent << " type=\"noderef\"\n"; -				break; -			default: -				// default on switch(enum) eliminates a warning on linux -				break; -			}; -		} - -		// Encoding -		if (!has_default_encoding) -		{ -			switch (mEncoding) -			{ -			case ENCODING_DECIMAL: -				output_stream << indent << " encoding=\"decimal\"\n"; -				break; -			case ENCODING_HEX: -				output_stream << indent << " encoding=\"hex\"\n"; -				break; -			/*case ENCODING_BASE32: -				output_stream << indent << " encoding=\"base32\"\n"; -				break;*/ -			default: -				// default on switch(enum) eliminates a warning on linux -				break; -			}; -		} - -		// Precision -		if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT)) -		{ -			output_stream << indent << " precision=\"" << mPrecision << "\"\n"; -		} - -		// Version -		if (mVersionMajor > 0 || mVersionMinor > 0) -		{ -			output_stream << indent << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"\n"; -		} - -		// Array length -		if (!has_default_length && mLength > 0) -		{ -			output_stream << indent << " length=\"" << mLength << "\"\n"; -		} -	} - -	{ -		// Write out attributes -		LLXMLAttribList::const_iterator attr_itr; -		LLXMLAttribList::const_iterator attr_end = mAttributes.end(); -		for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr) -		{ -			LLXMLNodePtr child = (*attr_itr).second; -			if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue) -			{ -				std::string attr = child->mName->mString; -				if (use_type_decorations -					&& (attr == "id" || -						attr == "type" || -						attr == "encoding" || -						attr == "precision" || -						attr == "version" || -						attr == "length")) -				{ -					continue; // skip built-in attributes -				} -				 -				std::string attr_str = llformat(" %s=\"%s\"", -											 attr.c_str(), -											 escapeXML(child->mValue).c_str()); -				output_stream << indent << attr_str << "\n"; -			} -		} -	} - -	// erase last \n before attaching final > or /> -	output_stream.seekp(-1, std::ios::cur); - -	if (mChildren.isNull() && mValue == "") -	{ -		output_stream << " />\n"; -		return; -	} -	else -	{ -		output_stream << ">\n"; -		if (mChildren.notNull()) -		{ -			// stream non-attributes -			std::string next_indent = indent + "    "; -			for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling()) -			{ -				child->writeToOstream(output_stream, next_indent, use_type_decorations); -			} -		} -		if (!mValue.empty()) -		{ -			std::string contents = getTextContents(); -			output_stream << indent << "    " << escapeXML(contents) << "\n"; -		} -		output_stream << indent << "</" << mName->mString << ">\n"; -	} -} - -void LLXMLNode::findName(const std::string& name, LLXMLNodeList &results) -{ -    LLStringTableEntry* name_entry = gStringTable.checkStringEntry(name); -	if (name_entry == mName) -	{ -		results.insert(std::make_pair(this->mName->mString, this)); -		return; -	} -	if (mChildren.notNull()) -	{ -		LLXMLChildList::const_iterator children_itr; -		LLXMLChildList::const_iterator children_end = mChildren->map.end(); -		for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) -		{ -			LLXMLNodePtr child = (*children_itr).second; -			child->findName(name_entry, results); -		} -	} -} - -void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results) -{ -	if (name == mName) -	{ -		results.insert(std::make_pair(this->mName->mString, this)); -		return; -	} -	if (mChildren.notNull()) -	{ -		LLXMLChildList::const_iterator children_itr; -		LLXMLChildList::const_iterator children_end = mChildren->map.end(); -		for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) -		{ -			LLXMLNodePtr child = (*children_itr).second; -			child->findName(name, results); -		} -	} -} - -void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results) -{ -	if (id == mID) -	{ -		results.insert(std::make_pair(this->mName->mString, this)); -		return; -	} -	if (mChildren.notNull()) -	{ -		LLXMLChildList::const_iterator children_itr; -		LLXMLChildList::const_iterator children_end = mChildren->map.end(); -		for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr) -		{ -			LLXMLNodePtr child = (*children_itr).second; -			child->findID(id, results); -		} -	} -} - -void LLXMLNode::scrubToTree(LLXMLNode *tree) -{ -	if (!tree || tree->mChildren.isNull()) -	{ -		return; -	} -	if (mChildren.notNull()) -	{ -		std::vector<LLXMLNodePtr> to_delete_list; -		LLXMLChildList::iterator itor = mChildren->map.begin(); -		while (itor != mChildren->map.end()) -		{ -			LLXMLNodePtr child = itor->second; -			LLXMLNodePtr child_tree = NULL; -			// Look for this child in the default's children -			bool found = false; -			LLXMLChildList::iterator itor2 = tree->mChildren->map.begin(); -			while (itor2 != tree->mChildren->map.end()) -			{ -				if (child->mName == itor2->second->mName) -				{ -					child_tree = itor2->second; -					found = true; -				} -				++itor2; -			} -			if (!found) -			{ -				to_delete_list.push_back(child); -			} -			else -			{ -				child->scrubToTree(child_tree); -			} -			++itor; -		} -		std::vector<LLXMLNodePtr>::iterator itor3; -		for (itor3=to_delete_list.begin(); itor3!=to_delete_list.end(); ++itor3) -		{ -			LLXMLNodePtr ptr; -			(*itor3)->setParent(ptr); -		} -	} -} - -bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, bool use_default_if_missing) -{ -    return getChild(gStringTable.checkStringEntry(name), node, use_default_if_missing); -} - -bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) -{ -	if (mChildren.notNull()) -	{ -		LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); -		if (child_itr != mChildren->map.end()) -		{ -			node = (*child_itr).second; -			return true; -		} -	} -	if (use_default_if_missing && !mDefault.isNull()) -	{ -		return mDefault->getChild(name, node, false); -	} -	node = NULL; -	return false; -} - -void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, bool use_default_if_missing) const -{ -    getChildren(gStringTable.checkStringEntry(name), children, use_default_if_missing); -} - -void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, bool use_default_if_missing) const -{ -	if (mChildren.notNull()) -	{ -		LLXMLChildList::const_iterator child_itr = mChildren->map.find(name); -		if (child_itr != mChildren->map.end()) -		{ -			LLXMLChildList::const_iterator children_end = mChildren->map.end(); -			while (child_itr != children_end) -			{ -				LLXMLNodePtr child = (*child_itr).second; -				if (name != child->mName) -				{ -					break; -				} -				children.insert(std::make_pair(child->mName->mString, child)); -				child_itr++; -			} -		} -	} -	if (children.size() == 0 && use_default_if_missing && !mDefault.isNull()) -	{ -		mDefault->getChildren(name, children, false); -	} -} - -// recursively walks the tree and returns all children at all nesting levels matching the name -void LLXMLNode::getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const -{ -	if (mChildren.notNull()) -	{ -		for (LLXMLChildList::const_iterator child_itr = mChildren->map.begin(); -			 child_itr != mChildren->map.end(); ++child_itr) -		{ -			LLXMLNodePtr child = (*child_itr).second; -			if (name == child->mName) -			{ -				children.insert(std::make_pair(child->mName->mString, child)); -			} -			// and check each child as well -			child->getDescendants(name, children); -		} -	} -} - -bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, bool use_default_if_missing) -{ -    return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing); -} - -bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) -{ -	LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); -	if (child_itr != mAttributes.end()) -	{ -		node = (*child_itr).second; -		return true; -	} -	if (use_default_if_missing && !mDefault.isNull()) -	{ -		return mDefault->getAttribute(name, node, false); -	} -	 -	return false; -} - -bool LLXMLNode::setAttributeString(const char* attr, const std::string& value) -{ -	LLStringTableEntry* name = gStringTable.checkStringEntry(attr); -	LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); -	if (child_itr != mAttributes.end()) -	{ -		LLXMLNodePtr node = (*child_itr).second; -		node->setValue(value); -		return true; -	} -	return false; -} - -bool LLXMLNode::hasAttribute(const char* name ) -{ -	LLXMLNodePtr node; -	return getAttribute(name, node); -} - -bool LLXMLNode::getAttributeBOOL(const char* name, bool& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getBoolValue(1, &value)); -} - -bool LLXMLNode::getAttributeU8(const char* name, U8& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getByteValue(1, &value)); -} - -bool LLXMLNode::getAttributeS8(const char* name, S8& value ) -{ -	LLXMLNodePtr node; -	S32 val; -	if (!(getAttribute(name, node) && node->getIntValue(1, &val))) -	{ -		return false; -	} -	value = val; -	return true; -} - -bool LLXMLNode::getAttributeU16(const char* name, U16& value ) -{ -	LLXMLNodePtr node; -	U32 val; -	if (!(getAttribute(name, node) && node->getUnsignedValue(1, &val))) -	{ -		return false; -	} -	value = val; -	return true; -} - -bool LLXMLNode::getAttributeS16(const char* name, S16& value ) -{ -	LLXMLNodePtr node; -	S32 val; -	if (!(getAttribute(name, node) && node->getIntValue(1, &val))) -	{ -		return false; -	} -	value = val; -	return true; -} - -bool LLXMLNode::getAttributeU32(const char* name, U32& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getUnsignedValue(1, &value)); -} - -bool LLXMLNode::getAttributeS32(const char* name, S32& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getIntValue(1, &value)); -} - -bool LLXMLNode::getAttributeF32(const char* name, F32& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getFloatValue(1, &value)); -} - -bool LLXMLNode::getAttributeF64(const char* name, F64& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getDoubleValue(1, &value)); -} - -bool LLXMLNode::getAttributeColor(const char* name, LLColor4& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getFloatValue(4, value.mV)); -} - -bool LLXMLNode::getAttributeColor4(const char* name, LLColor4& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getFloatValue(4, value.mV)); -} - -bool LLXMLNode::getAttributeColor4U(const char* name, LLColor4U& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getByteValue(4, value.mV)); -} - -bool LLXMLNode::getAttributeVector3(const char* name, LLVector3& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getFloatValue(3, value.mV)); -} - -bool LLXMLNode::getAttributeVector3d(const char* name, LLVector3d& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getDoubleValue(3, value.mdV)); -} - -bool LLXMLNode::getAttributeQuat(const char* name, LLQuaternion& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getFloatValue(4, value.mQ)); -} - -bool LLXMLNode::getAttributeUUID(const char* name, LLUUID& value ) -{ -	LLXMLNodePtr node; -	return (getAttribute(name, node) && node->getUUIDValue(1, &value)); -} - -bool LLXMLNode::getAttributeString(const char* name, std::string& value ) -{ -	LLXMLNodePtr node; -	if (!getAttribute(name, node)) -	{ -		return false; -	} -	value = node->getValue(); -	return true; -} - -LLXMLNodePtr LLXMLNode::getRoot() -{ -	if (mParent == NULL) -	{ -		return this; -	} -	return mParent->getRoot(); -} - -/*static */ -const char *LLXMLNode::skipWhitespace(const char *str) -{ -	// skip whitespace characters -	while (str[0] == ' ' || str[0] == '\t' || str[0] == '\n') ++str; -	return str; -} - -/*static */ -const char *LLXMLNode::skipNonWhitespace(const char *str) -{ -	// skip non-whitespace characters -	while (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != 0) ++str; -	return str; -} - -/*static */ -const char *LLXMLNode::parseInteger(const char *str, U64 *dest, bool *is_negative, U32 precision, Encoding encoding) -{ -	*dest = 0; -	*is_negative = false; - -	str = skipWhitespace(str); - -	if (str[0] == 0) return NULL; - -	if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT) -	{ -		if (str[0] == '+') -		{ -			++str; -		} -		if (str[0] == '-') -		{ -			*is_negative = true; -			++str; -		} - -		str = skipWhitespace(str); - -		U64 ret = 0; -		while (str[0] >= '0' && str[0] <= '9') -		{ -			ret *= 10; -			ret += str[0] - '0'; -			++str; -		} - -		if (str[0] == '.') -		{ -			// If there is a fractional part, skip it -			str = skipNonWhitespace(str); -		} - -		*dest = ret; -		return str; -	} -	if (encoding == ENCODING_HEX) -	{ -		U64 ret = 0; -		str = skipWhitespace(str); -		for (U32 pos=0; pos<(precision/4); ++pos) -		{ -			ret <<= 4; -			str = skipWhitespace(str); -			if (str[0] >= '0' && str[0] <= '9') -			{ -				ret += str[0] - '0'; -			}  -			else if (str[0] >= 'a' && str[0] <= 'f') -			{ -				ret += str[0] - 'a' + 10; -			} -			else if (str[0] >= 'A' && str[0] <= 'F') -			{ -				ret += str[0] - 'A' + 10; -			} -			else -			{ -				return NULL; -			} -			++str; -		} - -		*dest = ret; -		return str; -	} -	return NULL; -} - -// 25 elements - decimal expansions of 1/(2^n), multiplied by 10 each iteration -const U64 float_coeff_table[] =  -	{ 5, 25, 125, 625, 3125,  -	  15625, 78125, 390625, 1953125, 9765625, -	  48828125, 244140625, 1220703125, 6103515625LL, 30517578125LL, -	  152587890625LL, 762939453125LL, 3814697265625LL, 19073486328125LL, 95367431640625LL, -	  476837158203125LL, 2384185791015625LL, 11920928955078125LL, 59604644775390625LL, 298023223876953125LL }; - -// 36 elements - decimal expansions of 1/(2^n) after the last 28, truncated, no multiply each iteration -const U64 float_coeff_table_2[] = -	{  149011611938476562LL,74505805969238281LL, -	   37252902984619140LL, 18626451492309570LL, 9313225746154785LL, 4656612873077392LL, -	   2328306436538696LL,  1164153218269348LL,  582076609134674LL,  291038304567337LL, -	   145519152283668LL,   72759576141834LL,    36379788070917LL,   18189894035458LL, -	   9094947017729LL,     4547473508864LL,     2273736754432LL,    1136868377216LL, -	   568434188608LL,      284217094304LL,      142108547152LL,     71054273576LL, -	   35527136788LL,       17763568394LL,       8881784197LL,       4440892098LL, -	   2220446049LL,        1110223024LL,        555111512LL,        277555756LL, -	   138777878,         69388939,          34694469,         17347234, -	   8673617,           4336808,           2168404,          1084202, -	   542101,            271050,            135525,           67762, -	}; - -/*static */ -const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding) -{ -	str = skipWhitespace(str); - -	if (str[0] == 0) return NULL; - -	if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT) -	{ -		str = skipWhitespace(str); - -		if (memcmp(str, "inf", 3) == 0) -		{ -			*(U64 *)dest = 0x7FF0000000000000ll; -			return str + 3; -		} -		if (memcmp(str, "-inf", 4) == 0) -		{ -			*(U64 *)dest = 0xFFF0000000000000ll; -			return str + 4; -		} -		if (memcmp(str, "1.#INF", 6) == 0) -		{ -			*(U64 *)dest = 0x7FF0000000000000ll; -			return str + 6; -		} -		if (memcmp(str, "-1.#INF", 7) == 0) -		{ -			*(U64 *)dest = 0xFFF0000000000000ll; -			return str + 7; -		} - -		F64 negative = 1.0f; -		if (str[0] == '+') -		{ -			++str; -		} -		if (str[0] == '-') -		{ -			negative = -1.0f; -			++str; -		} - -		const char* base_str = str; -		str = skipWhitespace(str); - -		// Parse the integer part of the expression -		U64 int_part = 0; -		while (str[0] >= '0' && str[0] <= '9') -		{ -			int_part *= 10; -			int_part += U64(str[0] - '0'); -			++str; -		} - -		U64 f_part = 0;//, f_decimal = 1; -		if (str[0] == '.') -		{ -			++str; -			U64 remainder = 0; -			U32 pos = 0; -			// Parse the decimal part of the expression -			while (str[0] >= '0' && str[0] <= '9' && pos < 25) -			{ -				remainder = (remainder*10) + U64(str[0] - '0'); -				f_part <<= 1; -				//f_decimal <<= 1; -				// Check the n'th bit -				if (remainder >= float_coeff_table[pos]) -				{ -					remainder -= float_coeff_table[pos]; -					f_part |= 1; -				} -				++pos; -				++str; -			} -			if (pos == 25) -			{ -				// Drop any excessive digits -				while (str[0] >= '0' && str[0] <= '9') -				{ -					++str; -				} -			} -			else -			{ -				while (pos < 25) -				{ -					remainder *= 10; -					f_part <<= 1; -					//f_decimal <<= 1; -					// Check the n'th bit -					if (remainder >= float_coeff_table[pos]) -					{ -						remainder -= float_coeff_table[pos]; -						f_part |= 1; -					} -					++pos; -				} -			} -			pos = 0; -			while (pos < 36) -			{ -				f_part <<= 1; -				//f_decimal <<= 1; -				if (remainder >= float_coeff_table_2[pos]) -				{ -					remainder -= float_coeff_table_2[pos]; -					f_part |= 1; -				} -				++pos; -			} -		} -		 -		F64 ret = F64(int_part) + (F64(f_part)/F64(1LL<<61)); - -		F64 exponent = 1.f; -		if (str[0] == 'e') -		{ -			// Scientific notation! -			++str; -			U64 exp; -			bool is_negative; -			str = parseInteger(str, &exp, &is_negative, 64, ENCODING_DECIMAL); -			if (str == NULL) -			{ -				exp = 1; -			} -			F64 exp_d = F64(exp) * (is_negative?-1:1); -			exponent = pow(10.0, exp_d); -		} - -		if (str == base_str) -		{ -			// no digits parsed -			return NULL; -		} -		else -		{ -			*dest = ret*negative*exponent; -			return str; -		} -	} -	if (encoding == ENCODING_HEX) -	{ -		U64 bytes_dest; -		bool is_negative; -		str = parseInteger(str, (U64 *)&bytes_dest, &is_negative, precision, ENCODING_HEX); -		// Upcast to F64 -		switch (precision) -		{ -		case 32: -			{ -				U32 short_dest = (U32)bytes_dest; -				F32 ret_val = *(F32 *)&short_dest; -				*dest = ret_val; -			} -			break; -		case 64: -			*dest = *(F64 *)&bytes_dest; -			break; -		default: -			return NULL; -		} -		return str; -	} -	return NULL; -} - -U32 LLXMLNode::getBoolValue(U32 expected_length, bool *array) -{ -	llassert(array); - -	// Check type - accept booleans or strings -	if (mType != TYPE_BOOLEAN && mType != TYPE_STRING && mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	std::string *str_array = new std::string[expected_length]; - -	U32 length = getStringValue(expected_length, str_array); - -	U32 ret_length = 0; -	for (U32 i=0; i<length; ++i) -	{ -		LLStringUtil::toLower(str_array[i]); -		if (str_array[i] == "false") -		{ -			array[ret_length++] = false; -		} -		else if (str_array[i] == "true") -		{ -			array[ret_length++] = true; -		} -	} - -	delete[] str_array; - -#if LL_DEBUG -	if (ret_length != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getBoolValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << ret_length << LL_ENDL; -	} -#endif -	return ret_length; -} - -U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding) -{ -	llassert(array); - -	// Check type - accept bytes or integers (below 256 only) -	if (mType != TYPE_INTEGER  -		&& mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	if (mLength > 0 && mLength != expected_length) -	{ -		LL_WARNS() << "XMLNode::getByteValue asked for " << expected_length  -			<< " elements, while node has " << mLength << LL_ENDL; -		return 0; -	} - -	if (encoding == ENCODING_DEFAULT) -	{ -		encoding = mEncoding; -	} - -	const char *value_string = mValue.c_str(); - -	U32 i; -	for (i=0; i<expected_length; ++i) -	{ -		U64 value; -		bool is_negative; -		value_string = parseInteger(value_string, &value, &is_negative, 8, encoding); -		if (value_string == NULL) -		{ -			break; -		} -		if (value > 255 || is_negative) -		{ -			LL_WARNS() << "getByteValue: Value outside of valid range." << LL_ENDL; -			break; -		} -		array[i] = U8(value); -	} -#if LL_DEBUG -	if (i != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getByteValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << i << LL_ENDL; -	} -#endif -	return i; -} - -U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding) -{ -	llassert(array); - -	// Check type - accept bytes or integers -	if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	if (mLength > 0 && mLength != expected_length) -	{ -		LL_WARNS() << "XMLNode::getIntValue asked for " << expected_length  -			<< " elements, while node has " << mLength << LL_ENDL; -		return 0; -	} - -	if (encoding == ENCODING_DEFAULT) -	{ -		encoding = mEncoding; -	} - -	const char *value_string = mValue.c_str(); - -	U32 i = 0; -	for (i=0; i<expected_length; ++i) -	{ -		U64 value; -		bool is_negative; -		value_string = parseInteger(value_string, &value, &is_negative, 32, encoding); -		if (value_string == NULL) -		{ -			break; -		} -		if (value > 0x7fffffff) -		{ -			LL_WARNS() << "getIntValue: Value outside of valid range." << LL_ENDL; -			break; -		} -		array[i] = S32(value) * (is_negative?-1:1); -	} - -#if LL_DEBUG -	if (i != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getIntValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << i << LL_ENDL; -	} -#endif -	return i; -} - -U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding) -{ -	llassert(array); - -	// Check type - accept bytes or integers -	if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	if (mLength > 0 && mLength != expected_length) -	{ -		LL_WARNS() << "XMLNode::getUnsignedValue asked for " << expected_length  -			<< " elements, while node has " << mLength << LL_ENDL; -		return 0; -	} - -	if (encoding == ENCODING_DEFAULT) -	{ -		encoding = mEncoding; -	} - -	const char *value_string = mValue.c_str(); - -	U32 i = 0; -	// Int type -	for (i=0; i<expected_length; ++i) -	{ -		U64 value; -		bool is_negative; -		value_string = parseInteger(value_string, &value, &is_negative, 32, encoding); -		if (value_string == NULL) -		{ -			break; -		} -		if (is_negative || value > 0xffffffff) -		{ -			LL_WARNS() << "getUnsignedValue: Value outside of valid range." << LL_ENDL; -			break; -		} -		array[i] = U32(value); -	} - -#if LL_DEBUG -	if (i != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getUnsignedValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << i << LL_ENDL; -	} -#endif - -	return i; -} - -U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding) -{ -	llassert(array); - -	// Check type - accept bytes or integers -	if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	if (mLength > 0 && mLength != expected_length) -	{ -		LL_WARNS() << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; -		return 0; -	} - -	if (encoding == ENCODING_DEFAULT) -	{ -		encoding = mEncoding; -	} - -	const char *value_string = mValue.c_str(); - -	U32 i = 0; -	// Int type -	for (i=0; i<expected_length; ++i) -	{ -		U64 value; -		bool is_negative; -		value_string = parseInteger(value_string, &value, &is_negative, 64, encoding); -		if (value_string == NULL) -		{ -			break; -		} -		if (is_negative) -		{ -			LL_WARNS() << "getLongValue: Value outside of valid range." << LL_ENDL; -			break; -		} -		array[i] = value; -	} - -#if LL_DEBUG -	if (i != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getLongValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << i << LL_ENDL; -	} -#endif - -	return i; -} - -U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding) -{ -	llassert(array); - -	// Check type - accept only floats or doubles -	if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	if (mLength > 0 && mLength != expected_length) -	{ -		LL_WARNS() << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; -		return 0; -	} - -	if (encoding == ENCODING_DEFAULT) -	{ -		encoding = mEncoding; -	} - -	const char *value_string = mValue.c_str(); - -	U32 i; -	for (i=0; i<expected_length; ++i) -	{ -		F64 value; -		value_string = parseFloat(value_string, &value, 32, encoding); -		if (value_string == NULL) -		{ -			break; -		} -		array[i] = F32(value); -	} -#if LL_DEBUG -	if (i != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getFloatValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << i << LL_ENDL; -	} -#endif -	return i; -} - -U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding) -{ -	llassert(array); - -	// Check type - accept only floats or doubles -	if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	if (mLength > 0 && mLength != expected_length) -	{ -		LL_WARNS() << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; -		return 0; -	} - -	if (encoding == ENCODING_DEFAULT) -	{ -		encoding = mEncoding; -	} - -	const char *value_string = mValue.c_str(); - -	U32 i; -	for (i=0; i<expected_length; ++i) -	{ -		F64 value; -		value_string = parseFloat(value_string, &value, 64, encoding); -		if (value_string == NULL) -		{ -			break; -		} -		array[i] = value; -	} -#if LL_DEBUG -	if (i != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getDoubleValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << i << LL_ENDL; -	} -#endif -	return i; -} - -U32 LLXMLNode::getStringValue(U32 expected_length, std::string *array) -{ -	llassert(array); - -	// Can always return any value as a string - -	if (mLength > 0 && mLength != expected_length) -	{ -		LL_WARNS() << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; -		return 0; -	} - -	U32 num_returned_strings = 0; - -	// Array of strings is whitespace-separated -	const std::string sep(" \n\t"); -	 -	std::string::size_type n = 0; -	std::string::size_type m = 0; -	while(1) -	{ -		if (num_returned_strings >= expected_length) -		{ -			break; -		} -		n = mValue.find_first_not_of(sep, m); -		m = mValue.find_first_of(sep, n); -		if (m == std::string::npos) -		{ -			break; -		} -		array[num_returned_strings++] = mValue.substr(n,m-n); -	} -	if (n != std::string::npos && num_returned_strings < expected_length) -	{ -		array[num_returned_strings++] = mValue.substr(n); -	} -#if LL_DEBUG -	if (num_returned_strings != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getStringValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << num_returned_strings << LL_ENDL; -	} -#endif - -	return num_returned_strings; -} - -U32 LLXMLNode::getUUIDValue(U32 expected_length, LLUUID *array) -{ -	llassert(array); - -	// Check type -	if (mType != TYPE_UUID && mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	const char *value_string = mValue.c_str(); - -	U32 i; -	for (i=0; i<expected_length; ++i) -	{ -		LLUUID uuid_value; -		value_string = skipWhitespace(value_string); - -		if (strlen(value_string) < (UUID_STR_LENGTH-1))		/* Flawfinder: ignore */ -		{ -			break; -		} -		char uuid_string[UUID_STR_LENGTH];		/* Flawfinder: ignore */ -		memcpy(uuid_string, value_string, (UUID_STR_LENGTH-1));		/* Flawfinder: ignore */ -		uuid_string[(UUID_STR_LENGTH-1)] = 0; - -		if (!LLUUID::parseUUID(std::string(uuid_string), &uuid_value)) -		{ -			break; -		} -		value_string = &value_string[(UUID_STR_LENGTH-1)]; -		array[i] = uuid_value; -	} -#if LL_DEBUG -	if (i != expected_length) -	{ -		LL_DEBUGS() << "LLXMLNode::getUUIDValue() failed for node named '"  -			<< mName->mString << "' -- expected " << expected_length << " but " -			<< "only found " << i << LL_ENDL; -	} -#endif -	return i; -} - -U32 LLXMLNode::getNodeRefValue(U32 expected_length, LLXMLNode **array) -{ -	llassert(array); - -	// Check type -	if (mType != TYPE_NODEREF && mType != TYPE_UNKNOWN) -	{ -		return 0; -	} - -	std::string *string_array = new std::string[expected_length]; - -	U32 num_strings = getStringValue(expected_length, string_array); - -	U32 num_returned_refs = 0; - -	LLXMLNodePtr root = getRoot(); -	for (U32 strnum=0; strnum<num_strings; ++strnum) -	{ -		LLXMLNodeList node_list; -		root->findID(string_array[strnum], node_list); -		if (node_list.empty()) -		{ -			LL_WARNS() << "XML: Could not find node ID: " << string_array[strnum] << LL_ENDL; -		} -		else if (node_list.size() > 1) -		{ -			LL_WARNS() << "XML: Node ID not unique: " << string_array[strnum] << LL_ENDL; -		} -		else -		{ -			LLXMLNodeList::const_iterator list_itr = node_list.begin();  -			if (list_itr != node_list.end()) -			{ -				LLXMLNode* child = (*list_itr).second; - -				array[num_returned_refs++] = child; -			} -		} -	} - -	delete[] string_array; - -	return num_returned_refs; -} - -void LLXMLNode::setBoolValue(U32 length, const bool *array) -{ -	if (length == 0) return; - -	std::string new_value; -	for (U32 pos=0; pos<length; ++pos) -	{ -		if (pos > 0) -		{ -			new_value = llformat("%s %s", new_value.c_str(), array[pos]?"true":"false"); -		} -		else -		{ -			new_value = array[pos]?"true":"false"; -		} -	} - -	mValue = new_value; -	mEncoding = ENCODING_DEFAULT; -	mLength = length; -	mType = TYPE_BOOLEAN; -} - -void LLXMLNode::setByteValue(U32 length, const U8* const array, Encoding encoding) -{ -	if (length == 0) return; - -	std::string new_value; -	if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) -	{ -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0) -			{ -				new_value.append(llformat(" %u", array[pos])); -			} -			else -			{ -				new_value = llformat("%u", array[pos]); -			} -		} -	} -	if (encoding == ENCODING_HEX) -	{ -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0 && pos % 16 == 0) -			{ -				new_value.append(llformat(" %02X", array[pos])); -			} -			else -			{ -				new_value.append(llformat("%02X", array[pos])); -			} -		} -	} -	// TODO -- Handle Base32 - -	mValue = new_value; -	mEncoding = encoding; -	mLength = length; -	mType = TYPE_INTEGER; -	mPrecision = 8; -} - - -void LLXMLNode::setIntValue(U32 length, const S32 *array, Encoding encoding) -{ -	if (length == 0) return; - -	std::string new_value; -	if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) -	{ -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0) -			{ -				new_value.append(llformat(" %d", array[pos])); -			} -			else -			{ -				new_value = llformat("%d", array[pos]); -			} -		} -		mValue = new_value; -	} -	else if (encoding == ENCODING_HEX) -	{ -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0 && pos % 16 == 0) -			{ -				new_value.append(llformat(" %08X", ((U32 *)array)[pos])); -			} -			else -			{ -				new_value.append(llformat("%08X", ((U32 *)array)[pos])); -			} -		} -		mValue = new_value; -	} -	else -	{ -		mValue = new_value; -	} -	// TODO -- Handle Base32 - -	mEncoding = encoding; -	mLength = length; -	mType = TYPE_INTEGER; -	mPrecision = 32; -} - -void LLXMLNode::setUnsignedValue(U32 length, const U32* array, Encoding encoding) -{ -	if (length == 0) return; - -	std::string new_value; -	if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) -	{ -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0) -			{ -				new_value.append(llformat(" %u", array[pos])); -			} -			else -			{ -				new_value = llformat("%u", array[pos]); -			} -		} -	} -	if (encoding == ENCODING_HEX) -	{ -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0 && pos % 16 == 0) -			{ -				new_value.append(llformat(" %08X", array[pos])); -			} -			else -			{ -				new_value.append(llformat("%08X", array[pos])); -			} -		} -		mValue = new_value; -	} -	// TODO -- Handle Base32 - -	mValue = new_value; -	mEncoding = encoding; -	mLength = length; -	mType = TYPE_INTEGER; -	mPrecision = 32; -} - -#if LL_WINDOWS -#define PU64 "I64u" -#else -#define PU64 "llu" -#endif - -void LLXMLNode::setLongValue(U32 length, const U64* array, Encoding encoding) -{ -	if (length == 0) return; - -	std::string new_value; -	if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) -	{ -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0) -			{ -				new_value.append(llformat(" %" PU64, array[pos])); -			} -			else -			{ -				new_value = llformat("%" PU64, array[pos]); -			} -		} -		mValue = new_value; -	} -	if (encoding == ENCODING_HEX) -	{ -		for (U32 pos=0; pos<length; ++pos) -		{ -			U32 upper_32 = U32(array[pos]>>32); -			U32 lower_32 = U32(array[pos]&0xffffffff); -			if (pos > 0 && pos % 8 == 0) -			{ -				new_value.append(llformat(" %08X%08X", upper_32, lower_32)); -			} -			else -			{ -				new_value.append(llformat("%08X%08X", upper_32, lower_32)); -			} -		} -		mValue = new_value; -	} -	else -	{ -		mValue = new_value; -	} -	// TODO -- Handle Base32 - -	mEncoding = encoding; -	mLength = length; -	mType = TYPE_INTEGER; -	mPrecision = 64; -} - -void LLXMLNode::setFloatValue(U32 length, const F32 *array, Encoding encoding, U32 precision) -{ -	if (length == 0) return; - -	std::string new_value; -	if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) -	{ -		std::string format_string; -		if (precision > 0) -		{ -			if (precision > 25) -			{ -				precision = 25; -			} -			format_string = llformat( "%%.%dg", precision); -		} -		else -		{ -			format_string = llformat( "%%g"); -		} - -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0) -			{ -				new_value.append(" "); -				new_value.append(llformat(format_string.c_str(), array[pos])); -			} -			else -			{ -				new_value.assign(llformat(format_string.c_str(), array[pos])); -			} -		} -		mValue = new_value; -	} -	else if (encoding == ENCODING_HEX) -	{ -		U32 *byte_array = (U32 *)array; -		setUnsignedValue(length, byte_array, ENCODING_HEX); -	} -	else -	{ -		mValue = new_value; -	} - -	mEncoding = encoding; -	mLength = length; -	mType = TYPE_FLOAT; -	mPrecision = 32; -} - -void LLXMLNode::setDoubleValue(U32 length, const F64 *array, Encoding encoding, U32 precision) -{ -	if (length == 0) return; - -	std::string new_value; -	if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL) -	{ -		std::string format_string; -		if (precision > 0) -		{ -			if (precision > 25) -			{ -				precision = 25; -			} -			format_string = llformat( "%%.%dg", precision); -		} -		else -		{ -			format_string = llformat( "%%g"); -		} -		for (U32 pos=0; pos<length; ++pos) -		{ -			if (pos > 0) -			{ -				new_value.append(" "); -				new_value.append(llformat(format_string.c_str(), array[pos])); -			} -			else -			{ -				new_value.assign(llformat(format_string.c_str(), array[pos])); -			} -		} -		mValue = new_value; -	} -	if (encoding == ENCODING_HEX) -	{ -		U64 *byte_array = (U64 *)array; -		setLongValue(length, byte_array, ENCODING_HEX); -	} -	else -	{ -		mValue = new_value; -	} -	// TODO -- Handle Base32 - -	mEncoding = encoding; -	mLength = length; -	mType = TYPE_FLOAT; -	mPrecision = 64; -} - -// static -std::string LLXMLNode::escapeXML(const std::string& xml) -{ -	std::string out; -	for (std::string::size_type i = 0; i < xml.size(); ++i) -	{ -		char c = xml[i]; -		switch(c) -		{ -		case '"':	out.append(""");	break; -		case '\'':	out.append("'");	break; -		case '&':	out.append("&");	break; -		case '<':	out.append("<");		break; -		case '>':	out.append(">");		break; -		default:	out.push_back(c);		break; -		} -	} -	return out; -} - -void LLXMLNode::setStringValue(U32 length, const std::string *strings) -{ -	if (length == 0) return; - -	std::string new_value; -	for (U32 pos=0; pos<length; ++pos) -	{ -		// *NOTE: Do not escape strings here - do it on output -		new_value.append( strings[pos] ); -		if (pos < length-1) new_value.append(" "); -	} - -	mValue = new_value; -	mEncoding = ENCODING_DEFAULT; -	mLength = length; -	mType = TYPE_STRING; -} - -void LLXMLNode::setUUIDValue(U32 length, const LLUUID *array) -{ -	if (length == 0) return; - -	std::string new_value; -	for (U32 pos=0; pos<length; ++pos) -	{ -		new_value.append(array[pos].asString()); -		if (pos < length-1) new_value.append(" "); -	} - -	mValue = new_value; -	mEncoding = ENCODING_DEFAULT; -	mLength = length; -	mType = TYPE_UUID; -} - -void LLXMLNode::setNodeRefValue(U32 length, const LLXMLNode **array) -{ -	if (length == 0) return; - -	std::string new_value; -	for (U32 pos=0; pos<length; ++pos) -	{ -		if (array[pos]->mID != "") -		{ -			new_value.append(array[pos]->mID); -		} -		else -		{ -			new_value.append("(null)"); -		} -		if (pos < length-1) new_value.append(" "); -	} - -	mValue = new_value; -	mEncoding = ENCODING_DEFAULT; -	mLength = length; -	mType = TYPE_NODEREF; -} - -void LLXMLNode::setValue(const std::string& value) -{ -	if (TYPE_CONTAINER == mType) -	{ -		mType = TYPE_UNKNOWN; -	} -	mValue = value; -} - -void LLXMLNode::setDefault(LLXMLNode *default_node) -{ -	mDefault = default_node; -} - -void LLXMLNode::findDefault(LLXMLNode *defaults_list) -{ -	if (defaults_list) -	{ -		LLXMLNodeList children; -		defaults_list->getChildren(mName->mString, children); - -		LLXMLNodeList::const_iterator children_itr; -		LLXMLNodeList::const_iterator children_end = children.end(); -		for (children_itr = children.begin(); children_itr != children_end; ++children_itr) -		{ -			LLXMLNode* child = (*children_itr).second; -			if (child->mVersionMajor == mVersionMajor && -				child->mVersionMinor == mVersionMinor) -			{ -				mDefault = child; -				return; -			} -		} -	} -	mDefault = NULL; -} - -bool LLXMLNode::deleteChildren(const std::string& name) -{ -	U32 removed_count = 0; -	LLXMLNodeList node_list; -	findName(name, node_list); -	if (!node_list.empty()) -	{ -		// TODO -- use multimap::find() -		// TODO -- need to watch out for invalid iterators -		LLXMLNodeList::iterator children_itr; -		for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr) -		{  -			LLXMLNode* child = (*children_itr).second; -			if (deleteChild(child)) -			{ -				removed_count++; -			} -		} -	} -	return removed_count > 0; -} - -bool LLXMLNode::deleteChildren(LLStringTableEntry* name) -{ -	U32 removed_count = 0; -	LLXMLNodeList node_list; -	findName(name, node_list); -	if (!node_list.empty()) -	{ -		// TODO -- use multimap::find() -		// TODO -- need to watch out for invalid iterators -		LLXMLNodeList::iterator children_itr; -		for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr) -		{  -			LLXMLNode* child = (*children_itr).second; -			if (deleteChild(child)) -			{ -				removed_count++; -			} -		} -	} -	return removed_count > 0; -} - -void LLXMLNode::setAttributes(LLXMLNode::ValueType type, U32 precision, LLXMLNode::Encoding encoding, U32 length) -{ -	mType = type; -	mEncoding = encoding; -	mPrecision = precision; -	mLength = length; -} - -void LLXMLNode::setName(const std::string& name) -{ -	setName(gStringTable.addStringEntry(name)); -} - -void LLXMLNode::setName(LLStringTableEntry* name) -{ -	LLXMLNode* old_parent = mParent; -	if (mParent) -	{ -		// we need to remove and re-add to the parent so that -		// the multimap key agrees with this node's name -		mParent->removeChild(this); -	} -	mName = name; -	if (old_parent) -	{ -		LLXMLNodePtr this_ptr(this); -		old_parent->addChild(this_ptr); -	} -} - -// Unused -// void LLXMLNode::appendValue(const std::string& value) -// { -// 	mValue.append(value); -// } - -U32 LLXMLNode::getChildCount() const  -{  -	if (mChildren.notNull()) -	{ -		return mChildren->map.size();  -	} -	return 0; -} - -//*************************************************** -//  UNIT TESTING  -//*************************************************** - -U32 get_rand(U32 max_value) -{ -	U32 random_num = rand() + ((U32)rand() << 16); -	return (random_num % max_value); -} - -LLXMLNode *get_rand_node(LLXMLNode *node) -{ -	if (node->mChildren.notNull()) -	{ -		U32 num_children = node->mChildren->map.size(); -		if (get_rand(2) == 0) -		{ -			while (true) -			{ -				S32 child_num = S32(get_rand(num_children*2)) - num_children; -				LLXMLChildList::iterator itor = node->mChildren->map.begin(); -				while (child_num > 0) -				{ -					--child_num; -					++itor; -				} -				if (!itor->second->mIsAttribute) -				{ -					return get_rand_node(itor->second); -				} -			} -		} -	} -	return node; -} - -void LLXMLNode::createUnitTest(S32 max_num_children) -{ -	// Random ID -	std::string rand_id; -	U32 rand_id_len = get_rand(10)+5; -	for (U32 pos = 0; pos<rand_id_len; ++pos) -	{ -		char c = 'a' + get_rand(26); -		rand_id.append(1, c); -	} -	mID = rand_id; - -	if (max_num_children < 2) -	{ -		setStringValue(1, &mID); -		return; -	} - -	// Checksums -	U32 integer_checksum = 0; -	U64 long_checksum = 0; -	U32 bool_true_count = 0; -	LLUUID uuid_checksum; -	U32 noderef_checksum = 0; -	U32 float_checksum = 0; - -	// Create a random number of children -	U32 num_children = get_rand(max_num_children)+1; -	for (U32 child_num=0; child_num<num_children; ++child_num) -	{ -		// Random Name -		std::string child_name; -		U32 child_name_len = get_rand(10)+5; -		for (U32 pos = 0; pos<child_name_len; ++pos) -		{ -			char c = 'a' + get_rand(26); -			child_name.append(1, c); -		} - -		LLXMLNode *new_child = createChild(child_name.c_str(), false); - -		// Random ID -		std::string child_id; -		U32 child_id_len = get_rand(10)+5; -		for (U32 pos=0; pos<child_id_len; ++pos) -		{ -			char c = 'a' + get_rand(26); -			child_id.append(1, c); -		} -		new_child->mID = child_id; - -		// Random Length -		U32 array_size = get_rand(28)+1; - -		// Random Encoding -		Encoding new_encoding = get_rand(2)?ENCODING_DECIMAL:ENCODING_HEX; - -		// Random Type -		int type = get_rand(8); -		switch (type) -		{ -		case 0: // TYPE_CONTAINER -			new_child->createUnitTest(max_num_children/2); -			break; -		case 1: // TYPE_BOOLEAN -			{ -				bool random_bool_values[30]; -				for (U32 value=0; value<array_size; ++value) -				{ -					random_bool_values[value] = get_rand(2); -					if (random_bool_values[value]) -					{ -						++bool_true_count; -					} -				} -				new_child->setBoolValue(array_size, random_bool_values); -			} -			break; -		case 2: // TYPE_INTEGER (32-bit) -			{ -				U32 random_int_values[30]; -				for (U32 value=0; value<array_size; ++value) -				{ -					random_int_values[value] = get_rand(0xffffffff); -					integer_checksum ^= random_int_values[value]; -				} -				new_child->setUnsignedValue(array_size, random_int_values, new_encoding); -			} -			break; -		case 3: // TYPE_INTEGER (64-bit) -			{ -				U64 random_int_values[30]; -				for (U64 value=0; value<array_size; ++value) -				{ -					random_int_values[value] = (U64(get_rand(0xffffffff)) << 32) + get_rand(0xffffffff); -					long_checksum ^= random_int_values[value]; -				} -				new_child->setLongValue(array_size, random_int_values, new_encoding); -			} -			break; -		case 4: // TYPE_FLOAT (32-bit) -			{ -				F32 random_float_values[30]; -				for (U32 value=0; value<array_size; ++value) -				{ -					S32 exponent = get_rand(256) - 128; -					S32 fractional_part = get_rand(0xffffffff); -					S32 sign = get_rand(2) * 2 - 1; -					random_float_values[value] = F32(fractional_part) / F32(0xffffffff) * exp(F32(exponent)) * F32(sign); - -					U32 *float_bits = &((U32 *)random_float_values)[value]; -					if (*float_bits == 0x80000000) -					{ -						*float_bits = 0x00000000; -					} -					float_checksum ^= (*float_bits & 0xfffff000); -				} -				new_child->setFloatValue(array_size, random_float_values, new_encoding, 12); -			} -			break; -		case 5: // TYPE_FLOAT (64-bit) -			{ -				F64 random_float_values[30]; -				for (U32 value=0; value<array_size; ++value) -				{ -					S32 exponent = get_rand(2048) - 1024; -					S32 fractional_part = get_rand(0xffffffff); -					S32 sign = get_rand(2) * 2 - 1; -					random_float_values[value] = F64(fractional_part) / F64(0xffffffff) * exp(F64(exponent)) * F64(sign); - -					U64 *float_bits = &((U64 *)random_float_values)[value]; -					if (*float_bits == 0x8000000000000000ll) -					{ -						*float_bits = 0x0000000000000000ll; -					} -					float_checksum ^= ((*float_bits & 0xfffffff000000000ll) >> 32); -				} -				new_child->setDoubleValue(array_size, random_float_values, new_encoding, 12); -			} -			break; -		case 6: // TYPE_UUID -			{ -				LLUUID random_uuid_values[30]; -				for (U32 value=0; value<array_size; ++value) -				{ -					random_uuid_values[value].generate(); -					for (S32 byte=0; byte<UUID_BYTES; ++byte) -					{ -						uuid_checksum.mData[byte] ^= random_uuid_values[value].mData[byte]; -					} -				} -				new_child->setUUIDValue(array_size, random_uuid_values); -			} -			break; -		case 7: // TYPE_NODEREF -			{ -				LLXMLNode *random_node_array[30]; -				LLXMLNode *root = getRoot(); -				for (U32 value=0; value<array_size; ++value) -				{ -					random_node_array[value] = get_rand_node(root); -					const char *node_name = random_node_array[value]->mName->mString; -					for (U32 pos=0; pos<strlen(node_name); ++pos)		/* Flawfinder: ignore */ -					{ -						U32 hash_contrib = U32(node_name[pos]) << ((pos % 4) * 8); -						noderef_checksum ^= hash_contrib; -					} -				} -				new_child->setNodeRefValue(array_size, (const LLXMLNode **)random_node_array); -			} -			break; -		} -	} - -	createChild("integer_checksum", true)->setUnsignedValue(1, &integer_checksum, LLXMLNode::ENCODING_HEX); -	createChild("long_checksum", true)->setLongValue(1, &long_checksum, LLXMLNode::ENCODING_HEX); -	createChild("bool_true_count", true)->setUnsignedValue(1, &bool_true_count, LLXMLNode::ENCODING_HEX); -	createChild("uuid_checksum", true)->setUUIDValue(1, &uuid_checksum); -	createChild("noderef_checksum", true)->setUnsignedValue(1, &noderef_checksum, LLXMLNode::ENCODING_HEX); -	createChild("float_checksum", true)->setUnsignedValue(1, &float_checksum, LLXMLNode::ENCODING_HEX); -} - -bool LLXMLNode::performUnitTest(std::string &error_buffer) -{ -	if (mChildren.isNull()) -	{ -		error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString)); -		return false; -	} - -	// Checksums -	U32 integer_checksum = 0; -	U32 bool_true_count = 0; -	LLUUID uuid_checksum; -	U32 noderef_checksum = 0; -	U32 float_checksum = 0; -	U64 long_checksum = 0; - -	LLXMLChildList::iterator itor; -	for (itor=mChildren->map.begin(); itor!=mChildren->map.end(); ++itor) -	{ -		LLXMLNode *node = itor->second; -		if (node->mIsAttribute) -		{ -			continue; -		} -		if (node->mType == TYPE_CONTAINER) -		{ -			if (!node->performUnitTest(error_buffer)) -			{ -				error_buffer.append(llformat("Child test failed for %s.\n", mName->mString)); -				//return false; -			} -			continue; -		} -		if (node->mLength < 1 || node->mLength > 30) -		{ -			error_buffer.append(llformat("ERROR Node %s: Invalid array length %d, child %s.\n", mName->mString, node->mLength, node->mName->mString)); -			return false; -		} -		switch (node->mType) -		{ -		case TYPE_CONTAINER: -		case TYPE_UNKNOWN: -			break; -		case TYPE_BOOLEAN: -			{ -				bool bool_array[30]; -				if (node->getBoolValue(node->mLength, bool_array) < node->mLength) -				{ -					error_buffer.append(llformat("ERROR Node %s: Could not read boolean array, child %s.\n", mName->mString, node->mName->mString)); -					return false; -				} -				for (U32 pos=0; pos<(U32)node->mLength; ++pos) -				{ -					if (bool_array[pos]) -					{ -						++bool_true_count; -					} -				} -			} -			break; -		case TYPE_INTEGER: -			{ -				if (node->mPrecision == 32) -				{ -					U32 integer_array[30]; -					if (node->getUnsignedValue(node->mLength, integer_array, node->mEncoding) < node->mLength) -					{ -						error_buffer.append(llformat("ERROR Node %s: Could not read integer array, child %s.\n", mName->mString, node->mName->mString)); -						return false; -					} -					for (U32 pos=0; pos<(U32)node->mLength; ++pos) -					{ -						integer_checksum ^= integer_array[pos]; -					} -				} -				else -				{ -					U64 integer_array[30]; -					if (node->getLongValue(node->mLength, integer_array, node->mEncoding) < node->mLength) -					{ -						error_buffer.append(llformat("ERROR Node %s: Could not read long integer array, child %s.\n", mName->mString, node->mName->mString)); -						return false; -					} -					for (U32 pos=0; pos<(U32)node->mLength; ++pos) -					{ -						long_checksum ^= integer_array[pos]; -					} -				} -			} -			break; -		case TYPE_FLOAT: -			{ -				if (node->mPrecision == 32) -				{ -					F32 float_array[30]; -					if (node->getFloatValue(node->mLength, float_array, node->mEncoding) < node->mLength) -					{ -						error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString)); -						return false; -					} -					for (U32 pos=0; pos<(U32)node->mLength; ++pos) -					{ -						U32 float_bits = ((U32 *)float_array)[pos]; -						float_checksum ^= (float_bits & 0xfffff000); -					} -				} -				else -				{ -					F64 float_array[30]; -					if (node->getDoubleValue(node->mLength, float_array, node->mEncoding) < node->mLength) -					{ -						error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString)); -						return false; -					} -					for (U32 pos=0; pos<(U32)node->mLength; ++pos) -					{ -						U64 float_bits = ((U64 *)float_array)[pos]; -						float_checksum ^= ((float_bits & 0xfffffff000000000ll) >> 32); -					} -				} -			} -			break; -		case TYPE_STRING: -			break; -		case TYPE_UUID: -			{ -				LLUUID uuid_array[30]; -				if (node->getUUIDValue(node->mLength, uuid_array) < node->mLength) -				{ -					error_buffer.append(llformat("ERROR Node %s: Could not read uuid array, child %s.\n", mName->mString, node->mName->mString)); -					return false; -				} -				for (U32 pos=0; pos<(U32)node->mLength; ++pos) -				{ -					for (S32 byte=0; byte<UUID_BYTES; ++byte) -					{ -						uuid_checksum.mData[byte] ^= uuid_array[pos].mData[byte]; -					} -				} -			} -			break; -		case TYPE_NODEREF: -			{ -				LLXMLNode *node_array[30]; -				if (node->getNodeRefValue(node->mLength, node_array) < node->mLength) -				{ -					error_buffer.append(llformat("ERROR Node %s: Could not read node ref array, child %s.\n", mName->mString, node->mName->mString)); -					return false; -				} -				for (U32 pos=0; pos<node->mLength; ++pos) -				{ -					const char *node_name = node_array[pos]->mName->mString; -					for (U32 pos2=0; pos2<strlen(node_name); ++pos2)		/* Flawfinder: ignore */ -					{ -						U32 hash_contrib = U32(node_name[pos2]) << ((pos2 % 4) * 8); -						noderef_checksum ^= hash_contrib; -					} -				} -			} -			break; -		} -	} - -	LLXMLNodePtr checksum_node; - -	// Compare checksums -	{ -		U32 node_integer_checksum = 0; -		if (!getAttribute("integer_checksum", checksum_node, false) ||  -			checksum_node->getUnsignedValue(1, &node_integer_checksum, ENCODING_HEX) != 1) -		{ -			error_buffer.append(llformat("ERROR Node %s: Integer checksum missing.\n", mName->mString)); -			return false; -		} -		if (node_integer_checksum != integer_checksum) -		{ -			error_buffer.append(llformat("ERROR Node %s: Integer checksum mismatch: read %X / calc %X.\n", mName->mString, node_integer_checksum, integer_checksum)); -			return false; -		} -	} - -	{ -		U64 node_long_checksum = 0; -		if (!getAttribute("long_checksum", checksum_node, false) ||  -			checksum_node->getLongValue(1, &node_long_checksum, ENCODING_HEX) != 1) -		{ -			error_buffer.append(llformat("ERROR Node %s: Long Integer checksum missing.\n", mName->mString)); -			return false; -		} -		if (node_long_checksum != long_checksum) -		{ -			U32 *pp1 = (U32 *)&node_long_checksum; -			U32 *pp2 = (U32 *)&long_checksum; -			error_buffer.append(llformat("ERROR Node %s: Long Integer checksum mismatch: read %08X%08X / calc %08X%08X.\n", mName->mString, pp1[1], pp1[0], pp2[1], pp2[0])); -			return false; -		} -	} - -	{ -		U32 node_bool_true_count = 0; -		if (!getAttribute("bool_true_count", checksum_node, false) ||  -			checksum_node->getUnsignedValue(1, &node_bool_true_count, ENCODING_HEX) != 1) -		{ -			error_buffer.append(llformat("ERROR Node %s: Boolean checksum missing.\n", mName->mString)); -			return false; -		} -		if (node_bool_true_count != bool_true_count) -		{ -			error_buffer.append(llformat("ERROR Node %s: Boolean checksum mismatch: read %X / calc %X.\n", mName->mString, node_bool_true_count, bool_true_count)); -			return false; -		} -	} - -	{ -		LLUUID node_uuid_checksum; -		if (!getAttribute("uuid_checksum", checksum_node, false) ||  -			checksum_node->getUUIDValue(1, &node_uuid_checksum) != 1) -		{ -			error_buffer.append(llformat("ERROR Node %s: UUID checksum missing.\n", mName->mString)); -			return false; -		} -		if (node_uuid_checksum != uuid_checksum) -		{ -			error_buffer.append(llformat("ERROR Node %s: UUID checksum mismatch: read %s / calc %s.\n", mName->mString, node_uuid_checksum.asString().c_str(), uuid_checksum.asString().c_str())); -			return false; -		} -	} - -	{ -		U32 node_noderef_checksum = 0; -		if (!getAttribute("noderef_checksum", checksum_node, false) ||  -			checksum_node->getUnsignedValue(1, &node_noderef_checksum, ENCODING_HEX) != 1) -		{ -			error_buffer.append(llformat("ERROR Node %s: Node Ref checksum missing.\n", mName->mString)); -			return false; -		} -		if (node_noderef_checksum != noderef_checksum) -		{ -			error_buffer.append(llformat("ERROR Node %s: Node Ref checksum mismatch: read %X / calc %X.\n", mName->mString, node_noderef_checksum, noderef_checksum)); -			return false; -		} -	} - -	{ -		U32 node_float_checksum = 0; -		if (!getAttribute("float_checksum", checksum_node, false) ||  -			checksum_node->getUnsignedValue(1, &node_float_checksum, ENCODING_HEX) != 1) -		{ -			error_buffer.append(llformat("ERROR Node %s: Float checksum missing.\n", mName->mString)); -			return false; -		} -		if (node_float_checksum != float_checksum) -		{ -			error_buffer.append(llformat("ERROR Node %s: Float checksum mismatch: read %X / calc %X.\n", mName->mString, node_float_checksum, float_checksum)); -			return false; -		} -	} - -	return true; -} - -LLXMLNodePtr LLXMLNode::getFirstChild() const -{ -	if (mChildren.isNull()) return NULL; -	LLXMLNodePtr ret = mChildren->head; -	return ret; -} - -LLXMLNodePtr LLXMLNode::getNextSibling() const -{ -	LLXMLNodePtr ret = mNext; -	return ret; -} - -std::string LLXMLNode::getSanitizedValue() const  -{  -	if (mIsAttribute)  -	{ -		return getValue() ; -	} -	else  -	{ -		return getTextContents();  -	} -} - - -std::string LLXMLNode::getTextContents() const -{ -	std::string msg; -	std::string contents = mValue; -	std::string::size_type n = contents.find_first_not_of(" \t\n"); -	if (n != std::string::npos && contents[n] == '\"') -	{ -		// Case 1: node has quoted text -		S32 num_lines = 0; -		while(1) -		{ -			// mContents[n] == '"' -			++n; -			std::string::size_type t = n; -			std::string::size_type m = 0; -			// fix-up escaped characters -			while(1) -			{ -				m = contents.find_first_of("\\\"", t); // find first \ or " -				if ((m == std::string::npos) || (contents[m] == '\"')) -				{ -					break; -				} -				contents.erase(m,1); -				t = m+1; -			} -			if (m == std::string::npos) -			{ -				break; -			} -			// mContents[m] == '"' -			num_lines++; -			msg += contents.substr(n,m-n) + "\n"; -			n = contents.find_first_of("\"", m+1); -			if (n == std::string::npos) -			{ -				if (num_lines == 1) -				{ -					msg.erase(msg.size()-1); // remove "\n" if only one line -				} -				break; -			} -		} -	} -	else -	{ -		// Case 2: node has embedded text (beginning and trailing whitespace trimmed) -		std::string::size_type start = mValue.find_first_not_of(" \t\n"); -		if (start != mValue.npos) -		{ -			std::string::size_type end = mValue.find_last_not_of(" \t\n"); -			if (end != mValue.npos) -			{ -				msg = mValue.substr(start, end+1-start); -			} -			else -			{ -				msg = mValue.substr(start); -			} -		} -		// Convert any internal CR to LF -		msg = utf8str_removeCRLF(msg); -	} -	return msg; -} - -void LLXMLNode::setLineNumber(S32 line_number) -{ -	mLineNumber = line_number; -} - -S32 LLXMLNode::getLineNumber() -{ -	return mLineNumber; -} +/**
 + * @file llxmlnode.cpp
 + * @author Tom Yedwab
 + * @brief LLXMLNode implementation
 + *
 + * $LicenseInfo:firstyear=2005&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, Linden Research, Inc.
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation;
 + * version 2.1 of the License only.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 + *
 + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 + * $/LicenseInfo$
 + */
 +
 +#include "linden_common.h"
 +
 +#include <iostream>
 +#include <map>
 +
 +#include "llxmlnode.h"
 +
 +#include "v3color.h"
 +#include "v4color.h"
 +#include "v4coloru.h"
 +#include "v3math.h"
 +#include "v3dmath.h"
 +#include "v4math.h"
 +#include "llquaternion.h"
 +#include "llstring.h"
 +#include "lluuid.h"
 +#include "lldir.h"
 +
 +// static
 +bool LLXMLNode::sStripEscapedStrings = true;
 +bool LLXMLNode::sStripWhitespaceValues = false;
 +
 +LLXMLNode::LLXMLNode() :
 +    mID(""),
 +    mParser(NULL),
 +    mIsAttribute(false),
 +    mVersionMajor(0),
 +    mVersionMinor(0),
 +    mLength(0),
 +    mPrecision(64),
 +    mType(TYPE_CONTAINER),
 +    mEncoding(ENCODING_DEFAULT),
 +    mLineNumber(-1),
 +    mParent(NULL),
 +    mChildren(NULL),
 +    mAttributes(),
 +    mPrev(NULL),
 +    mNext(NULL),
 +    mName(NULL),
 +    mValue(""),
 +    mDefault(NULL)
 +{
 +}
 +
 +LLXMLNode::LLXMLNode(const char* name, bool is_attribute) :
 +    mID(""),
 +    mParser(NULL),
 +    mIsAttribute(is_attribute),
 +    mVersionMajor(0),
 +    mVersionMinor(0),
 +    mLength(0),
 +    mPrecision(64),
 +    mType(TYPE_CONTAINER),
 +    mEncoding(ENCODING_DEFAULT),
 +    mLineNumber(-1),
 +    mParent(NULL),
 +    mChildren(NULL),
 +    mAttributes(),
 +    mPrev(NULL),
 +    mNext(NULL),
 +    mValue(""),
 +    mDefault(NULL)
 +{
 +    mName = gStringTable.addStringEntry(name);
 +}
 +
 +LLXMLNode::LLXMLNode(LLStringTableEntry* name, bool is_attribute) :
 +    mID(""),
 +    mParser(NULL),
 +    mIsAttribute(is_attribute),
 +    mVersionMajor(0),
 +    mVersionMinor(0),
 +    mLength(0),
 +    mPrecision(64),
 +    mType(TYPE_CONTAINER),
 +    mEncoding(ENCODING_DEFAULT),
 +    mLineNumber(-1),
 +    mParent(NULL),
 +    mChildren(NULL),
 +    mAttributes(),
 +    mPrev(NULL),
 +    mNext(NULL),
 +    mName(name),
 +    mValue(""),
 +    mDefault(NULL)
 +{
 +}
 +
 +// copy constructor (except for the children)
 +LLXMLNode::LLXMLNode(const LLXMLNode& rhs) :
 +    mID(rhs.mID),
 +    mIsAttribute(rhs.mIsAttribute),
 +    mVersionMajor(rhs.mVersionMajor),
 +    mVersionMinor(rhs.mVersionMinor),
 +    mLength(rhs.mLength),
 +    mPrecision(rhs.mPrecision),
 +    mType(rhs.mType),
 +    mEncoding(rhs.mEncoding),
 +    mLineNumber(0),
 +    mParser(NULL),
 +    mParent(NULL),
 +    mChildren(NULL),
 +    mAttributes(),
 +    mPrev(NULL),
 +    mNext(NULL),
 +    mName(rhs.mName),
 +    mValue(rhs.mValue),
 +    mDefault(rhs.mDefault)
 +{
 +}
 +
 +// returns a new copy of this node and all its children
 +LLXMLNodePtr LLXMLNode::deepCopy()
 +{
 +    LLXMLNodePtr newnode = LLXMLNodePtr(new LLXMLNode(*this));
 +    if (mChildren.notNull())
 +    {
 +        for (LLXMLChildList::iterator iter = mChildren->map.begin();
 +             iter != mChildren->map.end(); ++iter)
 +        {
 +            LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy());
 +            newnode->addChild(temp_ptr_for_gcc);
 +        }
 +    }
 +    for (LLXMLAttribList::iterator iter = mAttributes.begin();
 +         iter != mAttributes.end(); ++iter)
 +    {
 +        LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy());
 +        newnode->addChild(temp_ptr_for_gcc);
 +    }
 +
 +    return newnode;
 +}
 +
 +// virtual
 +LLXMLNode::~LLXMLNode()
 +{
 +    // Strictly speaking none of this should be required execept 'delete mChildren'...
 +    // Sadly, that's only true if we hadn't had reference-counted smart pointers linked
 +    // in three different directions. This entire class is a frightening, hard-to-maintain
 +    // mess.
 +    if (mChildren.notNull())
 +    {
 +        for (LLXMLChildList::iterator iter = mChildren->map.begin();
 +             iter != mChildren->map.end(); ++iter)
 +        {
 +            LLXMLNodePtr child = iter->second;
 +            child->mParent = NULL;
 +            child->mNext = NULL;
 +            child->mPrev = NULL;
 +        }
 +        mChildren->map.clear();
 +        mChildren->head = NULL;
 +        mChildren->tail = NULL;
 +        mChildren = NULL;
 +    }
 +    for (LLXMLAttribList::iterator iter = mAttributes.begin();
 +         iter != mAttributes.end(); ++iter)
 +    {
 +        LLXMLNodePtr attr = iter->second;
 +        attr->mParent = NULL;
 +        attr->mNext = NULL;
 +        attr->mPrev = NULL;
 +    }
 +    llassert(mParent == NULL);
 +    mDefault = NULL;
 +}
 +
 +bool LLXMLNode::isNull()
 +{
 +    return (mName == NULL);
 +}
 +
 +// protected
 +bool LLXMLNode::removeChild(LLXMLNode *target_child)
 +{
 +    if (!target_child)
 +    {
 +        return false;
 +    }
 +    if (target_child->mIsAttribute)
 +    {
 +        LLXMLAttribList::iterator children_itr = mAttributes.find(target_child->mName);
 +        if (children_itr != mAttributes.end())
 +        {
 +            target_child->mParent = NULL;
 +            mAttributes.erase(children_itr);
 +            return true;
 +        }
 +    }
 +    else if (mChildren.notNull())
 +    {
 +        LLXMLChildList::iterator children_itr = mChildren->map.find(target_child->mName);
 +        while (children_itr != mChildren->map.end())
 +        {
 +            if (target_child == children_itr->second)
 +            {
 +                if (target_child == mChildren->head)
 +                {
 +                    mChildren->head = target_child->mNext;
 +                }
 +                if (target_child == mChildren->tail)
 +                {
 +                    mChildren->tail = target_child->mPrev;
 +                }
 +
 +                LLXMLNodePtr prev = target_child->mPrev;
 +                LLXMLNodePtr next = target_child->mNext;
 +                if (prev.notNull()) prev->mNext = next;
 +                if (next.notNull()) next->mPrev = prev;
 +
 +                target_child->mPrev = NULL;
 +                target_child->mNext = NULL;
 +                target_child->mParent = NULL;
 +                mChildren->map.erase(children_itr);
 +                if (mChildren->map.empty())
 +                {
 +                    mChildren = NULL;
 +                }
 +                return true;
 +            }
 +            else if (children_itr->first != target_child->mName)
 +            {
 +                break;
 +            }
 +            else
 +            {
 +                ++children_itr;
 +            }
 +        }
 +    }
 +    return false;
 +}
 +
 +void LLXMLNode::addChild(LLXMLNodePtr& new_child)
 +{
 +    if (new_child->mParent != NULL)
 +    {
 +        if (new_child->mParent == this)
 +        {
 +            return;
 +        }
 +        new_child->mParent->removeChild(new_child);
 +    }
 +
 +    new_child->mParent = this;
 +    if (new_child->mIsAttribute)
 +    {
 +        LLXMLAttribList::iterator found_it = mAttributes.find(new_child->mName);
 +        if (found_it != mAttributes.end())
 +        {
 +            removeChild(found_it->second);
 +        }
 +        mAttributes.insert(std::make_pair(new_child->mName, new_child));
 +    }
 +    else
 +    {
 +        if (mChildren.isNull())
 +        {
 +            mChildren = new LLXMLChildren();
 +            mChildren->head = new_child;
 +            mChildren->tail = new_child;
 +        }
 +        mChildren->map.insert(std::make_pair(new_child->mName, new_child));
 +
 +        if (mChildren->tail != new_child)
 +        {
 +            mChildren->tail->mNext = new_child;
 +            new_child->mPrev = mChildren->tail;
 +            mChildren->tail = new_child;
 +        }
 +    }
 +
 +    new_child->updateDefault();
 +}
 +
 +// virtual
 +LLXMLNodePtr LLXMLNode::createChild(const char* name, bool is_attribute)
 +{
 +    return createChild(gStringTable.addStringEntry(name), is_attribute);
 +}
 +
 +// virtual
 +LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, bool is_attribute)
 +{
 +    LLXMLNodePtr ret(new LLXMLNode(name, is_attribute));
 +    ret->mID.clear();
 +
 +    addChild(ret);
 +    return ret;
 +}
 +
 +bool LLXMLNode::deleteChild(LLXMLNode *child)
 +{
 +    if (removeChild(child))
 +    {
 +        return true;
 +    }
 +    return false;
 +}
 +
 +void LLXMLNode::setParent(LLXMLNodePtr& new_parent)
 +{
 +    if (new_parent.notNull())
 +    {
 +        LLXMLNodePtr this_ptr(this);
 +        new_parent->addChild(this_ptr);
 +    }
 +    else
 +    {
 +        if (mParent != NULL)
 +        {
 +            LLXMLNodePtr old_parent = mParent;
 +            mParent = NULL;
 +            old_parent->removeChild(this);
 +        }
 +    }
 +}
 +
 +
 +void LLXMLNode::updateDefault()
 +{
 +    if (mParent != NULL && !mParent->mDefault.isNull())
 +    {
 +        mDefault = NULL;
 +
 +        // Find default value in parent's default tree
 +        if (!mParent->mDefault.isNull())
 +        {
 +            findDefault(mParent->mDefault);
 +        }
 +    }
 +
 +    if (mChildren.notNull())
 +    {
 +        LLXMLChildList::const_iterator children_itr;
 +        LLXMLChildList::const_iterator children_end = mChildren->map.end();
 +        for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
 +        {
 +            LLXMLNodePtr child = (*children_itr).second;
 +            child->updateDefault();
 +        }
 +    }
 +}
 +
 +void XMLCALL StartXMLNode(void *userData,
 +                          const XML_Char *name,
 +                          const XML_Char **atts)
 +{
 +    // Create a new node
 +    LLXMLNode *new_node_ptr = new LLXMLNode(name, false);
 +
 +    LLXMLNodePtr new_node = new_node_ptr;
 +    new_node->mID.clear();
 +    LLXMLNodePtr ptr_new_node = new_node;
 +
 +    // Set the parent-child relationship with the current active node
 +    LLXMLNode* parent = (LLXMLNode *)userData;
 +
 +    if (NULL == parent)
 +    {
 +        LL_WARNS() << "parent (userData) is NULL; aborting function" << LL_ENDL;
 +        return;
 +    }
 +
 +    new_node_ptr->mParser = parent->mParser;
 +    new_node_ptr->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser));
 +
 +    // Set the current active node to the new node
 +    XML_Parser *parser = parent->mParser;
 +    XML_SetUserData(*parser, (void *)new_node_ptr);
 +
 +    // Parse attributes
 +    U32 pos = 0;
 +    while (atts[pos] != NULL)
 +    {
 +        std::string attr_name = atts[pos];
 +        std::string attr_value = atts[pos+1];
 +
 +        // Special cases
 +        if ('i' == attr_name[0] && "id" == attr_name)
 +        {
 +            new_node->mID = attr_value;
 +        }
 +        else if ('v' == attr_name[0] && "version" == attr_name)
 +        {
 +            U32 version_major = 0;
 +            U32 version_minor = 0;
 +            if (sscanf(attr_value.c_str(), "%d.%d", &version_major, &version_minor) > 0)
 +            {
 +                new_node->mVersionMajor = version_major;
 +                new_node->mVersionMinor = version_minor;
 +            }
 +        }
 +        else if (('s' == attr_name[0] && "size" == attr_name) || ('l' == attr_name[0] && "length" == attr_name))
 +        {
 +            U32 length;
 +            if (sscanf(attr_value.c_str(), "%d", &length) > 0)
 +            {
 +                new_node->mLength = length;
 +            }
 +        }
 +        else if ('p' == attr_name[0] && "precision" == attr_name)
 +        {
 +            U32 precision;
 +            if (sscanf(attr_value.c_str(), "%d", &precision) > 0)
 +            {
 +                new_node->mPrecision = precision;
 +            }
 +        }
 +        else if ('t' == attr_name[0] && "type" == attr_name)
 +        {
 +            if ("boolean" == attr_value)
 +            {
 +                new_node->mType = LLXMLNode::TYPE_BOOLEAN;
 +            }
 +            else if ("integer" == attr_value)
 +            {
 +                new_node->mType = LLXMLNode::TYPE_INTEGER;
 +            }
 +            else if ("float" == attr_value)
 +            {
 +                new_node->mType = LLXMLNode::TYPE_FLOAT;
 +            }
 +            else if ("string" == attr_value)
 +            {
 +                new_node->mType = LLXMLNode::TYPE_STRING;
 +            }
 +            else if ("uuid" == attr_value)
 +            {
 +                new_node->mType = LLXMLNode::TYPE_UUID;
 +            }
 +            else if ("noderef" == attr_value)
 +            {
 +                new_node->mType = LLXMLNode::TYPE_NODEREF;
 +            }
 +        }
 +        else if ('e' == attr_name[0] && "encoding" == attr_name)
 +        {
 +            if ("decimal" == attr_value)
 +            {
 +                new_node->mEncoding = LLXMLNode::ENCODING_DECIMAL;
 +            }
 +            else if ("hex" == attr_value)
 +            {
 +                new_node->mEncoding = LLXMLNode::ENCODING_HEX;
 +            }
 +            /*else if (attr_value == "base32")
 +            {
 +                new_node->mEncoding = LLXMLNode::ENCODING_BASE32;
 +            }*/
 +        }
 +
 +        // only one attribute child per description
 +        LLXMLNodePtr attr_node;
 +        if (!new_node->getAttribute(attr_name.c_str(), attr_node, false))
 +        {
 +            attr_node = new LLXMLNode(attr_name.c_str(), true);
 +            attr_node->setLineNumber(XML_GetCurrentLineNumber(*new_node_ptr->mParser));
 +        }
 +        attr_node->setValue(attr_value);
 +        new_node->addChild(attr_node);
 +
 +        pos += 2;
 +    }
 +
 +    if (parent)
 +    {
 +        parent->addChild(new_node);
 +    }
 +}
 +
 +void XMLCALL EndXMLNode(void *userData,
 +                        const XML_Char *name)
 +{
 +    // [FUGLY] Set the current active node to the current node's parent
 +    LLXMLNode *node = (LLXMLNode *)userData;
 +    XML_Parser *parser = node->mParser;
 +    XML_SetUserData(*parser, (void *)node->mParent);
 +    // SJB: total hack:
 +    if (LLXMLNode::sStripWhitespaceValues)
 +    {
 +        std::string value = node->getValue();
 +        bool is_empty = true;
 +        for (std::string::size_type s = 0; s < value.length(); s++)
 +        {
 +            char c = value[s];
 +            if (c != ' ' && c != '\t' && c != '\n')
 +            {
 +                is_empty = false;
 +                break;
 +            }
 +        }
 +        if (is_empty)
 +        {
 +            value.clear();
 +            node->setValue(value);
 +        }
 +    }
 +}
 +
 +void XMLCALL XMLData(void *userData,
 +                     const XML_Char *s,
 +                     int len)
 +{
 +    LLXMLNode* current_node = (LLXMLNode *)userData;
 +    std::string value = current_node->getValue();
 +    if (LLXMLNode::sStripEscapedStrings)
 +    {
 +        if (s[0] == '\"' && s[len-1] == '\"')
 +        {
 +            // Special-case: Escaped string.
 +            std::string unescaped_string;
 +            for (S32 pos=1; pos<len-1; ++pos)
 +            {
 +                if (s[pos] == '\\' && s[pos+1] == '\\')
 +                {
 +                    unescaped_string.append("\\");
 +                    ++pos;
 +                }
 +                else if (s[pos] == '\\' && s[pos+1] == '\"')
 +                {
 +                    unescaped_string.append("\"");
 +                    ++pos;
 +                }
 +                else
 +                {
 +                    unescaped_string.append(&s[pos], 1);
 +                }
 +            }
 +            value.append(unescaped_string);
 +            current_node->setValue(value);
 +            return;
 +        }
 +    }
 +    value.append(std::string(s, len));
 +    current_node->setValue(value);
 +}
 +
 +
 +
 +// static
 +bool LLXMLNode::updateNode(
 +    LLXMLNodePtr& node,
 +    LLXMLNodePtr& update_node)
 +{
 +
 +    if (!node || !update_node)
 +    {
 +        LL_WARNS() << "Node invalid" << LL_ENDL;
 +        return false;
 +    }
 +
 +    //update the node value
 +    node->mValue = update_node->mValue;
 +
 +    //update all attribute values
 +    LLXMLAttribList::const_iterator itor;
 +
 +    for(itor = update_node->mAttributes.begin(); itor != update_node->mAttributes.end(); ++itor)
 +    {
 +        const LLStringTableEntry* attribNameEntry = (*itor).first;
 +        LLXMLNodePtr updateAttribNode = (*itor).second;
 +
 +        LLXMLNodePtr attribNode;
 +
 +        node->getAttribute(attribNameEntry, attribNode, 0);
 +
 +        if (attribNode)
 +        {
 +            attribNode->mValue = updateAttribNode->mValue;
 +        }
 +    }
 +
 +    //update all of node's children with updateNodes children that match name
 +    LLXMLNodePtr child = node->getFirstChild();
 +    LLXMLNodePtr last_child = child;
 +    LLXMLNodePtr updateChild;
 +
 +    for (updateChild = update_node->getFirstChild(); updateChild.notNull();
 +         updateChild = updateChild->getNextSibling())
 +    {
 +        while(child.notNull())
 +        {
 +            std::string nodeName;
 +            std::string updateName;
 +
 +            updateChild->getAttributeString("name", updateName);
 +            child->getAttributeString("name", nodeName);
 +
 +
 +            //if it's a combobox there's no name, but there is a value
 +            if (updateName.empty())
 +            {
 +                updateChild->getAttributeString("value", updateName);
 +                child->getAttributeString("value", nodeName);
 +            }
 +
 +            if ((nodeName != "") && (updateName == nodeName))
 +            {
 +                updateNode(child, updateChild);
 +                last_child = child;
 +                child = child->getNextSibling();
 +                if (child.isNull())
 +                {
 +                    child = node->getFirstChild();
 +                }
 +                break;
 +            }
 +
 +            child = child->getNextSibling();
 +            if (child.isNull())
 +            {
 +                child = node->getFirstChild();
 +            }
 +            if (child == last_child)
 +            {
 +                break;
 +            }
 +        }
 +    }
 +
 +    return true;
 +}
 +
 +// static
 +bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree)
 +{
 +    // Read file
 +    LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL;
 +    LLFILE* fp = LLFile::fopen(filename, "rb");     /* Flawfinder: ignore */
 +    if (fp == NULL)
 +    {
 +        node = NULL ;
 +        return false;
 +    }
 +    fseek(fp, 0, SEEK_END);
 +    U32 length = ftell(fp);
 +    fseek(fp, 0, SEEK_SET);
 +
 +    U8* buffer = new U8[length+1];
 +    size_t nread = fread(buffer, 1, length, fp);
 +    buffer[nread] = 0;
 +    fclose(fp);
 +
 +    bool rv = parseBuffer(buffer, nread, node, defaults_tree);
 +    delete [] buffer;
 +    return rv;
 +}
 +
 +// static
 +bool LLXMLNode::parseBuffer(
 +    U8* buffer,
 +    U32 length,
 +    LLXMLNodePtr& node,
 +    LLXMLNode* defaults)
 +{
 +    // Init
 +    XML_Parser my_parser = XML_ParserCreate(NULL);
 +    XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
 +    XML_SetCharacterDataHandler(my_parser, XMLData);
 +
 +    // Create a root node
 +    LLXMLNode *file_node_ptr = new LLXMLNode("XML", false);
 +    LLXMLNodePtr file_node = file_node_ptr;
 +
 +    file_node->mParser = &my_parser;
 +
 +    XML_SetUserData(my_parser, (void *)file_node_ptr);
 +
 +    // Do the parsing
 +    if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK)
 +    {
 +        LL_WARNS() << "Error parsing xml error code: "
 +                << XML_ErrorString(XML_GetErrorCode(my_parser))
 +                << " on line " << XML_GetCurrentLineNumber(my_parser)
 +                << LL_ENDL;
 +    }
 +
 +    // Deinit
 +    XML_ParserFree(my_parser);
 +
 +    if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
 +    {
 +        LL_WARNS() << "Parse failure - wrong number of top-level nodes xml."
 +                << LL_ENDL;
 +        node = NULL ;
 +        return false;
 +    }
 +
 +    LLXMLNode *return_node = file_node->mChildren->map.begin()->second;
 +
 +    return_node->setDefault(defaults);
 +    return_node->updateDefault();
 +
 +    node = return_node;
 +    return true;
 +}
 +
 +// static
 +bool LLXMLNode::parseStream(
 +    std::istream& str,
 +    LLXMLNodePtr& node,
 +    LLXMLNode* defaults)
 +{
 +    // Init
 +    XML_Parser my_parser = XML_ParserCreate(NULL);
 +    XML_SetElementHandler(my_parser, StartXMLNode, EndXMLNode);
 +    XML_SetCharacterDataHandler(my_parser, XMLData);
 +
 +    // Create a root node
 +    LLXMLNode *file_node_ptr = new LLXMLNode("XML", false);
 +    LLXMLNodePtr file_node = file_node_ptr;
 +
 +    file_node->mParser = &my_parser;
 +
 +    XML_SetUserData(my_parser, (void *)file_node_ptr);
 +
 +    const int BUFSIZE = 1024;
 +    U8* buffer = new U8[BUFSIZE];
 +
 +    while(str.good())
 +    {
 +        str.read((char*)buffer, BUFSIZE);
 +        int count = (int)str.gcount();
 +
 +        if (XML_Parse(my_parser, (const char *)buffer, count, !str.good()) != XML_STATUS_OK)
 +        {
 +            LL_WARNS() << "Error parsing xml error code: "
 +                    << XML_ErrorString(XML_GetErrorCode(my_parser))
 +                    << " on lne " << XML_GetCurrentLineNumber(my_parser)
 +                    << LL_ENDL;
 +            break;
 +        }
 +    }
 +
 +    delete [] buffer;
 +
 +    // Deinit
 +    XML_ParserFree(my_parser);
 +
 +    if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
 +    {
 +        LL_WARNS() << "Parse failure - wrong number of top-level nodes xml."
 +                << LL_ENDL;
 +        node = NULL;
 +        return false;
 +    }
 +
 +    LLXMLNode *return_node = file_node->mChildren->map.begin()->second;
 +
 +    return_node->setDefault(defaults);
 +    return_node->updateDefault();
 +
 +    node = return_node;
 +    return true;
 +}
 +
 +
 +bool LLXMLNode::isFullyDefault()
 +{
 +    if (mDefault.isNull())
 +    {
 +        return false;
 +    }
 +    bool has_default_value = (mValue == mDefault->mValue);
 +    bool has_default_attribute = (mIsAttribute == mDefault->mIsAttribute);
 +    bool has_default_type = mIsAttribute || (mType == mDefault->mType);
 +    bool has_default_encoding = mIsAttribute || (mEncoding == mDefault->mEncoding);
 +    bool has_default_precision = mIsAttribute || (mPrecision == mDefault->mPrecision);
 +    bool has_default_length = mIsAttribute || (mLength == mDefault->mLength);
 +
 +    if (has_default_value
 +        && has_default_type
 +        && has_default_encoding
 +        && has_default_precision
 +        && has_default_length
 +        && has_default_attribute)
 +    {
 +        if (mChildren.notNull())
 +        {
 +            LLXMLChildList::const_iterator children_itr;
 +            LLXMLChildList::const_iterator children_end = mChildren->map.end();
 +            for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
 +            {
 +                LLXMLNodePtr child = (*children_itr).second;
 +                if (!child->isFullyDefault())
 +                {
 +                    return false;
 +                }
 +            }
 +        }
 +        return true;
 +    }
 +
 +    return false;
 +}
 +
 +// static
 +bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
 +                                  const std::vector<std::string>& paths)
 +{
 +    if (paths.empty()) return false;
 +
 +    std::string filename = paths.front();
 +    if (filename.empty())
 +    {
 +        return false;
 +    }
 +
 +    if (!LLXMLNode::parseFile(filename, root, NULL))
 +    {
 +        LL_WARNS() << "Problem reading UI description file: " << filename << " " << errno << LL_ENDL;
 +        return false;
 +    }
 +
 +    LLXMLNodePtr updateRoot;
 +
 +    std::vector<std::string>::const_iterator itor;
 +
 +    // We've already dealt with the first item, skip that one
 +    for (itor = paths.begin() + 1; itor != paths.end(); ++itor)
 +    {
 +        std::string layer_filename = *itor;
 +        if(layer_filename.empty() || layer_filename == filename)
 +        {
 +            // no localized version of this file, that's ok, keep looking
 +            continue;
 +        }
 +
 +        if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL))
 +        {
 +            LL_WARNS() << "Problem reading localized UI description file: " << layer_filename << LL_ENDL;
 +            return false;
 +        }
 +
 +        std::string nodeName;
 +        std::string updateName;
 +
 +        updateRoot->getAttributeString("name", updateName);
 +        root->getAttributeString("name", nodeName);
 +
 +        if (updateName == nodeName)
 +        {
 +            LLXMLNode::updateNode(root, updateRoot);
 +        }
 +    }
 +
 +    return true;
 +}
 +
 +// static
 +void LLXMLNode::writeHeaderToFile(LLFILE *out_file)
 +{
 +    fprintf(out_file, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n");
 +}
 +
 +void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations)
 +{
 +    if (isFullyDefault())
 +    {
 +        // Don't write out nodes that are an exact match to defaults
 +        return;
 +    }
 +
 +    std::ostringstream ostream;
 +    writeToOstream(ostream, indent, use_type_decorations);
 +    std::string outstring = ostream.str();
 +    size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file);
 +    if (written != outstring.length())
 +    {
 +        LL_WARNS() << "Short write" << LL_ENDL;
 +    }
 +}
 +
 +void LLXMLNode::writeToOstream(std::ostream& output_stream, const std::string& indent, bool use_type_decorations)
 +{
 +    if (isFullyDefault())
 +    {
 +        // Don't write out nodes that are an exact match to defaults
 +        return;
 +    }
 +
 +    bool has_default_type = mDefault.isNull()?false:(mType == mDefault->mType);
 +    bool has_default_encoding = mDefault.isNull()?false:(mEncoding == mDefault->mEncoding);
 +    bool has_default_precision = mDefault.isNull()?false:(mPrecision == mDefault->mPrecision);
 +    bool has_default_length = mDefault.isNull()?false:(mLength == mDefault->mLength);
 +
 +    // stream the name
 +    output_stream << indent << "<" << mName->mString << "\n";
 +
 +    if (use_type_decorations)
 +    {
 +        // ID
 +        if (mID != "")
 +        {
 +            output_stream << indent << " id=\"" << mID << "\"\n";
 +        }
 +
 +        // Type
 +        if (!has_default_type)
 +        {
 +            switch (mType)
 +            {
 +            case TYPE_BOOLEAN:
 +                output_stream << indent << " type=\"boolean\"\n";
 +                break;
 +            case TYPE_INTEGER:
 +                output_stream << indent << " type=\"integer\"\n";
 +                break;
 +            case TYPE_FLOAT:
 +                output_stream << indent << " type=\"float\"\n";
 +                break;
 +            case TYPE_STRING:
 +                output_stream << indent << " type=\"string\"\n";
 +                break;
 +            case TYPE_UUID:
 +                output_stream << indent << " type=\"uuid\"\n";
 +                break;
 +            case TYPE_NODEREF:
 +                output_stream << indent << " type=\"noderef\"\n";
 +                break;
 +            default:
 +                // default on switch(enum) eliminates a warning on linux
 +                break;
 +            };
 +        }
 +
 +        // Encoding
 +        if (!has_default_encoding)
 +        {
 +            switch (mEncoding)
 +            {
 +            case ENCODING_DECIMAL:
 +                output_stream << indent << " encoding=\"decimal\"\n";
 +                break;
 +            case ENCODING_HEX:
 +                output_stream << indent << " encoding=\"hex\"\n";
 +                break;
 +            /*case ENCODING_BASE32:
 +                output_stream << indent << " encoding=\"base32\"\n";
 +                break;*/
 +            default:
 +                // default on switch(enum) eliminates a warning on linux
 +                break;
 +            };
 +        }
 +
 +        // Precision
 +        if (!has_default_precision && (mType == TYPE_INTEGER || mType == TYPE_FLOAT))
 +        {
 +            output_stream << indent << " precision=\"" << mPrecision << "\"\n";
 +        }
 +
 +        // Version
 +        if (mVersionMajor > 0 || mVersionMinor > 0)
 +        {
 +            output_stream << indent << " version=\"" << mVersionMajor << "." << mVersionMinor << "\"\n";
 +        }
 +
 +        // Array length
 +        if (!has_default_length && mLength > 0)
 +        {
 +            output_stream << indent << " length=\"" << mLength << "\"\n";
 +        }
 +    }
 +
 +    {
 +        // Write out attributes
 +        LLXMLAttribList::const_iterator attr_itr;
 +        LLXMLAttribList::const_iterator attr_end = mAttributes.end();
 +        for (attr_itr = mAttributes.begin(); attr_itr != attr_end; ++attr_itr)
 +        {
 +            LLXMLNodePtr child = (*attr_itr).second;
 +            if (child->mDefault.isNull() || child->mDefault->mValue != child->mValue)
 +            {
 +                std::string attr = child->mName->mString;
 +                if (use_type_decorations
 +                    && (attr == "id" ||
 +                        attr == "type" ||
 +                        attr == "encoding" ||
 +                        attr == "precision" ||
 +                        attr == "version" ||
 +                        attr == "length"))
 +                {
 +                    continue; // skip built-in attributes
 +                }
 +
 +                std::string attr_str = llformat(" %s=\"%s\"",
 +                                             attr.c_str(),
 +                                             escapeXML(child->mValue).c_str());
 +                output_stream << indent << attr_str << "\n";
 +            }
 +        }
 +    }
 +
 +    // erase last \n before attaching final > or />
 +    output_stream.seekp(-1, std::ios::cur);
 +
 +    if (mChildren.isNull() && mValue == "")
 +    {
 +        output_stream << " />\n";
 +        return;
 +    }
 +    else
 +    {
 +        output_stream << ">\n";
 +        if (mChildren.notNull())
 +        {
 +            // stream non-attributes
 +            std::string next_indent = indent + "    ";
 +            for (LLXMLNode* child = getFirstChild(); child; child = child->getNextSibling())
 +            {
 +                child->writeToOstream(output_stream, next_indent, use_type_decorations);
 +            }
 +        }
 +        if (!mValue.empty())
 +        {
 +            std::string contents = getTextContents();
 +            output_stream << indent << "    " << escapeXML(contents) << "\n";
 +        }
 +        output_stream << indent << "</" << mName->mString << ">\n";
 +    }
 +}
 +
 +void LLXMLNode::findName(const std::string& name, LLXMLNodeList &results)
 +{
 +    LLStringTableEntry* name_entry = gStringTable.checkStringEntry(name);
 +    if (name_entry == mName)
 +    {
 +        results.insert(std::make_pair(this->mName->mString, this));
 +        return;
 +    }
 +    if (mChildren.notNull())
 +    {
 +        LLXMLChildList::const_iterator children_itr;
 +        LLXMLChildList::const_iterator children_end = mChildren->map.end();
 +        for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
 +        {
 +            LLXMLNodePtr child = (*children_itr).second;
 +            child->findName(name_entry, results);
 +        }
 +    }
 +}
 +
 +void LLXMLNode::findName(LLStringTableEntry* name, LLXMLNodeList &results)
 +{
 +    if (name == mName)
 +    {
 +        results.insert(std::make_pair(this->mName->mString, this));
 +        return;
 +    }
 +    if (mChildren.notNull())
 +    {
 +        LLXMLChildList::const_iterator children_itr;
 +        LLXMLChildList::const_iterator children_end = mChildren->map.end();
 +        for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
 +        {
 +            LLXMLNodePtr child = (*children_itr).second;
 +            child->findName(name, results);
 +        }
 +    }
 +}
 +
 +void LLXMLNode::findID(const std::string& id, LLXMLNodeList &results)
 +{
 +    if (id == mID)
 +    {
 +        results.insert(std::make_pair(this->mName->mString, this));
 +        return;
 +    }
 +    if (mChildren.notNull())
 +    {
 +        LLXMLChildList::const_iterator children_itr;
 +        LLXMLChildList::const_iterator children_end = mChildren->map.end();
 +        for (children_itr = mChildren->map.begin(); children_itr != children_end; ++children_itr)
 +        {
 +            LLXMLNodePtr child = (*children_itr).second;
 +            child->findID(id, results);
 +        }
 +    }
 +}
 +
 +void LLXMLNode::scrubToTree(LLXMLNode *tree)
 +{
 +    if (!tree || tree->mChildren.isNull())
 +    {
 +        return;
 +    }
 +    if (mChildren.notNull())
 +    {
 +        std::vector<LLXMLNodePtr> to_delete_list;
 +        LLXMLChildList::iterator itor = mChildren->map.begin();
 +        while (itor != mChildren->map.end())
 +        {
 +            LLXMLNodePtr child = itor->second;
 +            LLXMLNodePtr child_tree = NULL;
 +            // Look for this child in the default's children
 +            bool found = false;
 +            LLXMLChildList::iterator itor2 = tree->mChildren->map.begin();
 +            while (itor2 != tree->mChildren->map.end())
 +            {
 +                if (child->mName == itor2->second->mName)
 +                {
 +                    child_tree = itor2->second;
 +                    found = true;
 +                }
 +                ++itor2;
 +            }
 +            if (!found)
 +            {
 +                to_delete_list.push_back(child);
 +            }
 +            else
 +            {
 +                child->scrubToTree(child_tree);
 +            }
 +            ++itor;
 +        }
 +        std::vector<LLXMLNodePtr>::iterator itor3;
 +        for (itor3=to_delete_list.begin(); itor3!=to_delete_list.end(); ++itor3)
 +        {
 +            LLXMLNodePtr ptr;
 +            (*itor3)->setParent(ptr);
 +        }
 +    }
 +}
 +
 +bool LLXMLNode::getChild(const char* name, LLXMLNodePtr& node, bool use_default_if_missing)
 +{
 +    return getChild(gStringTable.checkStringEntry(name), node, use_default_if_missing);
 +}
 +
 +bool LLXMLNode::getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing)
 +{
 +    if (mChildren.notNull())
 +    {
 +        LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
 +        if (child_itr != mChildren->map.end())
 +        {
 +            node = (*child_itr).second;
 +            return true;
 +        }
 +    }
 +    if (use_default_if_missing && !mDefault.isNull())
 +    {
 +        return mDefault->getChild(name, node, false);
 +    }
 +    node = NULL;
 +    return false;
 +}
 +
 +void LLXMLNode::getChildren(const char* name, LLXMLNodeList &children, bool use_default_if_missing) const
 +{
 +    getChildren(gStringTable.checkStringEntry(name), children, use_default_if_missing);
 +}
 +
 +void LLXMLNode::getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, bool use_default_if_missing) const
 +{
 +    if (mChildren.notNull())
 +    {
 +        LLXMLChildList::const_iterator child_itr = mChildren->map.find(name);
 +        if (child_itr != mChildren->map.end())
 +        {
 +            LLXMLChildList::const_iterator children_end = mChildren->map.end();
 +            while (child_itr != children_end)
 +            {
 +                LLXMLNodePtr child = (*child_itr).second;
 +                if (name != child->mName)
 +                {
 +                    break;
 +                }
 +                children.insert(std::make_pair(child->mName->mString, child));
 +                child_itr++;
 +            }
 +        }
 +    }
 +    if (children.size() == 0 && use_default_if_missing && !mDefault.isNull())
 +    {
 +        mDefault->getChildren(name, children, false);
 +    }
 +}
 +
 +// recursively walks the tree and returns all children at all nesting levels matching the name
 +void LLXMLNode::getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const
 +{
 +    if (mChildren.notNull())
 +    {
 +        for (LLXMLChildList::const_iterator child_itr = mChildren->map.begin();
 +             child_itr != mChildren->map.end(); ++child_itr)
 +        {
 +            LLXMLNodePtr child = (*child_itr).second;
 +            if (name == child->mName)
 +            {
 +                children.insert(std::make_pair(child->mName->mString, child));
 +            }
 +            // and check each child as well
 +            child->getDescendants(name, children);
 +        }
 +    }
 +}
 +
 +bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, bool use_default_if_missing)
 +{
 +    return getAttribute(gStringTable.checkStringEntry(name), node, use_default_if_missing);
 +}
 +
 +bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing)
 +{
 +    LLXMLAttribList::const_iterator child_itr = mAttributes.find(name);
 +    if (child_itr != mAttributes.end())
 +    {
 +        node = (*child_itr).second;
 +        return true;
 +    }
 +    if (use_default_if_missing && !mDefault.isNull())
 +    {
 +        return mDefault->getAttribute(name, node, false);
 +    }
 +
 +    return false;
 +}
 +
 +bool LLXMLNode::setAttributeString(const char* attr, const std::string& value)
 +{
 +    LLStringTableEntry* name = gStringTable.checkStringEntry(attr);
 +    LLXMLAttribList::const_iterator child_itr = mAttributes.find(name);
 +    if (child_itr != mAttributes.end())
 +    {
 +        LLXMLNodePtr node = (*child_itr).second;
 +        node->setValue(value);
 +        return true;
 +    }
 +    return false;
 +}
 +
 +bool LLXMLNode::hasAttribute(const char* name )
 +{
 +    LLXMLNodePtr node;
 +    return getAttribute(name, node);
 +}
 +
 +bool LLXMLNode::getAttributeBOOL(const char* name, bool& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getBoolValue(1, &value));
 +}
 +
 +bool LLXMLNode::getAttributeU8(const char* name, U8& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getByteValue(1, &value));
 +}
 +
 +bool LLXMLNode::getAttributeS8(const char* name, S8& value )
 +{
 +    LLXMLNodePtr node;
 +    S32 val;
 +    if (!(getAttribute(name, node) && node->getIntValue(1, &val)))
 +    {
 +        return false;
 +    }
 +    value = val;
 +    return true;
 +}
 +
 +bool LLXMLNode::getAttributeU16(const char* name, U16& value )
 +{
 +    LLXMLNodePtr node;
 +    U32 val;
 +    if (!(getAttribute(name, node) && node->getUnsignedValue(1, &val)))
 +    {
 +        return false;
 +    }
 +    value = val;
 +    return true;
 +}
 +
 +bool LLXMLNode::getAttributeS16(const char* name, S16& value )
 +{
 +    LLXMLNodePtr node;
 +    S32 val;
 +    if (!(getAttribute(name, node) && node->getIntValue(1, &val)))
 +    {
 +        return false;
 +    }
 +    value = val;
 +    return true;
 +}
 +
 +bool LLXMLNode::getAttributeU32(const char* name, U32& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getUnsignedValue(1, &value));
 +}
 +
 +bool LLXMLNode::getAttributeS32(const char* name, S32& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getIntValue(1, &value));
 +}
 +
 +bool LLXMLNode::getAttributeF32(const char* name, F32& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getFloatValue(1, &value));
 +}
 +
 +bool LLXMLNode::getAttributeF64(const char* name, F64& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getDoubleValue(1, &value));
 +}
 +
 +bool LLXMLNode::getAttributeColor(const char* name, LLColor4& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getFloatValue(4, value.mV));
 +}
 +
 +bool LLXMLNode::getAttributeColor4(const char* name, LLColor4& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getFloatValue(4, value.mV));
 +}
 +
 +bool LLXMLNode::getAttributeColor4U(const char* name, LLColor4U& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getByteValue(4, value.mV));
 +}
 +
 +bool LLXMLNode::getAttributeVector3(const char* name, LLVector3& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getFloatValue(3, value.mV));
 +}
 +
 +bool LLXMLNode::getAttributeVector3d(const char* name, LLVector3d& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getDoubleValue(3, value.mdV));
 +}
 +
 +bool LLXMLNode::getAttributeQuat(const char* name, LLQuaternion& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getFloatValue(4, value.mQ));
 +}
 +
 +bool LLXMLNode::getAttributeUUID(const char* name, LLUUID& value )
 +{
 +    LLXMLNodePtr node;
 +    return (getAttribute(name, node) && node->getUUIDValue(1, &value));
 +}
 +
 +bool LLXMLNode::getAttributeString(const char* name, std::string& value )
 +{
 +    LLXMLNodePtr node;
 +    if (!getAttribute(name, node))
 +    {
 +        return false;
 +    }
 +    value = node->getValue();
 +    return true;
 +}
 +
 +LLXMLNodePtr LLXMLNode::getRoot()
 +{
 +    if (mParent == NULL)
 +    {
 +        return this;
 +    }
 +    return mParent->getRoot();
 +}
 +
 +/*static */
 +const char *LLXMLNode::skipWhitespace(const char *str)
 +{
 +    // skip whitespace characters
 +    while (str[0] == ' ' || str[0] == '\t' || str[0] == '\n') ++str;
 +    return str;
 +}
 +
 +/*static */
 +const char *LLXMLNode::skipNonWhitespace(const char *str)
 +{
 +    // skip non-whitespace characters
 +    while (str[0] != ' ' && str[0] != '\t' && str[0] != '\n' && str[0] != 0) ++str;
 +    return str;
 +}
 +
 +/*static */
 +const char *LLXMLNode::parseInteger(const char *str, U64 *dest, bool *is_negative, U32 precision, Encoding encoding)
 +{
 +    *dest = 0;
 +    *is_negative = false;
 +
 +    str = skipWhitespace(str);
 +
 +    if (str[0] == 0) return NULL;
 +
 +    if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT)
 +    {
 +        if (str[0] == '+')
 +        {
 +            ++str;
 +        }
 +        if (str[0] == '-')
 +        {
 +            *is_negative = true;
 +            ++str;
 +        }
 +
 +        str = skipWhitespace(str);
 +
 +        U64 ret = 0;
 +        while (str[0] >= '0' && str[0] <= '9')
 +        {
 +            ret *= 10;
 +            ret += str[0] - '0';
 +            ++str;
 +        }
 +
 +        if (str[0] == '.')
 +        {
 +            // If there is a fractional part, skip it
 +            str = skipNonWhitespace(str);
 +        }
 +
 +        *dest = ret;
 +        return str;
 +    }
 +    if (encoding == ENCODING_HEX)
 +    {
 +        U64 ret = 0;
 +        str = skipWhitespace(str);
 +        for (U32 pos=0; pos<(precision/4); ++pos)
 +        {
 +            ret <<= 4;
 +            str = skipWhitespace(str);
 +            if (str[0] >= '0' && str[0] <= '9')
 +            {
 +                ret += str[0] - '0';
 +            }
 +            else if (str[0] >= 'a' && str[0] <= 'f')
 +            {
 +                ret += str[0] - 'a' + 10;
 +            }
 +            else if (str[0] >= 'A' && str[0] <= 'F')
 +            {
 +                ret += str[0] - 'A' + 10;
 +            }
 +            else
 +            {
 +                return NULL;
 +            }
 +            ++str;
 +        }
 +
 +        *dest = ret;
 +        return str;
 +    }
 +    return NULL;
 +}
 +
 +// 25 elements - decimal expansions of 1/(2^n), multiplied by 10 each iteration
 +const U64 float_coeff_table[] =
 +    { 5, 25, 125, 625, 3125,
 +      15625, 78125, 390625, 1953125, 9765625,
 +      48828125, 244140625, 1220703125, 6103515625LL, 30517578125LL,
 +      152587890625LL, 762939453125LL, 3814697265625LL, 19073486328125LL, 95367431640625LL,
 +      476837158203125LL, 2384185791015625LL, 11920928955078125LL, 59604644775390625LL, 298023223876953125LL };
 +
 +// 36 elements - decimal expansions of 1/(2^n) after the last 28, truncated, no multiply each iteration
 +const U64 float_coeff_table_2[] =
 +    {  149011611938476562LL,74505805969238281LL,
 +       37252902984619140LL, 18626451492309570LL, 9313225746154785LL, 4656612873077392LL,
 +       2328306436538696LL,  1164153218269348LL,  582076609134674LL,  291038304567337LL,
 +       145519152283668LL,   72759576141834LL,    36379788070917LL,   18189894035458LL,
 +       9094947017729LL,     4547473508864LL,     2273736754432LL,    1136868377216LL,
 +       568434188608LL,      284217094304LL,      142108547152LL,     71054273576LL,
 +       35527136788LL,       17763568394LL,       8881784197LL,       4440892098LL,
 +       2220446049LL,        1110223024LL,        555111512LL,        277555756LL,
 +       138777878,         69388939,          34694469,         17347234,
 +       8673617,           4336808,           2168404,          1084202,
 +       542101,            271050,            135525,           67762,
 +    };
 +
 +/*static */
 +const char *LLXMLNode::parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding)
 +{
 +    str = skipWhitespace(str);
 +
 +    if (str[0] == 0) return NULL;
 +
 +    if (encoding == ENCODING_DECIMAL || encoding == ENCODING_DEFAULT)
 +    {
 +        str = skipWhitespace(str);
 +
 +        if (memcmp(str, "inf", 3) == 0)
 +        {
 +            *(U64 *)dest = 0x7FF0000000000000ll;
 +            return str + 3;
 +        }
 +        if (memcmp(str, "-inf", 4) == 0)
 +        {
 +            *(U64 *)dest = 0xFFF0000000000000ll;
 +            return str + 4;
 +        }
 +        if (memcmp(str, "1.#INF", 6) == 0)
 +        {
 +            *(U64 *)dest = 0x7FF0000000000000ll;
 +            return str + 6;
 +        }
 +        if (memcmp(str, "-1.#INF", 7) == 0)
 +        {
 +            *(U64 *)dest = 0xFFF0000000000000ll;
 +            return str + 7;
 +        }
 +
 +        F64 negative = 1.0f;
 +        if (str[0] == '+')
 +        {
 +            ++str;
 +        }
 +        if (str[0] == '-')
 +        {
 +            negative = -1.0f;
 +            ++str;
 +        }
 +
 +        const char* base_str = str;
 +        str = skipWhitespace(str);
 +
 +        // Parse the integer part of the expression
 +        U64 int_part = 0;
 +        while (str[0] >= '0' && str[0] <= '9')
 +        {
 +            int_part *= 10;
 +            int_part += U64(str[0] - '0');
 +            ++str;
 +        }
 +
 +        U64 f_part = 0;//, f_decimal = 1;
 +        if (str[0] == '.')
 +        {
 +            ++str;
 +            U64 remainder = 0;
 +            U32 pos = 0;
 +            // Parse the decimal part of the expression
 +            while (str[0] >= '0' && str[0] <= '9' && pos < 25)
 +            {
 +                remainder = (remainder*10) + U64(str[0] - '0');
 +                f_part <<= 1;
 +                //f_decimal <<= 1;
 +                // Check the n'th bit
 +                if (remainder >= float_coeff_table[pos])
 +                {
 +                    remainder -= float_coeff_table[pos];
 +                    f_part |= 1;
 +                }
 +                ++pos;
 +                ++str;
 +            }
 +            if (pos == 25)
 +            {
 +                // Drop any excessive digits
 +                while (str[0] >= '0' && str[0] <= '9')
 +                {
 +                    ++str;
 +                }
 +            }
 +            else
 +            {
 +                while (pos < 25)
 +                {
 +                    remainder *= 10;
 +                    f_part <<= 1;
 +                    //f_decimal <<= 1;
 +                    // Check the n'th bit
 +                    if (remainder >= float_coeff_table[pos])
 +                    {
 +                        remainder -= float_coeff_table[pos];
 +                        f_part |= 1;
 +                    }
 +                    ++pos;
 +                }
 +            }
 +            pos = 0;
 +            while (pos < 36)
 +            {
 +                f_part <<= 1;
 +                //f_decimal <<= 1;
 +                if (remainder >= float_coeff_table_2[pos])
 +                {
 +                    remainder -= float_coeff_table_2[pos];
 +                    f_part |= 1;
 +                }
 +                ++pos;
 +            }
 +        }
 +
 +        F64 ret = F64(int_part) + (F64(f_part)/F64(1LL<<61));
 +
 +        F64 exponent = 1.f;
 +        if (str[0] == 'e')
 +        {
 +            // Scientific notation!
 +            ++str;
 +            U64 exp;
 +            bool is_negative;
 +            str = parseInteger(str, &exp, &is_negative, 64, ENCODING_DECIMAL);
 +            if (str == NULL)
 +            {
 +                exp = 1;
 +            }
 +            F64 exp_d = F64(exp) * (is_negative?-1:1);
 +            exponent = pow(10.0, exp_d);
 +        }
 +
 +        if (str == base_str)
 +        {
 +            // no digits parsed
 +            return NULL;
 +        }
 +        else
 +        {
 +            *dest = ret*negative*exponent;
 +            return str;
 +        }
 +    }
 +    if (encoding == ENCODING_HEX)
 +    {
 +        U64 bytes_dest;
 +        bool is_negative;
 +        str = parseInteger(str, (U64 *)&bytes_dest, &is_negative, precision, ENCODING_HEX);
 +        // Upcast to F64
 +        switch (precision)
 +        {
 +        case 32:
 +            {
 +                U32 short_dest = (U32)bytes_dest;
 +                F32 ret_val = *(F32 *)&short_dest;
 +                *dest = ret_val;
 +            }
 +            break;
 +        case 64:
 +            *dest = *(F64 *)&bytes_dest;
 +            break;
 +        default:
 +            return NULL;
 +        }
 +        return str;
 +    }
 +    return NULL;
 +}
 +
 +U32 LLXMLNode::getBoolValue(U32 expected_length, bool *array)
 +{
 +    llassert(array);
 +
 +    // Check type - accept booleans or strings
 +    if (mType != TYPE_BOOLEAN && mType != TYPE_STRING && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    std::string *str_array = new std::string[expected_length];
 +
 +    U32 length = getStringValue(expected_length, str_array);
 +
 +    U32 ret_length = 0;
 +    for (U32 i=0; i<length; ++i)
 +    {
 +        LLStringUtil::toLower(str_array[i]);
 +        if (str_array[i] == "false")
 +        {
 +            array[ret_length++] = false;
 +        }
 +        else if (str_array[i] == "true")
 +        {
 +            array[ret_length++] = true;
 +        }
 +    }
 +
 +    delete[] str_array;
 +
 +#if LL_DEBUG
 +    if (ret_length != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getBoolValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << ret_length << LL_ENDL;
 +    }
 +#endif
 +    return ret_length;
 +}
 +
 +U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding)
 +{
 +    llassert(array);
 +
 +    // Check type - accept bytes or integers (below 256 only)
 +    if (mType != TYPE_INTEGER
 +        && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    if (mLength > 0 && mLength != expected_length)
 +    {
 +        LL_WARNS() << "XMLNode::getByteValue asked for " << expected_length
 +            << " elements, while node has " << mLength << LL_ENDL;
 +        return 0;
 +    }
 +
 +    if (encoding == ENCODING_DEFAULT)
 +    {
 +        encoding = mEncoding;
 +    }
 +
 +    const char *value_string = mValue.c_str();
 +
 +    U32 i;
 +    for (i=0; i<expected_length; ++i)
 +    {
 +        U64 value;
 +        bool is_negative;
 +        value_string = parseInteger(value_string, &value, &is_negative, 8, encoding);
 +        if (value_string == NULL)
 +        {
 +            break;
 +        }
 +        if (value > 255 || is_negative)
 +        {
 +            LL_WARNS() << "getByteValue: Value outside of valid range." << LL_ENDL;
 +            break;
 +        }
 +        array[i] = U8(value);
 +    }
 +#if LL_DEBUG
 +    if (i != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getByteValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << i << LL_ENDL;
 +    }
 +#endif
 +    return i;
 +}
 +
 +U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding)
 +{
 +    llassert(array);
 +
 +    // Check type - accept bytes or integers
 +    if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    if (mLength > 0 && mLength != expected_length)
 +    {
 +        LL_WARNS() << "XMLNode::getIntValue asked for " << expected_length
 +            << " elements, while node has " << mLength << LL_ENDL;
 +        return 0;
 +    }
 +
 +    if (encoding == ENCODING_DEFAULT)
 +    {
 +        encoding = mEncoding;
 +    }
 +
 +    const char *value_string = mValue.c_str();
 +
 +    U32 i = 0;
 +    for (i=0; i<expected_length; ++i)
 +    {
 +        U64 value;
 +        bool is_negative;
 +        value_string = parseInteger(value_string, &value, &is_negative, 32, encoding);
 +        if (value_string == NULL)
 +        {
 +            break;
 +        }
 +        if (value > 0x7fffffff)
 +        {
 +            LL_WARNS() << "getIntValue: Value outside of valid range." << LL_ENDL;
 +            break;
 +        }
 +        array[i] = S32(value) * (is_negative?-1:1);
 +    }
 +
 +#if LL_DEBUG
 +    if (i != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getIntValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << i << LL_ENDL;
 +    }
 +#endif
 +    return i;
 +}
 +
 +U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding)
 +{
 +    llassert(array);
 +
 +    // Check type - accept bytes or integers
 +    if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    if (mLength > 0 && mLength != expected_length)
 +    {
 +        LL_WARNS() << "XMLNode::getUnsignedValue asked for " << expected_length
 +            << " elements, while node has " << mLength << LL_ENDL;
 +        return 0;
 +    }
 +
 +    if (encoding == ENCODING_DEFAULT)
 +    {
 +        encoding = mEncoding;
 +    }
 +
 +    const char *value_string = mValue.c_str();
 +
 +    U32 i = 0;
 +    // Int type
 +    for (i=0; i<expected_length; ++i)
 +    {
 +        U64 value;
 +        bool is_negative;
 +        value_string = parseInteger(value_string, &value, &is_negative, 32, encoding);
 +        if (value_string == NULL)
 +        {
 +            break;
 +        }
 +        if (is_negative || value > 0xffffffff)
 +        {
 +            LL_WARNS() << "getUnsignedValue: Value outside of valid range." << LL_ENDL;
 +            break;
 +        }
 +        array[i] = U32(value);
 +    }
 +
 +#if LL_DEBUG
 +    if (i != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getUnsignedValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << i << LL_ENDL;
 +    }
 +#endif
 +
 +    return i;
 +}
 +
 +U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding)
 +{
 +    llassert(array);
 +
 +    // Check type - accept bytes or integers
 +    if (mType != TYPE_INTEGER && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    if (mLength > 0 && mLength != expected_length)
 +    {
 +        LL_WARNS() << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL;
 +        return 0;
 +    }
 +
 +    if (encoding == ENCODING_DEFAULT)
 +    {
 +        encoding = mEncoding;
 +    }
 +
 +    const char *value_string = mValue.c_str();
 +
 +    U32 i = 0;
 +    // Int type
 +    for (i=0; i<expected_length; ++i)
 +    {
 +        U64 value;
 +        bool is_negative;
 +        value_string = parseInteger(value_string, &value, &is_negative, 64, encoding);
 +        if (value_string == NULL)
 +        {
 +            break;
 +        }
 +        if (is_negative)
 +        {
 +            LL_WARNS() << "getLongValue: Value outside of valid range." << LL_ENDL;
 +            break;
 +        }
 +        array[i] = value;
 +    }
 +
 +#if LL_DEBUG
 +    if (i != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getLongValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << i << LL_ENDL;
 +    }
 +#endif
 +
 +    return i;
 +}
 +
 +U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding)
 +{
 +    llassert(array);
 +
 +    // Check type - accept only floats or doubles
 +    if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    if (mLength > 0 && mLength != expected_length)
 +    {
 +        LL_WARNS() << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL;
 +        return 0;
 +    }
 +
 +    if (encoding == ENCODING_DEFAULT)
 +    {
 +        encoding = mEncoding;
 +    }
 +
 +    const char *value_string = mValue.c_str();
 +
 +    U32 i;
 +    for (i=0; i<expected_length; ++i)
 +    {
 +        F64 value;
 +        value_string = parseFloat(value_string, &value, 32, encoding);
 +        if (value_string == NULL)
 +        {
 +            break;
 +        }
 +        array[i] = F32(value);
 +    }
 +#if LL_DEBUG
 +    if (i != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getFloatValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << i << LL_ENDL;
 +    }
 +#endif
 +    return i;
 +}
 +
 +U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding)
 +{
 +    llassert(array);
 +
 +    // Check type - accept only floats or doubles
 +    if (mType != TYPE_FLOAT && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    if (mLength > 0 && mLength != expected_length)
 +    {
 +        LL_WARNS() << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL;
 +        return 0;
 +    }
 +
 +    if (encoding == ENCODING_DEFAULT)
 +    {
 +        encoding = mEncoding;
 +    }
 +
 +    const char *value_string = mValue.c_str();
 +
 +    U32 i;
 +    for (i=0; i<expected_length; ++i)
 +    {
 +        F64 value;
 +        value_string = parseFloat(value_string, &value, 64, encoding);
 +        if (value_string == NULL)
 +        {
 +            break;
 +        }
 +        array[i] = value;
 +    }
 +#if LL_DEBUG
 +    if (i != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getDoubleValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << i << LL_ENDL;
 +    }
 +#endif
 +    return i;
 +}
 +
 +U32 LLXMLNode::getStringValue(U32 expected_length, std::string *array)
 +{
 +    llassert(array);
 +
 +    // Can always return any value as a string
 +
 +    if (mLength > 0 && mLength != expected_length)
 +    {
 +        LL_WARNS() << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL;
 +        return 0;
 +    }
 +
 +    U32 num_returned_strings = 0;
 +
 +    // Array of strings is whitespace-separated
 +    const std::string sep(" \n\t");
 +
 +    std::string::size_type n = 0;
 +    std::string::size_type m = 0;
 +    while(1)
 +    {
 +        if (num_returned_strings >= expected_length)
 +        {
 +            break;
 +        }
 +        n = mValue.find_first_not_of(sep, m);
 +        m = mValue.find_first_of(sep, n);
 +        if (m == std::string::npos)
 +        {
 +            break;
 +        }
 +        array[num_returned_strings++] = mValue.substr(n,m-n);
 +    }
 +    if (n != std::string::npos && num_returned_strings < expected_length)
 +    {
 +        array[num_returned_strings++] = mValue.substr(n);
 +    }
 +#if LL_DEBUG
 +    if (num_returned_strings != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getStringValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << num_returned_strings << LL_ENDL;
 +    }
 +#endif
 +
 +    return num_returned_strings;
 +}
 +
 +U32 LLXMLNode::getUUIDValue(U32 expected_length, LLUUID *array)
 +{
 +    llassert(array);
 +
 +    // Check type
 +    if (mType != TYPE_UUID && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    const char *value_string = mValue.c_str();
 +
 +    U32 i;
 +    for (i=0; i<expected_length; ++i)
 +    {
 +        LLUUID uuid_value;
 +        value_string = skipWhitespace(value_string);
 +
 +        if (strlen(value_string) < (UUID_STR_LENGTH-1))     /* Flawfinder: ignore */
 +        {
 +            break;
 +        }
 +        char uuid_string[UUID_STR_LENGTH];      /* Flawfinder: ignore */
 +        memcpy(uuid_string, value_string, (UUID_STR_LENGTH-1));     /* Flawfinder: ignore */
 +        uuid_string[(UUID_STR_LENGTH-1)] = 0;
 +
 +        if (!LLUUID::parseUUID(std::string(uuid_string), &uuid_value))
 +        {
 +            break;
 +        }
 +        value_string = &value_string[(UUID_STR_LENGTH-1)];
 +        array[i] = uuid_value;
 +    }
 +#if LL_DEBUG
 +    if (i != expected_length)
 +    {
 +        LL_DEBUGS() << "LLXMLNode::getUUIDValue() failed for node named '"
 +            << mName->mString << "' -- expected " << expected_length << " but "
 +            << "only found " << i << LL_ENDL;
 +    }
 +#endif
 +    return i;
 +}
 +
 +U32 LLXMLNode::getNodeRefValue(U32 expected_length, LLXMLNode **array)
 +{
 +    llassert(array);
 +
 +    // Check type
 +    if (mType != TYPE_NODEREF && mType != TYPE_UNKNOWN)
 +    {
 +        return 0;
 +    }
 +
 +    std::string *string_array = new std::string[expected_length];
 +
 +    U32 num_strings = getStringValue(expected_length, string_array);
 +
 +    U32 num_returned_refs = 0;
 +
 +    LLXMLNodePtr root = getRoot();
 +    for (U32 strnum=0; strnum<num_strings; ++strnum)
 +    {
 +        LLXMLNodeList node_list;
 +        root->findID(string_array[strnum], node_list);
 +        if (node_list.empty())
 +        {
 +            LL_WARNS() << "XML: Could not find node ID: " << string_array[strnum] << LL_ENDL;
 +        }
 +        else if (node_list.size() > 1)
 +        {
 +            LL_WARNS() << "XML: Node ID not unique: " << string_array[strnum] << LL_ENDL;
 +        }
 +        else
 +        {
 +            LLXMLNodeList::const_iterator list_itr = node_list.begin();
 +            if (list_itr != node_list.end())
 +            {
 +                LLXMLNode* child = (*list_itr).second;
 +
 +                array[num_returned_refs++] = child;
 +            }
 +        }
 +    }
 +
 +    delete[] string_array;
 +
 +    return num_returned_refs;
 +}
 +
 +void LLXMLNode::setBoolValue(U32 length, const bool *array)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    for (U32 pos=0; pos<length; ++pos)
 +    {
 +        if (pos > 0)
 +        {
 +            new_value = llformat("%s %s", new_value.c_str(), array[pos]?"true":"false");
 +        }
 +        else
 +        {
 +            new_value = array[pos]?"true":"false";
 +        }
 +    }
 +
 +    mValue = new_value;
 +    mEncoding = ENCODING_DEFAULT;
 +    mLength = length;
 +    mType = TYPE_BOOLEAN;
 +}
 +
 +void LLXMLNode::setByteValue(U32 length, const U8* const array, Encoding encoding)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
 +    {
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0)
 +            {
 +                new_value.append(llformat(" %u", array[pos]));
 +            }
 +            else
 +            {
 +                new_value = llformat("%u", array[pos]);
 +            }
 +        }
 +    }
 +    if (encoding == ENCODING_HEX)
 +    {
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0 && pos % 16 == 0)
 +            {
 +                new_value.append(llformat(" %02X", array[pos]));
 +            }
 +            else
 +            {
 +                new_value.append(llformat("%02X", array[pos]));
 +            }
 +        }
 +    }
 +    // TODO -- Handle Base32
 +
 +    mValue = new_value;
 +    mEncoding = encoding;
 +    mLength = length;
 +    mType = TYPE_INTEGER;
 +    mPrecision = 8;
 +}
 +
 +
 +void LLXMLNode::setIntValue(U32 length, const S32 *array, Encoding encoding)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
 +    {
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0)
 +            {
 +                new_value.append(llformat(" %d", array[pos]));
 +            }
 +            else
 +            {
 +                new_value = llformat("%d", array[pos]);
 +            }
 +        }
 +        mValue = new_value;
 +    }
 +    else if (encoding == ENCODING_HEX)
 +    {
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0 && pos % 16 == 0)
 +            {
 +                new_value.append(llformat(" %08X", ((U32 *)array)[pos]));
 +            }
 +            else
 +            {
 +                new_value.append(llformat("%08X", ((U32 *)array)[pos]));
 +            }
 +        }
 +        mValue = new_value;
 +    }
 +    else
 +    {
 +        mValue = new_value;
 +    }
 +    // TODO -- Handle Base32
 +
 +    mEncoding = encoding;
 +    mLength = length;
 +    mType = TYPE_INTEGER;
 +    mPrecision = 32;
 +}
 +
 +void LLXMLNode::setUnsignedValue(U32 length, const U32* array, Encoding encoding)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
 +    {
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0)
 +            {
 +                new_value.append(llformat(" %u", array[pos]));
 +            }
 +            else
 +            {
 +                new_value = llformat("%u", array[pos]);
 +            }
 +        }
 +    }
 +    if (encoding == ENCODING_HEX)
 +    {
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0 && pos % 16 == 0)
 +            {
 +                new_value.append(llformat(" %08X", array[pos]));
 +            }
 +            else
 +            {
 +                new_value.append(llformat("%08X", array[pos]));
 +            }
 +        }
 +        mValue = new_value;
 +    }
 +    // TODO -- Handle Base32
 +
 +    mValue = new_value;
 +    mEncoding = encoding;
 +    mLength = length;
 +    mType = TYPE_INTEGER;
 +    mPrecision = 32;
 +}
 +
 +#if LL_WINDOWS
 +#define PU64 "I64u"
 +#else
 +#define PU64 "llu"
 +#endif
 +
 +void LLXMLNode::setLongValue(U32 length, const U64* array, Encoding encoding)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
 +    {
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0)
 +            {
 +                new_value.append(llformat(" %" PU64, array[pos]));
 +            }
 +            else
 +            {
 +                new_value = llformat("%" PU64, array[pos]);
 +            }
 +        }
 +        mValue = new_value;
 +    }
 +    if (encoding == ENCODING_HEX)
 +    {
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            U32 upper_32 = U32(array[pos]>>32);
 +            U32 lower_32 = U32(array[pos]&0xffffffff);
 +            if (pos > 0 && pos % 8 == 0)
 +            {
 +                new_value.append(llformat(" %08X%08X", upper_32, lower_32));
 +            }
 +            else
 +            {
 +                new_value.append(llformat("%08X%08X", upper_32, lower_32));
 +            }
 +        }
 +        mValue = new_value;
 +    }
 +    else
 +    {
 +        mValue = new_value;
 +    }
 +    // TODO -- Handle Base32
 +
 +    mEncoding = encoding;
 +    mLength = length;
 +    mType = TYPE_INTEGER;
 +    mPrecision = 64;
 +}
 +
 +void LLXMLNode::setFloatValue(U32 length, const F32 *array, Encoding encoding, U32 precision)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
 +    {
 +        std::string format_string;
 +        if (precision > 0)
 +        {
 +            if (precision > 25)
 +            {
 +                precision = 25;
 +            }
 +            format_string = llformat( "%%.%dg", precision);
 +        }
 +        else
 +        {
 +            format_string = llformat( "%%g");
 +        }
 +
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0)
 +            {
 +                new_value.append(" ");
 +                new_value.append(llformat(format_string.c_str(), array[pos]));
 +            }
 +            else
 +            {
 +                new_value.assign(llformat(format_string.c_str(), array[pos]));
 +            }
 +        }
 +        mValue = new_value;
 +    }
 +    else if (encoding == ENCODING_HEX)
 +    {
 +        U32 *byte_array = (U32 *)array;
 +        setUnsignedValue(length, byte_array, ENCODING_HEX);
 +    }
 +    else
 +    {
 +        mValue = new_value;
 +    }
 +
 +    mEncoding = encoding;
 +    mLength = length;
 +    mType = TYPE_FLOAT;
 +    mPrecision = 32;
 +}
 +
 +void LLXMLNode::setDoubleValue(U32 length, const F64 *array, Encoding encoding, U32 precision)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    if (encoding == ENCODING_DEFAULT || encoding == ENCODING_DECIMAL)
 +    {
 +        std::string format_string;
 +        if (precision > 0)
 +        {
 +            if (precision > 25)
 +            {
 +                precision = 25;
 +            }
 +            format_string = llformat( "%%.%dg", precision);
 +        }
 +        else
 +        {
 +            format_string = llformat( "%%g");
 +        }
 +        for (U32 pos=0; pos<length; ++pos)
 +        {
 +            if (pos > 0)
 +            {
 +                new_value.append(" ");
 +                new_value.append(llformat(format_string.c_str(), array[pos]));
 +            }
 +            else
 +            {
 +                new_value.assign(llformat(format_string.c_str(), array[pos]));
 +            }
 +        }
 +        mValue = new_value;
 +    }
 +    if (encoding == ENCODING_HEX)
 +    {
 +        U64 *byte_array = (U64 *)array;
 +        setLongValue(length, byte_array, ENCODING_HEX);
 +    }
 +    else
 +    {
 +        mValue = new_value;
 +    }
 +    // TODO -- Handle Base32
 +
 +    mEncoding = encoding;
 +    mLength = length;
 +    mType = TYPE_FLOAT;
 +    mPrecision = 64;
 +}
 +
 +// static
 +std::string LLXMLNode::escapeXML(const std::string& xml)
 +{
 +    std::string out;
 +    for (std::string::size_type i = 0; i < xml.size(); ++i)
 +    {
 +        char c = xml[i];
 +        switch(c)
 +        {
 +        case '"':   out.append(""");   break;
 +        case '\'':  out.append("'");   break;
 +        case '&':   out.append("&");    break;
 +        case '<':   out.append("<");     break;
 +        case '>':   out.append(">");     break;
 +        default:    out.push_back(c);       break;
 +        }
 +    }
 +    return out;
 +}
 +
 +void LLXMLNode::setStringValue(U32 length, const std::string *strings)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    for (U32 pos=0; pos<length; ++pos)
 +    {
 +        // *NOTE: Do not escape strings here - do it on output
 +        new_value.append( strings[pos] );
 +        if (pos < length-1) new_value.append(" ");
 +    }
 +
 +    mValue = new_value;
 +    mEncoding = ENCODING_DEFAULT;
 +    mLength = length;
 +    mType = TYPE_STRING;
 +}
 +
 +void LLXMLNode::setUUIDValue(U32 length, const LLUUID *array)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    for (U32 pos=0; pos<length; ++pos)
 +    {
 +        new_value.append(array[pos].asString());
 +        if (pos < length-1) new_value.append(" ");
 +    }
 +
 +    mValue = new_value;
 +    mEncoding = ENCODING_DEFAULT;
 +    mLength = length;
 +    mType = TYPE_UUID;
 +}
 +
 +void LLXMLNode::setNodeRefValue(U32 length, const LLXMLNode **array)
 +{
 +    if (length == 0) return;
 +
 +    std::string new_value;
 +    for (U32 pos=0; pos<length; ++pos)
 +    {
 +        if (array[pos]->mID != "")
 +        {
 +            new_value.append(array[pos]->mID);
 +        }
 +        else
 +        {
 +            new_value.append("(null)");
 +        }
 +        if (pos < length-1) new_value.append(" ");
 +    }
 +
 +    mValue = new_value;
 +    mEncoding = ENCODING_DEFAULT;
 +    mLength = length;
 +    mType = TYPE_NODEREF;
 +}
 +
 +void LLXMLNode::setValue(const std::string& value)
 +{
 +    if (TYPE_CONTAINER == mType)
 +    {
 +        mType = TYPE_UNKNOWN;
 +    }
 +    mValue = value;
 +}
 +
 +void LLXMLNode::setDefault(LLXMLNode *default_node)
 +{
 +    mDefault = default_node;
 +}
 +
 +void LLXMLNode::findDefault(LLXMLNode *defaults_list)
 +{
 +    if (defaults_list)
 +    {
 +        LLXMLNodeList children;
 +        defaults_list->getChildren(mName->mString, children);
 +
 +        LLXMLNodeList::const_iterator children_itr;
 +        LLXMLNodeList::const_iterator children_end = children.end();
 +        for (children_itr = children.begin(); children_itr != children_end; ++children_itr)
 +        {
 +            LLXMLNode* child = (*children_itr).second;
 +            if (child->mVersionMajor == mVersionMajor &&
 +                child->mVersionMinor == mVersionMinor)
 +            {
 +                mDefault = child;
 +                return;
 +            }
 +        }
 +    }
 +    mDefault = NULL;
 +}
 +
 +bool LLXMLNode::deleteChildren(const std::string& name)
 +{
 +    U32 removed_count = 0;
 +    LLXMLNodeList node_list;
 +    findName(name, node_list);
 +    if (!node_list.empty())
 +    {
 +        // TODO -- use multimap::find()
 +        // TODO -- need to watch out for invalid iterators
 +        LLXMLNodeList::iterator children_itr;
 +        for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr)
 +        {
 +            LLXMLNode* child = (*children_itr).second;
 +            if (deleteChild(child))
 +            {
 +                removed_count++;
 +            }
 +        }
 +    }
 +    return removed_count > 0;
 +}
 +
 +bool LLXMLNode::deleteChildren(LLStringTableEntry* name)
 +{
 +    U32 removed_count = 0;
 +    LLXMLNodeList node_list;
 +    findName(name, node_list);
 +    if (!node_list.empty())
 +    {
 +        // TODO -- use multimap::find()
 +        // TODO -- need to watch out for invalid iterators
 +        LLXMLNodeList::iterator children_itr;
 +        for (children_itr = node_list.begin(); children_itr != node_list.end(); ++children_itr)
 +        {
 +            LLXMLNode* child = (*children_itr).second;
 +            if (deleteChild(child))
 +            {
 +                removed_count++;
 +            }
 +        }
 +    }
 +    return removed_count > 0;
 +}
 +
 +void LLXMLNode::setAttributes(LLXMLNode::ValueType type, U32 precision, LLXMLNode::Encoding encoding, U32 length)
 +{
 +    mType = type;
 +    mEncoding = encoding;
 +    mPrecision = precision;
 +    mLength = length;
 +}
 +
 +void LLXMLNode::setName(const std::string& name)
 +{
 +    setName(gStringTable.addStringEntry(name));
 +}
 +
 +void LLXMLNode::setName(LLStringTableEntry* name)
 +{
 +    LLXMLNode* old_parent = mParent;
 +    if (mParent)
 +    {
 +        // we need to remove and re-add to the parent so that
 +        // the multimap key agrees with this node's name
 +        mParent->removeChild(this);
 +    }
 +    mName = name;
 +    if (old_parent)
 +    {
 +        LLXMLNodePtr this_ptr(this);
 +        old_parent->addChild(this_ptr);
 +    }
 +}
 +
 +// Unused
 +// void LLXMLNode::appendValue(const std::string& value)
 +// {
 +//  mValue.append(value);
 +// }
 +
 +U32 LLXMLNode::getChildCount() const
 +{
 +    if (mChildren.notNull())
 +    {
 +        return mChildren->map.size();
 +    }
 +    return 0;
 +}
 +
 +//***************************************************
 +//  UNIT TESTING
 +//***************************************************
 +
 +U32 get_rand(U32 max_value)
 +{
 +    U32 random_num = rand() + ((U32)rand() << 16);
 +    return (random_num % max_value);
 +}
 +
 +LLXMLNode *get_rand_node(LLXMLNode *node)
 +{
 +    if (node->mChildren.notNull())
 +    {
 +        U32 num_children = node->mChildren->map.size();
 +        if (get_rand(2) == 0)
 +        {
 +            while (true)
 +            {
 +                S32 child_num = S32(get_rand(num_children*2)) - num_children;
 +                LLXMLChildList::iterator itor = node->mChildren->map.begin();
 +                while (child_num > 0)
 +                {
 +                    --child_num;
 +                    ++itor;
 +                }
 +                if (!itor->second->mIsAttribute)
 +                {
 +                    return get_rand_node(itor->second);
 +                }
 +            }
 +        }
 +    }
 +    return node;
 +}
 +
 +void LLXMLNode::createUnitTest(S32 max_num_children)
 +{
 +    // Random ID
 +    std::string rand_id;
 +    U32 rand_id_len = get_rand(10)+5;
 +    for (U32 pos = 0; pos<rand_id_len; ++pos)
 +    {
 +        char c = 'a' + get_rand(26);
 +        rand_id.append(1, c);
 +    }
 +    mID = rand_id;
 +
 +    if (max_num_children < 2)
 +    {
 +        setStringValue(1, &mID);
 +        return;
 +    }
 +
 +    // Checksums
 +    U32 integer_checksum = 0;
 +    U64 long_checksum = 0;
 +    U32 bool_true_count = 0;
 +    LLUUID uuid_checksum;
 +    U32 noderef_checksum = 0;
 +    U32 float_checksum = 0;
 +
 +    // Create a random number of children
 +    U32 num_children = get_rand(max_num_children)+1;
 +    for (U32 child_num=0; child_num<num_children; ++child_num)
 +    {
 +        // Random Name
 +        std::string child_name;
 +        U32 child_name_len = get_rand(10)+5;
 +        for (U32 pos = 0; pos<child_name_len; ++pos)
 +        {
 +            char c = 'a' + get_rand(26);
 +            child_name.append(1, c);
 +        }
 +
 +        LLXMLNode *new_child = createChild(child_name.c_str(), false);
 +
 +        // Random ID
 +        std::string child_id;
 +        U32 child_id_len = get_rand(10)+5;
 +        for (U32 pos=0; pos<child_id_len; ++pos)
 +        {
 +            char c = 'a' + get_rand(26);
 +            child_id.append(1, c);
 +        }
 +        new_child->mID = child_id;
 +
 +        // Random Length
 +        U32 array_size = get_rand(28)+1;
 +
 +        // Random Encoding
 +        Encoding new_encoding = get_rand(2)?ENCODING_DECIMAL:ENCODING_HEX;
 +
 +        // Random Type
 +        int type = get_rand(8);
 +        switch (type)
 +        {
 +        case 0: // TYPE_CONTAINER
 +            new_child->createUnitTest(max_num_children/2);
 +            break;
 +        case 1: // TYPE_BOOLEAN
 +            {
 +                bool random_bool_values[30];
 +                for (U32 value=0; value<array_size; ++value)
 +                {
 +                    random_bool_values[value] = get_rand(2);
 +                    if (random_bool_values[value])
 +                    {
 +                        ++bool_true_count;
 +                    }
 +                }
 +                new_child->setBoolValue(array_size, random_bool_values);
 +            }
 +            break;
 +        case 2: // TYPE_INTEGER (32-bit)
 +            {
 +                U32 random_int_values[30];
 +                for (U32 value=0; value<array_size; ++value)
 +                {
 +                    random_int_values[value] = get_rand(0xffffffff);
 +                    integer_checksum ^= random_int_values[value];
 +                }
 +                new_child->setUnsignedValue(array_size, random_int_values, new_encoding);
 +            }
 +            break;
 +        case 3: // TYPE_INTEGER (64-bit)
 +            {
 +                U64 random_int_values[30];
 +                for (U64 value=0; value<array_size; ++value)
 +                {
 +                    random_int_values[value] = (U64(get_rand(0xffffffff)) << 32) + get_rand(0xffffffff);
 +                    long_checksum ^= random_int_values[value];
 +                }
 +                new_child->setLongValue(array_size, random_int_values, new_encoding);
 +            }
 +            break;
 +        case 4: // TYPE_FLOAT (32-bit)
 +            {
 +                F32 random_float_values[30];
 +                for (U32 value=0; value<array_size; ++value)
 +                {
 +                    S32 exponent = get_rand(256) - 128;
 +                    S32 fractional_part = get_rand(0xffffffff);
 +                    S32 sign = get_rand(2) * 2 - 1;
 +                    random_float_values[value] = F32(fractional_part) / F32(0xffffffff) * exp(F32(exponent)) * F32(sign);
 +
 +                    U32 *float_bits = &((U32 *)random_float_values)[value];
 +                    if (*float_bits == 0x80000000)
 +                    {
 +                        *float_bits = 0x00000000;
 +                    }
 +                    float_checksum ^= (*float_bits & 0xfffff000);
 +                }
 +                new_child->setFloatValue(array_size, random_float_values, new_encoding, 12);
 +            }
 +            break;
 +        case 5: // TYPE_FLOAT (64-bit)
 +            {
 +                F64 random_float_values[30];
 +                for (U32 value=0; value<array_size; ++value)
 +                {
 +                    S32 exponent = get_rand(2048) - 1024;
 +                    S32 fractional_part = get_rand(0xffffffff);
 +                    S32 sign = get_rand(2) * 2 - 1;
 +                    random_float_values[value] = F64(fractional_part) / F64(0xffffffff) * exp(F64(exponent)) * F64(sign);
 +
 +                    U64 *float_bits = &((U64 *)random_float_values)[value];
 +                    if (*float_bits == 0x8000000000000000ll)
 +                    {
 +                        *float_bits = 0x0000000000000000ll;
 +                    }
 +                    float_checksum ^= ((*float_bits & 0xfffffff000000000ll) >> 32);
 +                }
 +                new_child->setDoubleValue(array_size, random_float_values, new_encoding, 12);
 +            }
 +            break;
 +        case 6: // TYPE_UUID
 +            {
 +                LLUUID random_uuid_values[30];
 +                for (U32 value=0; value<array_size; ++value)
 +                {
 +                    random_uuid_values[value].generate();
 +                    for (S32 byte=0; byte<UUID_BYTES; ++byte)
 +                    {
 +                        uuid_checksum.mData[byte] ^= random_uuid_values[value].mData[byte];
 +                    }
 +                }
 +                new_child->setUUIDValue(array_size, random_uuid_values);
 +            }
 +            break;
 +        case 7: // TYPE_NODEREF
 +            {
 +                LLXMLNode *random_node_array[30];
 +                LLXMLNode *root = getRoot();
 +                for (U32 value=0; value<array_size; ++value)
 +                {
 +                    random_node_array[value] = get_rand_node(root);
 +                    const char *node_name = random_node_array[value]->mName->mString;
 +                    for (U32 pos=0; pos<strlen(node_name); ++pos)       /* Flawfinder: ignore */
 +                    {
 +                        U32 hash_contrib = U32(node_name[pos]) << ((pos % 4) * 8);
 +                        noderef_checksum ^= hash_contrib;
 +                    }
 +                }
 +                new_child->setNodeRefValue(array_size, (const LLXMLNode **)random_node_array);
 +            }
 +            break;
 +        }
 +    }
 +
 +    createChild("integer_checksum", true)->setUnsignedValue(1, &integer_checksum, LLXMLNode::ENCODING_HEX);
 +    createChild("long_checksum", true)->setLongValue(1, &long_checksum, LLXMLNode::ENCODING_HEX);
 +    createChild("bool_true_count", true)->setUnsignedValue(1, &bool_true_count, LLXMLNode::ENCODING_HEX);
 +    createChild("uuid_checksum", true)->setUUIDValue(1, &uuid_checksum);
 +    createChild("noderef_checksum", true)->setUnsignedValue(1, &noderef_checksum, LLXMLNode::ENCODING_HEX);
 +    createChild("float_checksum", true)->setUnsignedValue(1, &float_checksum, LLXMLNode::ENCODING_HEX);
 +}
 +
 +bool LLXMLNode::performUnitTest(std::string &error_buffer)
 +{
 +    if (mChildren.isNull())
 +    {
 +        error_buffer.append(llformat("ERROR Node %s: No children found.\n", mName->mString));
 +        return false;
 +    }
 +
 +    // Checksums
 +    U32 integer_checksum = 0;
 +    U32 bool_true_count = 0;
 +    LLUUID uuid_checksum;
 +    U32 noderef_checksum = 0;
 +    U32 float_checksum = 0;
 +    U64 long_checksum = 0;
 +
 +    LLXMLChildList::iterator itor;
 +    for (itor=mChildren->map.begin(); itor!=mChildren->map.end(); ++itor)
 +    {
 +        LLXMLNode *node = itor->second;
 +        if (node->mIsAttribute)
 +        {
 +            continue;
 +        }
 +        if (node->mType == TYPE_CONTAINER)
 +        {
 +            if (!node->performUnitTest(error_buffer))
 +            {
 +                error_buffer.append(llformat("Child test failed for %s.\n", mName->mString));
 +                //return false;
 +            }
 +            continue;
 +        }
 +        if (node->mLength < 1 || node->mLength > 30)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Invalid array length %d, child %s.\n", mName->mString, node->mLength, node->mName->mString));
 +            return false;
 +        }
 +        switch (node->mType)
 +        {
 +        case TYPE_CONTAINER:
 +        case TYPE_UNKNOWN:
 +            break;
 +        case TYPE_BOOLEAN:
 +            {
 +                bool bool_array[30];
 +                if (node->getBoolValue(node->mLength, bool_array) < node->mLength)
 +                {
 +                    error_buffer.append(llformat("ERROR Node %s: Could not read boolean array, child %s.\n", mName->mString, node->mName->mString));
 +                    return false;
 +                }
 +                for (U32 pos=0; pos<(U32)node->mLength; ++pos)
 +                {
 +                    if (bool_array[pos])
 +                    {
 +                        ++bool_true_count;
 +                    }
 +                }
 +            }
 +            break;
 +        case TYPE_INTEGER:
 +            {
 +                if (node->mPrecision == 32)
 +                {
 +                    U32 integer_array[30];
 +                    if (node->getUnsignedValue(node->mLength, integer_array, node->mEncoding) < node->mLength)
 +                    {
 +                        error_buffer.append(llformat("ERROR Node %s: Could not read integer array, child %s.\n", mName->mString, node->mName->mString));
 +                        return false;
 +                    }
 +                    for (U32 pos=0; pos<(U32)node->mLength; ++pos)
 +                    {
 +                        integer_checksum ^= integer_array[pos];
 +                    }
 +                }
 +                else
 +                {
 +                    U64 integer_array[30];
 +                    if (node->getLongValue(node->mLength, integer_array, node->mEncoding) < node->mLength)
 +                    {
 +                        error_buffer.append(llformat("ERROR Node %s: Could not read long integer array, child %s.\n", mName->mString, node->mName->mString));
 +                        return false;
 +                    }
 +                    for (U32 pos=0; pos<(U32)node->mLength; ++pos)
 +                    {
 +                        long_checksum ^= integer_array[pos];
 +                    }
 +                }
 +            }
 +            break;
 +        case TYPE_FLOAT:
 +            {
 +                if (node->mPrecision == 32)
 +                {
 +                    F32 float_array[30];
 +                    if (node->getFloatValue(node->mLength, float_array, node->mEncoding) < node->mLength)
 +                    {
 +                        error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString));
 +                        return false;
 +                    }
 +                    for (U32 pos=0; pos<(U32)node->mLength; ++pos)
 +                    {
 +                        U32 float_bits = ((U32 *)float_array)[pos];
 +                        float_checksum ^= (float_bits & 0xfffff000);
 +                    }
 +                }
 +                else
 +                {
 +                    F64 float_array[30];
 +                    if (node->getDoubleValue(node->mLength, float_array, node->mEncoding) < node->mLength)
 +                    {
 +                        error_buffer.append(llformat("ERROR Node %s: Could not read float array, child %s.\n", mName->mString, node->mName->mString));
 +                        return false;
 +                    }
 +                    for (U32 pos=0; pos<(U32)node->mLength; ++pos)
 +                    {
 +                        U64 float_bits = ((U64 *)float_array)[pos];
 +                        float_checksum ^= ((float_bits & 0xfffffff000000000ll) >> 32);
 +                    }
 +                }
 +            }
 +            break;
 +        case TYPE_STRING:
 +            break;
 +        case TYPE_UUID:
 +            {
 +                LLUUID uuid_array[30];
 +                if (node->getUUIDValue(node->mLength, uuid_array) < node->mLength)
 +                {
 +                    error_buffer.append(llformat("ERROR Node %s: Could not read uuid array, child %s.\n", mName->mString, node->mName->mString));
 +                    return false;
 +                }
 +                for (U32 pos=0; pos<(U32)node->mLength; ++pos)
 +                {
 +                    for (S32 byte=0; byte<UUID_BYTES; ++byte)
 +                    {
 +                        uuid_checksum.mData[byte] ^= uuid_array[pos].mData[byte];
 +                    }
 +                }
 +            }
 +            break;
 +        case TYPE_NODEREF:
 +            {
 +                LLXMLNode *node_array[30];
 +                if (node->getNodeRefValue(node->mLength, node_array) < node->mLength)
 +                {
 +                    error_buffer.append(llformat("ERROR Node %s: Could not read node ref array, child %s.\n", mName->mString, node->mName->mString));
 +                    return false;
 +                }
 +                for (U32 pos=0; pos<node->mLength; ++pos)
 +                {
 +                    const char *node_name = node_array[pos]->mName->mString;
 +                    for (U32 pos2=0; pos2<strlen(node_name); ++pos2)        /* Flawfinder: ignore */
 +                    {
 +                        U32 hash_contrib = U32(node_name[pos2]) << ((pos2 % 4) * 8);
 +                        noderef_checksum ^= hash_contrib;
 +                    }
 +                }
 +            }
 +            break;
 +        }
 +    }
 +
 +    LLXMLNodePtr checksum_node;
 +
 +    // Compare checksums
 +    {
 +        U32 node_integer_checksum = 0;
 +        if (!getAttribute("integer_checksum", checksum_node, false) ||
 +            checksum_node->getUnsignedValue(1, &node_integer_checksum, ENCODING_HEX) != 1)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Integer checksum missing.\n", mName->mString));
 +            return false;
 +        }
 +        if (node_integer_checksum != integer_checksum)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Integer checksum mismatch: read %X / calc %X.\n", mName->mString, node_integer_checksum, integer_checksum));
 +            return false;
 +        }
 +    }
 +
 +    {
 +        U64 node_long_checksum = 0;
 +        if (!getAttribute("long_checksum", checksum_node, false) ||
 +            checksum_node->getLongValue(1, &node_long_checksum, ENCODING_HEX) != 1)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Long Integer checksum missing.\n", mName->mString));
 +            return false;
 +        }
 +        if (node_long_checksum != long_checksum)
 +        {
 +            U32 *pp1 = (U32 *)&node_long_checksum;
 +            U32 *pp2 = (U32 *)&long_checksum;
 +            error_buffer.append(llformat("ERROR Node %s: Long Integer checksum mismatch: read %08X%08X / calc %08X%08X.\n", mName->mString, pp1[1], pp1[0], pp2[1], pp2[0]));
 +            return false;
 +        }
 +    }
 +
 +    {
 +        U32 node_bool_true_count = 0;
 +        if (!getAttribute("bool_true_count", checksum_node, false) ||
 +            checksum_node->getUnsignedValue(1, &node_bool_true_count, ENCODING_HEX) != 1)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Boolean checksum missing.\n", mName->mString));
 +            return false;
 +        }
 +        if (node_bool_true_count != bool_true_count)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Boolean checksum mismatch: read %X / calc %X.\n", mName->mString, node_bool_true_count, bool_true_count));
 +            return false;
 +        }
 +    }
 +
 +    {
 +        LLUUID node_uuid_checksum;
 +        if (!getAttribute("uuid_checksum", checksum_node, false) ||
 +            checksum_node->getUUIDValue(1, &node_uuid_checksum) != 1)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: UUID checksum missing.\n", mName->mString));
 +            return false;
 +        }
 +        if (node_uuid_checksum != uuid_checksum)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: UUID checksum mismatch: read %s / calc %s.\n", mName->mString, node_uuid_checksum.asString().c_str(), uuid_checksum.asString().c_str()));
 +            return false;
 +        }
 +    }
 +
 +    {
 +        U32 node_noderef_checksum = 0;
 +        if (!getAttribute("noderef_checksum", checksum_node, false) ||
 +            checksum_node->getUnsignedValue(1, &node_noderef_checksum, ENCODING_HEX) != 1)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Node Ref checksum missing.\n", mName->mString));
 +            return false;
 +        }
 +        if (node_noderef_checksum != noderef_checksum)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Node Ref checksum mismatch: read %X / calc %X.\n", mName->mString, node_noderef_checksum, noderef_checksum));
 +            return false;
 +        }
 +    }
 +
 +    {
 +        U32 node_float_checksum = 0;
 +        if (!getAttribute("float_checksum", checksum_node, false) ||
 +            checksum_node->getUnsignedValue(1, &node_float_checksum, ENCODING_HEX) != 1)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Float checksum missing.\n", mName->mString));
 +            return false;
 +        }
 +        if (node_float_checksum != float_checksum)
 +        {
 +            error_buffer.append(llformat("ERROR Node %s: Float checksum mismatch: read %X / calc %X.\n", mName->mString, node_float_checksum, float_checksum));
 +            return false;
 +        }
 +    }
 +
 +    return true;
 +}
 +
 +LLXMLNodePtr LLXMLNode::getFirstChild() const
 +{
 +    if (mChildren.isNull()) return NULL;
 +    LLXMLNodePtr ret = mChildren->head;
 +    return ret;
 +}
 +
 +LLXMLNodePtr LLXMLNode::getNextSibling() const
 +{
 +    LLXMLNodePtr ret = mNext;
 +    return ret;
 +}
 +
 +std::string LLXMLNode::getSanitizedValue() const
 +{
 +    if (mIsAttribute)
 +    {
 +        return getValue() ;
 +    }
 +    else
 +    {
 +        return getTextContents();
 +    }
 +}
 +
 +
 +std::string LLXMLNode::getTextContents() const
 +{
 +    std::string msg;
 +    std::string contents = mValue;
 +    std::string::size_type n = contents.find_first_not_of(" \t\n");
 +    if (n != std::string::npos && contents[n] == '\"')
 +    {
 +        // Case 1: node has quoted text
 +        S32 num_lines = 0;
 +        while(1)
 +        {
 +            // mContents[n] == '"'
 +            ++n;
 +            std::string::size_type t = n;
 +            std::string::size_type m = 0;
 +            // fix-up escaped characters
 +            while(1)
 +            {
 +                m = contents.find_first_of("\\\"", t); // find first \ or "
 +                if ((m == std::string::npos) || (contents[m] == '\"'))
 +                {
 +                    break;
 +                }
 +                contents.erase(m,1);
 +                t = m+1;
 +            }
 +            if (m == std::string::npos)
 +            {
 +                break;
 +            }
 +            // mContents[m] == '"'
 +            num_lines++;
 +            msg += contents.substr(n,m-n) + "\n";
 +            n = contents.find_first_of("\"", m+1);
 +            if (n == std::string::npos)
 +            {
 +                if (num_lines == 1)
 +                {
 +                    msg.erase(msg.size()-1); // remove "\n" if only one line
 +                }
 +                break;
 +            }
 +        }
 +    }
 +    else
 +    {
 +        // Case 2: node has embedded text (beginning and trailing whitespace trimmed)
 +        std::string::size_type start = mValue.find_first_not_of(" \t\n");
 +        if (start != mValue.npos)
 +        {
 +            std::string::size_type end = mValue.find_last_not_of(" \t\n");
 +            if (end != mValue.npos)
 +            {
 +                msg = mValue.substr(start, end+1-start);
 +            }
 +            else
 +            {
 +                msg = mValue.substr(start);
 +            }
 +        }
 +        // Convert any internal CR to LF
 +        msg = utf8str_removeCRLF(msg);
 +    }
 +    return msg;
 +}
 +
 +void LLXMLNode::setLineNumber(S32 line_number)
 +{
 +    mLineNumber = line_number;
 +}
 +
 +S32 LLXMLNode::getLineNumber()
 +{
 +    return mLineNumber;
 +}
 diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h index d5b8b36d86..dd362d838a 100644 --- a/indra/llxml/llxmlnode.h +++ b/indra/llxml/llxmlnode.h @@ -1,335 +1,335 @@ -/**  - * @file llxmlnode.h - * @brief LLXMLNode 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_LLXMLNODE_H -#define LL_LLXMLNODE_H - -#ifndef XML_STATIC -#define XML_STATIC -#endif -#ifdef LL_USESYSTEMLIBS -#include <expat.h> -#else -#include "expat/expat.h" -#endif -#include <map> - -#include "indra_constants.h" -#include "llrefcount.h" -#include "llpointer.h" -#include "llstring.h" -#include "llstringtable.h" -#include "llfile.h" -#include "lluuid.h" - -class LLVector3; -class LLVector3d; -class LLQuaternion; -class LLColor4; -class LLColor4U; - - -struct CompareAttributes -{ -	bool operator()(const LLStringTableEntry* const lhs, const LLStringTableEntry* const rhs) const -	{	 -		if (lhs == NULL) -			return true; -		if (rhs == NULL) -			return true; - -		return strcmp(lhs->mString, rhs->mString) < 0; -	} -}; - - -// Defines a simple node hierarchy for reading and writing task objects - -class LLXMLNode; -typedef LLPointer<LLXMLNode> LLXMLNodePtr; -typedef std::multimap<std::string, LLXMLNodePtr > LLXMLNodeList; -typedef std::multimap<const LLStringTableEntry *, LLXMLNodePtr > LLXMLChildList; -typedef std::map<const LLStringTableEntry *, LLXMLNodePtr, CompareAttributes> LLXMLAttribList; - -class LLColor4; -class LLColor4U; -class LLQuaternion; -class LLVector3; -class LLVector3d; -class LLVector4; -class LLVector4U; - -struct LLXMLChildren : public LLThreadSafeRefCount -{ -	LLXMLChildList map;			// Map of children names->pointers -	LLXMLNodePtr head;			// Head of the double-linked list -	LLXMLNodePtr tail;			// Tail of the double-linked list -}; -typedef LLPointer<LLXMLChildren> LLXMLChildrenPtr; - -class LLXMLNode : public LLThreadSafeRefCount -{ -public: -	enum ValueType -	{ -		TYPE_CONTAINER,		// A node which contains nodes -		TYPE_UNKNOWN,		// A node loaded from file without a specified type -		TYPE_BOOLEAN,		// "true" or "false" -		TYPE_INTEGER,		// any integer type: U8, U32, S32, U64, etc. -		TYPE_FLOAT,			// any floating point type: F32, F64 -		TYPE_STRING,		// a string -		TYPE_UUID,			// a UUID -		TYPE_NODEREF,		// the ID of another node in the hierarchy to reference -	}; - -	enum Encoding -	{ -		ENCODING_DEFAULT = 0, -		ENCODING_DECIMAL, -		ENCODING_HEX, -		// ENCODING_BASE32, // Not implemented yet -	}; - -protected: -	~LLXMLNode(); - -public: -	LLXMLNode(); -	LLXMLNode(const char* name, bool is_attribute); -	LLXMLNode(LLStringTableEntry* name, bool is_attribute); -	LLXMLNode(const LLXMLNode& rhs); -	LLXMLNodePtr deepCopy(); - -	bool isNull(); - -	bool deleteChild(LLXMLNode* child); -    void addChild(LLXMLNodePtr& new_child);  -    void setParent(LLXMLNodePtr& new_parent); // reparent if necessary - -    // Serialization -	static bool parseFile( -		const std::string& filename, -		LLXMLNodePtr& node,  -		LLXMLNode* defaults_tree); -	static bool parseBuffer( -		U8* buffer, -		U32 length, -		LLXMLNodePtr& node,  -		LLXMLNode* defaults); -	static bool parseStream( -		std::istream& str, -		LLXMLNodePtr& node,  -		LLXMLNode* defaults); -	static bool updateNode( -		LLXMLNodePtr& node, -		LLXMLNodePtr& update_node); -	 -	static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths); -	 -	 -	// Write standard XML file header: -	// <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -	static void writeHeaderToFile(LLFILE *out_file); -	 -	// Write XML to file with one attribute per line. -	// XML escapes values as they are written. -    void writeToFile(LLFILE *out_file, const std::string& indent = std::string(), bool use_type_decorations=true); -    void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string(), bool use_type_decorations=true); - -    // Utility -    void findName(const std::string& name, LLXMLNodeList &results); -    void findName(LLStringTableEntry* name, LLXMLNodeList &results); -    void findID(const std::string& id, LLXMLNodeList &results); - - -    virtual LLXMLNodePtr createChild(const char* name, bool is_attribute); -    virtual LLXMLNodePtr createChild(LLStringTableEntry* name, bool is_attribute); - - -    // Getters -    U32 getBoolValue(U32 expected_length, bool *array); -    U32 getByteValue(U32 expected_length, U8 *array, Encoding encoding = ENCODING_DEFAULT); -    U32 getIntValue(U32 expected_length, S32 *array, Encoding encoding = ENCODING_DEFAULT); -    U32 getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding = ENCODING_DEFAULT); -    U32 getLongValue(U32 expected_length, U64 *array, Encoding encoding = ENCODING_DEFAULT); -    U32 getFloatValue(U32 expected_length, F32 *array, Encoding encoding = ENCODING_DEFAULT); -    U32 getDoubleValue(U32 expected_length, F64 *array, Encoding encoding = ENCODING_DEFAULT); -    U32 getStringValue(U32 expected_length, std::string *array); -    U32 getUUIDValue(U32 expected_length, LLUUID *array); -    U32 getNodeRefValue(U32 expected_length, LLXMLNode **array); - -	bool hasAttribute(const char* name ); - -	bool getAttributeBOOL(const char* name, bool& value ); -	bool getAttributeU8(const char* name, U8& value ); -	bool getAttributeS8(const char* name, S8& value ); -	bool getAttributeU16(const char* name, U16& value ); -	bool getAttributeS16(const char* name, S16& value ); -	bool getAttributeU32(const char* name, U32& value ); -	bool getAttributeS32(const char* name, S32& value ); -	bool getAttributeF32(const char* name, F32& value ); -	bool getAttributeF64(const char* name, F64& value ); -	bool getAttributeColor(const char* name, LLColor4& value ); -	bool getAttributeColor4(const char* name, LLColor4& value ); -	bool getAttributeColor4U(const char* name, LLColor4U& value ); -	bool getAttributeVector3(const char* name, LLVector3& value ); -	bool getAttributeVector3d(const char* name, LLVector3d& value ); -	bool getAttributeQuat(const char* name, LLQuaternion& value ); -	bool getAttributeUUID(const char* name, LLUUID& value ); -	bool getAttributeString(const char* name, std::string& value ); - -    const ValueType& getType() const { return mType; } -    U32 getLength() const { return mLength; } -    U32 getPrecision() const { return mPrecision; } -    const std::string& getValue() const { return mValue; } -	std::string getSanitizedValue() const; -	std::string getTextContents() const; -    const LLStringTableEntry* getName() const { return mName; } -	bool hasName(const char* name) const { return mName == gStringTable.checkStringEntry(name); } -	bool hasName(const std::string& name) const { return mName == gStringTable.checkStringEntry(name.c_str()); } -    const std::string& getID() const { return mID; } - -    U32 getChildCount() const; -    // getChild returns a Null LLXMLNode (not a NULL pointer) if there is no such child. -    // This child has no value so any getTYPEValue() calls on it will return 0. -    bool getChild(const char* name, LLXMLNodePtr& node, bool use_default_if_missing = true); -    bool getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing = true); -    void getChildren(const char* name, LLXMLNodeList &children, bool use_default_if_missing = true) const; -    void getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, bool use_default_if_missing = true) const; -	 -	// recursively finds all children at any level matching name -	void getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const; - -	bool getAttribute(const char* name, LLXMLNodePtr& node, bool use_default_if_missing = true); -	bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing = true); - -	S32 getLineNumber(); - -	// The following skip over attributes -	LLXMLNodePtr getFirstChild() const; -	LLXMLNodePtr getNextSibling() const; - -    LLXMLNodePtr getRoot(); - -	// Setters - -	bool setAttributeString(const char* attr, const std::string& value); -	 -	void setBoolValue(const bool value)	{ setBoolValue(1, &value); } -	void setByteValue(const U8 value, Encoding encoding = ENCODING_DEFAULT) { setByteValue(1, &value, encoding); } -	void setIntValue(const S32 value, Encoding encoding = ENCODING_DEFAULT) { setIntValue(1, &value, encoding); } -	void setUnsignedValue(const U32 value, Encoding encoding = ENCODING_DEFAULT) { setUnsignedValue(1, &value, encoding); } -	void setLongValue(const U64 value, Encoding encoding = ENCODING_DEFAULT) { setLongValue(1, &value, encoding); } -	void setFloatValue(const F32 value, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0) { setFloatValue(1, &value, encoding); } -	void setDoubleValue(const F64 value, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0) { setDoubleValue(1, &value, encoding); } -	void setStringValue(const std::string& value) { setStringValue(1, &value); } -	void setUUIDValue(const LLUUID value) { setUUIDValue(1, &value); } -	void setNodeRefValue(const LLXMLNode *value) { setNodeRefValue(1, &value); } - -	void setBoolValue(U32 length, const bool *array); -	void setByteValue(U32 length, const U8 *array, Encoding encoding = ENCODING_DEFAULT); -	void setIntValue(U32 length, const S32 *array, Encoding encoding = ENCODING_DEFAULT); -	void setUnsignedValue(U32 length, const U32* array, Encoding encoding = ENCODING_DEFAULT); -	void setLongValue(U32 length, const U64 *array, Encoding encoding = ENCODING_DEFAULT); -	void setFloatValue(U32 length, const F32 *array, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0); -	void setDoubleValue(U32 length, const F64 *array, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0); -	void setStringValue(U32 length, const std::string *array); -	void setUUIDValue(U32 length, const LLUUID *array); -	void setNodeRefValue(U32 length, const LLXMLNode **array); -	void setValue(const std::string& value); -	void setName(const std::string& name); -	void setName(LLStringTableEntry* name); - -	void setLineNumber(S32 line_number); - -	// Escapes " (quot) ' (apos) & (amp) < (lt) > (gt) -	static std::string escapeXML(const std::string& xml); - -	// Set the default node corresponding to this default node -	void setDefault(LLXMLNode *default_node); - -	// Find the node within defaults_list which corresponds to this node -	void findDefault(LLXMLNode *defaults_list); - -	void updateDefault(); - -	// Delete any child nodes that aren't among the tree's children, recursive -	void scrubToTree(LLXMLNode *tree); - -	bool deleteChildren(const std::string& name); -	bool deleteChildren(LLStringTableEntry* name); -	void setAttributes(ValueType type, U32 precision, Encoding encoding, U32 length); -// 	void appendValue(const std::string& value); // Unused - -	// Unit Testing -	void createUnitTest(S32 max_num_children); -	bool performUnitTest(std::string &error_buffer); - -protected: -	bool removeChild(LLXMLNode* child); - -public: -	std::string mID;				// The ID attribute of this node - -	XML_Parser *mParser;		// Temporary pointer while loading - -	bool mIsAttribute;			// Flag is only used for output formatting -	U32 mVersionMajor;			// Version of this tag to use -	U32 mVersionMinor; -	U32 mLength;				// If the length is nonzero, then only return arrays of this length -	U32 mPrecision;				// The number of BITS per array item -	ValueType mType;			// The value type -	Encoding mEncoding;			// The value encoding -	S32 mLineNumber;			// line number in source file, if applicable - -	LLXMLNode* mParent;				// The parent node -	LLXMLChildrenPtr mChildren;		// The child nodes -	LLXMLAttribList mAttributes;		// The attribute nodes -	LLXMLNodePtr mPrev;				// Double-linked list previous node -	LLXMLNodePtr mNext;				// Double-linked list next node - -	static bool sStripEscapedStrings; -	static bool sStripWhitespaceValues; -	 -protected: -	LLStringTableEntry *mName;		// The name of this node - -	// The value of this node (use getters/setters only) -	// Values are not XML-escaped in memory -	// They may contain " (quot) ' (apos) & (amp) < (lt) > (gt) -	std::string mValue; - -	LLXMLNodePtr mDefault;		// Mirror node in the default tree - -	static const char *skipWhitespace(const char *str); -	static const char *skipNonWhitespace(const char *str); -	static const char *parseInteger(const char *str, U64 *dest, bool *is_negative, U32 precision, Encoding encoding); -	static const char *parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding); - -	bool isFullyDefault(); -}; - -#endif // LL_LLXMLNODE +/**
 + * @file llxmlnode.h
 + * @brief LLXMLNode 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_LLXMLNODE_H
 +#define LL_LLXMLNODE_H
 +
 +#ifndef XML_STATIC
 +#define XML_STATIC
 +#endif
 +#ifdef LL_USESYSTEMLIBS
 +#include <expat.h>
 +#else
 +#include "expat/expat.h"
 +#endif
 +#include <map>
 +
 +#include "indra_constants.h"
 +#include "llrefcount.h"
 +#include "llpointer.h"
 +#include "llstring.h"
 +#include "llstringtable.h"
 +#include "llfile.h"
 +#include "lluuid.h"
 +
 +class LLVector3;
 +class LLVector3d;
 +class LLQuaternion;
 +class LLColor4;
 +class LLColor4U;
 +
 +
 +struct CompareAttributes
 +{
 +    bool operator()(const LLStringTableEntry* const lhs, const LLStringTableEntry* const rhs) const
 +    {
 +        if (lhs == NULL)
 +            return true;
 +        if (rhs == NULL)
 +            return true;
 +
 +        return strcmp(lhs->mString, rhs->mString) < 0;
 +    }
 +};
 +
 +
 +// Defines a simple node hierarchy for reading and writing task objects
 +
 +class LLXMLNode;
 +typedef LLPointer<LLXMLNode> LLXMLNodePtr;
 +typedef std::multimap<std::string, LLXMLNodePtr > LLXMLNodeList;
 +typedef std::multimap<const LLStringTableEntry *, LLXMLNodePtr > LLXMLChildList;
 +typedef std::map<const LLStringTableEntry *, LLXMLNodePtr, CompareAttributes> LLXMLAttribList;
 +
 +class LLColor4;
 +class LLColor4U;
 +class LLQuaternion;
 +class LLVector3;
 +class LLVector3d;
 +class LLVector4;
 +class LLVector4U;
 +
 +struct LLXMLChildren : public LLThreadSafeRefCount
 +{
 +    LLXMLChildList map;         // Map of children names->pointers
 +    LLXMLNodePtr head;          // Head of the double-linked list
 +    LLXMLNodePtr tail;          // Tail of the double-linked list
 +};
 +typedef LLPointer<LLXMLChildren> LLXMLChildrenPtr;
 +
 +class LLXMLNode : public LLThreadSafeRefCount
 +{
 +public:
 +    enum ValueType
 +    {
 +        TYPE_CONTAINER,     // A node which contains nodes
 +        TYPE_UNKNOWN,       // A node loaded from file without a specified type
 +        TYPE_BOOLEAN,       // "true" or "false"
 +        TYPE_INTEGER,       // any integer type: U8, U32, S32, U64, etc.
 +        TYPE_FLOAT,         // any floating point type: F32, F64
 +        TYPE_STRING,        // a string
 +        TYPE_UUID,          // a UUID
 +        TYPE_NODEREF,       // the ID of another node in the hierarchy to reference
 +    };
 +
 +    enum Encoding
 +    {
 +        ENCODING_DEFAULT = 0,
 +        ENCODING_DECIMAL,
 +        ENCODING_HEX,
 +        // ENCODING_BASE32, // Not implemented yet
 +    };
 +
 +protected:
 +    ~LLXMLNode();
 +
 +public:
 +    LLXMLNode();
 +    LLXMLNode(const char* name, bool is_attribute);
 +    LLXMLNode(LLStringTableEntry* name, bool is_attribute);
 +    LLXMLNode(const LLXMLNode& rhs);
 +    LLXMLNodePtr deepCopy();
 +
 +    bool isNull();
 +
 +    bool deleteChild(LLXMLNode* child);
 +    void addChild(LLXMLNodePtr& new_child);
 +    void setParent(LLXMLNodePtr& new_parent); // reparent if necessary
 +
 +    // Serialization
 +    static bool parseFile(
 +        const std::string& filename,
 +        LLXMLNodePtr& node,
 +        LLXMLNode* defaults_tree);
 +    static bool parseBuffer(
 +        U8* buffer,
 +        U32 length,
 +        LLXMLNodePtr& node,
 +        LLXMLNode* defaults);
 +    static bool parseStream(
 +        std::istream& str,
 +        LLXMLNodePtr& node,
 +        LLXMLNode* defaults);
 +    static bool updateNode(
 +        LLXMLNodePtr& node,
 +        LLXMLNodePtr& update_node);
 +
 +    static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths);
 +
 +
 +    // Write standard XML file header:
 +    // <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 +    static void writeHeaderToFile(LLFILE *out_file);
 +
 +    // Write XML to file with one attribute per line.
 +    // XML escapes values as they are written.
 +    void writeToFile(LLFILE *out_file, const std::string& indent = std::string(), bool use_type_decorations=true);
 +    void writeToOstream(std::ostream& output_stream, const std::string& indent = std::string(), bool use_type_decorations=true);
 +
 +    // Utility
 +    void findName(const std::string& name, LLXMLNodeList &results);
 +    void findName(LLStringTableEntry* name, LLXMLNodeList &results);
 +    void findID(const std::string& id, LLXMLNodeList &results);
 +
 +
 +    virtual LLXMLNodePtr createChild(const char* name, bool is_attribute);
 +    virtual LLXMLNodePtr createChild(LLStringTableEntry* name, bool is_attribute);
 +
 +
 +    // Getters
 +    U32 getBoolValue(U32 expected_length, bool *array);
 +    U32 getByteValue(U32 expected_length, U8 *array, Encoding encoding = ENCODING_DEFAULT);
 +    U32 getIntValue(U32 expected_length, S32 *array, Encoding encoding = ENCODING_DEFAULT);
 +    U32 getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding = ENCODING_DEFAULT);
 +    U32 getLongValue(U32 expected_length, U64 *array, Encoding encoding = ENCODING_DEFAULT);
 +    U32 getFloatValue(U32 expected_length, F32 *array, Encoding encoding = ENCODING_DEFAULT);
 +    U32 getDoubleValue(U32 expected_length, F64 *array, Encoding encoding = ENCODING_DEFAULT);
 +    U32 getStringValue(U32 expected_length, std::string *array);
 +    U32 getUUIDValue(U32 expected_length, LLUUID *array);
 +    U32 getNodeRefValue(U32 expected_length, LLXMLNode **array);
 +
 +    bool hasAttribute(const char* name );
 +
 +    bool getAttributeBOOL(const char* name, bool& value );
 +    bool getAttributeU8(const char* name, U8& value );
 +    bool getAttributeS8(const char* name, S8& value );
 +    bool getAttributeU16(const char* name, U16& value );
 +    bool getAttributeS16(const char* name, S16& value );
 +    bool getAttributeU32(const char* name, U32& value );
 +    bool getAttributeS32(const char* name, S32& value );
 +    bool getAttributeF32(const char* name, F32& value );
 +    bool getAttributeF64(const char* name, F64& value );
 +    bool getAttributeColor(const char* name, LLColor4& value );
 +    bool getAttributeColor4(const char* name, LLColor4& value );
 +    bool getAttributeColor4U(const char* name, LLColor4U& value );
 +    bool getAttributeVector3(const char* name, LLVector3& value );
 +    bool getAttributeVector3d(const char* name, LLVector3d& value );
 +    bool getAttributeQuat(const char* name, LLQuaternion& value );
 +    bool getAttributeUUID(const char* name, LLUUID& value );
 +    bool getAttributeString(const char* name, std::string& value );
 +
 +    const ValueType& getType() const { return mType; }
 +    U32 getLength() const { return mLength; }
 +    U32 getPrecision() const { return mPrecision; }
 +    const std::string& getValue() const { return mValue; }
 +    std::string getSanitizedValue() const;
 +    std::string getTextContents() const;
 +    const LLStringTableEntry* getName() const { return mName; }
 +    bool hasName(const char* name) const { return mName == gStringTable.checkStringEntry(name); }
 +    bool hasName(const std::string& name) const { return mName == gStringTable.checkStringEntry(name.c_str()); }
 +    const std::string& getID() const { return mID; }
 +
 +    U32 getChildCount() const;
 +    // getChild returns a Null LLXMLNode (not a NULL pointer) if there is no such child.
 +    // This child has no value so any getTYPEValue() calls on it will return 0.
 +    bool getChild(const char* name, LLXMLNodePtr& node, bool use_default_if_missing = true);
 +    bool getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing = true);
 +    void getChildren(const char* name, LLXMLNodeList &children, bool use_default_if_missing = true) const;
 +    void getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, bool use_default_if_missing = true) const;
 +
 +    // recursively finds all children at any level matching name
 +    void getDescendants(const LLStringTableEntry* name, LLXMLNodeList &children) const;
 +
 +    bool getAttribute(const char* name, LLXMLNodePtr& node, bool use_default_if_missing = true);
 +    bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing = true);
 +
 +    S32 getLineNumber();
 +
 +    // The following skip over attributes
 +    LLXMLNodePtr getFirstChild() const;
 +    LLXMLNodePtr getNextSibling() const;
 +
 +    LLXMLNodePtr getRoot();
 +
 +    // Setters
 +
 +    bool setAttributeString(const char* attr, const std::string& value);
 +
 +    void setBoolValue(const bool value) { setBoolValue(1, &value); }
 +    void setByteValue(const U8 value, Encoding encoding = ENCODING_DEFAULT) { setByteValue(1, &value, encoding); }
 +    void setIntValue(const S32 value, Encoding encoding = ENCODING_DEFAULT) { setIntValue(1, &value, encoding); }
 +    void setUnsignedValue(const U32 value, Encoding encoding = ENCODING_DEFAULT) { setUnsignedValue(1, &value, encoding); }
 +    void setLongValue(const U64 value, Encoding encoding = ENCODING_DEFAULT) { setLongValue(1, &value, encoding); }
 +    void setFloatValue(const F32 value, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0) { setFloatValue(1, &value, encoding); }
 +    void setDoubleValue(const F64 value, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0) { setDoubleValue(1, &value, encoding); }
 +    void setStringValue(const std::string& value) { setStringValue(1, &value); }
 +    void setUUIDValue(const LLUUID value) { setUUIDValue(1, &value); }
 +    void setNodeRefValue(const LLXMLNode *value) { setNodeRefValue(1, &value); }
 +
 +    void setBoolValue(U32 length, const bool *array);
 +    void setByteValue(U32 length, const U8 *array, Encoding encoding = ENCODING_DEFAULT);
 +    void setIntValue(U32 length, const S32 *array, Encoding encoding = ENCODING_DEFAULT);
 +    void setUnsignedValue(U32 length, const U32* array, Encoding encoding = ENCODING_DEFAULT);
 +    void setLongValue(U32 length, const U64 *array, Encoding encoding = ENCODING_DEFAULT);
 +    void setFloatValue(U32 length, const F32 *array, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0);
 +    void setDoubleValue(U32 length, const F64 *array, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0);
 +    void setStringValue(U32 length, const std::string *array);
 +    void setUUIDValue(U32 length, const LLUUID *array);
 +    void setNodeRefValue(U32 length, const LLXMLNode **array);
 +    void setValue(const std::string& value);
 +    void setName(const std::string& name);
 +    void setName(LLStringTableEntry* name);
 +
 +    void setLineNumber(S32 line_number);
 +
 +    // Escapes " (quot) ' (apos) & (amp) < (lt) > (gt)
 +    static std::string escapeXML(const std::string& xml);
 +
 +    // Set the default node corresponding to this default node
 +    void setDefault(LLXMLNode *default_node);
 +
 +    // Find the node within defaults_list which corresponds to this node
 +    void findDefault(LLXMLNode *defaults_list);
 +
 +    void updateDefault();
 +
 +    // Delete any child nodes that aren't among the tree's children, recursive
 +    void scrubToTree(LLXMLNode *tree);
 +
 +    bool deleteChildren(const std::string& name);
 +    bool deleteChildren(LLStringTableEntry* name);
 +    void setAttributes(ValueType type, U32 precision, Encoding encoding, U32 length);
 +//  void appendValue(const std::string& value); // Unused
 +
 +    // Unit Testing
 +    void createUnitTest(S32 max_num_children);
 +    bool performUnitTest(std::string &error_buffer);
 +
 +protected:
 +    bool removeChild(LLXMLNode* child);
 +
 +public:
 +    std::string mID;                // The ID attribute of this node
 +
 +    XML_Parser *mParser;        // Temporary pointer while loading
 +
 +    bool mIsAttribute;          // Flag is only used for output formatting
 +    U32 mVersionMajor;          // Version of this tag to use
 +    U32 mVersionMinor;
 +    U32 mLength;                // If the length is nonzero, then only return arrays of this length
 +    U32 mPrecision;             // The number of BITS per array item
 +    ValueType mType;            // The value type
 +    Encoding mEncoding;         // The value encoding
 +    S32 mLineNumber;            // line number in source file, if applicable
 +
 +    LLXMLNode* mParent;             // The parent node
 +    LLXMLChildrenPtr mChildren;     // The child nodes
 +    LLXMLAttribList mAttributes;        // The attribute nodes
 +    LLXMLNodePtr mPrev;             // Double-linked list previous node
 +    LLXMLNodePtr mNext;             // Double-linked list next node
 +
 +    static bool sStripEscapedStrings;
 +    static bool sStripWhitespaceValues;
 +
 +protected:
 +    LLStringTableEntry *mName;      // The name of this node
 +
 +    // The value of this node (use getters/setters only)
 +    // Values are not XML-escaped in memory
 +    // They may contain " (quot) ' (apos) & (amp) < (lt) > (gt)
 +    std::string mValue;
 +
 +    LLXMLNodePtr mDefault;      // Mirror node in the default tree
 +
 +    static const char *skipWhitespace(const char *str);
 +    static const char *skipNonWhitespace(const char *str);
 +    static const char *parseInteger(const char *str, U64 *dest, bool *is_negative, U32 precision, Encoding encoding);
 +    static const char *parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding);
 +
 +    bool isFullyDefault();
 +};
 +
 +#endif // LL_LLXMLNODE
 diff --git a/indra/llxml/llxmlparser.cpp b/indra/llxml/llxmlparser.cpp index f4116626f6..2cae8a14a7 100644 --- a/indra/llxml/llxmlparser.cpp +++ b/indra/llxml/llxmlparser.cpp @@ -1,416 +1,416 @@ -/**  - * @file llxmlparser.cpp - * @brief LLXmlParser implementation - * - * $LicenseInfo:firstyear=2002&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$ - */ - -// llxmlparser.cpp -//               -// copyright 2002, linden research inc - - -#include "linden_common.h" - -#include "llxmlparser.h" -#include "llerror.h" - - -LLXmlParser::LLXmlParser() -	: -	mParser( NULL ), -	mDepth( 0 ) -{ -	mAuxErrorString = "no error"; - -	// Override the document's declared encoding. -	mParser = XML_ParserCreate(NULL); - -	XML_SetUserData(mParser, this); -	XML_SetElementHandler(					mParser,	startElementHandler, endElementHandler); -	XML_SetCharacterDataHandler(			mParser,	characterDataHandler); -	XML_SetProcessingInstructionHandler(	mParser,	processingInstructionHandler); -	XML_SetCommentHandler(					mParser,	commentHandler); - -	XML_SetCdataSectionHandler(				mParser,	startCdataSectionHandler, endCdataSectionHandler); - -	// This sets the default handler but does not inhibit expansion of internal entities. -	// The entity reference will not be passed to the default handler. -	XML_SetDefaultHandlerExpand(			mParser,	defaultDataHandler); -	 -	XML_SetUnparsedEntityDeclHandler(		mParser,	unparsedEntityDeclHandler); -} - -LLXmlParser::~LLXmlParser() -{ -	XML_ParserFree( mParser ); -} - - -bool LLXmlParser::parseFile(const std::string &path) -{ -	llassert( !mDepth ); -	 -	bool success = true; - -	LLFILE* file = LLFile::fopen(path, "rb");		/* Flawfinder: ignore */ -	if( !file ) -	{ -		mAuxErrorString = llformat( "Couldn't open file %s", path.c_str()); -		success = false; -	} -	else -	{ -		S32 bytes_read = 0; -		 -		fseek(file, 0L, SEEK_END); -		S32 buffer_size = ftell(file); -		fseek(file, 0L, SEEK_SET); - -		void* buffer = XML_GetBuffer(mParser, buffer_size); -		if( !buffer )  -		{ -			mAuxErrorString = llformat( "Unable to allocate XML buffer while reading file %s", path.c_str() ); -			success = false; -			goto exit_label; -		} -		 -		bytes_read = (S32)fread(buffer, 1, buffer_size, file); -		if( bytes_read <= 0 ) -		{ -			mAuxErrorString = llformat( "Error while reading file  %s", path.c_str() ); -			success = false; -			goto exit_label; -		} -		 -		if( !XML_ParseBuffer(mParser, bytes_read, true ) ) -		{ -			mAuxErrorString = llformat( "Error while parsing file  %s", path.c_str() ); -			success = false; -		} - -exit_label:  -		fclose( file ); -	} - - -	if( success ) -	{ -		llassert( !mDepth ); -	} -	mDepth = 0; - -	if( !success ) -	{ -		LL_WARNS() << mAuxErrorString << LL_ENDL; -	} - -	return success; -} - - -//	Parses some input. Returns 0 if a fatal error is detected. -//	The last call must have isFinal true; -//	len may be zero for this call (or any other). -S32 LLXmlParser::parse( const char* buf, int len, int isFinal ) -{ -	return XML_Parse(mParser, buf, len, isFinal); -} - -const char* LLXmlParser::getErrorString() -{ -	const char* error_string = XML_ErrorString(XML_GetErrorCode( mParser )); -	if( !error_string ) -	{ -		error_string = mAuxErrorString.c_str(); -	} -	return error_string; -} - -S32 LLXmlParser::getCurrentLineNumber() -{ -	return XML_GetCurrentLineNumber( mParser ); -} - -S32 LLXmlParser::getCurrentColumnNumber() -{ -	return XML_GetCurrentColumnNumber(mParser); -} - -/////////////////////////////////////////////////////////////////////////////// -// Pseudo-private methods.  These are only used by internal callbacks. - -// static  -void LLXmlParser::startElementHandler( -	 void *userData, -	 const XML_Char *name, -	 const XML_Char **atts) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->startElement( name, atts ); -	self->mDepth++; -} - -// static  -void LLXmlParser::endElementHandler( -	void *userData, -	const XML_Char *name) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->mDepth--; -	self->endElement( name ); -} - -// s is not 0 terminated. -// static  -void LLXmlParser::characterDataHandler( -	void *userData, -	const XML_Char *s, -	int len) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->characterData( s, len ); -} - -// target and data are 0 terminated -// static  -void LLXmlParser::processingInstructionHandler( -	void *userData, -	const XML_Char *target, -	const XML_Char *data) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->processingInstruction( target, data ); -} - -// data is 0 terminated  -// static -void LLXmlParser::commentHandler(void *userData, const XML_Char *data) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->comment( data ); -} - -// static -void LLXmlParser::startCdataSectionHandler(void *userData) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->mDepth++; -	self->startCdataSection(); -} - -// static -void LLXmlParser::endCdataSectionHandler(void *userData) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->endCdataSection(); -	self->mDepth++; -} - -//	This is called for any characters in the XML document for -//	which there is no applicable handler.  This includes both -//	characters that are part of markup which is of a kind that is -//	not reported (comments, markup declarations), or characters -//	that are part of a construct which could be reported but -//	for which no handler has been supplied. The characters are passed -//	exactly as they were in the XML document except that -//	they will be encoded in UTF-8.  Line boundaries are not normalized. -//	Note that a byte order mark character is not passed to the default handler. -//	There are no guarantees about how characters are divided between calls -//	to the default handler: for example, a comment might be split between -//	multiple calls. - -// static  -void LLXmlParser::defaultDataHandler( -	void *userData, -	const XML_Char *s, -	int len) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->defaultData( s, len ); -} - -//	This is called for a declaration of an unparsed (NDATA) -//	entity.  The base argument is whatever was set by XML_SetBase. -//	The entityName, systemId and notationName arguments will never be null. -//	The other arguments may be. -// static  -void LLXmlParser::unparsedEntityDeclHandler( -	void *userData, -	const XML_Char *entityName, -	const XML_Char *base, -	const XML_Char *systemId, -	const XML_Char *publicId, -	const XML_Char *notationName) -{ -	LLXmlParser* self = (LLXmlParser*) userData; -	self->unparsedEntityDecl( entityName, base, systemId, publicId, notationName ); -} - - - - -//////////////////////////////////////////////////////////////////// -// Test code. - -/* -class LLXmlDOMParser : public LLXmlParser -{ -public: - -	LLXmlDOMParser() {} -	virtual ~LLXmlDOMParser() {} - -	void tabs() -	{ -		for ( int i = 0; i < getDepth(); i++) -		{ -			putchar(' '); -		} -	} - -	virtual void startElement(const char *name, const char **atts)  -	{ -		tabs(); -		printf("startElement %s\n", name); -		 -		S32 i = 0; -		while( atts[i] && atts[i+1] ) -		{ -			tabs(); -			printf( "\t%s=%s\n", atts[i], atts[i+1] ); -			i += 2; -		} - -		if( atts[i] ) -		{ -			tabs(); -			printf( "\ttrailing attribute: %s\n", atts[i] ); -		} -	} - -	virtual void endElement(const char *name)  -	{ -		tabs(); -		printf("endElement %s\n", name); -	} - -	virtual void characterData(const char *s, int len)  -	{ -		tabs(); - -		char* str = new char[len+1]; -		strncpy( str, s, len ); -		str[len] = '\0'; -		printf("CharacterData %s\n", str); -		delete str; -	} - -	virtual void processingInstruction(const char *target, const char *data) -	{ -		tabs(); -		printf("processingInstruction %s\n", data); -	} -	virtual void comment(const char *data) -	{ -		tabs(); -		printf("comment %s\n", data); -	} - -	virtual void startCdataSection() -	{ -		tabs(); -		printf("startCdataSection\n"); -	} - -	virtual void endCdataSection() -	{ -		tabs(); -		printf("endCdataSection\n"); -	} - -	virtual void defaultData(const char *s, int len) -	{ -		tabs(); - -		char* str = new char[len+1]; -		strncpy( str, s, len ); -		str[len] = '\0'; -		printf("defaultData %s\n", str); -		delete str; -	} - -	virtual void unparsedEntityDecl( -		const char *entityName, -		const char *base, -		const char *systemId, -		const char *publicId, -		const char *notationName) -	{ -		tabs(); - -		printf( -			"unparsed entity:\n" -				"\tentityName %s\n" -				"\tbase %s\n" -				"\tsystemId %s\n" -				"\tpublicId %s\n" -				"\tnotationName %s\n", -			entityName, -			base, -			systemId, -			publicId, -			notationName ); -	} -}; - - -int main() -{ -  char buf[1024]; - -  LLFILE* file = LLFile::fopen("test.xml", "rb"); -  if( !file ) -  { -	  return 1; -  } - -  LLXmlDOMParser parser; -  int done; -  do { -    size_t len = fread(buf, 1, sizeof(buf), file); -    done = len < sizeof(buf); -    if( 0 == parser.parse( buf, len, done) ) -	{ -      fprintf(stderr, -	      "%s at line %d\n", -	      parser.getErrorString(), -	      parser.getCurrentLineNumber() ); -      return 1; -    } -  } while (!done); - -  fclose( file ); -  return 0; -} -*/ - +/**
 + * @file llxmlparser.cpp
 + * @brief LLXmlParser implementation
 + *
 + * $LicenseInfo:firstyear=2002&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$
 + */
 +
 +// llxmlparser.cpp
 +//
 +// copyright 2002, linden research inc
 +
 +
 +#include "linden_common.h"
 +
 +#include "llxmlparser.h"
 +#include "llerror.h"
 +
 +
 +LLXmlParser::LLXmlParser()
 +    :
 +    mParser( NULL ),
 +    mDepth( 0 )
 +{
 +    mAuxErrorString = "no error";
 +
 +    // Override the document's declared encoding.
 +    mParser = XML_ParserCreate(NULL);
 +
 +    XML_SetUserData(mParser, this);
 +    XML_SetElementHandler(                  mParser,    startElementHandler, endElementHandler);
 +    XML_SetCharacterDataHandler(            mParser,    characterDataHandler);
 +    XML_SetProcessingInstructionHandler(    mParser,    processingInstructionHandler);
 +    XML_SetCommentHandler(                  mParser,    commentHandler);
 +
 +    XML_SetCdataSectionHandler(             mParser,    startCdataSectionHandler, endCdataSectionHandler);
 +
 +    // This sets the default handler but does not inhibit expansion of internal entities.
 +    // The entity reference will not be passed to the default handler.
 +    XML_SetDefaultHandlerExpand(            mParser,    defaultDataHandler);
 +
 +    XML_SetUnparsedEntityDeclHandler(       mParser,    unparsedEntityDeclHandler);
 +}
 +
 +LLXmlParser::~LLXmlParser()
 +{
 +    XML_ParserFree( mParser );
 +}
 +
 +
 +bool LLXmlParser::parseFile(const std::string &path)
 +{
 +    llassert( !mDepth );
 +
 +    bool success = true;
 +
 +    LLFILE* file = LLFile::fopen(path, "rb");       /* Flawfinder: ignore */
 +    if( !file )
 +    {
 +        mAuxErrorString = llformat( "Couldn't open file %s", path.c_str());
 +        success = false;
 +    }
 +    else
 +    {
 +        S32 bytes_read = 0;
 +
 +        fseek(file, 0L, SEEK_END);
 +        S32 buffer_size = ftell(file);
 +        fseek(file, 0L, SEEK_SET);
 +
 +        void* buffer = XML_GetBuffer(mParser, buffer_size);
 +        if( !buffer )
 +        {
 +            mAuxErrorString = llformat( "Unable to allocate XML buffer while reading file %s", path.c_str() );
 +            success = false;
 +            goto exit_label;
 +        }
 +
 +        bytes_read = (S32)fread(buffer, 1, buffer_size, file);
 +        if( bytes_read <= 0 )
 +        {
 +            mAuxErrorString = llformat( "Error while reading file  %s", path.c_str() );
 +            success = false;
 +            goto exit_label;
 +        }
 +
 +        if( !XML_ParseBuffer(mParser, bytes_read, true ) )
 +        {
 +            mAuxErrorString = llformat( "Error while parsing file  %s", path.c_str() );
 +            success = false;
 +        }
 +
 +exit_label:
 +        fclose( file );
 +    }
 +
 +
 +    if( success )
 +    {
 +        llassert( !mDepth );
 +    }
 +    mDepth = 0;
 +
 +    if( !success )
 +    {
 +        LL_WARNS() << mAuxErrorString << LL_ENDL;
 +    }
 +
 +    return success;
 +}
 +
 +
 +//  Parses some input. Returns 0 if a fatal error is detected.
 +//  The last call must have isFinal true;
 +//  len may be zero for this call (or any other).
 +S32 LLXmlParser::parse( const char* buf, int len, int isFinal )
 +{
 +    return XML_Parse(mParser, buf, len, isFinal);
 +}
 +
 +const char* LLXmlParser::getErrorString()
 +{
 +    const char* error_string = XML_ErrorString(XML_GetErrorCode( mParser ));
 +    if( !error_string )
 +    {
 +        error_string = mAuxErrorString.c_str();
 +    }
 +    return error_string;
 +}
 +
 +S32 LLXmlParser::getCurrentLineNumber()
 +{
 +    return XML_GetCurrentLineNumber( mParser );
 +}
 +
 +S32 LLXmlParser::getCurrentColumnNumber()
 +{
 +    return XML_GetCurrentColumnNumber(mParser);
 +}
 +
 +///////////////////////////////////////////////////////////////////////////////
 +// Pseudo-private methods.  These are only used by internal callbacks.
 +
 +// static
 +void LLXmlParser::startElementHandler(
 +     void *userData,
 +     const XML_Char *name,
 +     const XML_Char **atts)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->startElement( name, atts );
 +    self->mDepth++;
 +}
 +
 +// static
 +void LLXmlParser::endElementHandler(
 +    void *userData,
 +    const XML_Char *name)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->mDepth--;
 +    self->endElement( name );
 +}
 +
 +// s is not 0 terminated.
 +// static
 +void LLXmlParser::characterDataHandler(
 +    void *userData,
 +    const XML_Char *s,
 +    int len)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->characterData( s, len );
 +}
 +
 +// target and data are 0 terminated
 +// static
 +void LLXmlParser::processingInstructionHandler(
 +    void *userData,
 +    const XML_Char *target,
 +    const XML_Char *data)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->processingInstruction( target, data );
 +}
 +
 +// data is 0 terminated
 +// static
 +void LLXmlParser::commentHandler(void *userData, const XML_Char *data)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->comment( data );
 +}
 +
 +// static
 +void LLXmlParser::startCdataSectionHandler(void *userData)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->mDepth++;
 +    self->startCdataSection();
 +}
 +
 +// static
 +void LLXmlParser::endCdataSectionHandler(void *userData)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->endCdataSection();
 +    self->mDepth++;
 +}
 +
 +//  This is called for any characters in the XML document for
 +//  which there is no applicable handler.  This includes both
 +//  characters that are part of markup which is of a kind that is
 +//  not reported (comments, markup declarations), or characters
 +//  that are part of a construct which could be reported but
 +//  for which no handler has been supplied. The characters are passed
 +//  exactly as they were in the XML document except that
 +//  they will be encoded in UTF-8.  Line boundaries are not normalized.
 +//  Note that a byte order mark character is not passed to the default handler.
 +//  There are no guarantees about how characters are divided between calls
 +//  to the default handler: for example, a comment might be split between
 +//  multiple calls.
 +
 +// static
 +void LLXmlParser::defaultDataHandler(
 +    void *userData,
 +    const XML_Char *s,
 +    int len)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->defaultData( s, len );
 +}
 +
 +//  This is called for a declaration of an unparsed (NDATA)
 +//  entity.  The base argument is whatever was set by XML_SetBase.
 +//  The entityName, systemId and notationName arguments will never be null.
 +//  The other arguments may be.
 +// static
 +void LLXmlParser::unparsedEntityDeclHandler(
 +    void *userData,
 +    const XML_Char *entityName,
 +    const XML_Char *base,
 +    const XML_Char *systemId,
 +    const XML_Char *publicId,
 +    const XML_Char *notationName)
 +{
 +    LLXmlParser* self = (LLXmlParser*) userData;
 +    self->unparsedEntityDecl( entityName, base, systemId, publicId, notationName );
 +}
 +
 +
 +
 +
 +////////////////////////////////////////////////////////////////////
 +// Test code.
 +
 +/*
 +class LLXmlDOMParser : public LLXmlParser
 +{
 +public:
 +
 +    LLXmlDOMParser() {}
 +    virtual ~LLXmlDOMParser() {}
 +
 +    void tabs()
 +    {
 +        for ( int i = 0; i < getDepth(); i++)
 +        {
 +            putchar(' ');
 +        }
 +    }
 +
 +    virtual void startElement(const char *name, const char **atts)
 +    {
 +        tabs();
 +        printf("startElement %s\n", name);
 +
 +        S32 i = 0;
 +        while( atts[i] && atts[i+1] )
 +        {
 +            tabs();
 +            printf( "\t%s=%s\n", atts[i], atts[i+1] );
 +            i += 2;
 +        }
 +
 +        if( atts[i] )
 +        {
 +            tabs();
 +            printf( "\ttrailing attribute: %s\n", atts[i] );
 +        }
 +    }
 +
 +    virtual void endElement(const char *name)
 +    {
 +        tabs();
 +        printf("endElement %s\n", name);
 +    }
 +
 +    virtual void characterData(const char *s, int len)
 +    {
 +        tabs();
 +
 +        char* str = new char[len+1];
 +        strncpy( str, s, len );
 +        str[len] = '\0';
 +        printf("CharacterData %s\n", str);
 +        delete str;
 +    }
 +
 +    virtual void processingInstruction(const char *target, const char *data)
 +    {
 +        tabs();
 +        printf("processingInstruction %s\n", data);
 +    }
 +    virtual void comment(const char *data)
 +    {
 +        tabs();
 +        printf("comment %s\n", data);
 +    }
 +
 +    virtual void startCdataSection()
 +    {
 +        tabs();
 +        printf("startCdataSection\n");
 +    }
 +
 +    virtual void endCdataSection()
 +    {
 +        tabs();
 +        printf("endCdataSection\n");
 +    }
 +
 +    virtual void defaultData(const char *s, int len)
 +    {
 +        tabs();
 +
 +        char* str = new char[len+1];
 +        strncpy( str, s, len );
 +        str[len] = '\0';
 +        printf("defaultData %s\n", str);
 +        delete str;
 +    }
 +
 +    virtual void unparsedEntityDecl(
 +        const char *entityName,
 +        const char *base,
 +        const char *systemId,
 +        const char *publicId,
 +        const char *notationName)
 +    {
 +        tabs();
 +
 +        printf(
 +            "unparsed entity:\n"
 +                "\tentityName %s\n"
 +                "\tbase %s\n"
 +                "\tsystemId %s\n"
 +                "\tpublicId %s\n"
 +                "\tnotationName %s\n",
 +            entityName,
 +            base,
 +            systemId,
 +            publicId,
 +            notationName );
 +    }
 +};
 +
 +
 +int main()
 +{
 +  char buf[1024];
 +
 +  LLFILE* file = LLFile::fopen("test.xml", "rb");
 +  if( !file )
 +  {
 +      return 1;
 +  }
 +
 +  LLXmlDOMParser parser;
 +  int done;
 +  do {
 +    size_t len = fread(buf, 1, sizeof(buf), file);
 +    done = len < sizeof(buf);
 +    if( 0 == parser.parse( buf, len, done) )
 +    {
 +      fprintf(stderr,
 +          "%s at line %d\n",
 +          parser.getErrorString(),
 +          parser.getCurrentLineNumber() );
 +      return 1;
 +    }
 +  } while (!done);
 +
 +  fclose( file );
 +  return 0;
 +}
 +*/
 +
 diff --git a/indra/llxml/llxmlparser.h b/indra/llxml/llxmlparser.h index c5025ef450..dfee4b8070 100644 --- a/indra/llxml/llxmlparser.h +++ b/indra/llxml/llxmlparser.h @@ -1,133 +1,133 @@ -/**  - * @file llxmlparser.h - * @brief LLXmlParser class definition - * - * $LicenseInfo:firstyear=2002&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_LLXMLPARSER_H -#define LL_LLXMLPARSER_H - -#ifndef XML_STATIC -#define XML_STATIC -#endif -#ifdef LL_USESYSTEMLIBS -#include <expat.h> -#else -#include "expat/expat.h" -#endif - -class LLXmlParser -{ -public: -	LLXmlParser(); -	virtual ~LLXmlParser(); - -	// Parses entire file -	bool parseFile(const std::string &path); - -	//	Parses some input. Returns 0 if a fatal error is detected. -	//	The last call must have isFinal true; -	//	len may be zero for this call (or any other). -	S32 parse( const char* buf, int len, int isFinal ); - -	const char* getErrorString(); -	 -	S32 getCurrentLineNumber(); - -	S32 getCurrentColumnNumber(); - -	S32 getDepth() { return mDepth; } - -protected: -	// atts is array of name/value pairs, terminated by 0; -	// names and values are 0 terminated. -	virtual void startElement(const char *name, const char **atts) {} - -	virtual void endElement(const char *name) {} - -	// s is not 0 terminated. -	virtual void characterData(const char *s, int len) {} -	 -	// target and data are 0 terminated -	virtual void processingInstruction(const char *target, const char *data) {} - -	// data is 0 terminated  -	virtual void comment(const char *data) {} - -	virtual void startCdataSection() {} - -	virtual void endCdataSection() {} - -	//	This is called for any characters in the XML document for -	//	which there is no applicable handler.  This includes both -	//	characters that are part of markup which is of a kind that is -	//	not reported (comments, markup declarations), or characters -	//	that are part of a construct which could be reported but -	//	for which no handler has been supplied. The characters are passed -	//	exactly as they were in the XML document except that -	//	they will be encoded in UTF-8.  Line boundaries are not normalized. -	//	Note that a byte order mark character is not passed to the default handler. -	//	There are no guarantees about how characters are divided between calls -	//	to the default handler: for example, a comment might be split between -	//	multiple calls. -	virtual void defaultData(const char *s, int len) {} - -	//	This is called for a declaration of an unparsed (NDATA) -	//	entity.  The base argument is whatever was set by XML_SetBase. -	//	The entityName, systemId and notationName arguments will never be null. -	//	The other arguments may be. -	virtual void unparsedEntityDecl( -		const char *entityName, -		const char *base, -		const char *systemId, -		const char *publicId, -		const char *notationName) {} - -public: -	/////////////////////////////////////////////////////////////////////////////// -	// Pseudo-private methods.  These are only used by internal callbacks. -	 -	static void startElementHandler(void *userData, const XML_Char *name, const XML_Char **atts); -	static void endElementHandler(void *userData, const XML_Char *name); -	static void characterDataHandler(void *userData, const XML_Char *s, int len); -	static void processingInstructionHandler(void *userData, const XML_Char *target, const XML_Char *data); -	static void commentHandler(void *userData, const XML_Char *data); -	static void startCdataSectionHandler(void *userData); -	static void endCdataSectionHandler(void *userData); -	static void defaultDataHandler( void *userData, const XML_Char *s, int len); -	static void unparsedEntityDeclHandler( -		void *userData, -		const XML_Char *entityName, -		const XML_Char *base, -		const XML_Char *systemId, -		const XML_Char *publicId, -		const XML_Char *notationName); - - -protected: -	XML_Parser		mParser; -	int				mDepth; -	std::string		mAuxErrorString; -}; - -#endif  // LL_LLXMLPARSER_H +/**
 + * @file llxmlparser.h
 + * @brief LLXmlParser class definition
 + *
 + * $LicenseInfo:firstyear=2002&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_LLXMLPARSER_H
 +#define LL_LLXMLPARSER_H
 +
 +#ifndef XML_STATIC
 +#define XML_STATIC
 +#endif
 +#ifdef LL_USESYSTEMLIBS
 +#include <expat.h>
 +#else
 +#include "expat/expat.h"
 +#endif
 +
 +class LLXmlParser
 +{
 +public:
 +    LLXmlParser();
 +    virtual ~LLXmlParser();
 +
 +    // Parses entire file
 +    bool parseFile(const std::string &path);
 +
 +    //  Parses some input. Returns 0 if a fatal error is detected.
 +    //  The last call must have isFinal true;
 +    //  len may be zero for this call (or any other).
 +    S32 parse( const char* buf, int len, int isFinal );
 +
 +    const char* getErrorString();
 +
 +    S32 getCurrentLineNumber();
 +
 +    S32 getCurrentColumnNumber();
 +
 +    S32 getDepth() { return mDepth; }
 +
 +protected:
 +    // atts is array of name/value pairs, terminated by 0;
 +    // names and values are 0 terminated.
 +    virtual void startElement(const char *name, const char **atts) {}
 +
 +    virtual void endElement(const char *name) {}
 +
 +    // s is not 0 terminated.
 +    virtual void characterData(const char *s, int len) {}
 +
 +    // target and data are 0 terminated
 +    virtual void processingInstruction(const char *target, const char *data) {}
 +
 +    // data is 0 terminated
 +    virtual void comment(const char *data) {}
 +
 +    virtual void startCdataSection() {}
 +
 +    virtual void endCdataSection() {}
 +
 +    //  This is called for any characters in the XML document for
 +    //  which there is no applicable handler.  This includes both
 +    //  characters that are part of markup which is of a kind that is
 +    //  not reported (comments, markup declarations), or characters
 +    //  that are part of a construct which could be reported but
 +    //  for which no handler has been supplied. The characters are passed
 +    //  exactly as they were in the XML document except that
 +    //  they will be encoded in UTF-8.  Line boundaries are not normalized.
 +    //  Note that a byte order mark character is not passed to the default handler.
 +    //  There are no guarantees about how characters are divided between calls
 +    //  to the default handler: for example, a comment might be split between
 +    //  multiple calls.
 +    virtual void defaultData(const char *s, int len) {}
 +
 +    //  This is called for a declaration of an unparsed (NDATA)
 +    //  entity.  The base argument is whatever was set by XML_SetBase.
 +    //  The entityName, systemId and notationName arguments will never be null.
 +    //  The other arguments may be.
 +    virtual void unparsedEntityDecl(
 +        const char *entityName,
 +        const char *base,
 +        const char *systemId,
 +        const char *publicId,
 +        const char *notationName) {}
 +
 +public:
 +    ///////////////////////////////////////////////////////////////////////////////
 +    // Pseudo-private methods.  These are only used by internal callbacks.
 +
 +    static void startElementHandler(void *userData, const XML_Char *name, const XML_Char **atts);
 +    static void endElementHandler(void *userData, const XML_Char *name);
 +    static void characterDataHandler(void *userData, const XML_Char *s, int len);
 +    static void processingInstructionHandler(void *userData, const XML_Char *target, const XML_Char *data);
 +    static void commentHandler(void *userData, const XML_Char *data);
 +    static void startCdataSectionHandler(void *userData);
 +    static void endCdataSectionHandler(void *userData);
 +    static void defaultDataHandler( void *userData, const XML_Char *s, int len);
 +    static void unparsedEntityDeclHandler(
 +        void *userData,
 +        const XML_Char *entityName,
 +        const XML_Char *base,
 +        const XML_Char *systemId,
 +        const XML_Char *publicId,
 +        const XML_Char *notationName);
 +
 +
 +protected:
 +    XML_Parser      mParser;
 +    int             mDepth;
 +    std::string     mAuxErrorString;
 +};
 +
 +#endif  // LL_LLXMLPARSER_H
 diff --git a/indra/llxml/llxmltree.cpp b/indra/llxml/llxmltree.cpp index a9c702f552..626bbcabc3 100644 --- a/indra/llxml/llxmltree.cpp +++ b/indra/llxml/llxmltree.cpp @@ -1,694 +1,694 @@ -/**  - * @file llxmltree.cpp - * @brief LLXmlTree implementation - * - * $LicenseInfo:firstyear=2002&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 "llxmltree.h" -#include "v3color.h" -#include "v4color.h" -#include "v4coloru.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4math.h" -#include "llquaternion.h" -#include "lluuid.h" - -////////////////////////////////////////////////////////////// -// LLXmlTree - -// static -LLStdStringTable LLXmlTree::sAttributeKeys(1024); - -LLXmlTree::LLXmlTree() -	: mRoot( NULL ), -	  mNodeNames(512) -{ -} - -LLXmlTree::~LLXmlTree() -{ -	cleanup(); -} - -void LLXmlTree::cleanup() -{ -	delete mRoot; -	mRoot = NULL; -	mNodeNames.cleanup(); -} - - -bool LLXmlTree::parseFile(const std::string &path, bool keep_contents) -{ -	delete mRoot; -	mRoot = NULL; - -	LLXmlTreeParser parser(this); -	bool success = parser.parseFile( path, &mRoot, keep_contents ); -	if( !success ) -	{ -		S32 line_number = parser.getCurrentLineNumber(); -		const char* error =  parser.getErrorString(); -		LL_WARNS() << "LLXmlTree parse failed.  Line " << line_number << ": " << error << LL_ENDL; -	} -	return success; -} - -void LLXmlTree::dump() -{ -	if( mRoot ) -	{ -		dumpNode( mRoot, "    " ); -	} -} - -void LLXmlTree::dumpNode( LLXmlTreeNode* node, const std::string& prefix ) -{ -	node->dump( prefix ); - -	std::string new_prefix = prefix + "    "; -	for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() ) -	{ -		dumpNode( child, new_prefix ); -	} -} - -////////////////////////////////////////////////////////////// -// LLXmlTreeNode - -LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree ) -	: mName(name), -	  mParent(parent), -	  mTree(tree) -{ -} - -LLXmlTreeNode::~LLXmlTreeNode() -{ -	attribute_map_t::iterator iter; -	for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++) -		delete iter->second; -        for(LLXmlTreeNode* node : mChildren) -        { -            delete node; -        } -        mChildren.clear(); -} -  -void LLXmlTreeNode::dump( const std::string& prefix ) -{ -	LL_INFOS() << prefix << mName ; -	if( !mContents.empty() ) -	{ -		LL_CONT << " contents = \"" << mContents << "\""; -	} -	attribute_map_t::iterator iter; -	for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++) -	{ -		LLStdStringHandle key = iter->first; -		const std::string* value = iter->second; -		LL_CONT << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value); -	} -	LL_CONT << LL_ENDL; -}  - -bool LLXmlTreeNode::hasAttribute(const std::string& name) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString(name); -	attribute_map_t::iterator iter = mAttributes.find(canonical_name); -	return iter != mAttributes.end(); -} - -void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString(name); -	const std::string *newstr = new std::string(value); -	mAttributes[canonical_name] = newstr; // insert + copy -} - -LLXmlTreeNode*	LLXmlTreeNode::getFirstChild() -{ -	mChildrenIter = mChildren.begin(); -	return getNextChild(); -} -LLXmlTreeNode*	LLXmlTreeNode::getNextChild() -{ -	if (mChildrenIter == mChildren.end()) -		return 0; -	else -		return *mChildrenIter++; -} - -LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name) -{ -	LLStdStringHandle tableptr = mTree->mNodeNames.checkString(name); -	mChildMapIter = mChildMap.lower_bound(tableptr); -	mChildMapEndIter = mChildMap.upper_bound(tableptr); -	return getNextNamedChild(); -} - -LLXmlTreeNode* LLXmlTreeNode::getNextNamedChild() -{ -	if (mChildMapIter == mChildMapEndIter) -		return NULL; -	else -		return (mChildMapIter++)->second; -} - -void LLXmlTreeNode::appendContents(const std::string& str) -{ -	mContents.append( str ); -} - -void LLXmlTreeNode::addChild(LLXmlTreeNode* child) -{ -	llassert( child ); -	mChildren.push_back( child ); - -	// Add a name mapping to this node -	LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName); -	mChildMap.insert( child_map_t::value_type(tableptr, child)); -	 -	child->mParent = this; -} - -////////////////////////////////////////////////////////////// - -// These functions assume that name is already in mAttritrubteKeys - -bool LLXmlTreeNode::getFastAttributeBOOL(LLStdStringHandle canonical_name, bool& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToBOOL( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToU8( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToS8( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToS16( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToU16( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToU32( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToS32( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToF32( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s && LLStringUtil::convertToF64( *s, value ); -} - -bool LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s ? LLColor4::parseColor(*s, &value) : false; -} - -bool LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s ? LLColor4::parseColor4(*s, &value) : false; -} - -bool LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s ? LLColor4U::parseColor4U(*s, &value ) : false; -} - -bool LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s ? LLVector3::parseVector3(*s, &value ) : false; -} - -bool LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s ? LLVector3d::parseVector3d(*s,  &value ) : false; -} - -bool LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s ? LLQuaternion::parseQuat(*s, &value ) : false; -} - -bool LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	return s ? LLUUID::parseUUID(*s, &value ) : false; -} - -bool LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, std::string& value) -{ -	const std::string *s = getAttribute( canonical_name ); -	if( !s ) -	{ -		return false; -	} - -	value = *s; -	return true; -} - - -////////////////////////////////////////////////////////////// - -bool LLXmlTreeNode::getAttributeBOOL(const std::string& name, bool& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeBOOL(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeU8(const std::string& name, U8& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeU8(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeS8(const std::string& name, S8& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeS8(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeS16(const std::string& name, S16& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeS16(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeU16(const std::string& name, U16& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeU16(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeU32(const std::string& name, U32& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeU32(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeS32(const std::string& name, S32& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeS32(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeF32(const std::string& name, F32& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeF32(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeF64(const std::string& name, F64& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeF64(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeColor(const std::string& name, LLColor4& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeColor(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeColor4(const std::string& name, LLColor4& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeColor4(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeColor4U(const std::string& name, LLColor4U& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeColor4U(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeVector3(const std::string& name, LLVector3& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeVector3(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeVector3d(const std::string& name, LLVector3d& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeVector3d(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeQuat(const std::string& name, LLQuaternion& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeQuat(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeUUID(const std::string& name, LLUUID& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeUUID(canonical_name, value); -} - -bool LLXmlTreeNode::getAttributeString(const std::string& name, std::string& value) -{ -	LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name ); -	return getFastAttributeString(canonical_name, value); -} - -/* -  The following xml <message> nodes will all return the string from getTextContents(): -  "The quick brown fox\n  Jumps over the lazy dog" - -  1. HTML paragraph format: -		<message> -		<p>The quick brown fox</p> -		<p>  Jumps over the lazy dog</p> -		</message> -  2. Each quoted section -> paragraph: -		<message> -		"The quick brown fox" -		"  Jumps over the lazy dog" -		</message> -  3. Literal text with beginning and trailing whitespace removed: -		<message> -The quick brown fox -  Jumps over the lazy dog -		</message> -   -*/ - -std::string LLXmlTreeNode::getTextContents() -{ -	std::string msg; -	LLXmlTreeNode* p = getChildByName("p"); -	if (p) -	{ -		// Case 1: node has <p>text</p> tags -		while (p) -		{ -			msg += p->getContents() + "\n"; -			p = getNextNamedChild(); -		} -	} -	else -	{ -		std::string::size_type n = mContents.find_first_not_of(" \t\n"); -		if (n != std::string::npos && mContents[n] == '\"') -		{ -			// Case 2: node has quoted text -			S32 num_lines = 0; -			while(1) -			{ -				// mContents[n] == '"' -				++n; -				std::string::size_type t = n; -				std::string::size_type m = 0; -				// fix-up escaped characters -				while(1) -				{ -					m = mContents.find_first_of("\\\"", t); // find first \ or " -					if ((m == std::string::npos) || (mContents[m] == '\"')) -					{ -						break; -					} -					mContents.erase(m,1); -					t = m+1; -				} -				if (m == std::string::npos) -				{ -					break; -				} -				// mContents[m] == '"' -				num_lines++; -				msg += mContents.substr(n,m-n) + "\n"; -				n = mContents.find_first_of("\"", m+1); -				if (n == std::string::npos) -				{ -					if (num_lines == 1) -					{ -						msg.erase(msg.size()-1); // remove "\n" if only one line -					} -					break; -				} -			} -		} -		else -		{ -			// Case 3: node has embedded text (beginning and trailing whitespace trimmed) -			msg = mContents; -		} -	} -	return msg; -} -	 - -////////////////////////////////////////////////////////////// -// LLXmlTreeParser - -LLXmlTreeParser::LLXmlTreeParser(LLXmlTree* tree)  -	: mTree(tree), -	  mRoot( NULL ), -	  mCurrent( NULL ), -	  mDump( false ), -	  mKeepContents(false) -{ -} - -LLXmlTreeParser::~LLXmlTreeParser()  -{ -} - -bool LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, bool keep_contents) -{ -	llassert( !mRoot ); -	llassert( !mCurrent ); - -	mKeepContents = keep_contents; - -	bool success = LLXmlParser::parseFile(path); - -	*root = mRoot; -	mRoot = NULL; - -	if( success ) -	{ -		llassert( !mCurrent ); -	} -	mCurrent = NULL; -	 -	return success; -} - - -const std::string& LLXmlTreeParser::tabs() -{ -	static std::string s; -	s = ""; -	S32 num_tabs = getDepth() - 1; -	for( S32 i = 0; i < num_tabs; i++) -	{ -		s += "    "; -	} -	return s; -} - -void LLXmlTreeParser::startElement(const char* name, const char **atts)  -{ -	if( mDump ) -	{ -		LL_INFOS() << tabs() << "startElement " << name << LL_ENDL; -		 -		S32 i = 0; -		while( atts[i] && atts[i+1] ) -		{ -			LL_INFOS() << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << LL_ENDL; -			i += 2; -		} -	} - -	LLXmlTreeNode* child = CreateXmlTreeNode( std::string(name), mCurrent ); - -	S32 i = 0; -	while( atts[i] && atts[i+1] ) -	{ -		child->addAttribute( atts[i], atts[i+1] ); -		i += 2; -	} - -	if( mCurrent ) -	{ -		mCurrent->addChild( child ); - -	} -	else -	{ -		llassert( !mRoot ); -		mRoot = child; -	} -	mCurrent = child; -} - -LLXmlTreeNode* LLXmlTreeParser::CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent) -{ -	return new LLXmlTreeNode(name, parent, mTree); -} - - -void LLXmlTreeParser::endElement(const char* name)  -{ -	if( mDump ) -	{ -		LL_INFOS() << tabs() << "endElement " << name << LL_ENDL; -	} - -	if( !mCurrent->mContents.empty() ) -	{ -		LLStringUtil::trim(mCurrent->mContents); -		LLStringUtil::removeCRLF(mCurrent->mContents); -	} - -	mCurrent = mCurrent->getParent(); -} - -void LLXmlTreeParser::characterData(const char *s, int len)  -{ -	std::string str; -	if (s) str = std::string(s, len); -	if( mDump ) -	{ -		LL_INFOS() << tabs() << "CharacterData " << str << LL_ENDL; -	} - -	if (mKeepContents) -	{ -		mCurrent->appendContents( str ); -	} -} - -void LLXmlTreeParser::processingInstruction(const char *target, const char *data) -{ -	if( mDump ) -	{ -		LL_INFOS() << tabs() << "processingInstruction " << data << LL_ENDL; -	} -} - -void LLXmlTreeParser::comment(const char *data) -{ -	if( mDump ) -	{ -		LL_INFOS() << tabs() << "comment " << data << LL_ENDL; -	} -} - -void LLXmlTreeParser::startCdataSection() -{ -	if( mDump ) -	{ -		LL_INFOS() << tabs() << "startCdataSection" << LL_ENDL; -	} -} - -void LLXmlTreeParser::endCdataSection() -{ -	if( mDump ) -	{ -		LL_INFOS() << tabs() << "endCdataSection" << LL_ENDL; -	} -} - -void LLXmlTreeParser::defaultData(const char *s, int len) -{ -	if( mDump ) -	{ -		std::string str; -		if (s) str = std::string(s, len); -		LL_INFOS() << tabs() << "defaultData " << str << LL_ENDL; -	} -} - -void LLXmlTreeParser::unparsedEntityDecl( -	const char* entity_name, -	const char* base, -	const char* system_id, -	const char* public_id, -	const char* notation_name) -{ -	if( mDump ) -	{ -		LL_INFOS() << tabs() << "unparsed entity:"			<< LL_ENDL; -		LL_INFOS() << tabs() << "    entityName "			<< entity_name	<< LL_ENDL; -		LL_INFOS() << tabs() << "    base "				<< base			<< LL_ENDL; -		LL_INFOS() << tabs() << "    systemId "			<< system_id	<< LL_ENDL; -		LL_INFOS() << tabs() << "    publicId "			<< public_id	<< LL_ENDL; -		LL_INFOS() << tabs() << "    notationName "		<< notation_name<< LL_ENDL; -	} -} - -void test_llxmltree() -{ -	LLXmlTree tree; -	bool success = tree.parseFile( "test.xml" ); -	if( success ) -	{ -		tree.dump(); -	} -} - +/**
 + * @file llxmltree.cpp
 + * @brief LLXmlTree implementation
 + *
 + * $LicenseInfo:firstyear=2002&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 "llxmltree.h"
 +#include "v3color.h"
 +#include "v4color.h"
 +#include "v4coloru.h"
 +#include "v3math.h"
 +#include "v3dmath.h"
 +#include "v4math.h"
 +#include "llquaternion.h"
 +#include "lluuid.h"
 +
 +//////////////////////////////////////////////////////////////
 +// LLXmlTree
 +
 +// static
 +LLStdStringTable LLXmlTree::sAttributeKeys(1024);
 +
 +LLXmlTree::LLXmlTree()
 +    : mRoot( NULL ),
 +      mNodeNames(512)
 +{
 +}
 +
 +LLXmlTree::~LLXmlTree()
 +{
 +    cleanup();
 +}
 +
 +void LLXmlTree::cleanup()
 +{
 +    delete mRoot;
 +    mRoot = NULL;
 +    mNodeNames.cleanup();
 +}
 +
 +
 +bool LLXmlTree::parseFile(const std::string &path, bool keep_contents)
 +{
 +    delete mRoot;
 +    mRoot = NULL;
 +
 +    LLXmlTreeParser parser(this);
 +    bool success = parser.parseFile( path, &mRoot, keep_contents );
 +    if( !success )
 +    {
 +        S32 line_number = parser.getCurrentLineNumber();
 +        const char* error =  parser.getErrorString();
 +        LL_WARNS() << "LLXmlTree parse failed.  Line " << line_number << ": " << error << LL_ENDL;
 +    }
 +    return success;
 +}
 +
 +void LLXmlTree::dump()
 +{
 +    if( mRoot )
 +    {
 +        dumpNode( mRoot, "    " );
 +    }
 +}
 +
 +void LLXmlTree::dumpNode( LLXmlTreeNode* node, const std::string& prefix )
 +{
 +    node->dump( prefix );
 +
 +    std::string new_prefix = prefix + "    ";
 +    for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() )
 +    {
 +        dumpNode( child, new_prefix );
 +    }
 +}
 +
 +//////////////////////////////////////////////////////////////
 +// LLXmlTreeNode
 +
 +LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree )
 +    : mName(name),
 +      mParent(parent),
 +      mTree(tree)
 +{
 +}
 +
 +LLXmlTreeNode::~LLXmlTreeNode()
 +{
 +    attribute_map_t::iterator iter;
 +    for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
 +        delete iter->second;
 +        for(LLXmlTreeNode* node : mChildren)
 +        {
 +            delete node;
 +        }
 +        mChildren.clear();
 +}
 +
 +void LLXmlTreeNode::dump( const std::string& prefix )
 +{
 +    LL_INFOS() << prefix << mName ;
 +    if( !mContents.empty() )
 +    {
 +        LL_CONT << " contents = \"" << mContents << "\"";
 +    }
 +    attribute_map_t::iterator iter;
 +    for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
 +    {
 +        LLStdStringHandle key = iter->first;
 +        const std::string* value = iter->second;
 +        LL_CONT << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value);
 +    }
 +    LL_CONT << LL_ENDL;
 +}
 +
 +bool LLXmlTreeNode::hasAttribute(const std::string& name)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString(name);
 +    attribute_map_t::iterator iter = mAttributes.find(canonical_name);
 +    return iter != mAttributes.end();
 +}
 +
 +void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString(name);
 +    const std::string *newstr = new std::string(value);
 +    mAttributes[canonical_name] = newstr; // insert + copy
 +}
 +
 +LLXmlTreeNode*  LLXmlTreeNode::getFirstChild()
 +{
 +    mChildrenIter = mChildren.begin();
 +    return getNextChild();
 +}
 +LLXmlTreeNode*  LLXmlTreeNode::getNextChild()
 +{
 +    if (mChildrenIter == mChildren.end())
 +        return 0;
 +    else
 +        return *mChildrenIter++;
 +}
 +
 +LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name)
 +{
 +    LLStdStringHandle tableptr = mTree->mNodeNames.checkString(name);
 +    mChildMapIter = mChildMap.lower_bound(tableptr);
 +    mChildMapEndIter = mChildMap.upper_bound(tableptr);
 +    return getNextNamedChild();
 +}
 +
 +LLXmlTreeNode* LLXmlTreeNode::getNextNamedChild()
 +{
 +    if (mChildMapIter == mChildMapEndIter)
 +        return NULL;
 +    else
 +        return (mChildMapIter++)->second;
 +}
 +
 +void LLXmlTreeNode::appendContents(const std::string& str)
 +{
 +    mContents.append( str );
 +}
 +
 +void LLXmlTreeNode::addChild(LLXmlTreeNode* child)
 +{
 +    llassert( child );
 +    mChildren.push_back( child );
 +
 +    // Add a name mapping to this node
 +    LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName);
 +    mChildMap.insert( child_map_t::value_type(tableptr, child));
 +
 +    child->mParent = this;
 +}
 +
 +//////////////////////////////////////////////////////////////
 +
 +// These functions assume that name is already in mAttritrubteKeys
 +
 +bool LLXmlTreeNode::getFastAttributeBOOL(LLStdStringHandle canonical_name, bool& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToBOOL( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToU8( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToS8( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToS16( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToU16( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToU32( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToS32( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToF32( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s && LLStringUtil::convertToF64( *s, value );
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s ? LLColor4::parseColor(*s, &value) : false;
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s ? LLColor4::parseColor4(*s, &value) : false;
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s ? LLColor4U::parseColor4U(*s, &value ) : false;
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s ? LLVector3::parseVector3(*s, &value ) : false;
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s ? LLVector3d::parseVector3d(*s,  &value ) : false;
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s ? LLQuaternion::parseQuat(*s, &value ) : false;
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    return s ? LLUUID::parseUUID(*s, &value ) : false;
 +}
 +
 +bool LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, std::string& value)
 +{
 +    const std::string *s = getAttribute( canonical_name );
 +    if( !s )
 +    {
 +        return false;
 +    }
 +
 +    value = *s;
 +    return true;
 +}
 +
 +
 +//////////////////////////////////////////////////////////////
 +
 +bool LLXmlTreeNode::getAttributeBOOL(const std::string& name, bool& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeBOOL(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeU8(const std::string& name, U8& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeU8(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeS8(const std::string& name, S8& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeS8(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeS16(const std::string& name, S16& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeS16(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeU16(const std::string& name, U16& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeU16(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeU32(const std::string& name, U32& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeU32(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeS32(const std::string& name, S32& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeS32(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeF32(const std::string& name, F32& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeF32(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeF64(const std::string& name, F64& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeF64(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeColor(const std::string& name, LLColor4& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeColor(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeColor4(const std::string& name, LLColor4& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeColor4(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeColor4U(const std::string& name, LLColor4U& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeColor4U(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeVector3(const std::string& name, LLVector3& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeVector3(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeVector3d(const std::string& name, LLVector3d& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeVector3d(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeQuat(const std::string& name, LLQuaternion& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeQuat(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeUUID(const std::string& name, LLUUID& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeUUID(canonical_name, value);
 +}
 +
 +bool LLXmlTreeNode::getAttributeString(const std::string& name, std::string& value)
 +{
 +    LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
 +    return getFastAttributeString(canonical_name, value);
 +}
 +
 +/*
 +  The following xml <message> nodes will all return the string from getTextContents():
 +  "The quick brown fox\n  Jumps over the lazy dog"
 +
 +  1. HTML paragraph format:
 +        <message>
 +        <p>The quick brown fox</p>
 +        <p>  Jumps over the lazy dog</p>
 +        </message>
 +  2. Each quoted section -> paragraph:
 +        <message>
 +        "The quick brown fox"
 +        "  Jumps over the lazy dog"
 +        </message>
 +  3. Literal text with beginning and trailing whitespace removed:
 +        <message>
 +The quick brown fox
 +  Jumps over the lazy dog
 +        </message>
 +
 +*/
 +
 +std::string LLXmlTreeNode::getTextContents()
 +{
 +    std::string msg;
 +    LLXmlTreeNode* p = getChildByName("p");
 +    if (p)
 +    {
 +        // Case 1: node has <p>text</p> tags
 +        while (p)
 +        {
 +            msg += p->getContents() + "\n";
 +            p = getNextNamedChild();
 +        }
 +    }
 +    else
 +    {
 +        std::string::size_type n = mContents.find_first_not_of(" \t\n");
 +        if (n != std::string::npos && mContents[n] == '\"')
 +        {
 +            // Case 2: node has quoted text
 +            S32 num_lines = 0;
 +            while(1)
 +            {
 +                // mContents[n] == '"'
 +                ++n;
 +                std::string::size_type t = n;
 +                std::string::size_type m = 0;
 +                // fix-up escaped characters
 +                while(1)
 +                {
 +                    m = mContents.find_first_of("\\\"", t); // find first \ or "
 +                    if ((m == std::string::npos) || (mContents[m] == '\"'))
 +                    {
 +                        break;
 +                    }
 +                    mContents.erase(m,1);
 +                    t = m+1;
 +                }
 +                if (m == std::string::npos)
 +                {
 +                    break;
 +                }
 +                // mContents[m] == '"'
 +                num_lines++;
 +                msg += mContents.substr(n,m-n) + "\n";
 +                n = mContents.find_first_of("\"", m+1);
 +                if (n == std::string::npos)
 +                {
 +                    if (num_lines == 1)
 +                    {
 +                        msg.erase(msg.size()-1); // remove "\n" if only one line
 +                    }
 +                    break;
 +                }
 +            }
 +        }
 +        else
 +        {
 +            // Case 3: node has embedded text (beginning and trailing whitespace trimmed)
 +            msg = mContents;
 +        }
 +    }
 +    return msg;
 +}
 +
 +
 +//////////////////////////////////////////////////////////////
 +// LLXmlTreeParser
 +
 +LLXmlTreeParser::LLXmlTreeParser(LLXmlTree* tree)
 +    : mTree(tree),
 +      mRoot( NULL ),
 +      mCurrent( NULL ),
 +      mDump( false ),
 +      mKeepContents(false)
 +{
 +}
 +
 +LLXmlTreeParser::~LLXmlTreeParser()
 +{
 +}
 +
 +bool LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, bool keep_contents)
 +{
 +    llassert( !mRoot );
 +    llassert( !mCurrent );
 +
 +    mKeepContents = keep_contents;
 +
 +    bool success = LLXmlParser::parseFile(path);
 +
 +    *root = mRoot;
 +    mRoot = NULL;
 +
 +    if( success )
 +    {
 +        llassert( !mCurrent );
 +    }
 +    mCurrent = NULL;
 +
 +    return success;
 +}
 +
 +
 +const std::string& LLXmlTreeParser::tabs()
 +{
 +    static std::string s;
 +    s = "";
 +    S32 num_tabs = getDepth() - 1;
 +    for( S32 i = 0; i < num_tabs; i++)
 +    {
 +        s += "    ";
 +    }
 +    return s;
 +}
 +
 +void LLXmlTreeParser::startElement(const char* name, const char **atts)
 +{
 +    if( mDump )
 +    {
 +        LL_INFOS() << tabs() << "startElement " << name << LL_ENDL;
 +
 +        S32 i = 0;
 +        while( atts[i] && atts[i+1] )
 +        {
 +            LL_INFOS() << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << LL_ENDL;
 +            i += 2;
 +        }
 +    }
 +
 +    LLXmlTreeNode* child = CreateXmlTreeNode( std::string(name), mCurrent );
 +
 +    S32 i = 0;
 +    while( atts[i] && atts[i+1] )
 +    {
 +        child->addAttribute( atts[i], atts[i+1] );
 +        i += 2;
 +    }
 +
 +    if( mCurrent )
 +    {
 +        mCurrent->addChild( child );
 +
 +    }
 +    else
 +    {
 +        llassert( !mRoot );
 +        mRoot = child;
 +    }
 +    mCurrent = child;
 +}
 +
 +LLXmlTreeNode* LLXmlTreeParser::CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent)
 +{
 +    return new LLXmlTreeNode(name, parent, mTree);
 +}
 +
 +
 +void LLXmlTreeParser::endElement(const char* name)
 +{
 +    if( mDump )
 +    {
 +        LL_INFOS() << tabs() << "endElement " << name << LL_ENDL;
 +    }
 +
 +    if( !mCurrent->mContents.empty() )
 +    {
 +        LLStringUtil::trim(mCurrent->mContents);
 +        LLStringUtil::removeCRLF(mCurrent->mContents);
 +    }
 +
 +    mCurrent = mCurrent->getParent();
 +}
 +
 +void LLXmlTreeParser::characterData(const char *s, int len)
 +{
 +    std::string str;
 +    if (s) str = std::string(s, len);
 +    if( mDump )
 +    {
 +        LL_INFOS() << tabs() << "CharacterData " << str << LL_ENDL;
 +    }
 +
 +    if (mKeepContents)
 +    {
 +        mCurrent->appendContents( str );
 +    }
 +}
 +
 +void LLXmlTreeParser::processingInstruction(const char *target, const char *data)
 +{
 +    if( mDump )
 +    {
 +        LL_INFOS() << tabs() << "processingInstruction " << data << LL_ENDL;
 +    }
 +}
 +
 +void LLXmlTreeParser::comment(const char *data)
 +{
 +    if( mDump )
 +    {
 +        LL_INFOS() << tabs() << "comment " << data << LL_ENDL;
 +    }
 +}
 +
 +void LLXmlTreeParser::startCdataSection()
 +{
 +    if( mDump )
 +    {
 +        LL_INFOS() << tabs() << "startCdataSection" << LL_ENDL;
 +    }
 +}
 +
 +void LLXmlTreeParser::endCdataSection()
 +{
 +    if( mDump )
 +    {
 +        LL_INFOS() << tabs() << "endCdataSection" << LL_ENDL;
 +    }
 +}
 +
 +void LLXmlTreeParser::defaultData(const char *s, int len)
 +{
 +    if( mDump )
 +    {
 +        std::string str;
 +        if (s) str = std::string(s, len);
 +        LL_INFOS() << tabs() << "defaultData " << str << LL_ENDL;
 +    }
 +}
 +
 +void LLXmlTreeParser::unparsedEntityDecl(
 +    const char* entity_name,
 +    const char* base,
 +    const char* system_id,
 +    const char* public_id,
 +    const char* notation_name)
 +{
 +    if( mDump )
 +    {
 +        LL_INFOS() << tabs() << "unparsed entity:"          << LL_ENDL;
 +        LL_INFOS() << tabs() << "    entityName "           << entity_name  << LL_ENDL;
 +        LL_INFOS() << tabs() << "    base "             << base         << LL_ENDL;
 +        LL_INFOS() << tabs() << "    systemId "         << system_id    << LL_ENDL;
 +        LL_INFOS() << tabs() << "    publicId "         << public_id    << LL_ENDL;
 +        LL_INFOS() << tabs() << "    notationName "     << notation_name<< LL_ENDL;
 +    }
 +}
 +
 +void test_llxmltree()
 +{
 +    LLXmlTree tree;
 +    bool success = tree.parseFile( "test.xml" );
 +    if( success )
 +    {
 +        tree.dump();
 +    }
 +}
 +
 diff --git a/indra/llxml/llxmltree.h b/indra/llxml/llxmltree.h index 5d15c4c7f5..570edee5ad 100644 --- a/indra/llxml/llxmltree.h +++ b/indra/llxml/llxmltree.h @@ -1,234 +1,234 @@ -/**  - * @file llxmltree.h - * @author Aaron Yonas, Richard Nelson - * @brief LLXmlTree class definition - * - * $LicenseInfo:firstyear=2001&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_LLXMLTREE_H -#define LL_LLXMLTREE_H - -#include <map> -#include <list> -#include "llstring.h" -#include "llxmlparser.h" -#include "llstringtable.h" - -class LLColor4; -class LLColor4U; -class LLQuaternion; -class LLUUID; -class LLVector3; -class LLVector3d; -class LLXmlTreeNode; -class LLXmlTreeParser; - -////////////////////////////////////////////////////////////// -// LLXmlTree - -class LLXmlTree -{ -	friend class LLXmlTreeNode; -	 -public: -	LLXmlTree(); -	virtual ~LLXmlTree(); -	void cleanup(); - -	virtual bool	parseFile(const std::string &path, bool keep_contents = true); - -	LLXmlTreeNode*	getRoot() { return mRoot; } - -	void			dump(); -	void			dumpNode( LLXmlTreeNode* node, const std::string& prefix ); - -	static LLStdStringHandle addAttributeString( const std::string& name) -	{ -		return sAttributeKeys.addString( name ); -	} -	 -public: -	// global -	static LLStdStringTable sAttributeKeys; -	 -protected: -	LLXmlTreeNode* mRoot; - -	// local -	LLStdStringTable mNodeNames;	 -}; - -////////////////////////////////////////////////////////////// -// LLXmlTreeNode - -class LLXmlTreeNode -{ -	friend class LLXmlTree; -	friend class LLXmlTreeParser; - -protected: -	// Protected since nodes are only created and destroyed by friend classes and other LLXmlTreeNodes -	LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree ); -	 -public: -	virtual ~LLXmlTreeNode(); - -	const std::string&	getName() -	{ -		return mName; -	} -	bool hasName( const std::string& name ) -	{ -		return mName == name; -	} - -	bool hasAttribute( const std::string& name ); - -	// Fast versions use cannonical_name handlee to entru in LLXmlTree::sAttributeKeys string table -	bool			getFastAttributeBOOL(		LLStdStringHandle cannonical_name, bool& value ); -	bool			getFastAttributeU8(			LLStdStringHandle cannonical_name, U8& value ); -	bool			getFastAttributeS8(			LLStdStringHandle cannonical_name, S8& value ); -	bool			getFastAttributeU16(		LLStdStringHandle cannonical_name, U16& value ); -	bool			getFastAttributeS16(		LLStdStringHandle cannonical_name, S16& value ); -	bool			getFastAttributeU32(		LLStdStringHandle cannonical_name, U32& value ); -	bool			getFastAttributeS32(		LLStdStringHandle cannonical_name, S32& value ); -	bool			getFastAttributeF32(		LLStdStringHandle cannonical_name, F32& value ); -	bool			getFastAttributeF64(		LLStdStringHandle cannonical_name, F64& value ); -	bool			getFastAttributeColor(		LLStdStringHandle cannonical_name, LLColor4& value ); -	bool			getFastAttributeColor4(		LLStdStringHandle cannonical_name, LLColor4& value ); -	bool			getFastAttributeColor4U(	LLStdStringHandle cannonical_name, LLColor4U& value ); -	bool			getFastAttributeVector3(	LLStdStringHandle cannonical_name, LLVector3& value ); -	bool			getFastAttributeVector3d(	LLStdStringHandle cannonical_name, LLVector3d& value ); -	bool			getFastAttributeQuat(		LLStdStringHandle cannonical_name, LLQuaternion& value ); -	bool			getFastAttributeUUID(		LLStdStringHandle cannonical_name, LLUUID& value ); -	bool			getFastAttributeString(		LLStdStringHandle cannonical_name, std::string& value ); - -	// Normal versions find 'name' in LLXmlTree::sAttributeKeys then call fast versions -	virtual bool		getAttributeBOOL(		const std::string& name, bool& value ); -	virtual bool		getAttributeU8(			const std::string& name, U8& value ); -	virtual bool		getAttributeS8(			const std::string& name, S8& value ); -	virtual bool		getAttributeU16(		const std::string& name, U16& value ); -	virtual bool		getAttributeS16(		const std::string& name, S16& value ); -	virtual bool		getAttributeU32(		const std::string& name, U32& value ); -	virtual bool		getAttributeS32(		const std::string& name, S32& value ); -	virtual bool		getAttributeF32(		const std::string& name, F32& value ); -	virtual bool		getAttributeF64(		const std::string& name, F64& value ); -	virtual bool		getAttributeColor(		const std::string& name, LLColor4& value ); -	virtual bool		getAttributeColor4(		const std::string& name, LLColor4& value ); -	virtual bool		getAttributeColor4U(	const std::string& name, LLColor4U& value ); -	virtual bool		getAttributeVector3(	const std::string& name, LLVector3& value ); -	virtual bool		getAttributeVector3d(	const std::string& name, LLVector3d& value ); -	virtual bool		getAttributeQuat(		const std::string& name, LLQuaternion& value ); -	virtual bool		getAttributeUUID(		const std::string& name, LLUUID& value ); -	virtual bool		getAttributeString(		const std::string& name, std::string& value ); - -	const std::string& getContents() -	{ -		return mContents; -	} -	std::string getTextContents(); - -	LLXmlTreeNode*	getParent()							{ return mParent; } -	LLXmlTreeNode*	getFirstChild(); -	LLXmlTreeNode*	getNextChild(); -	S32				getChildCount()						{ return (S32)mChildren.size(); } -	LLXmlTreeNode*  getChildByName( const std::string& name );	// returns first child with name, NULL if none -	LLXmlTreeNode*  getNextNamedChild();				// returns next child with name, NULL if none - -protected: -	const std::string* getAttribute( LLStdStringHandle name) -	{ -		attribute_map_t::iterator iter = mAttributes.find(name); -		return (iter == mAttributes.end()) ? 0 : iter->second; -	} - -private: -	void			addAttribute( const std::string& name, const std::string& value ); -	void			appendContents( const std::string& str ); -	void			addChild( LLXmlTreeNode* child ); - -	void			dump( const std::string& prefix ); - -protected: -	typedef std::map<LLStdStringHandle, const std::string*> attribute_map_t; -	attribute_map_t						mAttributes; - -private: -	std::string							mName; -	std::string							mContents; -	 -	typedef std::vector<class LLXmlTreeNode *> children_t; -	children_t                          mChildren; -	children_t::iterator				mChildrenIter; -	 -	typedef std::multimap<LLStdStringHandle, LLXmlTreeNode *> child_map_t; -	child_map_t							mChildMap;		// for fast name lookups -	child_map_t::iterator				mChildMapIter; -	child_map_t::iterator				mChildMapEndIter; - -	LLXmlTreeNode*						mParent; -	LLXmlTree*							mTree; -}; - -////////////////////////////////////////////////////////////// -// LLXmlTreeParser - -class LLXmlTreeParser : public LLXmlParser -{ -public: -	LLXmlTreeParser(LLXmlTree* tree); -	virtual ~LLXmlTreeParser(); - -	bool parseFile(const std::string &path, LLXmlTreeNode** root, bool keep_contents ); - -protected: -	const std::string& tabs(); - -	// Overrides from LLXmlParser -	virtual void	startElement(const char *name, const char **attributes);  -	virtual void	endElement(const char *name); -	virtual void	characterData(const char *s, int len); -	virtual void	processingInstruction(const char *target, const char *data); -	virtual void	comment(const char *data); -	virtual void	startCdataSection(); -	virtual void	endCdataSection(); -	virtual void	defaultData(const char *s, int len); -	virtual void	unparsedEntityDecl( -		const char* entity_name, -		const char* base, -		const char* system_id, -		const char* public_id, -		const char* notation_name); - -	//template method pattern -	virtual LLXmlTreeNode* CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent); - -protected: -	LLXmlTree*		mTree; -	LLXmlTreeNode*	mRoot; -	LLXmlTreeNode*  mCurrent; -	bool			mDump;	// Dump parse tree to LL_INFOS() as it is read. -	bool			mKeepContents; -}; - -#endif  // LL_LLXMLTREE_H +/**
 + * @file llxmltree.h
 + * @author Aaron Yonas, Richard Nelson
 + * @brief LLXmlTree class definition
 + *
 + * $LicenseInfo:firstyear=2001&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_LLXMLTREE_H
 +#define LL_LLXMLTREE_H
 +
 +#include <map>
 +#include <list>
 +#include "llstring.h"
 +#include "llxmlparser.h"
 +#include "llstringtable.h"
 +
 +class LLColor4;
 +class LLColor4U;
 +class LLQuaternion;
 +class LLUUID;
 +class LLVector3;
 +class LLVector3d;
 +class LLXmlTreeNode;
 +class LLXmlTreeParser;
 +
 +//////////////////////////////////////////////////////////////
 +// LLXmlTree
 +
 +class LLXmlTree
 +{
 +    friend class LLXmlTreeNode;
 +
 +public:
 +    LLXmlTree();
 +    virtual ~LLXmlTree();
 +    void cleanup();
 +
 +    virtual bool    parseFile(const std::string &path, bool keep_contents = true);
 +
 +    LLXmlTreeNode*  getRoot() { return mRoot; }
 +
 +    void            dump();
 +    void            dumpNode( LLXmlTreeNode* node, const std::string& prefix );
 +
 +    static LLStdStringHandle addAttributeString( const std::string& name)
 +    {
 +        return sAttributeKeys.addString( name );
 +    }
 +
 +public:
 +    // global
 +    static LLStdStringTable sAttributeKeys;
 +
 +protected:
 +    LLXmlTreeNode* mRoot;
 +
 +    // local
 +    LLStdStringTable mNodeNames;
 +};
 +
 +//////////////////////////////////////////////////////////////
 +// LLXmlTreeNode
 +
 +class LLXmlTreeNode
 +{
 +    friend class LLXmlTree;
 +    friend class LLXmlTreeParser;
 +
 +protected:
 +    // Protected since nodes are only created and destroyed by friend classes and other LLXmlTreeNodes
 +    LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree );
 +
 +public:
 +    virtual ~LLXmlTreeNode();
 +
 +    const std::string&  getName()
 +    {
 +        return mName;
 +    }
 +    bool hasName( const std::string& name )
 +    {
 +        return mName == name;
 +    }
 +
 +    bool hasAttribute( const std::string& name );
 +
 +    // Fast versions use cannonical_name handlee to entru in LLXmlTree::sAttributeKeys string table
 +    bool            getFastAttributeBOOL(       LLStdStringHandle cannonical_name, bool& value );
 +    bool            getFastAttributeU8(         LLStdStringHandle cannonical_name, U8& value );
 +    bool            getFastAttributeS8(         LLStdStringHandle cannonical_name, S8& value );
 +    bool            getFastAttributeU16(        LLStdStringHandle cannonical_name, U16& value );
 +    bool            getFastAttributeS16(        LLStdStringHandle cannonical_name, S16& value );
 +    bool            getFastAttributeU32(        LLStdStringHandle cannonical_name, U32& value );
 +    bool            getFastAttributeS32(        LLStdStringHandle cannonical_name, S32& value );
 +    bool            getFastAttributeF32(        LLStdStringHandle cannonical_name, F32& value );
 +    bool            getFastAttributeF64(        LLStdStringHandle cannonical_name, F64& value );
 +    bool            getFastAttributeColor(      LLStdStringHandle cannonical_name, LLColor4& value );
 +    bool            getFastAttributeColor4(     LLStdStringHandle cannonical_name, LLColor4& value );
 +    bool            getFastAttributeColor4U(    LLStdStringHandle cannonical_name, LLColor4U& value );
 +    bool            getFastAttributeVector3(    LLStdStringHandle cannonical_name, LLVector3& value );
 +    bool            getFastAttributeVector3d(   LLStdStringHandle cannonical_name, LLVector3d& value );
 +    bool            getFastAttributeQuat(       LLStdStringHandle cannonical_name, LLQuaternion& value );
 +    bool            getFastAttributeUUID(       LLStdStringHandle cannonical_name, LLUUID& value );
 +    bool            getFastAttributeString(     LLStdStringHandle cannonical_name, std::string& value );
 +
 +    // Normal versions find 'name' in LLXmlTree::sAttributeKeys then call fast versions
 +    virtual bool        getAttributeBOOL(       const std::string& name, bool& value );
 +    virtual bool        getAttributeU8(         const std::string& name, U8& value );
 +    virtual bool        getAttributeS8(         const std::string& name, S8& value );
 +    virtual bool        getAttributeU16(        const std::string& name, U16& value );
 +    virtual bool        getAttributeS16(        const std::string& name, S16& value );
 +    virtual bool        getAttributeU32(        const std::string& name, U32& value );
 +    virtual bool        getAttributeS32(        const std::string& name, S32& value );
 +    virtual bool        getAttributeF32(        const std::string& name, F32& value );
 +    virtual bool        getAttributeF64(        const std::string& name, F64& value );
 +    virtual bool        getAttributeColor(      const std::string& name, LLColor4& value );
 +    virtual bool        getAttributeColor4(     const std::string& name, LLColor4& value );
 +    virtual bool        getAttributeColor4U(    const std::string& name, LLColor4U& value );
 +    virtual bool        getAttributeVector3(    const std::string& name, LLVector3& value );
 +    virtual bool        getAttributeVector3d(   const std::string& name, LLVector3d& value );
 +    virtual bool        getAttributeQuat(       const std::string& name, LLQuaternion& value );
 +    virtual bool        getAttributeUUID(       const std::string& name, LLUUID& value );
 +    virtual bool        getAttributeString(     const std::string& name, std::string& value );
 +
 +    const std::string& getContents()
 +    {
 +        return mContents;
 +    }
 +    std::string getTextContents();
 +
 +    LLXmlTreeNode*  getParent()                         { return mParent; }
 +    LLXmlTreeNode*  getFirstChild();
 +    LLXmlTreeNode*  getNextChild();
 +    S32             getChildCount()                     { return (S32)mChildren.size(); }
 +    LLXmlTreeNode*  getChildByName( const std::string& name );  // returns first child with name, NULL if none
 +    LLXmlTreeNode*  getNextNamedChild();                // returns next child with name, NULL if none
 +
 +protected:
 +    const std::string* getAttribute( LLStdStringHandle name)
 +    {
 +        attribute_map_t::iterator iter = mAttributes.find(name);
 +        return (iter == mAttributes.end()) ? 0 : iter->second;
 +    }
 +
 +private:
 +    void            addAttribute( const std::string& name, const std::string& value );
 +    void            appendContents( const std::string& str );
 +    void            addChild( LLXmlTreeNode* child );
 +
 +    void            dump( const std::string& prefix );
 +
 +protected:
 +    typedef std::map<LLStdStringHandle, const std::string*> attribute_map_t;
 +    attribute_map_t                     mAttributes;
 +
 +private:
 +    std::string                         mName;
 +    std::string                         mContents;
 +
 +    typedef std::vector<class LLXmlTreeNode *> children_t;
 +    children_t                          mChildren;
 +    children_t::iterator                mChildrenIter;
 +
 +    typedef std::multimap<LLStdStringHandle, LLXmlTreeNode *> child_map_t;
 +    child_map_t                         mChildMap;      // for fast name lookups
 +    child_map_t::iterator               mChildMapIter;
 +    child_map_t::iterator               mChildMapEndIter;
 +
 +    LLXmlTreeNode*                      mParent;
 +    LLXmlTree*                          mTree;
 +};
 +
 +//////////////////////////////////////////////////////////////
 +// LLXmlTreeParser
 +
 +class LLXmlTreeParser : public LLXmlParser
 +{
 +public:
 +    LLXmlTreeParser(LLXmlTree* tree);
 +    virtual ~LLXmlTreeParser();
 +
 +    bool parseFile(const std::string &path, LLXmlTreeNode** root, bool keep_contents );
 +
 +protected:
 +    const std::string& tabs();
 +
 +    // Overrides from LLXmlParser
 +    virtual void    startElement(const char *name, const char **attributes);
 +    virtual void    endElement(const char *name);
 +    virtual void    characterData(const char *s, int len);
 +    virtual void    processingInstruction(const char *target, const char *data);
 +    virtual void    comment(const char *data);
 +    virtual void    startCdataSection();
 +    virtual void    endCdataSection();
 +    virtual void    defaultData(const char *s, int len);
 +    virtual void    unparsedEntityDecl(
 +        const char* entity_name,
 +        const char* base,
 +        const char* system_id,
 +        const char* public_id,
 +        const char* notation_name);
 +
 +    //template method pattern
 +    virtual LLXmlTreeNode* CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent);
 +
 +protected:
 +    LLXmlTree*      mTree;
 +    LLXmlTreeNode*  mRoot;
 +    LLXmlTreeNode*  mCurrent;
 +    bool            mDump;  // Dump parse tree to LL_INFOS() as it is read.
 +    bool            mKeepContents;
 +};
 +
 +#endif  // LL_LLXMLTREE_H
 diff --git a/indra/llxml/tests/llcontrol_test.cpp b/indra/llxml/tests/llcontrol_test.cpp index 0c0ef61d23..2025111363 100644 --- a/indra/llxml/tests/llcontrol_test.cpp +++ b/indra/llxml/tests/llcontrol_test.cpp @@ -1,154 +1,154 @@ -/**  - * @file llcontrol_tut.cpp - * @date   February 2008 - * @brief control group unit tests - * - * $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" -#include "llsdserialize.h" -#include "llfile.h" -#include "stringize.h" - -#include "../llcontrol.h" - -#include "../test/lltut.h" -#include <memory> -#include <vector> - -namespace tut -{ -	struct control_group -	{ -		std::unique_ptr<LLControlGroup> mCG; -		std::string mTestConfigDir; -		std::string mTestConfigFile; -		std::vector<std::string> mCleanups; -		static bool mListenerFired; -		control_group() -		{ -			mCG.reset(new LLControlGroup("foo")); -			LLUUID random; -			random.generate(); -			// generate temp dir -			mTestConfigDir = STRINGIZE(LLFile::tmpdir() << "llcontrol-test-" << random << "/"); -			mTestConfigFile = mTestConfigDir + "settings.xml"; -			LLFile::mkdir(mTestConfigDir); -			LLSD config; -			config["TestSetting"]["Comment"] = "Dummy setting used for testing"; -			config["TestSetting"]["Persist"] = 1; -			config["TestSetting"]["Type"] = "U32"; -			config["TestSetting"]["Value"] = 12; -			writeSettingsFile(config); -		} -		~control_group() -		{ -			//Remove test files -			for (auto filename : mCleanups) -			{ -				LLFile::remove(filename); -			} -			LLFile::remove(mTestConfigFile); -			LLFile::rmdir(mTestConfigDir); -		} -		void writeSettingsFile(const LLSD& config) -		{ -			llofstream file(mTestConfigFile.c_str()); -			if (file.is_open()) -			{ -				LLSDSerialize::toPrettyXML(config, file); -			} -			file.close(); -		} -		static bool handleListenerTest() -		{ -			control_group::mListenerFired = true; -			return true; -		} -	}; - -	bool control_group::mListenerFired = false; - -	typedef test_group<control_group> control_group_test; -	typedef control_group_test::object control_group_t; -	control_group_test tut_control_group("control_group"); - -	//load settings from files - LLSD -	template<> template<> -	void control_group_t::test<1>() -	{ -		int results = mCG->loadFromFile(mTestConfigFile.c_str()); -		ensure("number of settings", (results == 1)); -		ensure("value of setting", (mCG->getU32("TestSetting") == 12)); -	} - -	//save settings to files -	template<> template<> -	void control_group_t::test<2>() -	{ -		int results = mCG->loadFromFile(mTestConfigFile.c_str()); -		mCG->setU32("TestSetting", 13); -		ensure_equals("value of changed setting", mCG->getU32("TestSetting"), 13); -		LLControlGroup test_cg("foo2"); -		std::string temp_test_file = (mTestConfigDir + "setting_llsd_temp.xml"); -		mCleanups.push_back(temp_test_file); -		mCG->saveToFile(temp_test_file.c_str(), true); -		results = test_cg.loadFromFile(temp_test_file.c_str()); -		ensure("number of changed settings loaded", (results == 1)); -		ensure("value of changed settings loaded", (test_cg.getU32("TestSetting") == 13)); -	} -    -	//priorities -	template<> template<> -	void control_group_t::test<3>() -	{ -		// Pass default_values = true. This tells loadFromFile() we're loading -		// a default settings file that declares variables, rather than a user -		// settings file. When loadFromFile() encounters an unrecognized user -		// settings variable, it forcibly preserves it (CHOP-962). -		int results = mCG->loadFromFile(mTestConfigFile.c_str(), true); -		LLControlVariable* control = mCG->getControl("TestSetting"); -		LLSD new_value = 13; -		control->setValue(new_value, false); -		ensure_equals("value of changed setting", mCG->getU32("TestSetting"), 13); -		LLControlGroup test_cg("foo3"); -		std::string temp_test_file = (mTestConfigDir + "setting_llsd_persist_temp.xml"); -		mCleanups.push_back(temp_test_file); -		mCG->saveToFile(temp_test_file.c_str(), true); -		results = test_cg.loadFromFile(temp_test_file.c_str()); -		//If we haven't changed any settings, then we shouldn't have any settings to load -		ensure("number of non-persisted changed settings loaded", (results == 0)); -	} - -	//listeners -	template<> template<> -	void control_group_t::test<4>() -	{ -		int results = mCG->loadFromFile(mTestConfigFile.c_str()); -		ensure("number of settings", (results == 1)); -		mCG->getControl("TestSetting")->getSignal()->connect(boost::bind(&this->handleListenerTest)); -		mCG->setU32("TestSetting", 13); -		ensure("listener fired on changed setting", mListenerFired); -	} - -} +/**
 + * @file llcontrol_tut.cpp
 + * @date   February 2008
 + * @brief control group unit tests
 + *
 + * $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"
 +#include "llsdserialize.h"
 +#include "llfile.h"
 +#include "stringize.h"
 +
 +#include "../llcontrol.h"
 +
 +#include "../test/lltut.h"
 +#include <memory>
 +#include <vector>
 +
 +namespace tut
 +{
 +    struct control_group
 +    {
 +        std::unique_ptr<LLControlGroup> mCG;
 +        std::string mTestConfigDir;
 +        std::string mTestConfigFile;
 +        std::vector<std::string> mCleanups;
 +        static bool mListenerFired;
 +        control_group()
 +        {
 +            mCG.reset(new LLControlGroup("foo"));
 +            LLUUID random;
 +            random.generate();
 +            // generate temp dir
 +            mTestConfigDir = STRINGIZE(LLFile::tmpdir() << "llcontrol-test-" << random << "/");
 +            mTestConfigFile = mTestConfigDir + "settings.xml";
 +            LLFile::mkdir(mTestConfigDir);
 +            LLSD config;
 +            config["TestSetting"]["Comment"] = "Dummy setting used for testing";
 +            config["TestSetting"]["Persist"] = 1;
 +            config["TestSetting"]["Type"] = "U32";
 +            config["TestSetting"]["Value"] = 12;
 +            writeSettingsFile(config);
 +        }
 +        ~control_group()
 +        {
 +            //Remove test files
 +            for (auto filename : mCleanups)
 +            {
 +                LLFile::remove(filename);
 +            }
 +            LLFile::remove(mTestConfigFile);
 +            LLFile::rmdir(mTestConfigDir);
 +        }
 +        void writeSettingsFile(const LLSD& config)
 +        {
 +            llofstream file(mTestConfigFile.c_str());
 +            if (file.is_open())
 +            {
 +                LLSDSerialize::toPrettyXML(config, file);
 +            }
 +            file.close();
 +        }
 +        static bool handleListenerTest()
 +        {
 +            control_group::mListenerFired = true;
 +            return true;
 +        }
 +    };
 +
 +    bool control_group::mListenerFired = false;
 +
 +    typedef test_group<control_group> control_group_test;
 +    typedef control_group_test::object control_group_t;
 +    control_group_test tut_control_group("control_group");
 +
 +    //load settings from files - LLSD
 +    template<> template<>
 +    void control_group_t::test<1>()
 +    {
 +        int results = mCG->loadFromFile(mTestConfigFile.c_str());
 +        ensure("number of settings", (results == 1));
 +        ensure("value of setting", (mCG->getU32("TestSetting") == 12));
 +    }
 +
 +    //save settings to files
 +    template<> template<>
 +    void control_group_t::test<2>()
 +    {
 +        int results = mCG->loadFromFile(mTestConfigFile.c_str());
 +        mCG->setU32("TestSetting", 13);
 +        ensure_equals("value of changed setting", mCG->getU32("TestSetting"), 13);
 +        LLControlGroup test_cg("foo2");
 +        std::string temp_test_file = (mTestConfigDir + "setting_llsd_temp.xml");
 +        mCleanups.push_back(temp_test_file);
 +        mCG->saveToFile(temp_test_file.c_str(), true);
 +        results = test_cg.loadFromFile(temp_test_file.c_str());
 +        ensure("number of changed settings loaded", (results == 1));
 +        ensure("value of changed settings loaded", (test_cg.getU32("TestSetting") == 13));
 +    }
 +
 +    //priorities
 +    template<> template<>
 +    void control_group_t::test<3>()
 +    {
 +        // Pass default_values = true. This tells loadFromFile() we're loading
 +        // a default settings file that declares variables, rather than a user
 +        // settings file. When loadFromFile() encounters an unrecognized user
 +        // settings variable, it forcibly preserves it (CHOP-962).
 +        int results = mCG->loadFromFile(mTestConfigFile.c_str(), true);
 +        LLControlVariable* control = mCG->getControl("TestSetting");
 +        LLSD new_value = 13;
 +        control->setValue(new_value, false);
 +        ensure_equals("value of changed setting", mCG->getU32("TestSetting"), 13);
 +        LLControlGroup test_cg("foo3");
 +        std::string temp_test_file = (mTestConfigDir + "setting_llsd_persist_temp.xml");
 +        mCleanups.push_back(temp_test_file);
 +        mCG->saveToFile(temp_test_file.c_str(), true);
 +        results = test_cg.loadFromFile(temp_test_file.c_str());
 +        //If we haven't changed any settings, then we shouldn't have any settings to load
 +        ensure("number of non-persisted changed settings loaded", (results == 0));
 +    }
 +
 +    //listeners
 +    template<> template<>
 +    void control_group_t::test<4>()
 +    {
 +        int results = mCG->loadFromFile(mTestConfigFile.c_str());
 +        ensure("number of settings", (results == 1));
 +        mCG->getControl("TestSetting")->getSignal()->connect(boost::bind(&this->handleListenerTest));
 +        mCG->setU32("TestSetting", 13);
 +        ensure("listener fired on changed setting", mListenerFired);
 +    }
 +
 +}
 | 
