something basic
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..bb6d589
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,3 @@
+syntax: glob
+
+*.pyc
diff --git a/binfiles/z.elf b/binfiles/z.elf
new file mode 100644
index 0000000..ccfa6ae
--- /dev/null
+++ b/binfiles/z.elf
Binary files differ
diff --git a/elftools/__init__.py b/elftools/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/elftools/__init__.py
diff --git a/elftools/construct/README b/elftools/construct/README
new file mode 100644
index 0000000..88ba6e9
--- /dev/null
+++ b/elftools/construct/README
@@ -0,0 +1,5 @@
+'construct' is the actual library (version 2, downloaded on 15.09.2010)
+Taken from http://construct.wikispaces.com/
+The code for version 2.00 has been released by the author into the public domain
+
+
diff --git a/elftools/construct/__init__.py b/elftools/construct/__init__.py
new file mode 100644
index 0000000..0b97feb
--- /dev/null
+++ b/elftools/construct/__init__.py
@@ -0,0 +1,81 @@
+"""

+Construct 2.00 -- parsing made even more fun (and faster)

+

+Homepage:

+http://construct.wikispaces.com

+

+Typical usage:

+>>> from construct import *

+

+Example:

+>>> from construct import *

+>>>

+>>> s = Struct("foo",

+...     UBInt8("a"),

+...     UBInt16("b"),

+... )

+>>>

+>>> s.parse("\x01\x02\x03")

+Container(a = 1, b = 515)

+>>> print s.parse("\x01\x02\x03")

+Container:

+    a = 1

+    b = 515

+>>> s.build(Container(a = 1, b = 0x0203))

+"\x01\x02\x03"

+"""

+from core import *

+from adapters import *

+from macros import *

+from debug import Probe, Debugger

+

+

+#===============================================================================

+# meta data

+#===============================================================================

+__author__ = "tomer filiba (tomerfiliba [at] gmail.com)"

+__version__ = "2.00"

+

+#===============================================================================

+# shorthands

+#===============================================================================

+Bits = BitField

+Byte = UBInt8

+Bytes = Field

+Const = ConstAdapter

+Tunnel = TunnelAdapter

+Embed = Embedded

+

+#===============================================================================

+# backward compatibility with RC1

+#===============================================================================

+MetaField = Field

+MetaBytes = Field

+GreedyRepeater = GreedyRange

+OptionalGreedyRepeater = OptionalGreedyRange

+Repeater = Array

+StrictRepeater = Array

+MetaRepeater = Array

+OneOfValidator = OneOf

+NoneOfValidator = NoneOf

+

+#===============================================================================

+# don't want to leek these out...

+#===============================================================================

+del encode_bin, decode_bin, int_to_bin, bin_to_int, swap_bytes

+del Packer, StringIO

+del HexString, LazyContainer, AttrDict

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/elftools/construct/adapters.py b/elftools/construct/adapters.py
new file mode 100644
index 0000000..98fda72
--- /dev/null
+++ b/elftools/construct/adapters.py
@@ -0,0 +1,482 @@
+from core import Adapter, AdaptationError, Pass

+from lib import int_to_bin, bin_to_int, swap_bytes, StringIO

+from lib import FlagsContainer, HexString

+

+

+#===============================================================================

+# exceptions

+#===============================================================================

+class BitIntegerError(AdaptationError):

+    __slots__ = []

+class MappingError(AdaptationError):

+    __slots__ = []

+class ConstError(AdaptationError):

+    __slots__ = []

+class ValidationError(AdaptationError):

+    __slots__ = []

+class PaddingError(AdaptationError):

+    __slots__ = []

+

+#===============================================================================

+# adapters

+#===============================================================================

+class BitIntegerAdapter(Adapter):

+    """

+    Adapter for bit-integers (converts bitstrings to integers, and vice versa).

+    See BitField.

+    

+    Parameters:

+    * subcon - the subcon to adapt

+    * width - the size of the subcon, in bits

+    * swapped - whether to swap byte order (little endian/big endian). 

+      default is False (big endian)

+    * signed - whether the value is signed (two's complement). the default

+      is False (unsigned)

+    * bytesize - number of bits per byte, used for byte-swapping (if swapped).

+      default is 8.

+    """

+    __slots__ = ["width", "swapped", "signed", "bytesize"]

+    def __init__(self, subcon, width, swapped = False, signed = False, 

+                 bytesize = 8):

+        Adapter.__init__(self, subcon)

+        self.width = width

+        self.swapped = swapped

+        self.signed = signed

+        self.bytesize = bytesize

+    def _encode(self, obj, context):

+        if obj < 0 and not self.signed:

+            raise BitIntegerError("object is negative, but field is not signed",

+                obj)

+        obj2 = int_to_bin(obj, width = self.width)

+        if self.swapped:

+            obj2 = swap_bytes(obj2, bytesize = self.bytesize)

+        return obj2

+    def _decode(self, obj, context):

+        if self.swapped:

+            obj = swap_bytes(obj, bytesize = self.bytesize)

+        return bin_to_int(obj, signed = self.signed)

+

+class MappingAdapter(Adapter):

+    """

+    Adapter that maps objects to other objects.

+    See SymmetricMapping and Enum.

+    

+    Parameters:

+    * subcon - the subcon to map

+    * decoding - the decoding (parsing) mapping (a dict)

+    * encoding - the encoding (building) mapping (a dict)

+    * decdefault - the default return value when the object is not found

+      in the decoding mapping. if no object is given, an exception is raised.

+      if `Pass` is used, the unmapped object will be passed as-is

+    * encdefault - the default return value when the object is not found

+      in the encoding mapping. if no object is given, an exception is raised.

+      if `Pass` is used, the unmapped object will be passed as-is

+    """

+    __slots__ = ["encoding", "decoding", "encdefault", "decdefault"]

+    def __init__(self, subcon, decoding, encoding, 

+                 decdefault = NotImplemented, encdefault = NotImplemented):

+        Adapter.__init__(self, subcon)

+        self.decoding = decoding

+        self.encoding = encoding

+        self.decdefault = decdefault

+        self.encdefault = encdefault

+    def _encode(self, obj, context):

+        try:

+            return self.encoding[obj]

+        except (KeyError, TypeError):

+            if self.encdefault is NotImplemented:

+                raise MappingError("no encoding mapping for %r" % (obj,))

+            if self.encdefault is Pass:

+                return obj

+            return self.encdefault

+    def _decode(self, obj, context):

+        try:

+            return self.decoding[obj]

+        except (KeyError, TypeError):

+            if self.decdefault is NotImplemented:

+                raise MappingError("no decoding mapping for %r"  % (obj,))

+            if self.decdefault is Pass:

+                return obj

+            return self.decdefault

+

+class FlagsAdapter(Adapter):

+    """

+    Adapter for flag fields. Each flag is extracted from the number, resulting

+    in a FlagsContainer object. Not intended for direct usage.

+    See FlagsEnum.

+    

+    Parameters

+    * subcon - the subcon to extract

+    * flags - a dictionary mapping flag-names to their value

+    """

+    __slots__ = ["flags"]

+    def __init__(self, subcon, flags):

+        Adapter.__init__(self, subcon)

+        self.flags = flags

+    def _encode(self, obj, context):

+        flags = 0

+        for name, value in self.flags.iteritems():

+            if getattr(obj, name, False):

+                flags |= value

+        return flags

+    def _decode(self, obj, context):

+        obj2 = FlagsContainer()

+        for name, value in self.flags.iteritems():

+            setattr(obj2, name, bool(obj & value))

+        return obj2

+

+class StringAdapter(Adapter):

+    """

+    Adapter for strings. Converts a sequence of characters into a python 

+    string, and optionally handles character encoding.

+    See String.

+    

+    Parameters:

+    * subcon - the subcon to convert

+    * encoding - the character encoding name (e.g., "utf8"), or None to 

+      return raw bytes (usually 8-bit ASCII).

+    """

+    __slots__ = ["encoding"]

+    def __init__(self, subcon, encoding = None):

+        Adapter.__init__(self, subcon)

+        self.encoding = encoding

+    def _encode(self, obj, context):

+        if self.encoding:

+            obj = obj.encode(self.encoding)

+        return obj

+    def _decode(self, obj, context):

+        obj = "".join(obj)

+        if self.encoding:

+            obj = obj.decode(self.encoding)

+        return obj

+

+class PaddedStringAdapter(Adapter):

+    r"""

+    Adapter for padded strings.

+    See String.

+    

+    Parameters:

+    * subcon - the subcon to adapt

+    * padchar - the padding character. default is "\x00".

+    * paddir - the direction where padding is placed ("right", "left", or 

+      "center"). the default is "right". 

+    * trimdir - the direction where trimming will take place ("right" or 

+      "left"). the default is "right". trimming is only meaningful for

+      building, when the given string is too long. 

+    """

+    __slots__ = ["padchar", "paddir", "trimdir"]

+    def __init__(self, subcon, padchar = "\x00", paddir = "right", 

+                 trimdir = "right"):

+        if paddir not in ("right", "left", "center"):

+            raise ValueError("paddir must be 'right', 'left' or 'center'", 

+                paddir)

+        if trimdir not in ("right", "left"):

+            raise ValueError("trimdir must be 'right' or 'left'", trimdir)

+        Adapter.__init__(self, subcon)

+        self.padchar = padchar

+        self.paddir = paddir

+        self.trimdir = trimdir

+    def _decode(self, obj, context):

+        if self.paddir == "right":

+            obj = obj.rstrip(self.padchar)

+        elif self.paddir == "left":

+            obj = obj.lstrip(self.padchar)

+        else:

+            obj = obj.strip(self.padchar)

+        return obj

+    def _encode(self, obj, context):

+        size = self._sizeof(context)

+        if self.paddir == "right":

+            obj = obj.ljust(size, self.padchar)

+        elif self.paddir == "left":

+            obj = obj.rjust(size, self.padchar)

+        else:

+            obj = obj.center(size, self.padchar)

+        if len(obj) > size:

+            if self.trimdir == "right":

+                obj = obj[:size]

+            else:

+                obj = obj[-size:]

+        return obj

+

+class LengthValueAdapter(Adapter):

+    """

+    Adapter for length-value pairs. It extracts only the value from the 

+    pair, and calculates the length based on the value.

+    See PrefixedArray and PascalString.

+    

+    Parameters:

+    * subcon - the subcon returning a length-value pair

+    """

+    __slots__ = []

+    def _encode(self, obj, context):

+        return (len(obj), obj)

+    def _decode(self, obj, context):

+        return obj[1]

+

+class CStringAdapter(StringAdapter):

+    r"""

+    Adapter for C-style strings (strings terminated by a terminator char).

+    

+    Parameters:

+    * subcon - the subcon to convert

+    * terminators - a sequence of terminator chars. default is "\x00".

+    * encoding - the character encoding to use (e.g., "utf8"), or None to

+      return raw-bytes. the terminator characters are not affected by the 

+      encoding.

+    """

+    __slots__ = ["terminators"]

+    def __init__(self, subcon, terminators = "\x00", encoding = None):

+        StringAdapter.__init__(self, subcon, encoding = encoding)

+        self.terminators = terminators

+    def _encode(self, obj, context):

+        return StringAdapter._encode(self, obj, context) + self.terminators[0]

+    def _decode(self, obj, context):

+        return StringAdapter._decode(self, obj[:-1], context)

+

+class TunnelAdapter(Adapter):

+    """

+    Adapter for tunneling (as in protocol tunneling). A tunnel is construct

+    nested upon another (layering). For parsing, the lower layer first parses

+    the data (note: it must return a string!), then the upper layer is called

+    to parse that data (bottom-up). For building it works in a top-down manner;

+    first the upper layer builds the data, then the lower layer takes it and

+    writes it to the stream.

+    

+    Parameters:

+    * subcon - the lower layer subcon

+    * inner_subcon - the upper layer (tunneled/nested) subcon

+    

+    Example:

+    # a pascal string containing compressed data (zlib encoding), so first

+    # the string is read, decompressed, and finally re-parsed as an array

+    # of UBInt16

+    TunnelAdapter(

+        PascalString("data", encoding = "zlib"),

+        GreedyRange(UBInt16("elements"))

+    )

+    """

+    __slots__ = ["inner_subcon"]

+    def __init__(self, subcon, inner_subcon):

+        Adapter.__init__(self, subcon)

+        self.inner_subcon = inner_subcon

+    def _decode(self, obj, context):

+        return self.inner_subcon._parse(StringIO(obj), context)

+    def _encode(self, obj, context):

+        stream = StringIO()

+        self.inner_subcon._build(obj, stream, context)

+        return stream.getvalue()

+

+class ExprAdapter(Adapter):

+    """

+    A generic adapter that accepts 'encoder' and 'decoder' as parameters. You

+    can use ExprAdapter instead of writing a full-blown class when only a 

+    simple expression is needed.

+    

+    Parameters:

+    * subcon - the subcon to adapt

+    * encoder - a function that takes (obj, context) and returns an encoded 

+      version of obj

+    * decoder - a function that takes (obj, context) and returns an decoded 

+      version of obj

+    

+    Example:

+    ExprAdapter(UBInt8("foo"), 

+        encoder = lambda obj, ctx: obj / 4,

+        decoder = lambda obj, ctx: obj * 4,

+    )

+    """

