OC封装的TLV数据格式解析库
作者:朱克锋
邮箱:zhukefeng@iboxpay.com
转载请注明出处: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卡交易的特有数据,而不对它们进行任何修改和处理。
* 为适应该子域需要不断变化的情况
* ,本域采用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
OC封装的TLV数据格式解析库的更多相关文章
- Pugixml一种快速解析XML文件的开源解析库
Pugixml是一个轻量级的C++ XML开源解析库,DOM形式的解析器.接口和丰富的遍历和修改操作,快速的解析,此外支持XPath1.0实现数据查询,支持unicode编码: 使用Pugixml可通 ...
- Tomjson - 一个"短小精悍"的 json 解析库
Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符 ...
- 【转】编译quickfast解析库(沪深level2行情转码库)
转自http://blog.csdn.net/hacode/article/details/7065889 编译quickfast解析库(沪深level2行情转码库) 目录(?)[-] 1 下载源代 ...
- iOS开源JSON解析库MJExtension
iOS中JSON与NSObject互转有两种方式:1.iOS自带类NSJSONSerialization 2.第三方开源库SBJSON.JSONKit.MJExtension.项目中一直用MJExte ...
- IOS学习:常用第三方库(GDataXMLNode:xml解析库)
IOS学习:常用第三方库(GDataXMLNode:xml解析库) 解析 XML 通常有两种方式,DOM 和 SAX: DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过 ...
- Tomjson - json 解析库
Tomjson - 一个"短小精悍"的 json 解析库 Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把 ...
- go通过swig封装、调用c++共享库的技术总结
go通过swig封装.调用c++共享库的技术总结 @(知识记录) 1 简介 最近在研究golang,希望能对目前既有的python服务做一些优化,这些服务目前已经占用了6-7台机器.选择golang的 ...
- HTML解析库Gumbo简单使用记录
目录 Gumbo简介 使用记录 1.GumboNode的类型 2.简单的使用 Gumbo简介 Gumbo是谷歌开源的一个纯C编写的HTML解析库,性能很好,就是用起来比较麻烦. github地址htt ...
- GDataXMLNode:xml解析库
IOS学习:常用第三方库(GDataXMLNode:xml解析库) 解析 XML 通常有两种方式,DOM 和 SAX: DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过 ...
随机推荐
- java.net.ServerSocket和java.net.Socket
个人博客地址:http://www.cnblogs.com/wdfwolf3/ java.net.ServerSocket 1.构造函数 a.ServerSocket() 创建一个无连接的server ...
- struts2 package元素
<package../>元素 name 必选 包名 extends 可选 继承 namespace ...
- 移动web页面使用微软雅黑字体的问题
很多前端工程师在开发手机页面的时候,发现视觉设计师们喜欢用微软雅黑作为中文字体进行设计,于是写页面的时候也定义 font-family 为微软雅黑,后来发到线上后,细心的产品经理发现页面的字体不是微软 ...
- Day16 DOM &jQuery
一.本节主要内容 JavaScript 正则表达式 字符串操作的三个方法 DOM(知道就行,一般使用jQuery) 查找: 直接查找: document.getElementById 根据ID获取一个 ...
- 《python源码剖析》笔记一——python编译
1.python的架构: 2.python源码的组织结构: 3.windows环境下编译python:
- typedef 类型重命名 和 #define 宏定义(1)
http://www.blogjava.net/jasmine214--love/archive/2010/11/29/339307.html 在现实生活中,信息的概念可能是长度,数量和面积等.在C语 ...
- Android 开发遇到的问题及解决办法
Failed to resolve: com.android.support:appcompat-v7:23.4.0 问题解决办法: 1.在Android SDK Manager中找到对应的SDK版本 ...
- LightOj_1284 Lights inside 3D Grid
题目链接 题意: 给一个X * Y * Z 的立方体, 每个单位立方体内都有一盏灯, 初始状态是灭的, 你每次操作如下: 1)选择一个点(x1, y1, z1) 再选择一个点(x2, y2, ...
- 区分html与css中的属性
CSS中id与Class的区别 1.在CSS文件里书写时,ID加前缀"#":CLASS用"." 2.id一个页面只可以使用一次:class可以多次引用. 3.I ...
- common头文件
#ifndef COMMON_HHH #define COMMON_HHH #define ASSERT(p) \ do{\ if (!p){\ printf("%s:%d\n", ...