import zlib
import binwalk.core.compat
import binwalk.core.plugin
from binwalk.core.common import BlockFile


class GzipValidPlugin(binwalk.core.plugin.Plugin):

    '''
    Validates gzip compressed data. Almost identical to zlibvalid.py.
    '''
    MODULES = ['Signature']

    MAX_DATA_SIZE = 33 * 1024

    def scan(self, result):
        # If this result is a gzip signature match, try to decompress the data
        if result.file and result.description.lower().startswith('gzip'):
            # Seek to and read the suspected gzip data
            fd = self.module.config.open_file(
                result.file.name, offset=result.offset, length=self.MAX_DATA_SIZE)
            data = fd.read(self.MAX_DATA_SIZE)
            fd.close()

            # Grab the flags and initialize the default offset of the start of
            # compressed data.
            flags = int(ord(data[3]))
            offset = 10

            # If there is a comment or the original file name, find the end of that
            # string and start decompression from there.
            if (flags & 0x0C) or (flags & 0x10):
                while data[offset] != "\x00":
                    offset += 1
                offset += 1

            # Append basic zlib header to the beginning of the compressed data
            data = "\x78\x9C" + data[offset:]

            # Check if this is valid deflate data (no zlib header)
            try:
                zlib.decompress(binwalk.core.compat.str2bytes(data))
            except zlib.error as e:
                error = str(e)
                # Truncated input data results in error -5.
                # gzip uses different checksums than zlib, which results in
                # error -3.
                if not error.startswith("Error -5") and not error.startswith("Error -3"):
                    result.valid = False