+    __slots__ = ["_encode", "_decode"]

+    def __init__(self, subcon, encoder, decoder):

+        Adapter.__init__(self, subcon)

+        self._encode = encoder

+        self._decode = decoder

+

+class HexDumpAdapter(Adapter):

+    """

+    Adapter for hex-dumping strings. It returns a HexString, which is a string

+    """

+    __slots__ = ["linesize"]

+    def __init__(self, subcon, linesize = 16):

+        Adapter.__init__(self, subcon)

+        self.linesize = linesize

+    def _encode(self, obj, context):

+        return obj

+    def _decode(self, obj, context):

+        return HexString(obj, linesize = self.linesize)

+

+class ConstAdapter(Adapter):

+    """

+    Adapter for enforcing a constant value ("magic numbers"). When decoding,

+    the return value is checked; when building, the value is substituted in.

+    

+    Parameters:

+    * subcon - the subcon to validate

+    * value - the expected value

+    

+    Example:

+    Const(Field("signature", 2), "MZ")

+    """

+    __slots__ = ["value"]

+    def __init__(self, subcon, value):

+        Adapter.__init__(self, subcon)

+        self.value = value

+    def _encode(self, obj, context):

+        if obj is None or obj == self.value:

+            return self.value

+        else:

+            raise ConstError("expected %r, found %r" % (self.value, obj))

+    def _decode(self, obj, context):

+        if obj != self.value:

+            raise ConstError("expected %r, found %r" % (self.value, obj))

+        return obj

+

+class SlicingAdapter(Adapter):

+    """

+    Adapter for slicing a list (getting a slice from that list)

+    

+    Parameters:

+    * subcon - the subcon to slice

+    * start - start index

+    * stop - stop index (or None for up-to-end)

+    * step - step (or None for every element)

+    """

+    __slots__ = ["start", "stop", "step"]

+    def __init__(self, subcon, start, stop = None):

+        Adapter.__init__(self, subcon)

+        self.start = start

+        self.stop = stop

+    def _encode(self, obj, context):

+        if self.start is None:

+            return obj

+        return [None] * self.start + obj

+    def _decode(self, obj, context):

+        return obj[self.start:self.stop]

+

+class IndexingAdapter(Adapter):

+    """

+    Adapter for indexing a list (getting a single item from that list)

+    

+    Parameters:

+    * subcon - the subcon to index

+    * index - the index of the list to get

+    """

+    __slots__ = ["index"]

+    def __init__(self, subcon, index):

+        Adapter.__init__(self, subcon)

+        if type(index) is not int:

+            raise TypeError("index must be an integer", type(index))

+        self.index = index

+    def _encode(self, obj, context):

+        return [None] * self.index + [obj]

+    def _decode(self, obj, context):

+        return obj[self.index]

+

+class PaddingAdapter(Adapter):

+    r"""

+    Adapter for padding.

+    

+    Parameters:

+    * subcon - the subcon to pad

+    * pattern - the padding pattern (character). default is "\x00")

+    * strict - whether or not to verify, during parsing, that the given 

+      padding matches the padding pattern. default is False (unstrict)

+    """

+    __slots__ = ["pattern", "strict"]

+    def __init__(self, subcon, pattern = "\x00", strict = False):

+        Adapter.__init__(self, subcon)

+        self.pattern = pattern

+        self.strict = strict

+    def _encode(self, obj, context):

+        return self._sizeof(context) * self.pattern

+    def _decode(self, obj, context):

+        if self.strict:

+            expected = self._sizeof(context) * self.pattern

+            if obj != expected:

+                raise PaddingError("expected %r, found %r" % (expected, obj))

+        return obj

+

+

+#===============================================================================

+# validators

+#===============================================================================

+class Validator(Adapter):

+    """

+    Abstract class: validates a condition on the encoded/decoded object. 

+    Override _validate(obj, context) in deriving classes.

+    

+    Parameters:

+    * subcon - the subcon to validate

+    """

+    __slots__ = []

+    def _decode(self, obj, context):

+        if not self._validate(obj, context):

+            raise ValidationError("invalid object", obj)

+        return obj

+    def _encode(self, obj, context):

+        return self._decode(obj, context)

+    def _validate(self, obj, context):

+        raise NotImplementedError()

+

+class OneOf(Validator):

+    """

+    Validates that the value is one of the listed values

+    

+    Parameters:

+    * subcon - the subcon to validate

+    * valids - a set of valid values

+    """

+    __slots__ = ["valids"]

+    def __init__(self, subcon, valids):

+        Validator.__init__(self, subcon)

+        self.valids = valids

+    def _validate(self, obj, context):

+        return obj in self.valids

+

+class NoneOf(Validator):

+    """

+    Validates that the value is none of the listed values

+    

+    Parameters:

+    * subcon - the subcon to validate

+    * invalids - a set of invalid values

+    """

+    __slots__ = ["invalids"]

+    def __init__(self, subcon, invalids):

+        Validator.__init__(self, subcon)

+        self.invalids = invalids

+    def _validate(self, obj, context):

+        return obj not in self.invalids

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/elftools/construct/core.py b/elftools/construct/core.py
new file mode 100644
index 0000000..b09382f
--- /dev/null
+++ b/elftools/construct/core.py
@@ -0,0 +1,1217 @@
+from lib import StringIO, Packer

+from lib import Container, ListContainer, AttrDict, LazyContainer

+

+

+#===============================================================================

+# exceptions

+#===============================================================================

+class ConstructError(Exception):

+    __slots__ = []

+class FieldError(ConstructError):

+    __slots__ = []

+class SizeofError(ConstructError):

+    __slots__ = []

+class AdaptationError(ConstructError):

+    __slots__ = []

+class ArrayError(ConstructError):

+    __slots__ = []

+class RangeError(ConstructError):

+    __slots__ = []

+class SwitchError(ConstructError):

+    __slots__ = []

+class SelectError(ConstructError):

+    __slots__ = []

+class TerminatorError(ConstructError):

+    __slots__ = []

+

+#===============================================================================

+# abstract constructs

+#===============================================================================

+class Construct(object):

+    """

+    The mother of all constructs!

+    

+    User API:

+    * parse(buf) - parses an in-memory buffer (usually a string)

+    * parse_stream(stream) - parses a stream (in-memory, file, pipe, ...)

+    * build(obj) - builds the object into an in-memory buffer (a string)

+    * build_stream(obj, stream) - builds the object into the given stream

+    * sizeof(context) - calculates the size of the construct, if possible,

+      based on the context

+    

+    Overriable methods for subclassing:

+    * _parse(stream, context) - low-level parse from stream

+    * _build(obj, stream, context) - low-level build to stream

+    * _sizeof(context) - low-level compute size

+    

+    Flags API:

+    * _set_flag(flag) - sets the given flag/flags

+    * _clear_flag(flag) - clears the given flag/flags

+    * _inherit_flags(*subcons) - inherits the flag of subcons

+    * _is_flag(flag) - is the flag set? (predicate)

+    

+    Overridable methods for the copy-API:

+    * __getstate__() - returns a dict of the attributes of self

+    * __setstate__(attrs) - sets the attrs to self

+    

+    Attributes:

+    All constructs have a name and flags. The name is used for naming 

+    struct-members and context dicts. Note that the name must be a string or

+    None (if the name is not needed). A single underscore ("_") is a reserved

+    name, and so are names starting with a less-than character ("<"). The name

+    should be descriptive, short, and valid as a python identifier (although

+    these rules are not enforced). 

+    

+    The flags specify additional behavioral information about this construct.

+    The flags are used by enclosing constructs to determine a proper course 

+    of action. Usually, flags are "inherited", i.e., an enclosing construct

+    inherits the flags of its subconstruct. The enclosing construct may

+    set new flags or clear existing ones, as necessary.

+        

+    For example, if FLAG_COPY_CONTEXT is set, repeaters will pass a copy of 

+    the context for each iteration, which is necessary for OnDemand parsing.

+    """

+    FLAG_COPY_CONTEXT          = 0x0001

+    FLAG_DYNAMIC               = 0x0002

+    FLAG_EMBED                 = 0x0004

+    FLAG_NESTING               = 0x0008

+    

+    __slots__ = ["name", "conflags"]

+    def __init__(self, name, flags = 0):

+        if name is not None:

+            if type(name) is not str:

+                raise TypeError("name must be a string or None", name)

+            if name == "_" or name.startswith("<"):

+                raise ValueError("reserved name", name)

+        self.name = name

+        self.conflags = flags

+    def __repr__(self):

+        return "%s(%r)" % (self.__class__.__name__, self.name)

+    

+    def _set_flag(self, flag):

+        self.conflags |= flag

+    def _clear_flag(self, flag):

+        self.conflags &= ~flag

+    def _inherit_flags(self, *subcons):

+        for sc in subcons:

+            self._set_flag(sc.conflags)

+    def _is_flag(self, flag):

+        return bool(self.conflags & flag)

+    

+    def __getstate__(self):

+        attrs = {}

+        if hasattr(self, "__dict__"):

+            attrs.update(self.__dict__)

+        slots = []

+        c = self.__class__

+        while c is not None:

+            if hasattr(c, "__slots__"):

+                slots.extend(c.__slots__)

+            c = c.__base__

+        for name in slots:

+            if hasattr(self, name):

+                attrs[name] = getattr(self, name)

+        return attrs

+    def __setstate__(self, attrs):

+        for name, value in attrs.iteritems():

+            setattr(self, name, value)

+    def __copy__(self):

+        """returns a copy of this construct"""

+        self2 = object.__new__(self.__class__)

+        self2.__setstate__(self.__getstate__())

+        return self2

+    

+    def parse(self, data):

+        """parses data given as a buffer or a string (in-memory)"""

+        return self.parse_stream(StringIO(data))

+    def parse_stream(self, stream):

+        """parses data read directly from a stream"""

+        return self._parse(stream, AttrDict())

+    def _parse(self, stream, context):

+        raise NotImplementedError()

+    

+    def build(self, obj):

+        """builds an object in a string (in memory)"""

+        stream = StringIO()

+        self.build_stream(obj, stream)

+        return stream.getvalue()

+    def build_stream(self, obj, stream):

+        """builds an object into a stream"""

+        self._build(obj, stream, AttrDict())

+    def _build(self, obj, stream, context):

+        raise NotImplementedError()

+    

+    def sizeof(self, context = None):

+        """calculates the size of the construct (if possible) using the 

+        given context"""

+        if context is None:

+            context = AttrDict()

+        return self._sizeof(context)

+    def _sizeof(self, context):

+        raise SizeofError("can't calculate size")

+

+class Subconstruct(Construct):

+    """

+    Abstract subconstruct (wraps an inner construct, inheriting it's 

+    name and flags). 

+    

+    Parameters:

+    * subcon - the construct to wrap

+    """

+    __slots__ = ["subcon"]

+    def __init__(self, subcon):

+        Construct.__init__(self, subcon.name, subcon.conflags)

+        self.subcon = subcon

+    def _parse(self, stream, context):

+        return self.subcon._parse(stream, context)

+    def _build(self, obj, stream, context):

+        self.subcon._build(obj, stream, context)

+    def _sizeof(self, context):

+        return self.subcon._sizeof(context)

+

+class Adapter(Subconstruct):

+    """

+    Abstract adapter: calls _decode for parsing and _encode for building.

+    

+    Parameters:

+    * subcon - the construct to wrap

+    """

+    __slots__ = []

+    def _parse(self, stream, context):

+        return self._decode(self.subcon._parse(stream, context), context)

+    def _build(self, obj, stream, context):

+        self.subcon._build(self._encode(obj, context), stream, context)

+    def _decode(self, obj, context):

+        raise NotImplementedError()

+    def _encode(self, obj, context):

+        raise NotImplementedError()

+

+

+#===============================================================================

+# primitives

+#===============================================================================

+def _read_stream(stream, length):

+    if length < 0:

+        raise ValueError("length must be >= 0", length)

+    data = stream.read(length)

+    if len(data) != length:

+        raise FieldError("expected %d, found %d" % (length, len(data)))

+    return data

+

+def _write_stream(stream, length, data):

+    if length < 0:

+        raise ValueError("length must be >= 0", length)

+    if len(data) != length:

+        raise FieldError("expected %d, found %d" % (length, len(data)))

+    stream.write(data)

+

+class StaticField(Construct):

+    """

+    A field of a fixed size

+    

+    Parameters:

+    * name - the name of the field

+    * length - the length (an integer)

+    

+    Example:

+    StaticField("foo", 5)

+    """

+    __slots__ = ["length"]

+    def __init__(self, name, length):

+        Construct.__init__(self, name)

+        self.length = length

+    def _parse(self, stream, context):

+        return _read_stream(stream, self.length)

+    def _build(self, obj, stream, context):

