Source code for plaso.lib.specification
"""The format specification classes."""
[docs]
class Signature:
"""The format specification signature.
The signature consists of a byte string pattern, an optional offset relative
to the start of the data, and a value to indicate if the pattern is bound to
the offset.
"""
[docs]
def __init__(self, pattern, offset=None):
"""Initializes a format specification signature.
The signatures can be defined in 3 different "modes":
* where offset >= 0, which represents that the signature is bound to the
start of the data and only the relevant part is scanned;
* where offset < 0, which represents that the signature is bound to the
end of the data and only the relevant part is scanned;
* offset == None, which represents that the signature is not offset bound
and that all of the data is scanned.
Args:
pattern (bytes): pattern of the signature. Wildcards or regular
expressions (regexp) are not supported.
offset (int): offset of the signature. None is used to indicate
the signature has no offset. A positive offset is relative from
the start of the data a negative offset is relative from the end
of the data.
"""
super().__init__()
self.identifier = None
self.offset = offset
self.pattern = pattern
[docs]
def SetIdentifier(self, identifier):
"""Sets the identifier of the signature in the specification store.
Args:
identifier (str): unique signature identifier for a specification store.
"""
self.identifier = identifier
[docs]
class FormatSpecification:
"""The format specification."""
[docs]
def __init__(self, identifier, text_format=False):
"""Initializes a format specification.
Args:
identifier (str): unique name for the format.
text_format (Optional[bool]): True if the format is a text format,
False otherwise.
"""
super().__init__()
self._text_format = text_format
self.identifier = identifier
self.signatures = []
[docs]
def AddNewSignature(self, pattern, offset=None):
"""Adds a signature.
Args:
pattern (bytes): pattern of the signature.
offset (int): offset of the signature. None is used to indicate
the signature has no offset. A positive offset is relative from
the start of the data a negative offset is relative from the end
of the data.
"""
self.signatures.append(Signature(pattern, offset=offset))
[docs]
def IsTextFormat(self):
"""Determines if the format is a text format.
Returns:
bool: True if the format is a text format, False otherwise.
"""
return self._text_format
[docs]
class FormatSpecificationStore:
"""The store for format specifications."""
[docs]
def __init__(self):
"""Initializes a specification store."""
super().__init__()
self._format_specifications = {}
# Maps signature identifiers to format specifications.
self._signature_map = {}
@property
def specifications(self):
"""iterator: specifications iterator."""
return iter(self._format_specifications.values())
[docs]
def AddNewSpecification(self, identifier):
"""Adds a new format specification.
Args:
identifier (str): format identifier, which should be unique for the store.
Returns:
FormatSpecification: format specification.
Raises:
KeyError: if the store already contains a specification with
the same identifier.
"""
if identifier in self._format_specifications:
raise KeyError(
f'Format specification {identifier:s} is already defined in store.')
self._format_specifications[identifier] = FormatSpecification(identifier)
return self._format_specifications[identifier]
[docs]
def AddSpecification(self, specification):
"""Adds a format specification.
Args:
specification (FormatSpecification): format specification.
Raises:
KeyError: if the store already contains a specification with
the same identifier.
"""
if specification.identifier in self._format_specifications:
raise KeyError(
f'Format specification {specification.identifier:s} is already '
f'defined in store.')
self._format_specifications[specification.identifier] = specification
for signature in specification.signatures:
signature_index = len(self._signature_map)
signature_identifier = f'{specification.identifier:s}:{signature_index:d}'
if signature_identifier in self._signature_map:
raise KeyError(
f'Signature {signature_identifier:s} is already defined in map.')
signature.SetIdentifier(signature_identifier)
self._signature_map[signature_identifier] = specification
[docs]
def GetSpecificationBySignature(self, signature_identifier):
"""Retrieves a specification mapped to a signature identifier.
Args:
signature_identifier (str): unique signature identifier for a
specification store.
Returns:
FormatSpecification: format specification or None if the signature
identifier does not exist within the specification store.
"""
return self._signature_map.get(signature_identifier)