Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Modules/_bz2module.c
12 views
1
/* _bz2 - Low-level Python interface to libbzip2. */
2
3
#include "Python.h"
4
#include "structmember.h" // PyMemberDef
5
6
#include <bzlib.h>
7
#include <stdio.h>
8
9
// Blocks output buffer wrappers
10
#include "pycore_blocks_output_buffer.h"
11
12
#if OUTPUT_BUFFER_MAX_BLOCK_SIZE > UINT32_MAX
13
#error "The maximum block size accepted by libbzip2 is UINT32_MAX."
14
#endif
15
16
typedef struct {
17
PyTypeObject *bz2_compressor_type;
18
PyTypeObject *bz2_decompressor_type;
19
} _bz2_state;
20
21
static inline _bz2_state *
22
get_module_state(PyObject *module)
23
{
24
void *state = PyModule_GetState(module);
25
assert(state != NULL);
26
return (_bz2_state *)state;
27
}
28
29
static struct PyModuleDef _bz2module;
30
31
static inline _bz2_state *
32
find_module_state_by_def(PyTypeObject *type)
33
{
34
PyObject *module = PyType_GetModuleByDef(type, &_bz2module);
35
assert(module != NULL);
36
return get_module_state(module);
37
}
38
39
/* On success, return value >= 0
40
On failure, return -1 */
41
static inline Py_ssize_t
42
OutputBuffer_InitAndGrow(_BlocksOutputBuffer *buffer, Py_ssize_t max_length,
43
char **next_out, uint32_t *avail_out)
44
{
45
Py_ssize_t allocated;
46
47
allocated = _BlocksOutputBuffer_InitAndGrow(
48
buffer, max_length, (void**) next_out);
49
*avail_out = (uint32_t) allocated;
50
return allocated;
51
}
52
53
/* On success, return value >= 0
54
On failure, return -1 */
55
static inline Py_ssize_t
56
OutputBuffer_Grow(_BlocksOutputBuffer *buffer,
57
char **next_out, uint32_t *avail_out)
58
{
59
Py_ssize_t allocated;
60
61
allocated = _BlocksOutputBuffer_Grow(
62
buffer, (void**) next_out, (Py_ssize_t) *avail_out);
63
*avail_out = (uint32_t) allocated;
64
return allocated;
65
}
66
67
static inline Py_ssize_t
68
OutputBuffer_GetDataSize(_BlocksOutputBuffer *buffer, uint32_t avail_out)
69
{
70
return _BlocksOutputBuffer_GetDataSize(buffer, (Py_ssize_t) avail_out);
71
}
72
73
static inline PyObject *
74
OutputBuffer_Finish(_BlocksOutputBuffer *buffer, uint32_t avail_out)
75
{
76
return _BlocksOutputBuffer_Finish(buffer, (Py_ssize_t) avail_out);
77
}
78
79
static inline void
80
OutputBuffer_OnError(_BlocksOutputBuffer *buffer)
81
{
82
_BlocksOutputBuffer_OnError(buffer);
83
}
84
85
86
#ifndef BZ_CONFIG_ERROR
87
#define BZ2_bzCompress bzCompress
88
#define BZ2_bzCompressInit bzCompressInit
89
#define BZ2_bzCompressEnd bzCompressEnd
90
#define BZ2_bzDecompress bzDecompress
91
#define BZ2_bzDecompressInit bzDecompressInit
92
#define BZ2_bzDecompressEnd bzDecompressEnd
93
#endif /* ! BZ_CONFIG_ERROR */
94
95
96
#define ACQUIRE_LOCK(obj) do { \
97
if (!PyThread_acquire_lock((obj)->lock, 0)) { \
98
Py_BEGIN_ALLOW_THREADS \
99
PyThread_acquire_lock((obj)->lock, 1); \
100
Py_END_ALLOW_THREADS \
101
} } while (0)
102
#define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock)
103
104
105
typedef struct {
106
PyObject_HEAD
107
bz_stream bzs;
108
int flushed;
109
PyThread_type_lock lock;
110
} BZ2Compressor;
111
112
typedef struct {
113
PyObject_HEAD
114
bz_stream bzs;
115
char eof; /* T_BOOL expects a char */
116
PyObject *unused_data;
117
char needs_input;
118
char *input_buffer;
119
size_t input_buffer_size;
120
121
/* bzs->avail_in is only 32 bit, so we store the true length
122
separately. Conversion and looping is encapsulated in
123
decompress_buf() */
124
size_t bzs_avail_in_real;
125
PyThread_type_lock lock;
126
} BZ2Decompressor;
127
128
/* Helper functions. */
129
130
static int
131
catch_bz2_error(int bzerror)
132
{
133
switch(bzerror) {
134
case BZ_OK:
135
case BZ_RUN_OK:
136
case BZ_FLUSH_OK:
137
case BZ_FINISH_OK:
138
case BZ_STREAM_END:
139
return 0;
140
141
#ifdef BZ_CONFIG_ERROR
142
case BZ_CONFIG_ERROR:
143
PyErr_SetString(PyExc_SystemError,
144
"libbzip2 was not compiled correctly");
145
return 1;
146
#endif
147
case BZ_PARAM_ERROR:
148
PyErr_SetString(PyExc_ValueError,
149
"Internal error - "
150
"invalid parameters passed to libbzip2");
151
return 1;
152
case BZ_MEM_ERROR:
153
PyErr_NoMemory();
154
return 1;
155
case BZ_DATA_ERROR:
156
case BZ_DATA_ERROR_MAGIC:
157
PyErr_SetString(PyExc_OSError, "Invalid data stream");
158
return 1;
159
case BZ_IO_ERROR:
160
PyErr_SetString(PyExc_OSError, "Unknown I/O error");
161
return 1;
162
case BZ_UNEXPECTED_EOF:
163
PyErr_SetString(PyExc_EOFError,
164
"Compressed file ended before the logical "
165
"end-of-stream was detected");
166
return 1;
167
case BZ_SEQUENCE_ERROR:
168
PyErr_SetString(PyExc_RuntimeError,
169
"Internal error - "
170
"Invalid sequence of commands sent to libbzip2");
171
return 1;
172
default:
173
PyErr_Format(PyExc_OSError,
174
"Unrecognized error from libbzip2: %d", bzerror);
175
return 1;
176
}
177
}
178
179
180
/* BZ2Compressor class. */
181
182
static PyObject *
183
compress(BZ2Compressor *c, char *data, size_t len, int action)
184
{
185
PyObject *result;
186
_BlocksOutputBuffer buffer = {.list = NULL};
187
188
if (OutputBuffer_InitAndGrow(&buffer, -1, &c->bzs.next_out, &c->bzs.avail_out) < 0) {
189
goto error;
190
}
191
c->bzs.next_in = data;
192
c->bzs.avail_in = 0;
193
194
for (;;) {
195
int bzerror;
196
197
/* On a 64-bit system, len might not fit in avail_in (an unsigned int).
198
Do compression in chunks of no more than UINT_MAX bytes each. */
199
if (c->bzs.avail_in == 0 && len > 0) {
200
c->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX);
201
len -= c->bzs.avail_in;
202
}
203
204
/* In regular compression mode, stop when input data is exhausted. */
205
if (action == BZ_RUN && c->bzs.avail_in == 0)
206
break;
207
208
if (c->bzs.avail_out == 0) {
209
if (OutputBuffer_Grow(&buffer, &c->bzs.next_out, &c->bzs.avail_out) < 0) {
210
goto error;
211
}
212
}
213
214
Py_BEGIN_ALLOW_THREADS
215
bzerror = BZ2_bzCompress(&c->bzs, action);
216
Py_END_ALLOW_THREADS
217
218
if (catch_bz2_error(bzerror))
219
goto error;
220
221
/* In flushing mode, stop when all buffered data has been flushed. */
222
if (action == BZ_FINISH && bzerror == BZ_STREAM_END)
223
break;
224
}
225
226
result = OutputBuffer_Finish(&buffer, c->bzs.avail_out);
227
if (result != NULL) {
228
return result;
229
}
230
231
error:
232
OutputBuffer_OnError(&buffer);
233
return NULL;
234
}
235
236
/*[clinic input]
237
module _bz2
238
class _bz2.BZ2Compressor "BZ2Compressor *" "clinic_state()->bz2_compressor_type"
239
class _bz2.BZ2Decompressor "BZ2Decompressor *" "clinic_state()->bz2_decompressor_type"
240
[clinic start generated code]*/
241
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=92348121632b94c4]*/
242
243
#define clinic_state() (find_module_state_by_def(type))
244
#include "clinic/_bz2module.c.h"
245
#undef clinic_state
246
247
/*[clinic input]
248
_bz2.BZ2Compressor.compress
249
250
data: Py_buffer
251
/
252
253
Provide data to the compressor object.
254
255
Returns a chunk of compressed data if possible, or b'' otherwise.
256
257
When you have finished providing data to the compressor, call the
258
flush() method to finish the compression process.
259
[clinic start generated code]*/
260
261
static PyObject *
262
_bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data)
263
/*[clinic end generated code: output=59365426e941fbcc input=85c963218070fc4c]*/
264
{
265
PyObject *result = NULL;
266
267
ACQUIRE_LOCK(self);
268
if (self->flushed)
269
PyErr_SetString(PyExc_ValueError, "Compressor has been flushed");
270
else
271
result = compress(self, data->buf, data->len, BZ_RUN);
272
RELEASE_LOCK(self);
273
return result;
274
}
275
276
/*[clinic input]
277
_bz2.BZ2Compressor.flush
278
279
Finish the compression process.
280
281
Returns the compressed data left in internal buffers.
282
283
The compressor object may not be used after this method is called.
284
[clinic start generated code]*/
285
286
static PyObject *
287
_bz2_BZ2Compressor_flush_impl(BZ2Compressor *self)
288
/*[clinic end generated code: output=3ef03fc1b092a701 input=d64405d3c6f76691]*/
289
{
290
PyObject *result = NULL;
291
292
ACQUIRE_LOCK(self);
293
if (self->flushed)
294
PyErr_SetString(PyExc_ValueError, "Repeated call to flush()");
295
else {
296
self->flushed = 1;
297
result = compress(self, NULL, 0, BZ_FINISH);
298
}
299
RELEASE_LOCK(self);
300
return result;
301
}
302
303
static void*
304
BZ2_Malloc(void* ctx, int items, int size)
305
{
306
if (items < 0 || size < 0)
307
return NULL;
308
if (size != 0 && (size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size)
309
return NULL;
310
/* PyMem_Malloc() cannot be used: compress() and decompress()
311
release the GIL */
312
return PyMem_RawMalloc((size_t)items * (size_t)size);
313
}
314
315
static void
316
BZ2_Free(void* ctx, void *ptr)
317
{
318
PyMem_RawFree(ptr);
319
}
320
321
/*[clinic input]
322
@classmethod
323
_bz2.BZ2Compressor.__new__
324
325
compresslevel: int = 9
326
Compression level, as a number between 1 and 9.
327
/
328
329
Create a compressor object for compressing data incrementally.
330
331
For one-shot compression, use the compress() function instead.
332
[clinic start generated code]*/
333
334
static PyObject *
335
_bz2_BZ2Compressor_impl(PyTypeObject *type, int compresslevel)
336
/*[clinic end generated code: output=83346c96beaacad7 input=d4500d2a52c8b263]*/
337
{
338
int bzerror;
339
BZ2Compressor *self;
340
341
if (!(1 <= compresslevel && compresslevel <= 9)) {
342
PyErr_SetString(PyExc_ValueError,
343
"compresslevel must be between 1 and 9");
344
return NULL;
345
}
346
347
assert(type != NULL && type->tp_alloc != NULL);
348
self = (BZ2Compressor *)type->tp_alloc(type, 0);
349
if (self == NULL) {
350
return NULL;
351
}
352
353
self->lock = PyThread_allocate_lock();
354
if (self->lock == NULL) {
355
Py_DECREF(self);
356
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
357
return NULL;
358
}
359
360
self->bzs.opaque = NULL;
361
self->bzs.bzalloc = BZ2_Malloc;
362
self->bzs.bzfree = BZ2_Free;
363
bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0);
364
if (catch_bz2_error(bzerror))
365
goto error;
366
367
return (PyObject *)self;
368
369
error:
370
Py_DECREF(self);
371
return NULL;
372
}
373
374
static void
375
BZ2Compressor_dealloc(BZ2Compressor *self)
376
{
377
BZ2_bzCompressEnd(&self->bzs);
378
if (self->lock != NULL) {
379
PyThread_free_lock(self->lock);
380
}
381
PyTypeObject *tp = Py_TYPE(self);
382
tp->tp_free((PyObject *)self);
383
Py_DECREF(tp);
384
}
385
386
static int
387
BZ2Compressor_traverse(BZ2Compressor *self, visitproc visit, void *arg)
388
{
389
Py_VISIT(Py_TYPE(self));
390
return 0;
391
}
392
393
static PyMethodDef BZ2Compressor_methods[] = {
394
_BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF
395
_BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF
396
{NULL}
397
};
398
399
static PyType_Slot bz2_compressor_type_slots[] = {
400
{Py_tp_dealloc, BZ2Compressor_dealloc},
401
{Py_tp_methods, BZ2Compressor_methods},
402
{Py_tp_new, _bz2_BZ2Compressor},
403
{Py_tp_doc, (char *)_bz2_BZ2Compressor__doc__},
404
{Py_tp_traverse, BZ2Compressor_traverse},
405
{0, 0}
406
};
407
408
static PyType_Spec bz2_compressor_type_spec = {
409
.name = "_bz2.BZ2Compressor",
410
.basicsize = sizeof(BZ2Compressor),
411
// Calling PyType_GetModuleState() on a subclass is not safe.
412
// bz2_compressor_type_spec does not have Py_TPFLAGS_BASETYPE flag
413
// which prevents to create a subclass.
414
// So calling PyType_GetModuleState() in this file is always safe.
415
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
416
.slots = bz2_compressor_type_slots,
417
};
418
419
/* BZ2Decompressor class. */
420
421
/* Decompress data of length d->bzs_avail_in_real in d->bzs.next_in. The output
422
buffer is allocated dynamically and returned. At most max_length bytes are
423
returned, so some of the input may not be consumed. d->bzs.next_in and
424
d->bzs_avail_in_real are updated to reflect the consumed input. */
425
static PyObject*
426
decompress_buf(BZ2Decompressor *d, Py_ssize_t max_length)
427
{
428
/* data_size is strictly positive, but because we repeatedly have to
429
compare against max_length and PyBytes_GET_SIZE we declare it as
430
signed */
431
PyObject *result;
432
_BlocksOutputBuffer buffer = {.list = NULL};
433
bz_stream *bzs = &d->bzs;
434
435
if (OutputBuffer_InitAndGrow(&buffer, max_length, &bzs->next_out, &bzs->avail_out) < 0) {
436
goto error;
437
}
438
439
for (;;) {
440
int bzret;
441
/* On a 64-bit system, buffer length might not fit in avail_out, so we
442
do decompression in chunks of no more than UINT_MAX bytes
443
each. Note that the expression for `avail` is guaranteed to be
444
positive, so the cast is safe. */
445
bzs->avail_in = (unsigned int)Py_MIN(d->bzs_avail_in_real, UINT_MAX);
446
d->bzs_avail_in_real -= bzs->avail_in;
447
448
Py_BEGIN_ALLOW_THREADS
449
bzret = BZ2_bzDecompress(bzs);
450
Py_END_ALLOW_THREADS
451
452
d->bzs_avail_in_real += bzs->avail_in;
453
454
if (catch_bz2_error(bzret))
455
goto error;
456
if (bzret == BZ_STREAM_END) {
457
d->eof = 1;
458
break;
459
} else if (d->bzs_avail_in_real == 0) {
460
break;
461
} else if (bzs->avail_out == 0) {
462
if (OutputBuffer_GetDataSize(&buffer, bzs->avail_out) == max_length) {
463
break;
464
}
465
if (OutputBuffer_Grow(&buffer, &bzs->next_out, &bzs->avail_out) < 0) {
466
goto error;
467
}
468
}
469
}
470
471
result = OutputBuffer_Finish(&buffer, bzs->avail_out);
472
if (result != NULL) {
473
return result;
474
}
475
476
error:
477
OutputBuffer_OnError(&buffer);
478
return NULL;
479
}
480
481
482
static PyObject *
483
decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length)
484
{
485
char input_buffer_in_use;
486
PyObject *result;
487
bz_stream *bzs = &d->bzs;
488
489
/* Prepend unconsumed input if necessary */
490
if (bzs->next_in != NULL) {
491
size_t avail_now, avail_total;
492
493
/* Number of bytes we can append to input buffer */
494
avail_now = (d->input_buffer + d->input_buffer_size)
495
- (bzs->next_in + d->bzs_avail_in_real);
496
497
/* Number of bytes we can append if we move existing
498
contents to beginning of buffer (overwriting
499
consumed input) */
500
avail_total = d->input_buffer_size - d->bzs_avail_in_real;
501
502
if (avail_total < len) {
503
size_t offset = bzs->next_in - d->input_buffer;
504
char *tmp;
505
size_t new_size = d->input_buffer_size + len - avail_now;
506
507
/* Assign to temporary variable first, so we don't
508
lose address of allocated buffer if realloc fails */
509
tmp = PyMem_Realloc(d->input_buffer, new_size);
510
if (tmp == NULL) {
511
PyErr_SetNone(PyExc_MemoryError);
512
return NULL;
513
}
514
d->input_buffer = tmp;
515
d->input_buffer_size = new_size;
516
517
bzs->next_in = d->input_buffer + offset;
518
}
519
else if (avail_now < len) {
520
memmove(d->input_buffer, bzs->next_in,
521
d->bzs_avail_in_real);
522
bzs->next_in = d->input_buffer;
523
}
524
memcpy((void*)(bzs->next_in + d->bzs_avail_in_real), data, len);
525
d->bzs_avail_in_real += len;
526
input_buffer_in_use = 1;
527
}
528
else {
529
bzs->next_in = data;
530
d->bzs_avail_in_real = len;
531
input_buffer_in_use = 0;
532
}
533
534
result = decompress_buf(d, max_length);
535
if(result == NULL) {
536
bzs->next_in = NULL;
537
return NULL;
538
}
539
540
if (d->eof) {
541
d->needs_input = 0;
542
if (d->bzs_avail_in_real > 0) {
543
Py_XSETREF(d->unused_data,
544
PyBytes_FromStringAndSize(bzs->next_in, d->bzs_avail_in_real));
545
if (d->unused_data == NULL)
546
goto error;
547
}
548
}
549
else if (d->bzs_avail_in_real == 0) {
550
bzs->next_in = NULL;
551
d->needs_input = 1;
552
}
553
else {
554
d->needs_input = 0;
555
556
/* If we did not use the input buffer, we now have
557
to copy the tail from the caller's buffer into the
558
input buffer */
559
if (!input_buffer_in_use) {
560
561
/* Discard buffer if it's too small
562
(resizing it may needlessly copy the current contents) */
563
if (d->input_buffer != NULL &&
564
d->input_buffer_size < d->bzs_avail_in_real) {
565
PyMem_Free(d->input_buffer);
566
d->input_buffer = NULL;
567
}
568
569
/* Allocate if necessary */
570
if (d->input_buffer == NULL) {
571
d->input_buffer = PyMem_Malloc(d->bzs_avail_in_real);
572
if (d->input_buffer == NULL) {
573
PyErr_SetNone(PyExc_MemoryError);
574
goto error;
575
}
576
d->input_buffer_size = d->bzs_avail_in_real;
577
}
578
579
/* Copy tail */
580
memcpy(d->input_buffer, bzs->next_in, d->bzs_avail_in_real);
581
bzs->next_in = d->input_buffer;
582
}
583
}
584
585
return result;
586
587
error:
588
Py_XDECREF(result);
589
return NULL;
590
}
591
592
/*[clinic input]
593
_bz2.BZ2Decompressor.decompress
594
595
data: Py_buffer
596
max_length: Py_ssize_t=-1
597
598
Decompress *data*, returning uncompressed data as bytes.
599
600
If *max_length* is nonnegative, returns at most *max_length* bytes of
601
decompressed data. If this limit is reached and further output can be
602
produced, *self.needs_input* will be set to ``False``. In this case, the next
603
call to *decompress()* may provide *data* as b'' to obtain more of the output.
604
605
If all of the input data was decompressed and returned (either because this
606
was less than *max_length* bytes, or because *max_length* was negative),
607
*self.needs_input* will be set to True.
608
609
Attempting to decompress data after the end of stream is reached raises an
610
EOFError. Any data found after the end of the stream is ignored and saved in
611
the unused_data attribute.
612
[clinic start generated code]*/
613
614
static PyObject *
615
_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data,
616
Py_ssize_t max_length)
617
/*[clinic end generated code: output=23e41045deb240a3 input=52e1ffc66a8ea624]*/
618
{
619
PyObject *result = NULL;
620
621
ACQUIRE_LOCK(self);
622
if (self->eof)
623
PyErr_SetString(PyExc_EOFError, "End of stream already reached");
624
else
625
result = decompress(self, data->buf, data->len, max_length);
626
RELEASE_LOCK(self);
627
return result;
628
}
629
630
/*[clinic input]
631
@classmethod
632
_bz2.BZ2Decompressor.__new__
633
634
Create a decompressor object for decompressing data incrementally.
635
636
For one-shot decompression, use the decompress() function instead.
637
[clinic start generated code]*/
638
639
static PyObject *
640
_bz2_BZ2Decompressor_impl(PyTypeObject *type)
641
/*[clinic end generated code: output=5150d51ccaab220e input=b87413ce51853528]*/
642
{
643
BZ2Decompressor *self;
644
int bzerror;
645
646
assert(type != NULL && type->tp_alloc != NULL);
647
self = (BZ2Decompressor *)type->tp_alloc(type, 0);
648
if (self == NULL) {
649
return NULL;
650
}
651
652
self->lock = PyThread_allocate_lock();
653
if (self->lock == NULL) {
654
Py_DECREF(self);
655
PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
656
return NULL;
657
}
658
659
self->needs_input = 1;
660
self->bzs_avail_in_real = 0;
661
self->input_buffer = NULL;
662
self->input_buffer_size = 0;
663
self->unused_data = PyBytes_FromStringAndSize(NULL, 0);
664
if (self->unused_data == NULL)
665
goto error;
666
667
bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0);
668
if (catch_bz2_error(bzerror))
669
goto error;
670
671
return (PyObject *)self;
672
673
error:
674
Py_DECREF(self);
675
return NULL;
676
}
677
678
static void
679
BZ2Decompressor_dealloc(BZ2Decompressor *self)
680
{
681
if(self->input_buffer != NULL) {
682
PyMem_Free(self->input_buffer);
683
}
684
BZ2_bzDecompressEnd(&self->bzs);
685
Py_CLEAR(self->unused_data);
686
if (self->lock != NULL) {
687
PyThread_free_lock(self->lock);
688
}
689
690
PyTypeObject *tp = Py_TYPE(self);
691
tp->tp_free((PyObject *)self);
692
Py_DECREF(tp);
693
}
694
695
static int
696
BZ2Decompressor_traverse(BZ2Decompressor *self, visitproc visit, void *arg)
697
{
698
Py_VISIT(Py_TYPE(self));
699
return 0;
700
}
701
702
static PyMethodDef BZ2Decompressor_methods[] = {
703
_BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF
704
{NULL}
705
};
706
707
PyDoc_STRVAR(BZ2Decompressor_eof__doc__,
708
"True if the end-of-stream marker has been reached.");
709
710
PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__,
711
"Data found after the end of the compressed stream.");
712
713
PyDoc_STRVAR(BZ2Decompressor_needs_input_doc,
714
"True if more input is needed before more decompressed data can be produced.");
715
716
static PyMemberDef BZ2Decompressor_members[] = {
717
{"eof", T_BOOL, offsetof(BZ2Decompressor, eof),
718
READONLY, BZ2Decompressor_eof__doc__},
719
{"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data),
720
READONLY, BZ2Decompressor_unused_data__doc__},
721
{"needs_input", T_BOOL, offsetof(BZ2Decompressor, needs_input), READONLY,
722
BZ2Decompressor_needs_input_doc},
723
{NULL}
724
};
725
726
static PyType_Slot bz2_decompressor_type_slots[] = {
727
{Py_tp_dealloc, BZ2Decompressor_dealloc},
728
{Py_tp_methods, BZ2Decompressor_methods},
729
{Py_tp_doc, (char *)_bz2_BZ2Decompressor__doc__},
730
{Py_tp_members, BZ2Decompressor_members},
731
{Py_tp_new, _bz2_BZ2Decompressor},
732
{Py_tp_traverse, BZ2Decompressor_traverse},
733
{0, 0}
734
};
735
736
static PyType_Spec bz2_decompressor_type_spec = {
737
.name = "_bz2.BZ2Decompressor",
738
.basicsize = sizeof(BZ2Decompressor),
739
// Calling PyType_GetModuleState() on a subclass is not safe.
740
// bz2_decompressor_type_spec does not have Py_TPFLAGS_BASETYPE flag
741
// which prevents to create a subclass.
742
// So calling PyType_GetModuleState() in this file is always safe.
743
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
744
.slots = bz2_decompressor_type_slots,
745
};
746
747
/* Module initialization. */
748
749
static int
750
_bz2_exec(PyObject *module)
751
{
752
_bz2_state *state = get_module_state(module);
753
state->bz2_compressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
754
&bz2_compressor_type_spec, NULL);
755
if (state->bz2_compressor_type == NULL) {
756
return -1;
757
}
758
if (PyModule_AddType(module, state->bz2_compressor_type) < 0) {
759
return -1;
760
}
761
762
state->bz2_decompressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
763
&bz2_decompressor_type_spec, NULL);
764
if (state->bz2_decompressor_type == NULL) {
765
return -1;
766
}
767
if (PyModule_AddType(module, state->bz2_decompressor_type) < 0) {
768
return -1;
769
}
770
771
return 0;
772
}
773
774
static int
775
_bz2_traverse(PyObject *module, visitproc visit, void *arg)
776
{
777
_bz2_state *state = get_module_state(module);
778
Py_VISIT(state->bz2_compressor_type);
779
Py_VISIT(state->bz2_decompressor_type);
780
return 0;
781
}
782
783
static int
784
_bz2_clear(PyObject *module)
785
{
786
_bz2_state *state = get_module_state(module);
787
Py_CLEAR(state->bz2_compressor_type);
788
Py_CLEAR(state->bz2_decompressor_type);
789
return 0;
790
}
791
792
static void
793
_bz2_free(void *module)
794
{
795
(void)_bz2_clear((PyObject *)module);
796
}
797
798
static struct PyModuleDef_Slot _bz2_slots[] = {
799
{Py_mod_exec, _bz2_exec},
800
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
801
{0, NULL}
802
};
803
804
static struct PyModuleDef _bz2module = {
805
.m_base = PyModuleDef_HEAD_INIT,
806
.m_name = "_bz2",
807
.m_size = sizeof(_bz2_state),
808
.m_traverse = _bz2_traverse,
809
.m_clear = _bz2_clear,
810
.m_free = _bz2_free,
811
.m_slots = _bz2_slots,
812
};
813
814
PyMODINIT_FUNC
815
PyInit__bz2(void)
816
{
817
return PyModuleDef_Init(&_bz2module);
818
}
819
820