blob: 30e034046ce4ab1857f3ac409b3f6b02c49e68ac [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
Larry Hastingsc2047262014-01-25 20:43:29 -0800202class _bz2.BZ2Compressor "BZ2Compressor *" "&BZ2Compressor_Type"
203class _bz2.BZ2Decompressor "BZ2Decompressor *" "&BZ2Decompressor_Type"
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200204[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
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200212 data: Py_buffer
213 /
214
215Provide data to the compressor object.
216
217Returns a chunk of compressed data if possible, or b'' otherwise.
218
219When you have finished providing data to the compressor, call the
220flush() method to finish the compression process.
221[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200222
223static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200224_bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data)
225/*[clinic end generated code: checksum=59365426e941fbcc4c7a4d0eef85ca7e19196eaa]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200226{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200227 PyObject *result = NULL;
228
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200229 ACQUIRE_LOCK(self);
230 if (self->flushed)
231 PyErr_SetString(PyExc_ValueError, "Compressor has been flushed");
232 else
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200233 result = compress(self, data->buf, data->len, BZ_RUN);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200234 RELEASE_LOCK(self);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200235 return result;
236}
237
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200238/*[clinic input]
239_bz2.BZ2Compressor.flush
240
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200241Finish the compression process.
242
243Returns the compressed data left in internal buffers.
244
245The compressor object may not be used after this method is called.
246[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200247
248static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200249_bz2_BZ2Compressor_flush_impl(BZ2Compressor *self)
250/*[clinic end generated code: checksum=3ef03fc1b092a701b382b97096c7fd50db87190b]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200251{
252 PyObject *result = NULL;
253
254 ACQUIRE_LOCK(self);
255 if (self->flushed)
256 PyErr_SetString(PyExc_ValueError, "Repeated call to flush()");
257 else {
258 self->flushed = 1;
259 result = compress(self, NULL, 0, BZ_FINISH);
260 }
261 RELEASE_LOCK(self);
262 return result;
263}
264
Nadeem Vawda37970652013-10-28 21:35:23 +0100265static PyObject *
266BZ2Compressor_getstate(BZ2Compressor *self, PyObject *noargs)
267{
268 PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
269 Py_TYPE(self)->tp_name);
270 return NULL;
271}
272
Victor Stinner5064a522013-07-07 16:50:27 +0200273static void*
274BZ2_Malloc(void* ctx, int items, int size)
275{
276 if (items < 0 || size < 0)
277 return NULL;
278 if ((size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
279 return NULL;
280 /* PyMem_Malloc() cannot be used: compress() and decompress()
281 release the GIL */
282 return PyMem_RawMalloc(items * size);
283}
284
285static void
286BZ2_Free(void* ctx, void *ptr)
287{
Victor Stinnerb7f1f652013-07-07 17:10:34 +0200288 PyMem_RawFree(ptr);
Victor Stinner5064a522013-07-07 16:50:27 +0200289}
290
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200291/*[clinic input]
292_bz2.BZ2Compressor.__init__
293
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200294 compresslevel: int = 9
295 Compression level, as a number between 1 and 9.
296 /
297
298Create a compressor object for compressing data incrementally.
299
300For one-shot compression, use the compress() function instead.
301[clinic start generated code]*/
302
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200303static int
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200304_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel)
305/*[clinic end generated code: checksum=c4e6adfd02963827075a1cc9309dc6df184b1246]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200306{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200307 int bzerror;
308
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200309 if (!(1 <= compresslevel && compresslevel <= 9)) {
310 PyErr_SetString(PyExc_ValueError,
311 "compresslevel must be between 1 and 9");
312 return -1;
313 }
314
315#ifdef WITH_THREAD
316 self->lock = PyThread_allocate_lock();
317 if (self->lock == NULL) {
318 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
319 return -1;
320 }
321#endif
322
Victor Stinner5064a522013-07-07 16:50:27 +0200323 self->bzs.opaque = NULL;
324 self->bzs.bzalloc = BZ2_Malloc;
325 self->bzs.bzfree = BZ2_Free;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200326 bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0);
327 if (catch_bz2_error(bzerror))
328 goto error;
329
330 return 0;
331
332error:
333#ifdef WITH_THREAD
334 PyThread_free_lock(self->lock);
335 self->lock = NULL;
336#endif
337 return -1;
338}
339
340static void
341BZ2Compressor_dealloc(BZ2Compressor *self)
342{
343 BZ2_bzCompressEnd(&self->bzs);
344#ifdef WITH_THREAD
345 if (self->lock != NULL)
346 PyThread_free_lock(self->lock);
347#endif
348 Py_TYPE(self)->tp_free((PyObject *)self);
349}
350
351static PyMethodDef BZ2Compressor_methods[] = {
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200352 _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF
353 _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF
Nadeem Vawda37970652013-10-28 21:35:23 +0100354 {"__getstate__", (PyCFunction)BZ2Compressor_getstate, METH_NOARGS},
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200355 {NULL}
356};
357
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200358
359static PyTypeObject BZ2Compressor_Type = {
360 PyVarObject_HEAD_INIT(NULL, 0)
361 "_bz2.BZ2Compressor", /* tp_name */
362 sizeof(BZ2Compressor), /* tp_basicsize */
363 0, /* tp_itemsize */
364 (destructor)BZ2Compressor_dealloc, /* tp_dealloc */
365 0, /* tp_print */
366 0, /* tp_getattr */
367 0, /* tp_setattr */
368 0, /* tp_reserved */
369 0, /* tp_repr */
370 0, /* tp_as_number */
371 0, /* tp_as_sequence */
372 0, /* tp_as_mapping */
373 0, /* tp_hash */
374 0, /* tp_call */
375 0, /* tp_str */
376 0, /* tp_getattro */
377 0, /* tp_setattro */
378 0, /* tp_as_buffer */
379 Py_TPFLAGS_DEFAULT, /* tp_flags */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200380 _bz2_BZ2Compressor___init____doc__, /* tp_doc */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200381 0, /* tp_traverse */
382 0, /* tp_clear */
383 0, /* tp_richcompare */
384 0, /* tp_weaklistoffset */
385 0, /* tp_iter */
386 0, /* tp_iternext */
387 BZ2Compressor_methods, /* tp_methods */
388 0, /* tp_members */
389 0, /* tp_getset */
390 0, /* tp_base */
391 0, /* tp_dict */
392 0, /* tp_descr_get */
393 0, /* tp_descr_set */
394 0, /* tp_dictoffset */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200395 _bz2_BZ2Compressor___init__, /* tp_init */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200396 0, /* tp_alloc */
397 PyType_GenericNew, /* tp_new */
398};
399
400
401/* BZ2Decompressor class. */
402
403static PyObject *
404decompress(BZ2Decompressor *d, char *data, size_t len)
405{
406 size_t data_size = 0;
407 PyObject *result;
408
409 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
410 if (result == NULL)
411 return result;
412 d->bzs.next_in = data;
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200413 /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
414 Do decompression in chunks of no more than UINT_MAX bytes each. */
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200415 d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200416 len -= d->bzs.avail_in;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200417 d->bzs.next_out = PyBytes_AS_STRING(result);
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200418 d->bzs.avail_out = SMALLCHUNK;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200419 for (;;) {
420 char *this_out;
421 int bzerror;
422
423 Py_BEGIN_ALLOW_THREADS
424 this_out = d->bzs.next_out;
425 bzerror = BZ2_bzDecompress(&d->bzs);
426 data_size += d->bzs.next_out - this_out;
427 Py_END_ALLOW_THREADS
428 if (catch_bz2_error(bzerror))
429 goto error;
430 if (bzerror == BZ_STREAM_END) {
431 d->eof = 1;
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200432 len += d->bzs.avail_in;
433 if (len > 0) { /* Save leftover input to unused_data */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200434 Py_CLEAR(d->unused_data);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200435 d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, len);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200436 if (d->unused_data == NULL)
437 goto error;
438 }
439 break;
440 }
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200441 if (d->bzs.avail_in == 0) {
442 if (len == 0)
443 break;
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200444 d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200445 len -= d->bzs.avail_in;
446 }
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200447 if (d->bzs.avail_out == 0) {
Nadeem Vawda18b7fcc2012-10-21 21:16:58 +0200448 size_t buffer_left = PyBytes_GET_SIZE(result) - data_size;
449 if (buffer_left == 0) {
450 if (grow_buffer(&result) < 0)
451 goto error;
452 d->bzs.next_out = PyBytes_AS_STRING(result) + data_size;
453 buffer_left = PyBytes_GET_SIZE(result) - data_size;
454 }
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200455 d->bzs.avail_out = (unsigned int)Py_MIN(buffer_left, UINT_MAX);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200456 }
457 }
458 if (data_size != PyBytes_GET_SIZE(result))
459 if (_PyBytes_Resize(&result, data_size) < 0)
460 goto error;
461 return result;
462
463error:
464 Py_XDECREF(result);
465 return NULL;
466}
467
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200468/*[clinic input]
469_bz2.BZ2Decompressor.decompress
470
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200471 data: Py_buffer
472 /
473
474Provide data to the decompressor object.
475
476Returns a chunk of decompressed data if possible, or b'' otherwise.
477
478Attempting to decompress data after the end of stream is reached
479raises an EOFError. Any data found after the end of the stream
480is ignored and saved in the unused_data attribute.
481[clinic start generated code]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200482
483static PyObject *
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200484_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data)
485/*[clinic end generated code: checksum=086e4b99e60cb3f67c0481959591eae0735320bc]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200486{
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200487 PyObject *result = NULL;
488
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200489 ACQUIRE_LOCK(self);
490 if (self->eof)
491 PyErr_SetString(PyExc_EOFError, "End of stream already reached");
492 else
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200493 result = decompress(self, data->buf, data->len);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200494 RELEASE_LOCK(self);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200495 return result;
496}
497
Nadeem Vawda37970652013-10-28 21:35:23 +0100498static PyObject *
499BZ2Decompressor_getstate(BZ2Decompressor *self, PyObject *noargs)
500{
501 PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
502 Py_TYPE(self)->tp_name);
503 return NULL;
504}
505
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200506/*[clinic input]
507_bz2.BZ2Decompressor.__init__
508
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200509Create a decompressor object for decompressing data incrementally.
510
511For one-shot decompression, use the decompress() function instead.
512[clinic start generated code]*/
513
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200514static int
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200515_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self)
516/*[clinic end generated code: checksum=e4d2b9bb866ab8f1f4a8bb786ddb5b614ce323c0]*/
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200517{
518 int bzerror;
519
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200520#ifdef WITH_THREAD
521 self->lock = PyThread_allocate_lock();
522 if (self->lock == NULL) {
523 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
524 return -1;
525 }
526#endif
527
528 self->unused_data = PyBytes_FromStringAndSize("", 0);
529 if (self->unused_data == NULL)
530 goto error;
531
532 bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0);
533 if (catch_bz2_error(bzerror))
534 goto error;
535
536 return 0;
537
538error:
539 Py_CLEAR(self->unused_data);
540#ifdef WITH_THREAD
541 PyThread_free_lock(self->lock);
542 self->lock = NULL;
543#endif
544 return -1;
545}
546
547static void
548BZ2Decompressor_dealloc(BZ2Decompressor *self)
549{
550 BZ2_bzDecompressEnd(&self->bzs);
551 Py_CLEAR(self->unused_data);
552#ifdef WITH_THREAD
553 if (self->lock != NULL)
554 PyThread_free_lock(self->lock);
555#endif
556 Py_TYPE(self)->tp_free((PyObject *)self);
557}
558
559static PyMethodDef BZ2Decompressor_methods[] = {
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200560 _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF
Nadeem Vawda37970652013-10-28 21:35:23 +0100561 {"__getstate__", (PyCFunction)BZ2Decompressor_getstate, METH_NOARGS},
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200562 {NULL}
563};
564
565PyDoc_STRVAR(BZ2Decompressor_eof__doc__,
566"True if the end-of-stream marker has been reached.");
567
568PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__,
569"Data found after the end of the compressed stream.");
570
571static PyMemberDef BZ2Decompressor_members[] = {
572 {"eof", T_BOOL, offsetof(BZ2Decompressor, eof),
573 READONLY, BZ2Decompressor_eof__doc__},
574 {"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data),
575 READONLY, BZ2Decompressor_unused_data__doc__},
576 {NULL}
577};
578
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200579static PyTypeObject BZ2Decompressor_Type = {
580 PyVarObject_HEAD_INIT(NULL, 0)
581 "_bz2.BZ2Decompressor", /* tp_name */
582 sizeof(BZ2Decompressor), /* tp_basicsize */
583 0, /* tp_itemsize */
584 (destructor)BZ2Decompressor_dealloc,/* tp_dealloc */
585 0, /* tp_print */
586 0, /* tp_getattr */
587 0, /* tp_setattr */
588 0, /* tp_reserved */
589 0, /* tp_repr */
590 0, /* tp_as_number */
591 0, /* tp_as_sequence */
592 0, /* tp_as_mapping */
593 0, /* tp_hash */
594 0, /* tp_call */
595 0, /* tp_str */
596 0, /* tp_getattro */
597 0, /* tp_setattro */
598 0, /* tp_as_buffer */
599 Py_TPFLAGS_DEFAULT, /* tp_flags */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200600 _bz2_BZ2Decompressor___init____doc__, /* tp_doc */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200601 0, /* tp_traverse */
602 0, /* tp_clear */
603 0, /* tp_richcompare */
604 0, /* tp_weaklistoffset */
605 0, /* tp_iter */
606 0, /* tp_iternext */
607 BZ2Decompressor_methods, /* tp_methods */
608 BZ2Decompressor_members, /* tp_members */
609 0, /* tp_getset */
610 0, /* tp_base */
611 0, /* tp_dict */
612 0, /* tp_descr_get */
613 0, /* tp_descr_set */
614 0, /* tp_dictoffset */
Serhiy Storchaka1bc4bb22014-01-25 12:07:57 +0200615 _bz2_BZ2Decompressor___init__, /* tp_init */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200616 0, /* tp_alloc */
617 PyType_GenericNew, /* tp_new */
618};
619
620
621/* Module initialization. */
622
623static struct PyModuleDef _bz2module = {
624 PyModuleDef_HEAD_INIT,
625 "_bz2",
626 NULL,
627 -1,
628 NULL,
629 NULL,
630 NULL,
631 NULL,
632 NULL
633};
634
635PyMODINIT_FUNC
636PyInit__bz2(void)
637{
638 PyObject *m;
639
640 if (PyType_Ready(&BZ2Compressor_Type) < 0)
641 return NULL;
642 if (PyType_Ready(&BZ2Decompressor_Type) < 0)
643 return NULL;
644
645 m = PyModule_Create(&_bz2module);
646 if (m == NULL)
647 return NULL;
648
649 Py_INCREF(&BZ2Compressor_Type);
650 PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Compressor_Type);
651
652 Py_INCREF(&BZ2Decompressor_Type);
653 PyModule_AddObject(m, "BZ2Decompressor",
654 (PyObject *)&BZ2Decompressor_Type);
655
656 return m;
657}