1.什么是TLV格式?
TLV即Tag-Length-Value,常在IC卡與POS終端設備中通過這樣的一個應用通信協議進行數據交換。 金融系統中的TLV是BER-TLV編碼的一個特例編碼規范,而BER-TLV是ISO定義中的規范。在TLV的定義中,可以知道它包括三個域,分別為:標簽域(Tag),長度域(Length),內容域(Value)。這里的長度域的值實際上就是內容域的長度。 其實,在BER編碼的方式有兩種情況,一種是確定長度的方式,一種是不確定長度的方式,而金融TLV選擇了確定長度的方式,這樣在設備之間的數據傳輸量上就可以減少。
2.Tag域
3.Length域
當b8為0時,該字節的b7-b1作為value域的長度;當b8為1時,b7-b1作為后續字節的長度。例:10000011,代表后續還有3個字節作為value域的長度(本字節不算,本字節變為作為一個Length的索引)。3個字節代表value的長度,意味着什么呢,意味着內容的長度當需要很大的時候,字節的位數就會跟着越高,3個字節就代表最大可以有256*256*256的長度。
4.Value域
分成兩種情況考慮,就是前面說到的Tag分成兩個數據元結構,一種是簡單數據元結構,一種是復合數據元架構:
先來看看簡單數據元結構:
復合數據元結構:
5.TLV格式數據實例
數據: 5F2D027A68
Tag域
5F → 01011111 → 5F 2D → 00101101 → 5F2D
Length域
02 → 00000010 → 02(2字節)
Value域
7A68
6.算法實現 C#
首先根據定義創建一個實體類
1 /// <summary> 2 /// TLV格式報文實體類 3 /// </summary> 4 public class TLVEntity 5 { 6 /// <summary> 7 /// 標記 8 /// </summary> 9 public byte[] Tag { get; set; } 10 11 /// <summary> 12 /// 數據長度 13 /// </summary> 14 public byte[] Length { get; set; } 15 16 /// <summary> 17 /// 數據 18 /// </summary> 19 public byte[] Value { get; set; } 20 21 /// <summary> 22 /// 標記占用字節數 23 /// </summary> 24 public int TagSize { get { return this.Tag.Length; } } 25 26 /// <summary> 27 /// 數據長度占用字節數 28 /// </summary> 29 public int LengthSize { get { return this.Length.Length; } } 30 31 /// <summary> 32 /// 子嵌套TLV實體列表 33 /// </summary> 34 public List<TLVEntity> SubTLVEntity { get; set; } 35 }
下面是tlv格式報文打包解析
1 /// <summary> 2 /// TLV格式報文打包解析 3 /// </summary> 4 public class TLVPackage 5 { 6 #region TLV 打包 7 8 /// <summary> 9 /// TLV報文打包 10 /// </summary> 11 /// <param name="buffer">字節數據</param> 12 /// <returns></returns> 13 public static List<TLVEntity> Construct(byte[] buffer) 14 { 15 List<TLVEntity> resultList = new List<TLVEntity>(); 16 int currentIndex = 0; 17 while (currentIndex < buffer.Length) 18 { 19 TLVEntity entity = new TLVEntity(); 20 //1. 根據Tag判斷數據是否是嵌套的TLV 21 bool hasSubEntity = HasSubEntity(buffer, currentIndex); 22 23 #region Tag解析 24 entity.Tag = GetTag(buffer, currentIndex); 25 currentIndex += entity.Tag.Length; 26 #endregion 27 28 #region Length解析 29 entity.Length = GetLength(buffer, currentIndex); 30 currentIndex += entity.Length.Length; 31 #endregion 32 33 #region Value解析 34 int valueLength = GetValueLengthByLengthByteValue(entity.Length); 35 entity.Value = buffer.Take(currentIndex + valueLength).Skip(currentIndex).ToArray(); 36 if (hasSubEntity)//判斷是否是嵌套結構 37 entity.SubTLVEntity = Construct(entity.Value);//嵌套結構遞歸解析 38 currentIndex += entity.Value.Length; 39 #endregion 40 41 resultList.Add(entity); 42 } 43 return resultList; 44 } 45 46 /// <summary> 47 /// 是否存在嵌套實體 48 /// </summary> 49 /// <returns></returns> 50 private static bool HasSubEntity(byte[] bytes, int index) 51 { 52 if (bytes.Length < index + 1) 53 throw new ArgumentException("無效的索引值"); 54 return (bytes[index] & 0x20) == 0x20; 55 } 56 57 /// <summary> 58 /// 獲取Tag字節數據 59 /// </summary> 60 /// <param name="bytes">長度</param> 61 /// <param name="index">索引位置</param> 62 /// <returns></returns> 63 private static byte[] GetTag(byte[] bytes, int index) 64 { 65 if (bytes.Length < index + 1) 66 throw new ArgumentException("無效的索引值"); 67 //判斷Tag所占字節長度 68 if ((bytes[index] & 0x1f) == 0x1f) 69 {//占2字節 70 return new byte[] { bytes[index], bytes[index + 1] }; 71 } 72 else 73 {//占1字節 74 return new byte[] { bytes[index] }; 75 } 76 } 77 78 /// <summary> 79 /// 獲取長度 80 /// </summary> 81 /// <param name="bytes">長度</param> 82 /// <param name="index">索引位置</param> 83 /// <returns></returns> 84 private static byte[] GetLength(byte[] bytes, int index) 85 { 86 if (bytes.Length < index + 1) 87 throw new ArgumentException("無效的索引值"); 88 //判斷Length部分所占字節 是1個字節還是多個字節 89 if ((bytes[index] & 0x80) == 0x80) 90 {//占多個字節 91 int lengthSize = (bytes[index] & 0x7f) + 1;//獲取Length所占字節數 92 return bytes.Take(index + lengthSize).Skip(index).ToArray(); 93 } 94 else 95 {//占單個字節 96 return new byte[] { bytes[index] }; 97 } 98 } 99 /// <summary> 100 /// 根據Length部分的值獲取到value部分的值 101 /// </summary> 102 /// <param name="bytes">Length部分的值</param> 103 /// <returns></returns> 104 private static int GetValueLengthByLengthByteValue(byte[] bytes) 105 { 106 int length = 0; 107 if (bytes.Length == 1) 108 length = bytes[0]; 109 else 110 { 111 //從下一個字節開始算Length域 112 for (int index = 1; index < bytes.Length; index++) 113 { 114 length += bytes[index] << ((index-1) * 8); //計算Length域的長度 115 } 116 } 117 return length; 118 } 119 120 #endregion 121 122 #region TLV 解析 123 /// <summary> 124 /// 解析TLV 125 /// </summary> 126 /// <param name="list"> 127 /// <returns></returns> 128 public static byte[] Parse(List<TLVEntity> list) 129 { 130 byte[] buffer = new byte[4096]; 131 int currentIndex = 0; 132 int currentTLVIndex = 0; 133 int valueSize = 0; 134 135 while (currentTLVIndex < list.Count()) 136 { 137 valueSize = 0; 138 TLVEntity entity = list[currentTLVIndex]; 139 140 Array.Copy(entity.Tag, 0, buffer, currentIndex, entity.TagSize); //解析Tag 141 142 currentIndex += entity.TagSize; 143 144 for (int index = 0; index < entity.LengthSize; index++) 145 { 146 valueSize += entity.Length[index] << (index * 8); //計算Length域的長度 147 } 148 if (valueSize > 127) 149 { 150 buffer[currentIndex] = Convert.ToByte(0x80 | entity.LengthSize); 151 currentIndex += 1; 152 } 153 154 Array.Copy(entity.Length, 0, buffer, currentIndex, entity.LengthSize); //解析Length 155 156 currentIndex += entity.LengthSize; 157 //判斷是否包含子嵌套TLV 158 if (entity.SubTLVEntity == null) 159 { 160 Array.Copy(entity.Value, 0, buffer, currentIndex, valueSize); //解析Value 161 currentIndex += valueSize; 162 } 163 else 164 { 165 byte[] tempBuffer = Parse(entity.SubTLVEntity); 166 Array.Copy(tempBuffer, 0, buffer, currentIndex, tempBuffer.Length); //解析子嵌套TLV 167 currentIndex += tempBuffer.Length; 168 } 169 170 currentTLVIndex++; 171 } 172 173 byte[] resultBuffer = new byte[currentIndex]; 174 Array.Copy(buffer, 0, resultBuffer, 0, currentIndex); 175 176 return resultBuffer; 177 } 178 #endregion 179 }
tlv實體操作幫助類
public class TLVHelper { /// <summary> /// 根據tag獲取tlv的值 /// </summary> /// <param name="entities"></param> /// <param name="tag"></param> /// <returns></returns> public static TLVEntity GetValueByTag(List<TLVEntity> entities, string tag) { TLVEntity resultEntity = null; var query = entities.SingleOrDefault(e => CodeConvert.ToHexString(e.Tag).ToUpper() == tag); if (query == null) { foreach (var tlv in entities) { if (tlv.SubTLVEntity != null) { TLVEntity result = GetValueByTag(tlv.SubTLVEntity, tag); if (result !=null && result.Length.Length > 0) return result; } } } else resultEntity = query; return resultEntity; } /// <summary> /// 16進制數據轉化為TVL實體 /// </summary> /// <param name="resultData"></param> /// <returns></returns> public static List<TLVEntity> ToTLVEntityList(string data) { byte[] dataBytes = CodeConvert.HexStringToByteArray(data); var tlvList = TLVPackage.Construct(dataBytes); return tlvList; } }
轉載請注明出處:http://www.cnblogs.com/xinwang/p/5733198.html