diff options
| author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 20:51:58 +0300 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-22 20:51:58 +0300 | 
| commit | 6cc7dd09d5e69cf57e6de7fb568a0ad2693f9c9a (patch) | |
| tree | fab23811a5cedc1ebf01479c852ee92ff62b636c /indra/llmessage/lltemplatemessagebuilder.cpp | |
| parent | ef8f4819822288e044ea719feb6af7a1f4df4c4e (diff) | |
| parent | 7bb5afc11ee5a6af78302a8d76a9a619e2baaab2 (diff) | |
Merge pull request #1545 from Ansariel/DRTVWR-600-maint-A
Merge main into DRTVWR-600-maint-a
Diffstat (limited to 'indra/llmessage/lltemplatemessagebuilder.cpp')
| -rw-r--r-- | indra/llmessage/lltemplatemessagebuilder.cpp | 1786 | 
1 files changed, 893 insertions, 893 deletions
diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index 62c53dbe55..57ffba9705 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -1,893 +1,893 @@ -/**  - * @file lltemplatemessagebuilder.cpp - * @brief LLTemplateMessageBuilder class implementation. - * - * $LicenseInfo:firstyear=2007&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 "lltemplatemessagebuilder.h" - -#include "llmessagetemplate.h" -#include "llmath.h" -#include "llquaternion.h" -#include "u64.h" -#include "v3dmath.h" -#include "v3math.h" -#include "v4math.h" - -LLTemplateMessageBuilder::LLTemplateMessageBuilder(const message_template_name_map_t& name_template_map) : -	mCurrentSMessageData(NULL), -	mCurrentSMessageTemplate(NULL), -	mCurrentSDataBlock(NULL), -	mCurrentSMessageName(NULL), -	mCurrentSBlockName(NULL), -	mbSBuilt(false), -	mbSClear(true), -	mCurrentSendTotal(0), -	mMessageTemplates(name_template_map) -{ -} - -//virtual -LLTemplateMessageBuilder::~LLTemplateMessageBuilder() -{ -	delete mCurrentSMessageData; -	mCurrentSMessageData = NULL; -} - -// virtual -void LLTemplateMessageBuilder::newMessage(const char *name) -{ -	mbSBuilt = false; -	mbSClear = false; - -	mCurrentSendTotal = 0; - -	delete mCurrentSMessageData; -	mCurrentSMessageData = NULL; - -	char* namep = (char*)name;  -	if (mMessageTemplates.count(namep) > 0) -	{ -		mCurrentSMessageTemplate = mMessageTemplates.find(name)->second; -		mCurrentSMessageData = new LLMsgData(namep); -		mCurrentSMessageName = namep; -		mCurrentSDataBlock = NULL; -		mCurrentSBlockName = NULL; - -		// add at one of each block -		const LLMessageTemplate* msg_template = mMessageTemplates.find(name)->second; - -		if (msg_template->getDeprecation() != MD_NOTDEPRECATED) -		{ -			LL_WARNS() << "Sending deprecated message " << namep << LL_ENDL; -		} -		 -		LLMessageTemplate::message_block_map_t::const_iterator iter; -		for(iter = msg_template->mMemberBlocks.begin(); -			iter != msg_template->mMemberBlocks.end(); -			++iter) -		{ -			LLMessageBlock* ci = *iter; -			LLMsgBlkData* tblockp = new LLMsgBlkData(ci->mName, 0); -			mCurrentSMessageData->addBlock(tblockp); -		} -	} -	else -	{ -		LL_ERRS() << "newMessage - Message " << name << " not registered" << LL_ENDL; -	} -} - -// virtual -void LLTemplateMessageBuilder::clearMessage() -{ -	mbSBuilt = false; -	mbSClear = true; - -	mCurrentSendTotal = 0; - -	mCurrentSMessageTemplate = NULL; - -	delete mCurrentSMessageData; -	mCurrentSMessageData = NULL; - -	mCurrentSMessageName = NULL; -	mCurrentSDataBlock = NULL; -	mCurrentSBlockName = NULL; -} - -// virtual -void LLTemplateMessageBuilder::nextBlock(const char* blockname) -{ -	char *bnamep = (char *)blockname;  - -	if (!mCurrentSMessageTemplate) -	{ -		LL_ERRS() << "newMessage not called prior to setBlock" << LL_ENDL; -		return; -	} - -	// now, does this block exist? -	const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep); -	if (!template_data) -	{ -		LL_ERRS() << "LLTemplateMessageBuilder::nextBlock " << bnamep -			<< " not a block in " << mCurrentSMessageTemplate->mName << LL_ENDL; -		return; -	} -	 -	// ok, have we already set this block? -	LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[bnamep]; -	if (block_data->mBlockNumber == 0) -	{ -		// nope! set this as the current block -		block_data->mBlockNumber = 1; -		mCurrentSDataBlock = block_data; -		mCurrentSBlockName = bnamep; - -		// add placeholders for each of the variables -		for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin(); -			 iter != template_data->mMemberVariables.end(); iter++) -		{ -			LLMessageVariable& ci = **iter; -			mCurrentSDataBlock->addVariable(ci.getName(), ci.getType()); -		} -		return; -	} -	else -	{ -		// already have this block. . .  -		// are we supposed to have a new one? - -		// if the block is type MBT_SINGLE this is bad! -		if (template_data->mType == MBT_SINGLE) -		{ -			LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called multiple times" -				<< " for " << bnamep << " but is type MBT_SINGLE" << LL_ENDL; -			return; -		} - - -		// if the block is type MBT_MULTIPLE then we need a known number,  -		// make sure that we're not exceeding it -		if (  (template_data->mType == MBT_MULTIPLE) -			&&(mCurrentSDataBlock->mBlockNumber == template_data->mNumber)) -		{ -			LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called " -				<< mCurrentSDataBlock->mBlockNumber << " times for " << bnamep -				<< " exceeding " << template_data->mNumber -				<< " specified in type MBT_MULTIPLE." << LL_ENDL; -			return; -		} - -		// ok, we can make a new one -		// modify the name to avoid name collision by adding number to end -		S32  count = block_data->mBlockNumber; - -		// incrememt base name's count -		block_data->mBlockNumber++; - -		if (block_data->mBlockNumber > MAX_BLOCKS) -		{ -			LL_ERRS() << "Trying to pack too many blocks into MBT_VARIABLE type " -				   << "(limited to " << MAX_BLOCKS << ")" << LL_ENDL; -		} - -		// create new name -		// Nota Bene: if things are working correctly,  -		// mCurrentMessageData->mMemberBlocks[blockname]->mBlockNumber ==  -		// mCurrentDataBlock->mBlockNumber + 1 - -		char *nbnamep = bnamep + count; -	 -		mCurrentSDataBlock = new LLMsgBlkData(bnamep, count); -		mCurrentSDataBlock->mName = nbnamep; -		mCurrentSMessageData->mMemberBlocks[nbnamep] = mCurrentSDataBlock; - -		// add placeholders for each of the variables -		for (LLMessageBlock::message_variable_map_t::const_iterator -				 iter = template_data->mMemberVariables.begin(), -				 end = template_data->mMemberVariables.end(); -			 iter != end; iter++) -		{ -			LLMessageVariable& ci = **iter; -			mCurrentSDataBlock->addVariable(ci.getName(), ci.getType()); -		} -		return; -	} -} - -// TODO: Remove this horror... -bool LLTemplateMessageBuilder::removeLastBlock() -{ -	if (mCurrentSBlockName) -	{ -		if (  (mCurrentSMessageData) -			&&(mCurrentSMessageTemplate)) -		{ -			if (mCurrentSMessageData->mMemberBlocks[mCurrentSBlockName]->mBlockNumber >= 1) -			{ -				// At least one block for the current block name. - -				// Store the current block name for future reference. -				char *block_name = mCurrentSBlockName; - -				// Decrement the sent total by the size of the -				// data in the message block that we're currently building. - -				const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName); -				 -				for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin(); -					 iter != template_data->mMemberVariables.end(); iter++) -				{ -					LLMessageVariable& ci = **iter; -					mCurrentSendTotal -= ci.getSize(); -				} - - -				// Now we want to find the block that we're blowing away. - -				// Get the number of blocks. -				LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[block_name]; -				S32 num_blocks = block_data->mBlockNumber; - -				// Use the same (suspect?) algorithm that's used to generate -				// the names in the nextBlock method to find it. -				char *block_getting_whacked = block_name + num_blocks - 1; -				LLMsgBlkData* whacked_data = mCurrentSMessageData->mMemberBlocks[block_getting_whacked]; -				delete whacked_data; -				mCurrentSMessageData->mMemberBlocks.erase(block_getting_whacked); - -				if (num_blocks <= 1) -				{ -					// we just blew away the last one, so return false -					LL_WARNS() << "not blowing away the only block of message " -							<< mCurrentSMessageName -							<< ". Block: " << block_name -							<< ". Number: " << num_blocks -							<< LL_ENDL; -					return false; -				} -				else -				{ -					// Decrement the counter. -					block_data->mBlockNumber--; -					return true; -				} -			} -		} -	} -	return false; -} - -// add data to variable in current block -void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type, S32 size) -{ -	char *vnamep = (char *)varname;  - -	// do we have a current message? -	if (!mCurrentSMessageTemplate) -	{ -		LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL; -		return; -	} - -	// do we have a current block? -	if (!mCurrentSDataBlock) -	{ -		LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL; -		return; -	} - -	// kewl, add the data if it exists -	const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep); -	if (!var_data || !var_data->getName()) -	{ -		LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL; -		return; -	} - -	// ok, it seems ok. . . are we the correct size? -	if (var_data->getType() == MVT_VARIABLE) -	{ -		// Variable 1 can only store 255 bytes, make sure our data is smaller -		if ((var_data->getSize() == 1) && -			(size > 255)) -		{ -			LL_WARNS() << "Field " << varname << " is a Variable 1 but program " -			       << "attempted to stuff more than 255 bytes in " -			       << "(" << size << ").  Clamping size and truncating data." << LL_ENDL; -			size = 255; -			char *truncate = (char *)data; -			truncate[254] = 0; // array size is 255 but the last element index is 254 -		} - -		// no correct size for MVT_VARIABLE, instead we need to tell how many bytes the size will be encoded as -		mCurrentSDataBlock->addData(vnamep, data, size, type, var_data->getSize()); -		mCurrentSendTotal += size; -	} -	else -	{ -		if (size != var_data->getSize()) -		{ -			LL_ERRS() << varname << " is type MVT_FIXED but request size " << size << " doesn't match template size " -				   << var_data->getSize() << LL_ENDL; -			return; -		} -		// alright, smash it in -		mCurrentSDataBlock->addData(vnamep, data, size, type); -		mCurrentSendTotal += size; -	} -} - -// add data to variable in current block - fails if variable isn't MVT_FIXED -void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type) -{ -	char *vnamep = (char *)varname;  - -	// do we have a current message? -	if (!mCurrentSMessageTemplate) -	{ -		LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL; -		return; -	} - -	// do we have a current block? -	if (!mCurrentSDataBlock) -	{ -		LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL; -		return; -	} - -	// kewl, add the data if it exists -	const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep); -	if (!var_data->getName()) -	{ -		LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL; -		return; -	} - -	// ok, it seems ok. . . are we MVT_VARIABLE? -	if (var_data->getType() == MVT_VARIABLE) -	{ -		// nope -		LL_ERRS() << vnamep << " is type MVT_VARIABLE. Call using addData(name, data, size)" << LL_ENDL; -		return; -	} -	else -	{ -		mCurrentSDataBlock->addData(vnamep, data, var_data->getSize(), type); -		mCurrentSendTotal += var_data->getSize(); -	} -} - -void LLTemplateMessageBuilder::addBinaryData(const char *varname,  -											const void *data, S32 size) -{ -	addData(varname, data, MVT_FIXED, size); -} - -void LLTemplateMessageBuilder::addS8(const char *varname, S8 s) -{ -	addData(varname, &s, MVT_S8, sizeof(s)); -} - -void LLTemplateMessageBuilder::addU8(const char *varname, U8 u) -{ -	addData(varname, &u, MVT_U8, sizeof(u)); -} - -void LLTemplateMessageBuilder::addS16(const char *varname, S16 i) -{ -	addData(varname, &i, MVT_S16, sizeof(i)); -} - -void LLTemplateMessageBuilder::addU16(const char *varname, U16 i) -{ -	addData(varname, &i, MVT_U16, sizeof(i)); -} - -void LLTemplateMessageBuilder::addF32(const char *varname, F32 f) -{ -	addData(varname, &f, MVT_F32, sizeof(f)); -} - -void LLTemplateMessageBuilder::addS32(const char *varname, S32 s) -{ -	addData(varname, &s, MVT_S32, sizeof(s)); -} - -void LLTemplateMessageBuilder::addU32(const char *varname, U32 u) -{ -	addData(varname, &u, MVT_U32, sizeof(u)); -} - -void LLTemplateMessageBuilder::addU64(const char *varname, U64 lu) -{ -	addData(varname, &lu, MVT_U64, sizeof(lu)); -} - -void LLTemplateMessageBuilder::addF64(const char *varname, F64 d) -{ -	addData(varname, &d, MVT_F64, sizeof(d)); -} - -void LLTemplateMessageBuilder::addIPAddr(const char *varname, U32 u) -{ -	addData(varname, &u, MVT_IP_ADDR, sizeof(u)); -} - -void LLTemplateMessageBuilder::addIPPort(const char *varname, U16 u) -{ -	u = htons(u); -	addData(varname, &u, MVT_IP_PORT, sizeof(u)); -} - -void LLTemplateMessageBuilder::addBOOL(const char* varname, bool b) -{ -	U8 temp = (b != 0); -	addData(varname, &temp, MVT_BOOL, sizeof(temp)); -} - -void LLTemplateMessageBuilder::addString(const char* varname, const char* s) -{ -	if (s) -		addData( varname, (void *)s, MVT_VARIABLE, (S32)strlen(s) + 1);  /* Flawfinder: ignore */   -	else -		addData( varname, NULL, MVT_VARIABLE, 0);  -} - -void LLTemplateMessageBuilder::addString(const char* varname, const std::string& s) -{ -	if (s.size()) -		addData( varname, (void *)s.c_str(), MVT_VARIABLE, (S32)(s.size()) + 1);  -	else -		addData( varname, NULL, MVT_VARIABLE, 0);  -} - -void LLTemplateMessageBuilder::addVector3(const char *varname, const LLVector3& vec) -{ -	addData(varname, vec.mV, MVT_LLVector3, sizeof(vec.mV)); -} - -void LLTemplateMessageBuilder::addVector4(const char *varname, const LLVector4& vec) -{ -	addData(varname, vec.mV, MVT_LLVector4, sizeof(vec.mV)); -} - -void LLTemplateMessageBuilder::addVector3d(const char *varname, const LLVector3d& vec) -{ -	addData(varname, vec.mdV, MVT_LLVector3d, sizeof(vec.mdV)); -} - -void LLTemplateMessageBuilder::addQuat(const char *varname, const LLQuaternion& quat) -{ -	addData(varname, quat.packToVector3().mV, MVT_LLQuaternion, sizeof(LLVector3)); -} - -void LLTemplateMessageBuilder::addUUID(const char *varname, const LLUUID& uuid) -{ -	addData(varname, uuid.mData, MVT_LLUUID, sizeof(uuid.mData)); -} - -static S32 zero_code(U8 **data, U32 *data_size) -{ -	// Encoded send buffer needs to be slightly larger since the zero -	// coding can potentially increase the size of the send data. -	static U8 encodedSendBuffer[2 * MAX_BUFFER_SIZE]; - -	S32 count = *data_size; -	 -	S32 net_gain = 0; -	U8 num_zeroes = 0; -	 -	U8 *inptr = (U8 *)*data; -	U8 *outptr = (U8 *)encodedSendBuffer; - -// skip the packet id field - -	for (U32 ii = 0; ii < LL_PACKET_ID_SIZE ; ++ii) -	{ -		count--; -		*outptr++ = *inptr++; -	} - -// build encoded packet, keeping track of net size gain - -// sequential zero bytes are encoded as 0 [U8 count]  -// with 0 0 [count] representing wrap (>256 zeroes) - -	while (count--) -	{ -		if (!(*inptr))   // in a zero count -		{ -			if (num_zeroes) -			{ -				if (++num_zeroes > 254) -				{ -					*outptr++ = num_zeroes; -					num_zeroes = 0; -				} -				net_gain--;   // subseqent zeroes save one -			} -			else -			{ -				*outptr++ = 0; -				net_gain++;  // starting a zero count adds one -				num_zeroes = 1; -			} -			inptr++; -		} -		else -		{ -			if (num_zeroes) -			{ -				*outptr++ = num_zeroes; -				num_zeroes = 0; -			} -			*outptr++ = *inptr++; -		} -	} - -	if (num_zeroes) -	{ -		*outptr++ = num_zeroes; -	} - -	if (net_gain < 0) -	{ -		// TODO: babbage: reinstate stat collecting... -		//mCompressedPacketsOut++; -		//mUncompressedBytesOut += *data_size; - -		*data = encodedSendBuffer; -		*data_size += net_gain; -		encodedSendBuffer[0] |= LL_ZERO_CODE_FLAG;          // set the head bit to indicate zero coding - -		//mCompressedBytesOut += *data_size; - -	} -	//mTotalBytesOut += *data_size; - -	return(net_gain); -} - -void LLTemplateMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length) -{ -	if(ME_ZEROCODED == mCurrentSMessageTemplate->getEncoding()) -	{ -		zero_code(&buf_ptr, &buffer_length); -	} -} - -bool LLTemplateMessageBuilder::isMessageFull(const char* blockname) const -{ -	if(mCurrentSendTotal > MTUBYTES) -	{ -		return true; -	} -	if(!blockname) -	{ -		return false; -	} -	char* bnamep = (char*)blockname; -	S32 max; - -	const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep); -	 -	switch(template_data->mType) -	{ -	case MBT_SINGLE: -		max = 1; -		break; -	case MBT_MULTIPLE: -		max = template_data->mNumber; -		break; -	case MBT_VARIABLE: -	default: -		max = MAX_BLOCKS; -		break; -	} -	if(mCurrentSMessageData->mMemberBlocks[bnamep]->mBlockNumber >= max) -	{ -		return true; -	} -	return false; -} - -static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* template_data, LLMsgData* message_data) -{ -	S32 result = 0; -	LLMsgData::msg_blk_data_map_t::const_iterator block_iter = message_data->mMemberBlocks.find(template_data->mName); -	const LLMsgBlkData* mbci = block_iter->second; -		 -	// ok, if this is the first block of a repeating pack, set -	// block_count and, if it's type MBT_VARIABLE encode a byte -	// for how many there are -	S32 block_count = mbci->mBlockNumber; -	if (template_data->mType == MBT_VARIABLE) -	{ -		// remember that mBlockNumber is a S32 -		U8 temp_block_number = (U8)mbci->mBlockNumber; -		if ((S32)(result + sizeof(U8)) < MAX_BUFFER_SIZE) -		{ -			memcpy(&buffer[result], &temp_block_number, sizeof(U8)); -			result += sizeof(U8); -		} -		else -		{ -			// Just reporting error is likely not enough. Need -			// to check how to abort or error out gracefully -			// from this function. XXXTBD -			LL_ERRS() << "buildBlock failed. Message excedding " -					<< "sendBuffersize." << LL_ENDL; -		} -	} -	else if (template_data->mType == MBT_MULTIPLE) -	{ -		if (block_count != template_data->mNumber) -		{ -			// nope!  need to fill it in all the way! -			LL_ERRS() << "Block " << mbci->mName -				<< " is type MBT_MULTIPLE but only has data for " -				<< block_count << " out of its " -				<< template_data->mNumber << " blocks" << LL_ENDL; -		} -	} - -	while(block_count > 0) -	{ -		// now loop through the variables -		for (LLMsgBlkData::msg_var_data_map_t::const_iterator iter = mbci->mMemberVarData.begin(); -			 iter != mbci->mMemberVarData.end(); iter++) -		{ -			const LLMsgVarData& mvci = *iter; -			if (mvci.getSize() == -1) -			{ -				// oops, this variable wasn't ever set! -				LL_ERRS() << "The variable " << mvci.getName() << " in block " -					<< mbci->mName << " of message " -					<< template_data->mName -					<< " wasn't set prior to buildMessage call" << LL_ENDL; -			} -			else -			{ -				S32 data_size = mvci.getDataSize(); -				if(data_size > 0) -				{ -					// The type is MVT_VARIABLE, which means that we -					// need to encode a size argument. Otherwise, -					// there is no need. -					S32 size = mvci.getSize(); -					U8 sizeb; -					U16 sizeh; -					switch(data_size) -					{ -					case 1: -						sizeb = size; -						htolememcpy(&buffer[result], &sizeb, MVT_U8, 1); -						break; -					case 2: -						sizeh = size; -						htolememcpy(&buffer[result], &sizeh, MVT_U16, 2); -						break; -					case 4: -						htolememcpy(&buffer[result], &size, MVT_S32, 4); -						break; -					default: -						LL_ERRS() << "Attempting to build variable field with unknown size of " << size << LL_ENDL; -						break; -					} -					result += mvci.getDataSize(); -				} - -				// if there is any data to pack, pack it -				if((mvci.getData() != NULL) && mvci.getSize()) -				{ -					if(result + mvci.getSize() < buffer_size) -					{ -					    memcpy( -							&buffer[result], -							mvci.getData(), -							mvci.getSize()); -					    result += mvci.getSize(); -					} -					else -					{ -					    // Just reporting error is likely not -					    // enough. Need to check how to abort or error -					    // out gracefully from this function. XXXTBD -						LL_ERRS() << "buildBlock failed. " -							<< "Attempted to pack " -							<< (result + mvci.getSize()) -							<< " bytes into a buffer with size " -							<< buffer_size << "." << LL_ENDL; -					}						 -				} -			} -		} - -		--block_count; -		 -		if (block_iter != message_data->mMemberBlocks.end()) -		{ -			++block_iter; -			if (block_iter != message_data->mMemberBlocks.end()) -			{ -				mbci = block_iter->second; -			} -		} -	} - -	return result; -} - - -// make sure that all the desired data is in place and then copy the data into MAX_BUFFER_SIZEd buffer -U32 LLTemplateMessageBuilder::buildMessage( -	U8* buffer, -	U32 buffer_size, -	U8 offset_to_data) -{ -	// basic algorithm is to loop through the various pieces, building -	// size and offset info if we encounter a -1 for mSize at any -	// point that variable wasn't given data - -	// do we have a current message? -	if (!mCurrentSMessageTemplate) -	{ -		LL_ERRS() << "newMessage not called prior to buildMessage" << LL_ENDL; -		return 0; -	} - -	// leave room for flags, packet sequence #, and data offset -	// information. -	buffer[PHL_OFFSET] = offset_to_data; -	U32 result = LL_PACKET_ID_SIZE; - -	// encode message number and adjust total_offset -	if (mCurrentSMessageTemplate->mFrequency == MFT_HIGH) -	{ -// old, endian-dependant way -//		memcpy(&buffer[result], &mCurrentMessageTemplate->mMessageNumber, sizeof(U8)); - -// new, independant way -		buffer[result] = (U8)mCurrentSMessageTemplate->mMessageNumber; -		result += sizeof(U8); -	} -	else if (mCurrentSMessageTemplate->mFrequency == MFT_MEDIUM) -	{ -		U8 temp = 255; -		memcpy(&buffer[result], &temp, sizeof(U8));  /*Flawfinder: ignore*/ -		result += sizeof(U8); - -		// mask off unsightly bits -		temp = mCurrentSMessageTemplate->mMessageNumber & 255; -		memcpy(&buffer[result], &temp, sizeof(U8));  /*Flawfinder: ignore*/ -		result += sizeof(U8); -	} -	else if (mCurrentSMessageTemplate->mFrequency == MFT_LOW) -	{ -		U8 temp = 255; -		U16  message_num; -		memcpy(&buffer[result], &temp, sizeof(U8));  /*Flawfinder: ignore*/ -		result += sizeof(U8); -		memcpy(&buffer[result], &temp, sizeof(U8));  /*Flawfinder: ignore*/ -		result += sizeof(U8); - -		// mask off unsightly bits -		message_num = mCurrentSMessageTemplate->mMessageNumber & 0xFFFF; - -	    // convert to network byte order -		message_num = htons(message_num); -		memcpy(&buffer[result], &message_num, sizeof(U16)); /*Flawfinder: ignore*/ -		result += sizeof(U16); -	} -	else -	{ -		LL_ERRS() << "unexpected message frequency in buildMessage" << LL_ENDL; -		return 0; -	} - -	// fast forward through the offset and build the message -	result += offset_to_data; -	for(LLMessageTemplate::message_block_map_t::const_iterator -			iter = mCurrentSMessageTemplate->mMemberBlocks.begin(), -			end = mCurrentSMessageTemplate->mMemberBlocks.end(); -		 iter != end; -		++iter) -	{ -		result += buildBlock(buffer + result, buffer_size - result, *iter, mCurrentSMessageData); -	} -	mbSBuilt = true; - -	return result; -} - -void LLTemplateMessageBuilder::copyFromMessageData(const LLMsgData& data) -{ -	// copy the blocks -	// counting variables used to encode multiple block info -	S32 block_count = 0; -    char *block_name = NULL; - -	// loop through msg blocks to loop through variables, totalling up size -	// data and filling the new (send) message -	LLMsgData::msg_blk_data_map_t::const_iterator iter =  -		data.mMemberBlocks.begin(); -	LLMsgData::msg_blk_data_map_t::const_iterator end =  -		data.mMemberBlocks.end(); -	for(; iter != end; ++iter) -	{ -		const LLMsgBlkData* mbci = iter->second; -		if(!mbci) continue; - -		// do we need to encode a block code? -		if (block_count == 0) -		{ -			block_count = mbci->mBlockNumber; -			block_name = (char *)mbci->mName; -		} - -		// counting down mutliple blocks -		block_count--; - -		nextBlock(block_name); - -		// now loop through the variables -		LLMsgBlkData::msg_var_data_map_t::const_iterator dit = mbci->mMemberVarData.begin(); -		LLMsgBlkData::msg_var_data_map_t::const_iterator dend = mbci->mMemberVarData.end(); -		 -		for(; dit != dend; ++dit) -		{ -			const LLMsgVarData& mvci = *dit; -			addData(mvci.getName(), mvci.getData(), mvci.getType(), mvci.getSize()); -		} -	} -} - -//virtual  -void LLTemplateMessageBuilder::copyFromLLSD(const LLSD&) -{ -	// TODO -} - -//virtual -void LLTemplateMessageBuilder::setBuilt(bool b) { mbSBuilt = b; } - -//virtual  -bool LLTemplateMessageBuilder::isBuilt() const {return mbSBuilt;} - -//virtual  -bool LLTemplateMessageBuilder::isClear() const {return mbSClear;} - -//virtual  -S32 LLTemplateMessageBuilder::getMessageSize() {return mCurrentSendTotal;} - -//virtual  -const char* LLTemplateMessageBuilder::getMessageName() const  -{ -	return mCurrentSMessageName; -} +/**
 + * @file lltemplatemessagebuilder.cpp
 + * @brief LLTemplateMessageBuilder class implementation.
 + *
 + * $LicenseInfo:firstyear=2007&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 "lltemplatemessagebuilder.h"
 +
 +#include "llmessagetemplate.h"
 +#include "llmath.h"
 +#include "llquaternion.h"
 +#include "u64.h"
 +#include "v3dmath.h"
 +#include "v3math.h"
 +#include "v4math.h"
 +
 +LLTemplateMessageBuilder::LLTemplateMessageBuilder(const message_template_name_map_t& name_template_map) :
 +    mCurrentSMessageData(NULL),
 +    mCurrentSMessageTemplate(NULL),
 +    mCurrentSDataBlock(NULL),
 +    mCurrentSMessageName(NULL),
 +    mCurrentSBlockName(NULL),
 +    mbSBuilt(false),
 +    mbSClear(true),
 +    mCurrentSendTotal(0),
 +    mMessageTemplates(name_template_map)
 +{
 +}
 +
 +//virtual
 +LLTemplateMessageBuilder::~LLTemplateMessageBuilder()
 +{
 +    delete mCurrentSMessageData;
 +    mCurrentSMessageData = NULL;
 +}
 +
 +// virtual
 +void LLTemplateMessageBuilder::newMessage(const char *name)
 +{
 +    mbSBuilt = false;
 +    mbSClear = false;
 +
 +    mCurrentSendTotal = 0;
 +
 +    delete mCurrentSMessageData;
 +    mCurrentSMessageData = NULL;
 +
 +    char* namep = (char*)name;
 +    if (mMessageTemplates.count(namep) > 0)
 +    {
 +        mCurrentSMessageTemplate = mMessageTemplates.find(name)->second;
 +        mCurrentSMessageData = new LLMsgData(namep);
 +        mCurrentSMessageName = namep;
 +        mCurrentSDataBlock = NULL;
 +        mCurrentSBlockName = NULL;
 +
 +        // add at one of each block
 +        const LLMessageTemplate* msg_template = mMessageTemplates.find(name)->second;
 +
 +        if (msg_template->getDeprecation() != MD_NOTDEPRECATED)
 +        {
 +            LL_WARNS() << "Sending deprecated message " << namep << LL_ENDL;
 +        }
 +
 +        LLMessageTemplate::message_block_map_t::const_iterator iter;
 +        for(iter = msg_template->mMemberBlocks.begin();
 +            iter != msg_template->mMemberBlocks.end();
 +            ++iter)
 +        {
 +            LLMessageBlock* ci = *iter;
 +            LLMsgBlkData* tblockp = new LLMsgBlkData(ci->mName, 0);
 +            mCurrentSMessageData->addBlock(tblockp);
 +        }
 +    }
 +    else
 +    {
 +        LL_ERRS() << "newMessage - Message " << name << " not registered" << LL_ENDL;
 +    }
 +}
 +
 +// virtual
 +void LLTemplateMessageBuilder::clearMessage()
 +{
 +    mbSBuilt = false;
 +    mbSClear = true;
 +
 +    mCurrentSendTotal = 0;
 +
 +    mCurrentSMessageTemplate = NULL;
 +
 +    delete mCurrentSMessageData;
 +    mCurrentSMessageData = NULL;
 +
 +    mCurrentSMessageName = NULL;
 +    mCurrentSDataBlock = NULL;
 +    mCurrentSBlockName = NULL;
 +}
 +
 +// virtual
 +void LLTemplateMessageBuilder::nextBlock(const char* blockname)
 +{
 +    char *bnamep = (char *)blockname;
 +
 +    if (!mCurrentSMessageTemplate)
 +    {
 +        LL_ERRS() << "newMessage not called prior to setBlock" << LL_ENDL;
 +        return;
 +    }
 +
 +    // now, does this block exist?
 +    const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep);
 +    if (!template_data)
 +    {
 +        LL_ERRS() << "LLTemplateMessageBuilder::nextBlock " << bnamep
 +            << " not a block in " << mCurrentSMessageTemplate->mName << LL_ENDL;
 +        return;
 +    }
 +
 +    // ok, have we already set this block?
 +    LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[bnamep];
 +    if (block_data->mBlockNumber == 0)
 +    {
 +        // nope! set this as the current block
 +        block_data->mBlockNumber = 1;
 +        mCurrentSDataBlock = block_data;
 +        mCurrentSBlockName = bnamep;
 +
 +        // add placeholders for each of the variables
 +        for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin();
 +             iter != template_data->mMemberVariables.end(); iter++)
 +        {
 +            LLMessageVariable& ci = **iter;
 +            mCurrentSDataBlock->addVariable(ci.getName(), ci.getType());
 +        }
 +        return;
 +    }
 +    else
 +    {
 +        // already have this block. . .
 +        // are we supposed to have a new one?
 +
 +        // if the block is type MBT_SINGLE this is bad!
 +        if (template_data->mType == MBT_SINGLE)
 +        {
 +            LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called multiple times"
 +                << " for " << bnamep << " but is type MBT_SINGLE" << LL_ENDL;
 +            return;
 +        }
 +
 +
 +        // if the block is type MBT_MULTIPLE then we need a known number,
 +        // make sure that we're not exceeding it
 +        if (  (template_data->mType == MBT_MULTIPLE)
 +            &&(mCurrentSDataBlock->mBlockNumber == template_data->mNumber))
 +        {
 +            LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called "
 +                << mCurrentSDataBlock->mBlockNumber << " times for " << bnamep
 +                << " exceeding " << template_data->mNumber
 +                << " specified in type MBT_MULTIPLE." << LL_ENDL;
 +            return;
 +        }
 +
 +        // ok, we can make a new one
 +        // modify the name to avoid name collision by adding number to end
 +        S32  count = block_data->mBlockNumber;
 +
 +        // incrememt base name's count
 +        block_data->mBlockNumber++;
 +
 +        if (block_data->mBlockNumber > MAX_BLOCKS)
 +        {
 +            LL_ERRS() << "Trying to pack too many blocks into MBT_VARIABLE type "
 +                   << "(limited to " << MAX_BLOCKS << ")" << LL_ENDL;
 +        }
 +
 +        // create new name
 +        // Nota Bene: if things are working correctly,
 +        // mCurrentMessageData->mMemberBlocks[blockname]->mBlockNumber ==
 +        // mCurrentDataBlock->mBlockNumber + 1
 +
 +        char *nbnamep = bnamep + count;
 +
 +        mCurrentSDataBlock = new LLMsgBlkData(bnamep, count);
 +        mCurrentSDataBlock->mName = nbnamep;
 +        mCurrentSMessageData->mMemberBlocks[nbnamep] = mCurrentSDataBlock;
 +
 +        // add placeholders for each of the variables
 +        for (LLMessageBlock::message_variable_map_t::const_iterator
 +                 iter = template_data->mMemberVariables.begin(),
 +                 end = template_data->mMemberVariables.end();
 +             iter != end; iter++)
 +        {
 +            LLMessageVariable& ci = **iter;
 +            mCurrentSDataBlock->addVariable(ci.getName(), ci.getType());
 +        }
 +        return;
 +    }
 +}
 +
 +// TODO: Remove this horror...
 +bool LLTemplateMessageBuilder::removeLastBlock()
 +{
 +    if (mCurrentSBlockName)
 +    {
 +        if (  (mCurrentSMessageData)
 +            &&(mCurrentSMessageTemplate))
 +        {
 +            if (mCurrentSMessageData->mMemberBlocks[mCurrentSBlockName]->mBlockNumber >= 1)
 +            {
 +                // At least one block for the current block name.
 +
 +                // Store the current block name for future reference.
 +                char *block_name = mCurrentSBlockName;
 +
 +                // Decrement the sent total by the size of the
 +                // data in the message block that we're currently building.
 +
 +                const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName);
 +
 +                for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin();
 +                     iter != template_data->mMemberVariables.end(); iter++)
 +                {
 +                    LLMessageVariable& ci = **iter;
 +                    mCurrentSendTotal -= ci.getSize();
 +                }
 +
 +
 +                // Now we want to find the block that we're blowing away.
 +
 +                // Get the number of blocks.
 +                LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[block_name];
 +                S32 num_blocks = block_data->mBlockNumber;
 +
 +                // Use the same (suspect?) algorithm that's used to generate
 +                // the names in the nextBlock method to find it.
 +                char *block_getting_whacked = block_name + num_blocks - 1;
 +                LLMsgBlkData* whacked_data = mCurrentSMessageData->mMemberBlocks[block_getting_whacked];
 +                delete whacked_data;
 +                mCurrentSMessageData->mMemberBlocks.erase(block_getting_whacked);
 +
 +                if (num_blocks <= 1)
 +                {
 +                    // we just blew away the last one, so return false
 +                    LL_WARNS() << "not blowing away the only block of message "
 +                            << mCurrentSMessageName
 +                            << ". Block: " << block_name
 +                            << ". Number: " << num_blocks
 +                            << LL_ENDL;
 +                    return false;
 +                }
 +                else
 +                {
 +                    // Decrement the counter.
 +                    block_data->mBlockNumber--;
 +                    return true;
 +                }
 +            }
 +        }
 +    }
 +    return false;
 +}
 +
 +// add data to variable in current block
 +void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type, S32 size)
 +{
 +    char *vnamep = (char *)varname;
 +
 +    // do we have a current message?
 +    if (!mCurrentSMessageTemplate)
 +    {
 +        LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL;
 +        return;
 +    }
 +
 +    // do we have a current block?
 +    if (!mCurrentSDataBlock)
 +    {
 +        LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL;
 +        return;
 +    }
 +
 +    // kewl, add the data if it exists
 +    const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep);
 +    if (!var_data || !var_data->getName())
 +    {
 +        LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL;
 +        return;
 +    }
 +
 +    // ok, it seems ok. . . are we the correct size?
 +    if (var_data->getType() == MVT_VARIABLE)
 +    {
 +        // Variable 1 can only store 255 bytes, make sure our data is smaller
 +        if ((var_data->getSize() == 1) &&
 +            (size > 255))
 +        {
 +            LL_WARNS() << "Field " << varname << " is a Variable 1 but program "
 +                   << "attempted to stuff more than 255 bytes in "
 +                   << "(" << size << ").  Clamping size and truncating data." << LL_ENDL;
 +            size = 255;
 +            char *truncate = (char *)data;
 +            truncate[254] = 0; // array size is 255 but the last element index is 254
 +        }
 +
 +        // no correct size for MVT_VARIABLE, instead we need to tell how many bytes the size will be encoded as
 +        mCurrentSDataBlock->addData(vnamep, data, size, type, var_data->getSize());
 +        mCurrentSendTotal += size;
 +    }
 +    else
 +    {
 +        if (size != var_data->getSize())
 +        {
 +            LL_ERRS() << varname << " is type MVT_FIXED but request size " << size << " doesn't match template size "
 +                   << var_data->getSize() << LL_ENDL;
 +            return;
 +        }
 +        // alright, smash it in
 +        mCurrentSDataBlock->addData(vnamep, data, size, type);
 +        mCurrentSendTotal += size;
 +    }
 +}
 +
 +// add data to variable in current block - fails if variable isn't MVT_FIXED
 +void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type)
 +{
 +    char *vnamep = (char *)varname;
 +
 +    // do we have a current message?
 +    if (!mCurrentSMessageTemplate)
 +    {
 +        LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL;
 +        return;
 +    }
 +
 +    // do we have a current block?
 +    if (!mCurrentSDataBlock)
 +    {
 +        LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL;
 +        return;
 +    }
 +
 +    // kewl, add the data if it exists
 +    const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep);
 +    if (!var_data->getName())
 +    {
 +        LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL;
 +        return;
 +    }
 +
 +    // ok, it seems ok. . . are we MVT_VARIABLE?
 +    if (var_data->getType() == MVT_VARIABLE)
 +    {
 +        // nope
 +        LL_ERRS() << vnamep << " is type MVT_VARIABLE. Call using addData(name, data, size)" << LL_ENDL;
 +        return;
 +    }
 +    else
 +    {
 +        mCurrentSDataBlock->addData(vnamep, data, var_data->getSize(), type);
 +        mCurrentSendTotal += var_data->getSize();
 +    }
 +}
 +
 +void LLTemplateMessageBuilder::addBinaryData(const char *varname,
 +                                            const void *data, S32 size)
 +{
 +    addData(varname, data, MVT_FIXED, size);
 +}
 +
 +void LLTemplateMessageBuilder::addS8(const char *varname, S8 s)
 +{
 +    addData(varname, &s, MVT_S8, sizeof(s));
 +}
 +
 +void LLTemplateMessageBuilder::addU8(const char *varname, U8 u)
 +{
 +    addData(varname, &u, MVT_U8, sizeof(u));
 +}
 +
 +void LLTemplateMessageBuilder::addS16(const char *varname, S16 i)
 +{
 +    addData(varname, &i, MVT_S16, sizeof(i));
 +}
 +
 +void LLTemplateMessageBuilder::addU16(const char *varname, U16 i)
 +{
 +    addData(varname, &i, MVT_U16, sizeof(i));
 +}
 +
 +void LLTemplateMessageBuilder::addF32(const char *varname, F32 f)
 +{
 +    addData(varname, &f, MVT_F32, sizeof(f));
 +}
 +
 +void LLTemplateMessageBuilder::addS32(const char *varname, S32 s)
 +{
 +    addData(varname, &s, MVT_S32, sizeof(s));
 +}
 +
 +void LLTemplateMessageBuilder::addU32(const char *varname, U32 u)
 +{
 +    addData(varname, &u, MVT_U32, sizeof(u));
 +}
 +
 +void LLTemplateMessageBuilder::addU64(const char *varname, U64 lu)
 +{
 +    addData(varname, &lu, MVT_U64, sizeof(lu));
 +}
 +
 +void LLTemplateMessageBuilder::addF64(const char *varname, F64 d)
 +{
 +    addData(varname, &d, MVT_F64, sizeof(d));
 +}
 +
 +void LLTemplateMessageBuilder::addIPAddr(const char *varname, U32 u)
 +{
 +    addData(varname, &u, MVT_IP_ADDR, sizeof(u));
 +}
 +
 +void LLTemplateMessageBuilder::addIPPort(const char *varname, U16 u)
 +{
 +    u = htons(u);
 +    addData(varname, &u, MVT_IP_PORT, sizeof(u));
 +}
 +
 +void LLTemplateMessageBuilder::addBOOL(const char* varname, bool b)
 +{
 +    U8 temp = (b != 0);
 +    addData(varname, &temp, MVT_BOOL, sizeof(temp));
 +}
 +
 +void LLTemplateMessageBuilder::addString(const char* varname, const char* s)
 +{
 +    if (s)
 +        addData( varname, (void *)s, MVT_VARIABLE, (S32)strlen(s) + 1);  /* Flawfinder: ignore */
 +    else
 +        addData( varname, NULL, MVT_VARIABLE, 0);
 +}
 +
 +void LLTemplateMessageBuilder::addString(const char* varname, const std::string& s)
 +{
 +    if (s.size())
 +        addData( varname, (void *)s.c_str(), MVT_VARIABLE, (S32)(s.size()) + 1);
 +    else
 +        addData( varname, NULL, MVT_VARIABLE, 0);
 +}
 +
 +void LLTemplateMessageBuilder::addVector3(const char *varname, const LLVector3& vec)
 +{
 +    addData(varname, vec.mV, MVT_LLVector3, sizeof(vec.mV));
 +}
 +
 +void LLTemplateMessageBuilder::addVector4(const char *varname, const LLVector4& vec)
 +{
 +    addData(varname, vec.mV, MVT_LLVector4, sizeof(vec.mV));
 +}
 +
 +void LLTemplateMessageBuilder::addVector3d(const char *varname, const LLVector3d& vec)
 +{
 +    addData(varname, vec.mdV, MVT_LLVector3d, sizeof(vec.mdV));
 +}
 +
 +void LLTemplateMessageBuilder::addQuat(const char *varname, const LLQuaternion& quat)
 +{
 +    addData(varname, quat.packToVector3().mV, MVT_LLQuaternion, sizeof(LLVector3));
 +}
 +
 +void LLTemplateMessageBuilder::addUUID(const char *varname, const LLUUID& uuid)
 +{
 +    addData(varname, uuid.mData, MVT_LLUUID, sizeof(uuid.mData));
 +}
 +
 +static S32 zero_code(U8 **data, U32 *data_size)
 +{
 +    // Encoded send buffer needs to be slightly larger since the zero
 +    // coding can potentially increase the size of the send data.
 +    static U8 encodedSendBuffer[2 * MAX_BUFFER_SIZE];
 +
 +    S32 count = *data_size;
 +
 +    S32 net_gain = 0;
 +    U8 num_zeroes = 0;
 +
 +    U8 *inptr = (U8 *)*data;
 +    U8 *outptr = (U8 *)encodedSendBuffer;
 +
 +// skip the packet id field
 +
 +    for (U32 ii = 0; ii < LL_PACKET_ID_SIZE ; ++ii)
 +    {
 +        count--;
 +        *outptr++ = *inptr++;
 +    }
 +
 +// build encoded packet, keeping track of net size gain
 +
 +// sequential zero bytes are encoded as 0 [U8 count]
 +// with 0 0 [count] representing wrap (>256 zeroes)
 +
 +    while (count--)
 +    {
 +        if (!(*inptr))   // in a zero count
 +        {
 +            if (num_zeroes)
 +            {
 +                if (++num_zeroes > 254)
 +                {
 +                    *outptr++ = num_zeroes;
 +                    num_zeroes = 0;
 +                }
 +                net_gain--;   // subseqent zeroes save one
 +            }
 +            else
 +            {
 +                *outptr++ = 0;
 +                net_gain++;  // starting a zero count adds one
 +                num_zeroes = 1;
 +            }
 +            inptr++;
 +        }
 +        else
 +        {
 +            if (num_zeroes)
 +            {
 +                *outptr++ = num_zeroes;
 +                num_zeroes = 0;
 +            }
 +            *outptr++ = *inptr++;
 +        }
 +    }
 +
 +    if (num_zeroes)
 +    {
 +        *outptr++ = num_zeroes;
 +    }
 +
 +    if (net_gain < 0)
 +    {
 +        // TODO: babbage: reinstate stat collecting...
 +        //mCompressedPacketsOut++;
 +        //mUncompressedBytesOut += *data_size;
 +
 +        *data = encodedSendBuffer;
 +        *data_size += net_gain;
 +        encodedSendBuffer[0] |= LL_ZERO_CODE_FLAG;          // set the head bit to indicate zero coding
 +
 +        //mCompressedBytesOut += *data_size;
 +
 +    }
 +    //mTotalBytesOut += *data_size;
 +
 +    return(net_gain);
 +}
 +
 +void LLTemplateMessageBuilder::compressMessage(U8*& buf_ptr, U32& buffer_length)
 +{
 +    if(ME_ZEROCODED == mCurrentSMessageTemplate->getEncoding())
 +    {
 +        zero_code(&buf_ptr, &buffer_length);
 +    }
 +}
 +
 +bool LLTemplateMessageBuilder::isMessageFull(const char* blockname) const
 +{
 +    if(mCurrentSendTotal > MTUBYTES)
 +    {
 +        return true;
 +    }
 +    if(!blockname)
 +    {
 +        return false;
 +    }
 +    char* bnamep = (char*)blockname;
 +    S32 max;
 +
 +    const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep);
 +
 +    switch(template_data->mType)
 +    {
 +    case MBT_SINGLE:
 +        max = 1;
 +        break;
 +    case MBT_MULTIPLE:
 +        max = template_data->mNumber;
 +        break;
 +    case MBT_VARIABLE:
 +    default:
 +        max = MAX_BLOCKS;
 +        break;
 +    }
 +    if(mCurrentSMessageData->mMemberBlocks[bnamep]->mBlockNumber >= max)
 +    {
 +        return true;
 +    }
 +    return false;
 +}
 +
 +static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* template_data, LLMsgData* message_data)
 +{
 +    S32 result = 0;
 +    LLMsgData::msg_blk_data_map_t::const_iterator block_iter = message_data->mMemberBlocks.find(template_data->mName);
 +    const LLMsgBlkData* mbci = block_iter->second;
 +
 +    // ok, if this is the first block of a repeating pack, set
 +    // block_count and, if it's type MBT_VARIABLE encode a byte
 +    // for how many there are
 +    S32 block_count = mbci->mBlockNumber;
 +    if (template_data->mType == MBT_VARIABLE)
 +    {
 +        // remember that mBlockNumber is a S32
 +        U8 temp_block_number = (U8)mbci->mBlockNumber;
 +        if ((S32)(result + sizeof(U8)) < MAX_BUFFER_SIZE)
 +        {
 +            memcpy(&buffer[result], &temp_block_number, sizeof(U8));
 +            result += sizeof(U8);
 +        }
 +        else
 +        {
 +            // Just reporting error is likely not enough. Need
 +            // to check how to abort or error out gracefully
 +            // from this function. XXXTBD
 +            LL_ERRS() << "buildBlock failed. Message excedding "
 +                    << "sendBuffersize." << LL_ENDL;
 +        }
 +    }
 +    else if (template_data->mType == MBT_MULTIPLE)
 +    {
 +        if (block_count != template_data->mNumber)
 +        {
 +            // nope!  need to fill it in all the way!
 +            LL_ERRS() << "Block " << mbci->mName
 +                << " is type MBT_MULTIPLE but only has data for "
 +                << block_count << " out of its "
 +                << template_data->mNumber << " blocks" << LL_ENDL;
 +        }
 +    }
 +
 +    while(block_count > 0)
 +    {
 +        // now loop through the variables
 +        for (LLMsgBlkData::msg_var_data_map_t::const_iterator iter = mbci->mMemberVarData.begin();
 +             iter != mbci->mMemberVarData.end(); iter++)
 +        {
 +            const LLMsgVarData& mvci = *iter;
 +            if (mvci.getSize() == -1)
 +            {
 +                // oops, this variable wasn't ever set!
 +                LL_ERRS() << "The variable " << mvci.getName() << " in block "
 +                    << mbci->mName << " of message "
 +                    << template_data->mName
 +                    << " wasn't set prior to buildMessage call" << LL_ENDL;
 +            }
 +            else
 +            {
 +                S32 data_size = mvci.getDataSize();
 +                if(data_size > 0)
 +                {
 +                    // The type is MVT_VARIABLE, which means that we
 +                    // need to encode a size argument. Otherwise,
 +                    // there is no need.
 +                    S32 size = mvci.getSize();
 +                    U8 sizeb;
 +                    U16 sizeh;
 +                    switch(data_size)
 +                    {
 +                    case 1:
 +                        sizeb = size;
 +                        htolememcpy(&buffer[result], &sizeb, MVT_U8, 1);
 +                        break;
 +                    case 2:
 +                        sizeh = size;
 +                        htolememcpy(&buffer[result], &sizeh, MVT_U16, 2);
 +                        break;
 +                    case 4:
 +                        htolememcpy(&buffer[result], &size, MVT_S32, 4);
 +                        break;
 +                    default:
 +                        LL_ERRS() << "Attempting to build variable field with unknown size of " << size << LL_ENDL;
 +                        break;
 +                    }
 +                    result += mvci.getDataSize();
 +                }
 +
 +                // if there is any data to pack, pack it
 +                if((mvci.getData() != NULL) && mvci.getSize())
 +                {
 +                    if(result + mvci.getSize() < buffer_size)
 +                    {
 +                        memcpy(
 +                            &buffer[result],
 +                            mvci.getData(),
 +                            mvci.getSize());
 +                        result += mvci.getSize();
 +                    }
 +                    else
 +                    {
 +                        // Just reporting error is likely not
 +                        // enough. Need to check how to abort or error
 +                        // out gracefully from this function. XXXTBD
 +                        LL_ERRS() << "buildBlock failed. "
 +                            << "Attempted to pack "
 +                            << (result + mvci.getSize())
 +                            << " bytes into a buffer with size "
 +                            << buffer_size << "." << LL_ENDL;
 +                    }
 +                }
 +            }
 +        }
 +
 +        --block_count;
 +
 +        if (block_iter != message_data->mMemberBlocks.end())
 +        {
 +            ++block_iter;
 +            if (block_iter != message_data->mMemberBlocks.end())
 +            {
 +                mbci = block_iter->second;
 +            }
 +        }
 +    }
 +
 +    return result;
 +}
 +
 +
 +// make sure that all the desired data is in place and then copy the data into MAX_BUFFER_SIZEd buffer
 +U32 LLTemplateMessageBuilder::buildMessage(
 +    U8* buffer,
 +    U32 buffer_size,
 +    U8 offset_to_data)
 +{
 +    // basic algorithm is to loop through the various pieces, building
 +    // size and offset info if we encounter a -1 for mSize at any
 +    // point that variable wasn't given data
 +
 +    // do we have a current message?
 +    if (!mCurrentSMessageTemplate)
 +    {
 +        LL_ERRS() << "newMessage not called prior to buildMessage" << LL_ENDL;
 +        return 0;
 +    }
 +
 +    // leave room for flags, packet sequence #, and data offset
 +    // information.
 +    buffer[PHL_OFFSET] = offset_to_data;
 +    U32 result = LL_PACKET_ID_SIZE;
 +
 +    // encode message number and adjust total_offset
 +    if (mCurrentSMessageTemplate->mFrequency == MFT_HIGH)
 +    {
 +// old, endian-dependant way
 +//      memcpy(&buffer[result], &mCurrentMessageTemplate->mMessageNumber, sizeof(U8));
 +
 +// new, independant way
 +        buffer[result] = (U8)mCurrentSMessageTemplate->mMessageNumber;
 +        result += sizeof(U8);
 +    }
 +    else if (mCurrentSMessageTemplate->mFrequency == MFT_MEDIUM)
 +    {
 +        U8 temp = 255;
 +        memcpy(&buffer[result], &temp, sizeof(U8));  /*Flawfinder: ignore*/
 +        result += sizeof(U8);
 +
 +        // mask off unsightly bits
 +        temp = mCurrentSMessageTemplate->mMessageNumber & 255;
 +        memcpy(&buffer[result], &temp, sizeof(U8));  /*Flawfinder: ignore*/
 +        result += sizeof(U8);
 +    }
 +    else if (mCurrentSMessageTemplate->mFrequency == MFT_LOW)
 +    {
 +        U8 temp = 255;
 +        U16  message_num;
 +        memcpy(&buffer[result], &temp, sizeof(U8));  /*Flawfinder: ignore*/
 +        result += sizeof(U8);
 +        memcpy(&buffer[result], &temp, sizeof(U8));  /*Flawfinder: ignore*/
 +        result += sizeof(U8);
 +
 +        // mask off unsightly bits
 +        message_num = mCurrentSMessageTemplate->mMessageNumber & 0xFFFF;
 +
 +        // convert to network byte order
 +        message_num = htons(message_num);
 +        memcpy(&buffer[result], &message_num, sizeof(U16)); /*Flawfinder: ignore*/
 +        result += sizeof(U16);
 +    }
 +    else
 +    {
 +        LL_ERRS() << "unexpected message frequency in buildMessage" << LL_ENDL;
 +        return 0;
 +    }
 +
 +    // fast forward through the offset and build the message
 +    result += offset_to_data;
 +    for(LLMessageTemplate::message_block_map_t::const_iterator
 +            iter = mCurrentSMessageTemplate->mMemberBlocks.begin(),
 +            end = mCurrentSMessageTemplate->mMemberBlocks.end();
 +         iter != end;
 +        ++iter)
 +    {
 +        result += buildBlock(buffer + result, buffer_size - result, *iter, mCurrentSMessageData);
 +    }
 +    mbSBuilt = true;
 +
 +    return result;
 +}
 +
 +void LLTemplateMessageBuilder::copyFromMessageData(const LLMsgData& data)
 +{
 +    // copy the blocks
 +    // counting variables used to encode multiple block info
 +    S32 block_count = 0;
 +    char *block_name = NULL;
 +
 +    // loop through msg blocks to loop through variables, totalling up size
 +    // data and filling the new (send) message
 +    LLMsgData::msg_blk_data_map_t::const_iterator iter =
 +        data.mMemberBlocks.begin();
 +    LLMsgData::msg_blk_data_map_t::const_iterator end =
 +        data.mMemberBlocks.end();
 +    for(; iter != end; ++iter)
 +    {
 +        const LLMsgBlkData* mbci = iter->second;
 +        if(!mbci) continue;
 +
 +        // do we need to encode a block code?
 +        if (block_count == 0)
 +        {
 +            block_count = mbci->mBlockNumber;
 +            block_name = (char *)mbci->mName;
 +        }
 +
 +        // counting down mutliple blocks
 +        block_count--;
 +
 +        nextBlock(block_name);
 +
 +        // now loop through the variables
 +        LLMsgBlkData::msg_var_data_map_t::const_iterator dit = mbci->mMemberVarData.begin();
 +        LLMsgBlkData::msg_var_data_map_t::const_iterator dend = mbci->mMemberVarData.end();
 +
 +        for(; dit != dend; ++dit)
 +        {
 +            const LLMsgVarData& mvci = *dit;
 +            addData(mvci.getName(), mvci.getData(), mvci.getType(), mvci.getSize());
 +        }
 +    }
 +}
 +
 +//virtual
 +void LLTemplateMessageBuilder::copyFromLLSD(const LLSD&)
 +{
 +    // TODO
 +}
 +
 +//virtual
 +void LLTemplateMessageBuilder::setBuilt(bool b) { mbSBuilt = b; }
 +
 +//virtual
 +bool LLTemplateMessageBuilder::isBuilt() const {return mbSBuilt;}
 +
 +//virtual
 +bool LLTemplateMessageBuilder::isClear() const {return mbSClear;}
 +
 +//virtual
 +S32 LLTemplateMessageBuilder::getMessageSize() {return mCurrentSendTotal;}
 +
 +//virtual
 +const char* LLTemplateMessageBuilder::getMessageName() const
 +{
 +    return mCurrentSMessageName;
 +}
  | 
