blob: 36332497a306a79b084447bb6b98daddce910416 [file] [log] [blame]
#-------------------------------------------------------------------------------
# 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()))