Skip to content

Commit 91cc253

Browse files
authored
Merge pull request #3443 from trailofbits/perf/lazy-kaitai
perf: lazy load Kaitai parsers and remove unused imports
2 parents f8d1e2b + 9597a43 commit 91cc253

1 file changed

Lines changed: 30 additions & 23 deletions

File tree

polyfile/kaitaimatcher.py

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
from kaitaistruct import KaitaiStruct, KaitaiStructError
66

77
from .kaitai.parser import ASTNode, KaitaiParser, RootNode
8-
from .kaitai.parsers.gif import Gif
9-
from .kaitai.parsers.jpeg import Jpeg
10-
from .kaitai.parsers.png import Png
118
from .logger import getStatusLogger
129
from .polyfile import register_parser, InvalidMatch, Match, Parser, Submatch
1310

@@ -83,31 +80,41 @@ def ast_to_matches(ast: RootNode, parent: Match) -> Iterator[Submatch]:
8380
stack.extend(reversed([(new_node, c) for c in node.children]))
8481

8582

86-
for mimetype, kaitai_path in KAITAI_MIME_MAPPING.items():
87-
class parse_:
88-
kaitai_parser = KaitaiParser.load(kaitai_path)
89-
90-
def __call__(self, stream, match):
91-
try:
92-
ast = self.kaitai_parser.parse(stream).ast
93-
except KaitaiStructError as e:
94-
log.warning(f"Error parsing {stream.name} using {self.kaitai_parser}: {e!s}")
95-
raise InvalidMatch()
96-
except Exception as e:
97-
log.error(f"Unexpected exception parsing {stream.name} using {self.kaitai_parser}: {e!s}")
98-
raise InvalidMatch()
99-
yield from ast_to_matches(ast, parent=match)
83+
class LazyKaitaiParser:
84+
"""Parser that lazily loads the Kaitai struct parser on first use."""
10085

101-
func_name = mimetype.replace("/", "_").replace("-", "_")
86+
def __init__(self, kaitai_path: str, mimetype: str):
87+
self.kaitai_path = kaitai_path
88+
self.mimetype = mimetype
89+
self._kaitai_parser = None
90+
91+
@property
92+
def kaitai_parser(self):
93+
if self._kaitai_parser is None:
94+
self._kaitai_parser = KaitaiParser.load(self.kaitai_path)
95+
MIME_BY_PARSER[self._kaitai_parser.struct_type] = self.mimetype
96+
return self._kaitai_parser
10297

103-
parse_.__name__ = f"{parse_.__name__}{func_name}"
104-
parse_.__qualname__ = f"{parse_.__qualname__}{func_name}"
98+
def __call__(self, stream, match):
99+
try:
100+
ast = self.kaitai_parser.parse(stream).ast
101+
except KaitaiStructError as e:
102+
log.warning(f"Error parsing {stream.name} using {self.kaitai_parser}: {e!s}")
103+
raise InvalidMatch()
104+
except Exception as e:
105+
log.error(f"Unexpected exception parsing {stream.name} using {self.kaitai_parser}: {e!s}")
106+
raise InvalidMatch()
107+
yield from ast_to_matches(ast, parent=match)
105108

106-
register_parser(mimetype)(parse_())
107109

108-
MIME_BY_PARSER[parse_.kaitai_parser.struct_type] = mimetype
110+
for mimetype, kaitai_path in KAITAI_MIME_MAPPING.items():
111+
func_name = mimetype.replace("/", "_").replace("-", "_")
112+
parser = LazyKaitaiParser(kaitai_path, mimetype)
113+
parser.__name__ = f"parse_{func_name}"
114+
parser.__qualname__ = f"parse_{func_name}"
115+
register_parser(mimetype)(parser)
109116

110117
del func_name
111118
del kaitai_path
112119
del mimetype
113-
del parse_
120+
del parser

0 commit comments

Comments
 (0)