转自 http://blog.csdn.net/super_mimi/article/details/49000981
BER-TLV 数据对象编码
根据 ISO/IEC 8825 的定义,一个 BER-TLV 数据对象包括 2-3 个连续数据域:
l 标签域( Tag)包括一个或多个连续字节。它定义一种类别、类型和一个数字。本规范规定的数据对象的标签域用一个或二个字节编码。
l 长度域( Length)包括一个或多个连续字节。它定义了接下来一个域的长度。本规范规定的数据对象的长度用一个、或二个字节编码。
l 标签域( Tag)包括一个或多个连续字节。它定义一种类别、类型和一个数字。本规范规定的数据对象的标签域用一个或二个字节编码。
l 长度域( Length)包括一个或多个连续字节。它定义了接下来一个域的长度。本规范规定的数据对象的长度用一个、或二个字节编码。
l 值域( Value)定义数据对象的值。如果 L= ‘ 00’ ,则值域不存在。
先看看Tag域的编码:
表 B- 2 根据 ISO/IEC 8825 定义了当标签号=31(即第一字节的 b5- b1 位为‘ 11111’ )时,BER-TLV 标签跟随字节的编码规则。即Tag域扩展到下一个字节。
当b8为1时,还需要扩展。但EMV文档中说明,Tag域最多占用两个字节。
Length域的规范:
当长度域的最高字节的 b8 位为 0 时,长度域仅有一个字节。 b7 到 b1 位的值为值域的字节数。长度域的范围为 1 到 127。
当长度域的最高字节的 b8 位位 1 时,紧接的 b7 到 b1 位的值为长度域最高字节后跟随的长度字节数。后续字节的整数值为值域的字节数。要表示 255 个字节以下的值域,至少需要2 个字节。
Value域的规范:
基本 BER-TLV 数据对象的值域是一个数据元。数据元是带标识(标签)的最小数据域。
复合 BER-TLV 数据对象包括一个标签、一个长度和一个值域,其值域由一个和多个BER-TLV 数据对象组成。
下面是TLV代码的例子:
TLV结构体:
- //创建TLV结构体
- typedef struct TLVEntity
- {
- unsigned char * Tag; //标签
- unsigned char * Length; //长度
- unsigned char * Value; //数据
- unsigned int TagSize; //标签占用字节 一般两个字节
- unsigned int LengthSize; //数据占用的字节
- TLVEntity * subTLVEntity; //嵌套的子TLV结构体,如果有的话,需要递归
- unsigned int subTLVnum; //下一级的TLV数量,不包括下下级的TLV(记录subTLVEntity[]的大小)
- }TLV, *PTLV;
构造TLV的函数:
- //构造TLV
- void TLVConstruct(unsigned char *buffer, //TLV字符串
- unsigned int bufferLength, //TLV字符串长度
- PTLV PTlvEntity, //TLV指针
- unsigned int& entitySize //TLV结构数量,解析时用到
- )
- {
- int currentIndex = 0; //用于标记buffer
- int currentTLVIndex = 0; //当前TLV结构标记
- int currentStatus = 'T'; //状态字符
- unsigned long valueSize = 0; //数据长度
- while (currentIndex < bufferLength)
- {
- switch (currentStatus)
- {
- case 'T':
- valueSize = 0; //清零
- //判断TLV是否为单一结构,字节的第6位是否为1
- if ((buffer[currentIndex] & 0x20) != 0x20)
- {
- //单一结构
- PTlvEntity[currentTLVIndex].subTLVEntity = NULL;
- PTlvEntity[currentTLVIndex].subTLVnum = 0; //子TLV的数量为零
- //判断是Tag是否为多字节,字节的1--5位是否都为1,是的话有后续字节
- if ((buffer[currentIndex] & 0x1f) == 0x1f)
- {
- //Tag为多字节
- int endTagIndex = currentIndex;
- while (buffer[++endTagIndex] & 0x80 == 0x80); //最后一个字节的最高位为0
- int tagSize = endTagIndex - currentIndex + 1; //计算标签所占用字节
- PTlvEntity[currentTLVIndex].Tag = (unsigned char *)malloc(tagSize);
- memcpy(PTlvEntity[currentTLVIndex].Tag, buffer + currentIndex, tagSize);
- PTlvEntity[currentTLVIndex].Tag[tagSize] = 0;//字符串末尾置0
- PTlvEntity[currentTLVIndex].TagSize = tagSize;
- currentIndex += tagSize;
- }
- else
- {
- //Tag占用1个字节
- PTlvEntity[currentTLVIndex].Tag = (unsigned char *)malloc(1);
- memcpy(PTlvEntity[currentTLVIndex].Tag, buffer + currentIndex, 1);
- PTlvEntity[currentTLVIndex].Tag[1] = 0;
- PTlvEntity[currentTLVIndex].TagSize = 1;
- currentIndex += 1;
- }
- }
- else
- {
- //复合结构
- //判断是否为多字节
- if ((buffer[currentIndex] & 0x1f) == 0x1f)
- {
- int endTagIndex = currentIndex;
- while (buffer[++endTagIndex] & 0x80 == 0x80);
- int tagSize = endTagIndex - currentIndex + 1;
- PTlvEntity[currentTLVIndex].Tag = (unsigned char *)malloc(tagSize);
- memcpy(PTlvEntity[currentTLVIndex].Tag, buffer + currentIndex, tagSize);
- PTlvEntity[currentTLVIndex].Tag[tagSize] = 0;
- PTlvEntity[currentTLVIndex].TagSize = tagSize;
- currentIndex += tagSize;
- }
- else
- {
- PTlvEntity[currentTLVIndex].Tag = (unsigned char *)malloc(1);
- memcpy(PTlvEntity[currentTLVIndex].Tag, buffer + currentIndex, 1);
- PTlvEntity[currentTLVIndex].Tag[1] = 0;
- PTlvEntity[currentTLVIndex].TagSize = 1;
- currentIndex += 1;
- }
- //分析子TLV中的Tag
- int subTlvLength = 0; //子TLV长度
- unsigned char * temp; //子TLV所包含的数据
- //先判断length域的长度,length域字节如果最高位为1,后续字节代表长度,为0,1--7位代表数据长度
- if ((buffer[currentIndex] & 0x80) == 0x80)
- {
- //最高位为1
- unsigned int lengthSize = buffer[currentIndex] & 0x7f;
- for (int index = 0; index < lengthSize; index++)
- {
- //大端显示数据
- subTlvLength += buffer[currentIndex + 1 + index] << ((lengthSize - 1 - index) * 8);
- /* 如果是小端的话
- subTlvLength += buffer[currentIndex + 1 + index] << (index * 8);
- */
- }
- //申请一段subTlvlength大小的内存存放该TLV的内容
- temp = (unsigned char *)malloc(subTlvLength);
- memcpy(temp, buffer + currentIndex + 1 + lengthSize, subTlvLength);
- }
- else
- {
- //最高位为0
- subTlvLength = buffer[currentIndex];
- temp = (unsigned char *)malloc(subTlvLength);
- memcpy(temp, buffer + currentIndex + 1, subTlvLength);
- }
- temp[subTlvLength] = 0;
- unsigned int oSize;//输出有多少个同等级的子TLV,解析时也应该用到
- //不清楚子TLV同等级的TLV有多少个,申请100TLV大小的内存肯定够用
- PTlvEntity[currentTLVIndex].subTLVEntity = (PTLV)malloc(sizeof(TLV[100]));
- TLVConstruct(temp, subTlvLength, PTlvEntity[currentTLVIndex].subTLVEntity, oSize);
- PTlvEntity[currentTLVIndex].subTLVnum = oSize; //填入子TLV的数量
- }
- currentStatus = 'L';
- break;
- case 'L':
- //判断长度字节的最高位是否为1,如果为1,则该字节为长度扩展字节,由下一个字节开始决定长度
- if ((buffer[currentIndex] & 0x80) == 0x80)
- {
- //最高位1
- unsigned int lengthSize = buffer[currentIndex] & 0x7f;
- currentIndex += 1; //从下一个字节开始算Length域
- for (int index = 0; index < lengthSize; index++)
- {
- valueSize += buffer[currentIndex + index] << ((lengthSize - 1 - index) * 8); //计算Length域的长度
- }
- PTlvEntity[currentTLVIndex].Length = (unsigned char *)malloc(lengthSize);
- memcpy(PTlvEntity[currentTLVIndex].Length, buffer + currentIndex, lengthSize);
- PTlvEntity[currentTLVIndex].Length[lengthSize] = 0;
- PTlvEntity[currentTLVIndex].LengthSize = lengthSize;
- currentIndex += lengthSize;
- }
- else
- {
- //最高位0
- PTlvEntity[currentTLVIndex].Length = (unsigned char *)malloc(1);
- memcpy(PTlvEntity[currentTLVIndex].Length, buffer + currentIndex, 1);
- PTlvEntity[currentTLVIndex].Length[1] = 0;
- PTlvEntity[currentTLVIndex].LengthSize = 1;
- valueSize = PTlvEntity[currentTLVIndex].Length[0];
- currentIndex += 1;
- }
- currentStatus = 'V';
- break;
- case 'V':
- PTlvEntity[currentTLVIndex].Value = (unsigned char *)malloc(valueSize);
- memcpy(PTlvEntity[currentTLVIndex].Value, buffer + currentIndex, valueSize);
- PTlvEntity[currentTLVIndex].Value[valueSize] = 0;
- currentIndex += valueSize;
- //进入下一个TLV构造循环
- currentTLVIndex += 1;
- currentStatus = 'T';
- break;
- }
- }
- entitySize = currentTLVIndex;
- }
- // 解析TLV
- BOOL TLVParseAndFindError(
- PTLV PTlvEntity, //输入的TLV结构体
- unsigned int entitySize, //TLV结构体的数量
- unsigned char* buffer, //输出的字符串
- unsigned int& bufferLength //字符串的长度
- )
- {
- int currentIndex = 0;
- int currentTLVIndex = 0;
- unsigned long valueSize = 0;
- while(currentTLVIndex < entitySize)
- {
- valueSize = 0;
- TLVEntity entity = PTlvEntity[currentTLVIndex];
- memcpy(buffer + currentIndex, entity.Tag, entity.TagSize); //解析Tag
- currentIndex += entity.TagSize;
- for (int index = 0; index < entity.LengthSize; index++)
- {
- //大端显示数据
- valueSize += entity.Length[index] << ((entity.LengthSize - 1 - index) * 8); //计算Length域的长度
- }
- if(valueSize > 127) //还原length 当最高位为1的情况
- {
- buffer[currentIndex] = 0x80 | entity.LengthSize;
- currentIndex += 1;/******************************************/
- }
- memcpy(buffer + currentIndex, entity.Length, entity.LengthSize); //解析Length
- currentIndex += entity.LengthSize;
- //判断是否包含子嵌套TLV
- if(entity.subTLVEntity == NULL)
- {
- //不包含
- memcpy(buffer + currentIndex, entity.Value, valueSize); //解析Value
- currentIndex += valueSize;
- }
- else
- {
- unsigned int oLength;
- TLVParseAndFindError(entity.subTLVEntity, entity.subTLVnum, buffer + currentIndex, oLength); //解析子嵌套TLV
- currentIndex += oLength;
- }
- currentTLVIndex++;
- }
- buffer[currentIndex] = 0;
- bufferLength = currentIndex;
- return TRUE;
- }
测试的函数:
- unsigned char requestBuf[] = {
- 0x30,0x82,0x02,0x5C,0x02,0x01,0x00,0x02,0x81,0x81,0x00,0xC2,0xA9,0x64,0x0E,0x11,
- 0x3A,0x29,0x83,0x31,0x21,0x92,0x72,0x79,0xE0,0xEF,0x1C,0xDB,0xF5,0xE4,0x98,0xA3,
- 0x0A,0x98,0x58,0x05,0x54,0xDF,0xE6,0x55,0xFD,0xB5,0x0D,0x5B,0x62,0x93,0x2C,0x0B,
- 0x4E,0x6C,0xE3,0xF7,0xCE,0x2A,0x76,0x18,0x72,0x15,0x90,0x34,0xCA,0x00,0xE2,0x79,
- 0x86,0x09,0x74,0xC6,0x50,0x85,0xF9,0x40,0xBF,0xA6,0xAE,0x3B,0xEB,0xF3,0xF1,0x70,
- 0x9A,0xE8,0x47,0xAB,0xB8,0x04,0x27,0xC1,0x02,0xFE,0xD2,0x4F,0xA7,0x96,0x55,0x0D,
- 0xE5,0x3B,0x8F,0xA8,0x5A,0xB4,0x50,0x2B,0x9D,0x1C,0x2C,0x16,0xD2,0xF9,0x75,0x13,
- 0xF5,0x35,0x87,0x38,0xF3,0xE0,0x4B,0x7F,0xCC,0x8C,0xBC,0x81,0xB9,0xFA,0x35,0x60,
- 0xD3,0x5B,0xDD,0xCA,0x50,0xD5,0x19,0xC6,0x5A,0x4B,0x05,0x02,0x03,0x01,0x00,0x01,
- 0x02,0x81,0x80,0x40,0x67,0x0F,0x89,0xD1,0xEC,0x46,0xC0,0xB7,0x58,0x0E,0x9E,0x1E,
- 0x31,0xAB,0x9A,0x86,0x31,0x87,0xC4,0x72,0x28,0xB6,0xB7,0x64,0x68,0x2C,0xBD,0x85,
- 0x94,0xAF,0x3A,0x70,0x92,0x1F,0xF3,0xF1,0xF7,0xAB,0xF2,0x0E,0x51,0xE0,0xDD,0x7A,
- 0x80,0x00,0x1F,0x5A,0x3F,0xBC,0xE4,0x30,0xE5,0x86,0x2A,0x62,0xD4,0x50,0x46,0xE3,
- 0x43,0xA5,0x0E,0xAA,0xDA,0x22,0x70,0x60,0x6A,0x5C,0xD5,0xEF,0xA5,0xEB,0x06,0x6A,
- 0x53,0xE9,0xFB,0x79,0xC6,0x00,0x84,0x05,0xB7,0x5E,0x12,0x53,0x4C,0xAC,0xA4,0xA1,
- 0x77,0x16,0x64,0x99,0xAB,0x5F,0x1B,0xC0,0xC6,0x88,0xEB,0x96,0x73,0x84,0x61,0x17,
- 0x50,0x1D,0x14,0xBC,0x90,0xC1,0x36,0xDF,0x9D,0x23,0x5A,0xB4,0xD7,0xE8,0x9F,0x2A,
- 0x77,0x3D,0xAF,0x02,0x41,0x00,0xF2,0xE5,0x23,0xFF,0x1C,0x24,0xFC,0x1A,0x80,0x53,
- 0x24,0x9C,0x57,0x06,0x0B,0xF7,0x7A,0x56,0x01,0xB9,0x50,0x7A,0xB4,0xAB,0xD4,0x5A,
- 0xC8,0xB3,0x6F,0x87,0xF0,0x2A,0xAC,0x13,0x4E,0xD7,0x5C,0x74,0x69,0x87,0x6B,0x20,
- 0x98,0x2C,0x0D,0x42,0x31,0xCA,0x5F,0xA3,0x8C,0x7E,0xE3,0x21,0x29,0x75,0xE4,0xAD,
- 0xAE,0xB0,0x11,0xFB,0xD9,0x37,0x02,0x41,0x00,0xCD,0x2A,0x0D,0x51,0x67,0xD2,0x25,
- 0xE8,0x6F,0xC9,0x51,0x31,0x46,0xEE,0x10,0x04,0xD0,0xA9,0x42,0x8D,0x15,0xC1,0x6D,
- 0x59,0x83,0x74,0x39,0x36,0xE6,0x6F,0xD6,0x70,0x93,0xAD,0x59,0xD5,0x31,0x35,0xAC,
- 0x8F,0xF2,0xC4,0x75,0xD9,0x60,0xC1,0xCE,0x93,0xBB,0x02,0x42,0x62,0xEE,0x42,0xF5,
- 0xBD,0x19,0x20,0x0D,0xDC,0x20,0xF3,0x6B,0xA3,0x02,0x41,0x00,0xBC,0xE1,0x69,0x1B,
- 0x91,0xB4,0x45,0x03,0x0A,0xB5,0x1C,0xEC,0x22,0x54,0x06,0x6C,0x3D,0x0A,0xB2,0xAE,
- 0x7B,0xA1,0xDF,0xEB,0x1A,0xE8,0x39,0xD8,0x27,0x2B,0xCB,0x9C,0x33,0x51,0x94,0x66,
- 0xAE,0x73,0xAC,0x38,0x6D,0x1A,0xDC,0x9A,0xAC,0xF8,0xC3,0xA5,0x3E,0xB7,0xFC,0xA2,
- 0x13,0x57,0x8F,0x59,0x29,0x29,0xD2,0x85,0x02,0x87,0x19,0x03,0x02,0x40,0x63,0x2F,
- 0xE5,0x68,0x69,0xCD,0x0B,0x4E,0xA8,0x5C,0xA7,0xC8,0x2F,0x06,0x80,0xF0,0x13,0x01,
- 0x01,0x8F,0xBB,0xE8,0xDB,0xB8,0xDE,0xF8,0x9D,0x80,0x91,0x3F,0x98,0x68,0xAC,0xBC,
- 0xAE,0x25,0x87,0xB8,0xEF,0x48,0x58,0x91,0xEA,0x77,0xC1,0x73,0x71,0x2F,0xB2,0xC5,
- 0x90,0xDA,0xCB,0x5D,0xCB,0xF8,0x33,0xE1,0x6F,0x51,0xF1,0x0C,0x3E,0x09,0x02,0x40,
- 0x7D,0x62,0x82,0x3D,0xAA,0xB6,0x2D,0x35,0x2B,0x87,0xB4,0x75,0x49,0x51,0x8A,0x77,
- 0x75,0x96,0xEA,0xA2,0x1C,0x75,0x57,0xA2,0xF4,0xE9,0x70,0xAE,0x81,0x09,0x84,0xE1,
- 0x4B,0x41,0x11,0x82,0xA7,0x41,0xD1,0xCC,0xD8,0xFF,0x21,0xC4,0x38,0x79,0x45,0xA5,
- 0x0F,0x98,0x64,0x85,0xF5,0x2B,0xA6,0xBE,0x36,0xF3,0xDC,0x05,0xD3,0xFA,0x12,0x33
- };
- int main(int argc, char* argv[])
- {
- TLV PtlvEntity[1000];
- unsigned int tlv_count;
- //构造TLV
- TLVConstruct(requestBuf, sizeof(requestBuf), PtlvEntity, tlv_count);
- MessageBox(NULL,"构造完成!","test",MB_OK);
- unsigned char parseBuf[4096];
- unsigned int buf_count;
- //解析TLV
- TLVParseAndFindError(PtlvEntity, tlv_count, parseBuf, buf_count);
- MessageBox(NULL,"解析完成!","test",MB_OK);
- //看了下前100个数据
- for(int i=0; i<100; i++)
- {
- char buf[5];
- wsprintf(buf,"%02x",parseBuf[i]);
- cout<<buf<<endl;
- }
- if(strncmp((char*)parseBuf, (char*)requestBuf, sizeof(requestBuf)) == 0)
- {
- MessageBox(NULL,"TRUE","test",MB_OK);
- }
- else
- {
- MessageBox(NULL,"FALSE","test",MB_OK);
- }
- printf("Hello World!\n");
- return 0;
- }
总结
TLV在数据通信方面,其实运用得很广泛,在应用层数据通信中,如HTTP协议,HTML,XML语言本身定义了一些标签(Body,Head,Script)对数据串行化,接收方再根据标签解析原始数据,通过浏览器展现出来。因此本质上也是属于TLV协议的设计模式。甚至在传输层的TCP,UDP协议,你完全可以通过TLV实现自定义的应用协议。
附上C#源代码:TLVPackageDemo.rar
总结
TLV在数据通信方面,其实运用得很广泛,在应用层数据通信中,如HTTP协议,HTML,XML语言本身定义了一些标签(Body,Head,Script)对数据串行化,接收方再根据标签解析原始数据,通过浏览器展现出来。因此本质上也是属于TLV协议的设计模式。甚至在传输层的TCP,UDP协议,你完全可以通过TLV实现自定义的应用协议。
附上C#源代码:TLVPackageDemo.rar
本文借鉴于:http://www.cnblogs.com/liping13599168/archive/2011/06/15/2081366.html
原文的代码有些小问题,本文修正了,另外代码注释更加得详细。