TLV格式解析與打包

TLV,簡單理解就是type,length,value。是一種結構化的數據。一般type爲4個字節的枚舉,length爲4個字節,表示value的長度。value即爲實際的值。TLV直接可以嵌套,比如大的TLV中的value又是一個TLV。下面有個小例子幫助理解。

#include <stdio.h>  
#include <string>  

#ifdef _WIN32
#include <WinSock2.h>  
#pragma comment(lib, "WS2_32")  
#endif //_WIN32

enum emTLVNodeType
{
	emTlvNNone = 0,
	emTlvNRoot,         
	emTlvName,          
	emTlvAge,           
	emTlvColor           
};


typedef struct _CAT_INFO
{
	char szName[12];
	int iAge;
	int iColor;
}CAT_INFO, *LPCAT_INFO;

class CTlvPacket
{
public:
	CTlvPacket(char *pBuf, unsigned int len) :m_pData(pBuf), m_uiLength(len), m_pEndData(m_pData + len), m_pWritePtr(m_pData), m_pReadPtr(m_pData) { }
	~CTlvPacket() { }

	bool WriteInt(int data, bool bMovePtr = true)
	{
		int tmp = htonl(data);
		return Write(&tmp, sizeof(int));
	}

	bool Write(const void *pDst, unsigned int uiCount)
	{
		::memcpy(m_pWritePtr, pDst, uiCount);
		m_pWritePtr += uiCount;
		return m_pWritePtr < m_pEndData ? true : false;
	}

	bool ReadInt(int *data, bool bMovePtr = true)
	{
		Read(data, sizeof(int));
		*data = ntohl(*data);
		return true;
	}

	bool Read(void *pDst, unsigned int uiCount)
	{
		::memcpy(pDst, m_pReadPtr, uiCount);
		m_pReadPtr += uiCount;
		return m_pReadPtr < m_pEndData ? true : false;
	}

private:
	char *m_pData;
	unsigned int m_uiLength;
	char *m_pEndData;
	char *m_pWritePtr;
	char *m_pReadPtr;
};

/*

**格式:**
root L1 V
T L V T L V T L V

L1 的長度即爲“T L V T L V T L V”的長度

*/

int TLV_EncodeCat(LPCAT_INFO pCatInfo, char *pBuf, int &iLen)
{
	if (!pCatInfo || !pBuf)
	{
		return -1;
	}

	CTlvPacket enc(pBuf, iLen);
	enc.WriteInt(emTlvNRoot);
	enc.WriteInt(20 + 12 + 12); 

	//T 佔4個字節 ,L佔4個字節,V佔12個字節,第一個子TLV佔20個字節
	enc.WriteInt(emTlvName);
	enc.WriteInt(sizeof(pCatInfo->szName));
	enc.Write(pCatInfo->szName, sizeof(pCatInfo->szName));

	enc.WriteInt(emTlvAge);
	enc.WriteInt(4);
	enc.WriteInt(pCatInfo->iAge);

	enc.WriteInt(emTlvColor);
	enc.WriteInt(4);
	enc.WriteInt(pCatInfo->iColor);

	iLen = 8 + 20 + 12 + 12;

	return 0;
}

int TLV_DecodeCat(char *pBuf, int iLen, LPCAT_INFO pCatInfo)
{
	if (!pCatInfo || !pBuf)
	{
		return -1;
	}

	CTlvPacket encDec(pBuf, iLen);
	int iType;
	int iSum, iLength;

	encDec.ReadInt(&iType);
	if (emTlvNRoot != iType)
	{
		return -2;
	}
	encDec.ReadInt(&iSum);

	while (iSum > 0)
	{
		encDec.ReadInt(&iType);
		encDec.ReadInt(&iLength);
		switch (iType)
		{
		case emTlvName:
			//encDec.Read(pCatInfo->szName, 12);
			encDec.Read(pCatInfo->szName, iLength);
			iSum -= iLength + sizeof(int) + sizeof(int);
			break;
		case emTlvAge:
			encDec.ReadInt(&pCatInfo->iAge);
			iSum -= 12;
			break;
		case emTlvColor:
			encDec.ReadInt(&pCatInfo->iColor);
			iSum -= 12;
			break;
		default:
			printf("TLV_DecodeCat unkonwn error. \n");
			break;
		}
	}

	return 0;
}

int main(int argc, char* argv[])
{

	int iRet, iLen;
	char buf[256] = { 0 };

	CAT_INFO cat;
	memset(&cat, 0, sizeof(cat));
	strcpy(cat.szName, "Tom");
	cat.iAge = 5;
	cat.iColor = 2;

	iRet = TLV_EncodeCat(&cat, buf, iLen);
	if (0 == iRet)
	{
		printf("TLV_EncodeCat ok, iLen = %d. \n", iLen);
	}
	else
	{
		printf("TLV_EncodeCat error \n");
	}

	memset(&cat, 0, sizeof(cat));
	iRet = TLV_DecodeCat(buf, iLen, &cat);
	if (0 == iRet)
	{
		printf("TLV_DecodeCat ok, cat name = %s, age = %d, color = %d. \n", cat.szName, cat.iAge, cat.iColor);
	}
	else
	{
		printf("TLV_DecodeCat error, code = %d. \n", iRet);
	}

	int iWait = getchar();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章