Stacks the various layers and attaches these to a specific requirement .

def stack(self, context: interfaces.context.ContextInterface, config_path: str,
              requirement: interfaces.configuration.RequirementInterface,
              progress_callback: constants.ProgressCallback) -> None:
        """Stacks the various layers and attaches these to a specific
        requirement.

        Args:
            context: Context on which to operate
            config_path: Configuration path under which to store stacking data
            requirement: Requirement that should have layers stacked on it
            progress_callback: Function to provide callback progress
        """
        # If we're cached, find Now we need to find where to apply the stack configuration
        if self._cached:
            top_layer_name, subconfig = self._cached
            result = self.find_suitable_requirements(context, config_path, requirement, [top_layer_name])
            if result:
                appropriate_config_path, layer_name = result
                context.config.merge(appropriate_config_path, subconfig)
                context.config[appropriate_config_path] = top_layer_name
                return
            self._cached = None

        new_context = context.clone()
        location = self.config.get('single_location', None)

        # Setup the local copy of the resource
        current_layer_name = context.layers.free_layer_name("FileLayer")
        current_config_path = interfaces.configuration.path_join(config_path, "stack", current_layer_name)

        # This must be specific to get us started, setup the config and run
        new_context.config[interfaces.configuration.path_join(current_config_path, "location")] = location
        physical_layer = physical.FileLayer(new_context, current_config_path, current_layer_name)
        new_context.add_layer(physical_layer)

        stacked_layers = self.stack_layer(new_context, current_layer_name, self.create_stackers_list(),
                                          progress_callback)

        if stacked_layers is not None:
            # Applies the stacked_layers to each requirement in the requirements list
            result = self.find_suitable_requirements(new_context, config_path, requirement, stacked_layers)
            if result:
                path, layer = result
                # splice in the new configuration into the original context
                context.config.merge(path, new_context.layers[layer].build_configuration())

                # Call the construction magic now we may have new things to construct
                constructor = construct_layers.ConstructionMagic(
                    context, interfaces.configuration.path_join(self.config_path, "ConstructionMagic"))
                constructor(context, config_path, requirement)

                # Stash the changed config items
                self._cached = context.config.get(path, None), context.config.branch(path)
        vollog.debug("Stacked layers: {}".format(stacked_layers))


Stacks as many possible layers on top of the initial layer as can be done .

def stack_layer(cls,
                    context: interfaces.context.ContextInterface,
                    initial_layer: str,
                    stack_set: List[Type[interfaces.automagic.StackerLayerInterface]] = None,
                    progress_callback: constants.ProgressCallback = None):
        """Stacks as many possible layers on top of the initial layer as can be done.

        WARNING: This modifies the context provided and may pollute it with unnecessary layers
        Recommended use is to:
        1. Pass in context.clone() instead of context
        2. When provided the layer list, choose the desired layer
        3. Build the configuration using layer.build_configuration()
        4. Merge the configuration into the original context with context.config.merge()
        5. Call Construction magic to reconstruct the layers from just the configuration

        Args:
            context: The context on which to operate
            initial_layer: The name of the initial layer within the context
            stack_set: A list of StackerLayerInterface objects in the order they should be stacked
            progress_callback: A function to report progress during the process

        Returns:
            A list of layer names that exist in the provided context, stacked in order (highest to lowest)
        """
        # Repeatedly apply "determine what this is" code and build as much up as possible
        stacked = True
        stacked_layers = [initial_layer]
        if stack_set is None:
            stack_set = list(framework.class_subclasses(interfaces.automagic.StackerLayerInterface))

        for stacker_item in stack_set:
            if not issubclass(stacker_item, interfaces.automagic.StackerLayerInterface):
                raise TypeError("Stacker {} is not a descendent of StackerLayerInterface".format(stacker_item.__name__))

        while stacked:
            stacked = False
            new_layer = None
            stacker_cls = None
            for stacker_cls in stack_set:
                stacker = stacker_cls()
                try:
                    vollog.log(constants.LOGLEVEL_VV, "Attempting to stack using {}".format(stacker_cls.__name__))
                    new_layer = stacker.stack(context, initial_layer, progress_callback)
                    if new_layer:
                        context.layers.add_layer(new_layer)
                        vollog.log(constants.LOGLEVEL_VV,
                                   "Stacked {} using {}".format(new_layer.name, stacker_cls.__name__))
                        break
                except Exception as excp:
                    # Stacking exceptions are likely only of interest to developers, so the lowest level of logging
                    fulltrace = traceback.TracebackException.from_exception(excp).format(chain = True)
                    vollog.log(constants.LOGLEVEL_VVV, "Exception during stacking: {}".format(str(excp)))
                    vollog.log(constants.LOGLEVEL_VVVV, "\n".join(fulltrace))
            else:
                stacked = False
            if new_layer and stacker_cls:
                stacked_layers = [new_layer.name] + stacked_layers
                initial_layer = new_layer.name
                stacked = True
                stack_set.remove(stacker_cls)
        return stacked_layers


def create_stackers_list(self) -> List[Type[interfaces.automagic.StackerLayerInterface]]:
        """Creates the list of stackers to use based on the config option"""
        stack_set = sorted(framework.class_subclasses(interfaces.automagic.StackerLayerInterface),
                           key = lambda x: x.stack_order)
        stacker_list = self.config.get('stackers', [])
        if len(stacker_list):
            result = []
            for stacker in stack_set:
                if stacker.__name__ in stacker_list:
                    result.append(stacker)
            stack_set = result
        return stack_set

def create_stackers_list ( self ) -> List [ Type [ interfaces . automagic . StackerLayerInterface ] ] : stack_set = sorted ( framework . class_subclasses ( interfaces . automagic . StackerLayerInterface ) , key = lambda x : x . stack_order ) stacker_list = self . config . get ( 'stackers' , [ ] ) if len ( stacker_list ) : result = [ ] for stacker in stack_set : if stacker . __name__ in stacker_list : result . append ( stacker ) stack_set = result return stack_set


Looks for translation layer requirements and attempts to apply the stacked layers to it . If it succeeds it returns the configuration path and layer name where the stacked nodes were spliced into the tree .

def find_suitable_requirements(cls, context: interfaces.context.ContextInterface, config_path: str,
                                   requirement: interfaces.configuration.RequirementInterface,
                                   stacked_layers: List[str]) -> Optional[Tuple[str, str]]:
        """Looks for translation layer requirements and attempts to apply the
        stacked layers to it.  If it succeeds it returns the configuration path
        and layer name where the stacked nodes were spliced into the tree.

        Returns:
            A tuple of a configuration path and layer name for the top of the stacked layers
                or None if suitable requirements are not found
        """
        child_config_path = interfaces.configuration.path_join(config_path, requirement.name)
        if isinstance(requirement, requirements.TranslationLayerRequirement):
            if requirement.unsatisfied(context, config_path):
                original_setting = context.config.get(child_config_path, None)
                for layer_name in stacked_layers:
                    context.config[child_config_path] = layer_name
                    if not requirement.unsatisfied(context, config_path):
                        return child_config_path, layer_name
                # Clean-up to restore the config
                if original_setting:
                    context.config[child_config_path] = original_setting
                else:
                    del context.config[child_config_path]
            else:
                return child_config_path, context.config.get(child_config_path, None)
        for req_name, req in requirement.requirements.items():
            result = cls.find_suitable_requirements(context, child_config_path, req, stacked_layers)
            if result:
                return result
        return None

def
find_suitable_requirements
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
config_path
:
str
,
requirement
:
interfaces
.
configuration
.
RequirementInterface
,
stacked_layers
:
List
[
str
]
)
->
Optional
[
Tuple
[
str
,
str
]
]
:
child_config_path
=
interfaces
.
configuration
.
path_join
(
config_path
,
requirement
.
name
)
if
isinstance
(
requirement
,
requirements
.
TranslationLayerRequirement
)
:
if
requirement
.
unsatisfied
(
context
,
config_path
)
:
original_setting
=
context
.
config
.
get
(
child_config_path
,
)
for
layer_name
in
stacked_layers
:
context
.
config
[
child_config_path
]
=
layer_name
if
not
requirement
.
unsatisfied
(
context
,
config_path
)
:
return
child_config_path
,
layer_name
# Clean-up to restore the config
if
original_setting
:
context
.
config
[
child_config_path
]
=
original_setting
else
:
del
context
.
config
[
child_config_path
]
else
:
return
child_config_path
,
context
.
config
.
get
(
child_config_path
,
)
for
req_name
,
req
in
requirement
.
requirements
.
items
(
)
:
result
=
cls
.
find_suitable_requirements
(
context
,
child_config_path
,
req
,
stacked_layers
)
if
result
:
return
result
return


Returns a symbol using the symbol_table_name of the Module .

def get_module_wrapper(method: str) -> Callable:
    """Returns a symbol using the symbol_table_name of the Module."""

    def wrapper(self, name: str) -> Callable:
        if constants.BANG not in name:
            name = self._module_name + constants.BANG + name
        else:
            raise ValueError("Cannot reference another module when calling {}".format(method))
        return getattr(self._context.symbol_space, method)(name)

    for entry in ['__annotations__', '__doc__', '__module__', '__name__', '__qualname__']:
        proxy_interface = getattr(interfaces.context.ModuleInterface, method)
        if hasattr(proxy_interface, entry):
            setattr(wrapper, entry, getattr(proxy_interface, entry))

    return wrapper


def __init__(self) -> None:
        """Initializes the context."""
        super().__init__()
        self._symbol_space = symbols.SymbolSpace()
        self._memory = interfaces.layers.LayerContainer()
        self._config = interfaces.configuration.HierarchicalDict()

def __init__ ( self ) -> None : super ( ) . __init__ ( ) self . _symbol_space = symbols . SymbolSpace ( ) self . _memory = interfaces . layers . LayerContainer ( ) self . _config = interfaces . configuration . HierarchicalDict ( )


Returns a mutable copy of the configuration but does not allow the whole configuration to be altered .

