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