blob: cdaa837ff04dc8c3adf38e0fa202780547098af4 [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
59
60/* Helper functions. */
61
62static int
63catch_bz2_error(int bzerror)
64{
65 switch(bzerror) {
66 case BZ_OK:
67 case BZ_RUN_OK:
68 case BZ_FLUSH_OK:
69 case BZ_FINISH_OK:
70 case BZ_STREAM_END:
71 return 0;
72
73#ifdef BZ_CONFIG_ERROR
74 case BZ_CONFIG_ERROR:
75 PyErr_SetString(PyExc_SystemError,
76 "libbzip2 was not compiled correctly");
77 return 1;
78#endif
79 case BZ_PARAM_ERROR:
80 PyErr_SetString(PyExc_ValueError,
81 "Internal error - "
82 "invalid parameters passed to libbzip2");
83 return 1;
84 case BZ_MEM_ERROR:
85 PyErr_NoMemory();
86 return 1;
87 case BZ_DATA_ERROR:
88 case BZ_DATA_ERROR_MAGIC:
89 PyErr_SetString(PyExc_IOError, "Invalid data stream");
90 return 1;
91 case BZ_IO_ERROR:
92 PyErr_SetString(PyExc_IOError, "Unknown I/O error");
93 return 1;
94 case BZ_UNEXPECTED_EOF:
95 PyErr_SetString(PyExc_EOFError,
96 "Compressed file ended before the logical "
97 "end-of-stream was detected");
98 return 1;
99 case BZ_SEQUENCE_ERROR:
100 PyErr_SetString(PyExc_RuntimeError,
101 "Internal error - "
102 "Invalid sequence of commands sent to libbzip2");
103 return 1;
104 default:
105 PyErr_Format(PyExc_IOError,
106 "Unrecognized error from libbzip2: %d", bzerror);
107 return 1;
108 }
109}
110
111#if BUFSIZ < 8192
112#define SMALLCHUNK 8192
113#else
114#define SMALLCHUNK BUFSIZ
115#endif
116
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200117static int
118grow_buffer(PyObject **buf)
119{
Nadeem Vawda72d6a132011-10-13 13:38:14 +0200120 /* Expand the buffer by an amount proportional to the current size,
121 giving us amortized linear-time behavior. Use a less-than-double
122 growth factor to avoid excessive allocation. */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200123 size_t size = PyBytes_GET_SIZE(*buf);
Nadeem Vawda18b7fcc2012-10-21 21:16:58 +0200124 size_t new_size = size + (size >> 3) + 6;
125 if (new_size > size) {
126 return _PyBytes_Resize(buf, new_size);
127 } else { /* overflow */
128 PyErr_SetString(PyExc_OverflowError,
129 "Unable to allocate buffer - output too large");
130 return -1;
131 }
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200132}
133
134
135/* BZ2Compressor class. */
136
137static PyObject *
138compress(BZ2Compressor *c, char *data, size_t len, int action)
139{
140 size_t data_size = 0;
141 PyObject *result;
142
143 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
144 if (result == NULL)
145 return NULL;
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100146
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200147 c->bzs.next_in = data;
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100148 c->bzs.avail_in = 0;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200149 c->bzs.next_out = PyBytes_AS_STRING(result);
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200150 c->bzs.avail_out = SMALLCHUNK;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200151 for (;;) {
152 char *this_out;
153 int bzerror;
154
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100155 /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
156 Do compression in chunks of no more than UINT_MAX bytes each. */
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200157 if (c->bzs.avail_in == 0 && len > 0) {
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200158 c->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200159 len -= c->bzs.avail_in;
160 }
161
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100162 /* In regular compression mode, stop when input data is exhausted. */
163 if (action == BZ_RUN && c->bzs.avail_in == 0)
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200164 break;
165
166 if (c->bzs.avail_out == 0) {
Nadeem Vawda18b7fcc2012-10-21 21:16:58 +0200167 size_t buffer_left = PyBytes_GET_SIZE(result) - data_size;
168 if (buffer_left == 0) {
169 if (grow_buffer(&result) < 0)
170 goto error;
171 c->bzs.next_out = PyBytes_AS_STRING(result) + data_size;
172 buffer_left = PyBytes_GET_SIZE(result) - data_size;
173 }
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200174 c->bzs.avail_out = (unsigned int)Py_MIN(buffer_left, UINT_MAX);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200175 }
Nadeem Vawda57cb81d2013-01-02 23:05:56 +0100176
177 Py_BEGIN_ALLOW_THREADS
178 this_out = c->bzs.next_out;
179 bzerror = BZ2_bzCompress(&c->bzs, action);
180 data_size += c->bzs.next_out - this_out;
181 Py_END_ALLOW_THREADS
182 if (catch_bz2_error(bzerror))
183 goto error;
184
185 /* In flushing mode, stop when all buffered data has been flushed. */
186 if (action == BZ_FINISH && bzerror == BZ_STREAM_END)
187 break;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200188 }
189 if (data_size != PyBytes_GET_SIZE(result))
190 if (_PyBytes_Resize(&result, data_size) < 0)
191 goto error;
192 return result;
193
194error:
195 Py_XDECREF(result);
196 return NULL;
197}
198
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200199/*[clinic input]
200output preset file
201module _bz2
202class _bz2.BZ2Compressor
203class _bz2.BZ2Decompressor
204[clinic start generated code]*/
205/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
206
207#include "_bz2module.clinic.c"
208
209/*[clinic input]
210_bz2.BZ2Compressor.compress
211
212 self: self(type="BZ2Compressor *")
213 data: Py_buffer
214 /
215
216Provide data to the compressor object.
217
218Returns a chunk of compressed data if possible, or b'' otherwise.
219
220When you have finished providing data to the compressor, call the
221flush() method to finish the compression process.
222[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200223
224static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200225_bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data)
226/*[clinic end generated code: checksum=59365426e941fbcc4c7a4d0eef85ca7e19196eaa]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200227{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200228 PyObject *result = NULL;
229
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200230 ACQUIRE_LOCK(self);
231 if (self->flushed)
232 PyErr_SetString(PyExc_ValueError, "Compressor has been flushed");
233 else
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200234 result = compress(self, data->buf, data->len, BZ_RUN);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200235 RELEASE_LOCK(self);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200236 return result;
237}
238
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200239/*[clinic input]
240_bz2.BZ2Compressor.flush
241
242 self: self(type="BZ2Compressor *")
243
244Finish the compression process.
245
246Returns the compressed data left in internal buffers.
247
248The compressor object may not be used after this method is called.
249[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200250
251static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200252_bz2_BZ2Compressor_flush_impl(BZ2Compressor *self)
253/*[clinic end generated code: checksum=3ef03fc1b092a701b382b97096c7fd50db87190b]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200254{
255 PyObject *result = NULL;
256
257 ACQUIRE_LOCK(self);
258 if (self->flushed)
259 PyErr_SetString(PyExc_ValueError, "Repeated call to flush()");
260 else {
261 self->flushed = 1;
262 result = compress(self, NULL, 0, BZ_FINISH);
263 }
264 RELEASE_LOCK(self);
265 return result;
266}
267
Nadeem Vawda37970652013-10-28 21:35:23 +0100268static PyObject *
269BZ2Compressor_getstate(BZ2Compressor *self, PyObject *noargs)
270{
271 PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
272 Py_TYPE(self)->tp_name);
273 return NULL;
274}
275
Victor Stinner5064a522013-07-07 16:50:27 +0200276static void*
277BZ2_Malloc(void* ctx, int items, int size)
278{
279 if (items < 0 || size < 0)
280 return NULL;
281 if ((size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
282 return NULL;
283 /* PyMem_Malloc() cannot be used: compress() and decompress()
284 release the GIL */
285 return PyMem_RawMalloc(items * size);
286}
287
288static void
289BZ2_Free(void* ctx, void *ptr)
290{
Victor Stinnerb7f1f652013-07-07 17:10:34 +0200291 PyMem_RawFree(ptr);
Victor Stinner5064a522013-07-07 16:50:27 +0200292}
293
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200294/*[clinic input]
295_bz2.BZ2Compressor.__init__
296
297 self: self(type="BZ2Compressor *")
298 compresslevel: int = 9
299 Compression level, as a number between 1 and 9.
300 /
301
302Create a compressor object for compressing data incrementally.
303
304For one-shot compression, use the compress() function instead.
305[clinic start generated code]*/
306
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200307static int
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200308_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
309/*[clinic end generated code: checksum=c4e6adfd02963827075a1cc9309dc6df184b1246]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200310{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200311 int bzerror;
312
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200313 if (!(1 <= compresslevel && compresslevel <= 9)) {
314 PyErr_SetString(PyExc_ValueError,
315 "compresslevel must be between 1 and 9");
316 return -1;
317 }
318
319#ifdef WITH_THREAD
320 self->lock = PyThread_allocate_lock();
321 if (self->lock == NULL) {
322 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
323 return -1;
324 }
325#endif
326
Victor Stinner5064a522013-07-07 16:50:27 +0200327 self->bzs.opaque = NULL;
328 self->bzs.bzalloc = BZ2_Malloc;
329 self->bzs.bzfree = BZ2_Free;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200330 bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0);
331 if (catch_bz2_error(bzerror))
332 goto error;
333
334 return 0;
335
336error:
337#ifdef WITH_THREAD
338 PyThread_free_lock(self->lock);
339 self->lock = NULL;
340#endif
341 return -1;
342}
343
344static void
345BZ2Compressor_dealloc(BZ2Compressor *self)
346{
347 BZ2_bzCompressEnd(&self->bzs);
348#ifdef WITH_THREAD
349 if (self->lock != NULL)
350 PyThread_free_lock(self->lock);
351#endif
352 Py_TYPE(self)->tp_free((PyObject *)self);
353}
354
355static PyMethodDef BZ2Compressor_methods[] = {
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200356 _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF
357 _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF
Nadeem Vawda37970652013-10-28 21:35:23 +0100358 {"__getstate__", (PyCFunction)BZ2Compressor_getstate, METH_NOARGS},
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200359 {NULL}
360};
361
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200362
363static PyTypeObject BZ2Compressor_Type = {
364 PyVarObject_HEAD_INIT(NULL, 0)
365 "_bz2.BZ2Compressor", /* tp_name */
366 sizeof(BZ2Compressor), /* tp_basicsize */
367 0, /* tp_itemsize */
368 (destructor)BZ2Compressor_dealloc, /* tp_dealloc */
369 0, /* tp_print */
370 0, /* tp_getattr */
371 0, /* tp_setattr */
372 0, /* tp_reserved */
373 0, /* tp_repr */
374 0, /* tp_as_number */
375 0, /* tp_as_sequence */
376 0, /* tp_as_mapping */
377 0, /* tp_hash */
378 0, /* tp_call */
379 0, /* tp_str */
380 0, /* tp_getattro */
381 0, /* tp_setattro */
382 0, /* tp_as_buffer */
383 Py_TPFLAGS_DEFAULT, /* tp_flags */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200384 _bz2_BZ2Compressor___init____doc__, /* tp_doc */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200385 0, /* tp_traverse */
386 0, /* tp_clear */
387 0, /* tp_richcompare */
388 0, /* tp_weaklistoffset */
389 0, /* tp_iter */
390 0, /* tp_iternext */
391 BZ2Compressor_methods, /* tp_methods */
392 0, /* tp_members */
393 0, /* tp_getset */
394 0, /* tp_base */
395 0, /* tp_dict */
396 0, /* tp_descr_get */
397 0, /* tp_descr_set */
398 0, /* tp_dictoffset */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200399 _bz2_BZ2Compressor___init__, /* tp_init */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200400 0, /* tp_alloc */
401 PyType_GenericNew, /* tp_new */
402};
403
404
405/* BZ2Decompressor class. */
406
407static PyObject *
408decompress(BZ2Decompressor *d, char *data, size_t len)
409{
410 size_t data_size = 0;
411 PyObject *result;
412
413 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
414 if (result == NULL)
415 return result;
416 d->bzs.next_in = data;
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200417 /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
418 Do decompression in chunks of no more than UINT_MAX bytes each. */
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200419 d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200420 len -= d->bzs.avail_in;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200421 d->bzs.next_out = PyBytes_AS_STRING(result);
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200422 d->bzs.avail_out = SMALLCHUNK;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200423 for (;;) {
424 char *this_out;
425 int bzerror;
426
427 Py_BEGIN_ALLOW_THREADS
428 this_out = d->bzs.next_out;
429 bzerror = BZ2_bzDecompress(&d->bzs);
430 data_size += d->bzs.next_out - this_out;
431 Py_END_ALLOW_THREADS
432 if (catch_bz2_error(bzerror))
433 goto error;
434 if (bzerror == BZ_STREAM_END) {
435 d->eof = 1;
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200436 len += d->bzs.avail_in;
437 if (len > 0) { /* Save leftover input to unused_data */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200438 Py_CLEAR(d->unused_data);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200439 d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, len);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200440 if (d->unused_data == NULL)
441 goto error;
442 }
443 break;
444 }
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200445 if (d->bzs.avail_in == 0) {
446 if (len == 0)
447 break;
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200448 d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200449 len -= d->bzs.avail_in;
450 }
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200451 if (d->bzs.avail_out == 0) {
Nadeem Vawda18b7fcc2012-10-21 21:16:58 +0200452 size_t buffer_left = PyBytes_GET_SIZE(result) - data_size;
453 if (buffer_left == 0) {
454 if (grow_buffer(&result) < 0)
455 goto error;
456 d->bzs.next_out = PyBytes_AS_STRING(result) + data_size;
457 buffer_left = PyBytes_GET_SIZE(result) - data_size;
458 }
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200459 d->bzs.avail_out = (unsigned int)Py_MIN(buffer_left, UINT_MAX);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200460 }
461 }
462 if (data_size != PyBytes_GET_SIZE(result))
463 if (_PyBytes_Resize(&result, data_size) < 0)
464 goto error;
465 return result;
466
467error:
468 Py_XDECREF(result);
469 return NULL;
470}
471
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200472/*[clinic input]
473_bz2.BZ2Decompressor.decompress
474
475 self: self(type="BZ2Decompressor *")
476 data: Py_buffer
477 /
478
479Provide data to the decompressor object.
480
481Returns a chunk of decompressed data if possible, or b'' otherwise.
482
483Attempting to decompress data after the end of stream is reached
484raises an EOFError. Any data found after the end of the stream
485is ignored and saved in the unused_data attribute.
486[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200487
488static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200489_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data)
490/*[clinic end generated code: checksum=086e4b99e60cb3f67c0481959591eae0735320bc]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200491{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200492 PyObject *result = NULL;
493
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200494 ACQUIRE_LOCK(self);
495 if (self->eof)
496 PyErr_SetString(PyExc_EOFError, "End of stream already reached");
497 else
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200498 result = decompress(self, data->buf, data->len);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200499 RELEASE_LOCK(self);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200500 return result;
501}
502
Nadeem Vawda37970652013-10-28 21:35:23 +0100503static PyObject *
504BZ2Decompressor_getstate(BZ2Decompressor *self, PyObject *noargs)
505{
506 PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
507 Py_TYPE(self)->tp_name);
508 return NULL;
509}
510
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200511/*[clinic input]
512_bz2.BZ2Decompressor.__init__
513
514 self: self(type="BZ2Decompressor *")
515
516Create a decompressor object for decompressing data incrementally.
517
518For one-shot decompression, use the decompress() function instead.
519[clinic start generated code]*/
520
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200521static int
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200522_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
523/*[clinic end generated code: checksum=e4d2b9bb866ab8f1f4a8bb786ddb5b614ce323c0]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200524{
525 int bzerror;
526
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200527#ifdef WITH_THREAD
528 self->lock = PyThread_allocate_lock();
529 if (self->lock == NULL) {
530 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
531 return -1;
532 }
533#endif
534
535 self->unused_data = PyBytes_FromStringAndSize("", 0);
536 if (self->unused_data == NULL)
537 goto error;
538
539 bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0);
540 if (catch_bz2_error(bzerror))
541 goto error;
542
543 return 0;
544
545error:
546 Py_CLEAR(self->unused_data);
547#ifdef WITH_THREAD
548 PyThread_free_lock(self->lock);
549 self->lock = NULL;
550#endif
551 return -1;
552}
553
554static void
555BZ2Decompressor_dealloc(BZ2Decompressor *self)
556{
557 BZ2_bzDecompressEnd(&self->bzs);
558 Py_CLEAR(self->unused_data);
559#ifdef WITH_THREAD
560 if (self->lock != NULL)
561 PyThread_free_lock(self->lock);
562#endif
563 Py_TYPE(self)->tp_free((PyObject *)self);
564}
565
566static PyMethodDef BZ2Decompressor_methods[] = {
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200567 _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF
Nadeem Vawda37970652013-10-28 21:35:23 +0100568 {"__getstate__", (PyCFunction)BZ2Decompressor_getstate, METH_NOARGS},
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200569 {NULL}
570};
571
572PyDoc_STRVAR(BZ2Decompressor_eof__doc__,
573"True if the end-of-stream marker has been reached.");
574
575PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__,
576"Data found after the end of the compressed stream.");
577
578static PyMemberDef BZ2Decompressor_members[] = {
579 {"eof", T_BOOL, offsetof(BZ2Decompressor, eof),
580 READONLY, BZ2Decompressor_eof__doc__},
581 {"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data),
582 READONLY, BZ2Decompressor_unused_data__doc__},
583 {NULL}
584};
585
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200586static PyTypeObject BZ2Decompressor_Type = {
587 PyVarObject_HEAD_INIT(NULL, 0)
588 "_bz2.BZ2Decompressor", /* tp_name */
589 sizeof(BZ2Decompressor), /* tp_basicsize */
590 0, /* tp_itemsize */
591 (destructor)BZ2Decompressor_dealloc,/* tp_dealloc */
592 0, /* tp_print */
593 0, /* tp_getattr */
594 0, /* tp_setattr */
595 0, /* tp_reserved */
596 0, /* tp_repr */
597 0, /* tp_as_number */
598 0, /* tp_as_sequence */
599 0, /* tp_as_mapping */
600 0, /* tp_hash */
601 0, /* tp_call */
602 0, /* tp_str */
603 0, /* tp_getattro */
604 0, /* tp_setattro */
605 0, /* tp_as_buffer */
606 Py_TPFLAGS_DEFAULT, /* tp_flags */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200607 _bz2_BZ2Decompressor___init____doc__, /* tp_doc */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200608 0, /* tp_traverse */
609 0, /* tp_clear */
610 0, /* tp_richcompare */
611 0, /* tp_weaklistoffset */
612 0, /* tp_iter */
613 0, /* tp_iternext */
614 BZ2Decompressor_methods, /* tp_methods */
615 BZ2Decompressor_members, /* tp_members */
616 0, /* tp_getset */
617 0, /* tp_base */
618 0, /* tp_dict */
619 0, /* tp_descr_get */
620 0, /* tp_descr_set */
621 0, /* tp_dictoffset */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200622 _bz2_BZ2Decompressor___init__, /* tp_init */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200623 0, /* tp_alloc */
624 PyType_GenericNew, /* tp_new */
625};
626
627
628/* Module initialization. */
629
630static struct PyModuleDef _bz2module = {
631 PyModuleDef_HEAD_INIT,
632 "_bz2",
633 NULL,
634 -1,
635 NULL,
636 NULL,
637 NULL,
638 NULL,
639 NULL
640};
641
642PyMODINIT_FUNC
643PyInit__bz2(void)
644{
645 PyObject *m;
646
647 if (PyType_Ready(&BZ2Compressor_Type) < 0)
648 return NULL;
649 if (PyType_Ready(&BZ2Decompressor_Type) < 0)
650 return NULL;
651
652 m = PyModule_Create(&_bz2module);
653 if (m == NULL)
654 return NULL;
655
656 Py_INCREF(&BZ2Compressor_Type);
657 PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Compressor_Type);
658
659 Py_INCREF(&BZ2Decompressor_Type);
660 PyModule_AddObject(m, "BZ2Decompressor",
661 (PyObject *)&BZ2Decompressor_Type);
662
663 return m;
664}