def config(self) -> interfaces.configuration.HierarchicalDict:
        """Returns a mutable copy of the configuration, but does not allow the
        whole configuration to be altered."""
        return self._config

def config ( self ) -> interfaces . configuration . HierarchicalDict : return self . _config


The space of all symbols that can be accessed within this context .

def symbol_space(self) -> interfaces.symbols.SymbolSpaceInterface:
        """The space of all symbols that can be accessed within this
        context."""
        return self._symbol_space

def symbol_space ( self ) -> interfaces . symbols . SymbolSpaceInterface : return self . _symbol_space


A LayerContainer object allowing access to all data and translation layers currently available within the context .

def layers(self) -> interfaces.layers.LayerContainer:
        """A LayerContainer object, allowing access to all data and translation
        layers currently available within the context."""
        return self._memory

def layers ( self ) -> interfaces . layers . LayerContainer : return self . _memory


Adds a named translation layer to the context .

def add_layer(self, layer: interfaces.layers.DataLayerInterface) -> None:
        """Adds a named translation layer to the context.

        Args:
            layer: The layer to be added to the memory

        Raises:
            volatility.framework.exceptions.LayerException: if the layer is already present, or has
                unmet dependencies
        """
        self._memory.add_layer(layer)

def add_layer ( self , layer : interfaces . layers . DataLayerInterface ) -> None : self . _memory . add_layer ( layer )


Object factory takes a context symbol offset and optional layername .

def object(self,
               object_type: Union[str, interfaces.objects.Template],
               layer_name: str,
               offset: int,
               native_layer_name: Optional[str] = None,
               **arguments) -> interfaces.objects.ObjectInterface:
        """Object factory, takes a context, symbol, offset and optional
        layername.

        Looks up the layername in the context, finds the object template based on the symbol,
        and constructs an object using the object template on the layer at the offset.

        Args:
            object_type: The name (or template) of the symbol type on which to construct the object.  If this is a name, it should contain an explicit table name.
            layer_name: The name of the layer on which to construct the object
            offset: The offset within the layer at which the data used to create the object lives
            native_layer_name: The name of the layer the object references (for pointers) if different to layer_name

        Returns:
            A fully constructed object
        """
        if not isinstance(object_type, interfaces.objects.Template):
            try:
                object_template = self._symbol_space.get_type(object_type)
            except exceptions.SymbolError:
                object_template = self._symbol_space.get_enumeration(object_type)
        else:
            if isinstance(object_type, templates.ReferenceTemplate):
                object_type = self._symbol_space.get_type(object_type.vol.type_name)
            object_template = object_type
            # Ensure that if a pre-constructed type is provided we just instantiate it
            arguments.update(object_template.vol)

        object_template = object_template.clone()
        object_template.update_vol(**arguments)
        return object_template(context = self,
                               object_info = interfaces.objects.ObjectInformation(layer_name = layer_name,
                                                                                offset = offset,
                                                                                native_layer_name = native_layer_name,
                                                                                size = object_template.size))


Constructs a new os - independent module .

def module(self,
               module_name: str,
               layer_name: str,
               offset: int,
               native_layer_name: Optional[str] = None,
               size: Optional[int] = None) -> interfaces.context.ModuleInterface:
        """Constructs a new os-independent module.

        Args:
            module_name: The name of the module
            layer_name: The layer within the context in which the module exists
            offset: The offset at which the module exists in the layer
            native_layer_name: The default native layer for objects constructed by the module
            size: The size, in bytes, that the module occupys from offset location within the layer named layer_name
        """
        if size:
            return SizedModule(self,
                               module_name = module_name,
                               layer_name = layer_name,
                               offset = offset,
                               size = size,
                               native_layer_name = native_layer_name)
        return Module(self,
                      module_name = module_name,
                      layer_name = layer_name,
                      offset = offset,
                      native_layer_name = native_layer_name)

def module ( self , module_name : str , layer_name : str , offset : int , native_layer_name : Optional [ str ] = None , size : Optional [ int ] = None ) -> interfaces . context . ModuleInterface : if size : return SizedModule ( self , module_name = module_name , layer_name = layer_name , offset = offset , size = size , native_layer_name = native_layer_name ) return Module ( self , module_name = module_name , layer_name = layer_name , offset = offset , native_layer_name = native_layer_name )


Returns an object created using the symbol_table_name and layer_name of the Module .

def object(self,
               object_type: str,
               offset: int = None,
               native_layer_name: Optional[str] = None,
               absolute: bool = False,
               **kwargs) -> 'interfaces.objects.ObjectInterface':
        """Returns an object created using the symbol_table_name and layer_name
        of the Module.

        Args:
            object_type: Name of the type/enumeration (within the module) to construct
            offset: The location of the object, ignored when symbol_type is SYMBOL
            native_layer_name: Name of the layer in which constructed objects are made (for pointers)
            absolute: whether the type's offset is absolute within memory or relative to the module
        """
        if constants.BANG not in object_type:
            object_type = self.symbol_table_name + constants.BANG + object_type
        else:
            raise ValueError("Cannot reference another module when constructing an object")

        if offset is None:
            raise TypeError("Offset must not be None for non-symbol objects")

        if not absolute:
            offset += self._offset

        # Ensure we don't use a layer_name other than the module's, why would anyone do that?
        if 'layer_name' in kwargs:
            del kwargs['layer_name']
        return self._context.object(object_type = object_type,
                                    layer_name = self._layer_name,
                                    offset = offset,
                                    native_layer_name = native_layer_name or self._native_layer_name,
                                    **kwargs)


Returns an object based on a specific symbol ( containing type and offset information ) and the layer_name of the Module . This will throw a ValueError if the symbol does not contain an associated type or if the symbol name is invalid . It will throw a SymbolError if the symbol cannot be found .

def object_from_symbol(self,
                           symbol_name: str,
                           native_layer_name: Optional[str] = None,
                           absolute: bool = False,
                           **kwargs) -> 'interfaces.objects.ObjectInterface':
        """Returns an object based on a specific symbol (containing type and
        offset information) and the layer_name of the Module.  This will throw
        a ValueError if the symbol does not contain an associated type, or if
        the symbol name is invalid.  It will throw a SymbolError if the symbol
        cannot be found.

        Args:
            symbol_name: Name of the symbol (within the module) to construct
            native_layer_name: Name of the layer in which constructed objects are made (for pointers)
            absolute: whether the symbol's address is absolute or relative to the module
        """
        if constants.BANG not in symbol_name:
            symbol_name = self.symbol_table_name + constants.BANG + symbol_name
        else:
            raise ValueError("Cannot reference another module when constructing an object")

        # Only set the offset if type is Symbol and we were given a name, not a template
        symbol_val = self._context.symbol_space.get_symbol(symbol_name)
        offset = symbol_val.address

        if not absolute:
            offset += self._offset

        if symbol_val.type is None:
            raise TypeError("Symbol {} has no associated type".format(symbol_val.name))

        # Ensure we don't use a layer_name other than the module's, why would anyone do that?
        if 'layer_name' in kwargs:
            del kwargs['layer_name']

        # Since type may be a template, we don't just call our own module method
        return self._context.object(object_type = symbol_val.type,
                                    layer_name = self._layer_name,
                                    offset = offset,
                                    native_layer_name = native_layer_name or self._native_layer_name,
                                    **kwargs)


Returns the size of the module ( 0 for unknown size )

def size(self) -> int:
        """Returns the size of the module (0 for unknown size)"""
        return self._size

def size ( self ) -> int : return self . _size


def hash(self) -> str:
        """Hashes the module for equality checks.

        The mapping should be sorted and should be quicker than reading
        the data We turn it into JSON to make a common string and use a
        quick hash, because collissions are unlikely
        """
        layer = self._context.layers[self.layer_name]
        if not isinstance(layer, interfaces.layers.TranslationLayerInterface):
            raise TypeError("Hashing modules on non-TranslationLayers is not allowed")
        return hashlib.md5(bytes(str(list(layer.mapping(self.offset, self.size, ignore_errors = True))),
                                 'utf-8')).hexdigest()


Returns the symbols within this module that live at the specified absolute offset provided .

def get_symbols_by_absolute_location(self, offset: int, size: int = 0) -> List[str]:
        """Returns the symbols within this module that live at the specified
        absolute offset provided."""
        if size < 0:
            raise ValueError("Size must be strictly non-negative")
        if offset > self._offset + self.size:
            return []
        return list(
            self._context.symbol_space.get_symbols_by_location(offset = offset - self._offset,
                                                               size = size,
                                                               table_name = self.symbol_table_name))

def
get_symbols_by_absolute_location
(
self
,
offset
:
int
,
size
:
int
=
0
)
->
List
[
str
]
:
if
size
<
0
:
raise
ValueError
(
"Size must be strictly non-negative"
)
if
offset
>
self
.
_offset
+
self
.
size
:
return
[
]
return
list
(
self
.
_context
.
symbol_space
.
get_symbols_by_location
(
offset
=
offset
self
.
_offset
,
size
=
size
,
table_name
=
self
.
symbol_table_name
)
)


Returns a new deduplicated ModuleCollection featuring no repeated modules ( based on data hash )

def deduplicate(self) -> 'ModuleCollection':
        """Returns a new deduplicated ModuleCollection featuring no repeated
        modules (based on data hash)

        All 0 sized modules will have identical hashes and are therefore
        included in the deduplicated version
        """
        new_modules = []
        seen = set()  # type: Set[str]
        for mod in self._modules:
            if mod.hash not in seen or mod.size == 0:
                new_modules.append(mod)
                seen.add(mod.hash)  # type: ignore # FIXME: mypy #5107
        return ModuleCollection(new_modules)

def
deduplicate
(
self
)
->
'ModuleCollection'
:
new_modules
=
[
]
seen
=
set
(
)
# type: Set[str]
for
mod
in
self
.
_modules
:
if
mod
.
hash
not
in
seen
or
mod
.
size
==
0
:
new_modules
.
append
(
mod
)
seen
.
add
(
mod
.
hash
)
# type: ignore # FIXME: mypy #5107
return
ModuleCollection
(
new_modules
)


