LCOV - code coverage report
Current view: | top level - Modules - _bz2module.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 27 | 296 | 9.1 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 6 | 27 | 22.2 %
|  |  | Branches: | 12 | 153 | 7.8 %

               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                 :            : }

Generated by: LCOV version 1.14