+        _write_stream(stream, self.length, obj)

+    def _sizeof(self, context):

+        return self.length

+

+class FormatField(StaticField):

+    """

+    A field that uses python's built-in struct module to pack/unpack data

+    according to a format string.

+    Note: this field has been originally implemented as an Adapter, but it 

+    was made a construct for performance reasons.

+    

+    Parameters:

+    * name - the name

+    * endianity - "<" for little endian, ">" for big endian, or "=" for native

+    * format - a single format character

+    

+    Example:

+    FormatField("foo", ">", "L")

+    """

+    __slots__ = ["packer"]

+    def __init__(self, name, endianity, format):

+        if endianity not in (">", "<", "="):

+            raise ValueError("endianity must be be '=', '<', or '>'", 

+                endianity)

+        if len(format) != 1:

+            raise ValueError("must specify one and only one format char")

+        self.packer = Packer(endianity + format)

+        StaticField.__init__(self, name, self.packer.size)

+    def __getstate__(self):

+        attrs = StaticField.__getstate__(self)

+        attrs["packer"] = attrs["packer"].format

+        return attrs

+    def __setstate__(self, attrs):

+        attrs["packer"] = Packer(attrs["packer"])

+        return StaticField.__setstate__(attrs)

+    def _parse(self, stream, context):

+        try:

+            return self.packer.unpack(_read_stream(stream, self.length))[0]

+        except Exception, ex:

+            raise FieldError(ex)

+    def _build(self, obj, stream, context):

+        try:

+            _write_stream(stream, self.length, self.packer.pack(obj))

+        except Exception, ex:

+            raise FieldError(ex)

+

+class MetaField(Construct):

+    """

+    A field of a meta-length. The length is computed at runtime based on

+    the context.

+    

+    Parameters:

+    * name - the name of the field

+    * lengthfunc - a function that takes the context as a parameter and return

+      the length of the field

+    

+    Example:

+    MetaField("foo", lambda ctx: 5)

+    """

+    __slots__ = ["lengthfunc"]

+    def __init__(self, name, lengthfunc):

+        Construct.__init__(self, name)

+        self.lengthfunc = lengthfunc

+        self._set_flag(self.FLAG_DYNAMIC)

+    def _parse(self, stream, context):

+        return _read_stream(stream, self.lengthfunc(context))

+    def _build(self, obj, stream, context):

+        _write_stream(stream, self.lengthfunc(context), obj)

+    def _sizeof(self, context):

+        return self.lengthfunc(context)

+

+

+#===============================================================================

+# arrays and repeaters

+#===============================================================================

+class MetaArray(Subconstruct):

+    """

+    An array (repeater) of a meta-count. The array will iterate exactly 

+    `countfunc()` times. Will raise ArrayError if less elements are found.

+    See also Array, Range and RepeatUntil.

+    

+    Parameters:

+    * countfunc - a function that takes the context as a parameter and returns

+      the number of elements of the array (count)

+    * subcon - the subcon to repeat `countfunc()` times

+    

+    Example:

+    MetaArray(lambda ctx: 5, UBInt8("foo"))

+    """

+    __slots__ = ["countfunc"]

+    def __init__(self, countfunc, subcon):

+        Subconstruct.__init__(self, subcon)

+        self.countfunc = countfunc

+        self._clear_flag(self.FLAG_COPY_CONTEXT)

+        self._set_flag(self.FLAG_DYNAMIC)

+    def _parse(self, stream, context):

+        obj = ListContainer()

+        c = 0

+        count = self.countfunc(context)

+        try:

+            if self.subcon.conflags & self.FLAG_COPY_CONTEXT:

+                while c < count:

+                    obj.append(self.subcon._parse(stream, context.__copy__()))

+                    c += 1

+            else:

+                while c < count:

+                    obj.append(self.subcon._parse(stream, context))

+                    c += 1

+        except ConstructError, ex:

+            raise ArrayError("expected %d, found %d" % (count, c), ex)

+        return obj

+    def _build(self, obj, stream, context):

+        count = self.countfunc(context)

+        if len(obj) != count:

+            raise ArrayError("expected %d, found %d" % (count, len(obj)))

+        if self.subcon.conflags & self.FLAG_COPY_CONTEXT:

+            for subobj in obj:

+                self.subcon._build(subobj, stream, context.__copy__())

+        else:

+            for subobj in obj:

+                self.subcon._build(subobj, stream, context)

+    def _sizeof(self, context):

+        return self.subcon._sizeof(context) * self.countfunc(context)

+

+class Range(Subconstruct):

+    """

+    A range-array. The subcon will iterate between `mincount` to `maxcount`

+    times. If less than `mincount` elements are found, raises RangeError.

+    See also GreedyRange and OptionalGreedyRange.

+    

+    Notes:

+    * requires a seekable stream.

+    

+    Parameters:

+    * mincount - the minimal count (an integer)

+    * maxcount - the maximal count (an integer)

+    * subcon - the subcon to repeat

+    

+    Example:

+    Range(5, 8, UBInt8("foo"))

+    """

+    __slots__ = ["mincount", "maxcout"]

+    def __init__(self, mincount, maxcout, subcon):

+        Subconstruct.__init__(self, subcon)

+        self.mincount = mincount

+        self.maxcout = maxcout

+        self._clear_flag(self.FLAG_COPY_CONTEXT)

+        self._set_flag(self.FLAG_DYNAMIC)

+    def _parse(self, stream, context):

+        obj = ListContainer()

+        c = 0

+        try:

+            if self.subcon.conflags & self.FLAG_COPY_CONTEXT:

+                while c < self.maxcout:

+                    pos = stream.tell()

+                    obj.append(self.subcon._parse(stream, context.__copy__()))

+                    c += 1

+            else:

+                while c < self.maxcout:

+                    pos = stream.tell()

+                    obj.append(self.subcon._parse(stream, context))

+                    c += 1

+        except ConstructError:

+            if c < self.mincount:

+                raise RangeError("expected %d to %d, found %d" % 

+                    (self.mincount, self.maxcout, c))

+            stream.seek(pos)

+        return obj

+    def _build(self, obj, stream, context):

+        if len(obj) < self.mincount or len(obj) > self.maxcout:

+            raise RangeError("expected %d to %d, found %d" % 

+                (self.mincount, self.maxcout, len(obj)))

+        cnt = 0

+        try:

+            if self.subcon.conflags & self.FLAG_COPY_CONTEXT:

+                for subobj in obj:

+                    self.subcon._build(subobj, stream, context.__copy__())

+                    cnt += 1

+            else:

+                for subobj in obj:

+                    self.subcon._build(subobj, stream, context)

+                    cnt += 1

+        except ConstructError:

+            if cnt < self.mincount:

+                raise RangeError("expected %d to %d, found %d" % 

+                    (self.mincount, self.maxcout, len(obj)))

+    def _sizeof(self, context):

+        raise SizeofError("can't calculate size")

+

+class RepeatUntil(Subconstruct):

+    """

+    An array that repeat until the predicate indicates it to stop. Note that

+    the last element (which caused the repeat to exit) is included in the 

+    return value.

+    

+    Parameters:

+    * predicate - a predicate function that takes (obj, context) and returns

+      True if the stop-condition is met, or False to continue.

+    * subcon - the subcon to repeat.

+    

+    Example:

+    # will read chars until \x00 (inclusive)

+    RepeatUntil(lambda obj, ctx: obj == "\x00",

+        Field("chars", 1)

+    )

+    """

+    __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:

+            if self.subcon.conflags & self.FLAG_COPY_CONTEXT:

+                while True:

+                    subobj = self.subcon._parse(stream, context.__copy__())

+                    obj.append(subobj)

+                    if self.predicate(subobj, context):

+                        break

+            else:

+                while True:

+                    subobj = self.subcon._parse(stream, context)

+                    obj.append(subobj)

+                    if self.predicate(subobj, context):

+                        break

+        except ConstructError, ex:

+            raise ArrayError("missing terminator", ex)

+        return obj

+    def _build(self, obj, stream, context):

+        terminated = False

+        if self.subcon.conflags & self.FLAG_COPY_CONTEXT:

+            for subobj in obj:

+                self.subcon._build(subobj, stream, context.__copy__())

+                if self.predicate(subobj, context):

+                    terminated = True

+                    break

+        else:

+            for subobj in obj:

+                self.subcon._build(subobj, stream, context.__copy__())

+                if self.predicate(subobj, context):

+                    terminated = True

+                    break

+        if not terminated:

+            raise ArrayError("missing terminator")

+    def _sizeof(self, context):

+        raise SizeofError("can't calculate size")

+

+

+#===============================================================================

+# structures and sequences

+#===============================================================================

+class Struct(Construct):

+    """

+    A sequence of named constructs, similar to structs in C. The elements are

+    parsed and built in the order they are defined.

+    See also Embedded.

+    

+    Parameters:

+    * name - the name of the structure

+    * subcons - a sequence of subconstructs that make up this structure.

+    * nested - a keyword-only argument that indicates whether this struct 

+      creates a nested context. The default is True. This parameter is 

+      considered "advanced usage", and may be removed in the future.

+    

+    Example:

+    Struct("foo",

+        UBInt8("first_element"),

+        UBInt16("second_element"),

+        Padding(2),

+        UBInt8("third_element"),

+    )

+    """

+    __slots__ = ["subcons", "nested"]

+    def __init__(self, name, *subcons, **kw):

+        self.nested = kw.pop("nested", True)

+        if kw:

+            raise TypeError("the only keyword argument accepted is 'nested'", kw)

+        Construct.__init__(self, name)

+        self.subcons = subcons

+        self._inherit_flags(*subcons)

+        self._clear_flag(self.FLAG_EMBED)

+    def _parse(self, stream, context):

+        if "<obj>" in context:

+            obj = context["<obj>"]

+            del context["<obj>"]

+        else:

+            obj = Container()

+            if self.nested:

+                context = AttrDict(_ = context)

+        for sc in self.subcons:

+            if sc.conflags & self.FLAG_EMBED:

+                context["<obj>"] = obj

+                sc._parse(stream, context)

+            else:

+                subobj = sc._parse(stream, context)

+                if sc.name is not None:

+                    obj[sc.name] = subobj

+                    context[sc.name] = subobj

+        return obj

+    def _build(self, obj, stream, context):

+        if "<unnested>" in context:

+            del context["<unnested>"]

+        elif self.nested:

+            context = AttrDict(_ = context)

+        for sc in self.subcons:

+            if sc.conflags & self.FLAG_EMBED:

+                context["<unnested>"] = True

+                subobj = obj

+            elif sc.name is None:

+                subobj = None

+            else:

+                subobj = getattr(obj, sc.name)

+                context[sc.name] = subobj

+            sc._build(subobj, stream, context)

+    def _sizeof(self, context):

+        if self.nested:

+            context = AttrDict(_ = context)

+        return sum(sc._sizeof(context) for sc in self.subcons)

+

+class Sequence(Struct):

+    """

+    A sequence of unnamed constructs. The elements are parsed and built in the

+    order they are defined.

+    See also Embedded.

+    

+    Parameters:

+    * name - the name of the structure

+    * subcons - a sequence of subconstructs that make up this structure.

+    * nested - a keyword-only argument that indicates whether this struct 

+      creates a nested context. The default is True. This parameter is 

+      considered "advanced usage", and may be removed in the future.

+    

+    Example:

+    Sequence("foo",

+        UBInt8("first_element"),

+        UBInt16("second_element"),

+        Padding(2),

+        UBInt8("third_element"),

+    )

+    """

+    __slots__ = []

+    def _parse(self, stream, context):

+        if "<obj>" in context:

+            obj = context["<obj>"]

+            del context["<obj>"]

+        else:

+            obj = ListContainer()

+            if self.nested:

+                context = AttrDict(_ = context)

+        for sc in self.subcons:

+            if sc.conflags & self.FLAG_EMBED:

+                context["<obj>"] = obj

+                sc._parse(stream, context)

+            else:

+                subobj = sc._parse(stream, context)

+                if sc.name is not None:

+                    obj.append(subobj)

+                    context[sc.name] = subobj

+        return obj

+    def _build(self, obj, stream, context):

+        if "<unnested>" in context:

+            del context["<unnested>"]

+        elif self.nested:

+            context = AttrDict(_ = context)

+        objiter = iter(obj)

+        for sc in self.subcons:

+            if sc.conflags & self.FLAG_EMBED:

+                context["<unnested>"] = True

+                subobj = objiter

+            elif sc.name is None:

+                subobj = None

+            else:

+                subobj = objiter.next()

+                context[sc.name] = subobj

+            sc._build(subobj, stream, context)

+

+class Union(Construct):

+    """

+    a set of overlapping fields (like unions in C). when parsing, 

+    all fields read the same data; when building, only the first subcon

+    (called "master") is used. 

+    

+    Parameters:

+    * name - the name of the union

+    * master - the master subcon, i.e., the subcon used for building and 

+      calculating the total size

+    * subcons - additional subcons

+    

+    Example:

+    Union("what_are_four_bytes",

+        UBInt32("one_dword"),

+        Struct("two_words", UBInt16("first"), UBInt16("second")),

+        Struct("four_bytes", 

+            UBInt8("a"), 

+            UBInt8("b"), 

+            UBInt8("c"), 

+            UBInt8("d")

+        ),

+    )

+    """

