diff options
Diffstat (limited to 'indra/llmessage/lltemplatemessagebuilder.cpp')
-rw-r--r-- | indra/llmessage/lltemplatemessagebuilder.cpp | 1788 |
1 files changed, 893 insertions, 895 deletions
diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index be5dcadb28..57ffba9705 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -1,895 +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) -{ - // Can't just cast a BOOL (actually a U32) to a U8. - // In some cases the low order bits will be zero. - 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;
+}
|