diff --git a/parsers/s3_parser.py b/parsers/s3_parser.py index 2f32933..4b8a2bc 100644 --- a/parsers/s3_parser.py +++ b/parsers/s3_parser.py @@ -33,7 +33,7 @@ STX = 0x02 ETX = 0x03 ACK = 0x41 -__version__ = "0.2.3" +__version__ = "0.2.4" @dataclass @@ -184,9 +184,9 @@ def validate_bw_body_auto(body: bytes) -> Optional[Tuple[bytes, bytes, str]]: def parse_s3(blob: bytes, trailer_len: int) -> List[Frame]: frames: List[Frame] = [] - IDLE = 0 - IN_FRAME = 1 - AFTER_DLE = 2 + IDLE = 0 + IN_FRAME = 1 + IN_FRAME_DLE = 2 # saw DLE inside frame — waiting for next byte state = IDLE body = bytearray() @@ -206,22 +206,15 @@ def parse_s3(blob: bytes, trailer_len: int) -> List[Frame]: state = IN_FRAME i += 2 continue + # ACK bytes, boot strings, garbage — silently ignored elif state == IN_FRAME: if b == DLE: - state = AFTER_DLE + state = IN_FRAME_DLE i += 1 continue - body.append(b) - - else: # AFTER_DLE - if b == DLE: - body.append(DLE) - state = IN_FRAME - i += 1 - continue - if b == ETX: + # Bare ETX = real S3 frame terminator (confirmed from S3FrameParser) end_offset = i + 1 trailer_start = i + 1 trailer_end = trailer_start + trailer_len @@ -259,13 +252,27 @@ def parse_s3(blob: bytes, trailer_len: int) -> List[Frame]: state = IDLE i = trailer_end continue + body.append(b) + else: # IN_FRAME_DLE + if b == DLE: + # DLE DLE → literal 0x10 in payload + body.append(DLE) + state = IN_FRAME + i += 1 + continue + if b == ETX: + # DLE+ETX inside a frame = inner-frame terminator (A4/E5 sub-frames). + # Treat as literal data, NOT the outer frame end. + body.append(DLE) + body.append(ETX) + state = IN_FRAME + i += 1 + continue # Unexpected DLE + byte → treat as literal data body.append(DLE) body.append(b) state = IN_FRAME - i += 1 - continue i += 1