Example #1
0
    def test_same_param_from_parent_and_siblings(self):
        # Test that we ask the parent for a parameter even when there is a
        # child with the same name (but _after_ the entry that needs it).
        a = Sequence('a', [
            Sequence('expected', [], value=Constant(2)),
            Sequence('b', [
                # This should come from the parent (ie: a.expected)
                Field('c', length=8, constraints=[Equals(ValueResult('expected'))]),
                Sequence('expected', [], value=Constant(1)),
                # This should come from the sibling (ie: b.expected)
                Field('d', length=8, constraints=[Equals(ValueResult('expected'))]),
                ])
            ])
        b = a.children[1].entry
        lookup = ExpressionParameters([a])
        self.assertEqual([Param('expected', Param.IN, _Integer())],
            list(lookup.get_passed_variables(a, a.children[1])))
        self.assertEqual([Param('expected', Param.OUT, _Integer())],
            list(lookup.get_passed_variables(b, b.children[1])))
        self.assertEqual([Param('expected', Param.IN, _Integer())],
            list(lookup.get_passed_variables(b, b.children[2])))

        self.assertRaises(bdec.DecodeError, list, a.decode(Data('\x01\x01')))
        self.assertRaises(bdec.DecodeError, list, a.decode(Data('\x02\x00')))
        list(a.decode(Data('\x02\x01')))
Example #2
0
    def test_in_and_out_parameters(self):
        # Test what happens when we have a parameter that is to be passed out
        # of an entry, but also into a child (issue122).
        #
        #        ___ e ___
        #   __c__         d(len=a)
        #  a   b(len=a)
        a = Field('a', length=8)
        b = Field('b', length=parse('${a}'))
        c = Sequence('c', [a, b])
        d = Field('d', length=parse('${c.a}'))
        e = Sequence('e', [c, d])

        lookup = ExpressionParameters([e])
        self.assertEqual([], lookup.get_params(e))
        self.assertEqual([Param('a', Param.OUT, _Integer())], lookup.get_params(a))
        self.assertEqual([Param('a', Param.OUT, _Integer())], lookup.get_params(c))
        self.assertEqual([Param('a', Param.IN, _Integer())], lookup.get_params(b))
        self.assertEqual([Param('c.a', Param.IN, _Integer())], lookup.get_params(d))
        self.assertEqual([Local('c.a', _Integer())], lookup.get_locals(e))
        self.assertEqual([], lookup.get_locals(c))

        self.assertTrue(lookup.is_value_referenced(a))

        self.assertEqual([Param('a', Param.IN, _Integer())],
                list(lookup.get_passed_variables(c, c.children[1])))
        self.assertEqual([Param('c.a', Param.IN, _Integer())],
                list(lookup.get_passed_variables(e, e.children[1])))
Example #3
0
    def test_sub_children(self):
        a2 = Field('a2', 8)
        a1 = Sequence('a1', [a2])
        a = Sequence('a', [a1])
        value = ValueResult('a.a1.a2')
        b1 = Field('b1', value)
        b = Sequence('b', [b1])
        spec = Sequence('blah', [a,b])

        vars = ExpressionParameters([spec])
        self.assertEqual([Local('a.a1.a2', _Integer())], vars.get_locals(spec))
        # Note that despite containing a referenced entry, it isn't a local (as
        # it is passed up to the parent entry).
        self.assertEqual([], vars.get_locals(a))

        # Now check what parameters are passed in and out. Note that we check
        # that the name is correct for the context of the parameter.
        self.assertEqual([], vars.get_params(spec))
        self.assertEqual([Param('a2', Param.OUT, _Integer())], vars.get_params(a2))
        self.assertEqual([Param('a2', Param.OUT, _Integer())], vars.get_params(a1))
        self.assertEqual([Param('a1.a2', Param.OUT, _Integer())], vars.get_params(a))
        self.assertEqual([Param('a1.a2', Param.OUT, _Integer())], list(vars.get_passed_variables(a, a.children[0])))
        self.assertEqual([Param('a.a1.a2', Param.IN, _Integer())], vars.get_params(b))
        self.assertEqual([Param('a.a1.a2', Param.IN, _Integer())], vars.get_params(b1))
        self.assertEqual([Param('a.a1.a2', Param.IN, _Integer())], list(vars.get_passed_variables(b, b.children[0])))
