Python 如何让construct.greedRange返回一个字节?

Python 如何让construct.greedRange返回一个字节?,python,struct,enums,construct,Python,Struct,Enums,Construct,好吧,假设我让它完全按照预期工作: 从enum导入IntEnum 从contstruct导入* 夏令营: 开始=0xAB 停止=0xBC ESC=0xCD MAPPING=MappingByte,{x:x+1表示字符中的x} 滑动=格里迪范围 选择 聚焦均衡 “x”, ConstChar.ESC,字节, 重命名贴图“x” , 字节 例如: >>>缓冲区=字节[0x00,0xAB,0xBC,0xCD,0xFF] >>>滑动缓冲区 b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff

好吧,假设我让它完全按照预期工作:

从enum导入IntEnum 从contstruct导入* 夏令营: 开始=0xAB 停止=0xBC ESC=0xCD MAPPING=MappingByte,{x:x+1表示字符中的x} 滑动=格里迪范围 选择 聚焦均衡 “x”, ConstChar.ESC,字节, 重命名贴图“x” , 字节 例如:

>>>缓冲区=字节[0x00,0xAB,0xBC,0xCD,0xFF] >>>滑动缓冲区 b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff' 以及:

>>>从运算符导入eq >>>allmapeq,SLIP.parseSLIP.buildbuffer,buffer 符合事实的 现在我需要将编码/解码包装到另一个结构中:

协议=聚焦均衡 "讯息",, ConstChar.START,字节, 重命名纸条,“消息”, ConstChar.STOP,字节 构建完全按照预期工作:

>>>PROTOCOL.buildbuffer b'\xab\x00\xcd\xac\xcd\xbd\xcd\xce\xff\xbc' 但是,解析时,GreedyRange消耗的字节太多:

>>>协议.parseb'\xab\x00\xcd\xac\xcd\xbd\xcd\xce\xff\xbc' construct.core.StreamError:流读取少于指定量,应为1,找到0
如何让GreedyRange返回一个字节?

在您的情况下,您可以简单地重新排列协议字段并在末尾添加SLIP

PROTOCOL = FocusedSeq(
    'message',
    Const(Char.START, Byte),
    Const(Char.STOP, Byte),
    Renamed(SLIP, 'message')
)
这样,GreedyRange将不会使用导致流分析错误的所有字节:construct.core.StreamError:流读取少于指定数量,应为1,找到0

以下是一个修改后的示例:

from construct import Byte, Const, FocusedSeq, GreedyRange, Mapping, Renamed, Select
from enum import IntEnum


class Char(IntEnum):
    START = 0xAB
    STOP = 0xBC
    ESC = 0xCD

MAPPING = Mapping(Byte, {x: x+1 for x in Char})

SLIP = GreedyRange(
    Select(
        FocusedSeq(
            'x',
            Const(Char.ESC, Byte),
            Renamed(MAPPING, 'x')
        ),
        Byte
    )
)
buffer = bytes([0x00, 0xAB, 0xBC, 0xCD, 0xFF])

slip_build = SLIP.build(buffer)
assert slip_build == b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff'
slip_parsed = SLIP.parse(b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff')

PROTOCOL = FocusedSeq(
    'message',
    Const(Char.START, Byte),
    Const(Char.STOP, Byte),
    Renamed(SLIP, 'message')
)

protocol_build = PROTOCOL.build(buffer)
assert protocol_build == b'\xab\xbc\x00\xcd\xac\xcd\xbd\xcd\xce\xff'
protocol_parsed = PROTOCOL.parse(protocol_build)
assert protocol_parsed == slip_parsed
解决方案是NullTerminated…,term=STOP,它在内部缓冲底层流,并在必要时返回

PROTOCOL = FocusedSeq(
    'message'
    Const(Char.START, Byte),
    message=NullTerminated(
        # NOTE build consumes entire stream and appends STOP
        # NOTE parse consumes steam until STOP and passes buffer to GreedyRange
        GreedyRange(
            Select(
                FocusedSeq(
                    'x',
                    Const(Char.ESC, Byte),
                    x=MAPPING  # NOTE intentionally raises MappingError
                ),
                Byte  # NOTE fallback for MappingError
            )
        ),
        term=Byte.build(Char.STOP)
    )
)

另一种方法是使用修改字节序列

下面是另一个代码示例:

from construct import Byte, Const, FocusedSeq, GreedyRange, \
    If, Mapping, Renamed, Select, this, Adapter
from enum import IntEnum


class Char(IntEnum):
    START = 0xAB
    STOP = 0xBC
    ESC = 0xCD

MAPPING = Mapping(Byte, {x: x+1 for x in Char})

SLIP = GreedyRange(
    Select(
        FocusedSeq(
            'x',
            Const(Char.ESC, Byte),
            Renamed(MAPPING, 'x')
        ),
        Byte
    )
)
buffer = bytes([0x00, 0xAB, 0xBC, 0xCD, 0xFF])

slip_build = SLIP.build(buffer)
assert slip_build == b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff'
slip_parsed = SLIP.parse(b'\x00\xcd\xac\xcd\xbd\xcd\xce\xff')


class ProtocolAdapter(Adapter):
    def _decode(self, obj, context, path):

        # remove first and last bite
        obj.pop(0)
        obj.pop(-1)
        return obj

    def _encode(self, obj, context, path):
        return obj

PROTOCOL = FocusedSeq(
    "message",
    If(this._building == True, Const(Char.START, Byte)),
    "message" / SLIP,
    If(this._building == True, Const(Char.STOP, Byte))

)
ADAPTED_PROTOCOL = ProtocolAdapter(PROTOCOL)

protocol_build = ADAPTED_PROTOCOL.build(buffer)
assert protocol_build == b'\xab\x00\xcd\xac\xcd\xbd\xcd\xce\xff\xbc'
protocol_parsed = ADAPTED_PROTOCOL.parse(protocol_build)
assert protocol_parsed == slip_parsed

不幸的是,这是不对的;生成的缓冲区必须以BC结尾,而不是第二个字符