天天看點

PBOC-TLV編碼格式解碼

      PBOC的IC卡大部分資料都是 TLV 格式的, TLV 是 tag, length 和 value 的縮寫,tag是這個資料元的标示,length是這個資料元值的部分的長度,value則是該資料元的值。其中tag在pboc中最多占兩個位元組,第一個位元組的編碼規則 。 b8 和 b7 兩位辨別 tag 所屬類别 。 這個可以暫時不用理 。b6 決定目前的 TLV 資料是一個單一的資料和複合結構的資料 。 複合的 TLV 是指 value 域裡也包含一個或多個 TLV, 類似嵌套的編碼格式 . b5~b1 如果全為 1 ,則說明這個 tag 下面還有一個子位元組 , 占兩個位元組 , 否則 tag 占一個位元組 。如果tag占用兩個位元組,第二個位元組的編碼格式, B8決定tag是否還有後緒的位元組存在,因為前面說過,PBOC/EMV裡的tag最多占兩個位元組,是以該位保持為0。

     下面是解析TLV格式的java代碼:

import java.util.HashMap;
import java.util.Map;

public class TLVDecode {
	Map<String, String> tlvMap = new HashMap<String, String>();

	/*
	 * 遞歸解析TLV格式資料
	 *  xuys 
	 *  2014-3-2
	 */
	public void decodeTLV(String srcTLV, int len) {
		if (srcTLV.substring(0, srcTLV.length()).length() > 0) {
			String[] st = new String[srcTLV.substring(0, srcTLV.length())
					.length() / 2];
			for (int t = 0; t < srcTLV.substring(0, srcTLV.length()).length() / 2; t++) {
				st[t] = srcTLV.substring(0, srcTLV.length()).substring(2 * t,
						2 * t + 2);
			}
			if ((Integer.valueOf(st[0], 16) & 0x20) != 0x20) { // 單一結構
				if ((Integer.parseInt(st[0], 16) & 0x1f) != 0x1f) { // tag為一個位元組
					StringBuilder sbd = new StringBuilder();
					int dataLen = Integer.valueOf(st[1], 16) == 0x81 ? Integer
							.valueOf(st[2], 16) : Integer.valueOf(st[1], 16);
					int dt = 2;
					if (dataLen > 0x80) {
						dt = 3;
					}
					for (int t = dt; t < dataLen + dt; t++) {
						sbd.append(st[t]);
					}
					tlvMap.put(st[0], sbd.toString());
					if (len > dataLen + dt) {
						StringBuilder lastTlv = new StringBuilder();
						for (int t = dataLen + dt; t < st.length; t++) {
							lastTlv.append(st[t]);
						}
						decodeTLV(lastTlv.toString(), st.length
								- (dataLen + dt));
					}
				} else {// tag為兩個位元組
					StringBuilder sbd = new StringBuilder();
					int dataLen = Integer.valueOf(st[2], 16) == 0x81 ? Integer
							.valueOf(st[3], 16) : Integer.valueOf(st[2], 16);
					int dt = 3;
					if (dataLen > 0x80) {
						dt = 4;
					}
					for (int t = dt; t < dataLen + dt; t++) {
						sbd.append(st[t]);
					}
					tlvMap.put(st[0] + st[1], sbd.toString());
					if (len > dataLen + dt) {
						StringBuilder lastTlv = new StringBuilder();

						for (int t = dataLen + dt; t < st.length; t++) {
							lastTlv.append(st[t]);
						}
						decodeTLV(lastTlv.toString(), st.length
								- (dataLen + dt));
					}
				}

			} else { // 複合結構
				if ((Integer.valueOf(st[0], 16) & 0x1f) != 0x1f) { // tag為一個位元組
					StringBuilder sbd = new StringBuilder();
					int dataLen = Integer.valueOf(st[1], 16) == 0x81 ? Integer
							.valueOf(st[2], 16) : Integer.valueOf(st[1], 16);
					int dt = 2;
					if (dataLen > 0x80) {
						dt = 3;
					}
					for (int t = dt; t < dataLen + dt; t++) {
						sbd.append(st[t]);
					}
					tlvMap.put(st[0], sbd.toString());
					decodeTLV(sbd.toString(), sbd.length() / 2);
					if (len > dataLen + dt) {
						StringBuilder lastTlv = new StringBuilder();
						for (int t = dataLen + dt; t < st.length; t++) {
							lastTlv.append(st[t]);
						}
						decodeTLV(lastTlv.toString(), st.length);
					}
				} else {// tag為兩個位元組
					StringBuilder sbd = new StringBuilder();
					// int tk = Integer.valueOf(st[2], 16);
					int dataLen = Integer.valueOf(st[2], 16) == 0x81 ? Integer
							.valueOf(st[3], 16) : Integer.valueOf(st[2], 16);
					int dt = 3;
					if (dataLen > 0x80) {
						dt = 4;
					}
					for (int t = dt; t < dataLen + dt; t++) {
						sbd.append(st[t]);
					}
					tlvMap.put(st[0] + st[1], sbd.toString());
					decodeTLV(sbd.toString(), sbd.length() / 2);
					if (len > dataLen + 4) {
						StringBuilder lastTlv = new StringBuilder();
						for (int t = dataLen + dt; t < st.length; t++) {
							lastTlv.append(st[t]);
						}
						decodeTLV(lastTlv.toString(), st.length);
					}
				}
			}
		}
	}

	public Map<String, String> getTlvMap() {
		return tlvMap;
	}

	public void setTlvMap(Map<String, String> tlvMap) {
		this.tlvMap = tlvMap;
	}

	/**
	 * @param args
	 * 測試程式
	 */
	public static void main(String[] args) {
		TLVDecode t = new TLVDecode();
		t.decodeTLV(
				"7081E09081B04174C908D9EFBB0F8978BF8C964C22F9ACAA03C5FAE97AC8DFB829C3320E22A4BF45A8DF8010A2B81B3770F801BA1F4FEBA72195FFBBAA48274DB0B44903709FF49D9BD4F414938E32C21419A2E877E08D1E21F8DA7725860CAF3D98FB61D3F5C2B95A9BE870741EA85DE4E82A1BEDEA2BC175AE4927A26817277BA0674198500D176A779641CEAE4BB9E25039A3AAC448BCDD7781238D7882A86DCCB8CB913820494C1BB9574201DEF582EC0404D65A9F320103922420CF86C702825B7A3DD811C5F0F61D6EED533458FEFE81C931AB58910BE9A2033E85C1918F0103",

				"7081E09081B04174C908D9EFBB0F8978BF8C964C22F9ACAA03C5FAE97AC8DFB829C3320E22A4BF45A8DF8010A2B81B3770F801BA1F4FEBA72195FFBBAA48274DB0B44903709FF49D9BD4F414938E32C21419A2E877E08D1E21F8DA7725860CAF3D98FB61D3F5C2B95A9BE870741EA85DE4E82A1BEDEA2BC175AE4927A26817277BA0674198500D176A779641CEAE4BB9E25039A3AAC448BCDD7781238D7882A86DCCB8CB913820494C1BB9574201DEF582EC0404D65A9F320103922420CF86C702825B7A3DD811C5F0F61D6EED533458FEFE81C931AB58910BE9A2033E85C1918F0103"
						.length() / 2);
		for (String tt : t.tlvMap.keySet()) {
			System.out.println(tt + " : " + t.tlvMap.get(tt));
		}
	}

}
           

繼續閱讀