Example #4
0
    def test_sequence_value(self):
        # Define an integer with a custom byte ordering
        lower = Field('lower byte', 8)
        lower_value = ValueResult('lower byte')
        ignored = Field('ignored', 8)
        upper = Field('upper byte', 8)
        upper_value = ValueResult('upper byte')
        value = ArithmeticExpression(operator.__add__, ArithmeticExpression(operator.__mul__, upper_value, Constant(256)), lower_value)
        length = Sequence('length', [lower, ignored, upper], value)
        header = Sequence('header', [length])

        int_value = ValueResult('length')
        data = Field('data', int_value)
        spec = Sequence('blah', [length, data])

        vars = ExpressionParameters([spec])
        self.assertEquals([], vars.get_params(spec))
        self.assertTrue(vars.is_value_referenced(lower))
        self.assertFalse(vars.is_value_referenced(ignored))
        self.assertTrue(vars.is_value_referenced(upper))
        self.assertEqual([Local('lower byte', _Integer()), Local('upper byte', _Integer())], vars.get_locals(length))
        self.assertEqual([Param('lower byte', Param.OUT, _Integer())], vars.get_params(lower))
        self.assertEqual([Param('upper byte', Param.OUT, _Integer())], vars.get_params(upper))
        self.assertEqual([Param('length', Param.OUT, _Integer())], vars.get_params(length))

        self.assertEqual([Local('length', _Integer())], vars.get_locals(spec))
        self.assertEqual([Param('length', Param.IN, _Integer())], vars.get_params(data))
Example #5
0
 def test_sequence_with_referenced_value(self):
     a = Field('a', length=8)
     b = Sequence('b', [Child('b:', a)], value=parse('${b:}'))
     c = Field('c', length=parse('${b} * 8'))
     d = Sequence('d', [a, b, c])
     lookup = ExpressionParameters([a, d])
     self.assertEqual([Local('b:', _Integer())], lookup.get_locals(b))
     self.assertEqual([Param('a', Param.OUT, _Integer())], lookup.get_params(a))
     self.assertEqual([Param('b', Param.OUT, _Integer())], lookup.get_params(b))
     self.assertEqual([Param('b', Param.IN, _Integer())], lookup.get_params(c))
     self.assertEqual([], lookup.get_params(d))
Example #6
0
    def test_direct_children(self):
        a = Field('a', 8)
        value = ValueResult('a')
        b = Field('b', value)
        spec = Sequence('blah', [a,b])

        vars = ExpressionParameters([spec])
        self.assertEqual([Local('a', _Integer())], vars.get_locals(spec))
        self.assertTrue(vars.is_value_referenced(a))
        self.assertFalse(vars.is_value_referenced(b))
        self.assertEqual([], vars.get_locals(a))
Example #7
0
    def test_common_entry_with_input_parameter(self):
        # Test that we correctly resolve a common entry that has an input
        # parameter that resolves to mulitiple (different) entries.
        a = Field('a', length=parse('${b}'))

        # Here the common entry 'a' is used into two locations, each time it
        # resolves to an entry with a different length.
        c = Sequence('c', [Field('b', 8), a])
        d = Sequence('d', [Field('b', 16), a])
        lookup = ExpressionParameters([a, c, d])

        self.assertEqual([Param('b', Param.OUT, _Integer())], list(lookup.get_passed_variables(c, c.children[0])))
        self.assertEqual([Param('b', Param.OUT, _Integer())], list(lookup.get_passed_variables(d, d.children[0])))
Example #8
0
    def test_renamed_common_reference(self):
        text_digit = Field('text digit', 8, constraints=[Minimum(48), Maximum(58)])

        digit = Sequence('digit', [text_digit],
            value=parse("${text digit} - 48"))
        b = Sequence('b', [
            Child('length', digit),
            Field('data', length=parse("${length} * 8"))])
        lookup = ExpressionParameters([b])
        self.assertEqual([], lookup.get_params(b))
        self.assertEqual([Param('digit', Param.OUT, _Integer())],
                lookup.get_params(digit))
        self.assertEqual([Param('length', Param.OUT, _Integer())],
                list(lookup.get_passed_variables(b, b.children[0])))