+    __slots__ = ["parser", "builder"]

+    def __init__(self, name, master, *subcons, **kw):

+        Construct.__init__(self, name)

+        args = [Peek(sc) for sc in subcons]

+        args.append(MetaField(None, lambda ctx: master._sizeof(ctx)))

+        self.parser = Struct(name, Peek(master, perform_build = True), *args)

+        self.builder = Struct(name, master)

+    def _parse(self, stream, context):

+        return self.parser._parse(stream, context)

+    def _build(self, obj, stream, context):

+        return self.builder._build(obj, stream, context)

+    def _sizeof(self, context):

+        return self.builder._sizeof(context)

+

+#===============================================================================

+# conditional

+#===============================================================================

+class Switch(Construct):

+    """

+    A conditional branch. Switch will choose the case to follow based on

+    the return value of keyfunc. If no case is matched, and no default value 

+    is given, SwitchError will be raised.

+    See also Pass.

+    

+    Parameters:

+    * name - the name of the construct

+    * keyfunc - a function that takes the context and returns a key, which 

+      will ne used to choose the relevant case.

+    * cases - a dictionary mapping keys to constructs. the keys can be any 

+      values that may be returned by keyfunc.

+    * default - a default value to use when the key is not found in the cases.

+      if not supplied, an exception will be raised when the key is not found.

+      You can use the builtin construct Pass for 'do-nothing'.

+    * include_key - whether or not to include the key in the return value

+      of parsing. defualt is False.

+    

+    Example:

+    Struct("foo",

+        UBInt8("type"),

+        Switch("value", lambda ctx: ctx.type, {

+                1 : UBInt8("spam"),

+                2 : UBInt16("spam"),

+                3 : UBInt32("spam"),

+                4 : UBInt64("spam"),

+            }

+        ),

+    )

+    """

+    

+    class NoDefault(Construct):

+        def _parse(self, stream, context):

+            raise SwitchError("no default case defined")

+        def _build(self, obj, stream, context):

+            raise SwitchError("no default case defined")

+        def _sizeof(self, context):

+            raise SwitchError("no default case defined")

+    NoDefault = NoDefault("NoDefault")

+    

+    __slots__ = ["subcons", "keyfunc", "cases", "default", "include_key"]

+    

+    def __init__(self, name, keyfunc, cases, default = NoDefault, 

+                 include_key = False):

+        Construct.__init__(self, name)

+        self._inherit_flags(*cases.values())

+        self.keyfunc = keyfunc

+        self.cases = cases

+        self.default = default

+        self.include_key = include_key

+        self._inherit_flags(*cases.values())

+        self._set_flag(self.FLAG_DYNAMIC)

+    def _parse(self, stream, context):

+        key = self.keyfunc(context)

+        obj = self.cases.get(key, self.default)._parse(stream, context)

+        if self.include_key:

+            return key, obj

+        else:

+            return obj

+    def _build(self, obj, stream, context):

+        if self.include_key:

+            key, obj = obj

+        else:

+            key = self.keyfunc(context)

+        case = self.cases.get(key, self.default)

+        case._build(obj, stream, context)

+    def _sizeof(self, context):

+        case = self.cases.get(self.keyfunc(context), self.default)

+        return case._sizeof(context)

+

+class Select(Construct):

+    """

+    Selects the first matching subconstruct. It will literally try each of

+    the subconstructs, until one matches.

+    

+    Notes:

+    * requires a seekable stream.

+    

+    Parameters:

+    * name - the name of the construct

+    * subcons - the subcons to try (order-sensitive)

+    * include_name - a keyword only argument, indicating whether to include 

+      the name of the selected subcon in the return value of parsing. default

+      is false.

+    

+    Example:

+    Select("foo",

+        UBInt64("large"),

+        UBInt32("medium"),

+        UBInt16("small"),

+        UBInt8("tiny"),

+    )

+    """

+    __slots__ = ["subcons", "include_name"]

+    def __init__(self, name, *subcons, **kw):

+        include_name = kw.pop("include_name", False)

+        if kw:

+            raise TypeError("the only keyword argument accepted "

+                "is 'include_name'", kw)

+        Construct.__init__(self, name)

+        self.subcons = subcons

+        self.include_name = include_name

+        self._inherit_flags(*subcons)

+        self._set_flag(self.FLAG_DYNAMIC)

+    def _parse(self, stream, context):

+        for sc in self.subcons:

+            pos = stream.tell()

+            context2 = context.__copy__()

+            try:

+                obj = sc._parse(stream, context2)

+            except ConstructError:

+                stream.seek(pos)

+            else:

+                context.__update__(context2)

+                if self.include_name:

+                    return sc.name, obj

+                else:

+                    return obj

+        raise SelectError("no subconstruct matched")

+    def _build(self, obj, stream, context):

+        if self.include_name:

+            name, obj = obj

+            for sc in self.subcons:

+                if sc.name == name:

+                    sc._build(obj, stream, context)

+                    return

+        else: 

+            for sc in self.subcons:

+                stream2 = StringIO()

+                context2 = context.__copy__()

+                try:

+                    sc._build(obj, stream2, context2)

+                except Exception:

+                    pass

+                else:

+                    context.__update__(context2)

+                    stream.write(stream2.getvalue())

+                    return

+        raise SelectError("no subconstruct matched", obj)

+    def _sizeof(self, context):

+        raise SizeofError("can't calculate size")

+

+

+#===============================================================================

+# stream manipulation

+#===============================================================================

+class Pointer(Subconstruct):

+    """

+    Changes the stream position to a given offset, where the construction

+    should take place, and restores the stream position when finished.

+    See also Anchor, OnDemand and OnDemandPointer.

+    

+    Notes:

+    * requires a seekable stream.

+    

+    Parameters:

+    * offsetfunc: a function that takes the context and returns an absolute 

+      stream position, where the construction would take place

+    * subcon - the subcon to use at `offsetfunc()`

+    

+    Example:

+    Struct("foo",

+        UBInt32("spam_pointer"),

+        Pointer(lambda ctx: ctx.spam_pointer,

+            Array(5, UBInt8("spam"))

+        )

+    )

+    """

+    __slots__ = ["offsetfunc"]

+    def __init__(self, offsetfunc, subcon):

+        Subconstruct.__init__(self, subcon)

+        self.offsetfunc = offsetfunc

+    def _parse(self, stream, context):

+        newpos = self.offsetfunc(context)

+        origpos = stream.tell()

+        stream.seek(newpos)

+        obj = self.subcon._parse(stream, context)

+        stream.seek(origpos)

+        return obj

+    def _build(self, obj, stream, context):

+        newpos = self.offsetfunc(context)

+        origpos = stream.tell()

+        stream.seek(newpos)

+        self.subcon._build(obj, stream, context)

+        stream.seek(origpos)

+    def _sizeof(self, context):

+        return 0

+

+class Peek(Subconstruct):

+    """

+    Peeks at the stream: parses without changing the stream position.

+    See also Union. If the end of the stream is reached when peeking,

+    returns None.

+    

+    Notes:

+    * requires a seekable stream.

+    

+    Parameters:

+    * subcon - the subcon to peek at

+    * perform_build - whether or not to perform building. by default this 

+      parameter is set to False, meaning building is a no-op.

+    

+    Example:

+    Peek(UBInt8("foo"))

+    """

+    __slots__ = ["perform_build"]

+    def __init__(self, subcon, perform_build = False):

+        Subconstruct.__init__(self, subcon)

+        self.perform_build = perform_build

+    def _parse(self, stream, context):

+        pos = stream.tell()

+        try:

+            try:

+                return self.subcon._parse(stream, context)

+            except FieldError:

+                pass

+        finally:

+            stream.seek(pos)

+    def _build(self, obj, stream, context):

+        if self.perform_build:

+            self.subcon._build(obj, stream, context)

+    def _sizeof(self, context):

+        return 0

+

+class OnDemand(Subconstruct):

+    """

+    Allows for on-demand (lazy) parsing. When parsing, it will return a 

+    LazyContainer that represents a pointer to the data, but does not actually

+    parses it from stream until it's "demanded".

+    By accessing the 'value' property of LazyContainers, you will demand the 

+    data from the stream. The data will be parsed and cached for later use.

+    You can use the 'has_value' property to know whether the data has already 

+    been demanded.

+    See also OnDemandPointer.

+    

+    Notes:

+    * requires a seekable stream.

+    

+    Parameters:

+    * subcon - 

+    * advance_stream - whether or not to advance the stream position. by 

+      default this is True, but if subcon is a pointer, this should be False.

+    * force_build - whether or not to force build. If set to False, and the

+      LazyContainer has not been demaned, building is a no-op.

+    

+    Example:

+    OnDemand(Array(10000, UBInt8("foo"))

+    """

+    __slots__ = ["advance_stream", "force_build"]

+    def __init__(self, subcon, advance_stream = True, force_build = True):

+        Subconstruct.__init__(self, subcon)

+        self.advance_stream = advance_stream

+        self.force_build = force_build

+    def _parse(self, stream, context):

+        obj = LazyContainer(self.subcon, stream, stream.tell(), context)

+        if self.advance_stream:

+            stream.seek(self.subcon._sizeof(context), 1)

+        return obj

+    def _build(self, obj, stream, context):

+        if not isinstance(obj, LazyContainer):

+            self.subcon._build(obj, stream, context)

+        elif self.force_build or obj.has_value:

+            self.subcon._build(obj.value, stream, context)

+        elif self.advance_stream:

+            stream.seek(self.subcon._sizeof(context), 1)

+

+class Buffered(Subconstruct):

+    """

+    Creates an in-memory buffered stream, which can undergo encoding and 

+    decoding prior to being passed on to the subconstruct.

+    See also Bitwise.

+    

+    Note:

+    * Do not use pointers inside Buffered

+    

+    Parameters:

+    * subcon - the subcon which will operate on the buffer

+    * encoder - a function that takes a string and returns an encoded

+      string (used after building)

+    * decoder - a function that takes a string and returns a decoded

+      string (used before parsing)

+    * resizer - a function that takes the size of the subcon and "adjusts"

+      or "resizes" it according to the encoding/decoding process.

+    

+    Example:

+    Buffered(BitField("foo", 16),

+        encoder = decode_bin,

+        decoder = encode_bin,

+        resizer = lambda size: size / 8,

+    )

+    """

+    __slots__ = ["encoder", "decoder", "resizer"]

+    def __init__(self, subcon, decoder, encoder, resizer):

+        Subconstruct.__init__(self, subcon)

+        self.encoder = encoder

+        self.decoder = decoder

+        self.resizer = resizer

+    def _parse(self, stream, context):

+        data = _read_stream(stream, self._sizeof(context))

+        stream2 = StringIO(self.decoder(data))

+        return self.subcon._parse(stream2, context)

+    def _build(self, obj, stream, context):

+        size = self._sizeof(context)

+        stream2 = StringIO()

+        self.subcon._build(obj, stream2, context)

+        data = self.encoder(stream2.getvalue())

+        assert len(data) == size

+        _write_stream(stream, self._sizeof(context), data)

+    def _sizeof(self, context):

+        return self.resizer(self.subcon._sizeof(context))

+

+class Restream(Subconstruct):

+    """

+    Wraps the stream with a read-wrapper (for parsing) or a 

+    write-wrapper (for building). The stream wrapper can buffer the data

+    internally, reading it from- or writing it to the underlying stream 

+    as needed. For example, BitStreamReader reads whole bytes from the 

+    underlying stream, but returns them as individual bits. 

+    See also Bitwise.

+    

+    When the parsing or building is done, the stream's close method 

+    will be invoked. It can perform any finalization needed for the stream

+    wrapper, but it must not close the underlying stream.

+    

+    Note:

+    * Do not use pointers inside Restream

+    

+    Parameters:

+    * subcon - the subcon

+    * stream_reader - the read-wrapper

+    * stream_writer - the write wrapper

+    * resizer - a function that takes the size of the subcon and "adjusts"

+      or "resizes" it according to the encoding/decoding process.

+    

+    Example:

+    Restream(BitField("foo", 16),

+        stream_reader = BitStreamReader,

+        stream_writer = BitStreamWriter,

+        resizer = lambda size: size / 8,

+    )

+    """

+    __slots__ = ["stream_reader", "stream_writer", "resizer"]

+    def __init__(self, subcon, stream_reader, stream_writer, resizer):

+        Subconstruct.__init__(self, subcon)

+        self.stream_reader = stream_reader

+        self.stream_writer = stream_writer

+        self.resizer = resizer

+    def _parse(self, stream, context):

+        stream2 = self.stream_reader(stream)

+        obj = self.subcon._parse(stream2, context)

+        stream2.close()

+        return obj

+    def _build(self, obj, stream, context):

+        stream2 = self.stream_writer(stream)

