void LLTemplateMessageBuilderTestObject::test<17>()
		 // IPPort
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_IP_PORT, 2));
		U16 outValue, inValue = 80;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addIPPort(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getIPPort(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure IPPort", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<14>()
		 // Quaternion
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_LLQuaternion, 12));
		LLQuaternion outValue, inValue = LLQuaternion(1,2,3,0);
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addQuat(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getQuat(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure LLQuaternion", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<10>()
		 // F64
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_F64, 8));
		F64 outValue, inValue = 3232143.33;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addF64(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getF64(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure F64", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<13>()
		 // Vector3d
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_LLVector3d, 24));
		LLVector3d outValue, inValue = LLVector3d(1,2,3);
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addVector3d(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getVector3d(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure LLVector3d", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<8>()
		 // U32
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_U32, 4));
		U32 outValue, inValue = 88;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addU32(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure U32", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<5>()
		 // U16
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_U16, 2));
		U16 outValue, inValue = 3;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addU16(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getU16(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure U16", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<2>()
		 // BOOL
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_BOOL, 1));
		BOOL outValue, inValue = TRUE;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addBOOL(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getBOOL(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure BOOL", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<16>()
		 // IPAddr
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_IP_ADDR, 4));
		U32 outValue, inValue = 12344556;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addIPAddr(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getIPAddr(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure IPAddr", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<28>()
		 // non-zero offset with S16
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_S16, 2));
		S16 outValue, inValue = 90;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addS16(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(
			messageTemplate, builder, 2);
		reader->getS16(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure S16", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<31>()
		 // non-zero offset with F32
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_F32, 4));
		F32 outValue, inValue = 121.44f;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addF32(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(
			messageTemplate, builder, 16);
		reader->getF32(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure F32", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<33>()
		 // non-zero offset with U64
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_U64, 8));
		U64 outValue, inValue = 121;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addU64(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(
			messageTemplate, builder, 32);
		reader->getU64(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure U64", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<15>()
		 // UUID
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_LLUUID, 16));
		LLUUID outValue, inValue;
		inValue.generate();
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addUUID(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getUUID(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure UUID", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<36>()
		 // non-zero offset with Vector4
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_LLVector4, 16));
		LLVector4 outValue, inValue = LLVector4(1,2,3,4);
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addVector4(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(
			messageTemplate, builder, 64);
		reader->getVector4(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure LLVector4", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<27>()
		 // non-zero offset with U8
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_U8, 1));
		U8 outValue, inValue = 2;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addU8(_PREHASH_Test0, inValue);
		LLTemplateMessageReader* reader = setReader(
			messageTemplate, builder, 255);
		reader->getU8(_PREHASH_Test0, _PREHASH_Test0, outValue);
		ensure_equals("Ensure U8", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<18>()
		// String
	{
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_VARIABLE, 1));
		std::string outValue, inValue = "testing";
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addString(_PREHASH_Test0, inValue.c_str());
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		char buffer[MAX_STRING];
		reader->getString(_PREHASH_Test0, _PREHASH_Test0, MAX_STRING, buffer);
		outValue = buffer;
		ensure_equals("Ensure String", inValue, outValue);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<23>()
		// variable repeated block name never accessed
	{
		U32 inTest = 1, outTest;
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(
			createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE));
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4));

		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addU32(_PREHASH_Test0, inTest);

		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outTest);
		S32 blockCount = reader->getNumberOfBlocks(const_cast<char*>(_PREHASH_Test1));
		ensure_equals("Ensure block count", blockCount, 0);
		ensure_equals("Ensure Test0", inTest, outTest);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<19>()
		// block name !-> binary order
	{
		U8 buffer1[MAX_BUFFER_SIZE];
		memset(buffer1, 0, MAX_BUFFER_SIZE);
		U8 buffer2[MAX_BUFFER_SIZE];
		memset(buffer2, 0, MAX_BUFFER_SIZE);
		U32 bufferSize1, bufferSize2;

		// build template: Test0 before Test1
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE));
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE));

		// build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0));
		builder->addU32(_PREHASH_Test0, 0xaaaa);
		builder->nextBlock(_PREHASH_Test1);
		builder->addU32(_PREHASH_Test0, 0xbbbb);
		bufferSize1 = builder->buildMessage(buffer1, MAX_BUFFER_SIZE, 0);
		delete builder;

		// build template: Test1 before Test0
		messageTemplate = defaultTemplate();
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE));
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE));

		// build message: 1st declared block var == 0xaaaa, 2nd declared block var == 0xbbbb
		builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test1));
		builder->addU32(_PREHASH_Test0, 0xaaaa);
		builder->nextBlock(_PREHASH_Test0);
		builder->addU32(_PREHASH_Test0, 0xbbbb);
		bufferSize2 = builder->buildMessage(buffer2, MAX_BUFFER_SIZE, 0);
		delete builder;

		ensure_equals("Ensure Buffer Sizes Equal", bufferSize1, bufferSize2);
		ensure_equals("Ensure Buffer Contents Equal", memcmp(buffer1, buffer2, bufferSize1), 0);
	}
	void LLTemplateMessageBuilderTestObject::test<22>()
		// repeated penultimate block (crashes when data in LLDynamicArrayIndexed)
	{
		U32 inTest00 = 0, inTest01 = 1, inTest1 = 2;
		U32 outTest00, outTest01, outTest1;
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4));
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4));
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addU32(_PREHASH_Test0, inTest00);
		builder->nextBlock(_PREHASH_Test0);
		builder->addU32(_PREHASH_Test0, inTest01);
		builder->nextBlock(_PREHASH_Test1);
		builder->addU32(_PREHASH_Test0, inTest1);
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);
		reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outTest00, 0);
		reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outTest01, 1);
		reader->getU32(_PREHASH_Test1, _PREHASH_Test0, outTest1);
		ensure_equals("Ensure Test0[0]", inTest00, outTest00);
		ensure_equals("Ensure Test0[1]", inTest01, outTest01);
		ensure_equals("Ensure Test1", inTest1, outTest1);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<45>()
		// read variable length data past end of message -> 0 length
	{
		// build message with single block
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(defaultBlock(MVT_U32, 4, MBT_SINGLE));
		U32 outValue, outValue2, inValue = 0xbbbbbbbb;
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addU32(_PREHASH_Test0, inValue);
		const U32 bufferSize = 1024;
		U8 buffer[bufferSize];
		memset(buffer, 0xaa, bufferSize);
		memset(buffer, 0, LL_PACKET_ID_SIZE);
		U32 builtSize = builder->buildMessage(buffer, bufferSize, 0);
		delete builder;

		// add variable block to reader template
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_VARIABLE, 4,
											 MBT_SINGLE));

		// read message value and default string
		numberMap[1] = &messageTemplate;
		LLTemplateMessageReader* reader = 
			new LLTemplateMessageReader(numberMap);
		reader->validateMessage(buffer, builtSize, LLHost());
		reader->readMessage(buffer, LLHost());
		reader->getU32(_PREHASH_Test0, _PREHASH_Test0, outValue);
		char outBuffer[bufferSize];
		memset(buffer, 0xcc, bufferSize);
		reader->getString(_PREHASH_Test1, _PREHASH_Test0, bufferSize, 
						  outBuffer);
		outValue2 = reader->getNumberOfBlocks(_PREHASH_Test1);
		ensure_equals("Ensure present value ", outValue, inValue);
		ensure_equals("Ensure unchanged buffer ", strlen(outBuffer), 0);
		delete reader;
	}
	void LLTemplateMessageBuilderTestObject::test<21>()
		// block appended in declaration -> data appended in binary
	{
		U8 buffer1[MAX_BUFFER_SIZE];
		memset(buffer1, 0, MAX_BUFFER_SIZE);
		U8 buffer2[MAX_BUFFER_SIZE];
		memset(buffer2, 0, MAX_BUFFER_SIZE);
		U32 bufferSize1, bufferSize2;

		// Build template: Test0 only
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE));

		// Build message
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0));
		builder->addU32(_PREHASH_Test0, 0xaaaa);
		bufferSize1 = builder->buildMessage(buffer1, MAX_BUFFER_SIZE, 0);
		delete builder;

		// Build template: Test0 before Test1
		messageTemplate = defaultTemplate();
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4, MBT_SINGLE));
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test1), MVT_U32, 4, MBT_SINGLE));

		// Build message
		builder = defaultBuilder(messageTemplate, const_cast<char*>(_PREHASH_Test0));
		builder->addU32(_PREHASH_Test0, 0xaaaa);
		builder->nextBlock(_PREHASH_Test1);
		builder->addU32(_PREHASH_Test0, 0xbbbb);
		bufferSize2 = builder->buildMessage(buffer2, MAX_BUFFER_SIZE, 0);
		delete builder;

		ensure_not_equals("Ensure Buffer Sizes Not Equal", bufferSize1, bufferSize2);
		ensure_equals("Ensure Buffer Prefix Equal", memcmp(buffer1, buffer2, bufferSize1), 0);
		ensure_not_equals("Ensure Buffer Contents Not Equal", memcmp(buffer1, buffer2, bufferSize2), 0);
	}
	void LLTemplateMessageBuilderTestObject::test<24>()
		// forwarding message
	{
		// build template
		LLMessageTemplate messageTemplate = defaultTemplate();
		messageTemplate.addBlock(createBlock(const_cast<char*>(_PREHASH_Test0), MVT_U32, 4));

		// build message
		LLTemplateMessageBuilder* builder = defaultBuilder(messageTemplate);
		builder->addU32(_PREHASH_Test0, 42);

		// read message
		LLTemplateMessageReader* reader = setReader(messageTemplate, builder);

		// forward message
		builder = defaultBuilder(messageTemplate);
		builder->newMessage(_PREHASH_TestMessage);
		reader->copyToBuilder(*builder);
		U8 buffer[MAX_BUFFER_SIZE];
		builder->buildMessage(buffer, MAX_BUFFER_SIZE, 0);

		delete builder;
		delete reader;
	}
