1 #-------------------------------------------------------------------------------
2 # elftools: common/construct_utils.py
4 # Some complementary construct utilities
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from ..construct
import (
10 Subconstruct
, ConstructError
, ArrayError
, Adapter
, Field
, RepeatUntil
,
11 Rename
, SizeofError
, Construct
15 class RepeatUntilExcluding(Subconstruct
):
16 """ A version of construct's RepeatUntil that doesn't include the last
17 element (which casued the repeat to exit) in the return value.
19 Only parsing is currently implemented.
21 P.S. removed some code duplication
23 __slots__
= ["predicate"]
24 def __init__(self
, predicate
, subcon
):
25 Subconstruct
.__init
__(self
, subcon
)
26 self
.predicate
= predicate
27 self
._clear
_flag
(self
.FLAG_COPY_CONTEXT
)
28 self
._set
_flag
(self
.FLAG_DYNAMIC
)
29 def _parse(self
, stream
, context
):
32 context_for_subcon
= context
33 if self
.subcon
.conflags
& self
.FLAG_COPY_CONTEXT
:
34 context_for_subcon
= context
.__copy
__()
37 subobj
= self
.subcon
._parse
(stream
, context_for_subcon
)
38 if self
.predicate(subobj
, context
):
41 except ConstructError
as ex
:
42 raise ArrayError("missing terminator", ex
)
44 def _build(self
, obj
, stream
, context
):
45 raise NotImplementedError('no building')
46 def _sizeof(self
, context
):
47 raise SizeofError("can't calculate size")
51 """ Read LEB128 variable-length data from the stream. The data is terminated
52 by a byte with 0 in its highest bit.
55 lambda obj
, ctx
: ord(obj
) < 0x80,
59 class _ULEB128Adapter(Adapter
):
60 """ An adapter for ULEB128, given a sequence of bytes in a sub-construct.
62 def _decode(self
, obj
, context
):
64 for b
in reversed(obj
):
65 value
= (value
<< 7) + (ord(b
) & 0x7F)
69 class _SLEB128Adapter(Adapter
):
70 """ An adapter for SLEB128, given a sequence of bytes in a sub-construct.
72 def _decode(self
, obj
, context
):
74 for b
in reversed(obj
):
75 value
= (value
<< 7) + (ord(b
) & 0x7F)
76 if ord(obj
[-1]) & 0x40:
77 # negative -> sign extend
78 value |
= - (1 << (7 * len(obj
)))
83 """ A construct creator for ULEB128 encoding.
85 return Rename(name
, _ULEB128Adapter(_LEB128_reader()))
89 """ A construct creator for SLEB128 encoding.
91 return Rename(name
, _SLEB128Adapter(_LEB128_reader()))
93 class StreamOffset(Construct
):
95 Captures the current stream offset
98 * name - the name of the value
101 StreamOffset("item_offset")
104 def __init__(self
, name
):
105 Construct
.__init
__(self
, name
)
106 self
._set
_flag
(self
.FLAG_DYNAMIC
)
107 def _parse(self
, stream
, context
):
109 def _build(self
, obj
, stream
, context
):
110 context
[self
.name
] = stream
.tell()
111 def _sizeof(self
, context
):