# -*- coding: utf-8 -*-
"""Data type definitions."""
import abc
import collections
import typing
from typing import Dict, List, Optional, Union # pylint: disable=unused-import
from dtfabric import definitions
[docs]class DataTypeDefinition(object):
"""Data type definition interface.
Attributes:
aliases (list[str]): aliases.
description (str): description.
name (str): name.
urls (list[str]): URLs.
"""
# Note that redundant-returns-doc is broken for pylint 1.7.x for abstract
# methods.
# pylint: disable=redundant-returns-doc
TYPE_INDICATOR: 'Union[str, None]' = None
_IS_COMPOSITE: 'bool' = False
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(DataTypeDefinition, self).__init__()
self.aliases: 'List[str]' = aliases or []
self.description: 'Union[str, None]' = description
self.name: 'str' = name
self.urls: 'Union[List[str], None]' = urls
[docs] @abc.abstractmethod
def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
[docs] def IsComposite(self) -> 'bool':
"""Determines if the data type is composite.
A composite data type consists of other data types.
Returns:
bool: True if the data type is composite, False otherwise.
"""
return self._IS_COMPOSITE
[docs]class StorageDataTypeDefinition(DataTypeDefinition):
"""Storage data type definition interface.
Attributes:
byte_order (str): byte-order the data type.
"""
# Note that redundant-returns-doc is broken for pylint 1.7.x for abstract
# methods.
# pylint: disable=redundant-returns-doc
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a storage data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(StorageDataTypeDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.byte_order: 'str' = definitions.BYTE_ORDER_NATIVE
[docs] @abc.abstractmethod
def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
[docs]class FixedSizeDataTypeDefinition(StorageDataTypeDefinition):
"""Fixed-size data type definition.
Attributes:
size (int|str): size of the data type or SIZE_NATIVE.
units (str): units of the size of the data type.
"""
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a fixed-size data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(FixedSizeDataTypeDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.size: 'Union[int, str]' = definitions.SIZE_NATIVE
self.units: 'str' = 'bytes'
[docs] def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
if self.size == definitions.SIZE_NATIVE or self.units != 'bytes':
return None
return typing.cast('Union[int, None]', self.size)
[docs]class BooleanDefinition(FixedSizeDataTypeDefinition):
"""Boolean data type definition.
Attributes:
false_value (int): value of False, None represents any value except that
defined by true_value.
true_value (int): value of True, None represents any value except that
defined by false_value.
"""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_BOOLEAN
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None, false_value: 'int' = 0,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a boolean data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
false_value (Optional[int]): value that represents false.
urls (Optional[list[str]]): URLs.
"""
super(BooleanDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.false_value: 'Union[int, None]' = false_value
self.true_value: 'Union[int, None]' = None
[docs]class CharacterDefinition(FixedSizeDataTypeDefinition):
"""Character data type definition."""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_CHARACTER
[docs]class FloatingPointDefinition(FixedSizeDataTypeDefinition):
"""Floating point data type definition."""
TYPE_INDICATOR: 'Union[str, None]' = (
definitions.TYPE_INDICATOR_FLOATING_POINT)
[docs]class IntegerDefinition(FixedSizeDataTypeDefinition):
"""Integer data type definition.
Attributes:
format (str): format of the data type.
maximum_value (int): maximum allowed value of the integer data type.
minimum_value (int): minimum allowed value of the integer data type.
"""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_INTEGER
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
maximum_value: 'Optional[int]' = None,
minimum_value: 'Optional[int]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes an integer data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
maximum_value (Optional[int]): maximum allowed value of the integer
data type.
minimum_value (Optional[int]): minimum allowed value of the integer
data type.
urls (Optional[list[str]]): URLs.
"""
super(IntegerDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.format: 'str' = definitions.FORMAT_SIGNED
self.maximum_value: 'Union[int, None]' = maximum_value
self.minimum_value: 'Union[int, None]' = minimum_value
[docs]class UUIDDefinition(FixedSizeDataTypeDefinition):
"""UUID (or GUID) data type definition."""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_UUID
_IS_COMPOSITE: 'bool' = True
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes an UUID data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(UUIDDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.size: 'Union[int, str]' = 16
[docs]class PaddingDefinition(StorageDataTypeDefinition):
"""Padding data type definition.
Attributes:
alignment_size (int): alignment size.
"""
# Note that redundant-returns-doc is broken for pylint 1.7.x for abstract
# methods.
# pylint: disable=redundant-returns-doc
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_PADDING
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
alignment_size: 'Optional[int]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a padding data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
alignment_size (Optional[int]): alignment size.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(PaddingDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.alignment_size: 'Union[int, None]' = alignment_size
[docs] def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
return None
[docs]class ElementSequenceDataTypeDefinition(StorageDataTypeDefinition):
"""Element sequence data type definition.
Attributes:
byte_order (str): byte-order the data type.
elements_data_size (int): data size of the sequence elements.
elements_data_size_expression (str): expression to determine the data
size of the sequence elements.
element_data_type (str): name of the sequence element data type.
element_data_type_definition (DataTypeDefinition): sequence element
data type definition.
elements_terminator (bytes|int): element value that indicates the
end-of-sequence.
number_of_elements (int): number of sequence elements.
number_of_elements_expression (str): expression to determine the number
of sequence elements.
"""
_IS_COMPOSITE: 'bool' = True
def __init__(
self, name: 'str', data_type_definition: 'DataTypeDefinition',
aliases: 'Optional[List[str]]' = None,
data_type: 'Optional[str]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a sequence data type definition.
Args:
name (str): name.
data_type_definition (DataTypeDefinition): sequence element data type
definition.
aliases (Optional[list[str]]): aliases.
data_type (Optional[str]): name of the sequence element data type.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(ElementSequenceDataTypeDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.byte_order: 'str' = getattr(
data_type_definition, 'byte_order', definitions.BYTE_ORDER_NATIVE)
self.elements_data_size: 'Union[int, None]' = None
self.elements_data_size_expression: 'Union[str, None]' = None
self.element_data_type: 'Union[str, None]' = data_type
self.element_data_type_definition: 'DataTypeDefinition' = (
data_type_definition)
self.elements_terminator: 'Union[str, None]' = None
self.number_of_elements: 'Union[int, None]' = None
self.number_of_elements_expression: 'Union[str, None]' = None
[docs] def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
if not self.element_data_type_definition:
return None
if self.elements_data_size:
return self.elements_data_size
if not self.number_of_elements:
return None
element_byte_size = self.element_data_type_definition.GetByteSize()
if not element_byte_size:
return None
return element_byte_size * self.number_of_elements
[docs]class SequenceDefinition(ElementSequenceDataTypeDefinition):
"""Sequence data type definition."""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_SEQUENCE
[docs]class StreamDefinition(ElementSequenceDataTypeDefinition):
"""Stream data type definition."""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_STREAM
[docs]class StringDefinition(ElementSequenceDataTypeDefinition):
"""String data type definition.
Attributes:
encoding (str): string encoding.
"""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_STRING
def __init__(
self, name: 'str', data_type_definition: 'DataTypeDefinition',
aliases: 'Optional[List[str]]' = None,
data_type: 'Optional[str]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a string data type definition.
Args:
name (str): name.
data_type_definition (DataTypeDefinition): string element data type
definition.
aliases (Optional[list[str]]): aliases.
data_type (Optional[str]): name of the string element data type.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(StringDefinition, self).__init__(
name, data_type_definition, aliases=aliases, data_type=data_type,
description=description, urls=urls)
self.encoding: 'str' = 'ascii'
[docs]class DataTypeDefinitionWithMembers(StorageDataTypeDefinition):
"""Data type definition with members.
Attributes:
members (list[DataTypeDefinition]): member data type definitions.
sections (list[MemberSectionDefinition]): member section definitions.
"""
# Note that redundant-returns-doc is broken for pylint 1.7.x for abstract
# methods.
# pylint: disable=redundant-returns-doc
_IS_COMPOSITE: 'bool' = True
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(DataTypeDefinitionWithMembers, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self._byte_size: 'Union[int, None]' = None
self._members_by_name: 'OrderedDict[str, DataTypeDefinition]' = (
collections.OrderedDict())
self.sections: 'List[MemberSectionDefinition]' = []
@property
def members(self) -> 'List[DataTypeDefinition]':
"""members (list[DataTypeDefinition]): member data type definitions."""
return list(self._members_by_name.values())
[docs] def AddMemberDefinition(
self, member_definition: 'DataTypeDefinition') -> 'None':
"""Adds a member definition.
Args:
member_definition (DataTypeDefinition): member data type definition.
Raises:
KeyError: if a member with the name already exists.
"""
if member_definition.name in self._members_by_name:
raise KeyError(f'Member: {member_definition.name:s} already set.')
self._byte_size = None
self._members_by_name[member_definition.name] = member_definition
if self.sections:
section_definition = self.sections[-1]
section_definition.members.append(member_definition)
[docs] def AddSectionDefinition(
self, section_definition: 'MemberSectionDefinition') -> 'None':
"""Adds a section definition.
Args:
section_definition (MemberSectionDefinition): member section definition.
"""
self.sections.append(section_definition)
[docs] @abc.abstractmethod
def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
[docs] def GetMemberDefinitionByName(
self, name: 'str') -> 'Union[int, DataTypeDefinition]':
"""Retrieve a specific member definition.
Args:
name (str): name of the member definition.
Returns:
DataTypeDefinition: member data type definition or None if not available.
"""
return self._members_by_name.get(name, None)
[docs]class MemberDataTypeDefinition(StorageDataTypeDefinition):
"""Member data type definition.
Attributes:
byte_order (str): byte-order the data type.
condition (str): condition under which the data type applies.
member_data_type (str): member data type.
member_data_type_definition (DataTypeDefinition): member data type
definition.
values (list[int|str]): supported values.
"""
def __init__(
self, name: 'str', data_type_definition: 'DataTypeDefinition',
aliases: 'Optional[List[str]]' = None, condition: 'Optional[str]' = None,
data_type: 'Optional[str]' = None, description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None,
values: 'Optional[List[Union[int, str]]]' = None) -> 'None':
"""Initializes a member data type definition.
Args:
name (str): name.
data_type_definition (DataTypeDefinition): member data type definition.
aliases (Optional[list[str]]): aliases.
condition (Optional[str]): condition under which the member is considered
present.
data_type (Optional[str]): member data type.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
values (Optional[list[int|str]]): supported values
defined.
"""
super(MemberDataTypeDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.byte_order: 'str' = getattr(
data_type_definition, 'byte_order', definitions.BYTE_ORDER_NATIVE)
self.condition: 'Union[str, None]' = condition
self.member_data_type: 'Union[str, None]' = data_type
self.member_data_type_definition: 'DataTypeDefinition' = (
data_type_definition)
self.values: 'Union[List[Union[int, str]], None]' = values
[docs] def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
if self.condition or not self.member_data_type_definition:
return None
return self.member_data_type_definition.GetByteSize()
[docs] def IsComposite(self) -> 'bool':
"""Determines if the data type is composite.
A composite data type consists of other data types.
Returns:
bool: True if the data type is composite, False otherwise.
"""
return bool(self.condition) or bool(
self.member_data_type_definition and
self.member_data_type_definition.IsComposite())
[docs]class MemberSectionDefinition(object):
"""Member section definition.
Attributes:
name (str): name of the section.
members (list[DataTypeDefinition]): member data type definitions of
the section.
"""
def __init__(self, name: 'str') -> 'None':
"""Initializes a member section definition.
Args:
name (str): name.
"""
super(MemberSectionDefinition, self).__init__()
self.name: 'str' = name
self.members: 'List[DataTypeDefinition]' = []
[docs]class StructureDefinition(DataTypeDefinitionWithMembers):
"""Structure data type definition."""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_STRUCTURE
[docs] def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
if self._byte_size is None and self._members_by_name:
self._byte_size = 0
for member_definition in self._members_by_name.values():
if (not isinstance(member_definition, PaddingDefinition) or
not member_definition.alignment_size):
byte_size = member_definition.GetByteSize()
if byte_size is None:
self._byte_size = None
break
else:
_, byte_size = divmod(
self._byte_size, member_definition.alignment_size)
if byte_size > 0:
byte_size = member_definition.alignment_size - byte_size
self._byte_size += byte_size
return self._byte_size
[docs]class UnionDefinition(DataTypeDefinitionWithMembers):
"""Union data type definition."""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_UNION
[docs] def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
if self._byte_size is None and self._members_by_name:
self._byte_size = 0
for member_definition in self._members_by_name.values():
byte_size = member_definition.GetByteSize()
if byte_size is None:
self._byte_size = None
break
self._byte_size = max(self._byte_size, byte_size)
return self._byte_size
[docs]class SemanticDataTypeDefinition(DataTypeDefinition):
"""Semantic data type definition interface."""
# Note that redundant-returns-doc is broken for pylint 1.7.x for abstract
# methods.
# pylint: disable=redundant-returns-doc
[docs] def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
return None
[docs]class ConstantDefinition(SemanticDataTypeDefinition):
"""Constant data type definition.
Attributes:
value (int): constant value.
"""
TYPE_INDICATOR: 'Union[str, None]' = definitions.TYPE_INDICATOR_CONSTANT
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes an enumeration data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(ConstantDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.value: 'Union[int, None]' = None
[docs]class EnumerationValue(object):
"""Enumeration value.
Attributes:
aliases (list[str]): aliases.
description (str): description.
name (str): name.
number (int): number.
"""
def __init__(
self, name: 'str', number: 'int',
aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None) -> 'None':
"""Initializes an enumeration value.
Args:
name (str): name.
number (int): number.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
"""
super(EnumerationValue, self).__init__()
self.aliases: 'List[str]' = aliases or []
self.description: 'Union[str, None]' = description
self.name: 'str' = name
self.number: 'int' = number
[docs]class EnumerationDefinition(SemanticDataTypeDefinition):
"""Enumeration data type definition.
Attributes:
values (list[EnumerationValue]): enumeration values.
values_per_alias (dict[str, EnumerationValue]): enumeration values per
alias.
values_per_name (dict[str, EnumerationValue]): enumeration values per name.
values_per_number (dict[int, EnumerationValue]): enumeration values per
number.
"""
TYPE_INDICATOR: 'Union[str, None]' = (
definitions.TYPE_INDICATOR_ENUMERATION)
def __init__(
self, name: 'str', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes an enumeration data type definition.
Args:
name (str): name.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(EnumerationDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self.values: 'List[EnumerationValue]' = []
self.values_per_alias: 'Dict[str, EnumerationValue]' = {}
self.values_per_name: 'Dict[str, EnumerationValue]' = {}
self.values_per_number: 'Dict[int, EnumerationValue]' = {}
[docs] def AddValue(
self, name: 'str', number: 'int', aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None) -> 'None':
"""Adds an enumeration value.
Args:
name (str): name.
number (int): number.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
Raises:
KeyError: if the enumeration value already exists.
"""
if name in self.values_per_name:
raise KeyError(f'Value with name: {name:s} already exists.')
if number in self.values_per_number:
raise KeyError(f'Value with number: {number!s} already exists.')
for alias in aliases or []:
if alias in self.values_per_alias:
raise KeyError(f'Value with alias: {alias:s} already exists.')
enumeration_value = EnumerationValue(
name, number, aliases=aliases, description=description)
self.values.append(enumeration_value)
self.values_per_name[name] = enumeration_value
self.values_per_number[number] = enumeration_value
for alias in aliases or []:
self.values_per_alias[alias] = enumeration_value
[docs]class LayoutDataTypeDefinition(DataTypeDefinition):
"""Layout data type definition interface."""
# Note that redundant-returns-doc is broken for pylint 1.7.x for abstract
# methods.
# pylint: disable=redundant-returns-doc
_IS_COMPOSITE: 'bool' = True
[docs] def GetByteSize(self) -> 'Union[int, None]':
"""Retrieves the byte size of the data type definition.
Returns:
int: data type size in bytes or None if size cannot be determined.
"""
return None
[docs]class LayoutElementDefinition(object):
"""Layout element definition.
Attributes:
data_type (str): name of the data type definition of the layout element.
offset (int): offset of the layout element.
"""
def __init__(
self, data_type: 'str', offset: 'Optional[int]' = None) -> 'None':
"""Initializes a layout element definition.
Args:
data_type (str): name of the data type of the layout element.
offset (Optional[int]): offset of the layout element.
"""
super(LayoutElementDefinition, self).__init__()
self.data_type: 'str' = data_type
self.offset: 'Union[int, None]' = offset
[docs]class StructureFamilyDefinition(LayoutDataTypeDefinition):
"""Structure family definition.
Attributes:
base (DataTypeDefinition): base data type definition.
members (list[DataTypeDefinition]): member data type definitions.
"""
TYPE_INDICATOR: 'Union[str, None]' = (
definitions.TYPE_INDICATOR_STRUCTURE_FAMILY)
def __init__(
self, name: 'str', base_definition: 'StructureDefinition',
aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a structure family data type definition.
Args:
name (str): name.
base_definition (StructureDefinition): base data type definition.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(StructureFamilyDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self._members_by_name: 'OrderedDict[str, DataTypeDefinition]' = (
collections.OrderedDict())
self.base: 'Union[DataTypeDefinition, None]' = base_definition
@property
def members(self) -> 'List[DataTypeDefinition]':
"""members (list[DataTypeDefinition]): member data type definitions."""
return list(self._members_by_name.values())
[docs] def AddMemberDefinition(
self, member_definition: 'StructureDefinition') -> 'None':
"""Adds a member definition.
Args:
member_definition (StructureDefinition): member data type definition.
Raises:
KeyError: if a member with the name already exists.
"""
if member_definition.name in self._members_by_name:
raise KeyError(f'Member: {member_definition.name:s} already set.')
self._members_by_name[member_definition.name] = member_definition
[docs] def SetBaseDefinition(
self, base_definition: 'StructureDefinition') -> 'None':
"""Sets a base definition.
Args:
base_definition (StructureDefinition): base data type definition.
"""
self.base = base_definition
[docs]class StructureGroupDefinition(LayoutDataTypeDefinition):
"""Structure group definition.
Attributes:
base (DataTypeDefinition): base data type definition.
byte_order (str): byte-order the data type.
default (DataTypeDefinition): default data type definition.
identifier (str): name of the base structure member to identify the group
members.
members (list[DataTypeDefinition]): member data type definitions.
"""
TYPE_INDICATOR: 'Union[str, None]' = (
definitions.TYPE_INDICATOR_STRUCTURE_GROUP)
def __init__(
self, name: 'str', base_definition: 'StructureDefinition',
identifier: 'str', default_definition: 'StructureDefinition',
aliases: 'Optional[List[str]]' = None,
description: 'Optional[str]' = None,
urls: 'Optional[List[str]]' = None) -> 'None':
"""Initializes a structure group data type definition.
Args:
name (str): name.
base_definition (StructureDefinition): base data type definition.
identifier (str): name of the base structure member to identify the group
members.
default_definition (StructureDefinition): default data type definition.
aliases (Optional[list[str]]): aliases.
description (Optional[str]): description.
urls (Optional[list[str]]): URLs.
"""
super(StructureGroupDefinition, self).__init__(
name, aliases=aliases, description=description, urls=urls)
self._members_by_name: 'OrderedDict[str, DataTypeDefinition]' = (
collections.OrderedDict())
self.base: 'Union[DataTypeDefinition, None]' = base_definition
self.byte_order: 'str' = getattr(
base_definition, 'byte_order', definitions.BYTE_ORDER_NATIVE)
self.default: 'Union[DataTypeDefinition, None]' = default_definition
self.identifier: 'Union[str, None]' = identifier
@property
def members(self) -> 'List[DataTypeDefinition]':
"""members (list[DataTypeDefinition]): member data type definitions."""
return list(self._members_by_name.values())
[docs] def AddMemberDefinition(
self, member_definition: 'StructureDefinition') -> 'None':
"""Adds a member definition.
Args:
member_definition (StructureDefinition): member data type definition.
Raises:
KeyError: if a member with the name already exists.
"""
if member_definition.name in self._members_by_name:
raise KeyError(f'Member: {member_definition.name:s} already set.')
self._members_by_name[member_definition.name] = member_definition