TLV 解析(Java)

TLV数据解析的函数整理(Java )

如有问题,请拍板砖!!会及时更正!!
废话不多说直接上代码!!!
测试调用:

public class test {
    public static void main(String[] args){        
        //测试数据
        String data = "950500000008004F08A0000003330101019F36022935500A50424F432044454249549F3704CC8DEE7A82027C009F34030000009F101307020103A00000010A010000017400116766E99F3303E0E1C0";

        TLVTools  tlvTools = new TLVTools();
        TLV tlv;
        tlvTools.unpack(data);

        for(int i=0;iget(i);
            System.out.print("   标签:["+i+"]"+"\n");
            System.out.print("  tag:"+tlv.getTag()+"\n");
            System.out.print("  len:"+tlv.getLen()+"\n");
            System.out.print("value:"+ tlvTools.bytesToHex(tlv.getValue())+"\n");
        }
    }
}

TLV数据类:

public class TLV{
    int tag;//tag定义成数字是为了方便遍历使用
    int len;
    byte[] value;

    public int getTag() {
        return tag;
    }
    public void setTag(int tag) {
        this.tag = tag;
    }
    public int getLen() {
        return len;
    }
    public void setLen(int len) {
        this.len = len;
    }
    public byte[] getValue() {
        return value;
    }
    public void setValue(byte[] value) {
        this.value = value;
    }
}

解析 工具类:

public class TLVTools {
    public List tlvList;

    public TLVTools() {
        tlvList = new ArrayList();
    }

    public List unpack(String tlv){
        int current = 0;//遍历数据标签
        int lenValue = 0;//L的值
        int tagLen = 0;//tag的长度

        //将string数据转换成byte
        byte[] data =hexStrToBytes(tlv);

        while(current < data.length){
            TLV tlvData = new TLV();

            //获取tag的长度
            tagLen = getTagLen(data, current);

            //获取tag值,并转成int
            tlvData.setTag(getTagToInt(data,current,tagLen));

            current += tagLen;
            //当L字段最左边字节的最左bit位(即bit8)为0,表示该L字段占一个字节
            //当L字段最左边字节的最左bit位(即bit8)为1,表示该L字段不止占一个字节
            //若最左字节为10000010,表示L字段除该字节外,后面还有两个字节
            //若最左字节为10000001,表示L字段除该字节外,后面还有一个字节
            //例如,若L字段为“1000 0001 1111 1111”,表示该子域取值占255个字节
            if((data[current]&0x80) == 0x80){
                int tmpLen = data[current]&0x7F;
                switch(tmpLen){
                case 1:
                    //L字段占俩个字节
                    lenValue = data[current + 1]&0xFF;
                    break;
                case 2:
                    //L字段占三个字节
                    lenValue = (data[current + 1]<<8)&0xFF00 + (data[current+2]&0xFF);
                    break;
                }
                current += tmpLen + 1;
            } else{
                //L字段占一个字节
                lenValue = data[current]&0xFF;
                current +=1;
            }
            //设置len值
            tlvData.setLen(lenValue);

            //设置value值
            byte[] temp = new byte[lenValue];
            System.arraycopy(data, current, temp, 0, lenValue);
            tlvData.setValue(temp);

            current += lenValue;

            tlvList.add(tlvData);
        }

        return tlvList;
    }

    //hex数据转换成byte
    public byte[] hexStrToBytes(String data)    {
        if (data == null || "".equals(data)) {
            return null;
        }
        int len = data.length() / 2;
        byte[] result = new byte[len];

        //将每个char字符单独转换成byte数据
        char[] chArr = data.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(chArr[pos]) << 4 | toByte(chArr[pos + 1]));
        }
        return result;
    }

    //获取tag长度
    public int getTagLen(byte[] data, int flag) {
        /*若tag标签的第一个字节(注:字节排序方向为从左往右数,
         * 第一个字节即为最左边的字节。bit排序规则同理。)的后
         * 四个bit为“1111”,则说明该tag占两个字节,例如“9F33”;
         * 否则占一个字节,例如“95”。*/
        int tagLen = 1;
        for (int i = 0; i < 2; i++) {
            byte b = data[i + flag];
            if ((b & 0x0F) == 0x0F) {
                tagLen++;
            } else {
                break;
            }
        }
        return tagLen;
    }

    public static byte toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }

    //获取tag,并转成int
    public int getTagToInt(byte[] data, int flag, int len){
        int mask = 0xFF;
        int temp = 0;
        int result = 0;
        len = Math.min(len, 4);//tag最长4位
        for (int i = 0; i < len; i++) {
            result <<= 8;//向左位移8
            temp = data[flag + i] & mask;
            result |= temp;//将获取出的数据填充到result让出右侧的8位上
        }
        return result;
    }

    private static char[] HEX_VOCABLE = { '0', '1', '2', '3', '4', '5', '6',
        '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

    //bytes数组转换成string
    public static String bytesToHex(byte[] data) {
        StringBuilder sb = new StringBuilder();
        for (byte b : data) {
            //获取高4位的数据值,正好对应HEX_VOCABLE数组中的下标,和相应char的值
            int high = (b >> 4) & 0x0f;
            //获取低4位的数据值,正好对应HEX_VOCABLE数组中的下标,和相应char的值
            int low = b & 0x0f;
            sb.append(HEX_VOCABLE[high]);
            sb.append(HEX_VOCABLE[low]);
        }
        return sb.toString();
    }

}

