资讯专栏INFORMATION COLUMN

[Android] PacketParser 二进制协议转换工具

chnmagnus / 2204人阅读

摘要:表达式内可通过引用任意方法。表示可出现次或多次,包装在中。注意仅可用于最后一个元素会先解析父类留意代码中注释标注出的新特性。

这个工具通过自动生成解析类,实现了字节数组和对象之间的转换。

1. 0.40更新

版本0.40发布,更新内容如下所示:

支持继承

支持对象作为字段

支持条件解析字段

支持忽略字段

支持对象List

使用0.40版本,你可以做到:

以TLV格式的数据为例,首先定义一个基类:

@ParsePacket({
        "type:1",
        "length:2",
        "~value:this.length" // ~表示解析该字段但不会移动buffer的cursor
})
public class TLVHeaderObject {
    public byte type;
    public short length;
    public byte[] value;
}

再定义一个普通的TLV类:

@ParsePacket({
    "type:1",
    "length:2",
    "value:this.length"
})
public class TLVObject {
    public byte type;
    public short length;
    public byte[] value;
}

对于任意一个TLV协议单元,可以定义一个类继承TLVHeaderObject:

@ParsePacket({
        "tlvObject", // 字段可以是任意以@ParsePacket标注的类,无需指定数据长度
        "c:4",
        "2a:4", // 字段名前的数字表示该字段出现的次数,包装在List中
        "[this.c > 0x02]*b", // “[]”中括号内的为条件解析语句,括号内的表达式为true才会解析该字段。
                             // 表达式内可通过this引用任意public方法。
                             // “*b”表示b可出现0次或多次,包装在List中。注意“*”仅可用于最后一个元素
})
public class TLVHolderListObject extends TLVHeaderObject /* 会先解析父类 */ {
    public TLVObject tlvObject;
    public int c;
    public List a;
    public List b;
}

留意代码中注释标注出的新特性。

编译项目后,可以通过如下测试:

byte[] bytes = hexToBytes("0a000fBB0003010101000000030000000100000002BB0003010100BB000101BB00020101");

// 使用生成的TLVHolderListObjectPacketParser解析字节数组
TLVHolderListObject tlvHolderListObject = TLVHolderListObjectPacketParser.parse(bytes);

// 检查TLV头部,即继承TLVHeaderObject的部分
assertEquals((byte) 0x0A, tlvHolderListObject.type);
assertEquals(0x000f, tlvHolderListObject.length);

// 检查对象作为字段
assertEquals((byte) 0xBB, tlvHolderListObject.tlvObject.type);
assertEquals(0x0003, tlvHolderListObject.tlvObject.length);
assertArrayEquals(new byte[]{0x01, 0x01, 0x01}, tlvHolderListObject.tlvObject.value);

// 检查普通字段
assertEquals(0x3, tlvHolderListObject.c);

// 检查列表字段
assertEquals(Integer.valueOf(0x1), tlvHolderListObject.a.get(0));
assertEquals(Integer.valueOf(0x2), tlvHolderListObject.a.get(1));

// 依次检查列表对象
assertEquals(3, tlvHolderListObject.b.size());

TLVObject b0 = tlvHolderListObject.b.get(0);
assertEquals((byte) 0xBB, b0.type);
assertEquals(0x0003, b0.length);
assertArrayEquals(new byte[]{0x01, 0x01, 0x00}, b0.value);

TLVObject b1 = tlvHolderListObject.b.get(1);
assertEquals((byte) 0xBB, b1.type);
assertEquals(0x0001, b1.length);
assertArrayEquals(new byte[]{0x01}, b1.value);

TLVObject b2 = tlvHolderListObject.b.get(2);
assertEquals((byte) 0xBB, b2.type);
assertEquals(0x0002, b2.length);
assertArrayEquals(new byte[]{0x01, 0x01}, b2.value);

// 检查对象转字节数组
byte[] toBytes = TLVHolderListObjectPacketParser.toBytes(tlvHolderListObject);
assertArrayEquals(bytes, toBytes);
2. 介绍 2.1. 使用@ParsePacket注解标注实体类
@ParsePacket(
    "header:1", // 需要按照解析的顺序写
    "cmd:2", // 格式为:[字段名:数据长度]
    "len:2", // 数据长度需要与数据类型对应,如例子所示
    "seq:2",
    "mac:6",
    "data:this.len-6", // 可以用“this.fieldname”来引用任意public的属性或方法
    "check:1",
    "tail:1"
)
public class TargetObject {
    public byte header;
    public short cmd;
    public short len;
    public short seq;
    public byte[] mac;
    public byte[] data;
    public byte check;
    public byte tail;
}
2.2. 框架自动生成解析类 <类名>PacketParser
public class TargetObjectPacketParser {
    public static final TargetObject parse(byte[] src) {
        return parse(src, new TargetObject());
    }

