Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/unblob/parser.py: 87%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import itertools
3from lark.exceptions import UnexpectedInput
4from lark.lark import Lark
5from lark.visitors import Transformer
7_hex_string_parser = Lark(
8 """
9 %import common.HEXDIGIT
10 %import common.NUMBER
11 %import common.NEWLINE
12 %import common.WS
13 %ignore WS
15 COMMENT: "//" /(.)+/ NEWLINE?
17 %ignore COMMENT
19 start: START_ANCHOR? item+ END_ANCHOR?
21 item: LITERAL -> literal
22 | WILDCARD -> wildcard
23 | FIRSTNIBLE -> first_nible
24 | SECONDNIBLE -> second_nible
25 | JUMP -> jump
26 | RANGE_JUMP -> range_jump
27 | alternative
29 alternative: "(" item+ (ALTERNATIVE_SEPARATOR item+)+ ")"
30 ALTERNATIVE_SEPARATOR: "|"
31 LITERAL: HEXDIGIT HEXDIGIT
32 START_ANCHOR: "^"
33 END_ANCHOR: "$"
34 WILDCARD: "??"
35 FIRSTNIBLE: "?" HEXDIGIT
36 SECONDNIBLE: HEXDIGIT "?"
37 JUMP: "[" NUMBER "]"
38 RANGE_JUMP: "[" NUMBER "-" NUMBER "]"
39""",
40 parser="lalr",
41 lexer="basic",
42)
45class _HexStringToRegex(Transformer):
46 def literal(self, s):
47 return f"\\x{s[0]}"
49 def wildcard(self, _s):
50 return "."
52 def first_nible(self, s):
53 second_nible = s[0][1]
54 byte_list = ",".join(
55 [f"\\x{first_nible:x}{second_nible}" for first_nible in range(16)]
56 )
57 return f"[{byte_list}]"
59 def second_nible(self, s):
60 first_nible = s[0][0]
61 return f"[\\x{first_nible}0-\\x{first_nible}f]"
63 def jump(self, s):
64 jump_length = s[0][1:-1]
65 return f".{{{jump_length}}}"
67 def range_jump(self, s):
68 jumps = s[0][1:-1].split("-", 1)
69 return f".{{{jumps[0]},{jumps[1]}}}"
71 def alternative(self, s):
72 spl = [
73 "".join(body)
74 for x, body in itertools.groupby(s, lambda item: item == "|")
75 if not x
76 ]
77 alternatives = "|".join(spl)
78 return f"({alternatives})"
80 def item(self, s):
81 return s[0]
83 def start(self, s):
84 return "".join(s).encode()
87class InvalidHexString(ValueError):
88 pass
91def hexstring2regex(hexastr):
92 try:
93 parsed = _hex_string_parser.parse(hexastr)
94 except UnexpectedInput as e:
95 raise InvalidHexString(str(e)) from e
96 return _HexStringToRegex().transform(parsed)