显示结果:
标签:[0]
tag:149
len:5
value:0000000800
标签:[1]
tag:20232
len:5
value:027C009F34
标签:[2]
tag:3
len:0
value:
标签:[3]
tag:0
len:0
value:
标签:[4]
tag:40720
len:19
value:07020103A00000010A010000017400116766E9
标签:[5]
tag:40755
len:3
value:E0E1C0

附银联相关TLV说明:
本域将根据不同的交易种类包含不同的子域。处理中心仅在受理方和发卡方之间传递这些适用于IC卡交易的特有数据,而不对它们进行任何修改和处理。为适应该子域需要不断变化的情况,本域采用TLV(tag-length-value)的表示方式,即每个子域由tag标签(T),子域取值的长度(L)和子域取值(V)构成。
tag标签的属性为bit,由16进制表示,占1~2个字节长度。例如,“9F33”为一个占用两个字节的tag标签。而“95”为一个占用一个字节的tag标签。若tag标签的第一个字节(注:字节排序方向为从左往右数,第一个字节即为最左边的字节。bit排序规则同理。)的后四个bit为“1111”,则说明该tag占两个字节,例如“9F33”;否则占一个字节,例如“95”。
子域长度(即L本身)的属性也为bit,占1~3个字节长度。具体编码规则如下:
a) 当L字段最左边字节的最左bit位(即bit8)为0,表示该L字段占一个字节,它的后续7个bit位(即bit7~bit1)表示子域取值的长度,采用二进制数表示子域取值长度的十进制数。例如,某个域取值占3个字节,那么其子域取值长度表示为“00000011”。所以,若子域取值的长度在1~127字节之间,那么该L字段本身仅占一个字节。
b) 当L字段最左边字节的最左bit位(即bit8)为1,表示该L字段不止占一个字节,那么它到底占几个字节由该最左字节的后续7个bit位(即bit7~bit1)的十进制取值表示。例如,若最左字节为10000010,表示L字段除该字节外,后面还有两个字节。其后续字节的十进制取值表示子域取值的长度。例如,若L字段为“1000 0001 1111 1111”,表示该子域取值占255个字节。所以,若子域取值的长度在127~255字节之间,那么该L字段本身需占两个字节。
子域取值根据不同的子域含义分别取不同的数值。由于该域中所包含的子域都是IC卡卡片和IC卡终端所特有的信息,而非处理中心的特征信息,处理中心仅为一个数据传递的桥梁,所以具体取值需参见IC卡卡片及IC卡终端规范,并根据其标准的变化不断更新。对于境内交易需参见《中国金融集成电路(IC)卡规范 第5部分 借记/贷记卡片规范》和《中国金融集成电路(IC)卡规范 第6部分 借记/贷记终端规范分》。对于外卡收单交易需根据不同国际信用卡公司组织(例如,Visa、万事达、JCB、大莱、运通)的发卡策略参见其相应的卡片和终端规范。但由于所有组织(包括银联)对卡片和终端的定义都是基于EMV2000标准的,因此不论这些信息的具体取值有何不同,它们的tag标签都是一致的。因此,在本标准中仅给出tag标签,入网机构即可根据标签取值查找到不同组织对该子域的具体取值。下面将列举每个子域的tag标签、和长度值及其属性。

你可能感兴趣的:(TLV 解析(Java))