    public static final TargetObject parse(byte[] bytes, TargetObject src) {
        ...
        return src;
    }

    public static final byte[] toBytes(TargetObject src) {
        ...
        return byteBuffer.array();
    }
}

注:需Builder一次项目,PacketParser才会生成。

2.3. 使用方法
String data = "AA11220008556677889911223344556677";
byte[] bytes = hexToBytes(data);
// bytes to object
TargetObject targetObject = TargetObjectPacketParser.parse(bytes); // suffix with "PacketParser"
//object to bytes
byte[] toBytes = TargetObjectPacketParser.toBytes(targetObject);

Gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        ...
        classpath "com.neenbedankt.gradle.plugins:android-apt:1.8" // add this
        ...
    }
}

apply plugin: "com.android.application"
apply plugin: "com.neenbedankt.android-apt"

apt "com.squareup:javapoet:1.8.0"
apt "com.google.auto:auto-common:0.6"
apt "com.google.auto.service:auto-service:1.0-rc2"
apt "com.legendmohe.maven:packetparser-compiler:x.y"
compile "com.legendmohe.maven:packetparser-annotation:x.y"

packetparser-compiler
packetparser-annotation

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/13127.html

相关文章

  • 【干货】测试Android应用安全性

    摘要:在应用程序的渗透测试期间,通常需要修改应用程序的源代码以绕过绑定,检查篡改保护,绕过应用程序逻辑等步骤。在本文中,我们将介绍成功修改源代码的过程。因此,下一步是创建一个密钥对,并使用该签名进行签名。 想要开发一款安全的Android应用程序,最佳方法之一是进行渗透测试,其实际情况就是模拟攻击者对你的应用程序进行破解分析!首先、我们设置测试环境;其次、我们讨论一些工具和代理技术--Dro...

    sushi 评论0 收藏0
  • Android包管理机制(一) PackageInstaller的初始化

    摘要:类名描述用于向应用程序进程提供一些功能,最终的功能是由来实现的一个的接口,用于和进行进程间通信用于权限动态检测在中被引入提供安装升级和删除应用程序功能用于多用户管理注释处的方法如下所示。前言 包管理机制是Android中的重要机制,是应用开发和系统开发需要掌握的知识点之一。 包指的是Apk、jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一个机制...

    番茄西红柿 评论0 收藏0
  • Android学习路线

    摘要:这是网上抄的一篇学习路径,希望记录下来以供自己随时的学习,所有的博客也基本按照里面的知识点来发散。这是网上抄的一篇Android学习路径,希望记录下来以供自己随时的学习,所有的博客也基本按照里面的知识点来发散。   1Java 基础   Java Object类方法 HashMap原理,Hash冲突,并发集合,线程安全集合及实现原理 HashMap 和 HashTable 区别 ...

    paulquei 评论0 收藏0
  • Android 技能图谱学习路线

    摘要:这里是在网上找到的一片学习路线,希望记录下来供以后学习基础类方法原理,冲突,并发集合,线程安全集合及实现原理和区别作用,如何重载方法与区别与联系机制反射机制,代理模式泛型原理实现原理方法锁对象锁类锁的意义和区别线程同步的方法分析锁的种类这里是在网上找到的一片Android学习路线,希望记录下来供以后学习   1Java 基础   Java Object类方法 HashMap原理,Ha...

    Wildcard 评论0 收藏0
  • Android开发需要了解的 IM 知识

    摘要:引言即便在通讯如此发达的今天,也依然是诸多场景下非常重要的基础能力。因此做为一名开发,不可避免的会遇到一些相关的需求或问题。本文以一个开发的角度来讲述开发相关的基础知识。了解网易云信,来自网易核心架构的通信与视频云服务。 引言即便在通讯如此发达的今天,IM 也依然是诸多场景下非常重要的基础能力。因此做为 一名 Android 开发,不可避免的会遇到一些IM 相关的需求或问题。本文以一个...

    graf 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<