A name indexed dictionary of modules using that name in this collection .

def modules(self) -> Dict[str, List[SizedModule]]:
        """A name indexed dictionary of modules using that name in this
        collection."""
        return self._generate_module_dict(self._modules)

def modules ( self ) -> Dict [ str , List [ SizedModule ] ] : return self . _generate_module_dict ( self . _modules )


Returns a tuple of ( module_name list_of_symbol_names ) for each module where symbols live at the absolute offset in memory provided .

def get_module_symbols_by_absolute_location(self, offset: int, size: int = 0) -> Iterable[Tuple[str, List[str]]]:
        """Returns a tuple of (module_name, list_of_symbol_names) for each
        module, where symbols live at the absolute offset in memory
        provided."""
        if size < 0:
            raise ValueError("Size must be strictly non-negative")
        for module in self._modules:
            if (offset <= module.offset + module.size) and (offset + size >= module.offset):
                yield (module.name, module.get_symbols_by_absolute_location(offset, size))

def
get_module_symbols_by_absolute_location
(
self
,
offset
:
int
,
size
:
int
=
0
)
->
Iterable
[
Tuple
[
str
,
List
[
str
]
]
]
:
if
size
<
0
:
raise
ValueError
(
"Size must be strictly non-negative"
)
for
module
in
self
.
_modules
:
if
(
offset
<=
module
.
offset
+
module
.
size
)
and
(
offset
+
size
>=
module
.
offset
)
:
yield
(
module
.
name
,
module
.
get_symbols_by_absolute_location
(
offset
,
size
)
)


def __getattr__(self, attr: str) -> Any:
        """Returns the item as an attribute."""
        if attr == '_dict':
            return super().__getattribute__(attr)
        if attr in self._dict:
            return self._dict[attr]
        raise AttributeError("Object has no attribute: {}.{}".format(self.__class__.__name__, attr))

def
__getattr__
(
self
,
attr
:
str
)
->
Any
:
if
attr
==
'_dict'
:
return
super
(
)
.
__getattribute__
(
attr
)
if
attr
in
self
.
_dict
:
return
self
.
_dict
[
attr
]
raise
AttributeError
(
"Object has no attribute: {}.{}"
.
format
(
self
.
__class__
.
__name__
,
attr
)
)


def __getitem__(self, name: str) -> Any:
        """Returns the item requested."""
        return self._dict[name]

def __getitem__ ( self , name : str ) -> Any : return self . _dict [ name ]


Returns an iterator of the dictionary items .

def __iter__(self):
        """Returns an iterator of the dictionary items."""
        return self._dict.__iter__()

def __iter__ ( self ) : return self . _dict . __iter__ ( )


Returns the length of the internal dictionary .

def __len__(self) -> int:
        """Returns the length of the internal dictionary."""
        return len(self._dict)

def __len__ ( self ) -> int : return len ( self . _dict )


Constructs a container for basic information about an object .

def __init__(self,
                 layer_name: str,
                 offset: int,
                 member_name: Optional[str] = None,
                 parent: Optional['ObjectInterface'] = None,
                 native_layer_name: Optional[str] = None,
                 size: Optional[int] = None):
        """Constructs a container for basic information about an object.

        Args:
            layer_name: Layer from which the data for the object will be read
            offset: Offset within the layer at which the data for the object will be read
            member_name: If the object was accessed as a member of a parent object, this was the name used to access it
            parent: If the object was accessed as a member of a parent object, this is the parent object
            native_layer_name: If this object references other objects (such as a pointer), what layer those objects live in
            size: The size that the whole structure consumes in bytes
        """
        super().__init__({
            'layer_name': layer_name,
            'offset': offset,
            'member_name': member_name,
            'parent': parent,
            'native_layer_name': native_layer_name or layer_name,
            'size': size
        })

def __init__ ( self , layer_name : str , offset : int , member_name : Optional [ str ] = None , parent : Optional [ 'ObjectInterface' ] = None , native_layer_name : Optional [ str ] = None , size : Optional [ int ] = None ) : super ( ) . __init__ ( { 'layer_name' : layer_name , 'offset' : offset , 'member_name' : member_name , 'parent' : parent , 'native_layer_name' : native_layer_name or layer_name , 'size' : size } )


Constructs an Object adhering to the ObjectInterface .

def __init__(self, context: 'interfaces.context.ContextInterface', type_name: str, object_info: 'ObjectInformation',
                 **kwargs) -> None:
        """Constructs an Object adhering to the ObjectInterface.

        Args:
            context: The context associated with the object
            type_name: The name of the type structure for the object
            object_info: Basic information relevant to the object (layer, offset, member_name, parent, etc)
        """
        # Since objects are likely to be instantiated often,
        # we're reliant on type_checking to ensure correctness of context, offset and parent
        # Everything else may be wrong, but that will get caught later on

        # Add an empty dictionary at the start to allow objects to add their own data to the vol object
        #
        # NOTE:
        # This allows objects to MASSIVELY MESS with their own internal representation!!!
        # Changes to offset, type_name, etc should NEVER be done
        #

        # Normalize offsets
        mask = context.layers[object_info.layer_name].address_mask
        normalized_offset = object_info.offset & mask

        self._vol = collections.ChainMap({}, object_info, {'type_name': type_name, 'offset': normalized_offset}, kwargs)
        self._context = context


Method for ensuring volatility members can be returned .

def __getattr__(self, attr: str) -> Any:
        """Method for ensuring volatility members can be returned."""
        raise AttributeError

def __getattr__ ( self , attr : str ) -> Any : raise AttributeError


Returns the volatility specific object information .

def vol(self) -> ReadOnlyMapping:
        """Returns the volatility specific object information."""
        # Wrap the outgoing vol in a read-only proxy
        return ReadOnlyMapping(self._vol)


Writes the new value into the format at the offset the object currently resides at .

def write(self, value: Any):
        """Writes the new value into the format at the offset the object
        currently resides at."""


Returns the symbol table name for this particular object .

def get_symbol_table_name(self) -> str:
        """Returns the symbol table name for this particular object.

        Raises:
            ValueError: If the object's symbol does not contain an explicit table
            KeyError: If the table_name is not valid within the object's context
        """
        if constants.BANG not in self.vol.type_name:
            raise ValueError("Unable to determine table for symbol: {}".format(self.vol.type_name))
        table_name = self.vol.type_name[:self.vol.type_name.index(constants.BANG)]
        if table_name not in self._context.symbol_space:
            raise KeyError("Symbol table not found in context's symbol_space for symbol: {}".format(self.vol.type_name))
        return table_name


Returns a new object at the offset and from the layer that the current object inhabits .

def cast(self, new_type_name: str, **additional) -> 'ObjectInterface':
        """Returns a new object at the offset and from the layer that the
        current object inhabits.

        .. note:: If new type name does not include a symbol table, the
           symbol table for the current object is used
        """
        # TODO: Carefully consider the implications of casting and how it should work
        if constants.BANG not in new_type_name:
            symbol_table = self.vol['type_name'].split(constants.BANG)[0]
            new_type_name = symbol_table + constants.BANG + new_type_name
        object_template = self._context.symbol_space.get_type(new_type_name)
        object_template = object_template.clone()
        object_template.update_vol(**additional)
        object_info = ObjectInformation(layer_name = self.vol.layer_name,
                                        offset = self.vol.offset,
                                        member_name = self.vol.member_name,
                                        parent = self.vol.parent,
                                        native_layer_name = self.vol.native_layer_name,
                                        size = object_template.size)
        return object_template(context = self._context, object_info = object_info)


Returns whether the object would contain a member called member_name .

def has_member(self, member_name: str) -> bool:
        """Returns whether the object would contain a member called
        member_name.

        Args:
            member_name: Name to test whether a member exists within the type structure
        """
        return False

def has_member ( self , member_name : str ) -> bool : return False


Returns whether the dereferenced type has a valid member .

def has_valid_member(self, member_name: str) -> bool:
        """Returns whether the dereferenced type has a valid member.

        Args:
            member_name: Name of the member to test access to determine if the member is valid or not
        """
        if self.has_member(member_name):
            # noinspection PyBroadException
            try:
                _ = getattr(self, member_name)
                return True
            except Exception:
                pass
        return False

def
has_valid_member
(
self
,
member_name
:
str
)
->
bool
:
if
self
.
has_member
(
member_name
)
:
# noinspection PyBroadException
try
:
_
=
getattr
(
self
,
member_name
)
return
True
except
Exception
:
pass
return
False


def has_valid_members(self, member_names: List[str]) -> bool:
        """Returns whether the object has all of the members listed in member_names

        Args:
            member_names: List of names to test as to members with those names validity
        """
        return all([self.has_valid_member(member_name) for member_name in member_names])

def has_valid_members ( self , member_names : List [ str ] ) -> bool : return all ( [ self . has_valid_member ( member_name ) for member_name in member_names ] )


Stores the keyword arguments for later object creation .

def __init__(self, type_name: str, **arguments) -> None:
        """Stores the keyword arguments for later object creation."""
        # Allow the updating of template arguments whilst still in template form
        super().__init__()
        empty_dict = {}  # type: Dict[str, Any]
        self._vol = collections.ChainMap(empty_dict, arguments, {'type_name': type_name})


Returns a volatility information object much like the : class : ~volatility . framework . interfaces . objects . ObjectInformation provides .

def vol(self) -> ReadOnlyMapping:
        """Returns a volatility information object, much like the
        :class:`~volatility.framework.interfaces.objects.ObjectInformation`
        provides."""
        return ReadOnlyMapping(self._vol)

def vol ( self ) -> ReadOnlyMapping : return ReadOnlyMapping ( self . _vol )


The children of this template ( such as member types sub - types and base - types where they are relevant ) .

def children(self) -> List['Template']:
        """The children of this template (such as member types, sub-types and
        base-types where they are relevant).

        Used to traverse the template tree.
        """
        return []