+        self.subcon._build(obj, stream2, context)

+        stream2.close()

+    def _sizeof(self, context):

+        return self.resizer(self.subcon._sizeof(context))

+

+

+#===============================================================================

+# miscellaneous

+#===============================================================================

+class Reconfig(Subconstruct):

+    """

+    Reconfigures a subconstruct. Reconfig can be used to change the name and

+    set and clear flags of the inner subcon.

+    

+    Parameters:

+    * name - the new name

+    * subcon - the subcon to reconfigure

+    * setflags - the flags to set (default is 0)

+    * clearflags - the flags to clear (default is 0)

+    

+    Example:

+    Reconfig("foo", UBInt8("bar"))

+    """

+    __slots__ = []

+    def __init__(self, name, subcon, setflags = 0, clearflags = 0):

+        Construct.__init__(self, name, subcon.conflags)

+        self.subcon = subcon

+        self._set_flag(setflags)

+        self._clear_flag(clearflags)

+

+class Anchor(Construct):

+    """

+    Returns the "anchor" (stream position) at the point where it's inserted.

+    Useful for adjusting relative offsets to absolute positions, or to measure

+    sizes of constructs.

+    absolute pointer = anchor + relative offset

+    size = anchor_after - anchor_before

+    See also Pointer.

+    

+    Notes:

+    * requires a seekable stream.

+    

+    Parameters:

+    * name - the name of the anchor

+    

+    Example:

+    Struct("foo",

+        Anchor("base"),

+        UBInt8("relative_offset"),

+        Pointer(lambda ctx: ctx.relative_offset + ctx.base,

+            UBInt8("data")

+        )

+    )

+    """

+    __slots__ = []

+    def _parse(self, stream, context):

+        return stream.tell()

+    def _build(self, obj, stream, context):

+        context[self.name] = stream.tell()

+    def _sizeof(self, context):

+        return 0

+

+class Value(Construct):

+    """

+    A computed value.

+    

+    Parameters:

+    * name - the name of the value

+    * func - a function that takes the context and return the computed value

+    

+    Example:

+    Struct("foo",

+        UBInt8("width"),

+        UBInt8("height"),

+        Value("total_pixels", lambda ctx: ctx.width * ctx.height),

+    )

+    """

+    __slots__ = ["func"]

+    def __init__(self, name, func):

+        Construct.__init__(self, name)

+        self.func = func

+        self._set_flag(self.FLAG_DYNAMIC)

+    def _parse(self, stream, context):

+        return self.func(context)

+    def _build(self, obj, stream, context):

+        context[self.name] = self.func(context)

+    def _sizeof(self, context):

+        return 0

+

+#class Dynamic(Construct):

+#    """

+#    Dynamically creates a construct and uses it for parsing and building.

+#    This allows you to create change the construction tree on the fly.

+#    Deprecated.

+#    

+#    Parameters:

+#    * name - the name of the construct

+#    * factoryfunc - a function that takes the context and returns a new 

+#      construct object which will be used for parsing and building.

+#    

+#    Example:

+#    def factory(ctx):

+#        if ctx.bar == 8:

+#            return UBInt8("spam")

+#        if ctx.bar == 9:

+#            return String("spam", 9)

+#    

+#    Struct("foo",

+#        UBInt8("bar"),

+#        Dynamic("spam", factory),

+#    )

+#    """

+#    __slots__ = ["factoryfunc"]

+#    def __init__(self, name, factoryfunc):

+#        Construct.__init__(self, name, self.FLAG_COPY_CONTEXT)

+#        self.factoryfunc = factoryfunc

+#        self._set_flag(self.FLAG_DYNAMIC)

+#    def _parse(self, stream, context):

+#        return self.factoryfunc(context)._parse(stream, context)

+#    def _build(self, obj, stream, context):

+#        return self.factoryfunc(context)._build(obj, stream, context)

+#    def _sizeof(self, context):

+#        return self.factoryfunc(context)._sizeof(context)

+

+class LazyBound(Construct):

+    """

+    Lazily bound construct, useful for constructs that need to make cyclic 

+    references (linked-lists, expression trees, etc.).

+    

+    Parameters:

+    

+    

+    Example:

+    foo = Struct("foo",

+        UBInt8("bar"),

+        LazyBound("next", lambda: foo),

+    )

+    """

+    __slots__ = ["bindfunc", "bound"]

+    def __init__(self, name, bindfunc):

+        Construct.__init__(self, name)

+        self.bound = None

+        self.bindfunc = bindfunc

+    def _parse(self, stream, context):

+        if self.bound is None:

+            self.bound = self.bindfunc()

+        return self.bound._parse(stream, context)

+    def _build(self, obj, stream, context):

+        if self.bound is None:

+            self.bound = self.bindfunc()

+        self.bound._build(obj, stream, context)

+    def _sizeof(self, context):

+        if self.bound is None:

+            self.bound = self.bindfunc()

+        return self.bound._sizeof(context)

+

+class Pass(Construct):

+    """

+    A do-nothing construct, useful as the default case for Switch, or

+    to indicate Enums.

+    See also Switch and Enum.

+    

+    Notes:

+    * this construct is a singleton. do not try to instatiate it, as it 

+      will not work :)

+    

+    Example:

+    Pass

+    """

+    __slots__ = []

+    def _parse(self, stream, context):

+        pass

+    def _build(self, obj, stream, context):

+        assert obj is None

+    def _sizeof(self, context):

+        return 0

+Pass = Pass(None)

+

+class Terminator(Construct):

+    """

+    Asserts the end of the stream has been reached at the point it's placed.

+    You can use this to ensure no more unparsed data follows.

+    

+    Notes:

+    * this construct is a singleton. do not try to instatiate it, as it 

+      will not work :)

+    

+    Example:

+    Terminator

+    """

+    __slots__ = []

+    def _parse(self, stream, context):

+        if stream.read(1):

+            raise TerminatorError("expected end of stream")

+    def _build(self, obj, stream, context):

+        assert obj is None

+    def _sizeof(self, context):

+        return 0

+Terminator = Terminator(None)

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/elftools/construct/debug.py b/elftools/construct/debug.py
new file mode 100644
index 0000000..47e47c6
--- /dev/null
+++ b/elftools/construct/debug.py
@@ -0,0 +1,160 @@
+"""

+Debugging utilities for constructs

+"""

+import sys

+import traceback

+import pdb

+import inspect

+from core import Construct, Subconstruct

+from lib import HexString, Container, ListContainer, AttrDict

+

+

+class Probe(Construct):

+    """

+    A probe: dumps the context, stack frames, and stream content to the screen

+    to aid the debugging process.

+    See also Debugger.

+    

+    Parameters:

+    * name - the display name

+    * show_stream - whether or not to show stream contents. default is True. 

+      the stream must be seekable.

+    * show_context - whether or not to show the context. default is True.

+    * show_stack - whether or not to show the upper stack frames. default 

+      is True.

+    * stream_lookahead - the number of bytes to dump when show_stack is set.

+      default is 100.

+    

+    Example:

+    Struct("foo",

+        UBInt8("a"),

+        Probe("between a and b"),

+        UBInt8("b"),

+    )

+    """

+    __slots__ = [

+        "printname", "show_stream", "show_context", "show_stack", 

+        "stream_lookahead"

+    ]

+    counter = 0

+    

+    def __init__(self, name = None, show_stream = True, 

+                 show_context = True, show_stack = True, 

+                 stream_lookahead = 100):

+        Construct.__init__(self, None)

+        if name is None:

+            Probe.counter += 1

+            name = "<unnamed %d>" % (Probe.counter,)

+        self.printname = name

+        self.show_stream = show_stream

+        self.show_context = show_context

+        self.show_stack = show_stack

+        self.stream_lookahead = stream_lookahead

+    def __repr__(self):

+        return "%s(%r)" % (self.__class__.__name__, self.printname)

+    def _parse(self, stream, context):

+        self.printout(stream, context)

+    def _build(self, obj, stream, context):

+        self.printout(stream, context)

+    def _sizeof(self, context):

+        return 0

+    

+    def printout(self, stream, context):

+        obj = Container()

+        if self.show_stream:

+            obj.stream_position = stream.tell()

+            follows = stream.read(self.stream_lookahead)

+            if not follows:

+                obj.following_stream_data = "EOF reached"

+            else:

+                stream.seek(-len(follows), 1)

+                obj.following_stream_data = HexString(follows)

+            print

+        

+        if self.show_context:

+            obj.context = context

+        

+        if self.show_stack:

+            obj.stack = ListContainer()

+            frames = [s[0] for s in inspect.stack()][1:-1]

+            frames.reverse()

+            for f in frames:

+                a = AttrDict()

+                a.__update__(f.f_locals)

+                obj.stack.append(a)

+        

+        print "=" * 80

+        print "Probe", self.printname

+        print obj

+        print "=" * 80

+

+class Debugger(Subconstruct):

+    """

+    A pdb-based debugger. When an exception occurs in the subcon, a debugger

+    will appear and allow you to debug the error (and even fix on-the-fly).

+    

+    Parameters:

+    * subcon - the subcon to debug

+    

+    Example:

+    Debugger(

+        Enum(UBInt8("foo"),

+            a = 1,

+            b = 2,

+            c = 3

+        )

+    )

+    """

+    __slots__ = ["retval"]

+    def _parse(self, stream, context):

+        try:

+            return self.subcon._parse(stream, context)

+        except Exception:

+            self.retval = NotImplemented

+            self.handle_exc("(you can set the value of 'self.retval', "

+                "which will be returned)")

+            if self.retval is NotImplemented:

+                raise

+            else:

+                return self.retval

+    def _build(self, obj, stream, context):

+        try:

+            self.subcon._build(obj, stream, context)

+        except Exception:

+            self.handle_exc()

+    def handle_exc(self, msg = None):

+        print "=" * 80

+        print "Debugging exception of %s:" % (self.subcon,)

+        print "".join(traceback.format_exception(*sys.exc_info())[1:])

+        if msg:

+            print msg

+        pdb.post_mortem(sys.exc_info()[2])

+        print "=" * 80

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/elftools/construct/lib/__init__.py b/elftools/construct/lib/__init__.py
new file mode 100644
index 0000000..23f0820
--- /dev/null
+++ b/elftools/construct/lib/__init__.py
@@ -0,0 +1,10 @@
+from binary import int_to_bin, bin_to_int, swap_bytes, encode_bin, decode_bin

+from bitstream import BitStreamReader, BitStreamWriter

+from container import (Container, AttrDict, FlagsContainer, 

+    ListContainer, LazyContainer)

+from hex import HexString, hexdump

+from utils import Packer, StringIO

+

+

+

+

diff --git a/elftools/construct/lib/binary.py b/elftools/construct/lib/binary.py
new file mode 100644
index 0000000..971882e
--- /dev/null
+++ b/elftools/construct/lib/binary.py
@@ -0,0 +1,61 @@
+def int_to_bin(number, width = 32):

+    if number < 0:

+        number += 1 << width

+    i = width - 1

+    bits = ["\x00"] * width

+    while number and i >= 0:

+        bits[i] = "\x00\x01"[number & 1]

+        number >>= 1

+        i -= 1

+    return "".join(bits)

+

+_bit_values = {"\x00" : 0, "\x01" : 1, "0" : 0, "1" : 1}

+def bin_to_int(bits, signed = False):

+    number = 0

+    bias = 0

+    if signed and _bit_values[bits[0]] == 1:

+        bits = bits[1:]

+        bias = 1 << len(bits)

+    for b in bits:

+        number <<= 1

+        number |= _bit_values[b]

+    return number - bias

+

+def swap_bytes(bits, bytesize = 8):

+    i = 0

+    l = len(bits)

