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