def children ( self ) -> List [ 'Template' ] : return [ ]


def size(self) -> int:
        """Returns the size of the template."""


Returns the relative offset of the child member from its parent offset .

def relative_child_offset(self, child: str) -> int:
        """Returns the relative offset of the `child` member from its parent
        offset."""

def relative_child_offset ( self , child : str ) -> int :


Replaces old_child with new_child in the list of children .

def replace_child(self, old_child: 'Template', new_child: 'Template') -> None:
        """Replaces `old_child` with `new_child` in the list of children."""

def replace_child ( self , old_child : 'Template' , new_child : 'Template' ) -> None :


Returns whether the object would contain a member called member_name

def has_member(self, member_name: str) -> bool:
        """Returns whether the object would contain a member called
        `member_name`"""

def has_member ( self , member_name : str ) -> bool :


Returns a copy of the original Template as constructed ( without update_vol additions having been made )

def clone(self) -> 'Template':
        """Returns a copy of the original Template as constructed (without
        `update_vol` additions having been made)"""
        clone = self.__class__(**self._vol.parents.new_child())
        return clone

def clone ( self ) -> 'Template' : clone = self . __class__ ( * * self . _vol . parents . new_child ( ) ) return clone


Updates the keyword arguments with values that will ** not ** be carried across to clones .

def update_vol(self, **new_arguments) -> None:
        """Updates the keyword arguments with values that will **not** be
        carried across to clones."""
        self._vol.update(new_arguments)

def update_vol ( self , * * new_arguments ) -> None : self . _vol . update ( new_arguments )


Exposes any other values stored in . _vol as attributes ( for example enumeration choices )

def __getattr__(self, attr: str) -> Any:
        """Exposes any other values stored in ._vol as attributes (for example,
        enumeration choices)"""
        if attr != '_vol':
            if attr in self._vol:
                return self._vol[attr]
        raise AttributeError("{} object has no attribute {}".format(self.__class__.__name__, attr))

def
__getattr__
(
self
,
attr
:
str
)
->
Any
:
if
attr
!=
'_vol'
:
if
attr
in
self
.
_vol
:
return
self
.
_vol
[
attr
]
raise
AttributeError
(
"{} object has no attribute {}"
.
format
(
self
.
__class__
.
__name__
,
attr
)
)


def __call__(self, context: 'interfaces.context.ContextInterface',
                 object_info: ObjectInformation) -> ObjectInterface:
        """Constructs the object."""

def __call__ ( self , context : 'interfaces.context.ContextInterface' , object_info : ObjectInformation ) -> ObjectInterface :


def path_join(*args) -> str:
    """Joins configuration paths together."""
    # If a path element (particularly the first) is empty, then remove it from the list
    args = tuple([arg for arg in args if arg])
    return CONFIG_SEPARATOR.join(args)


Returns the parent configuration path from a configuration path .

def parent_path(value: str) -> str:
    """Returns the parent configuration path from a configuration path."""
    return CONFIG_SEPARATOR.join(value.split(CONFIG_SEPARATOR)[:-1])

def parent_path ( value : str ) -> str : return CONFIG_SEPARATOR . join ( value . split ( CONFIG_SEPARATOR ) [ : - 1 ] )


def path_head(value: str) -> str:
    """Return the top of the configuration path"""
    return value.split(CONFIG_SEPARATOR)[-1]

def path_head ( value : str ) -> str : return value . split ( CONFIG_SEPARATOR ) [ - 1 ]


Returns the path up to a certain depth .

def path_depth(path: str, depth: int = 1) -> str:
    """Returns the `path` up to a certain depth.

    Note that `depth` can be negative (such as `-x`) and will return all
    elements except for the last `x` components
    """
    return path_join(path.split(CONFIG_SEPARATOR)[:depth])

def path_depth ( path : str , depth : int = 1 ) -> str : return path_join ( path . split ( CONFIG_SEPARATOR ) [ : depth ] )


Args : initial_dict : A dictionary to populate the HierachicalDict with initially separator : A custom hierarchy separator ( defaults to CONFIG_SEPARATOR )

def __init__(self,
                 initial_dict: Dict[str, 'SimpleTypeRequirement'] = None,
                 separator: str = CONFIG_SEPARATOR) -> None:
        """
        Args:
            initial_dict: A dictionary to populate the HierachicalDict with initially
            separator: A custom hierarchy separator (defaults to CONFIG_SEPARATOR)
        """
        if not (isinstance(separator, str) and len(separator) == 1):
            raise TypeError("Separator must be a one character string: {}".format(separator))
        self._separator = separator
        self._data = {}  # type: Dict[str, ConfigSimpleType]
        self._subdict = {}  # type: Dict[str, 'HierarchicalDict']
        if isinstance(initial_dict, str):
            initial_dict = json.loads(initial_dict)
        if isinstance(initial_dict, dict):
            for k, v in initial_dict.items():
                self[k] = v
        elif initial_dict is not None:
            raise TypeError(
                "Initial_dict must be a dictionary or JSON string containing a dictionary: {}".format(initial_dict))


def __eq__(self, other):
        """Define equality between HierarchicalDicts"""
        return dict(self) == dict(other)

def __eq__ ( self , other ) : return dict ( self ) == dict ( other )


Specifies the hierarchy separator in use in this HierarchyDict .

def separator(self) -> str:
        """Specifies the hierarchy separator in use in this HierarchyDict."""
        return self._separator

def separator ( self ) -> str : return self . _separator


Returns just the data - containing mappings on this level of the Hierarchy .

def data(self) -> Dict:
        """Returns just the data-containing mappings on this level of the
        Hierarchy."""
        return self._data.copy()

def data ( self ) -> Dict : return self . _data . copy ( )


Returns the first division of a key based on the dict separator or the full key if the separator is not present .

def _key_head(self, key: str) -> str:
        """Returns the first division of a key based on the dict separator, or
        the full key if the separator is not present."""
        if self.separator in key:
            return key[:key.index(self.separator)]
        else:
            return key

def _key_head ( self , key : str ) -> str : if self . separator in key : return key [ : key . index ( self . separator ) ] else : return key


Returns all but the first division of a key based on the dict separator or None if the separator is not in the key .

def _key_tail(self, key: str) -> str:
        """Returns all but the first division of a key based on the dict
        separator, or None if the separator is not in the key."""
        if self.separator in key:
            return key[key.index(self.separator) + 1:]
        return ''

def _key_tail ( self , key : str ) -> str : if self . separator in key : return key [ key . index ( self . separator ) + 1 : ] return ''


Returns an iterator object that supports the iterator protocol .

def __iter__(self):
        """Returns an iterator object that supports the iterator protocol."""
        return self.generator()

def __iter__ ( self ) : return self . generator ( )


A generator for the data in this level and lower levels of this mapping .

def generator(self) -> Generator[str, None, None]:
        """A generator for the data in this level and lower levels of this
        mapping.

        Returns:
            Returns each item in the top level data, and then all subkeys in a depth first order
        """
        for key in self._data:
            yield key
        for subdict_key in self._subdict:
            for key in self._subdict[subdict_key]:
                yield subdict_key + self.separator + key

def generator ( self ) -> Generator [ str , None , None ] : for key in self . _data : yield key for subdict_key in self . _subdict : for key in self . _subdict [ subdict_key ] : yield subdict_key + self . separator + key


Gets an item traversing down the trees to get to the final value .

def __getitem__(self, key):
        """Gets an item, traversing down the trees to get to the final
        value."""
        try:
            if self.separator in key:
                subdict = self._subdict[self._key_head(key)]
                return subdict[self._key_tail(key)]
            else:
                return self._data[key]
        except KeyError:
            raise KeyError(key)

def __getitem__ ( self , key ) : try : if self . separator in key : subdict = self . _subdict [ self . _key_head ( key ) ] return subdict [ self . _key_tail ( key ) ] else : return self . _data [ key ] except KeyError : raise KeyError ( key )


Sets an item or creates a subdict and sets the item within that .

def __setitem__(self, key: str, value: Any) -> None:
        """Sets an item or creates a subdict and sets the item within that."""
        self._setitem(key, value)

def __setitem__ ( self , key : str , value : Any ) -> None : self . _setitem ( key , value )


Set an item or appends a whole subtree at a key location .

def _setitem(self, key: str, value: Any, is_data: bool = True) -> None:
        """Set an item or appends a whole subtree at a key location."""
        if self.separator in key:
            subdict = self._subdict.get(self._key_head(key), HierarchicalDict(separator = self.separator))
            subdict._setitem(self._key_tail(key), value, is_data)
            self._subdict[self._key_head(key)] = subdict
        else:
            if is_data:
                self._data[key] = self._sanitize_value(value)
            else:
                if not isinstance(value, HierarchicalDict):
                    raise TypeError(
                        "HierarchicalDicts can only store HierarchicalDicts within their structure: {}".format(
                            type(value)))
                self._subdict[key] = value


Method to ensure all values are standard values and not volatility objects containing contexts .

def _sanitize_value(self, value: Any) -> ConfigSimpleType:
        """Method to ensure all values are standard values and not volatility
        objects containing contexts."""
        if isinstance(value, bool):
            return bool(value)
        elif isinstance(value, int):
            return int(value)
        elif isinstance(value, str):
            return str(value)
        elif isinstance(value, bytes):
            return bytes(value)
        elif isinstance(value, list):
            new_list = []
            for element in value:
                element_value = self._sanitize_value(element)
                if isinstance(element_value, list):
                    raise TypeError("Configuration list types cannot contain list types")
                new_list.append(element_value)
            return new_list
        elif value is None:
            return None
        else:
            raise TypeError("Invalid type stored in configuration")


Deletes an item from the hierarchical dict .

def __delitem__(self, key: str) -> None:
        """Deletes an item from the hierarchical dict."""
        try:
            if self.separator in key:
                subdict = self._subdict[self._key_head(key)]
                del subdict[self._key_tail(key)]
            else:
                del self._data[self._key_head(key)]
        except KeyError:
            raise KeyError(key)

