OC封裝的TLV數據格式解析庫

作者:朱克鋒

郵箱:[email protected]

轉載請註明出處:http://blog.csdn.net/linux_zkf



TLV是一種可變格式,意思就是:

Type類型, Lenght長度,Value值;

Type和Length的長度固定,一般那是2、4個字節(這裏統一採用4個字節);

Value的長度有Length指定;

解碼方法:

1.      讀取type 用ntohl轉換爲主機字節序得到類型,指針偏移+4

2.      讀取lengh用ntohl轉換爲主機字節序得到長度;指針偏移+4

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卡交易的特有數據,而不對它們進行任何修改和處理。

 * 爲適應該子域需要不斷變化的情況

 * ,本域採用TLVtag-length-value)的表示方式,即每個子域由tag標籤(T),子域取值的長度(L)和子域取值(V)構成。

 * tag標籤的屬性爲bit

 * ,由16進製表示,佔12個字節長度。例如,"9F33"爲一個佔用兩個字節的tag標籤。而"95"爲一個佔用一個字節的tag標籤

 * 。若tag標籤的第一個字節

 * (注:字節排序方向爲從左往右數,第一個字節即爲最左邊的字節。bit排序規則同理。)的後五個bit"11111",則說明該tag佔兩個字節

 * ,例如"9F33";否則佔一個字節,例如"95" 子域長度(即L本身)的屬性也爲bit,佔13個字節長度。具體編碼規則如下: a)

 * L字段最左邊字節的最左bit位(即bit8)爲0,表示該L字段佔一個字節,它的後續7bit位(即bit7bit1)表示子域取值的長度,

 * 採用二進制數表示子域取值長度的十進制數

 * 。例如,某個域取值佔3個字節,那麼其子域取值長度表示爲"00000011"。所以,若子域取值的長度在1127

 * 字節之間,那麼該L字段本身僅佔一個字節。 b)

 * L字段最左邊字節的最左bit位(即bit8)爲1,表示該L字段不止佔一個字節,那麼它到底佔幾個字節由該最左字節的後續7bit

 * (即bit7bit1)的十進制取值表示。例如,若最左字節爲10000010,表示L字段除該字節外,後面還有兩個字節。其後續字節

 * 的十進制取值表示子域取值的長度。例如,若L字段爲"1000 0001 1111 1111",表示該子域取值佔255個字節。

 * 所以,若子域取值的長度在128255字節之間,那麼該L字段本身需佔兩個字節

 *

 * @return tlv NSArray

 */

-(NSArray*) saxUnionField55_2List:(NSString*) hexfiled55

{

    

    if (nil == hexfiled55) {

        

    }

    return [[[self builderTLV:hexfiled55] retain] autorelease];

}


-(NSArray*) builderTLV:(NSString *)hexString

{

    NSMutableArray *arr = [[[NSMutableArray alloc] 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;//字符0ASCII值爲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

{

    [super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

    TLVParseUtils*s = [[[TLVParseUtils alloc] init] autorelease];

    NSArray *tlvArr =  [s saxUnionField55_2List:@"9F260879CC8EC5A09FB9479F2701809F100807010199A0B806019F3704000000009F360201C2950500001800009A031205089C01609F02060000000000005F2A02015682027D009F1A0201569F03060000000000009F3303E0F0F09F34036003029F3501119F1E0832303033313233318405FFFFFFFFFF9F090220069F4104000000019F74064543433030319F631030313032303030308030303030303030"];

    

    NSLog(@"tlv arr :%@",tlvArr);

}


獲取源代碼請到https://github.com/zhukefeng-ios/TVLParse







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章