From 32625610783a417dcdc70a36a508fb68a65a5346 Mon Sep 17 00:00:00 2001 From: Friedrich Delgado Date: Mon, 18 Oct 2010 14:47:36 +0200 Subject: [PATCH 1/2] add bencode script via entry point --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index ea432d1..cc6245a 100755 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ entry_points={'console_scripts': [ 'bcompile = bdec.tools.compile:main', 'bdecode = bdec.tools.decode:main', + 'bencode = bdec.tools.encode:main', ]}, install_requires=['pyparsing', 'nose', 'mako'], zip_safe=True, From c71d35359de818817dc87457614a067875137bd4 Mon Sep 17 00:00:00 2001 From: Friedrich Delgado Date: Mon, 7 Feb 2011 17:15:23 +0100 Subject: [PATCH 2/2] add a visible attributes field to each entry, so it's visible from inside the templates (Original changes by Christopher Schwardt, but I had to squash everything into one commit, because our repository was a bit broken) --- bdec/choice.py | 4 ++-- bdec/data.py | 2 +- bdec/entry.py | 3 ++- bdec/field.py | 4 ++-- bdec/sequence.py | 4 ++-- bdec/sequenceof.py | 4 ++-- bdec/spec/integer.py | 26 +++++++++++++------------- bdec/spec/xmlspec.py | 14 +++++++------- 8 files changed, 31 insertions(+), 30 deletions(-) diff --git a/bdec/choice.py b/bdec/choice.py index 29b26e5..ef39a76 100644 --- a/bdec/choice.py +++ b/bdec/choice.py @@ -28,8 +28,8 @@ class Choice(bdec.entry.Entry): The first entry to decode correctly will be used. """ - def __init__(self, name, children, length=None): - bdec.entry.Entry.__init__(self, name, length, children) + def __init__(self, name, children, length=None, attributes=None): + bdec.entry.Entry.__init__(self, name, length, children, attributes=attributes) assert len(children) > 0 diff --git a/bdec/data.py b/bdec/data.py index 5218e5c..7fbfb94 100644 --- a/bdec/data.py +++ b/bdec/data.py @@ -111,7 +111,7 @@ def __init__(self, data, encoding): self.encoding = encoding def __str__(self): - return "'%s' can't convert %s" % (self.encoding, self.data) + return "'%s' can't convert '%s'" % (self.encoding, self.data) class _OutOfDataError(Exception): """Not derived from DataError as this is an internal error.""" diff --git a/bdec/entry.py b/bdec/entry.py index 28485b8..7e08b71 100644 --- a/bdec/entry.py +++ b/bdec/entry.py @@ -97,7 +97,7 @@ class Entry(object): directly). """ - def __init__(self, name, length, children, constraints=[]): + def __init__(self, name, length, children, constraints=[], attributes=None): """Construct an Entry instance. children -- A list of Entry or Child instances. @@ -119,6 +119,7 @@ def __init__(self, name, length, children, constraints=[]): self.constraints = list(constraints) for constraint in self.constraints: assert getattr(constraint, 'check') is not None + self.attributes = attributes if attributes!=None else {} def _get_children(self): return self._children diff --git a/bdec/field.py b/bdec/field.py index 5ee7417..e15f3d7 100644 --- a/bdec/field.py +++ b/bdec/field.py @@ -106,8 +106,8 @@ class Field(bdec.entry.Entry): LITTLE_ENDIAN = "little endian" BIG_ENDIAN = "big endian" - def __init__(self, name, length, format=BINARY, encoding=None, constraints=[]): - bdec.entry.Entry.__init__(self, name, length, [], constraints) + def __init__(self, name, length, format=BINARY, encoding=None, constraints=[], attributes=None): + bdec.entry.Entry.__init__(self, name, length, [], constraints, attributes=attributes) assert format in self._formats if encoding is None: diff --git a/bdec/sequence.py b/bdec/sequence.py index 010ecf2..7631d15 100644 --- a/bdec/sequence.py +++ b/bdec/sequence.py @@ -34,8 +34,8 @@ class Sequence(bdec.entry.Entry): lookup tables, and alternate integer encoding methods. """ - def __init__(self, name, children, value=None, length=None, constraints=[]): - bdec.entry.Entry.__init__(self, name, length, children, constraints) + def __init__(self, name, children, value=None, length=None, constraints=[], attributes=None): + bdec.entry.Entry.__init__(self, name, length, children, constraints, attributes=attributes) self.value = value def _range(self, ignore_entries): diff --git a/bdec/sequenceof.py b/bdec/sequenceof.py index 585ac9b..64cd5d4 100644 --- a/bdec/sequenceof.py +++ b/bdec/sequenceof.py @@ -55,7 +55,7 @@ class SequenceOf(bdec.entry.Entry): ITERATING = "iterating" STOPPING = "stopping" - def __init__(self, name, child, count, length=None, end_entries=[]): + def __init__(self, name, child, count, length=None, end_entries=[], attributes=None): """ count -- The number of times the child will repeat. If this value is None, the count will not be used. @@ -67,7 +67,7 @@ def __init__(self, name, child, count, length=None, end_entries=[]): If neither count, length, or end_entries are used, the SequenceOf will fail to decode after using all of the available buffer. """ - bdec.entry.Entry.__init__(self, name, length, [child]) + bdec.entry.Entry.__init__(self, name, length, [child], attributes=attributes) if isinstance(count, int): count = Constant(count) assert count is None or isinstance(count, Expression) diff --git a/bdec/spec/integer.py b/bdec/spec/integer.py index 183fa20..2c96d1e 100644 --- a/bdec/spec/integer.py +++ b/bdec/spec/integer.py @@ -40,7 +40,7 @@ class Integers: def __init__(self): self.common = {} - def signed_big_endian(self, length_expr): + def signed_big_endian(self, length_expr, attributes=None): try: # We try to choose the name based on the length value. If we # cannot evaluate the length, we'll use the length name. @@ -51,14 +51,14 @@ def signed_big_endian(self, length_expr): try: result = self.common[name] except KeyError: - is_signed = Field('signed:', 1) - value = Field('integer value:', ArithmeticExpression(operator.sub, length_expr, Constant(1))) + is_signed = Field('signed:', 1, attributes=attributes) + value = Field('integer value:', ArithmeticExpression(operator.sub, length_expr, Constant(1)), attributes=attributes) expression = compile('${signed:} * ((0 - 1) << (%s - 1)) + ${integer value:}' % (length_expr)) - result = Sequence(name, [is_signed, value], value=expression) + result = Sequence(name, [is_signed, value], value=expression, attributes=attributes) self.common[name] = result return result - def _variable_length_signed_little_endian(self, length_expr): + def _variable_length_signed_little_endian(self, length_expr, attributes=None): name = 'variable length integer' try: result = self.common[name] @@ -72,16 +72,16 @@ def _variable_length_signed_little_endian(self, length_expr): # We wrap the choice inside a sequence, as choices don't currently # 'compile' to integers (and sequences do). var_name = 'variable integer types:' - result = Sequence(name, [Choice(var_name, options)], - value=compile('${%s.value}' % var_name)) + result = Sequence(name, [Choice(var_name, options, attributes=attributes)], + value=compile('${%s}' % var_name), attributes=attributes) self.common[name] = result return result - def signed_litte_endian(self, length_expr): + def signed_litte_endian(self, length_expr, attributes=None): try: length = length_expr.evaluate({}) except UndecodedReferenceError: - return self._variable_length_signed_little_endian(length_expr) + return self._variable_length_signed_little_endian(length_expr, attributes=attributes) if length % 8 != 0: raise IntegerError('The length of little endian fields must be a multiple of 8.') @@ -93,9 +93,9 @@ def signed_litte_endian(self, length_expr): children = [] num_bytes = length / 8 for i in range(num_bytes - 1): - children.append(Field('byte %i:' % i, 8)) - children.append(Field('signed:', 1)) - children.append(Field('byte %i:' % (num_bytes - 1), 7)) + children.append(Field('byte %i:' % i, 8, attributes=attributes)) + children.append(Field('signed:', 1, attributes=attributes)) + children.append(Field('byte %i:' % (num_bytes - 1), 7, attributes=attributes)) # We define the minimum as being '-number - 1' to avoid compiler # warnings in C, where there are no negative constants, just # constants that are then negated (and the positive version of @@ -105,7 +105,7 @@ def signed_litte_endian(self, length_expr): names.reverse() reference = reduce(lambda left, right: '(%s) * 256 + %s' % (left, right), names) value_text = '${signed:} * (0 - %i - 1) + %s' % (maximum - 1, reference) - result = Sequence(name, children, value=compile(value_text)) + result = Sequence(name, children, value=compile(value_text), attributes=attributes) self.common[name] = result return result diff --git a/bdec/spec/xmlspec.py b/bdec/spec/xmlspec.py index 321ab51..b1c7831 100644 --- a/bdec/spec/xmlspec.py +++ b/bdec/spec/xmlspec.py @@ -195,7 +195,7 @@ def endElement(self, name): self.lookup[entry] = (self._filename, lineno, colno) name = 'optional %s' % entry_name if entry_name else 'optional:' - optional = chc.Choice(name, [not_present, entry]) + optional = chc.Choice(name, [not_present, entry], attributes=attrs) entry = optional if entry is not None: @@ -278,16 +278,16 @@ def _field(self, attributes, children, name, length, breaks): # have to know about these types. try: if encoding in [None, fld.Field.BIG_ENDIAN]: - integer = self._integers.signed_big_endian(length) + integer = self._integers.signed_big_endian(length, attributes=attributes) else: assert encoding == fld.Field.LITTLE_ENDIAN - integer = self._integers.signed_litte_endian(length) + integer = self._integers.signed_litte_endian(length, attributes=attributes) except IntegerError, error: raise self._error(str(error)) return self._references.get_common(name, integer.name) # We'll create the field, then use it to create the expected value. - result = fld.Field(name, length, format, encoding) + result = fld.Field(name, length, format, encoding, attributes=attributes) if attributes.has_key('value'): # Get the correct object type by encoding, then decoding, the text # value. @@ -325,12 +325,12 @@ def _sequence(self, attributes, children, name, length, breaks): if attributes.has_key('value'): # A sequence can have a value derived from its children... value = self._parse_expression(attributes['value']) - return seq.Sequence(name, children, value, length) + return seq.Sequence(name, children, value, length, attributes=attributes) def _choice(self, attributes, children, name, length, breaks): if len(children) == 0: raise self._error("Choice '%s' must have children! Should this be a 'reference' entry?" % attributes['name']) - return chc.Choice(name, children, length) + return chc.Choice(name, children, length, attributes=attributes) def _sequenceof(self, attributes, children, name, length, breaks): if len(children) == 0: @@ -342,7 +342,7 @@ def _sequenceof(self, attributes, children, name, length, breaks): count = None if attributes.has_key('count'): count = self._parse_expression(attributes['count']) - result = sof.SequenceOf(name, children[0], count, length, breaks) + result = sof.SequenceOf(name, children[0], count, length, breaks, attributes=attributes) return result