Construct框架RepeatUntil处理器使用疑问及非递增ID适配
问题:Construct框架处理非递增ID的二进制数组结构
在使用Construct框架处理二进制结构时,遇到如下场景:结构包含numResults(Int16ul)字段,以及对应数量的resultItems数组;每个resultItems由ID(不总是递增)、strLen、my_str[strLen]组成。已知需要使用RepeatUntil组件,但不清楚其重复处理器的工作逻辑,当前代码仅在ID递增时有效,求指导如何实现非递增ID下遍历所有resultItems。
原代码示例
import construct as ct from pprint import pprint def repeat_handler( x, lst, ctx): pprint(f'{x=}, {lst=}, {ctx=}') pprint(f'{ctx.numResults=}, {x["ID"]=}') return ctx.numResults==x["ID"] format = ct.Struct( 'numResults' / ct.Int16ul, 'resultItem' / ct.RepeatUntil(repeat_handler, ct.Struct( 'ID' / ct.Int16ul, 'strLen' / ct.Int16ul, 'my_str' / ct.PascalString(ct.Computed(ct.this.strLen) , 'ISO-8859-1'), ), ), )
测试代码
d = dict(numResults=2, resultItem=[ dict(ID=0, strLen=3, my_str='abc'), dict(ID=1, strLen=3, my_str='abc'), dict(ID=2, strLen=3, my_str='abc')] ) f= format.build(d) pprint(f) pprint(format.parse(f))
解决方案
原代码的问题在于RepeatUntil的停止条件依赖ID与numResults相等,这仅在ID递增且连续的情况下有效。实际上RepeatUntil的处理器函数接收三个参数:
x:刚解析出的当前条目lst:已经解析完成的所有条目组成的列表ctx:解析上下文,包含已解析的numResults字段
正确的停止逻辑应该是判断已解析的条目数量是否达到numResults指定的值,也就是当len(lst)等于ctx.numResults时停止重复,这样完全不依赖ID的取值。
修改后的处理器函数
def repeat_handler(x, lst, ctx): return len(lst) == ctx.numResults
完整修改后代码
import construct as ct from pprint import pprint def repeat_handler(x, lst, ctx): # 已解析条目数等于指定数量时停止 return len(lst) == ctx.numResults format = ct.Struct( 'numResults' / ct.Int16ul, 'resultItem' / ct.RepeatUntil( repeat_handler, ct.Struct( 'ID' / ct.Int16ul, 'strLen' / ct.Int16ul, 'my_str' / ct.PascalString(ct.Computed(ct.this.strLen), 'ISO-8859-1'), ), ), ) # 测试非递增ID场景 d = dict( numResults=2, resultItem=[ dict(ID=5, strLen=3, my_str='abc'), dict(ID=2, strLen=3, my_str='def') ] ) f = format.build(d) pprint(f) pprint(format.parse(f))
这样修改后,无论ID是任意值,只要numResults与实际条目数量匹配,就能正确解析出所有resultItem。
内容的提问来源于stack exchange,提问作者Startin Mohanzl
相关产品推荐
相关产品推荐

