namedstruct是一个解析二进制结构体的专用库,它不仅可以解析简单的C结构体,还可以支持变长结构体、可扩展的结构体之类复杂的情况。它被用来在VLCP中解析OpenFlow(SDN专用的二进制协议)。
使用这个库,你会发现,即便是像OpenFlow这样复杂的协议,实际上只需要将对应的C程序的头文件(比如openflow.h)按照相应的规则进行修改,添加一些简单的参数说明结构体之间的关系,就可以用一行代码将它完整解析出来,或者用一行代码生成出相应的结构体。
可以使用pip安装:
pip install nstruct示例###### BASIC STRUCT #####from namedstruct import *mytype = nstruct((uint16, 'myshort'), # unsigned short int (uint8, 'mybyte'), # unsigned char (uint8,), # a padding byte of unsigned char (char[5], 'mystr'), # a 16-byte bytes string (uint8,), (uint16[5], 'myarray'), # name = 'mytype', padding = 1)# Create an objectobj0 = mytype()# Access a fields = obj0.myshortobj0.myshort = 12# Create an object with the specified fields initializedobj1 = mytype(myshort = 2, mystr = b'123', myarray = [1,2,3,4,5]) # Unpack an object from stream, return the object and bytes size usedobj2,size = mytype.parse(b'\x00\x02\x01\x00123\x00\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05')# Unpack an object from packed bytesobj3 = mytype.create(b'\x00\x02\x01\x00123\x00\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05')# Estimate the struct sizesize = len(obj0)# Estimate the struct size excludes automatic padding bytessize2 = obj0._realsize()# Pack the objectb = obj0._tobytes()b2 = mytype.tobytes(obj0)# Use the type in other structsmytype2 = nstruct((mytype, 'mydata'), (mytype[4], 'mystructarray'), name = 'mytype2', padding = 1)obj4 = mytype2()obj4.mydata.myshort = 12obj4.mystructarray[0].mybyte = 7b3 = obj4._tobytes()###### VARIABLE LENGTH TYPES #####my_unsize_struct = nstruct((uint16, 'length'), (raw, 'data'), padding = 1, name = 'my_unsize_struct')""">>> my_unsize_struct.create(b'\x00\x07abcde').datab'abcde'>>> my_unsize_struct.parse(b'\x00\x07abcde')[0].datab''"""my_size_struct = nstruct((uint16, 'length'), (raw, 'data'), padding = 1, name = 'my_size_struct', prepack = packrealsize('length'), size = lambda x: x.length)"""packrealsize('length') is equivalent to: def _packsize(x): x.length = x._realsize()"""""">>> my_unsize_struct(data = b'abcde')._tobytes()b'\x00\x07abcde'>>> my_unsize_struct.parse(b'\x00\x07abcde')[0].datab'abcde'"""##### EXTENDING #####my_base = nstruct((uint16, 'length'), (uint8, 'type'), (uint8, 'basedata'), name = 'my_base', size = lambda x: x.length, prepack = packrealsize('length'), padding = 4)my_child1 = nstruct((uint16, 'data1'), (uint8, 'data2'), name = 'my_child1', base = my_base, criteria = lambda x: x.type == 1, init = packvalue(1, 'type'))my_child2 = nstruct((uint32, 'data3'), name = 'my_child2', base = my_base, criteria = lambda x: x.type == 2, init = packvalue(2, 'type'))"""Fields and most base class options are inherited, e.g. size, prepack, padding>>> my_child1(basedata = 1, data1 = 2, data2 = 3)._tobytes()b'\x00\x07\x01\x01\x00\x02\x03\x00'>>> my_child2(basedata = 1, data3 = 4)._tobytes()b'\x00\x08\x02\x01\x00\x00\x00\x04'"""# Fields in child classes are automatically parsed when the type is determinedobj1, _ = my_base.parse(b'\x00\x07\x01\x01\x00\x02\x03\x00')""">>> obj1.basedata1>>> obj1.data12>>> obj1.data23>>> obj1._gettype()my_child1"""# Base type can be used in fields or arrays of other structsmy_base_array = nstruct((uint16, 'total_len'), (my_base[0], 'array'), name = 'my_base_array', padding = 1, size = lambda x: x.total_len, prepack = packrealsize('total_len'))obj2 = my_base_array()obj2.array.append(my_child1(data1 = 1, data2 = 2, basedata = 3))obj2.array.append(my_child2(data3 = 4, basedata = 5))""">>> obj2._tobytes()b'\x00\x12\x00\x07\x01\x03\x00\x01\x02\x00\x00\x08\x02\x05\x00\x00\x00\x04'"""obj3, _ = my_base_array.parse(b'\x00\x12\x00\x07\x01\x03\x00\x01\x02\x00\x00\x08\x02\x05\x00\x00\x00\x04')""">>> obj3.array[0].data22"""
评论