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

39 statements  

1import itertools 

2 

3from lark.exceptions import UnexpectedInput 

4from lark.lark import Lark 

5from lark.visitors import Transformer 

6 

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 

14 

15 COMMENT: "//" /(.)+/ NEWLINE? 

16 

17 %ignore COMMENT 

18 

19 start: START_ANCHOR? item+ END_ANCHOR? 

20 

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 

28 

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) 

43 

44 

45class _HexStringToRegex(Transformer): 

46 def literal(self, s): 

47 return f"\\x{s[0]}" 

48 

49 def wildcard(self, _s): 

50 return "." 

51 

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}]" 

58 

59 def second_nible(self, s): 

60 first_nible = s[0][0] 

61 return f"[\\x{first_nible}0-\\x{first_nible}f]" 

62 

63 def jump(self, s): 

64 jump_length = s[0][1:-1] 

65 return f".{{{jump_length}}}" 

66 

67 def range_jump(self, s): 

68 jumps = s[0][1:-1].split("-", 1) 

69 return f".{{{jumps[0]},{jumps[1]}}}" 

70 

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})" 

79 

80 def item(self, s): 

81 return s[0] 

82 

83 def start(self, s): 

84 return "".join(s).encode() 

85 

86 

87class InvalidHexString(ValueError): 

88 pass 

89 

90 

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)