blob: e652f4dfcd81edc1972314bf36a817d88d1d199f [file] [log] [blame]
Antoine Pitrou37dc5f82011-04-03 17:05:46 +02001/* _bz2 - Low-level Python interface to libbzip2. */
2
3#define PY_SSIZE_T_CLEAN
4
5#include "Python.h"
6#include "structmember.h"
7
8#ifdef WITH_THREAD
9#include "pythread.h"
10#endif
11
12#include <bzlib.h>
13#include <stdio.h>
14
15
16#ifndef BZ_CONFIG_ERROR
17#define BZ2_bzCompress bzCompress
18#define BZ2_bzCompressInit bzCompressInit
19#define BZ2_bzCompressEnd bzCompressEnd
20#define BZ2_bzDecompress bzDecompress
21#define BZ2_bzDecompressInit bzDecompressInit
22#define BZ2_bzDecompressEnd bzDecompressEnd
23#endif /* ! BZ_CONFIG_ERROR */
24
25
26#ifdef WITH_THREAD
27#define ACQUIRE_LOCK(obj) do { \
28 if (!PyThread_acquire_lock((obj)->lock, 0)) { \
29 Py_BEGIN_ALLOW_THREADS \
30 PyThread_acquire_lock((obj)->lock, 1); \
31 Py_END_ALLOW_THREADS \
32 } } while (0)
33#define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock)
34#else
35#define ACQUIRE_LOCK(obj)
36#define RELEASE_LOCK(obj)
37#endif
38
39
40typedef struct {
41 PyObject_HEAD
42 bz_stream bzs;
43 int flushed;
44#ifdef WITH_THREAD
45 PyThread_type_lock lock;
46#endif
47} BZ2Compressor;
48
49typedef struct {
50 PyObject_HEAD
51 bz_stream bzs;
52 char eof; /* T_BOOL expects a char */
53 PyObject *unused_data;
54#ifdef WITH_THREAD
55 PyThread_type_lock lock;
56#endif
57} BZ2Decompressor;
58
Larry Hastingsf256c222014-01-25 21:30:37 -080059static PyTypeObject BZ2Compressor_Type;
60static PyTypeObject BZ2Decompressor_Type;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +020061
62/* Helper functions. */
63
64static int
65catch_bz2_error(int bzerror)
66{
67 switch(bzerror) {
68 case BZ_OK:
69 case BZ_RUN_OK:
70 case BZ_FLUSH_OK:
71 case BZ_FINISH_OK:
72 case BZ_STREAM_END:
73 return 0;
74
75#ifdef BZ_CONFIG_ERROR
76 case BZ_CONFIG_ERROR:
77 PyErr_SetString(PyExc_SystemError,
78 "libbzip2 was not compiled correctly");
79 return 1;
80#endif
81 case BZ_PARAM_ERROR:
82 PyErr_SetString(PyExc_ValueError,
83 "Internal error - "
84 "invalid parameters passed to libbzip2");
85 return 1;
86 case BZ_MEM_ERROR:
87 PyErr_NoMemory();
88 return 1;
89 case BZ_DATA_ERROR:
90 case BZ_DATA_ERROR_MAGIC:
91 PyErr_SetString(PyExc_IOError, "Invalid data stream");
92 return 1;
93 case BZ_IO_ERROR:
94 PyErr_SetString(PyExc_IOError, "Unknown I/O error");
95 return 1;
96 case BZ_UNEXPECTED_EOF:
97 PyErr_SetString(PyExc_EOFError,
98 "Compressed file ended before the logical "
99 "end-of-stream was detected");
100 return 1;
101 case BZ_SEQUENCE_ERROR:
102 PyErr_SetString(PyExc_RuntimeError,
103 "Internal error - "
104 "Invalid sequence of commands sent to libbzip2");
105 return 1;
106 default:
107 PyErr_Format(PyExc_IOError,
108 "Unrecognized error from libbzip2: %d", bzerror);
109 return 1;
110 }
111}
112
113#if BUFSIZ < 8192
114#define SMALLCHUNK 8192
115#else
116#define SMALLCHUNK BUFSIZ
117#endif
118
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200119static int
120grow_buffer(PyObject **buf)
121{
Nadeem Vawda72d6a132011-10-13 13:38:14 +0200122 /* Expand the buffer by an amount proportional to the current size,
123 giving us amortized linear-time behavior. Use a less-than-double
124 growth factor to avoid excessive allocation. */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200125 size_t size = PyBytes_GET_SIZE(*buf);
Nadeem Vawda18b7fcc2012-10-21 21:16:58 +0200126 size_t new_size = size + (size >> 3) + 6;
127 if (new_size > size) {
128 return _PyBytes_Resize(buf, new_size);
129 } else { /* overflow */
130 PyErr_SetString(PyExc_OverflowError,
131 "Unable to allocate buffer - output too large");
132 return -1;
133 }
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200134}
135
136
137/* BZ2Compressor class. */
138
139static PyObject *
140compress(BZ2Compressor *c, char *data, size_t len, int action)
141{
142 size_t data_size = 0;
143 PyObject *result;
144
145 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
146 if (result == NULL)
147 return NULL;
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100148
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200149 c->bzs.next_in = data;
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100150 c->bzs.avail_in = 0;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200151 c->bzs.next_out = PyBytes_AS_STRING(result);
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200152 c->bzs.avail_out = SMALLCHUNK;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200153 for (;;) {
154 char *this_out;
155 int bzerror;
156
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100157 /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
158 Do compression in chunks of no more than UINT_MAX bytes each. */
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200159 if (c->bzs.avail_in == 0 && len > 0) {
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200160 c->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200161 len -= c->bzs.avail_in;
162 }
163
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100164 /* In regular compression mode, stop when input data is exhausted. */
165 if (action == BZ_RUN && c->bzs.avail_in == 0)
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200166 break;
167
168 if (c->bzs.avail_out == 0) {
Nadeem Vawda18b7fcc2012-10-21 21:16:58 +0200169 size_t buffer_left = PyBytes_GET_SIZE(result) - data_size;
170 if (buffer_left == 0) {
171 if (grow_buffer(&result) < 0)
172 goto error;
173 c->bzs.next_out = PyBytes_AS_STRING(result) + data_size;
174 buffer_left = PyBytes_GET_SIZE(result) - data_size;
175 }
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200176 c->bzs.avail_out = (unsigned int)Py_MIN(buffer_left, UINT_MAX);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200177 }
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100178
179 Py_BEGIN_ALLOW_THREADS
180 this_out = c->bzs.next_out;
181 bzerror = BZ2_bzCompress(&c->bzs, action);
182 data_size += c->bzs.next_out - this_out;
183 Py_END_ALLOW_THREADS
184 if (catch_bz2_error(bzerror))
185 goto error;
186
187 /* In flushing mode, stop when all buffered data has been flushed. */
188 if (action == BZ_FINISH && bzerror == BZ_STREAM_END)
189 break;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200190 }
191 if (data_size != PyBytes_GET_SIZE(result))
192 if (_PyBytes_Resize(&result, data_size) < 0)
193 goto error;
194 return result;
195
196error:
197 Py_XDECREF(result);
198 return NULL;
199}
200
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200201/*[clinic input]
202output preset file
203module _bz2
Larry Hastingsc2047262014-01-25 20:43:29 -0800204class _bz2.BZ2Compressor "BZ2Compressor *" "&BZ2Compressor_Type"
205class _bz2.BZ2Decompressor "BZ2Decompressor *" "&BZ2Decompressor_Type"
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200206[clinic start generated code]*/
Larry Hastings581ee362014-01-28 05:00:08 -0800207/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e3b139924f5e18cc]*/
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200208
Larry Hastingsf256c222014-01-25 21:30:37 -0800209#include "clinic/_bz2module.c.h"
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200210
211/*[clinic input]
212_bz2.BZ2Compressor.compress
213
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200214 data: Py_buffer
215 /
216
217Provide data to the compressor object.
218
219Returns a chunk of compressed data if possible, or b'' otherwise.
220
221When you have finished providing data to the compressor, call the
222flush() method to finish the compression process.
223[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200224
225static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200226_bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data)
Larry Hastings581ee362014-01-28 05:00:08 -0800227/*[clinic end generated code: output=59365426e941fbcc input=85c963218070fc4c]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200228{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200229 PyObject *result = NULL;
230
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200231 ACQUIRE_LOCK(self);
232 if (self->flushed)
233 PyErr_SetString(PyExc_ValueError, "Compressor has been flushed");
234 else
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200235 result = compress(self, data->buf, data->len, BZ_RUN);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200236 RELEASE_LOCK(self);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200237 return result;
238}
239
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200240/*[clinic input]
241_bz2.BZ2Compressor.flush
242
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200243Finish the compression process.
244
245Returns the compressed data left in internal buffers.
246
247The compressor object may not be used after this method is called.
248[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200249
250static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200251_bz2_BZ2Compressor_flush_impl(BZ2Compressor *self)
Larry Hastings581ee362014-01-28 05:00:08 -0800252/*[clinic end generated code: output=3ef03fc1b092a701 input=d64405d3c6f76691]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200253{
254 PyObject *result = NULL;
255
256 ACQUIRE_LOCK(self);
257 if (self->flushed)
258 PyErr_SetString(PyExc_ValueError, "Repeated call to flush()");
259 else {
260 self->flushed = 1;
261 result = compress(self, NULL, 0, BZ_FINISH);
262 }
263 RELEASE_LOCK(self);
264 return result;
265}
266
Nadeem Vawda37970652013-10-28 21:35:23 +0100267static PyObject *
268BZ2Compressor_getstate(BZ2Compressor *self, PyObject *noargs)
269{
270 PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
271 Py_TYPE(self)->tp_name);
272 return NULL;
273}
274
Victor Stinner5064a522013-07-07 16:50:27 +0200275static void*
276BZ2_Malloc(void* ctx, int items, int size)
277{
278 if (items < 0 || size < 0)
279 return NULL;
280 if ((size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
281 return NULL;
282 /* PyMem_Malloc() cannot be used: compress() and decompress()
283 release the GIL */
284 return PyMem_RawMalloc(items * size);
285}
286
287static void
288BZ2_Free(void* ctx, void *ptr)
289{
Victor Stinnerb7f1f652013-07-07 17:10:34 +0200290 PyMem_RawFree(ptr);
Victor Stinner5064a522013-07-07 16:50:27 +0200291}
292
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200293/*[clinic input]
294_bz2.BZ2Compressor.__init__
295
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200296 compresslevel: int = 9
297 Compression level, as a number between 1 and 9.
298 /
299
300Create a compressor object for compressing data incrementally.
301
302For one-shot compression, use the compress() function instead.
303[clinic start generated code]*/
304
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200305static int
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200306_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
Larry Hastings581ee362014-01-28 05:00:08 -0800307/*[clinic end generated code: output=c4e6adfd02963827 input=4e1ff7b8394b6e9a]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200308{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200309 int bzerror;
310
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200311 if (!(1 <= compresslevel && compresslevel <= 9)) {
312 PyErr_SetString(PyExc_ValueError,
313 "compresslevel must be between 1 and 9");
314 return -1;
315 }
316
317#ifdef WITH_THREAD
318 self->lock = PyThread_allocate_lock();
319 if (self->lock == NULL) {
320 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
321 return -1;
322 }
323#endif
324
Victor Stinner5064a522013-07-07 16:50:27 +0200325 self->bzs.opaque = NULL;
326 self->bzs.bzalloc = BZ2_Malloc;
327 self->bzs.bzfree = BZ2_Free;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200328 bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0);
329 if (catch_bz2_error(bzerror))
330 goto error;
331
332 return 0;
333
334error:
335#ifdef WITH_THREAD
336 PyThread_free_lock(self->lock);
337 self->lock = NULL;
338#endif
339 return -1;
340}
341
342static void
343BZ2Compressor_dealloc(BZ2Compressor *self)
344{
345 BZ2_bzCompressEnd(&self->bzs);
346#ifdef WITH_THREAD
347 if (self->lock != NULL)
348 PyThread_free_lock(self->lock);
349#endif
350 Py_TYPE(self)->tp_free((PyObject *)self);
351}
352
353static PyMethodDef BZ2Compressor_methods[] = {
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200354 _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF
355 _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF
Nadeem Vawda37970652013-10-28 21:35:23 +0100356 {"__getstate__", (PyCFunction)BZ2Compressor_getstate, METH_NOARGS},
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200357 {NULL}
358};
359
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200360
361static PyTypeObject BZ2Compressor_Type = {
362 PyVarObject_HEAD_INIT(NULL, 0)
363 "_bz2.BZ2Compressor", /* tp_name */
364 sizeof(BZ2Compressor), /* tp_basicsize */
365 0, /* tp_itemsize */
366 (destructor)BZ2Compressor_dealloc, /* tp_dealloc */
367 0, /* tp_print */
368 0, /* tp_getattr */
369 0, /* tp_setattr */
370 0, /* tp_reserved */
371 0, /* tp_repr */
372 0, /* tp_as_number */
373 0, /* tp_as_sequence */
374 0, /* tp_as_mapping */
375 0, /* tp_hash */
376 0, /* tp_call */
377 0, /* tp_str */
378 0, /* tp_getattro */
379 0, /* tp_setattro */
380 0, /* tp_as_buffer */
381 Py_TPFLAGS_DEFAULT, /* tp_flags */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200382 _bz2_BZ2Compressor___init____doc__, /* tp_doc */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200383 0, /* tp_traverse */
384 0, /* tp_clear */
385 0, /* tp_richcompare */
386 0, /* tp_weaklistoffset */
387 0, /* tp_iter */
388 0, /* tp_iternext */
389 BZ2Compressor_methods, /* tp_methods */
390 0, /* tp_members */
391 0, /* tp_getset */
392 0, /* tp_base */
393 0, /* tp_dict */
394 0, /* tp_descr_get */
395 0, /* tp_descr_set */
396 0, /* tp_dictoffset */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200397 _bz2_BZ2Compressor___init__, /* tp_init */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200398 0, /* tp_alloc */
399 PyType_GenericNew, /* tp_new */
400};
401
402
403/* BZ2Decompressor class. */
404
405static PyObject *
406decompress(BZ2Decompressor *d, char *data, size_t len)
407{
408 size_t data_size = 0;
409 PyObject *result;
410
411 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
412 if (result == NULL)
413 return result;
414 d->bzs.next_in = data;
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200415 /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
416 Do decompression in chunks of no more than UINT_MAX bytes each. */
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200417 d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200418 len -= d->bzs.avail_in;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200419 d->bzs.next_out = PyBytes_AS_STRING(result);
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200420 d->bzs.avail_out = SMALLCHUNK;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200421 for (;;) {
422 char *this_out;
423 int bzerror;
424
425 Py_BEGIN_ALLOW_THREADS
426 this_out = d->bzs.next_out;
427 bzerror = BZ2_bzDecompress(&d->bzs);
428 data_size += d->bzs.next_out - this_out;
429 Py_END_ALLOW_THREADS
430 if (catch_bz2_error(bzerror))
431 goto error;
432 if (bzerror == BZ_STREAM_END) {
433 d->eof = 1;
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200434 len += d->bzs.avail_in;
435 if (len > 0) { /* Save leftover input to unused_data */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200436 Py_CLEAR(d->unused_data);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200437 d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, len);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200438 if (d->unused_data == NULL)
439 goto error;
440 }
441 break;
442 }
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200443 if (d->bzs.avail_in == 0) {
444 if (len == 0)
445 break;
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200446 d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200447 len -= d->bzs.avail_in;
448 }
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200449 if (d->bzs.avail_out == 0) {
Nadeem Vawda18b7fcc2012-10-21 21:16:58 +0200450 size_t buffer_left = PyBytes_GET_SIZE(result) - data_size;
451 if (buffer_left == 0) {
452 if (grow_buffer(&result) < 0)
453 goto error;
454 d->bzs.next_out = PyBytes_AS_STRING(result) + data_size;
455 buffer_left = PyBytes_GET_SIZE(result) - data_size;
456 }
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200457 d->bzs.avail_out = (unsigned int)Py_MIN(buffer_left, UINT_MAX);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200458 }
459 }
460 if (data_size != PyBytes_GET_SIZE(result))
461 if (_PyBytes_Resize(&result, data_size) < 0)
462 goto error;
463 return result;
464
465error:
466 Py_XDECREF(result);
467 return NULL;
468}
469
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200470/*[clinic input]
471_bz2.BZ2Decompressor.decompress
472
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200473 data: Py_buffer
474 /
475
476Provide data to the decompressor object.
477
478Returns a chunk of decompressed data if possible, or b'' otherwise.
479
480Attempting to decompress data after the end of stream is reached
481raises an EOFError. Any data found after the end of the stream
482is ignored and saved in the unused_data attribute.
483[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200484
485static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200486_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data)
Larry Hastings581ee362014-01-28 05:00:08 -0800487/*[clinic end generated code: output=086e4b99e60cb3f6 input=616c2a6db5269961]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200488{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200489 PyObject *result = NULL;
490
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200491 ACQUIRE_LOCK(self);
492 if (self->eof)
493 PyErr_SetString(PyExc_EOFError, "End of stream already reached");
494 else
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200495 result = decompress(self, data->buf, data->len);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200496 RELEASE_LOCK(self);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200497 return result;
498}
499
Nadeem Vawda37970652013-10-28 21:35:23 +0100500static PyObject *
501BZ2Decompressor_getstate(BZ2Decompressor *self, PyObject *noargs)
502{
503 PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
504 Py_TYPE(self)->tp_name);
505 return NULL;
506}
507
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200508/*[clinic input]
509_bz2.BZ2Decompressor.__init__
510
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200511Create a decompressor object for decompressing data incrementally.
512
513For one-shot decompression, use the decompress() function instead.
514[clinic start generated code]*/
515
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200516static int
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200517_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
Larry Hastings581ee362014-01-28 05:00:08 -0800518/*[clinic end generated code: output=e4d2b9bb866ab8f1 input=95f6500dcda60088]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200519{
520 int bzerror;
521
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200522#ifdef WITH_THREAD
523 self->lock = PyThread_allocate_lock();
524 if (self->lock == NULL) {
525 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
526 return -1;
527 }
528#endif
529
530 self->unused_data = PyBytes_FromStringAndSize("", 0);
531 if (self->unused_data == NULL)
532 goto error;
533
534 bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0);
535 if (catch_bz2_error(bzerror))
536 goto error;
537
538 return 0;
539
540error:
541 Py_CLEAR(self->unused_data);
542#ifdef WITH_THREAD
543 PyThread_free_lock(self->lock);
544 self->lock = NULL;
545#endif
546 return -1;
547}
548
549static void
550BZ2Decompressor_dealloc(BZ2Decompressor *self)
551{
552 BZ2_bzDecompressEnd(&self->bzs);
553 Py_CLEAR(self->unused_data);
554#ifdef WITH_THREAD
555 if (self->lock != NULL)
556 PyThread_free_lock(self->lock);
557#endif
558 Py_TYPE(self)->tp_free((PyObject *)self);
559}
560
561static PyMethodDef BZ2Decompressor_methods[] = {
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200562 _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF
Nadeem Vawda37970652013-10-28 21:35:23 +0100563 {"__getstate__", (PyCFunction)BZ2Decompressor_getstate, METH_NOARGS},
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200564 {NULL}
565};
566
567PyDoc_STRVAR(BZ2Decompressor_eof__doc__,
568"True if the end-of-stream marker has been reached.");
569
570PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__,
571"Data found after the end of the compressed stream.");
572
573static PyMemberDef BZ2Decompressor_members[] = {
574 {"eof", T_BOOL, offsetof(BZ2Decompressor, eof),
575 READONLY, BZ2Decompressor_eof__doc__},
576 {"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data),
577 READONLY, BZ2Decompressor_unused_data__doc__},
578 {NULL}
579};
580
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200581static PyTypeObject BZ2Decompressor_Type = {
582 PyVarObject_HEAD_INIT(NULL, 0)
583 "_bz2.BZ2Decompressor", /* tp_name */
584 sizeof(BZ2Decompressor), /* tp_basicsize */
585 0, /* tp_itemsize */
586 (destructor)BZ2Decompressor_dealloc,/* tp_dealloc */
587 0, /* tp_print */
588 0, /* tp_getattr */
589 0, /* tp_setattr */
590 0, /* tp_reserved */
591 0, /* tp_repr */
592 0, /* tp_as_number */
593 0, /* tp_as_sequence */
594 0, /* tp_as_mapping */
595 0, /* tp_hash */
596 0, /* tp_call */
597 0, /* tp_str */
598 0, /* tp_getattro */
599 0, /* tp_setattro */
600 0, /* tp_as_buffer */
601 Py_TPFLAGS_DEFAULT, /* tp_flags */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200602 _bz2_BZ2Decompressor___init____doc__, /* tp_doc */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200603 0, /* tp_traverse */
604 0, /* tp_clear */
605 0, /* tp_richcompare */
606 0, /* tp_weaklistoffset */
607 0, /* tp_iter */
608 0, /* tp_iternext */
609 BZ2Decompressor_methods, /* tp_methods */
610 BZ2Decompressor_members, /* tp_members */
611 0, /* tp_getset */
612 0, /* tp_base */
613 0, /* tp_dict */
614 0, /* tp_descr_get */
615 0, /* tp_descr_set */
616 0, /* tp_dictoffset */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200617 _bz2_BZ2Decompressor___init__, /* tp_init */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200618 0, /* tp_alloc */
619 PyType_GenericNew, /* tp_new */
620};
621
622
623/* Module initialization. */
624
625static struct PyModuleDef _bz2module = {
626 PyModuleDef_HEAD_INIT,
627 "_bz2",
628 NULL,
629 -1,
630 NULL,
631 NULL,
632 NULL,
633 NULL,
634 NULL
635};
636
637PyMODINIT_FUNC
638PyInit__bz2(void)
639{
640 PyObject *m;
641
642 if (PyType_Ready(&BZ2Compressor_Type) < 0)
643 return NULL;
644 if (PyType_Ready(&BZ2Decompressor_Type) < 0)
645 return NULL;
646
647 m = PyModule_Create(&_bz2module);
648 if (m == NULL)
649 return NULL;
650
651 Py_INCREF(&BZ2Compressor_Type);
652 PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Compressor_Type);
653
654 Py_INCREF(&BZ2Decompressor_Type);
655 PyModule_AddObject(m, "BZ2Decompressor",
656 (PyObject *)&BZ2Decompressor_Type);
657
658 return m;
659}