Example #9
0
    def test_length_and_value_reference(self):
        # Test a length reference and a value reference to the same entry.
        a = Field('a', length=8)
        c = Field('c', length=parse('len{a}'))
        d = Field('d', length=parse('${a}'))
        b = Sequence('b', [a, c, d])

        # Lets just try a quick decode to make sure we've specified it ok...
        #list(b.decode(Data('\x08cd')))

        # Now test the parameters being passed around.
        lookup = ExpressionParameters([b])
        self.assertEqual([Param('a', Param.OUT, _Integer()),
            Param('a length', Param.OUT, _Integer())],
                lookup.get_params(a))
        self.assertEqual([Param('a', Param.OUT, _Integer()),
            Param('a length', Param.OUT, _Integer())],
                list(lookup.get_passed_variables(b, b.children[0])))
        self.assertEqual([Param('a length', Param.IN, _Integer())],
                list(lookup.get_passed_variables(b, b.children[1])))
        self.assertEqual([Param('a length', Param.IN, _Integer())],
                lookup.get_params(c))
        self.assertEqual([Local('a', _Integer()), Local('a length', _Integer())],
                lookup.get_locals(b))
        self.assertTrue(lookup.is_length_referenced(a))
Example #10
0
    def test_unused_parameters_with_same_name(self):
        # Test that when we have multiple 'unused' parameters with the same
        # name we don't duplicate the same local variable. This happened with
        # the vfat specification (the different bootsector types all had the
        # same output parameters).
        a1 = Field('a', length=16)
        a2 = Field('a', length=8)
        # C doesn't use the outputs from a1 and a2, so should have a single
        # local variable.
        c = Sequence('c', [a1, a2])
        # Now create a couple of other entries that actually use a1 & a2
        d1 = Sequence('d1', [a1, Field('e1', length=parse('${a}'))])
        d2 = Sequence('d2', [a2, Field('e2', length=parse('${a}'))])

        lookup = ExpressionParameters([a1, a2, c, d1, d2])
        self.assertEqual([Param('unused a', Param.OUT, _Integer())], list(lookup.get_passed_variables(c, c.children[0])))
        self.assertEqual([Param('unused a', Param.OUT, _Integer())], list(lookup.get_passed_variables(c, c.children[1])))
        self.assertEqual([Local('unused a', _Integer())], lookup.get_locals(c))
Example #11
0
 def test_name_ends_in_length(self):
     a = Field('data length', 8, Field.INTEGER)
     b = Field('data', parse('${data length} * 8'))
     c = Sequence('c', [a, b])
     params = ExpressionParameters([c])
     self.assertEqual([Local('data length', _Integer())], params.get_locals(c))
     self.assertEqual([], params.get_params(c))
     self.assertEqual([Param('data length', Param.OUT, _Integer())], params.get_params(a))
     self.assertEqual([Param('data length', Param.IN, _Integer())], params.get_params(b))
     self.assertEqual(True, params.is_value_referenced(a))
     self.assertEqual(False, params.is_length_referenced(a))
Example #12
0
    def test_param_ordering(self):
        # Test that we order the parameters consistently
        a = Field('a', 8)
        b = Field('b', 8)
        c = Field('c', 8)
        d = Sequence('d', [a,b,c])

        e = Field('e', parse('${d.a} + ${d.b} + ${d.c}'))
        f = Sequence('f', [d, e])

        params = ExpressionParameters([f])
        self.assertEqual([Local('d.a', _Integer()),
            Local('d.b', _Integer()),
            Local('d.c', _Integer())], params.get_locals(f))
        self.assertEqual([Param('a', Param.OUT, _Integer()), 
            Param('b', Param.OUT, _Integer()),
            Param('c', Param.OUT, _Integer())],
            params.get_params(d))
        self.assertEqual([Param('d.a', Param.OUT, _Integer()),
            Param('d.b', Param.OUT, _Integer()),
            Param('d.c', Param.OUT, _Integer())],
            list(params.get_passed_variables(f, f.children[0])))
