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
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<
原文的代码有些小问题,本文修正了,另外代码注释更加得详细。