// static
LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens)
{
	LLMessageTemplate	*templatep = NULL;
	if(!tokens.want("{"))
	{
		return NULL;
	}

	// name first
	std::string template_name = tokens.next();
	
	// is name a legit C variable name
	if (!b_variable_ok(template_name.c_str()))
	{
		llerrs << "Not legit variable name: " << template_name << " at " << tokens.line() << llendl;
	}

	// ok, now get Frequency ("High", "Medium", or "Low")
	EMsgFrequency frequency = MFT_LOW;
	std::string freq_string = tokens.next();
	if (freq_string == "High")
	{
		frequency = MFT_HIGH;
	}
	else if (freq_string == "Medium")
	{
		frequency = MFT_MEDIUM;
	}
	else if (freq_string == "Low" || freq_string == "Fixed")
	{
		frequency = MFT_LOW;
	}
	else
	{
		llerrs << "Expected frequency, got " << freq_string << " at " << tokens.line() << llendl;
	}

	// TODO more explicit checking here pls
	U32 message_number = strtoul(tokens.next().c_str(),NULL,0);

	switch (frequency) {
	case MFT_HIGH:
		break;
	case MFT_MEDIUM:
		message_number = (255 << 8) | message_number;
		break;
	case MFT_LOW:
		message_number = (255 << 24) | (255 << 16) | message_number;
		break;
	default:
		llerrs << "Unknown frequency enum: " << frequency << llendl;
	}
   
	templatep = new LLMessageTemplate(
		template_name.c_str(),
		message_number,
		frequency);
		
	// Now get trust ("Trusted", "NotTrusted")
	std::string trust = tokens.next();
	if (trust == "Trusted")
	{
		templatep->setTrust(MT_TRUST);
	}
	else if (trust == "NotTrusted")
	{
		templatep->setTrust(MT_NOTRUST);
	}
	else
	{
		llerrs << "Bad trust " << trust << " at " << tokens.line() << llendl;
	}
	
	// get encoding
	std::string encoding = tokens.next();
	if(encoding == "Unencoded")
	{
		templatep->setEncoding(ME_UNENCODED);
	}
	else if(encoding == "Zerocoded")
	{
		templatep->setEncoding(ME_ZEROCODED);
	}
	else
	{
		llerrs << "Bad encoding " << encoding << " at " << tokens.line() << llendl;
	}

	// get deprecation
	if(tokens.want("Deprecated"))
	{
		templatep->setDeprecation(MD_DEPRECATED);
	}
	else if (tokens.want("UDPDeprecated"))
	{
		templatep->setDeprecation(MD_UDPDEPRECATED);
	}
	else if (tokens.want("UDPBlackListed"))
	{
		templatep->setDeprecation(MD_UDPBLACKLISTED);
	}	
	else if (tokens.want("NotDeprecated"))
	{
		// this is the default value, but it can't hurt to set it twice
		templatep->setDeprecation(MD_NOTDEPRECATED);
	}
	else {
		// It's probably a brace, let's just start block processing
	}

	while(LLMessageBlock * blockp = parseBlock(tokens))
	{
		templatep->addBlock(blockp);
	}
	
	if(!tokens.want("}"))
	{
		llerrs << "Expecting closing } for message " << template_name
			   << " at " << tokens.line() << llendl;
	}
	return templatep;
}