Example #13
0
 def test_param_length_postfix(self):
     # Test that a 'length:' postfix doesn't confuse the parameter
     # detection. There was a bug where the types would get confused if
     # both the length and value of an entry ending in ' length:' were
     # referenced.
     a = Sequence('a', [
         Field('b length:', 8),
         Field('b', length=parse('${b length:}'), format=Field.TEXT),
         Sequence('c', [], value=parse('len{b length:} + len{b}')),
         ])
     lookup = ExpressionParameters([a])
     self.assertEqual([
         Param('b length:', Param.OUT, EntryValueType(a.children[0].entry)),
         Param('b length: length', Param.OUT, EntryLengthType(a.children[0].entry))],
         list(lookup.get_passed_variables(a, a.children[0])))
     self.assertEqual([
         Param('b length', Param.OUT, EntryLengthType(a.children[1].entry)),
         Param('b length:', Param.IN, EntryValueType(a.children[0].entry))],
         list(lookup.get_passed_variables(a, a.children[1])))
     self.assertEqual([
         Param('b length', Param.IN, EntryLengthType(a.children[1].entry)),
         Param('b length: length', Param.IN, EntryLengthType(a.children[0].entry))],
         list(lookup.get_passed_variables(a, a.children[2])))
Example #14
0
    def test_recursive_entry_with_input_param(self):
        # There was a bug with passing input parameters to recursive entries,
        # where the embedded (recursed) entry wouldn't have the parameter
        # correctly passed. This technique is used in the asn.1 decoder.
        a = Choice('a', [
            Field('not recursive', length=8, constraints=[Equals(ValueResult('zero'))]),
            Sequence('recursive', [
                Field('unused', length=8)
                ])
            ])
        a.children[1].entry.children.append(Child('a', a))
        b = Sequence('b', [
            Sequence('zero', [], value=Constant(0)),
            a
            ])

        lookup = ExpressionParameters([a, b])
        self.assertEqual([
            Param('zero', Param.IN, _Integer())],
            list(lookup.get_passed_variables(a, a.children[1])))
        self.assertEqual([
            Param('zero', Param.IN, _Integer())],
            list(lookup.get_passed_variables(a.children[1].entry, a.children[1].entry.children[1])))
Example #15
0
    def test_two_recursive_entries_with_input_parameters(self):
        # The previous fix for recursive parameters didn't handle two
        # structures that were recursive using the same intermediate instance.
        #
        # In this case, 'a' is recursive through both 'recursive x' and
        # 'recursive y', and the bug was that any input parameters to
        # 'recursive y' weren't being correctly detected.
        a = Choice('a', [
            Field('not recursive', length=8, constraints=[Equals(ValueResult('zero'))]),
            Sequence('recursive x', [
                Field('unused', length=8, constraints=[Maximum(10)])
                ]),
            Sequence('recursive y', [
                Field('unused', length=8)
                ]),
            ])
        a.children[1].entry.children.append(Child('a1', a))
        a.children[2].entry.children.append(Child('a2', a))
        b = Sequence('b', [
            Sequence('zero', [], value=Constant(0)),
            a
            ])

        lookup = ExpressionParameters([a, b])
        self.assertEqual([
            Param('zero', Param.IN, _Integer())],
            list(lookup.get_passed_variables(a, a.children[1])))
        self.assertEqual([
            Param('zero', Param.IN, _Integer())],
            list(lookup.get_passed_variables(a.children[1].entry, a.children[1].entry.children[1])))
        self.assertEqual([
            Param('zero', Param.IN, _Integer())],
            list(lookup.get_passed_variables(a, a.children[2])))
        self.assertEqual([
            Param('zero', Param.IN, _Integer())],
            list(lookup.get_passed_variables(a.children[2].entry, a.children[2].entry.children[1])))
