Skip to content

Commit

Permalink
Const taken over ConstAdapter and Magic.
Browse files Browse the repository at this point in the history
  • Loading branch information
arekbulski committed Aug 30, 2016
1 parent 6bdd8fa commit db6a924
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 65 deletions.
15 changes: 7 additions & 8 deletions construct/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
Container, FieldError, FormatField, LazyBound, LazyContainer, ListContainer, MetaArray, MetaField, OnDemand,
OverwriteError, Packer, Pass, Peek, Pointer, Range, RangeError, Reconfig, RepeatUntil, Restream, Select,
SelectError, Sequence, SizeofError, StaticField, Struct, Subconstruct, Switch, SwitchError, Terminator,
TerminatorError, ULInt24, Union, Computed, Padding, PaddingError)
from construct.adapters import (BitIntegerAdapter, BitIntegerError, CStringAdapter, ConstAdapter, ConstError,
TerminatorError, ULInt24, Union, Computed, Padding, PaddingError, Const, ConstError)
from construct.adapters import (BitIntegerAdapter, BitIntegerError, CStringAdapter,
ExprAdapter, FlagsAdapter, FlagsContainer, HexDumpAdapter, HexString, IndexingAdapter, LengthValueAdapter,
MappingAdapter, MappingError, NoneOf, OneOf, PaddedStringAdapter, SlicingAdapter,
StringAdapter, TunnelAdapter, ValidationError, Validator)
from construct.macros import (Alias, Aligned, AlignedStruct, Array, BFloat32, BFloat64, Bit, BitField,
BitStreamReader, BitStreamWriter, BitStruct, Bitwise, CString, Embedded, EmbeddedBitStruct, Enum, Field,
Flag, FlagsEnum, GreedyRange, If, IfThenElse, LFloat32, LFloat64, Magic, NFloat32, NFloat64, Nibble, Octet,
Flag, FlagsEnum, GreedyRange, If, IfThenElse, LFloat32, LFloat64, NFloat32, NFloat64, Nibble, Octet,
OnDemandPointer, OpenRange, Optional, OptionalGreedyRange, PascalString, PrefixedArray,
Rename, SBInt16, SBInt32, SBInt64, SBInt8, SLInt16, SLInt32, SLInt64, SLInt8, SNInt16, SNInt32, SNInt64,
SNInt8, SeqOfOne, String, SymmetricMapping, UBInt16, UBInt32, UBInt64, UBInt8, ULInt16, ULInt32, ULInt64,
Expand All @@ -50,7 +50,6 @@
Bits = BitField
Byte = UBInt8
Bytes = Field
Const = ConstAdapter
Tunnel = TunnelAdapter
Embed = Embedded

Expand All @@ -60,11 +59,11 @@
__all__ = [
'AdaptationError', 'Adapter', 'Alias', 'Aligned', 'AlignedStruct', 'Anchor', 'Array', 'ArrayError',
'BFloat32', 'BFloat64', 'Bit', 'BitField', 'BitIntegerAdapter', 'BitIntegerError', 'BitStreamReader',
'BitStreamWriter', 'BitStruct', 'Bitwise', 'Buffered', 'CString', 'CStringAdapter', 'ConstAdapter',
'ConstError', 'Construct', 'ConstructError', 'Container', 'Debugger', 'Embedded', 'EmbeddedBitStruct',
'BitStreamWriter', 'BitStruct', 'Bitwise', 'Buffered', 'CString', 'CStringAdapter',
'Construct', 'ConstructError', 'Container', 'Debugger', 'Embedded', 'EmbeddedBitStruct',
'Enum', 'ExprAdapter', 'Field', 'FieldError', 'Flag', 'FlagsAdapter', 'FlagsContainer', 'FlagsEnum',
'FormatField', 'GreedyRange', 'HexDumpAdapter', 'HexString', 'If', 'IfThenElse', 'IndexingAdapter',
'LFloat32', 'LFloat64', 'LazyBound', 'LazyContainer', 'LengthValueAdapter', 'ListContainer', 'Magic',
'LFloat32', 'LFloat64', 'LazyBound', 'LazyContainer', 'LengthValueAdapter', 'ListContainer',
'MappingAdapter', 'MappingError', 'MetaArray', 'MetaField', 'NFloat32', 'NFloat64', 'Nibble', 'NoneOf',
'Octet', 'OnDemand', 'OnDemandPointer', 'OneOf', 'OpenRange', 'Optional', 'OptionalGreedyRange',
'OverwriteError', 'Packer', 'PaddedStringAdapter', 'Padding', 'PaddingError',
Expand All @@ -75,5 +74,5 @@
'Subconstruct', 'Switch', 'SwitchError', 'SymmetricMapping', 'Terminator', 'TerminatorError',
'TunnelAdapter', 'UBInt16', 'UBInt32', 'UBInt64', 'UBInt8', 'ULInt16', 'ULInt24', 'ULInt32', 'ULInt64',
'ULInt8', 'UNInt16', 'UNInt32', 'UNInt64', 'UNInt8', 'Union', 'ValidationError', 'Validator', 'Computed',
'this', 'Bits', 'Byte', 'Bytes', 'Const', 'Tunnel', 'Embed',
'this', 'Bits', 'Byte', 'Bytes', 'Tunnel', 'Embed', 'Const', 'ConstError',
]
28 changes: 0 additions & 28 deletions construct/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ class BitIntegerError(AdaptationError):
pass
class MappingError(AdaptationError):
pass
class ConstError(AdaptationError):
pass
class ValidationError(AdaptationError):
pass

Expand Down Expand Up @@ -306,32 +304,6 @@ def _encode(self, obj, context):
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.
:param subcon: the subcon to validate
:param value: the expected value
Example::
Const(Field("signature", 2), "MZ")
"""
__slots__ = ["value"]
def __init__(self, subcon, value):
super(ConstAdapter, self).__init__(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)
Expand Down
40 changes: 40 additions & 0 deletions construct/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class OverwriteError(ValueError):
pass
class PaddingError(ConstructError):
pass
class ConstError(ConstructError):
pass

#===============================================================================
# abstract constructs
Expand Down Expand Up @@ -1455,3 +1457,41 @@ def _build(self, obj, stream, context):
def _sizeof(self, context):
length = self.length(context) if callable(self.length) else self.length
return length

class Const(Construct):
r"""
Constant field enforcing a constant value. It is used for file signatures,
to validate that the given pattern exists. When parsed, the value must match.
:param data: a bytes object
:param subcon: the subcon to validate
:param value: the expected value
Example::
Const(b"IHDR")
Const("signature", b"IHDR")
Const(ULInt64("signature"), 123)
"""
__slots__ = ["subcon", "value"]
def __init__(self, subcon, value=None):
if value is None:
subcon, value = StaticField(None, len(subcon)), subcon
if isinstance(subcon, str):
subcon, value = StaticField(subcon, len(value)), value
super(Const, self).__init__(subcon.name)
self.subcon = subcon
self.value = value
def _parse(self, stream, context):
obj = self.subcon._parse(stream, context)
if obj != self.value:
raise ConstError("expected %r but parsed %r" % (self.value,obj))
return obj
def _build(self, obj, stream, context):
return self.subcon._build(self.value, stream, context)
def _sizeof(self, context):
return self.subcon._sizeof(context)

4 changes: 2 additions & 2 deletions construct/formats/graphics/png.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def splt_info_data_length(ctx):

image_header_chunk = Struct("image_header",
UBInt32("length"),
Magic(b"IHDR"),
Const(b"IHDR"),
UBInt32("width"),
UBInt32("height"),
UBInt8("bit_depth"),
Expand Down Expand Up @@ -348,7 +348,7 @@ def splt_info_data_length(ctx):
# the complete PNG file
#===============================================================================
png_file = Struct("png",
Magic(b"\x89PNG\r\n\x1a\n"),
Const(b"\x89PNG\r\n\x1a\n"),
image_header_chunk,
Rename("chunks", GreedyRange(chunk)),
)
19 changes: 2 additions & 17 deletions construct/macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from construct.lib.py3compat import int2byte
from construct.lib import BitStreamReader, BitStreamWriter, encode_bin, decode_bin
from construct.core import Struct, MetaField, StaticField, FormatField, OnDemand, Pointer, Switch, Computed, RepeatUntil, MetaArray, Sequence, Range, Select, Pass, SizeofError, Buffered, Restream, Reconfig, Padding
from construct.adapters import BitIntegerAdapter, ConstAdapter, CStringAdapter, LengthValueAdapter, IndexingAdapter, PaddedStringAdapter, FlagsAdapter, StringAdapter, MappingAdapter
from construct.core import Struct, MetaField, StaticField, FormatField, OnDemand, Pointer, Switch, Computed, RepeatUntil, MetaArray, Sequence, Range, Select, Pass, SizeofError, Buffered, Restream, Reconfig, Padding, Const
from construct.adapters import BitIntegerAdapter, CStringAdapter, LengthValueAdapter, IndexingAdapter, PaddedStringAdapter, FlagsAdapter, StringAdapter, MappingAdapter


#===============================================================================
Expand Down Expand Up @@ -664,18 +664,3 @@ def OnDemandPointer(offsetfunc, subcon, force_build=True):
force_build = force_build
)

def Magic(data):
"""A 'magic number' construct. It is used for file signatures, to validate
that the given pattern exists. When parsed. the value must match.
:param data: a bytes object
Example::
elf_header = Struct("elf_header",
Magic("\x7fELF"),
# ...
)
"""
return ConstAdapter(Field(None, len(data)), data)

24 changes: 14 additions & 10 deletions tests/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,19 @@ class ZlibCodec(object):
[TunnelAdapter(PascalString("data", encoding = ZlibCodec), GreedyRange(UBInt16("elements"))).build,
[3] * 100, b"\rx\x9cc`f\x18\x16\x10\x00u\xf8\x01-", None],

[Const(Field("const", 2), b"MZ").parse, b"MZ", b"MZ", None],
[Const(Field("const", 2), b"MZ").parse, b"MS", None, ConstError],
[Const(Field("const", 2), b"MZ").build, b"MZ", b"MZ", None],
[Const(Field("const", 2), b"MZ").build, b"MS", None, ConstError],
[Const(Field("const", 2), b"MZ").build, None, b"MZ", None],

[Const(b"MZ").parse, b"MZ", b"MZ", None],
[Const(b"MZ").parse, b"ELF", None, ConstError],
[Const(b"MZ").build, None, b"MZ", None],
[Const(b"MZ").build, b"MZ", b"MZ", None],
[Const("const", b"MZ").parse, b"MZ", b"MZ", None],
[Const("const", b"MZ").parse, b"ELF", None, ConstError],
[Const("const", b"MZ").build, None, b"MZ", None],
[Const("const", b"MZ").build, b"MZ", b"MZ", None],
[Const(ULInt32("const"), 255).parse, b"\xff\x00\x00\x00", 255, None],
[Const(ULInt32("const"), 255).parse, b"\x00\x00\x00\x00", 255, ConstError],
[Const(ULInt32("const"), 255).build, None, b"\xff\x00\x00\x00", None],
[Const(ULInt32("const"), 255).build, 255, b"\xff\x00\x00\x00", None],

[ExprAdapter(UBInt8("expradapter"),
encoder = lambda obj, ctx: obj // 7,
decoder = lambda obj, ctx: obj * 7).parse,
Expand Down Expand Up @@ -266,10 +273,6 @@ class ZlibCodec(object):
[IfThenElse("ifthenelse", lambda ctx: False, UBInt8("then"), UBInt16("else")).parse, b"\x00\x01", 1, None],
[IfThenElse("ifthenelse", lambda ctx: True, UBInt8("then"), UBInt16("else")).build, 1, b"\x01", None],
[IfThenElse("ifthenelse", lambda ctx: False, UBInt8("then"), UBInt16("else")).build, 1, b"\x00\x01", None],

[Magic(b"MZ").parse, b"MZ", b"MZ", None],
[Magic(b"MZ").parse, b"ELF", None, ConstError],
[Magic(b"MZ").build, None, b"MZ", None],
]


Expand All @@ -291,6 +294,7 @@ def _run_tests(self, tests):
continue
else:
if exctype is not None:
print("Testing: %r", (i, func, args, res, exctype))
errors.append("%s: expected exception %r" % (func, exctype))
continue
if r != res:
Expand Down

0 comments on commit db6a924

Please sign in to comment.