def __delitem__ ( self , key : str ) -> None : try : if self . separator in key : subdict = self . _subdict [ self . _key_head ( key ) ] del subdict [ self . _key_tail ( key ) ] else : del self . _data [ self . _key_head ( key ) ] except KeyError : raise KeyError ( key )


Determines whether the key is present in the hierarchy .

def __contains__(self, key: Any) -> bool:
        """Determines whether the key is present in the hierarchy."""
        if self.separator in key:
            try:
                subdict = self._subdict[self._key_head(key)]
                return self._key_tail(key) in subdict
            except KeyError:
                return False
        else:
            return key in self._data

def __contains__ ( self , key : Any ) -> bool : if self . separator in key : try : subdict = self . _subdict [ self . _key_head ( key ) ] return self . _key_tail ( key ) in subdict except KeyError : return False else : return key in self . _data


def __len__(self) -> int:
        """Returns the length of all items."""
        return len(self._data) + sum([len(subdict) for subdict in self._subdict])

def __len__ ( self ) -> int : return len ( self . _data ) + sum ( [ len ( subdict ) for subdict in self . _subdict ] )


Returns the HierarchicalDict housed under the key .

def branch(self, key: str) -> 'HierarchicalDict':
        """Returns the HierarchicalDict housed under the key.

        This differs from the data property, in that it is directed by the `key`, and all layers under that key are
        returned, not just those in that level.

        Higher layers are not prefixed with the location of earlier layers, so branching a hierarchy containing `a.b.c.d`
        on `a.b` would return a hierarchy containing `c.d`, not `a.b.c.d`.

        Args:
            key: The location within the hierarchy to return higher layers.

        Returns:
            The HierarchicalDict underneath the specified key (not just the data at that key location in the tree)
        """
        try:
            if self.separator in key:
                return self._subdict[self._key_head(key)].branch(self._key_tail(key))
            else:
                return self._subdict[key]
        except KeyError:
            self._setitem(key = key, value = HierarchicalDict(separator = self.separator), is_data = False)
        return HierarchicalDict()

def branch ( self , key : str ) -> 'HierarchicalDict' : try : if self . separator in key : return self . _subdict [ self . _key_head ( key ) ] . branch ( self . _key_tail ( key ) ) else : return self . _subdict [ key ] except KeyError : self . _setitem ( key = key , value = HierarchicalDict ( separator = self . separator ) , is_data = False ) return HierarchicalDict ( )


Splices an existing HierarchicalDictionary under a specific key .

def splice(self, key: str, value: 'HierarchicalDict') -> None:
        """Splices an existing HierarchicalDictionary under a specific key.

        This can be thought of as an inverse of :func:`branch`, although
        `branch` does not remove the requested hierarchy, it simply
        returns it.
        """
        if not isinstance(key, str) or not isinstance(value, HierarchicalDict):
            raise TypeError("Splice requires a string key and HierarchicalDict value")
        self._setitem(key, value, False)


Acts similarly to splice but maintains previous values .

def merge(self, key: str, value: 'HierarchicalDict', overwrite: bool = False) -> None:
        """Acts similarly to splice, but maintains previous values.

        If overwrite is true, then entries in the new value are used over those that exist within key already

        Args:
            key: The location within the hierarchy at which to merge the `value`
            value: HierarchicalDict to be merged under the key node
            overwrite: A boolean defining whether the value will be overwritten if it already exists
        """
        if not isinstance(key, str) or not isinstance(value, HierarchicalDict):
            raise TypeError("Splice requires a string key and HierarchicalDict value")
        for item in dict(value):
            if self.get(key + self._separator + item, None) is not None:
                if overwrite:
                    self[key + self._separator + item] = value[item]
            else:
                self[key + self._separator + item] = value[item]


Duplicates the configuration allowing changes without affecting the original .

def clone(self) -> 'HierarchicalDict':
        """Duplicates the configuration, allowing changes without affecting the
        original.

        Returns:
            A duplicate HierarchicalDict of this object
        """
        return copy.deepcopy(self)

def clone ( self ) -> 'HierarchicalDict' : return copy . deepcopy ( self )


Turns the Hierarchical dict into a string representation .

def __str__(self) -> str:
        """Turns the Hierarchical dict into a string representation."""
        return json.dumps(dict([(key, self[key]) for key in sorted(self.generator())]), indent = 2)

def __str__ ( self ) -> str : return json . dumps ( dict ( [ ( key , self [ key ] ) for key in sorted ( self . generator ( ) ) ] ) , indent = 2 )


def __init__(self,
                 name: str,
                 description: str = None,
                 default: ConfigSimpleType = None,
                 optional: bool = False) -> None:
        """

        Args:
            name: The name of the requirement
            description: A short textual description of the requirement
            default: The default value for the requirement if no value is provided
            optional: Whether the requirement must be satisfied or not
        """
        super().__init__()
        if CONFIG_SEPARATOR in name:
            raise ValueError("Name cannot contain the config-hierarchy divider ({})".format(CONFIG_SEPARATOR))
        self._name = name
        self._description = description or ""
        self._default = default
        self._optional = optional
        self._requirements = {}


def name(self) -> str:
        """The name of the Requirement.

        Names cannot contain CONFIG_SEPARATOR ('.' by default) since
        this is used within the configuration hierarchy.
        """
        return self._name

def name ( self ) -> str : return self . _name


A short description of what the Requirement is designed to affect or achieve .

def description(self) -> str:
        """A short description of what the Requirement is designed to affect or
        achieve."""
        return self._description

def description ( self ) -> str : return self . _description


Returns the default value if one is set .

def default(self) -> ConfigSimpleType:
        """Returns the default value if one is set."""
        return self._default

def default ( self ) -> ConfigSimpleType : return self . _default


Whether the Requirement is optional or not .

def optional(self) -> bool:
        """Whether the Requirement is optional or not."""
        return self._optional

def optional ( self ) -> bool : return self . _optional


Sets the optional value for a requirement .

def optional(self, value) -> None:
        """Sets the optional value for a requirement."""
        self._optional = bool(value)

def optional ( self , value ) -> None : self . _optional = bool ( value )


Returns the value for this Requirement from its config path .

def config_value(self,
                     context: 'interfaces.context.ContextInterface',
                     config_path: str,
                     default: ConfigSimpleType = None) -> ConfigSimpleType:
        """Returns the value for this Requirement from its config path.

        Args:
            context: the configuration store to find the value for this requirement
            config_path: the configuration path of the instance of the requirement to be recovered
            default: a default value to provide if the requirement's configuration value is not found
        """
        return context.config.get(config_path, default)

def config_value ( self , context : 'interfaces.context.ContextInterface' , config_path : str , default : ConfigSimpleType = None ) -> ConfigSimpleType : return context . config . get ( config_path , default )


Returns a dictionary of all the child requirements indexed by name .

def requirements(self) -> Dict[str, 'RequirementInterface']:
        """Returns a dictionary of all the child requirements, indexed by
        name."""
        return self._requirements.copy()

def requirements ( self ) -> Dict [ str , 'RequirementInterface' ] : return self . _requirements . copy ( )


Adds a child to the list of requirements .

def add_requirement(self, requirement: 'RequirementInterface') -> None:
        """Adds a child to the list of requirements.

        Args:
            requirement: The requirement to add as a child-requirement
        """
        self._requirements[requirement.name] = requirement

def add_requirement ( self , requirement : 'RequirementInterface' ) -> None : self . _requirements [ requirement . name ] = requirement


Removes a child from the list of requirements .

def remove_requirement(self, requirement: 'RequirementInterface') -> None:
        """Removes a child from the list of requirements.

        Args:
            requirement: The requirement to remove as a child-requirement
        """
        del self._requirements[requirement.name]

def remove_requirement ( self , requirement : 'RequirementInterface' ) -> None : del self . _requirements [ requirement . name ]


Method that will validate all child requirements .

def unsatisfied_children(self, context: 'interfaces.context.ContextInterface',
                             config_path: str) -> Dict[str, 'RequirementInterface']:
        """Method that will validate all child requirements.

        Args:
            context: the context containing the configuration data for this requirement
            config_path: the configuration path of this instance of the requirement

        Returns:
            A dictionary of full configuration paths for each unsatisfied child-requirement
        """
        result = {}
        for requirement in self.requirements.values():
            if not requirement.optional:
                subresult = requirement.unsatisfied(context, path_join(config_path, self._name))
                result.update(subresult)
        return result

def unsatisfied_children ( self , context : 'interfaces.context.ContextInterface' , config_path : str ) -> Dict [ str , 'RequirementInterface' ] : result = { } for requirement in self . requirements . values ( ) : if not requirement . optional : subresult = requirement . unsatisfied ( context , path_join ( config_path , self . _name ) ) result . update ( subresult ) return result


Method to validate the value stored at config_path for the configuration object against a context .

def unsatisfied(self, context: 'interfaces.context.ContextInterface',
                    config_path: str) -> Dict[str, 'RequirementInterface']:
        """Method to validate the value stored at config_path for the
        configuration object against a context.

        Returns a list containing its own name (or multiple unsatisfied requirement names) when invalid

        Args:
            context: The context object containing the configuration for this requirement
            config_path: The configuration path for this requirement to test satisfaction

        Returns:
            A dictionary of configuration-paths to requirements that could not be satisfied
        """

def unsatisfied ( self , context : 'interfaces.context.ContextInterface' , config_path : str ) -> Dict [ str , 'RequirementInterface' ] :


Always raises a TypeError as instance requirements cannot have children .

def add_requirement(self, requirement: RequirementInterface):
        """Always raises a TypeError as instance requirements cannot have
        children."""
        raise TypeError("Instance Requirements cannot have subrequirements")


def remove_requirement(self, requirement: RequirementInterface):
        """Always raises a TypeError as instance requirements cannot have
        children."""
        raise TypeError("Instance Requirements cannot have subrequirements")


