Skip to content

Commit

Permalink
Added support for structure member external context #3
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimmetz committed Jan 24, 2022
1 parent fdbcfc6 commit 9af44cc
Show file tree
Hide file tree
Showing 4 changed files with 270 additions and 13 deletions.
18 changes: 14 additions & 4 deletions dtfabric/runtime/data_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,8 +687,12 @@ def _EvaluateElementsDataSize(self, context):
raise errors.MappingError(
'Unable to determine elements data size with error: {0!s}'.format(
exception))
try:
invalid_value = elements_data_size is None or elements_data_size < 0
except TypeError:
invalid_value = True

if elements_data_size is None or elements_data_size < 0:
if invalid_value:
raise errors.MappingError(
'Invalid elements data size: {0!s}'.format(elements_data_size))

Expand Down Expand Up @@ -725,7 +729,12 @@ def _EvaluateNumberOfElements(self, context):
'Unable to determine number of elements with error: {0!s}'.format(
exception))

if number_of_elements is None or number_of_elements < 0:
try:
invalid_value = number_of_elements is None or number_of_elements < 0
except TypeError:
invalid_value = True

if invalid_value:
raise errors.MappingError(
'Invalid number of elements: {0!s}'.format(number_of_elements))

Expand Down Expand Up @@ -1589,6 +1598,7 @@ def _CompositeMapByteStream(
the byte stream.
"""
context_state = getattr(context, 'state', {})
context_values = getattr(context, 'values', {})

attribute_index = context_state.get('attribute_index', 0)
mapped_values = context_state.get('mapped_values', None)
Expand All @@ -1597,8 +1607,8 @@ def _CompositeMapByteStream(
if not mapped_values:
mapped_values = self._structure_values_class()
if not subcontext:
subcontext = DataTypeMapContext(values={
type(mapped_values).__name__: mapped_values})
context_values.update({type(mapped_values).__name__: mapped_values})
subcontext = DataTypeMapContext(values=context_values)

members_data_size = 0

Expand Down
26 changes: 26 additions & 0 deletions test_data/sequence_with_context.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: int32
type: integer
description: 32-bit signed integer type
attributes:
byte_order: little-endian
format: signed
size: 4
units: bytes
---
name: nvector
type: sequence
description: n-dimensional vector
element_data_type: int32
number_of_elements: n
---
name: fixed_size_vector
type: sequence
description: vector with a fixed size
element_data_type: int32
elements_data_size: 32
---
name: variable_size_vector
type: sequence
description: vector with a variable size
element_data_type: int32
elements_data_size: vector_size
27 changes: 27 additions & 0 deletions test_data/structure_with_context.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: byte
type: integer
attributes:
format: unsigned
size: 1
units: bytes
---
name: uint32
type: integer
attributes:
format: unsigned
size: 4
units: bytes
---
name: instance_block_header
type: structure
attributes:
byte_order: little-endian
members:
- name: name_offset
data_type: uint32
- name: unknown1
data_type: byte
- name: property_value_offsets
type: sequence
element_data_type: uint32
number_of_elements: number_of_properties
212 changes: 203 additions & 9 deletions tests/runtime/data_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,120 @@ def testInitialize(self):
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)
self.assertIsNotNone(data_type_map)

# TODO: add tests for _CalculateElementsDataSize.
# TODO: add tests for _EvaluateElementsDataSize.
# TODO: add tests for _EvaluateNumberOfElements.
def testCalculateElementsDataSize(self):
"""Tests the _CalculateElementsDataSize function."""
definitions_file = self._GetTestFilePath(['sequence.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName('triangle4')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

context = data_maps.DataTypeMapContext()

elements_data_size = data_type_map._CalculateElementsDataSize(context)
self.assertEqual(elements_data_size, 48)

definitions_file = self._GetTestFilePath(['sequence_with_context.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName('nvector')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

context = data_maps.DataTypeMapContext(values={'n': 99})

elements_data_size = data_type_map._CalculateElementsDataSize(context)
self.assertEqual(elements_data_size, 396)

data_type_definition = definitions_registry.GetDefinitionByName(
'variable_size_vector')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

context = data_maps.DataTypeMapContext(values={'vector_size': 404})

elements_data_size = data_type_map._CalculateElementsDataSize(context)
self.assertEqual(elements_data_size, 404)

def testEvaluateElementsDataSize(self):
"""Tests the _EvaluateElementsDataSize function."""
definitions_file = self._GetTestFilePath(['sequence_with_context.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName(
'fixed_size_vector')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

context = data_maps.DataTypeMapContext()

elements_data_size = data_type_map._EvaluateElementsDataSize(context)
self.assertEqual(elements_data_size, 32)

data_type_definition = definitions_registry.GetDefinitionByName(
'variable_size_vector')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

context = data_maps.DataTypeMapContext(values={'vector_size': 404})

elements_data_size = data_type_map._EvaluateElementsDataSize(context)
self.assertEqual(elements_data_size, 404)

with self.assertRaises(errors.MappingError):
context = data_maps.DataTypeMapContext()

data_type_map._EvaluateElementsDataSize(context)

with self.assertRaises(errors.MappingError):
context = data_maps.DataTypeMapContext(values={'vector_size': -404})

data_type_map._EvaluateElementsDataSize(context)

with self.assertRaises(errors.MappingError):
context = data_maps.DataTypeMapContext(values={'vector_size': 'bogus'})

data_type_map._EvaluateElementsDataSize(context)

def testEvaluateNumberOfElements(self):
"""Tests the _EvaluateNumberOfElements function."""
definitions_file = self._GetTestFilePath(['sequence.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName('triangle4')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

context = data_maps.DataTypeMapContext()

number_of_elements = data_type_map._EvaluateNumberOfElements(context)
self.assertEqual(number_of_elements, 3)

definitions_file = self._GetTestFilePath(['sequence_with_context.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName('nvector')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

context = data_maps.DataTypeMapContext(values={'n': 99})

number_of_elements = data_type_map._EvaluateNumberOfElements(context)
self.assertEqual(number_of_elements, 99)

with self.assertRaises(errors.MappingError):
context = data_maps.DataTypeMapContext()

data_type_map._EvaluateNumberOfElements(context)

with self.assertRaises(errors.MappingError):
context = data_maps.DataTypeMapContext(values={'n': -99})

data_type_map._EvaluateNumberOfElements(context)

with self.assertRaises(errors.MappingError):
context = data_maps.DataTypeMapContext(values={'n': 'bogus'})

data_type_map._EvaluateNumberOfElements(context)

def testGetElementDataTypeDefinition(self):
"""Tests the _GetElementDataTypeDefinition function."""
Expand All @@ -699,11 +810,53 @@ def testGetElementDataTypeDefinition(self):
data_type_definition = EmptyDataTypeDefinition('empty')
data_type_map._GetElementDataTypeDefinition(data_type_definition)

# TODO: add tests for _HasElementsDataSize.
# TODO: add tests for _HasElementsTerminator.
# TODO: add tests for _HasNumberOfElements.
def testHasElementsDataSize(self):
"""Tests the _HasElementsDataSize function."""
definitions_file = self._GetTestFilePath(['sequence.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

# TODO: add tests for GetSizeHint.
data_type_definition = definitions_registry.GetDefinitionByName('vector4')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

result = data_type_map._HasElementsDataSize()
self.assertFalse(result)

def testHasElementsTerminator(self):
"""Tests the _HasElementsTerminator function."""
definitions_file = self._GetTestFilePath(['sequence.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName('vector4')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

result = data_type_map._HasElementsTerminator()
self.assertFalse(result)

def testHasNumberOfElements(self):
"""Tests the _HasNumberOfElements function."""
definitions_file = self._GetTestFilePath(['sequence.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName('vector4')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

result = data_type_map._HasNumberOfElements()
self.assertTrue(result)

def testGetSizeHint(self):
"""Tests the GetSizeHint function."""
definitions_file = self._GetTestFilePath(['sequence.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName('vector4')
data_type_map = data_maps.ElementSequenceDataTypeMap(data_type_definition)

size_hint = data_type_map.GetSizeHint()
self.assertEqual(size_hint, 16)

def testGetStructByteOrderString(self):
"""Tests the GetStructByteOrderString function."""
Expand Down Expand Up @@ -1085,7 +1238,48 @@ def testCheckCompositeMap(self):
self.assertTrue(result)

# TODO: add tests for _CompositeFoldByteStream.
# TODO: add tests for _CompositeMapByteStream.

def testCompositeMapByteStream(self):
"""Tests the _CompositeMapByteStream function."""
definitions_file = self._GetTestFilePath(['structure_with_string.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName(
'utf16_string')
data_type_map = data_maps.StructureMap(data_type_definition)

text_stream = 'dtFabric'.encode('utf-16-le')
byte_stream = b''.join([
bytes(bytearray([len(text_stream), 0])), text_stream])

utf16_string = data_type_map._CompositeMapByteStream(byte_stream)
self.assertEqual(utf16_string.size, len(text_stream))
self.assertEqual(utf16_string.text, 'dtFabric')

byte_stream = b''.join([bytes(bytearray([3, 0])), text_stream])

with self.assertRaises(errors.MappingError):
data_type_map._CompositeMapByteStream(byte_stream)

definitions_file = self._GetTestFilePath(['structure_with_context.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)

data_type_definition = definitions_registry.GetDefinitionByName(
'instance_block_header')
data_type_map = data_maps.StructureMap(data_type_definition)

context = data_maps.DataTypeMapContext(values={'number_of_properties': 3})

byte_stream = bytes(bytearray([
10, 0, 0, 0, 128, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]))

instance_block_header = data_type_map._CompositeMapByteStream(
byte_stream, context=context)
self.assertEqual(instance_block_header.name_offset, 10)
self.assertEqual(instance_block_header.unknown1, 0x80)
self.assertEqual(instance_block_header.property_value_offsets, (1, 2, 3))

def testGetMemberDataTypeMaps(self):
"""Tests the _GetMemberDataTypeMaps function."""
Expand Down Expand Up @@ -1537,7 +1731,7 @@ def testMapByteStreamWithStringArray(self):
data_type_map.MapByteStream(byte_stream)

def testGetSizeHint(self):
"""Tests the GetSizeHint function with a string."""
"""Tests the GetSizeHint function."""
definitions_file = self._GetTestFilePath(['structure_with_string.yaml'])
definitions_registry = self._CreateDefinitionRegistryFromFile(
definitions_file)
Expand Down

0 comments on commit 9af44cc

Please sign in to comment.