使用构造解析索引列表

时间:2018-05-04 09:15:31

标签: python construct

假设文件格式定义如下:

size (uint32)
some_list[size] (uint32)
size_indexes (uint32)
other_list[size_indexes] (uint32)

所以有一个列表some_list包含一些整数,然后还有另一个包含other_list索引的列表some_list

我可以用以下方式解析整个结构:

from construct import *

fmt = Struct(
        "size" / Int32ul,
        "some_list" / Array(this.size, Int32ul),
        "size_indexes" / Int32ul,
        "other_list" / Array(this.size_indexes, Int32ul),
        )

print(fmt.parse(b"\x02\x00\x00\x00\x23\x42\x23\x42\x13\x37\x13\x37\x04\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"))

给了我

Container: 
    size = 2
    some_list = ListContainer: 
        1109606947
        924006163
    size_indexes = 4
    other_list = ListContainer: 
        1
        1
        0
        1

现在我已经解析了fileformat,从中构建python对象的首选方法是什么?例如,我想让它包含实际值,而不是让other_list包含索引。 你会在它周围包裹另一个具有这种能力的物体,例如:

from construct import *

fmt = Struct(
        "size" / Int32ul,
        "some_list" / Array(this.size, Int32ul),
        "size_indexes" / Int32ul,
        "other_list" / Array(this.size_indexes, Int32ul),
        )


class MyFormat:
    def __init__(self, raw):
        self._parsed = fmt.parse(raw)

    @property
    def other_list(self):
        for idx in self._parsed.other_list:
            yield self._parsed.some_list[idx]



container = MyFormat(b"\x02\x00\x00\x00\x23\x42\x23\x42\x13\x37\x13\x37\x04\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00")

print(list(container.other_list))

打印:

[924006163, 924006163, 1109606947, 924006163]

有更好,更首选的方式吗?

1 个答案:

答案 0 :(得分:0)

如果struct代码不太复杂,则可以使用construct库提供的类。对于您的情况,我将尝试IfThenElseRepeatUntil类仅使用一个struct来构建和解析二进制数据。

这里是示例:

import construct

def repeat_handler( x, lst, ctx):
    lst[-1] = ctx.some_list[x]
    return len(lst) == ctx.size_indexes

my_struct = Struct(
        "s" / Int32ul,
        "some_list" / Array(this.s, Int32ul),
        "size_indexes" / Int32ul,
        "other_list" / construct.IfThenElse(this._parsing,
                                            RepeatUntil(repeat_handler, construct.Int32ul),
                                            Array(this.size_indexes, Int32ul))
        )


built_struct = my_struct.build(dict(s=2, some_list=[1109606947, 924006163], size_indexes=4, other_list=[1, 1, 0, 1]))
print(built_struct)

parsed_struct = my_struct.parse(built_struct)
print(parsed_struct)

assert parsed_struct.other_list == [924006163, 924006163, 1109606947, 924006163]