做者:朱克鋒linux
郵箱:zhukefeng@iboxpay.comios
轉載請註明出處:http://blog.csdn.net/linux_zkfgit
TLV是一種可變格式,意思就是:github
Type類型, Lenght長度,Value值;數組
Type和Length的長度固定,通常那是二、4個字節(這裏統一採用4個字節);數據結構
Value的長度有Length指定;測試
解碼方法:ui
1. 讀取type 用ntohl轉換爲主機字節序獲得類型,指針偏移+4編碼
2. 讀取lengh用ntohl轉換爲主機字節序獲得長度;指針偏移+4atom
3. 根據獲得的長度讀取value,若value數據類型爲int、char、short,用ntohl轉換爲主機字節序,指針偏移+4;若value數據類型爲字符串類型,指針偏移+length
類型(Type)字段是關於標籤和編碼格式的信息;
長度 (Length)字段定義數值的長度;
內容(Value)字段表示實際的數值。
所以,一個編碼值又稱TLV(Type,Length,Value)三元組。編碼能夠是基本型或結構型,若是它表示一個簡單類型的、完整的顯式值,那麼編碼就是基本型 (primitive);若是它表示的值具備嵌套結構,那麼編碼就是結構型(constructed)。
以上是對tlv的簡單解釋,從網上搜集的資源來看,用C、C++來寫的開源軟件都很是的複雜,我這裏使用了不多的OC代碼實現了一個簡單實用的TLV解析庫,供各位參考使用
TLV數據結構
//
// TLV.h
// CashBox
//
// Created by ZKF on 13-11-18.
// Copyright (c) 2013年 ZKF. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface TLV : NSObject
@property (nonatomic, assign) NSInteger length;
@property (nonatomic, retain) NSString *value;
@property (nonatomic, retain) NSString *tag;
@end
//
// TLV.m
// CashBox
//
// Created by ZKF on 13-11-18.
// Copyright (c) 2013年 ZKF. All rights reserved.
//
#import "TLV.h"
@implementation TLV
@synthesize tag;
@synthesize value;
@synthesize length;
@end
解析數據結構
//
// LPositon.h
// CashBox
//
// Created by ZKF on 13-11-18.
// Copyright (c) 2013年 ZKF. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface LPositon : NSObject
@property (nonatomic,assign) NSInteger vl;
@property (nonatomic,assign) NSInteger position;
@end
//
// LPositon.m
// CashBox
//
// Created by ZKF on 13-11-18.
// Copyright (c) 2013年 ZKF. All rights reserved.
//
#import "LPositon.h"
@implementation LPositon
@synthesize vl;
@synthesize position;
@end
解析代碼
//
// SAXUnionFiled55Utils.h
// CashBox
//
// Created by ZKF on 13-11-18.
// Copyright (c) 2013年 ZKF. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TLV.h"
#import "LPositon.h"
@interface TLVParseUtils : NSObject
-(NSArray*) saxUnionField55_2List:(NSString*) hexfiled55;
@end
//
// SAXUnionFiled55Utils.m
// CashBox
//
// Created by ZKF on 13-11-18.
// Copyright (c) 2013年 ZKF. All rights reserved.
//
#import "TLVParseUtils.h"
@implementation TLVParseUtils
/**
* 銀聯55域
*
* 本域將根據不一樣的交易種類包含不一樣的子域。銀聯處理中心僅在受理方和髮卡方之間傳遞這些適用於IC卡交易的特有數據,而不對它們進行任何修改和處理。
* 爲適應該子域須要不斷變化的狀況
* ,本域採用TLV(tag-length-value)的表示方式,即每一個子域由tag標籤(T),子域取值的長度(L)和子域取值(V)構成。
* tag標籤的屬性爲bit
* ,由16進製表示,佔1~2個字節長度。例如,"9F33"爲一個佔用兩個字節的tag標籤。而"95"爲一個佔用一個字節的tag標籤
* 。若tag標籤的第一個字節
* (注:字節排序方向爲從左往右數,第一個字節即爲最左邊的字節。bit排序規則同理。)的後五個bit爲"11111",則說明該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個字節。
* 因此,若子域取值的長度在128~255字節之間,那麼該L字段自己需佔兩個字節
*
* @return tlv NSArray
*/
-(NSArray*) saxUnionField55_2List:(NSString*) hexfiled55
{
if (nil == hexfiled55) {
}
return [[[self builderTLV:hexfiled55] retain] autorelease];
}
-(NSArray*) builderTLV:(NSString *)hexString
{
NSMutableArray *arr = [[[NSMutableArrayalloc] initWithCapacity:10] autorelease];
int position = 0;
while (position != hexString.length) {
NSString * _hexTag = [self getUnionTag:hexString P:position];
NSLog(@"hex tag :%@",_hexTag);
if ([_hexTag isEqualToString:@"00"] || [_hexTag isEqualToString:@"0000"]) {
position += _hexTag.length;
continue;
}
position += _hexTag.length;
LPositon *l_position = [[[self getUnionLAndPosition:hexString P:position] retain] autorelease];;
int _vl = l_position.vl;
NSLog(@"value len :%i",_vl);
position = l_position.position;
NSString* _value = [hexString substringWithRange:NSMakeRange(position, _vl * 2)];
NSLog(@"value :%@",_value);
position = position + _value.length;
TLV *tlv = [[[TLV alloc] init] autorelease];
tlv.tag = _hexTag;
tlv.value = _value;
tlv.length = _vl;
[arr addObject:tlv];
}
return arr;
}
int ChangeNum(char * str,int length)
{
char revstr[128] = {0}; //根據十六進制字符串的長度,這裏注意數組不要越界
int num[16] = {0};
int count = 1;
int result = 0;
strcpy(revstr,str);
for (int i = length - 1;i >= 0;i--)
{
if ((revstr[i] >= '0') && (revstr[i] <= '9')) {
num[i] = revstr[i] - 48;//字符0的ASCII值爲48
} else if ((revstr[i] >= 'a') && (revstr[i] <= 'f')) {
num[i] = revstr[i] - 'a' + 10;
} else if ((revstr[i] >= 'A') && (revstr[i] <= 'F')) {
num[i] = revstr[i] - 'A' + 10;
} else {
num[i] = 0;
}
result = result+num[i]*count;
count = count*16;//十六進制(若是是八進制就在這裏乘以8)
}
return result;
}
-(LPositon *)getUnionLAndPosition:(NSString *)hexString P:(NSInteger) position
{
NSString *firstByteString = [hexString substringWithRange:NSMakeRange(position, 2)];
int i = ChangeNum((char *)[firstByteString UTF8String],2);
NSString * hexLength = @"";
if (((i >> 7) & 1) == 0) {
hexLength = [hexString substringWithRange:NSMakeRange(position, 2)];
position = position + 2;
} else {
// 當最左側的bit位爲1的時候,取得後7bit的值,
int _L_Len = i & 127;
position = position + 2;
hexLength = [hexString substringWithRange:NSMakeRange(position, _L_Len * 2)];
// position表示第一個字節,後面的表示有多少個字節來表示後面的Value值
position = position + _L_Len * 2;
}
LPositon *LP = [[[LPositon alloc] init] autorelease];
LP.vl = ChangeNum((char *)[hexLength UTF8String],2);
LP.position = position;
return LP;
}
-(NSString*) getUnionTag:(NSString* )hexString P:(NSInteger) position
{
NSString* firstByte = [hexString substringWithRange:NSMakeRange(position, 2)];
int i = ChangeNum((char *)[firstByte UTF8String],2);
if ((i & 0x1f) == 0x1f) {
return [hexString substringWithRange:NSMakeRange(position, 4)];
} else {
return [hexString substringWithRange:NSMakeRange(position, 2)];
}
}
@end
測試代碼
- (void)viewDidLoad
{
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
TLVParseUtils*s = [[[TLVParseUtilsalloc] init] autorelease];
NSArray *tlvArr = [s saxUnionField55_2List:@"9F260879CC8EC5A09FB9479F2701809F100807010199A0B806019F3704000000009F360201C2950500001800009A031205089C01609F02060000000000005F2A02015682027D009F1A0201569F03060000000000009F3303E0F0F09F34036003029F3501119F1E0832303033313233318405FFFFFFFFFF9F090220069F4104000000019F74064543433030319F631030313032303030308030303030303030"];
NSLog(@"tlv arr :%@",tlvArr);
}
獲取源代碼請到https://github.com/zhukefeng-ios/TVLParse