+    output = [""] * ((l // bytesize) + 1)

+    j = len(output) - 1

+    while i < l:

+        output[j] = bits[i : i + bytesize]

+        i += bytesize

+        j -= 1

+    return "".join(output)

+

+_char_to_bin = {}

+_bin_to_char = {}

+for i in range(256):

+    ch = chr(i)

+    bin = int_to_bin(i, 8)

+    _char_to_bin[ch] = bin

+    _bin_to_char[bin] = ch

+    _bin_to_char[bin] = ch

+

+def encode_bin(data):

+    return "".join(_char_to_bin[ch] for ch in data)

+

+def decode_bin(data):

+    assert len(data) & 7 == 0, "data length must be a multiple of 8"

+    i = 0

+    j = 0

+    l = len(data) // 8

+    chars = [""] * l

+    while j < l:

+        chars[j] = _bin_to_char[data[i:i+8]]

+        i += 8

+        j += 1

+    return "".join(chars)

+

+

+

+

diff --git a/elftools/construct/lib/bitstream.py b/elftools/construct/lib/bitstream.py
new file mode 100644
index 0000000..ff56be6
--- /dev/null
+++ b/elftools/construct/lib/bitstream.py
@@ -0,0 +1,80 @@
+from binary import encode_bin, decode_bin

+

+

+class BitStreamReader(object):

+    __slots__ = ["substream", "buffer", "total_size"]

+    def __init__(self, substream):

+        self.substream = substream

+        self.total_size = 0

+        self.buffer = ""

+    def close(self):

+        if self.total_size % 8 != 0:

+            raise ValueError("total size of read data must be a multiple of 8",

+                self.total_size)

+    def tell(self):

+        return self.substream.tell()

+    def seek(self, pos, whence = 0):

+        self.buffer = ""

+        self.total_size = 0

+        self.substream.seek(pos, whence)

+    def read(self, count):

+        assert count >= 0

+        l = len(self.buffer)

+        if count == 0:

+            data = ""

+        elif count <= l:

+            data = self.buffer[:count]

+            self.buffer = self.buffer[count:]

+        else:

+            data = self.buffer

+            count -= l

+            bytes = count // 8

+            if count & 7: 

+                bytes += 1

+            buf = encode_bin(self.substream.read(bytes))

+            data += buf[:count]

+            self.buffer = buf[count:]

+        self.total_size += len(data)

+        return data

+

+

+class BitStreamWriter(object):

+    __slots__ = ["substream", "buffer", "pos"]

+    def __init__(self, substream):

+        self.substream = substream

+        self.buffer = []

+        self.pos = 0

+    def close(self):

+        self.flush()

+    def flush(self):

+        bytes = decode_bin("".join(self.buffer))

+        self.substream.write(bytes)

+        self.buffer = []

+        self.pos = 0

+    def tell(self):

+        return self.substream.tell() + self.pos // 8

+    def seek(self, pos, whence = 0):

+        self.flush()

+        self.substream.seek(pos, whence)

+    def write(self, data):

+        if not data:

+            return

+        if type(data) is not str:

+            raise TypeError("data must be a string, not %r" % (type(data),))

+        self.buffer.append(data)

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/elftools/construct/lib/container.py b/elftools/construct/lib/container.py
new file mode 100644
index 0000000..66f8ab4
--- /dev/null
+++ b/elftools/construct/lib/container.py
@@ -0,0 +1,258 @@
+def recursion_lock(retval, lock_name = "__recursion_lock__"):

+    def decorator(func):

+        def wrapper(self, *args, **kw):

+            if getattr(self, lock_name, False):

+                return retval

+            setattr(self, lock_name, True)

+            try:

+                return func(self, *args, **kw)

+            finally:

+                setattr(self, lock_name, False)

+        wrapper.__name__ = func.__name__

+        return wrapper

+    return decorator

+

+class Container(object):

+    """

+    A generic container of attributes

+    """

+    __slots__ = ["__dict__", "__attrs__"]

+    def __init__(self, **kw):

+        self.__dict__.update(kw)

+        object.__setattr__(self, "__attrs__", kw.keys())

+    

+    def __eq__(self, other):

+        try:

+            return self.__dict__ == other.__dict__

+        except AttributeError:

+            return False

+    def __ne__(self, other):

+        return not (self == other)

+    

+    def __delattr__(self, name):

+        object.__delattr__(self, name)

+        self.__attrs__.remove(name)

+    def __setattr__(self, name, value):

+        d = self.__dict__

+        if name not in d:

+            self.__attrs__.append(name)

+        d[name] = value

+    def __getitem__(self, name):

+        return self.__dict__[name]

+    def __delitem__(self, name):

+        self.__delattr__(name)

+    def __setitem__(self, name, value):

+        self.__setattr__(name, value)

+    def __update__(self, obj):

+        for name in obj.__attrs__:

+            self[name] = obj[name]

+    def __copy__(self):

+        new = self.__class__()

+        new.__attrs__ = self.__attrs__[:]

+        new.__dict__ = self.__dict__.copy()

+        return new

+    

+    @recursion_lock("<...>")

+    def __repr__(self):

+        attrs = sorted("%s = %r" % (k, v) 

+            for k, v in self.__dict__.iteritems() 

+            if not k.startswith("_"))

+        return "%s(%s)" % (self.__class__.__name__, ", ".join(attrs))

+    def __str__(self):

+        return self.__pretty_str__()

+    @recursion_lock("<...>")

+    def __pretty_str__(self, nesting = 1, indentation = "    "):

+        attrs = []

+        ind = indentation * nesting

+        for k in self.__attrs__:

+            v = self.__dict__[k]

+            if not k.startswith("_"):

+                text = [ind, k, " = "]

+                if hasattr(v, "__pretty_str__"):

+                    text.append(v.__pretty_str__(nesting + 1, indentation))

+                else:

+                    text.append(repr(v))

+                attrs.append("".join(text))

+        if not attrs:

+            return "%s()" % (self.__class__.__name__,)

+        attrs.insert(0, self.__class__.__name__ + ":")

+        return "\n".join(attrs)

+

+class FlagsContainer(Container):

+    """

+    A container providing pretty-printing for flags. Only set flags are 

+    displayed. 

+    """

+    def __pretty_str__(self, nesting = 1, indentation = "    "):

+        attrs = []

+        ind = indentation * nesting

+        for k in self.__attrs__:

+            v = self.__dict__[k]

+            if not k.startswith("_") and v:

+                attrs.append(ind + k)

+        if not attrs:

+            return "%s()" % (self.__class__.__name__,)

+        attrs.insert(0, self.__class__.__name__+ ":")

+        return "\n".join(attrs)

+

+class ListContainer(list):

+    """

+    A container for lists

+    """

+    __slots__ = ["__recursion_lock__"]

+    def __str__(self):

+        return self.__pretty_str__()

+    @recursion_lock("[...]")

+    def __pretty_str__(self, nesting = 1, indentation = "    "):

+        if not self:

+            return "[]"

+        ind = indentation * nesting

+        lines = ["["]

+        for elem in self:

+            lines.append("\n")

+            lines.append(ind)

+            if hasattr(elem, "__pretty_str__"):

+                lines.append(elem.__pretty_str__(nesting + 1, indentation))

+            else:

+                lines.append(repr(elem))

+        lines.append("\n")

+        lines.append(indentation * (nesting - 1))

+        lines.append("]")

+        return "".join(lines)

+

+class AttrDict(object):

+    """

+    A dictionary that can be accessed both using indexing and attributes,

+    i.e., 

+        x = AttrDict()

+        x.foo = 5

+        print x["foo"]

+    """

+    __slots__ = ["__dict__"]

+    def __init__(self, **kw):

+        self.__dict__ = kw

+    def __contains__(self, key):

+        return key in self.__dict__

+    def __nonzero__(self):

+        return bool(self.__dict__)

+    def __repr__(self):

+        return repr(self.__dict__)

+    def __str__(self):

+        return self.__pretty_str__()

+    def __pretty_str__(self, nesting = 1, indentation = "    "):

+        if not self:

+            return "{}"

+        text = ["{\n"]

+        ind = nesting * indentation

+        for k in sorted(self.__dict__.keys()):

+            v = self.__dict__[k]

+            text.append(ind)

+            text.append(repr(k))

+            text.append(" : ")

+            if hasattr(v, "__pretty_str__"):

+                try:

+                    text.append(v.__pretty_str__(nesting+1, indentation))

+                except Exception:

+                    text.append(repr(v))

+            else:

+                text.append(repr(v))

+            text.append("\n")

+        text.append((nesting-1) * indentation)

+        text.append("}")

+        return "".join(text)

+    def __delitem__(self, key):

+        del self.__dict__[key]

+    def __getitem__(self, key):

+        return self.__dict__[key]

+    def __setitem__(self, key, value):

+        self.__dict__[key] = value

+    def __copy__(self):

+        new = self.__class__()

+        new.__dict__ = self.__dict__.copy()

+        return new

+    def __update__(self, other):

+        if isinstance(other, dict):

+            self.__dict__.update(other)

+        else:

+            self.__dict__.update(other.__dict__)

+

+class LazyContainer(object):

+    __slots__ = ["subcon", "stream", "pos", "context", "_value"]

+    def __init__(self, subcon, stream, pos, context):

+        self.subcon = subcon

+        self.stream = stream

+        self.pos = pos

+        self.context = context

+        self._value = NotImplemented

+    def __eq__(self, other):

+        try:

+            return self._value == other._value

+        except AttributeError:

+            return False

+    def __ne__(self, other):

+        return not (self == other)

+    def __str__(self):

+        return self.__pretty_str__()

+    def __pretty_str__(self, nesting = 1, indentation = "    "):

+        if self._value is NotImplemented:

+            text = "<unread>"

+        elif hasattr(self._value, "__pretty_str__"):

+            text = self._value.__pretty_str__(nesting, indentation)

+        else:

+            text = repr(self._value)

+        return "%s: %s" % (self.__class__.__name__, text)

+    def read(self):

+        self.stream.seek(self.pos)

+        return self.subcon._parse(self.stream, self.context)

+    def dispose(self):

+        self.subcon = None

+        self.stream = None

+        self.context = None

+        self.pos = None

+    def _get_value(self):

+        if self._value is NotImplemented:

+            self._value = self.read()

+        return self._value

+    value = property(_get_value)

+    has_value = property(lambda self: self._value is not NotImplemented)

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/elftools/construct/lib/hex.py b/elftools/construct/lib/hex.py
new file mode 100644
index 0000000..e392bd3
--- /dev/null
+++ b/elftools/construct/lib/hex.py
@@ -0,0 +1,34 @@
+_printable = dict((chr(i), ".") for i in range(256))

+_printable.update((chr(i), chr(i)) for i in range(32, 128))

+

+def hexdump(data, linesize = 16):

+    prettylines = []

+    if len(data) < 65536:

+        fmt = "%%04X   %%-%ds   %%s"

+    else:

+        fmt = "%%08X   %%-%ds   %%s"

+    fmt = fmt % (3 * linesize - 1,)

+    for i in xrange(0, len(data), linesize):

+        line = data[i : i + linesize]

+        hextext = " ".join(b.encode("hex") for b in line)

+        rawtext = "".join(_printable[b] for b in line)

+        prettylines.append(fmt % (i, hextext, rawtext))

+    return prettylines

+

+class HexString(str):

+    """

+    represents a string that will be hex-dumped (only via __pretty_str__).

+    this class derives of str, and behaves just like a normal string in all

+    other contexts.

+    """

+    def __init__(self, data, linesize = 16):

+        str.__init__(self, data)

+        self.linesize = linesize

+    def __new__(cls, data, *args, **kwargs):

+        return str.__new__(cls, data)

+    def __pretty_str__(self, nesting = 1, indentation = "    "):

+        sep = "\n" + indentation * nesting

+        return sep + sep.join(hexdump(self))

+

+

+

diff --git a/elftools/construct/lib/utils.py b/elftools/construct/lib/utils.py
new file mode 100644
index 0000000..968dc26
--- /dev/null
+++ b/elftools/construct/lib/utils.py
@@ -0,0 +1,22 @@
+try:

+    from cStringIO import StringIO

+except ImportError:

+    from StringIO import StringIO

+

+

+try:

+    from struct import Struct as Packer

+except ImportError:

+    from struct import pack, unpack, calcsize

+    class Packer(object):

+        __slots__ = ["format", "size"]

+        def __init__(self, format):

+            self.format = format

+            self.size = calcsize(format)

+        def pack(self, *args):

+            return pack(self.format, *args)

+        def unpack(self, data):

+            return unpack(self.format, data)

+

+

+

diff --git a/elftools/construct/macros.py b/elftools/construct/macros.py
new file mode 100644
index 0000000..35e689a
--- /dev/null
+++ b/elftools/construct/macros.py
@@ -0,0 +1,514 @@
+from lib import BitStreamReader, BitStreamWriter, encode_bin, decode_bin

+from core import *

+from adapters import *

+

+

+#===============================================================================

+# fields

+#===============================================================================

+def Field(name, length):

+    """a field

+    * name - the name of the field

+    * length - the length of the field. the length can be either an integer

+      (StaticField), or a function that takes the context as an argument and 

+      returns the length (MetaField)

+    """

+    if callable(length):

+        return MetaField(name, length)

+    else:

+        return StaticField(name, length)

+

+def BitField(name, length, swapped = False, signed = False, bytesize = 8):

+    """a bit field; must be enclosed in a BitStruct

+    * name - the name of the field

+    * length - the length of the field in bits. the length can be either 

+      an integer, or a function that takes the context as an argument and 

+      returns the length

+    * swapped - whether the value is byte-swapped (little endian). the 

+      default is False.

+    * signed - whether the value of the bitfield is a signed integer. the 

+      default is False.

+    * bytesize - the number of bits in a byte (used for byte-swapping). the

+      default is 8.

+    """

+    return BitIntegerAdapter(Field(name, length), 

+        length,

+        swapped = swapped, 

+        signed = signed,

+        bytesize = bytesize

+    )

+

+def Padding(length, pattern = "\x00", strict = False):

+    r"""a padding field (value is discarded)

+    * length - the length of the field. the length can be either an integer,

+      or a function that takes the context as an argument and returns the 

+      length

+    * pattern - the padding pattern (character) to use. default is "\x00"

+    * strict - whether or not to raise an exception is the actual padding 

+      pattern mismatches the desired pattern. default is False.

+    """

+    return PaddingAdapter(Field(None, length), 

+        pattern = pattern, 

+        strict = strict,

+    )

+

+def Flag(name, truth = 1, falsehood = 0, default = False):

+    """a flag field (True or False)

+    * name - the name of the field

+    * truth - the numeric value of truth. the default is 1.

+    * falsehood - the numeric value of falsehood. the default is 0.

+    * default - the default value to assume, when the value is neither 

+      `truth` nor `falsehood`. the default is False.

+    """

+    return SymmetricMapping(Field(name, 1), 

+        {True : chr(truth), False : chr(falsehood)},

+        default = default,

+    )

+

+#===============================================================================

+# field shortcuts

+#===============================================================================

+def Bit(name):

+    """a 1-bit BitField; must be enclosed in a BitStruct"""

+    return BitField(name, 1)

+def Nibble(name):

+    """a 4-bit BitField; must be enclosed in a BitStruct"""

+    return BitField(name, 4)

+def Octet(name):

+    """an 8-bit BitField; must be enclosed in a BitStruct"""

+    return BitField(name, 8)

+

+def UBInt8(name):

+    """unsigned, big endian 8-bit integer"""

+    return FormatField(name, ">", "B")

+def UBInt16(name):

+    """unsigned, big endian 16-bit integer"""

+    return FormatField(name, ">", "H")

+def UBInt32(name):

+    """unsigned, big endian 32-bit integer"""

+    return FormatField(name, ">", "L")

+def UBInt64(name):

+    """unsigned, big endian 64-bit integer"""

+    return FormatField(name, ">", "Q")

+

+def SBInt8(name):

+    """signed, big endian 8-bit integer"""

+    return FormatField(name, ">", "b")

+def SBInt16(name):

+    """signed, big endian 16-bit integer"""

+    return FormatField(name, ">", "h")

+def SBInt32(name):

+    """signed, big endian 32-bit integer"""

+    return FormatField(name, ">", "l")

+def SBInt64(name):

+    """signed, big endian 64-bit integer"""

+    return FormatField(name, ">", "q")

+

+def ULInt8(name):

+    """unsigned, little endian 8-bit integer"""

+    return FormatField(name, "<", "B")

+def ULInt16(name):

+    """unsigned, little endian 16-bit integer"""

+    return FormatField(name, "<", "H")

+def ULInt32(name):

+    """unsigned, little endian 32-bit integer"""

+    return FormatField(name, "<", "L")

+def ULInt64(name):

+    """unsigned, little endian 64-bit integer"""

+    return FormatField(name, "<", "Q")

+

+def SLInt8(name):

+    """signed, little endian 8-bit integer"""

+    return FormatField(name, "<", "b")

+def SLInt16(name):

+    """signed, little endian 16-bit integer"""

+    return FormatField(name, "<", "h")

+def SLInt32(name):

+    """signed, little endian 32-bit integer"""

+    return FormatField(name, "<", "l")

+def SLInt64(name):

+    """signed, little endian 64-bit integer"""

+    return FormatField(name, "<", "q")

+

+def UNInt8(name):

+    """unsigned, native endianity 8-bit integer"""

+    return FormatField(name, "=", "B")

+def UNInt16(name):

+    """unsigned, native endianity 16-bit integer"""

+    return FormatField(name, "=", "H")

+def UNInt32(name):

+    """unsigned, native endianity 32-bit integer"""

+    return FormatField(name, "=", "L")

+def UNInt64(name):

+    """unsigned, native endianity 64-bit integer"""

+    return FormatField(name, "=", "Q")

+

+def SNInt8(name):

+    """signed, native endianity 8-bit integer"""

+    return FormatField(name, "=", "b")

+def SNInt16(name):

+    """signed, native endianity 16-bit integer"""

+    return FormatField(name, "=", "h")

+def SNInt32(name):

+    """signed, native endianity 32-bit integer"""

+    return FormatField(name, "=", "l")

+def SNInt64(name):

+    """signed, native endianity 64-bit integer"""

+    return FormatField(name, "=", "q")

+

+def BFloat32(name):

+    """big endian, 32-bit IEEE floating point number"""

+    return FormatField(name, ">", "f")

+def LFloat32(name):

+    """little endian, 32-bit IEEE floating point number"""

+    return FormatField(name, "<", "f")

+def NFloat32(name):

+    """native endianity, 32-bit IEEE floating point number"""

+    return FormatField(name, "=", "f")

+

+def BFloat64(name):

+    """big endian, 64-bit IEEE floating point number"""

+    return FormatField(name, ">", "d")

+def LFloat64(name):

+    """little endian, 64-bit IEEE floating point number"""

+    return FormatField(name, "<", "d")

+def NFloat64(name):

+    """native endianity, 64-bit IEEE floating point number"""

+    return FormatField(name, "=", "d")

+

+

+#===============================================================================

+# arrays

+#===============================================================================

+def Array(count, subcon):

+    """array of subcon repeated count times.

+    * subcon - the subcon.

+    * count - an integer, or a function taking the context as an argument, 

+      returning the count

+    """

+    if callable(count):

+        con = MetaArray(count, subcon)

+    else:

+        con = MetaArray(lambda ctx: count, subcon)

+        con._clear_flag(con.FLAG_DYNAMIC)

+    return con

+

+def PrefixedArray(subcon, length_field = UBInt8("length")):

+    """an array prefixed by a length field.

+    * subcon - the subcon to be repeated

+    * length_field - an integer construct

+    """

+    return LengthValueAdapter(

+        Sequence(subcon.name, 

+            length_field, 

+            Array(lambda ctx: ctx[length_field.name], subcon),

+            nested = False

+        )

+    )

+

+def OpenRange(mincount, subcon):

+    from sys import maxint

+    return Range(mincount, maxint, subcon)

+

+def GreedyRange(subcon):

+    """an open range (1 or more times) of repeated subcon.

+    * subcon - the subcon to repeat"""

+    return OpenRange(1, subcon)

+

+def OptionalGreedyRange(subcon):

+    """an open range (0 or more times) of repeated subcon.

+    * subcon - the subcon to repeat"""

+    return OpenRange(0, subcon)

+

+

+#===============================================================================

+# subconstructs

+#===============================================================================

+def Optional(subcon):

+    """an optional construct. if parsing fails, returns None.

+    * subcon - the subcon to optionally parse or build

+    """

+    return Select(subcon.name, subcon, Pass)

+

+def Bitwise(subcon):

+    """converts the stream to bits, and passes the bitstream to subcon

+    * subcon - a bitwise construct (usually BitField)

+    """

+    # subcons larger than MAX_BUFFER will be wrapped by Restream instead 

+    # of Buffered. implementation details, don't stick your nose :)

+    MAX_BUFFER = 1024 * 8

+    def resizer(length):

+        if length & 7:

+            raise SizeofError("size must be a multiple of 8", length)

+        return length >> 3

+    if not subcon._is_flag(subcon.FLAG_DYNAMIC) and subcon.sizeof() < MAX_BUFFER:

+        con = Buffered(subcon, 

+            encoder = decode_bin, 

+            decoder = encode_bin, 

+            resizer = resizer

+        )

+    else:

+        con = Restream(subcon, 

+            stream_reader = BitStreamReader, 

+            stream_writer = BitStreamWriter, 

+            resizer = resizer)

+    return con

+

+def Aligned(subcon, modulus = 4, pattern = "\x00"):

+    r"""aligns subcon to modulus boundary using padding pattern

+    * subcon - the subcon to align

+    * modulus - the modulus boundary (default is 4)

+    * pattern - the padding pattern (default is \x00)

+    """

+    if modulus < 2:

+        raise ValueError("modulus must be >= 2", modulus)

+    if modulus in (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024):

+        def padlength(ctx):

+            m1 = modulus - 1

+            return (modulus - (subcon._sizeof(ctx) & m1)) & m1

+    else:

+        def padlength(ctx):

+            return (modulus - (subcon._sizeof(ctx) % modulus)) % modulus

+    return IndexingAdapter(

+        Sequence(subcon.name, 

+            subcon, 

+            Padding(padlength, pattern = pattern),

+            nested = False,

+        ),

+        0

+    )

+

+def Embedded(subcon):

+    """embeds a struct into the enclosing struct.

+    * subcon - the struct to embed

+    """

+    return Reconfig(subcon.name, subcon, subcon.FLAG_EMBED)

+

+def Rename(newname, subcon):

+    """renames an existing construct

+    * newname - the new name

+    * subcon - the subcon to rename

+    """

+    return Reconfig(newname, subcon)

+

+def Alias(newname, oldname):

+    """creates an alias for an existing element in a struct

+    * newname - the new name

+    * oldname - the name of an existing element

+    """

+    return Value(newname, lambda ctx: ctx[oldname])

+

+

+#===============================================================================

+# mapping

+#===============================================================================

+def SymmetricMapping(subcon, mapping, default = NotImplemented):

+    """defines a symmetrical mapping: a->b, b->a.

+    * subcon - the subcon to map

+    * mapping - the encoding mapping (a dict); the decoding mapping is 

+      achieved by reversing this mapping

+    * default - the default value to use when no mapping is found. if no 

+      default value is given, and exception is raised. setting to Pass would

+      return the value "as is" (unmapped)

+    """

+    reversed_mapping = dict((v, k) for k, v in mapping.iteritems())

+    return MappingAdapter(subcon, 

+        encoding = mapping, 

+        decoding = reversed_mapping, 

+        encdefault = default,

+        decdefault = default, 

+    )

+

+def Enum(subcon, **kw):

+    """a set of named values mapping. 

+    * subcon - the subcon to map

+    * kw - keyword arguments which serve as the encoding mapping

+    * _default_ - an optional, keyword-only argument that specifies the 

+      default value to use when the mapping is undefined. if not given,

+      and exception is raised when the mapping is undefined. use `Pass` to

+      pass the unmapped value as-is

+    """

+    return SymmetricMapping(subcon, kw, kw.pop("_default_", NotImplemented))

+

+def FlagsEnum(subcon, **kw):

+    """a set of flag values mapping.

+    * subcon - the subcon to map

+    * kw - keyword arguments which serve as the encoding mapping

+    """

+    return FlagsAdapter(subcon, kw)

+

+

+#===============================================================================

+# structs

+#===============================================================================

+def AlignedStruct(name, *subcons, **kw):

+    """a struct of aligned fields

+    * name - the name of the struct

+    * subcons - the subcons that make up this structure

+    * kw - keyword arguments to pass to Aligned: 'modulus' and 'pattern'

+    """

+    return Struct(name, *(Aligned(sc, **kw) for sc in subcons))

+

+def BitStruct(name, *subcons):

+    """a struct of bitwise fields

+    * name - the name of the struct

+    * subcons - the subcons that make up this structure

+    """

+    return Bitwise(Struct(name, *subcons))

+

+def EmbeddedBitStruct(*subcons):

+    """an embedded BitStruct. no name is necessary.

+    * subcons - the subcons that make up this structure

+    """

+    return Bitwise(Embedded(Struct(None, *subcons)))

+

+#===============================================================================

+# strings

+#===============================================================================

+def String(name, length, encoding = None, padchar = None, 

+           paddir = "right", trimdir = "right"):

+    """a fixed-length, optionally padded string of characters

+    * name - the name of the field

+    * length - the length (integer)

+    * encoding - the encoding to use (e.g., "utf8"), or None, for raw bytes.

+      default is None

+    * padchar - the padding character (commonly "\x00"), or None to 

+      disable padding. default is None

+    * paddir - the direction where padding is placed ("right", "left", or 

+      "center"). the default is "right". this argument is meaningless if 

+      padchar is None.

+    * trimdir - the direction where trimming will take place ("right" or 

+      "left"). the default is "right". trimming is only meaningful for

+      building, when the given string is too long. this argument is 

+      meaningless if padchar is None.

+    """

+    con = StringAdapter(Field(name, length), encoding = encoding)

+    if padchar is not None:

+        con = PaddedStringAdapter(con, 

+            padchar = padchar, 

+            paddir = paddir, 

+            trimdir = trimdir

+        )

+    return con

+

+def PascalString(name, length_field = UBInt8("length"), encoding = None):

+    """a string prefixed with a length field. the data must directly follow 

+    the length field.

+    * name - the name of the 

+    * length_field - a numeric construct (i.e., UBInt8) that holds the 

+      length. default is an unsigned, 8-bit integer field. note that this

+      argument must pass an instance of a construct, not a class 

+      (`UBInt8("length")` rather than `UBInt8`)

+    * encoding - the encoding to use (e.g., "utf8"), or None, for raw bytes.

+      default is None

+    """

+    return StringAdapter(

+        LengthValueAdapter(

+            Sequence(name,

+                length_field,

+                Field("data", lambda ctx: ctx[length_field.name]),

+            )

+        ),

+        encoding = encoding,

+    )

+

+def CString(name, terminators = "\x00", encoding = None, 

+            char_field = Field(None, 1)):

+    r"""a c-style string (string terminated by a terminator char)

+    * name - the name fo the string

+    * terminators - a sequence of terminator chars. default is "\x00".

+    * encoding - the encoding to use (e.g., "utf8"), or None, for raw bytes.

+      default is None

+    * char_field - the construct that represents a single character. default

+      is a one-byte character. note that this argument must be an instance

+      of a construct, not a construct class (`Field("char", 1)` rather than

+      `Field`)

+    """

+    return Rename(name,

+        CStringAdapter(

+            RepeatUntil(lambda obj, ctx: obj in terminators, 

+                char_field,

+            ),

+            terminators = terminators,

+            encoding = encoding,

+        )

+    )

+

+

+#===============================================================================

+# conditional

+#===============================================================================

+def IfThenElse(name, predicate, then_subcon, else_subcon):

+    """an if-then-else conditional construct: if the predicate indicates True,

+    `then_subcon` will be used; otherwise `else_subcon`

+    * name - the name of the construct

+    * predicate - a function taking the context as an argument and returning

+      True or False

+    * then_subcon - the subcon that will be used if the predicate returns True

+    * else_subcon - the subcon that will be used if the predicate returns False

+    """

+    return Switch(name, lambda ctx: bool(predicate(ctx)),

+        {

+            True : then_subcon,

+            False : else_subcon,

+        }

+    )

+

+def If(predicate, subcon, elsevalue = None):

+    """an if-then conditional construct: if the predicate indicates True,

+    subcon will be used; otherwise, `elsevalue` will be returned instead.

+    * predicate - a function taking the context as an argument and returning

+      True or False

+    * subcon - the subcon that will be used if the predicate returns True

+    * elsevalue - the value that will be used should the predicate return False.

+      by default this value is None.

+    """

+    return IfThenElse(subcon.name, 

+        predicate, 

+        subcon, 

+        Value("elsevalue", lambda ctx: elsevalue)

+    )

+

+

+#===============================================================================

+# misc

+#===============================================================================

+def OnDemandPointer(offsetfunc, subcon, force_build = True):

+    """an on-demand pointer. 

+    * offsetfunc - a function taking the context as an argument and returning 

+      the absolute stream position

+    * subcon - the subcon that will be parsed from the `offsetfunc()` stream 

+      position on demand

+    * force_build - see OnDemand. by default True.

+    """

+    return OnDemand(Pointer(offsetfunc, subcon), 

+        advance_stream = False, 

+        force_build = force_build

+    )

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/elftools/construct/text.py b/elftools/construct/text.py
new file mode 100644
index 0000000..dee47a1
--- /dev/null
+++ b/elftools/construct/text.py
@@ -0,0 +1,286 @@
+from core import *

+from adapters import *

+from macros import *

+

+

+#===============================================================================

+# exceptions

+#===============================================================================

+class QuotedStringError(ConstructError):

+    __slots__ = []

+

+

+#===============================================================================

+# constructs

+#===============================================================================

+class QuotedString(Construct):

+    r"""

+    A quoted string (begins with an opening-quote, terminated by a 

+    closing-quote, which may be escaped by an escape character)

+    

+    Parameters:

+    * name - the name of the field

+    * start_quote - the opening quote character. default is '"'

+    * end_quote - the closing quote character. default is '"'

+    * esc_char - the escape character, or None to disable escaping. defualt

+      is "\" (backslash)

+    * encoding - the character encoding (e.g., "utf8"), or None to return

+      raw bytes. defualt is None.

+    * allow_eof - whether to allow EOF before the closing quote is matched.

+      if False, an exception will be raised when EOF is reached by the closing

+      quote is missing. default is False.

+    

+    Example:

+    QuotedString("foo", start_quote = "{", end_quote = "}", esc_char = None)

+    """

+    __slots__ = [

+        "start_quote", "end_quote", "char", "esc_char", "encoding", 

+        "allow_eof"

+    ]

+    def __init__(self, name, start_quote = '"', end_quote = None, 

+                 esc_char = '\\', encoding = None, allow_eof = False):

+        Construct.__init__(self, name)

+        if end_quote is None:

+            end_quote = start_quote

+        self.start_quote = Literal(start_quote)

+        self.char = Char("char")

+        self.end_quote = end_quote

+        self.esc_char = esc_char

+        self.encoding = encoding

+        self.allow_eof = allow_eof

+    

+    def _parse(self, stream, context):

+        self.start_quote._parse(stream, context)

+        text = []

+        escaped = False

+        try:

+            while True:

+                ch = self.char._parse(stream, context)

+                if ch == self.esc_char:

+                    if escaped:

+                        text.append(ch)

+                        escaped = False

+                    else:

+                        escaped = True

+                elif ch == self.end_quote and not escaped:

+                    break

+                else:

+                    text.append(ch)

+                    escaped = False

+        except FieldError:

+            if not self.allow_eof:

+                raise

+        text = "".join(text)

+        if self.encoding is not None:

+            text = text.decode(self.encoding)

+        return text

+    

+    def _build(self, obj, stream, context):

+        self.start_quote._build(None, stream, context)

+        if self.encoding:

+            obj = obj.encode(self.encoding)

+        for ch in obj:

+            if ch == self.esc_char:

+                self.char._build(self.esc_char, stream, context)

+            elif ch == self.end_quote:

+                if self.esc_char is None:

+                    raise QuotedStringError("found ending quote in data, "

+                        "but no escape char defined", ch)

+                else:

+                    self.char._build(self.esc_char, stream, context)

+            self.char._build(ch, stream, context)

+        self.char._build(self.end_quote, stream, context)

+    

+    def _sizeof(self, context):

+        raise SizeofError("can't calculate size")

+

+

+#===============================================================================

+# macros

+#===============================================================================

+class WhitespaceAdapter(Adapter):

+    """

+    Adapter for whitespace sequences; do not use directly.

+    See Whitespace.

+    

+    Parameters:

+    * subcon - the subcon to adapt

+    * build_char - the character used for encoding (building)

+    """

+    __slots__ = ["build_char"]

+    def __init__(self, subcon, build_char):

+        Adapter.__init__(self, subcon)

+        self.build_char = build_char

+    def _encode(self, obj, context):

+        return self.build_char

+    def _decode(self, obj, context):

+        return None

+

+def Whitespace(charset = " \t", optional = True):

+    """whitespace (space that is ignored between tokens). when building, the

+    first character of the charset is used.

+    * charset - the set of characters that are considered whitespace. default

+      is space and tab.

+    * optional - whether or not whitespace is optional. default is True.

+    """

+    con = CharOf(None, charset)

+    if optional:

+        con = OptionalGreedyRange(con)

+    else:

+        con = GreedyRange(con)

+    return WhitespaceAdapter(con, build_char = charset[0])

+

+def Literal(text):

+    """matches a literal string in the text

+    * text - the text (string) to match

+    """

+    return ConstAdapter(Field(None, len(text)), text)

+

+def Char(name):

+    """a one-byte character"""

+    return Field(name, 1)

+

+def CharOf(name, charset):

+    """matches only characters of a given charset

+    * name - the name of the field

+    * charset - the set of valid characters

+    """

+    return OneOf(Char(name), charset)

+

+def CharNoneOf(name, charset):

+    """matches only characters that do not belong to a given charset

+    * name - the name of the field

+    * charset - the set of invalid characters

+    """

+    return NoneOf(Char(name), charset)

+

+def Alpha(name):

+    """a letter character (A-Z, a-z)"""

+    return CharOf(name, set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'))

+

+def Digit(name):

+    """a digit character (0-9)"""

+    return CharOf(name, set('0123456789'))

+

+def AlphaDigit(name):

+    """an alphanumeric character (A-Z, a-z, 0-9)"""

+    return CharOf(name, set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"))

+

+def BinDigit(name):

+    """a binary digit (0-1)"""

+    return CharOf(name, set('01'))

+

+def HexDigit(name):

+    """a hexadecimal digit (0-9, A-F, a-f)"""

+    return CharOf(name, set('0123456789abcdefABCDEF'))

+

+def Word(name):

+    """a sequence of letters"""

+    return StringAdapter(GreedyRange(Alpha(name)))

+

+class TextualIntAdapter(Adapter):

+    """

+    Adapter for textual integers

+    

+    Parameters:

+    * subcon - the subcon to adapt

+    * radix - the base of the integer (decimal, hexadecimal, binary, ...)

+    * digits - the sequence of digits of that radix

+    """

+    __slots__ = ["radix", "digits"]

+    def __init__(self, subcon, radix = 10, digits = "0123456789abcdef"):

+        Adapter.__init__(self, subcon)

+        if radix > len(digits):

+            raise ValueError("not enough digits for radix %d" % (radix,))

+        self.radix = radix

+        self.digits = digits

+    def _encode(self, obj, context):

+        chars = []

+        if obj < 0:

+            chars.append("-")

+            n = -obj

+        else:

+            n = obj

+        r = self.radix

+        digs = self.digits

+        while n > 0:

+            n, d = divmod(n, r)

+            chars.append(digs[d])

+        # obj2 = "".join(reversed(chars))

+        # filler = digs[0] * (self._sizeof(context) - len(obj2))

+        # return filler + obj2

+        return "".join(reversed(chars))

+    def _decode(self, obj, context):

+        return int("".join(obj), self.radix)

+

+def DecNumber(name):

+    """decimal number"""

+    return TextualIntAdapter(GreedyRange(Digit(name)))

+

+def BinNumber(name):

+    """binary number"""

+    return TextualIntAdapter(GreedyRange(Digit(name)), 2)

+

+def HexNumber(name):

+    """hexadecimal number"""

+    return TextualIntAdapter(GreedyRange(Digit(name)), 16)

+

+def StringUpto(name, charset):

+    """a string that stretches up to a terminator, or EOF. unlike CString, 

+    StringUpto will no consume the terminator char.

+    * name - the name of the field

+    * charset - the set of terminator characters"""

+    return StringAdapter(OptionalGreedyRange(CharNoneOf(name, charset)))

+

+def Line(name):

+    r"""a textual line (up to "\n")"""

+    return StringUpto(name, "\n")

+

+class IdentifierAdapter(Adapter):

+    """

+    Adapter for programmatic identifiers

+    

+    Parameters:

+    * subcon - the subcon to adapt

+    """

+    def _encode(self, obj, context):

+        return obj[0], obj[1:]

+    def _decode(self, obj, context):

+        return obj[0] + "".join(obj[1])

+

+def Identifier(name, 

+               headset = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"), 

+               tailset = set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")

+    ):

+    """a programmatic identifier (symbol). must start with a char of headset,

+    followed by a sequence of tailset characters

+    * name - the name of the field

+    * headset - charset for the first character. default is A-Z, a-z, and _

+    * tailset - charset for the tail. default is A-Z, a-z, 0-9 and _

+    """

+    return IdentifierAdapter(

+        Sequence(name,

+            CharOf("head", headset),

+            OptionalGreedyRange(CharOf("tail", tailset)),

+        )

+    )

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

diff --git a/elftools/elf/__init__.py b/elftools/elf/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/elftools/elf/__init__.py
diff --git a/elftools/elf/enums.py b/elftools/elf/enums.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/elftools/elf/enums.py
diff --git a/elftools/elf/structs.py b/elftools/elf/structs.py
new file mode 100644
index 0000000..87725a8
--- /dev/null
+++ b/elftools/elf/structs.py
@@ -0,0 +1,37 @@
+from ..construct import (

+    UBInt8, UBInt16, UBInt32, UBInt64,

+    ULInt8, ULInt16, ULInt32, ULInt64,

+    SBInt32, SLInt32, SBInt64, SLInt64,

+    Struct, Array,

+    )

+

+

+class ELFStructs(object):
+    def __init__(self, little_endian=True, elfclass=32):

+        assert elfclass == 32 or elfclass == 64

+        self.little_endian = little_endian

+        self.elfclass = elfclass        

+        self._create_structs()

+    

+    def _create_structs(self):
+        if self.little_endian:

+            self.Elf_byte = ULInt8

+            self.Elf_half = ULInt16

+            self.Elf_word = ULInt32

+            self.Elf_addr = ULInt32 if self.elfclass == 32 else ULInt64

+            self.Elf_offset = self.Elf_addr

+            self.Elf_sword = SLInt32

+            self.Elf_xword = ULInt64

+            self.Elf_sxword = SLInt64

+        else:

+            self.Elf_byte = UBInt8

+            self.Elf_half = UBInt16

+            self.Elf_word = UBInt32

+            self.Elf_addr = UBInt32 if self.elfclass == 32 else UBInt64

+            self.Elf_offset = self.Elf_addr

+            self.Elf_sword = SBInt32

+            self.Elf_xword = UBInt64

+            self.Elf_sxword = SBInt64

+        

+        self.Elf_Ehdr = Struct('Elf_Ehdr',

+            
\ No newline at end of file
diff --git a/z.py b/z.py
new file mode 100644
index 0000000..22d4d03
--- /dev/null
+++ b/z.py
@@ -0,0 +1,2 @@
+from elftools.elf.structs import ELFStructs

+