~bzr-pqm/bzr/bzr.dev

1185.1.29 by Robert Collins
merge merge tweaks from aaron, which includes latest .dev
1
# $Id: gzip_consumer.py 271 2004-10-09 10:50:59Z fredrik $
2
# gzip consumer
3
#
4
# Copyright (c) 2001-2004 by Fredrik Lundh.  All rights reserved.
5
#
6
6379.6.3 by Jelmer Vernooij
Use absolute_import.
7
from __future__ import absolute_import
8
1185.1.29 by Robert Collins
merge merge tweaks from aaron, which includes latest .dev
9
##
10
# Consumer wrapper for GZIP streams.
11
12
class GzipConsumer:
13
14
    def __init__(self, consumer):
15
        self.__consumer = consumer
16
        self.__decoder = None
17
        self.__data = ""
18
19
    def __getattr__(self, key):
20
        return getattr(self.__consumer, key)
21
22
    def feed(self, data):
23
        if self.__decoder is None:
24
            # check if we have a full gzip header
25
            data = self.__data + data
26
            try:
27
                i = 10
28
                flag = ord(data[3])
29
                if flag & 4: # extra
30
                    x = ord(data[i]) + 256*ord(data[i+1])
31
                    i = i + 2 + x
32
                if flag & 8: # filename
33
                    while ord(data[i]):
34
                        i = i + 1
35
                    i = i + 1
36
                if flag & 16: # comment
37
                    while ord(data[i]):
38
                        i = i + 1
39
                    i = i + 1
40
                if flag & 2: # crc
41
                    i = i + 2
42
                if len(data) < i:
43
                    raise IndexError("not enough data")
44
                if data[:3] != "\x1f\x8b\x08":
45
                    raise IOError("invalid gzip data")
46
                data = data[i:]
47
            except IndexError:
48
                self.__data = data
49
                return # need more data
50
            import zlib
51
            self.__data = ""
52
            self.__decoder = zlib.decompressobj(-zlib.MAX_WBITS)
53
        data = self.__decoder.decompress(data)
54
        if data:
55
            self.__consumer.feed(data)
56
57
    def close(self):
58
        if self.__decoder:
59
            data = self.__decoder.flush()
60
            if data:
61
                self.__consumer.feed(data)
62
        self.__consumer.close()