blob: fd05de0a27c65b7307dbb3a50f154cf2ee47097a [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
199PyDoc_STRVAR(BZ2Compressor_compress__doc__,
200"compress(data) -> bytes\n"
201"\n"
202"Provide data to the compressor object. Returns a chunk of\n"
203"compressed data if possible, or b'' otherwise.\n"
204"\n"
205"When you have finished providing data to the compressor, call the\n"
206"flush() method to finish the compression process.\n");
207
208static PyObject *
209BZ2Compressor_compress(BZ2Compressor *self, PyObject *args)
210{
211 Py_buffer buffer;
212 PyObject *result = NULL;
213
214 if (!PyArg_ParseTuple(args, "y*:compress", &buffer))
215 return NULL;
216
217 ACQUIRE_LOCK(self);
218 if (self->flushed)
219 PyErr_SetString(PyExc_ValueError, "Compressor has been flushed");
220 else
221 result = compress(self, buffer.buf, buffer.len, BZ_RUN);
222 RELEASE_LOCK(self);
223 PyBuffer_Release(&buffer);
224 return result;
225}
226
227PyDoc_STRVAR(BZ2Compressor_flush__doc__,
228"flush() -> bytes\n"
229"\n"
230"Finish the compression process. Returns the compressed data left\n"
231"in internal buffers.\n"
232"\n"
233"The compressor object may not be used after this method is called.\n");
234
235static PyObject *
236BZ2Compressor_flush(BZ2Compressor *self, PyObject *noargs)
237{
238 PyObject *result = NULL;
239
240 ACQUIRE_LOCK(self);
241 if (self->flushed)
242 PyErr_SetString(PyExc_ValueError, "Repeated call to flush()");
243 else {
244 self->flushed = 1;
245 result = compress(self, NULL, 0, BZ_FINISH);
246 }
247 RELEASE_LOCK(self);
248 return result;
249}
250
Nadeem Vawda37970652013-10-28 21:35:23 +0100251static PyObject *
252BZ2Compressor_getstate(BZ2Compressor *self, PyObject *noargs)
253{
254 PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
255 Py_TYPE(self)->tp_name);
256 return NULL;
257}
258
Victor Stinner5064a522013-07-07 16:50:27 +0200259static void*
260BZ2_Malloc(void* ctx, int items, int size)
261{
262 if (items < 0 || size < 0)
263 return NULL;
264 if ((size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
265 return NULL;
266 /* PyMem_Malloc() cannot be used: compress() and decompress()
267 release the GIL */
268 return PyMem_RawMalloc(items * size);
269}
270
271static void
272BZ2_Free(void* ctx, void *ptr)
273{
Victor Stinnerb7f1f652013-07-07 17:10:34 +0200274 PyMem_RawFree(ptr);
Victor Stinner5064a522013-07-07 16:50:27 +0200275}
276
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200277static int
278BZ2Compressor_init(BZ2Compressor *self, PyObject *args, PyObject *kwargs)
279{
280 int compresslevel = 9;
281 int bzerror;
282
283 if (!PyArg_ParseTuple(args, "|i:BZ2Compressor", &compresslevel))
284 return -1;
285 if (!(1 <= compresslevel && compresslevel <= 9)) {
286 PyErr_SetString(PyExc_ValueError,
287 "compresslevel must be between 1 and 9");
288 return -1;
289 }
290
291#ifdef WITH_THREAD
292 self->lock = PyThread_allocate_lock();
293 if (self->lock == NULL) {
294 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
295 return -1;
296 }
297#endif
298
Victor Stinner5064a522013-07-07 16:50:27 +0200299 self->bzs.opaque = NULL;
300 self->bzs.bzalloc = BZ2_Malloc;
301 self->bzs.bzfree = BZ2_Free;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200302 bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0);
303 if (catch_bz2_error(bzerror))
304 goto error;
305
306 return 0;
307
308error:
309#ifdef WITH_THREAD
310 PyThread_free_lock(self->lock);
311 self->lock = NULL;
312#endif
313 return -1;
314}
315
316static void
317BZ2Compressor_dealloc(BZ2Compressor *self)
318{
319 BZ2_bzCompressEnd(&self->bzs);
320#ifdef WITH_THREAD
321 if (self->lock != NULL)
322 PyThread_free_lock(self->lock);
323#endif
324 Py_TYPE(self)->tp_free((PyObject *)self);
325}
326
327static PyMethodDef BZ2Compressor_methods[] = {
Nadeem Vawda37970652013-10-28 21:35:23 +0100328 {"compress", (PyCFunction)BZ2Compressor_compress, METH_VARARGS,
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200329 BZ2Compressor_compress__doc__},
Nadeem Vawda37970652013-10-28 21:35:23 +0100330 {"flush", (PyCFunction)BZ2Compressor_flush, METH_NOARGS,
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200331 BZ2Compressor_flush__doc__},
Nadeem Vawda37970652013-10-28 21:35:23 +0100332 {"__getstate__", (PyCFunction)BZ2Compressor_getstate, METH_NOARGS},
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200333 {NULL}
334};
335
336PyDoc_STRVAR(BZ2Compressor__doc__,
337"BZ2Compressor(compresslevel=9)\n"
338"\n"
339"Create a compressor object for compressing data incrementally.\n"
340"\n"
341"compresslevel, if given, must be a number between 1 and 9.\n"
342"\n"
343"For one-shot compression, use the compress() function instead.\n");
344
345static PyTypeObject BZ2Compressor_Type = {
346 PyVarObject_HEAD_INIT(NULL, 0)
347 "_bz2.BZ2Compressor", /* tp_name */
348 sizeof(BZ2Compressor), /* tp_basicsize */
349 0, /* tp_itemsize */
350 (destructor)BZ2Compressor_dealloc, /* tp_dealloc */
351 0, /* tp_print */
352 0, /* tp_getattr */
353 0, /* tp_setattr */
354 0, /* tp_reserved */
355 0, /* tp_repr */
356 0, /* tp_as_number */
357 0, /* tp_as_sequence */
358 0, /* tp_as_mapping */
359 0, /* tp_hash */
360 0, /* tp_call */
361 0, /* tp_str */
362 0, /* tp_getattro */
363 0, /* tp_setattro */
364 0, /* tp_as_buffer */
365 Py_TPFLAGS_DEFAULT, /* tp_flags */
366 BZ2Compressor__doc__, /* tp_doc */
367 0, /* tp_traverse */
368 0, /* tp_clear */
369 0, /* tp_richcompare */
370 0, /* tp_weaklistoffset */
371 0, /* tp_iter */
372 0, /* tp_iternext */
373 BZ2Compressor_methods, /* tp_methods */
374 0, /* tp_members */
375 0, /* tp_getset */
376 0, /* tp_base */
377 0, /* tp_dict */
378 0, /* tp_descr_get */
379 0, /* tp_descr_set */
380 0, /* tp_dictoffset */
381 (initproc)BZ2Compressor_init, /* tp_init */
382 0, /* tp_alloc */
383 PyType_GenericNew, /* tp_new */
384};
385
386
387/* BZ2Decompressor class. */
388
389static PyObject *
390decompress(BZ2Decompressor *d, char *data, size_t len)
391{
392 size_t data_size = 0;
393 PyObject *result;
394
395 result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
396 if (result == NULL)
397 return result;
398 d->bzs.next_in = data;
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200399 /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
400 Do decompression in chunks of no more than UINT_MAX bytes each. */
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200401 d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200402 len -= d->bzs.avail_in;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200403 d->bzs.next_out = PyBytes_AS_STRING(result);
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200404 d->bzs.avail_out = SMALLCHUNK;
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200405 for (;;) {
406 char *this_out;
407 int bzerror;
408
409 Py_BEGIN_ALLOW_THREADS
410 this_out = d->bzs.next_out;
411 bzerror = BZ2_bzDecompress(&d->bzs);
412 data_size += d->bzs.next_out - this_out;
413 Py_END_ALLOW_THREADS
414 if (catch_bz2_error(bzerror))
415 goto error;
416 if (bzerror == BZ_STREAM_END) {
417 d->eof = 1;
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200418 len += d->bzs.avail_in;
419 if (len > 0) { /* Save leftover input to unused_data */
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200420 Py_CLEAR(d->unused_data);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200421 d->unused_data = PyBytes_FromStringAndSize(d->bzs.next_in, len);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200422 if (d->unused_data == NULL)
423 goto error;
424 }
425 break;
426 }
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200427 if (d->bzs.avail_in == 0) {
428 if (len == 0)
429 break;
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200430 d->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
Nadeem Vawdaea4b46f2011-04-12 23:02:42 +0200431 len -= d->bzs.avail_in;
432 }
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200433 if (d->bzs.avail_out == 0) {
Nadeem Vawda18b7fcc2012-10-21 21:16:58 +0200434 size_t buffer_left = PyBytes_GET_SIZE(result) - data_size;
435 if (buffer_left == 0) {
436 if (grow_buffer(&result) < 0)
437 goto error;
438 d->bzs.next_out = PyBytes_AS_STRING(result) + data_size;
439 buffer_left = PyBytes_GET_SIZE(result) - data_size;
440 }
Victor Stinnerfbf50d42013-06-04 23:18:48 +0200441 d->bzs.avail_out = (unsigned int)Py_MIN(buffer_left, UINT_MAX);
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200442 }
443 }
444 if (data_size != PyBytes_GET_SIZE(result))
445 if (_PyBytes_Resize(&result, data_size) < 0)
446 goto error;
447 return result;
448
449error:
450 Py_XDECREF(result);
451 return NULL;
452}
453
454PyDoc_STRVAR(BZ2Decompressor_decompress__doc__,
455"decompress(data) -> bytes\n"
456"\n"
457"Provide data to the decompressor object. Returns a chunk of\n"
458"decompressed data if possible, or b'' otherwise.\n"
459"\n"
460"Attempting to decompress data after the end of stream is reached\n"
461"raises an EOFError. Any data found after the end of the stream\n"
462"is ignored and saved in the unused_data attribute.\n");
463
464static PyObject *
465BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args)
466{
467 Py_buffer buffer;
468 PyObject *result = NULL;
469
470 if (!PyArg_ParseTuple(args, "y*:decompress", &buffer))
471 return NULL;
472
473 ACQUIRE_LOCK(self);
474 if (self->eof)
475 PyErr_SetString(PyExc_EOFError, "End of stream already reached");
476 else
477 result = decompress(self, buffer.buf, buffer.len);
478 RELEASE_LOCK(self);
479 PyBuffer_Release(&buffer);
480 return result;
481}
482
Nadeem Vawda37970652013-10-28 21:35:23 +0100483static PyObject *
484BZ2Decompressor_getstate(BZ2Decompressor *self, PyObject *noargs)
485{
486 PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
487 Py_TYPE(self)->tp_name);
488 return NULL;
489}
490
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200491static int
492BZ2Decompressor_init(BZ2Decompressor *self, PyObject *args, PyObject *kwargs)
493{
494 int bzerror;
495
496 if (!PyArg_ParseTuple(args, ":BZ2Decompressor"))
497 return -1;
498
499#ifdef WITH_THREAD
500 self->lock = PyThread_allocate_lock();
501 if (self->lock == NULL) {
502 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
503 return -1;
504 }
505#endif
506
507 self->unused_data = PyBytes_FromStringAndSize("", 0);
508 if (self->unused_data == NULL)
509 goto error;
510
511 bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0);
512 if (catch_bz2_error(bzerror))
513 goto error;
514
515 return 0;
516
517error:
518 Py_CLEAR(self->unused_data);
519#ifdef WITH_THREAD
520 PyThread_free_lock(self->lock);
521 self->lock = NULL;
522#endif
523 return -1;
524}
525
526static void
527BZ2Decompressor_dealloc(BZ2Decompressor *self)
528{
529 BZ2_bzDecompressEnd(&self->bzs);
530 Py_CLEAR(self->unused_data);
531#ifdef WITH_THREAD
532 if (self->lock != NULL)
533 PyThread_free_lock(self->lock);
534#endif
535 Py_TYPE(self)->tp_free((PyObject *)self);
536}
537
538static PyMethodDef BZ2Decompressor_methods[] = {
539 {"decompress", (PyCFunction)BZ2Decompressor_decompress, METH_VARARGS,
540 BZ2Decompressor_decompress__doc__},
Nadeem Vawda37970652013-10-28 21:35:23 +0100541 {"__getstate__", (PyCFunction)BZ2Decompressor_getstate, METH_NOARGS},
Antoine Pitrou37dc5f82011-04-03 17:05:46 +0200542 {NULL}
543};
544
545PyDoc_STRVAR(BZ2Decompressor_eof__doc__,
546"True if the end-of-stream marker has been reached.");
547
548PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__,
549"Data found after the end of the compressed stream.");
550
551static PyMemberDef BZ2Decompressor_members[] = {
552 {"eof", T_BOOL, offsetof(BZ2Decompressor, eof),
553 READONLY, BZ2Decompressor_eof__doc__},
554 {"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data),
555 READONLY, BZ2Decompressor_unused_data__doc__},
556 {NULL}
557};
558
559PyDoc_STRVAR(BZ2Decompressor__doc__,
560"BZ2Decompressor()\n"
561"\n"
562"Create a decompressor object for decompressing data incrementally.\n"
563"\n"
564"For one-shot decompression, use the decompress() function instead.\n");
565
566static PyTypeObject BZ2Decompressor_Type = {
567 PyVarObject_HEAD_INIT(NULL, 0)
568 "_bz2.BZ2Decompressor", /* tp_name */
569 sizeof(BZ2Decompressor), /* tp_basicsize */
570 0, /* tp_itemsize */
571 (destructor)BZ2Decompressor_dealloc,/* tp_dealloc */
572 0, /* tp_print */
573 0, /* tp_getattr */
574 0, /* tp_setattr */
575 0, /* tp_reserved */
576 0, /* tp_repr */
577 0, /* tp_as_number */
578 0, /* tp_as_sequence */
579 0, /* tp_as_mapping */
580 0, /* tp_hash */
581 0, /* tp_call */
582 0, /* tp_str */
583 0, /* tp_getattro */
584 0, /* tp_setattro */
585 0, /* tp_as_buffer */
586 Py_TPFLAGS_DEFAULT, /* tp_flags */
587 BZ2Decompressor__doc__, /* tp_doc */
588 0, /* tp_traverse */
589 0, /* tp_clear */
590 0, /* tp_richcompare */
591 0, /* tp_weaklistoffset */
592 0, /* tp_iter */
593 0, /* tp_iternext */
594 BZ2Decompressor_methods, /* tp_methods */
595 BZ2Decompressor_members, /* tp_members */
596 0, /* tp_getset */
597 0, /* tp_base */
598 0, /* tp_dict */
599 0, /* tp_descr_get */
600 0, /* tp_descr_set */
601 0, /* tp_dictoffset */
602 (initproc)BZ2Decompressor_init, /* tp_init */
603 0, /* tp_alloc */
604 PyType_GenericNew, /* tp_new */
605};
606
607
608/* Module initialization. */
609
610static struct PyModuleDef _bz2module = {
611 PyModuleDef_HEAD_INIT,
612 "_bz2",
613 NULL,
614 -1,
615 NULL,
616 NULL,
617 NULL,
618 NULL,
619 NULL
620};
621
622PyMODINIT_FUNC
623PyInit__bz2(void)
624{
625 PyObject *m;
626
627 if (PyType_Ready(&BZ2Compressor_Type) < 0)
628 return NULL;
629 if (PyType_Ready(&BZ2Decompressor_Type) < 0)
630 return NULL;
631
632 m = PyModule_Create(&_bz2module);
633 if (m == NULL)
634 return NULL;
635
636 Py_INCREF(&BZ2Compressor_Type);
637 PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Compressor_Type);
638
639 Py_INCREF(&BZ2Decompressor_Type);
640 PyModule_AddObject(m, "BZ2Decompressor",
641 (PyObject *)&BZ2Decompressor_Type);
642
643 return m;
644}