#------------------------------------------------------------------------------- # elftools: common/construct_utils.py # # Some complementary construct utilities # # Eli Bendersky (eliben@gmail.com) # This code is in the public domain #------------------------------------------------------------------------------- from ..construct import ( Subconstruct, ConstructError, ArrayError, Adapter, Field, RepeatUntil, Rename ) class RepeatUntilExcluding(Subconstruct): """ A version of construct's RepeatUntil that doesn't include the last element (which casued the repeat to exit) in the return value. Only parsing is currently implemented. P.S. removed some code duplication """ __slots__ = ["predicate"] def __init__(self, predicate, subcon): Subconstruct.__init__(self, subcon) self.predicate = predicate self._clear_flag(self.FLAG_COPY_CONTEXT) self._set_flag(self.FLAG_DYNAMIC) def _parse(self, stream, context): obj = [] try: context_for_subcon = context if self.subcon.conflags & self.FLAG_COPY_CONTEXT: context_for_subcon = context.__copy__() while True: subobj = self.subcon._parse(stream, context_for_subcon) if self.predicate(subobj, context): break obj.append(subobj) except ConstructError as ex: raise ArrayError("missing terminator", ex) return obj def _build(self, obj, stream, context): raise NotImplementedError('no building') def _sizeof(self, context): raise SizeofError("can't calculate size") def _LEB128_reader(): """ Read LEB128 variable-length data from the stream. The data is terminated by a byte with 0 in its highest bit. """ return RepeatUntil( lambda obj, ctx: ord(obj) < 0x80, Field(None, 1)) class _ULEB128Adapter(Adapter): """ An adapter for ULEB128, given a sequence of bytes in a sub-construct. """ def _decode(self, obj, context): value = 0 for b in reversed(obj): value = (value << 7) + (ord(b) & 0x7F) return value class _SLEB128Adapter(Adapter): """ An adapter for SLEB128, given a sequence of bytes in a sub-construct. """ def _decode(self, obj, context): value = 0 for b in reversed(obj): value = (value << 7) + (ord(b) & 0x7F) if ord(obj[-1]) & 0x40: # negative -> sign extend value |= - (1 << (7 * len(obj))) return value def ULEB128(name): """ A construct creator for ULEB128 encoding. """ return Rename(name, _ULEB128Adapter(_LEB128_reader())) def SLEB128(name): """ A construct creator for SLEB128 encoding. """ return Rename(name, _SLEB128Adapter(_LEB128_reader()))