You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.8 KiB
91 lines
2.8 KiB
#-------------------------------------------------------------------------------
|
|
# 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()))
|
|
|