Upstream version 8.36.161.0
[platform/framework/web/crosswalk.git] / src / third_party / pyelftools / elftools / construct / adapters.py
1 from .core import Adapter, AdaptationError, Pass
2 from .lib import int_to_bin, bin_to_int, swap_bytes
3 from .lib import FlagsContainer, HexString
4 from .lib.py3compat import BytesIO, decodebytes
5
6
7 #===============================================================================
8 # exceptions
9 #===============================================================================
10 class BitIntegerError(AdaptationError):
11     __slots__ = []
12 class MappingError(AdaptationError):
13     __slots__ = []
14 class ConstError(AdaptationError):
15     __slots__ = []
16 class ValidationError(AdaptationError):
17     __slots__ = []
18 class PaddingError(AdaptationError):
19     __slots__ = []
20
21 #===============================================================================
22 # adapters
23 #===============================================================================
24 class BitIntegerAdapter(Adapter):
25     """
26     Adapter for bit-integers (converts bitstrings to integers, and vice versa).
27     See BitField.
28     
29     Parameters:
30     * subcon - the subcon to adapt
31     * width - the size of the subcon, in bits
32     * swapped - whether to swap byte order (little endian/big endian). 
33       default is False (big endian)
34     * signed - whether the value is signed (two's complement). the default
35       is False (unsigned)
36     * bytesize - number of bits per byte, used for byte-swapping (if swapped).
37       default is 8.
38     """
39     __slots__ = ["width", "swapped", "signed", "bytesize"]
40     def __init__(self, subcon, width, swapped = False, signed = False, 
41                  bytesize = 8):
42         Adapter.__init__(self, subcon)
43         self.width = width
44         self.swapped = swapped
45         self.signed = signed
46         self.bytesize = bytesize
47     def _encode(self, obj, context):
48         if obj < 0 and not self.signed:
49             raise BitIntegerError("object is negative, but field is not signed",
50                 obj)
51         obj2 = int_to_bin(obj, width = self.width)
52         if self.swapped:
53             obj2 = swap_bytes(obj2, bytesize = self.bytesize)
54         return obj2
55     def _decode(self, obj, context):
56         if self.swapped:
57             obj = swap_bytes(obj, bytesize = self.bytesize)
58         return bin_to_int(obj, signed = self.signed)
59
60 class MappingAdapter(Adapter):
61     """
62     Adapter that maps objects to other objects.
63     See SymmetricMapping and Enum.
64     
65     Parameters:
66     * subcon - the subcon to map
67     * decoding - the decoding (parsing) mapping (a dict)
68     * encoding - the encoding (building) mapping (a dict)
69     * decdefault - the default return value when the object is not found
70       in the decoding mapping. if no object is given, an exception is raised.
71       if `Pass` is used, the unmapped object will be passed as-is
72     * encdefault - the default return value when the object is not found
73       in the encoding mapping. if no object is given, an exception is raised.
74       if `Pass` is used, the unmapped object will be passed as-is
75     """
76     __slots__ = ["encoding", "decoding", "encdefault", "decdefault"]
77     def __init__(self, subcon, decoding, encoding, 
78                  decdefault = NotImplemented, encdefault = NotImplemented):
79         Adapter.__init__(self, subcon)
80         self.decoding = decoding
81         self.encoding = encoding
82         self.decdefault = decdefault
83         self.encdefault = encdefault
84     def _encode(self, obj, context):
85         try:
86             return self.encoding[obj]
87         except (KeyError, TypeError):
88             if self.encdefault is NotImplemented:
89                 raise MappingError("no encoding mapping for %r [%s]" % (
90                     obj, self.subcon.name))
91             if self.encdefault is Pass:
92                 return obj
93             return self.encdefault
94     def _decode(self, obj, context):
95         try:
96             return self.decoding[obj]
97         except (KeyError, TypeError):
98             if self.decdefault is NotImplemented:
99                 raise MappingError("no decoding mapping for %r [%s]" % (
100                     obj, self.subcon.name))
101             if self.decdefault is Pass:
102                 return obj
103             return self.decdefault
104
105 class FlagsAdapter(Adapter):
106     """
107     Adapter for flag fields. Each flag is extracted from the number, resulting
108     in a FlagsContainer object. Not intended for direct usage.
109     See FlagsEnum.
110     
111     Parameters
112     * subcon - the subcon to extract
113     * flags - a dictionary mapping flag-names to their value
114     """
115     __slots__ = ["flags"]
116     def __init__(self, subcon, flags):
117         Adapter.__init__(self, subcon)
118         self.flags = flags
119     def _encode(self, obj, context):
120         flags = 0
121         for name, value in self.flags.items():
122             if getattr(obj, name, False):
123                 flags |= value
124         return flags
125     def _decode(self, obj, context):
126         obj2 = FlagsContainer()
127         for name, value in self.flags.items():
128             setattr(obj2, name, bool(obj & value))
129         return obj2
130
131 class StringAdapter(Adapter):
132     """
133     Adapter for strings. Converts a sequence of characters into a python 
134     string, and optionally handles character encoding.
135     See String.
136     
137     Parameters:
138     * subcon - the subcon to convert
139     * encoding - the character encoding name (e.g., "utf8"), or None to 
140       return raw bytes (usually 8-bit ASCII).
141     """
142     __slots__ = ["encoding"]
143     def __init__(self, subcon, encoding = None):
144         Adapter.__init__(self, subcon)
145         self.encoding = encoding
146     def _encode(self, obj, context):
147         if self.encoding:
148             obj = obj.encode(self.encoding)
149         return obj
150     def _decode(self, obj, context):
151         if self.encoding:
152             obj = obj.decode(self.encoding)
153         return obj
154
155 class PaddedStringAdapter(Adapter):
156     r"""
157     Adapter for padded strings.
158     See String.
159     
160     Parameters:
161     * subcon - the subcon to adapt
162     * padchar - the padding character. default is "\x00".
163     * paddir - the direction where padding is placed ("right", "left", or 
164       "center"). the default is "right". 
165     * trimdir - the direction where trimming will take place ("right" or 
166       "left"). the default is "right". trimming is only meaningful for
167       building, when the given string is too long. 
168     """
169     __slots__ = ["padchar", "paddir", "trimdir"]
170     def __init__(self, subcon, padchar = "\x00", paddir = "right", 
171                  trimdir = "right"):
172         if paddir not in ("right", "left", "center"):
173             raise ValueError("paddir must be 'right', 'left' or 'center'", 
174                 paddir)
175         if trimdir not in ("right", "left"):
176             raise ValueError("trimdir must be 'right' or 'left'", trimdir)
177         Adapter.__init__(self, subcon)
178         self.padchar = padchar
179         self.paddir = paddir
180         self.trimdir = trimdir
181     def _decode(self, obj, context):
182         if self.paddir == "right":
183             obj = obj.rstrip(self.padchar)
184         elif self.paddir == "left":
185             obj = obj.lstrip(self.padchar)
186         else:
187             obj = obj.strip(self.padchar)
188         return obj
189     def _encode(self, obj, context):
190         size = self._sizeof(context)
191         if self.paddir == "right":
192             obj = obj.ljust(size, self.padchar)
193         elif self.paddir == "left":
194             obj = obj.rjust(size, self.padchar)
195         else:
196             obj = obj.center(size, self.padchar)
197         if len(obj) > size:
198             if self.trimdir == "right":
199                 obj = obj[:size]
200             else:
201                 obj = obj[-size:]
202         return obj
203
204 class LengthValueAdapter(Adapter):
205     """
206     Adapter for length-value pairs. It extracts only the value from the 
207     pair, and calculates the length based on the value.
208     See PrefixedArray and PascalString.
209     
210     Parameters:
211     * subcon - the subcon returning a length-value pair
212     """
213     __slots__ = []
214     def _encode(self, obj, context):
215         return (len(obj), obj)
216     def _decode(self, obj, context):
217         return obj[1]
218
219 class CStringAdapter(StringAdapter):
220     r"""
221     Adapter for C-style strings (strings terminated by a terminator char).
222     
223     Parameters:
224     * subcon - the subcon to convert
225     * terminators - a sequence of terminator chars. default is "\x00".
226     * encoding - the character encoding to use (e.g., "utf8"), or None to
227       return raw-bytes. the terminator characters are not affected by the 
228       encoding.
229     """
230     __slots__ = ["terminators"]
231     def __init__(self, subcon, terminators = b"\x00", encoding = None):
232         StringAdapter.__init__(self, subcon, encoding = encoding)
233         self.terminators = terminators
234     def _encode(self, obj, context):
235         return StringAdapter._encode(self, obj, context) + self.terminators[0:1]
236     def _decode(self, obj, context):
237         return StringAdapter._decode(self, b''.join(obj[:-1]), context)
238
239 class TunnelAdapter(Adapter):
240     """
241     Adapter for tunneling (as in protocol tunneling). A tunnel is construct
242     nested upon another (layering). For parsing, the lower layer first parses
243     the data (note: it must return a string!), then the upper layer is called
244     to parse that data (bottom-up). For building it works in a top-down manner;
245     first the upper layer builds the data, then the lower layer takes it and
246     writes it to the stream.
247     
248     Parameters:
249     * subcon - the lower layer subcon
250     * inner_subcon - the upper layer (tunneled/nested) subcon
251     
252     Example:
253     # a pascal string containing compressed data (zlib encoding), so first
254     # the string is read, decompressed, and finally re-parsed as an array
255     # of UBInt16
256     TunnelAdapter(
257         PascalString("data", encoding = "zlib"),
258         GreedyRange(UBInt16("elements"))
259     )
260     """
261     __slots__ = ["inner_subcon"]
262     def __init__(self, subcon, inner_subcon):
263         Adapter.__init__(self, subcon)
264         self.inner_subcon = inner_subcon
265     def _decode(self, obj, context):
266         return self.inner_subcon._parse(BytesIO(obj), context)
267     def _encode(self, obj, context):
268         stream = BytesIO()
269         self.inner_subcon._build(obj, stream, context)
270         return stream.getvalue()
271
272 class ExprAdapter(Adapter):
273     """
274     A generic adapter that accepts 'encoder' and 'decoder' as parameters. You
275     can use ExprAdapter instead of writing a full-blown class when only a 
276     simple expression is needed.
277     
278     Parameters:
279     * subcon - the subcon to adapt
280     * encoder - a function that takes (obj, context) and returns an encoded 
281       version of obj
282     * decoder - a function that takes (obj, context) and returns an decoded 
283       version of obj
284     
285     Example:
286     ExprAdapter(UBInt8("foo"), 
287         encoder = lambda obj, ctx: obj / 4,
288         decoder = lambda obj, ctx: obj * 4,
289     )
290     """
291     __slots__ = ["_encode", "_decode"]
292     def __init__(self, subcon, encoder, decoder):
293         Adapter.__init__(self, subcon)
294         self._encode = encoder
295         self._decode = decoder
296
297 class HexDumpAdapter(Adapter):
298     """
299     Adapter for hex-dumping strings. It returns a HexString, which is a string
300     """
301     __slots__ = ["linesize"]
302     def __init__(self, subcon, linesize = 16):
303         Adapter.__init__(self, subcon)
304         self.linesize = linesize
305     def _encode(self, obj, context):
306         return obj
307     def _decode(self, obj, context):
308         return HexString(obj, linesize = self.linesize)
309
310 class ConstAdapter(Adapter):
311     """
312     Adapter for enforcing a constant value ("magic numbers"). When decoding,
313     the return value is checked; when building, the value is substituted in.
314     
315     Parameters:
316     * subcon - the subcon to validate
317     * value - the expected value
318     
319     Example:
320     Const(Field("signature", 2), "MZ")
321     """
322     __slots__ = ["value"]
323     def __init__(self, subcon, value):
324         Adapter.__init__(self, subcon)
325         self.value = value
326     def _encode(self, obj, context):
327         if obj is None or obj == self.value:
328             return self.value
329         else:
330             raise ConstError("expected %r, found %r" % (self.value, obj))
331     def _decode(self, obj, context):
332         if obj != self.value:
333             raise ConstError("expected %r, found %r" % (self.value, obj))
334         return obj
335
336 class SlicingAdapter(Adapter):
337     """
338     Adapter for slicing a list (getting a slice from that list)
339     
340     Parameters:
341     * subcon - the subcon to slice
342     * start - start index
343     * stop - stop index (or None for up-to-end)
344     * step - step (or None for every element)
345     """
346     __slots__ = ["start", "stop", "step"]
347     def __init__(self, subcon, start, stop = None):
348         Adapter.__init__(self, subcon)
349         self.start = start
350         self.stop = stop
351     def _encode(self, obj, context):
352         if self.start is None:
353             return obj
354         return [None] * self.start + obj
355     def _decode(self, obj, context):
356         return obj[self.start:self.stop]
357
358 class IndexingAdapter(Adapter):
359     """
360     Adapter for indexing a list (getting a single item from that list)
361     
362     Parameters:
363     * subcon - the subcon to index
364     * index - the index of the list to get
365     """
366     __slots__ = ["index"]
367     def __init__(self, subcon, index):
368         Adapter.__init__(self, subcon)
369         if type(index) is not int:
370             raise TypeError("index must be an integer", type(index))
371         self.index = index
372     def _encode(self, obj, context):
373         return [None] * self.index + [obj]
374     def _decode(self, obj, context):
375         return obj[self.index]
376
377 class PaddingAdapter(Adapter):
378     r"""
379     Adapter for padding.
380     
381     Parameters:
382     * subcon - the subcon to pad
383     * pattern - the padding pattern (character). default is "\x00"
384     * strict - whether or not to verify, during parsing, that the given 
385       padding matches the padding pattern. default is False (unstrict)
386     """
387     __slots__ = ["pattern", "strict"]
388     def __init__(self, subcon, pattern = "\x00", strict = False):
389         Adapter.__init__(self, subcon)
390         self.pattern = pattern
391         self.strict = strict
392     def _encode(self, obj, context):
393         return self._sizeof(context) * self.pattern
394     def _decode(self, obj, context):
395         if self.strict:
396             expected = self._sizeof(context) * self.pattern
397             if obj != expected:
398                 raise PaddingError("expected %r, found %r" % (expected, obj))
399         return obj
400
401
402 #===============================================================================
403 # validators
404 #===============================================================================
405 class Validator(Adapter):
406     """
407     Abstract class: validates a condition on the encoded/decoded object. 
408     Override _validate(obj, context) in deriving classes.
409     
410     Parameters:
411     * subcon - the subcon to validate
412     """
413     __slots__ = []
414     def _decode(self, obj, context):
415         if not self._validate(obj, context):
416             raise ValidationError("invalid object", obj)
417         return obj
418     def _encode(self, obj, context):
419         return self._decode(obj, context)
420     def _validate(self, obj, context):
421         raise NotImplementedError()
422
423 class OneOf(Validator):
424     """
425     Validates that the object is one of the listed values.
426
427     :param ``Construct`` subcon: object to validate
428     :param iterable valids: a set of valid values
429
430     >>> OneOf(UBInt8("foo"), [4,5,6,7]).parse("\\x05")
431     5
432     >>> OneOf(UBInt8("foo"), [4,5,6,7]).parse("\\x08")
433     Traceback (most recent call last):
434         ...
435     construct.core.ValidationError: ('invalid object', 8)
436     >>>
437     >>> OneOf(UBInt8("foo"), [4,5,6,7]).build(5)
438     '\\x05'
439     >>> OneOf(UBInt8("foo"), [4,5,6,7]).build(9)
440     Traceback (most recent call last):
441         ...
442     construct.core.ValidationError: ('invalid object', 9)
443     """
444     __slots__ = ["valids"]
445     def __init__(self, subcon, valids):
446         Validator.__init__(self, subcon)
447         self.valids = valids
448     def _validate(self, obj, context):
449         return obj in self.valids
450
451 class NoneOf(Validator):
452     """
453     Validates that the object is none of the listed values.
454
455     :param ``Construct`` subcon: object to validate
456     :param iterable invalids: a set of invalid values
457
458     >>> NoneOf(UBInt8("foo"), [4,5,6,7]).parse("\\x08")
459     8
460     >>> NoneOf(UBInt8("foo"), [4,5,6,7]).parse("\\x06")
461     Traceback (most recent call last):
462         ...
463     construct.core.ValidationError: ('invalid object', 6)
464     """
465     __slots__ = ["invalids"]
466     def __init__(self, subcon, invalids):
467         Validator.__init__(self, subcon)
468         self.invalids = invalids
469     def _validate(self, obj, context):
470         return obj not in self.invalids