Python学习笔记之struct的unpack与pack一个类的使用示例(一)

今天介绍一个新类,这个类的使用将会简化Python的struct的打包以及解包操作code逻辑(unpack以及pack);是zdataclass,目前出到V0.3;

pip install zdataclass

from zdataclass.zdataclass import *
from dataclasses import dataclass
import dataclasses

1. 带长度域结构(简单结构)

@dataclass
class s_with_length_field(basedataclass):
    '''
    typedef struct s_with_length_field {
        uint8 length;
        uint8 * data;
    }
    '''
    length: uint8 = dataclasses.field(default=None, metadata={DATA_FIELD: 'data'})
    data: bytearray = dataclasses.field(default_factory=bytearray, metadata={LENGTH_FIELD: 'length', UNION_FIELD: True})

上述length取值是依赖于data域的length。

测试示例:

def test_length_field():
    d = s_with_length_field(data=b'\x01\x02')
    print('{}, len={}'.format(d, len(d)))
    print(hexlify(d.pack()))

    d2 = s_with_length_field().unpack(d.pack())
    print('{}, len={}'.format(d2, len(d2)))

    if d2 == d:
        print('test_length_field pass\r\n')
    else:
        print('test_length_field fail\r\n')

if __name__ == '__main__':
    test_length_field()

数据结果:

s_with_length_field(length=0x02(2), data=bytearray(b'\x01\x02')), len=3
b'020102'
s_with_length_field(length=0x02(2), data=bytearray(b'\x01\x02')), len=3
test_length_field pass

2. 带UNION域结构

@dataclass
class s_with_union_field(basedataclass):
    '''
    typedef struct s_with_union_field {
        uint16 hci_length;
        union 
        {
           uint8* hci_data;
           struct {
               uint16 l2c_length;
               uint16 cid;
               uint8* l2c_data;
           }l2c;
        };
    };
    '''
    hci_length: uint16 = dataclasses.field(default=None, metadata={DATA_FIELD: 'hci_data'})
    hci_data: bytearray = dataclasses.field(default_factory=bytearray,
                                            metadata={UNION_FIELD: True, LENGTH_FIELD: 'hci_length'})
    l2c_length: uint16 = dataclasses.field(default=None, metadata={DATA_FIELD: 'l2c_data'})
    cid: uint16 = None
    l2c_data: bytearray = dataclasses.field(default_factory=bytearray,
                                            metadata={UNION_FIELD: True, LENGTH_FIELD: 'l2c_length'})

上述如果单独看Python源码,有些囫囵的感觉,如hci_data中的field中定义的元数据,存在一个UNION_FIELD:True则表示,后续所有element或成员都共享此域存储空间;

此处l2c_length、cid、l2c_data都是共享hci_data存储域的;另外注意的是其中hci_length取值是依赖于hci_data域的length;而l2c_length取值依赖于l2c_data数据length;

下面以一个示例说明这一切:

def test_union_field():
    d = s_with_union_field(cid=0x0040, l2c_data=b'\x01')
    print('{}, len={}'.format(d, len(d)))
    data = d.pack()
    print(hexlify(data))

    d2 = s_with_union_field().unpack(data)
    print('{}, len={}'.format(d2, len(d2)))

    if d2 == d:
        print('test_union_field pass\r\n')
    else:
        print('test_union_field fail\r\n')

if __name__ == '__main__':
    test_union_field()

输出结果:

s_with_union_field(hci_length=0x0005(5), hci_data=bytearray(b'\x01\x00@\x00\x01'), l2c_length=0x0001(1), cid=0x0040(64), l2c_data=bytearray(b'\x01')), len=7
b'05000100400001'
s_with_union_field(hci_length=0x0005(5), hci_data=bytearray(b'\x01\x00@\x00\x01'), l2c_length=0x0001(1), cid=0x0040(64), l2c_data=bytearray(b'\x01')), len=7
test_union_field pass

3. 通用数据结构

@dataclass
class s_with_common_field(basedataclass):
    '''
    # C++中结构示例
    typedef struct s_with_common_field {
        uint8 code;
        uint8 size;
        uint8 *data;
        uint16 crc;
    };
    '''
    code: uint8 = 0x01
    size: uint8 = dataclasses.field(default=None, metadata={DATA_FIELD: 'data'})
    data: bytearray = dataclasses.field(default_factory=bytearray, metadata={LENGTH_FIELD: 'size'})
    crc: uint16 = None

注意上述@dataclass这个在Python3.7中心加入的,而basedataClass就是引用的zdataclass类接口;在类中使用的uint8、uint16、uint32都是重新封装的;

具体可以看源码定义。在上述值得关注的就是size与data域定义,注意metadata里面的内容,在data中定义有LENGTH_FIELD域,输入指定bytearray,其size自动赋值的;

测试案例:

def test_with_common_field():
    
    # 此处的两个值只是简单的示例数据
    # 实际应用中可自行输入数据
    payload = b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00'
    crc = crc16(payload)
    
    # 注意data的输入
    # crc的赋值
    d = s_with_common_field(data=payload, crc=crc)
    print('1: {}, len={}'.format(d, len(d)))
    
    # 数据打包
    data = d.pack()
   
    # 数据解包
    d2 = s_with_common_field().unpack(data)
    print('2: {}, len={}'.format(d2, len(d2)))

    print(hexlify(data))

if __name__ == '__main__':
    test_with_common_field()

输出结果:

1: s_with_common_field(code=0x01(1), size=0x0a(10), data=bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x00'), crc=0x6c01(27649)), len=14
2: s_with_common_field(code=0x01(1), size=0x0a(10), data=bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x00'), crc=0x6c01(27649)), len=14
b'010a01020304050607080900016c'

上述非常快捷的打包、解包一个较简单的数据结构。

Python学习笔记之struct的unpack与pack一个类的使用示例(二)

猜你喜欢

转载自blog.csdn.net/xsophiax/article/details/89674883