# Source code for dfwinreg.interface

    # -*- coding: utf-8 -*-
    """The Windows Registry object interfaces."""

    import abc

    from dfwinreg import definitions
    from dfwinreg import key_paths

    class WinRegistryFile(object):
      """Windows Registry file interface."""

      def __init__(self, ascii_codepage='cp1252', key_path_prefix=''):
        """Initializes a Windows Registry file.

        Args:
          ascii_codepage (Optional[str]): ASCII string codepage.
          key_path_prefix (Optional[str]): Windows Registry key path prefix.
        """
        super(WinRegistryFile, self).__init__()
        self._ascii_codepage = ascii_codepage
        self._key_path_prefix = key_path_prefix
        self._key_path_prefix_length = len(key_path_prefix)
        self._key_path_prefix_upper = key_path_prefix.upper()

      @abc.abstractmethod
      def Close(self):
        """Closes the Windows Registry file."""

      @abc.abstractmethod
      def GetKeyByPath(self, key_path):
        """Retrieves the key for a specific path.

        Args:
          key_path (str): Windows Registry key path.

        Returns:
          WinRegistryKey: Windows Registry key or None if not available.
        """

      @abc.abstractmethod
      def GetRootKey(self):
        """Retrieves the root key.

        Returns:
          WinRegistryKey: Windows Registry root key or None if not available.
        """

      @abc.abstractmethod
      def Open(self, file_object):
        """Opens the Windows Registry file using a file-like object.

        Args:
          file_object (file): file-like object.

        Returns:
          bool: True if successful or False if not.
        """

      def RecurseKeys(self):
        """Recurses the Windows Registry keys starting with the root key.

        Yields:
          WinRegistryKey: Windows Registry key.
        """
        root_key = self.GetRootKey()
        if root_key:
          for registry_key in root_key.RecurseKeys():
            yield registry_key

      def SetKeyPathPrefix(self, key_path_prefix):
        """Sets the Window Registry key path prefix.

        Args:
          key_path_prefix (str): Windows Registry key path prefix.
        """
        self._key_path_prefix = key_path_prefix
        self._key_path_prefix_length = len(key_path_prefix)
        self._key_path_prefix_upper = key_path_prefix.upper()

    class WinRegistryFileReader(object):
      """Windows Registry file reader interface."""

      @abc.abstractmethod
      def Open(self, path, ascii_codepage='cp1252'):
        """Opens a Windows Registry file specified by the path.

        Args:
          path (str): path of the Windows Registry file. The path is a Windows
              path relative to the root of the file system that contains the
              specific Windows Registry file, for example:
              C:\\Windows\\System32\\config\\SYSTEM
          ascii_codepage (Optional[str]): ASCII string codepage.

        Returns:
          WinRegistryFile: Windows Registry file or None.
        """

    class WinRegistryKey(object):
      """Windows Registry key interface."""

      def __init__(self, key_helper=None, key_path_prefix='', relative_key_path=''):
        """Initializes a Windows Registry key.

        Args:
          key_helper (Optional[WinRegistryKeyHelper]): Windows Registry key helper.
          key_path_prefix (Optional[str]): Windows Registry key path prefix.
          relative_key_path (Optional[str]): relative Windows Registry key path.
        """
        super(WinRegistryKey, self).__init__()
        self._key_helper = key_helper
        self._key_path_prefix = key_path_prefix
        self._relative_key_path = relative_key_path

      @property
      @abc.abstractmethod
      def class_name(self):
        """str: class name of the key or None if not available."""

      @property
      @abc.abstractmethod
      def last_written_time(self):
        """dfdatetime.DateTimeValues: last written time or None."""

      @property
      @abc.abstractmethod
      def name(self):
        """str: name of the key."""

      @property
      @abc.abstractmethod
      def number_of_subkeys(self):
        """int: number of subkeys within the key."""

      @property
      @abc.abstractmethod
      def number_of_values(self):
        """int: number of values within the key."""

      @property
      @abc.abstractmethod
      def offset(self):
        """int: offset of the key within the Windows Registry file or None."""

      @property
      def path(self):
        """str: Windows Registry key path."""
        return key_paths.JoinKeyPath([
            self._key_path_prefix, self._relative_key_path])

      @abc.abstractmethod
      def GetSubkeyByIndex(self, index):
        """Retrieves a subkey by index.

        Args:
          index (int): index of the subkey.

        Returns:
          WinRegistryKey: Windows Registry subkey.

        Raises:
          IndexError: if the index is out of bounds.
        """

      @abc.abstractmethod
      def GetSubkeyByName(self, name):
        """Retrieves a subkey by name.

        Args:
          name (str): name of the subkey.

        Returns:
          WinRegistryKey: Windows Registry subkey or None if not found.
        """

      @abc.abstractmethod
      def GetSubkeyByPath(self, key_path):
        """Retrieves a subkey by a path.

        Args:
          key_path (str): relative key path of the subkey.

        Returns:
          WinRegistryKey: Windows Registry subkey or None if not found.
        """

      @abc.abstractmethod
      def GetSubkeys(self):
        """Retrieves all subkeys within the key.

        Yields:
          WinRegistryKey: Windows Registry subkey.
        """

      @abc.abstractmethod
      def GetValueByName(self, name):
        """Retrieves a value by name.

        Args:
          name (str): name of the value or an empty string for the default value.

        Returns:
          WinRegistryValue: Windows Registry value or None if not found.
        """

      @abc.abstractmethod
      def GetValues(self):
        """Retrieves all values within the key.

        Yields:
          WinRegistryValue: Windows Registry value.
        """

      def RecurseKeys(self):
        """Recurses the subkeys starting with the key.

        Yields:
          WinRegistryKey: Windows Registry key.
        """
        yield self
        for subkey in self.GetSubkeys():
          for key in subkey.RecurseKeys():
            yield key

    class WinRegistryKeyHelper(object):
      """Windows Registry key helper."""

    class WinRegistryValue(object):
      """Windows Registry value interface."""

      _DATA_TYPE_STRINGS = {
          0: 'REG_NONE',
          1: 'REG_SZ',
          2: 'REG_EXPAND_SZ',
          3: 'REG_BINARY',
          4: 'REG_DWORD_LE',
          5: 'REG_DWORD_BE',
          6: 'REG_LINK',
          7: 'REG_MULTI_SZ',
          8: 'REG_RESOURCE_LIST',
          9: 'REG_FULL_RESOURCE_DESCRIPTOR',
          10: 'REG_RESOURCE_REQUIREMENTS_LIST',
          11: 'REG_QWORD'}

      _STRING_VALUE_TYPES = frozenset([
          definitions.REG_SZ, definitions.REG_EXPAND_SZ, definitions.REG_LINK])

      @property
      @abc.abstractmethod
      def data(self):
        """bytes: value data."""

      @property
      @abc.abstractmethod
      def data_type(self):
        """int: data type."""

      @property
      def data_type_string(self):
        """str: string representation of the data type."""
        return self._DATA_TYPE_STRINGS.get(self.data_type, 'UNKNOWN')

      @property
      @abc.abstractmethod
      def name(self):
        """str: name of the value."""

      @property
      @abc.abstractmethod
      def offset(self):
        """int: offset of the value within the Windows Registry file."""

      def DataIsBinaryData(self):
        """Determines, based on the data type, if the data is binary data.

        The data types considered binary data are: REG_BINARY.

        Returns:
          bool: True if the data is a binary data, False otherwise.
        """
        return self.data_type == definitions.REG_BINARY

      def DataIsInteger(self):
        """Determines, based on the data type, if the data is an integer.

        The data types considered strings are: REG_DWORD (REG_DWORD_LITTLE_ENDIAN),
        REG_DWORD_BIG_ENDIAN and REG_QWORD.

        Returns:
          bool: True if the data is an integer, False otherwise.
        """
        return self.data_type in (
            definitions.REG_DWORD, definitions.REG_DWORD_BIG_ENDIAN,
            definitions.REG_QWORD)

      def DataIsMultiString(self):
        """Determines, based on the data type, if the data is a multi string.

        The data types considered multi strings are: REG_MULTI_SZ.

        Returns:
          bool: True if the data is multi string, False otherwise.
        """
        return self.data_type == definitions.REG_MULTI_SZ

      def DataIsString(self):
        """Determines, based on the data type, if the data is a string.

        The data types considered strings are: REG_SZ and REG_EXPAND_SZ.

        Returns:
          bool: True if the data is a string, False otherwise.
        """
        return self.data_type in (definitions.REG_SZ, definitions.REG_EXPAND_SZ)

      @abc.abstractmethod
      def GetDataAsObject(self):
        """Retrieves the data as an object.

        Returns:
          object: data as a Python type.
        """