Example #16
0
    def test_length_reference(self):
        a1 = Field('a1', 8)
        a = Sequence('a', [a1])
        b1 = Field('b1', LengthResult('a'))
        b = Sequence('b', [b1])
        spec = Sequence('blah', [a,b])

        vars = ExpressionParameters([spec])
        self.assertEqual([Local('a length', _Integer())], vars.get_locals(spec))
        self.assertFalse(vars.is_length_referenced(a1))
        self.assertTrue(vars.is_length_referenced(a))
        self.assertEqual([Param('a length', Param.OUT, EntryLengthType(a))], vars.get_params(a))
        self.assertEqual([Param('a length', Param.IN, EntryLengthType(a))], vars.get_params(b))
Example #17
0
    def test_choice_reference(self):
        """
        Test the parameter names when we have items selected under a choice.
        """
        byte = Sequence('8 bit:', [Field('id', 8, constraints=[Equals(Data('\x00'))]), Field('length', 8)])
        word = Sequence('16 bit:', [Field('id', 8, constraints=[Equals(Data('\x01'))]), Field('length', 16)])
        length = Choice('variable integer', [byte, word])
        length_value = ValueResult('variable integer.length')
        data = Field('data', length_value)
        spec = Sequence('spec', [length, data])
        vars = ExpressionParameters([spec])

        self.assertFalse(vars.is_value_referenced(byte))
        self.assertTrue(vars.is_value_referenced(byte.children[1].entry))
        self.assertFalse(vars.is_value_referenced(word))
        self.assertTrue(vars.is_value_referenced(word.children[1].entry))
        self.assertEqual([Param('length', Param.OUT, _Integer())], vars.get_params(byte))
        self.assertEqual([Param('length', Param.OUT, _Integer())], vars.get_params(word))
        self.assertEqual([Param('length', Param.OUT, _Integer())], vars.get_params(length))
        self.assertEqual([], vars.get_locals(length))
        self.assertEqual([Param('length', Param.OUT, _Integer())], list(vars.get_passed_variables(length, length.children[0])))

        self.assertEqual([Local('variable integer.length', _Integer())], vars.get_locals(spec))
        self.assertEqual([Param('variable integer.length', Param.IN, _Integer())], vars.get_params(data))
Example #18
0
    def test_reference_outside_of_choice(self):
        """
        Test passing in a parameter into choice options.
        """
        # Note that the 'integer' option has a fixed length...
        length = Field('length:', 8)
        length_value = ValueResult('length:')
        text = Sequence('text', [
            Field('id:',  8, constraints=[Equals(Data('\x00'))]),
            Field('value', length_value, Field.TEXT)])
        integer = Sequence('integer', [
            Field('id:',  8, constraints=[Equals(Data('\x01'))]),
            Field('value', 16, Field.INTEGER)])
        spec = Sequence('spec', [length, Choice('data', [text, integer])])

        vars = ExpressionParameters([spec])
        self.assertTrue(vars.is_value_referenced(length))
        self.assertEqual([], vars.get_params(spec))
        self.assertEqual([Local('length:', _Integer())], vars.get_locals(spec))
        self.assertEqual([Param('length:', Param.OUT, _Integer())], vars.get_params(length))
        self.assertEqual([Param('length:', Param.OUT, _Integer())], list(vars.get_passed_variables(spec, spec.children[0])))

        self.assertEqual([Param('length:', Param.IN, _Integer())], vars.get_params(spec.children[1].entry))
        self.assertEqual([Param('length:', Param.IN, _Integer())], list(vars.get_passed_variables(spec, spec.children[1])))
        self.assertEqual([Param('length:', Param.IN, _Integer())], vars.get_params(text))
        self.assertEqual([Param('length:', Param.IN, _Integer())], list(vars.get_passed_variables(spec.children[1].entry, spec.children[1].entry.children[0])))
        self.assertEqual([Param('length:', Param.IN, _Integer())], vars.get_params(text.children[1].entry))
        self.assertEqual([], vars.get_params(integer))
        self.assertEqual([], list(vars.get_passed_variables(spec.children[1].entry, spec.children[1].entry.children[1])))
