Source code for winregrc.output_writers

"""Output writer."""

import abc

from dfdatetime import fat_date_time as dfdatetime_fat_date_time
from dfdatetime import filetime as dfdatetime_filetime

from winregrc import hexdump


[docs] class OutputWriter: """Output writer interface.""" # Note that redundant-returns-doc is broken for pylint 1.7.x # pylint: disable=redundant-returns-doc _HEXDUMP_CHARACTER_MAP = [ "." if byte < 0x20 or byte > 0x7E else chr(byte) for byte in range(256) ] def _FormatDataInHexadecimal(self, data): """Formats data in a hexadecimal representation. Args: data (bytes): data. Returns: str: hexadecimal representation of the data. """ in_group = False previous_hexadecimal_string = None lines = [] data_size = len(data) for block_index in range(0, data_size, 16): data_string = data[block_index : block_index + 16] hexadecimal_byte_values = [] printable_values = [] for byte_value in data_string: if isinstance(byte_value, str): byte_value = ord(byte_value) hexadecimal_byte_values.append(f"{byte_value:02x}") printable_value = self._HEXDUMP_CHARACTER_MAP[byte_value] printable_values.append(printable_value) remaining_size = 16 - len(data_string) if remaining_size == 0: whitespace = "" elif remaining_size >= 8: whitespace = " " * ((3 * remaining_size) - 1) else: whitespace = " " * (3 * remaining_size) hexadecimal_string_part1 = " ".join(hexadecimal_byte_values[0:8]) hexadecimal_string_part2 = " ".join(hexadecimal_byte_values[8:16]) hexadecimal_string = ( f"{hexadecimal_string_part1:s} {hexadecimal_string_part2:s}" f"{whitespace:s}" ) if ( previous_hexadecimal_string is not None and previous_hexadecimal_string == hexadecimal_string and block_index + 16 < data_size ): if not in_group: in_group = True lines.append("...") else: printable_string = "".join(printable_values) lines.append( f"0x{block_index:08x} {hexadecimal_string:s} " f"{printable_string:s}" ) in_group = False previous_hexadecimal_string = hexadecimal_string lines.extend(["", ""]) return "\n".join(lines) def _FormatFATDateTimeValue(self, value): """Formats a FAT date time value. Args: value (int): FAT date time value. Returns: str: date time string. """ if not value: date_time_string = "Not set (0)" else: date_time = dfdatetime_fat_date_time.FATDateTime(fat_date_time=value) date_time_string = date_time.CopyToDateTimeString() if not date_time_string: date_time_string = f"0x{value:04x}" return date_time_string def _FormatFiletimeValue(self, value): """Formats a FILETIME timestamp value. Args: value (int): FILETIME timestamp value. Returns: str: date time string. """ if value == 0: date_time_string = "Not set (0)" elif value == 0x7FFFFFFFFFFFFFFF: date_time_string = "Never (0x7fffffffffffffff)" else: date_time = dfdatetime_filetime.Filetime(timestamp=value) date_time_string = date_time.CopyToDateTimeString() if date_time_string: date_time_string = f"{date_time_string:s} UTC" else: date_time_string = f"0x{value:08x}" return date_time_string
[docs] @abc.abstractmethod def Close(self): """Closes the output writer."""
[docs] def DebugPrintData(self, description, data): """Prints data for debugging. Args: description (str): description. data (bytes): data. """ self.WriteText(f"{description:s}:\n") value_string = self._FormatDataInHexadecimal(data) self.WriteText(value_string)
[docs] def DebugPrintValue(self, description, value): """Prints a value for debugging. Args: description (str): description. value (object): value. """ alignment, _ = divmod(len(description), 8) alignment_string = "\t" * (8 - alignment + 1) self.WriteText(f"{description:s}{alignment_string:s}: {value!s}\n")
[docs] def DebugPrintText(self, text): """Prints text for debugging. Args: text (str): text. """ self.WriteText(text)
[docs] @abc.abstractmethod def Open(self): """Opens the output writer. Returns: bool: True if successful or False if not. """
[docs] @abc.abstractmethod def WriteDebugData(self, description, data): """Writes data for debugging. Args: description (str): description. data (bytes): data to write. """
[docs] @abc.abstractmethod def WriteIntegerValueAsDecimal(self, description, value): """Writes an integer value as decimal. Args: description (str): description. value (int): value to write. """
[docs] @abc.abstractmethod def WriteFiletimeValue(self, description, value): """Writes a FILETIME timestamp value. Args: description (str): description. value (str): value to write. """
[docs] @abc.abstractmethod def WriteText(self, text): """Writes text. Args: text (str): text to write. """
[docs] @abc.abstractmethod def WriteValue(self, description, value): """Writes a value. Args: description (str): description. value (str): value to write. """
[docs] class StdoutOutputWriter(OutputWriter): """Stdout output writer."""
[docs] def Close(self): """Closes the output writer.""" return
[docs] def Open(self): """Opens the output writer. Returns: bool: True if successful or False if not. """ return True
[docs] def WriteDebugData(self, description, data): """Writes data for debugging. Args: description (str): description. data (bytes): data. """ self.WriteText(description) self.WriteText("\n") hexdump_text = hexdump.Hexdump(data) self.WriteText(hexdump_text)
[docs] def WriteFiletimeValue(self, description, value): """Writes a FILETIME timestamp value. Args: description (str): description. value (int): FILETIME timestamp value. """ date_time_string = self._FormatFiletimeValue(value) self.WriteValue(description, date_time_string)
[docs] def WriteIntegerValueAsDecimal(self, description, value): """Writes an integer value as decimal. Args: description (str): description. value (int): integer value. """ self.WriteValue(description, f"{value:d}")
[docs] def WriteText(self, text): """Writes text. Args: text (str): text to write. """ print(text, end="")
[docs] def WriteValue(self, description, value): """Writes a value. Args: description (str): description. value (object): value. """ description_no_tabs = description.replace("\t", " " * 8) alignment, _ = divmod(len(description_no_tabs), 8) alignment_string = "\t" * (8 - alignment + 1) self.WriteText(f"{description:s}{alignment_string:s}: {value!s}\n")