blob: 8ee976626ed8cdbf27784240e1b46a831935a78b [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001"""
2The functions in this module allow compression and decompression using the
3zlib library, which is based on GNU zip.
4
5adler32(string[, start]) -- Compute an Adler-32 checksum.
6compress(string[, level]) -- Compress string, with compression level in 1-9.
7compressobj([level]) -- Return a compressor object.
8crc32(string[, start]) -- Compute a CRC-32 checksum.
9decompress(string,[wbits],[bufsize]) -- Decompresses a compressed string.
10decompressobj([wbits]) -- Return a decompressor object.
11
12'wbits' is window buffer size.
13Compressor objects support compress() and flush() methods; decompressor
14objects support decompress() and flush().
15"""
16import array
17import binascii
18import jarray
19
20from java.util.zip import Adler32, Deflater, Inflater, DataFormatException
21from java.lang import Long, String
22
23from cStringIO import StringIO
24
25class error(Exception):
26 pass
27
28
29DEFLATED = 8
30MAX_WBITS = 15
31DEF_MEM_LEVEL = 8
32ZLIB_VERSION = "1.1.3"
33Z_BEST_COMPRESSION = 9
34Z_BEST_SPEED = 1
35
36Z_FILTERED = 1
37Z_HUFFMAN_ONLY = 2
38
39Z_DEFAULT_COMPRESSION = -1
40Z_DEFAULT_STRATEGY = 0
41
42# Most options are removed because java does not support them
43# Z_NO_FLUSH = 0
44# Z_SYNC_FLUSH = 2
45# Z_FULL_FLUSH = 3
46Z_FINISH = 4
47_valid_flush_modes = (Z_FINISH,)
48
49def adler32(s, value=1):
50 if value != 1:
51 raise ValueError, "adler32 only support start value of 1"
52 checksum = Adler32()
53 checksum.update(String.getBytes(s, 'iso-8859-1'))
54 return Long(checksum.getValue()).intValue()
55
56def crc32(string, value=0):
57 return binascii.crc32(string, value)
58
59
60def compress(string, level=6):
61 if level < Z_BEST_SPEED or level > Z_BEST_COMPRESSION:
62 raise error, "Bad compression level"
63 deflater = Deflater(level, 0)
64 string = _to_input(string)
65 deflater.setInput(string, 0, len(string))
66 deflater.finish()
67 return _get_deflate_data(deflater)
68
69def decompress(string, wbits=0, bufsize=16384):
70 inflater = Inflater(wbits < 0)
71 inflater.setInput(_to_input(string))
72
73 return _get_inflate_data(inflater)
74
75class compressobj:
76 # all jython uses wbits for is deciding whether to skip the header if it's negative
77 def __init__(self, level=6, method=DEFLATED, wbits=MAX_WBITS,
78 memLevel=0, strategy=0):
79 if abs(wbits) > MAX_WBITS or abs(wbits) < 8:
80 raise ValueError, "Invalid initialization option"
81 self.deflater = Deflater(level, wbits < 0)
82 self.deflater.setStrategy(strategy)
83 if wbits < 0:
84 _get_deflate_data(self.deflater)
85 self._ended = False
86
87 def compress(self, string):
88 if self._ended:
89 raise error("compressobj may not be used after flush(Z_FINISH)")
90 string = _to_input(string)
91 self.deflater.setInput(string, 0, len(string))
92 return _get_deflate_data(self.deflater)
93
94 def flush(self, mode=Z_FINISH):
95 if self._ended:
96 raise error("compressobj may not be used after flush(Z_FINISH)")
97 if mode not in _valid_flush_modes:
98 raise ValueError, "Invalid flush option"
99 self.deflater.finish()
100 last = _get_deflate_data(self.deflater)
101 if mode == Z_FINISH:
102 self.deflater.end()
103 self._ended = True
104 return last
105
106class decompressobj:
107 # all jython uses wbits for is deciding whether to skip the header if it's negative
108 def __init__(self, wbits=MAX_WBITS):
109 if abs(wbits) > MAX_WBITS or abs(wbits) < 8:
110 raise ValueError, "Invalid initialization option"
111 self.inflater = Inflater(wbits < 0)
112 self.unused_data = ""
113 self._ended = False
114
115 def decompress(self, string, max_length=0):
116 if self._ended:
117 raise error("decompressobj may not be used after flush()")
118
119 # unused_data is always "" until inflation is finished; then it is
120 # the unused bytes of the input;
121 # unconsumed_tail is whatever input was not used because max_length
122 # was exceeded before inflation finished.
123 # Thus, at most one of {unused_data, unconsumed_tail} may be non-empty.
124 self.unused_data = ""
125 self.unconsumed_tail = ""
126
127 if max_length < 0:
128 raise ValueError("max_length must be a positive integer")
129
130 string = _to_input(string)
131 self.inflater.setInput(string)
132 inflated = _get_inflate_data(self.inflater, max_length)
133
134 r = self.inflater.getRemaining()
135 if r:
136 if max_length:
137 self.unconsumed_tail = string[-r:]
138 else:
139 self.unused_data = string[-r:]
140
141 return inflated
142
143 def flush(self, length=None):
144 if self._ended:
145 raise error("decompressobj may not be used after flush()")
146 if length is None:
147 length = 0
148 elif length <= 0:
149 raise ValueError('length must be greater than zero')
150 last = _get_inflate_data(self.inflater, length)
151 self.inflater.end()
152 return last
153
154def _to_input(string):
155 return string.tostring() if isinstance(string, array.array) else string
156
157def _get_deflate_data(deflater):
158 buf = jarray.zeros(1024, 'b')
159 s = StringIO()
160 while not deflater.finished():
161 l = deflater.deflate(buf)
162
163 if l == 0:
164 break
165 s.write(String(buf, 0, 0, l))
166 s.seek(0)
167 return s.read()
168
169def _get_inflate_data(inflater, max_length=0):
170 buf = jarray.zeros(1024, 'b')
171 s = StringIO()
172 total = 0
173 while not inflater.finished():
174 try:
175 if max_length:
176 l = inflater.inflate(buf, 0, min(1024, max_length - total))
177 else:
178 l = inflater.inflate(buf)
179 except DataFormatException, e:
180 raise error(str(e))
181
182 if l == 0:
183 break
184
185 total += l
186 s.write(String(buf, 0, 0, l))
187 if max_length and total == max_length:
188 break
189 s.seek(0)
190 return s.read()