Example #19
0
    def test_unused_parameters(self):
        # Test detection of re-use of a common entry, where not all output parameters are used.
        length = Field('length', 8)
        shared = Sequence('shared', [length])
        length_value = ValueResult('shared.length')

        # Now we'll reference that common component twice, but only once
        # referencing an actual value. In 'b' we use it twice, to detect that
        # it only turns up in the locals list once.
        a = Sequence('a', [shared, Field('a data', length_value)])
        b = Sequence('b', [shared, shared])
        spec = Sequence('spec', [a,b])
        vars = ExpressionParameters([spec])
        self.assertEqual([], list(vars.get_params(spec)))
        self.assertTrue(vars.is_value_referenced(length))
        self.assertFalse(vars.is_value_referenced(shared))
        self.assertEqual([], vars.get_locals(spec))

        # Test that the 'length' and 'shared' entries pass out their value
        self.assertEqual([Param('length', Param.OUT, _Integer())], list(vars.get_params(length)))
        self.assertEqual([Param('length', Param.OUT, _Integer())], vars.get_params(shared))

        # First validate the passing of the length value within entry 'a'
        self.assertEqual([], vars.get_params(a))
        self.assertEqual([Local('shared.length', _Integer())], vars.get_locals(a))
        self.assertEqual([Param('shared.length', Param.OUT, _Integer())], list(vars.get_passed_variables(a, a.children[0])))
        self.assertEqual([Param('shared.length', Param.IN, _Integer())], list(vars.get_passed_variables(a, a.children[1])))
        self.assertEqual([], list(vars.get_passed_variables(spec, spec.children[0])))

        # Now test the passing out (and ignoring) of the length value within 'b'
        self.assertEqual([], vars.get_params(b))
        self.assertEqual([Local('unused length', _Integer())], vars.get_locals(b))
        self.assertEqual([Param('unused length', Param.OUT, _Integer())], list(vars.get_passed_variables(b, b.children[0])))
        self.assertEqual([], list(vars.get_passed_variables(spec, spec.children[0])))
Example #20
0
    def test_choice_reference(self):
        # Test that we can correctly reference a choice (which in effect
        # references each of its children).
        #
        # We test this by creating a choice where each child has a value type,
        # and attempt to reference the top level choice.
        len = Field('len', length=8)
        a = Field('a', length=32)
        b = Field('b', length=16)
        c = Field('c', length=8)
        var_len = Choice('var_len', [a, b, c], length=parse('${len}'))
        data = Field('data', length=parse('${var_len}'))
        spec = Sequence('spec', [len, var_len, data])

        # Check the parameters passed in and out of each entry
        lookup = ExpressionParameters([spec])
        self.assertEqual([], lookup.get_params(spec))
        self.assertEqual([Param('len', Param.OUT, _Integer())],
                lookup.get_params(len))
        self.assertEqual([Param('len', Param.IN, _Integer()),
                    Param('var_len', Param.OUT, _Integer())],
                lookup.get_params(var_len))
        self.assertEqual([Param('a', Param.OUT, _Integer())],
                lookup.get_params(a))
        self.assertEqual([Param('b', Param.OUT, _Integer())],
                lookup.get_params(b))
        self.assertEqual([Param('var_len', Param.IN, _Integer())],
                lookup.get_params(data))

        # Test the mapping of the parameters for the choice to the option
        # entries.
        self.assertEqual([Param('var_len', Param.OUT, _Integer())],
                list(lookup.get_passed_variables(var_len, var_len.children[0])))
        self.assertEqual([Param('var_len', Param.OUT, _Integer())],
                list(lookup.get_passed_variables(var_len, var_len.children[1])))
        self.assertEqual([Param('var_len', Param.OUT, _Integer())],
                list(lookup.get_passed_variables(var_len, var_len.children[2])))

        # And validate the locals...
        self.assertEqual([Local('len', _Integer()), Local('var_len', _Integer())], lookup.get_locals(spec))
        self.assertEqual([], lookup.get_locals(len))
        self.assertEqual([], lookup.get_locals(var_len))
        self.assertEqual([], lookup.get_locals(a))
        self.assertEqual([], lookup.get_locals(data))