Validates the instance requirement based upon its instance_type .

def unsatisfied(self, context: 'interfaces.context.ContextInterface',
                    config_path: str) -> Dict[str, RequirementInterface]:
        """Validates the instance requirement based upon its
        `instance_type`."""
        config_path = path_join(config_path, self.name)

        value = self.config_value(context, config_path, None)
        if not isinstance(value, self.instance_type):
            vollog.log(
                constants.LOGLEVEL_V,
                "TypeError - {} requirements only accept {} type: {}".format(self.name, self.instance_type.__name__,
                                                                             repr(value)))
            return {config_path: self}
        return {}


Contains the actual chosen class based on the configuration value s class name .

def cls(self) -> Type:
        """Contains the actual chosen class based on the configuration value's
        class name."""
        return self._cls

def cls ( self ) -> Type : return self . _cls


Checks to see if a class can be recovered .

def unsatisfied(self, context: 'interfaces.context.ContextInterface',
                    config_path: str) -> Dict[str, RequirementInterface]:
        """Checks to see if a class can be recovered."""
        config_path = path_join(config_path, self.name)

        value = self.config_value(context, config_path, None)
        self._cls = None
        if value is not None and isinstance(value, str):
            if "." in value:
                # TODO: consider importing the prefix
                module = sys.modules.get(value[:value.rindex(".")], None)
                class_name = value[value.rindex(".") + 1:]
                if hasattr(module, class_name):
                    self._cls = getattr(module, class_name)
            else:
                if value in globals():
                    self._cls = globals()[value]
        if self._cls is None:
            return {config_path: self}
        return {}

def
unsatisfied
(
self
,
context
:
'interfaces.context.ContextInterface'
,
config_path
:
str
)
->
Dict
[
str
,
RequirementInterface
]
:
config_path
=
path_join
(
config_path
,
self
.
name
)
value
=
self
.
config_value
(
context
,
config_path
,
)
self
.
_cls
=
if
value
is
not
and
isinstance
(
value
,
str
)
:
if
"."
in
value
:
# TODO: consider importing the prefix
module
=
sys
.
modules
.
get
(
value
[
:
value
.
rindex
(
"."
)
]
,
)
class_name
=
value
[
value
.
rindex
(
"."
)
+
1
:
]
if
hasattr
(
module
,
class_name
)
:
self
.
_cls
=
getattr
(
module
,
class_name
)
else
:
if
value
in
globals
(
)
:
self
.
_cls
=
globals
(
)
[
value
]
if
self
.
_cls
is
:
return
{
config_path
:
self
}
return
{
}


Method for constructing within the context any required elements from subrequirements .

def construct(self, context: 'interfaces.context.ContextInterface', config_path: str) -> None:
        """Method for constructing within the context any required elements
        from subrequirements.

        Args:
            context: The context object containing the configuration data for the constructable
            config_path: The configuration path for the specific instance of this constructable
        """

def construct ( self , context : 'interfaces.context.ContextInterface' , config_path : str ) -> None :


Method to check if the class Requirement is valid and if so populate the other requirements ( but no need to validate since we re invalid already )

def _validate_class(self, context: 'interfaces.context.ContextInterface', config_path: str) -> None:
        """Method to check if the class Requirement is valid and if so populate
        the other requirements (but no need to validate, since we're invalid
        already)

        Args:
             context: The context object containing the configuration data for the constructable
             config_path: The configuration path for the specific instance of this constructable
        """
        class_req = self.requirements['class']
        subreq_config_path = path_join(config_path, self.name)
        if not class_req.unsatisfied(context, subreq_config_path) and isinstance(class_req, ClassRequirement):
            # We have a class, and since it's validated we can construct our requirements from it
            if issubclass(class_req.cls, ConfigurableInterface):
                # In case the class has changed, clear out the old requirements
                for old_req in self._current_class_requirements.copy():
                    del self._requirements[old_req]
                    self._current_class_requirements.remove(old_req)
                # And add the new ones
                for requirement in class_req.cls.get_requirements():
                    self._current_class_requirements.add(requirement.name)
                    self.add_requirement(requirement)


Constructs the class handing args and the subrequirements as parameters to __init__

def _construct_class(self,
                         context: 'interfaces.context.ContextInterface',
                         config_path: str,
                         requirement_dict: Dict[str, object] = None) -> Optional['interfaces.objects.ObjectInterface']:
        """Constructs the class, handing args and the subrequirements as
        parameters to __init__"""
        if self.requirements["class"].unsatisfied(context, config_path):
            return None

        if not isinstance(self.requirements["class"], ClassRequirement):
            return None
        cls = self.requirements["class"].cls

        # These classes all have a name property
        # We could subclass this out as a NameableInterface, but it seems a little excessive
        # FIXME: We can't test this, because importing the other interfaces causes all kinds of import loops
        # if not issubclass(cls, [interfaces.layers.TranslationLayerInterface,
        #                         interfaces.symbols.SymbolTableInterface]):
        #     return None

        if requirement_dict is None:
            requirement_dict = {}

        # Fulfillment must happen, exceptions happening here mean the requirements aren't correct
        # and these need to be raised and fixed, rather than caught and ignored
        obj = cls(**requirement_dict)
        context.config[config_path] = obj.name
        return obj


Proxies to a ConfigurableInterface if necessary .

def build_configuration(self, context: 'interfaces.context.ContextInterface', config_path: str,
                            value: Any) -> HierarchicalDict:
        """Proxies to a ConfigurableInterface if necessary."""

def build_configuration ( self , context : 'interfaces.context.ContextInterface' , config_path : str , value : Any ) -> HierarchicalDict :


Basic initializer that allows configurables to access their own config settings .

def __init__(self, context: 'interfaces.context.ContextInterface', config_path: str) -> None:
        """Basic initializer that allows configurables to access their own
        config settings."""
        super().__init__()
        self._context = context
        self._config_path = config_path
        self._config_cache = None

def __init__ ( self , context : 'interfaces.context.ContextInterface' , config_path : str ) -> None : super ( ) . __init__ ( ) self . _context = context self . _config_path = config_path self . _config_cache = None


The context object that this configurable belongs to / configuration is stored in .

def context(self) -> 'interfaces.context.ContextInterface':
        """The context object that this configurable belongs to/configuration
        is stored in."""
        return self._context

def context ( self ) -> 'interfaces.context.ContextInterface' : return self . _context


The configuration path on which this configurable lives .

def config_path(self) -> str:
        """The configuration path on which this configurable lives."""
        return self._config_path

def config_path ( self ) -> str : return self . _config_path


def config_path(self, value: str) -> None:
        """The configuration path on which this configurable lives."""
        self._config_path = value
        self._config_cache = None

def config_path ( self , value : str ) -> None : self . _config_path = value self . _config_cache = None


The Hierarchical configuration Dictionary for this Configurable object .

def config(self) -> HierarchicalDict:
        """The Hierarchical configuration Dictionary for this Configurable
        object."""
        if not hasattr(self, "_config_cache") or self._config_cache is None:
            self._config_cache = self._context.config.branch(self._config_path)
        return self._config_cache

def config ( self ) -> HierarchicalDict : if not hasattr ( self , "_config_cache" ) or self . _config_cache is None : self . _config_cache = self . _context . config . branch ( self . _config_path ) return self . _config_cache


Constructs a HierarchicalDictionary of all the options required to build this component in the current context .

def build_configuration(self) -> HierarchicalDict:
        """Constructs a HierarchicalDictionary of all the options required to
        build this component in the current context.

        Ensures that if the class has been created, it can be recreated
        using the configuration built Inheriting classes must override
        this to ensure any dependent classes update their configurations
        too
        """
        result = HierarchicalDict()
        for req in self.get_requirements():
            value = self.config.get(req.name, None)
            # Do not include the name of constructed classes
            if value is not None and not isinstance(req, ConstructableRequirementInterface):
                result[req.name] = value
            if isinstance(req, ConfigurableRequirementInterface):
                if value is not None:
                    result.splice(req.name, req.build_configuration(self.context, self.config_path, value))
        return result


Returns a list of RequirementInterface objects required by this object .

def get_requirements(cls) -> List[RequirementInterface]:
        """Returns a list of RequirementInterface objects required by this
        object."""
        return []

def get_requirements ( cls ) -> List [ RequirementInterface ] : return [ ]


Returns a list of the names of all unsatisfied requirements .

def unsatisfied(cls, context: 'interfaces.context.ContextInterface',
                    config_path: str) -> Dict[str, RequirementInterface]:
        """Returns a list of the names of all unsatisfied requirements.

        Since a satisfied set of requirements will return [], it can be used in tests as follows:

        .. code-block:: python

            unmet = configurable.unsatisfied(context, config_path)
            if unmet:
                raise RuntimeError("Unsatisfied requirements: {}".format(unmet)
        """
        result = {}
        for requirement in cls.get_requirements():
            if not requirement.optional:
                subresult = requirement.unsatisfied(context, config_path)
                result.update(subresult)
        return result

def unsatisfied ( cls , context : 'interfaces.context.ContextInterface' , config_path : str ) -> Dict [ str , RequirementInterface ] : result = { } for requirement in cls . get_requirements ( ) : if not requirement . optional : subresult = requirement . unsatisfied ( context , config_path ) result . update ( subresult ) return result


Convenience function to allow constructing a new randomly generated sub - configuration path containing each element from kwargs .

def make_subconfig(cls, context: 'interfaces.context.ContextInterface', base_config_path: str, **kwargs) -> str:
        """Convenience function to allow constructing a new randomly generated
        sub-configuration path, containing each element from kwargs.

        Args:
            context: The context in which to store the new configuration
            base_config_path: The base configuration path on which to build the new configuration
            kwargs: Keyword arguments that are used to populate the new configuration path

        Returns:
            str: The newly generated full configuration path
        """
        random_config_dict = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits)
                                     for _ in range(8))
        new_config_path = path_join(base_config_path, random_config_dict)
        # TODO: Check that the new_config_path is empty, although it's not critical if it's not since the values are merged in

        # This should check that each k corresponds to a requirement and each v is of the appropriate type
        # This would require knowledge of the new configurable itself to verify, and they should do validation in the
        # constructor anyway, however, to prevent bad types getting into the config tree we just verify that v is a simple type
        for k, v in kwargs.items():
            if not isinstance(v, (int, str, bool, float, bytes)):
                raise TypeError("Config values passed to make_subconfig can only be simple types")
            context.config[path_join(new_config_path, k)] = v

        return new_config_path


