Source code for dfvfs.lib.data_format
# -*- coding: utf-8 -*-
"""dtFabric data format helpers."""
import os
from dtfabric import errors as dtfabric_errors
from dtfabric.runtime import data_maps as dtfabric_data_maps
from dfvfs.lib import errors
[docs]
class DataFormat(object):
"""Data format."""
def _ReadData(self, file_object, file_offset, data_size):
"""Reads data.
Args:
file_object (dfvfs.FileIO): a file-like object to read.
file_offset (int): offset of the data relative to the start of
the file-like object.
data_size (int): size of the data. The resulting data size much match
the requested data size so that dtFabric can map the data type
definitions onto the byte stream.
Returns:
bytes: byte stream containing the data.
Raises:
FileFormatError: if the data cannot be read.
ValueError: if the file-like object is missing.
"""
if not file_object:
raise ValueError('Missing file-like object.')
file_object.seek(file_offset, os.SEEK_SET)
read_error = ''
try:
data = file_object.read(data_size)
if len(data) != data_size:
read_error = 'missing data'
except IOError as exception:
read_error = f'{exception!s}'
if read_error:
raise errors.FileFormatError((
f'Unable to read data at offset: 0x{file_offset:08x} with error: '
f'{read_error:s}'))
return data
def _ReadStructureFromFileObject(
self, file_object, file_offset, data_type_map):
"""Reads a structure from a file-like object.
If the data type map has a fixed size this method will read the predefined
number of bytes from the file-like object. If the data type map has a
variable size, depending on values in the byte stream, this method will
continue to read from the file-like object until the data type map can be
successfully mapped onto the byte stream or until an error occurs.
Args:
file_object (dfvfs.FileIO): a file-like object to parse.
file_offset (int): offset of the structure data relative to the start
of the file-like object.
data_type_map (dtfabric.DataTypeMap): data type map of the structure.
Returns:
tuple[object, int]: structure values object and data size of
the structure.
Raises:
FileFormatError: if the structure cannot be read.
ValueError: if file-like object or data type map is missing.
"""
context = None
data = b''
last_data_size = 0
data_size = data_type_map.GetSizeHint()
while data_size != last_data_size:
read_offset = file_offset + last_data_size
read_size = data_size - last_data_size
data_segment = self._ReadData(file_object, read_offset, read_size)
data = b''.join([data, data_segment])
try:
context = dtfabric_data_maps.DataTypeMapContext()
structure_values_object = data_type_map.MapByteStream(
data, context=context)
return structure_values_object, data_size
except dtfabric_errors.ByteStreamTooSmallError:
pass
except dtfabric_errors.MappingError as exception:
raise errors.FileFormatError((
f'Unable to map {data_type_map.name:s} data at offset: '
f'0x{file_offset:08x} with error: {exception!s}'))
last_data_size = data_size
data_size = data_type_map.GetSizeHint(context=context)
raise errors.FileFormatError((
f'Unable to read {data_type_map.name:s} at offset: '
f'0x{file_offset:08x}'))