The version of the current interface ( classmethods available on the component ) .

def version(cls) -> Tuple[int, int, int]:
        """The version of the current interface (classmethods available on the component).

        It is strongly recommended that Semantic Versioning be used (and the default version verification is defined that way):

            MAJOR version when you make incompatible API changes.
            MINOR version when you add functionality in a backwards compatible manner.
            PATCH version when you make backwards compatible bug fixes.
        """
        return cls._version

def version ( cls ) -> Tuple [ int , int , int ] : return cls . _version


Runs the automagic over the configurable .

def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback: constants.ProgressCallback = None) -> Optional[List[Any]]:
        """Runs the automagic over the configurable."""
        return []

def __call__ ( self , context : interfaces . context . ContextInterface , config_path : str , requirement : interfaces . configuration . RequirementInterface , progress_callback : constants . ProgressCallback = None ) -> Optional [ List [ Any ] ] : return [ ]


Determines if there is actually an unfulfilled Requirement waiting .

def find_requirements(self,
                          context: interfaces.context.ContextInterface,
                          config_path: str,
                          requirement_root: interfaces.configuration.RequirementInterface,
                          requirement_type: Union[Tuple[Type[interfaces.configuration.RequirementInterface], ...],
                                                  Type[interfaces.configuration.RequirementInterface]],
                          shortcut: bool = True) -> List[Tuple[str, interfaces.configuration.RequirementInterface]]:
        """Determines if there is actually an unfulfilled `Requirement`
        waiting.

        This ensures we do not carry out an expensive search when there is no need for a particular `Requirement`

        Args:
            context: Context on which to operate
            config_path: Configuration path of the top-level requirement
            requirement_root: Top-level requirement whose subrequirements will all be searched
            requirement_type: Type of requirement to find
            shortcut: Only returns requirements that live under unsatisfied requirements

        Returns:
            A list of tuples containing the config_path, sub_config_path and requirement identifying the unsatisfied `Requirements`
        """
        sub_config_path = interfaces.configuration.path_join(config_path, requirement_root.name)
        results = []  # type: List[Tuple[str, interfaces.configuration.RequirementInterface]]
        recurse = not shortcut
        if isinstance(requirement_root, requirement_type):
            if recurse or requirement_root.unsatisfied(context, config_path):
                results.append((sub_config_path, requirement_root))
        else:
            recurse = True
        if recurse:
            for subreq in requirement_root.requirements.values():
                results += self.find_requirements(context, sub_config_path, subreq, requirement_type, shortcut)
        return results


Method to determine whether this builder can operate on the named layer . If so modify the context appropriately .

def stack(self,
              context: interfaces.context.ContextInterface,
              layer_name: str,
              progress_callback: constants.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]:
        """Method to determine whether this builder can operate on the named
        layer.  If so, modify the context appropriately.

        Returns the name of any new layer stacked on top of this layer or None.  The stacking is therefore strictly
        linear rather than tree driven.

        Configuration options provided by the context are ignored, and defaults are to be used by this method
        to build a space where possible.

        Args:
           context: Context in which to construct the higher layer
           layer_name: Name of the layer to stack on top of
           progress_callback: A callback function to indicate progress through a scan (if one is necessary)
        """

def stack ( self , context : interfaces . context . ContextInterface , layer_name : str , progress_callback : constants . ProgressCallback = None ) -> Optional [ interfaces . layers . DataLayerInterface ] :


Stores the context locally in case the scanner needs to access the layer .

def context(self, ctx: 'interfaces.context.ContextInterface') -> None:
        """Stores the context locally in case the scanner needs to access the
        layer."""
        self._context = ctx

def context ( self , ctx : 'interfaces.context.ContextInterface' ) -> None : self . _context = ctx


Stores the layer_name being scanned locally in case the scanner needs to access the layer .

def layer_name(self, layer_name: str) -> None:
        """Stores the layer_name being scanned locally in case the scanner
        needs to access the layer."""
        self._layer_name = layer_name

def layer_name ( self , layer_name : str ) -> None : self . _layer_name = layer_name


Searches through a chunk of data for a particular value / pattern / etc Always returns an iterator of the same type of object ( need not be a volatility object )

def __call__(self, data: bytes, data_offset: int) -> Iterable[Any]:
        """Searches through a chunk of data for a particular value/pattern/etc
        Always returns an iterator of the same type of object (need not be a
        volatility object)

        data is the chunk of data to search through data_offset is the
        offset within the layer that the data being searched starts at
        """

def __call__ ( self , data : bytes , data_offset : int ) -> Iterable [ Any ] :


def name(self) -> str:
        """Returns the layer name."""
        return self._name

def name ( self ) -> str : return self . _name


Returns the maximum valid address of the space .

def maximum_address(self) -> int:
        """Returns the maximum valid address of the space."""


Returns the minimum valid address of the space .

def minimum_address(self) -> int:
        """Returns the minimum valid address of the space."""


Returns a mask which encapsulates all the active bits of an address for this layer .

def address_mask(self) -> int:
        """Returns a mask which encapsulates all the active bits of an address
        for this layer."""
        return (1 << int(math.ceil(math.log2(self.maximum_address)))) - 1

def address_mask ( self ) -> int : return ( 1 << int ( math . ceil ( math . log2 ( self . maximum_address ) ) ) ) - 1


Returns a boolean based on whether the entire chunk of data ( from offset to length ) is valid or not .

def is_valid(self, offset: int, length: int = 1) -> bool:
        """Returns a boolean based on whether the entire chunk of data (from
        offset to length) is valid or not.

        Args:
            offset: The address to start determining whether bytes are readable/valid
            length: The number of bytes from offset of which to test the validity

        Returns:
             Whether the bytes are valid and accessible
        """

def is_valid ( self , offset : int , length : int = 1 ) -> bool :


Reads an offset for length bytes and returns bytes ( not str ) of length size .

def read(self, offset: int, length: int, pad: bool = False) -> bytes:
        """Reads an offset for length bytes and returns 'bytes' (not 'str') of
        length size.

        If there is a fault of any kind (such as a page fault), an exception will be thrown
        unless pad is set, in which case the read errors will be replaced by null characters.

        Args:
            offset: The offset at which to being reading within the layer
            length: The number of bytes to read within the layer
            pad: A boolean indicating whether exceptions should be raised or bad bytes replaced with null characters

        Returns:
            The bytes read from the layer, starting at offset for length bytes
        """

def read ( self , offset : int , length : int , pad : bool = False ) -> bytes :


def write(self, offset: int, data: bytes) -> None:
        """Writes a chunk of data at offset.

        Any unavailable sections in the underlying bases will cause an exception to be thrown.
        Note: Writes are not guaranteed atomic, therefore some data may have been written, even if an exception is thrown.
        """

def write ( self , offset : int , data : bytes ) -> None :


Causes a DataLayer to close any open handles etc .

def destroy(self) -> None:
        """Causes a DataLayer to close any open handles, etc.

        Systems that make use of Data Layers should call destroy when
        they are done with them. This will close all handles, and make
        the object unreadable (exceptions will be thrown using a
        DataLayer after destruction)
        """
        pass


Returns a list of Requirement objects for this type of layer .

def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
        """Returns a list of Requirement objects for this type of layer."""
        return super().get_requirements()

def get_requirements ( cls ) -> List [ interfaces . configuration . RequirementInterface ] : return super ( ) . get_requirements ( )


A list of other layer names required by this layer .

def dependencies(self) -> List[str]:
        """A list of other layer names required by this layer.

        Note:
            DataLayers must never define other layers
        """
        return []

def dependencies ( self ) -> List [ str ] : return [ ]


def scan(self,
             context: interfaces.context.ContextInterface,
             scanner: ScannerInterface,
             progress_callback: constants.ProgressCallback = None,
             sections: Iterable[Tuple[int, int]] = None) -> Iterable[Any]:
        """Scans a Translation layer by chunk.

        Note: this will skip missing/unmappable chunks of memory

        Args:
             context: The context containing the data layer
             scanner: The constructed Scanner object to be applied
             progress_callback: Method that is called periodically during scanning to update progress
             sections: A list of (start, size) tuples defining the portions of the layer to scan

        Returns:
             The output iterable from the scanner object having been run against the layer
        """
        if progress_callback is not None and not callable(progress_callback):
            raise TypeError("Progress_callback is not callable")

        scanner.context = context
        scanner.layer_name = self.name

        if sections is None:
            sections = [(self.minimum_address, self.maximum_address - self.minimum_address)]

        sections = list(self._coalesce_sections(sections))

        try:
            progress = DummyProgress()  # type: ProgressValue
            scan_iterator = functools.partial(self._scan_iterator, scanner, sections)
            scan_metric = self._scan_metric(scanner, sections)
            if not scanner.thread_safe or constants.PARALLELISM == constants.Parallelism.Off:
                progress = DummyProgress()
                scan_chunk = functools.partial(self._scan_chunk, scanner, progress)
                for value in scan_iterator():
                    if progress_callback:
                        progress_callback(scan_metric(progress.value),
                                          "Scanning {} using {}".format(self.name, scanner.__class__.__name__))
                    yield from scan_chunk(value)
            else:
                progress = multiprocessing.Manager().Value("Q", 0)
                parallel_module = multiprocessing  # type: types.ModuleType
                if constants.PARALLELISM == constants.Parallelism.Threading:
                    progress = DummyProgress()
                    parallel_module = threading
                scan_chunk = functools.partial(self._scan_chunk, scanner, progress)
                with parallel_module.Pool() as pool:
                    result = pool.map_async(scan_chunk, scan_iterator())
                    while not result.ready():
                        if progress_callback:
                            # Run the progress_callback
                            progress_callback(scan_metric(progress.value),
                                              "Scanning {} using {}".format(self.name, scanner.__class__.__name__))
                        # Ensures we don't burn CPU cycles going round in a ready waiting loop
                        # without delaying the user too long between progress updates/results
                        result.wait(0.1)
                    for result_value in result.get():
                        yield from result_value
        except Exception as e:
            # We don't care the kind of exception, so catch and report on everything, yielding nothing further
            vollog.debug("Scan Failure: {}".format(str(e)))
            vollog.log(constants.LOGLEVEL_VVV,
                       "\n".join(traceback.TracebackException.from_exception(e).format(chain = True)))


Take a list of ( start length ) sections and coalesce any adjacent sections .

def _coalesce_sections(self, sections: Iterable[Tuple[int, int]]) -> Iterable[Tuple[int, int]]:
        """Take a list of (start, length) sections and coalesce any adjacent
        sections."""
        result = []  # type: List[Tuple[int, int]]
        position = 0
        for (start, length) in sorted(sections):
            if result and start <= position:
                initial_start, _ = result.pop()
                result.append((initial_start, (start + length) - initial_start))
            else:
                result.append((start, length))
            position = start + length

        while result and result[0] < (self.minimum_address, 0):
            first_start, first_length = result[0]
            if first_start + first_length < self.minimum_address:
                result = result[1:]
            elif first_start < self.minimum_address:
                result[0] = (self.minimum_address, (first_start + first_length) - self.minimum_address)
        while result and result[-1] > (self.maximum_address, 0):
            last_start, last_length = result[-1]
            if last_start > self.maximum_address:
                result.pop()
            elif last_start + last_length > self.maximum_address:
                result[1] = (last_start, self.maximum_address - last_start)
        return result

def
_coalesce_sections
(
self
,
sections
:
Iterable
[
Tuple
[
int
,
int
]
]
)
->
Iterable
[
Tuple
[
int
,
int
]
]
:
result
=
[
]
# type: List[Tuple[int, int]]
position
=
0
for
(
start
,
length
)
in
sorted
(
sections
)
:
if
result
and
start
<=
position
:
initial_start
,
_
=
result
.
pop
(
)
result
.
append
(
(
initial_start
,
(
start
+
length
)
initial_start
)
)
else
:
result
.
append
(
(
start
,
length
)
)
position
=
start
+
length
while
result
and
result
[
0
]
<
(
self
.
minimum_address
,
0
)
:
first_start
,
first_length
=
result
[
0
]
if
first_start
+
first_length
<
self
.
minimum_address
:
result
=
result
[
1
:
]
elif
first_start
<
self
.
minimum_address
:
result
[
0
]
=
(
self
.
minimum_address
,
(
first_start
+
first_length
)
self
.
minimum_address
)
while
result
and
result
[
1
]
>
(
self
.
maximum_address
,
0
)
:
last_start
,
last_length
=
result
[
1
]
if
last_start
>
self
.
maximum_address
:
result
.
pop
(
)
elif
last_start
+
last_length
>
self
.
maximum_address
:
result
[
1
]
=
(
last_start
,
self
.
maximum_address
last_start
)
return
result


Iterator that indicates which blocks in the layer are to be read by for the scanning .

def _scan_iterator(self, scanner: 'ScannerInterface', sections: Iterable[Tuple[int,
                                                                                int]]) -> Iterable[IteratorValue]:
        """Iterator that indicates which blocks in the layer are to be read by
        for the scanning.

        Returns a list of blocks (potentially in lower layers) that make
        up this chunk contiguously. Chunks can be no bigger than
        scanner.chunk_size + scanner.overlap DataLayers by default are
        assumed to have no holes
        """
        for section_start, section_length in sections:
            offset, mapped_offset, length, layer_name = section_start, section_start, section_length, self.name
            while length > 0:
                chunk_size = min(length, scanner.chunk_size + scanner.overlap)
                yield [(layer_name, mapped_offset, chunk_size)], offset + chunk_size
                # It we've got more than the scanner's chunk_size, only move up by the chunk_size
                if chunk_size > scanner.chunk_size:
                    chunk_size -= scanner.overlap
                length -= chunk_size
                mapped_offset += chunk_size
                offset += chunk_size


Returns a ReadOnly copy of the metadata published by this layer .

def metadata(self) -> Mapping:
        """Returns a ReadOnly copy of the metadata published by this layer."""
        maps = [self.context.layers[layer_name].metadata for layer_name in self.dependencies]
        return interfaces.objects.ReadOnlyMapping(collections.ChainMap({}, self._direct_metadata, *maps))

def metadata ( self ) -> Mapping : maps = [ self . context . layers [ layer_name ] . metadata for layer_name in self . dependencies ] return interfaces . objects . ReadOnlyMapping ( collections . ChainMap ( { } , self . _direct_metadata , * maps ) )


Returns a sorted iterable of ( offset sublength mapped_offset mapped_length layer ) mappings .

def mapping(self,
                offset: int,
                length: int,
                ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, int, str]]:
        """Returns a sorted iterable of (offset, sublength, mapped_offset, mapped_length, layer)
        mappings.

        ignore_errors will provide all available maps with gaps, but
        their total length may not add up to the requested length This
        allows translation layers to provide maps of contiguous regions
        in one layer
        """
        return []

def mapping ( self , offset : int , length : int , ignore_errors : bool = False ) -> Iterable [ Tuple [ int , int , int , int , str ] ] : return [ ]


Returns a list of layer names that this layer translates onto .

def dependencies(self) -> List[str]:
        """Returns a list of layer names that this layer translates onto."""
        return []


Decodes any necessary data . Note additional data may need to be read from the lower layer such as lookup tables or similar . The data provided to this layer is purely that data which encompasses the requested data range .

def _decode_data(self, data: bytes, mapped_offset: int, offset: int, output_length: int) -> bytes:
        """Decodes any necessary data.  Note, additional data may need to be read from the lower layer, such as lookup
        tables or similar.  The data provided to this layer is purely that data which encompasses the requested data
        range.

        Args:
            data: The bytes of data necessary for decoding
            mapped_offset: The offset in the underlying layer where the data would begin
            offset: The offset in the higher-layer where the data would begin
            output_length: The expected length of the returned data

        Returns:
             The data to be read from the underlying layer."""
        return data

def _decode_data ( self , data : bytes , mapped_offset : int , offset : int , output_length : int ) -> bytes : return data


def _encode_data(self, layer_name: str, mapped_offset: int, offset: int, value: bytes) -> bytes:
        """Encodes any necessary data.

        Args:
            layer_name: The layer to write data back to
            mapped_offset: The offset in the underlying layer where the data would begin
            offset: The offset in the higher-layer where the data would begin
            value: The new value to encode

        Returns:
             The data to be rewritten at mapped_offset."""
        return value

def _encode_data ( self , layer_name : str , mapped_offset : int , offset : int , value : bytes ) -> bytes : return value


def read(self, offset: int, length: int, pad: bool = False) -> bytes:
        """Reads an offset for length bytes and returns 'bytes' (not 'str') of
        length size."""
        current_offset = offset
        output = b''  # type: bytes
        for (layer_offset, sublength, mapped_offset, mapped_length, layer) in self.mapping(offset,
                                                                                length,
                                                                                ignore_errors = pad):
            if not pad and layer_offset > current_offset:
                raise exceptions.InvalidAddressException(
                    self.name, current_offset, "Layer {} cannot map offset: {}".format(self.name, current_offset))
            elif layer_offset > current_offset:
                output += b"\x00" * (layer_offset - current_offset)
                current_offset = layer_offset
            # The layer_offset can be less than the current_offset in non-linearly mapped layers
            # it does not suggest an overlap, but that the data is in an encoded block
            if mapped_length > 0:
                unprocessed_data = self._context.layers.read(layer, mapped_offset, mapped_length, pad)
                processed_data = self._decode_data(unprocessed_data, mapped_offset, layer_offset, sublength)
                if len(processed_data) != sublength:
                    raise ValueError("ProcessedData length does not match expected length of chunk")
                output += processed_data
                current_offset += sublength
        return output + (b"\x00" * (length - len(output)))


Writes a value at offset distributing the writing across any underlying mapping .

def write(self, offset: int, value: bytes) -> None:
        """Writes a value at offset, distributing the writing across any
        underlying mapping."""
        current_offset = offset
        length = len(value)
        for (layer_offset, sublength, mapped_offset, mapped_length, layer) in self.mapping(offset, length):
            if layer_offset > current_offset:
                raise exceptions.InvalidAddressException(
                    self.name, current_offset, "Layer {} cannot map offset: {}".format(self.name, current_offset))

            value_chunk = value[layer_offset - offset:layer_offset - offset + sublength]
            new_data = self._encode_data(layer, mapped_offset, layer_offset, value_chunk)
            self._context.layers.write(layer, mapped_offset, new_data)

            current_offset += len(new_data)

def
write
(
self
,
offset
:
int
,
value
:
bytes
)
->
:
current_offset
=
offset
length
=
len
(
value
)
for
(
layer_offset
,
sublength
,
mapped_offset
,
mapped_length
,
layer
)
in
self
.
mapping
(
offset
,
length
)
:
if
layer_offset
>
current_offset
:
raise
exceptions
.
InvalidAddressException
(
self
.
name
,
current_offset
,
"Layer {} cannot map offset: {}"
.
format
(
self
.
name
,
current_offset
)
)
value_chunk
=
value
[
layer_offset
offset
:
layer_offset
offset
+
sublength
]
new_data
=
self
.
_encode_data
(
layer
,
mapped_offset
,
layer_offset
,
value_chunk
)
self
.
_context
.
layers
.
write
(
layer
,
mapped_offset
,
new_data
)
current_offset
+=
len
(
new_data
)