| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | /* _bz2 - Low-level Python interface to libbzip2. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PY_SSIZE_T_CLEAN
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Python.h"
 | 
					
						
							| 
									
										
										
										
											2020-04-15 02:35:41 +02:00
										 |  |  | #include "structmember.h"         // PyMemberDef
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <bzlib.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | // Blocks output buffer wrappers
 | 
					
						
							|  |  |  | #include "pycore_blocks_output_buffer.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if OUTPUT_BUFFER_MAX_BLOCK_SIZE > UINT32_MAX
 | 
					
						
							|  |  |  |     #error "The maximum block size accepted by libbzip2 is UINT32_MAX."
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* On success, return value >= 0
 | 
					
						
							|  |  |  |    On failure, return -1 */ | 
					
						
							|  |  |  | static inline Py_ssize_t | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  | OutputBuffer_InitAndGrow(_BlocksOutputBuffer *buffer, Py_ssize_t max_length, | 
					
						
							|  |  |  |                          char **next_out, uint32_t *avail_out) | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     Py_ssize_t allocated; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     allocated = _BlocksOutputBuffer_InitAndGrow( | 
					
						
							|  |  |  |                     buffer, max_length, (void**) next_out); | 
					
						
							|  |  |  |     *avail_out = (uint32_t) allocated; | 
					
						
							|  |  |  |     return allocated; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* On success, return value >= 0
 | 
					
						
							|  |  |  |    On failure, return -1 */ | 
					
						
							|  |  |  | static inline Py_ssize_t | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  | OutputBuffer_Grow(_BlocksOutputBuffer *buffer, | 
					
						
							|  |  |  |                   char **next_out, uint32_t *avail_out) | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     Py_ssize_t allocated; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     allocated = _BlocksOutputBuffer_Grow( | 
					
						
							|  |  |  |                     buffer, (void**) next_out, (Py_ssize_t) *avail_out); | 
					
						
							|  |  |  |     *avail_out = (uint32_t) allocated; | 
					
						
							|  |  |  |     return allocated; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline Py_ssize_t | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  | OutputBuffer_GetDataSize(_BlocksOutputBuffer *buffer, uint32_t avail_out) | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     return _BlocksOutputBuffer_GetDataSize(buffer, (Py_ssize_t) avail_out); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline PyObject * | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  | OutputBuffer_Finish(_BlocksOutputBuffer *buffer, uint32_t avail_out) | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     return _BlocksOutputBuffer_Finish(buffer, (Py_ssize_t) avail_out); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  | OutputBuffer_OnError(_BlocksOutputBuffer *buffer) | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     _BlocksOutputBuffer_OnError(buffer); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifndef BZ_CONFIG_ERROR
 | 
					
						
							|  |  |  | #define BZ2_bzCompress bzCompress
 | 
					
						
							|  |  |  | #define BZ2_bzCompressInit bzCompressInit
 | 
					
						
							|  |  |  | #define BZ2_bzCompressEnd bzCompressEnd
 | 
					
						
							|  |  |  | #define BZ2_bzDecompress bzDecompress
 | 
					
						
							|  |  |  | #define BZ2_bzDecompressInit bzDecompressInit
 | 
					
						
							|  |  |  | #define BZ2_bzDecompressEnd bzDecompressEnd
 | 
					
						
							|  |  |  | #endif  /* ! BZ_CONFIG_ERROR */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ACQUIRE_LOCK(obj) do { \
 | 
					
						
							|  |  |  |     if (!PyThread_acquire_lock((obj)->lock, 0)) { \ | 
					
						
							|  |  |  |         Py_BEGIN_ALLOW_THREADS \ | 
					
						
							|  |  |  |         PyThread_acquire_lock((obj)->lock, 1); \ | 
					
						
							|  |  |  |         Py_END_ALLOW_THREADS \ | 
					
						
							|  |  |  |     } } while (0) | 
					
						
							|  |  |  | #define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     PyTypeObject *bz2_compressor_type; | 
					
						
							|  |  |  |     PyTypeObject *bz2_decompressor_type; | 
					
						
							|  |  |  | } _bz2_state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline _bz2_state* | 
					
						
							|  |  |  | get_bz2_state(PyObject *module) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     void *state = PyModule_GetState(module); | 
					
						
							|  |  |  |     assert(state != NULL); | 
					
						
							|  |  |  |     return (_bz2_state *)state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     PyObject_HEAD | 
					
						
							|  |  |  |     bz_stream bzs; | 
					
						
							|  |  |  |     int flushed; | 
					
						
							|  |  |  |     PyThread_type_lock lock; | 
					
						
							|  |  |  | } BZ2Compressor; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |     PyObject_HEAD | 
					
						
							|  |  |  |     bz_stream bzs; | 
					
						
							|  |  |  |     char eof;           /* T_BOOL expects a char */ | 
					
						
							|  |  |  |     PyObject *unused_data; | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |     char needs_input; | 
					
						
							|  |  |  |     char *input_buffer; | 
					
						
							|  |  |  |     size_t input_buffer_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* bzs->avail_in is only 32 bit, so we store the true length
 | 
					
						
							|  |  |  |        separately. Conversion and looping is encapsulated in | 
					
						
							|  |  |  |        decompress_buf() */ | 
					
						
							|  |  |  |     size_t bzs_avail_in_real; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     PyThread_type_lock lock; | 
					
						
							|  |  |  | } BZ2Decompressor; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Helper functions. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | catch_bz2_error(int bzerror) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch(bzerror) { | 
					
						
							|  |  |  |         case BZ_OK: | 
					
						
							|  |  |  |         case BZ_RUN_OK: | 
					
						
							|  |  |  |         case BZ_FLUSH_OK: | 
					
						
							|  |  |  |         case BZ_FINISH_OK: | 
					
						
							|  |  |  |         case BZ_STREAM_END: | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef BZ_CONFIG_ERROR
 | 
					
						
							|  |  |  |         case BZ_CONFIG_ERROR: | 
					
						
							|  |  |  |             PyErr_SetString(PyExc_SystemError, | 
					
						
							|  |  |  |                             "libbzip2 was not compiled correctly"); | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |         case BZ_PARAM_ERROR: | 
					
						
							|  |  |  |             PyErr_SetString(PyExc_ValueError, | 
					
						
							|  |  |  |                             "Internal error - " | 
					
						
							|  |  |  |                             "invalid parameters passed to libbzip2"); | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  |         case BZ_MEM_ERROR: | 
					
						
							|  |  |  |             PyErr_NoMemory(); | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  |         case BZ_DATA_ERROR: | 
					
						
							|  |  |  |         case BZ_DATA_ERROR_MAGIC: | 
					
						
							| 
									
										
										
										
											2017-04-16 10:46:38 +03:00
										 |  |  |             PyErr_SetString(PyExc_OSError, "Invalid data stream"); | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |             return 1; | 
					
						
							|  |  |  |         case BZ_IO_ERROR: | 
					
						
							| 
									
										
										
										
											2017-04-16 10:46:38 +03:00
										 |  |  |             PyErr_SetString(PyExc_OSError, "Unknown I/O error"); | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |             return 1; | 
					
						
							|  |  |  |         case BZ_UNEXPECTED_EOF: | 
					
						
							|  |  |  |             PyErr_SetString(PyExc_EOFError, | 
					
						
							|  |  |  |                             "Compressed file ended before the logical " | 
					
						
							|  |  |  |                             "end-of-stream was detected"); | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  |         case BZ_SEQUENCE_ERROR: | 
					
						
							|  |  |  |             PyErr_SetString(PyExc_RuntimeError, | 
					
						
							|  |  |  |                             "Internal error - " | 
					
						
							|  |  |  |                             "Invalid sequence of commands sent to libbzip2"); | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2017-04-16 10:46:38 +03:00
										 |  |  |             PyErr_Format(PyExc_OSError, | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |                          "Unrecognized error from libbzip2: %d", bzerror); | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* BZ2Compressor class. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | compress(BZ2Compressor *c, char *data, size_t len, int action) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *result; | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  |     _BlocksOutputBuffer buffer = {.list = NULL}; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |     if (OutputBuffer_InitAndGrow(&buffer, -1, &c->bzs.next_out, &c->bzs.avail_out) < 0) { | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     c->bzs.next_in = data; | 
					
						
							| 
									
										
										
										
											2013-01-02 23:05:56 +01:00
										 |  |  |     c->bzs.avail_in = 0; | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     for (;;) { | 
					
						
							|  |  |  |         int bzerror; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-02 23:05:56 +01:00
										 |  |  |         /* On a 64-bit system, len might not fit in avail_in (an unsigned int).
 | 
					
						
							|  |  |  |            Do compression in chunks of no more than UINT_MAX bytes each. */ | 
					
						
							| 
									
										
										
										
											2011-04-12 23:02:42 +02:00
										 |  |  |         if (c->bzs.avail_in == 0 && len > 0) { | 
					
						
							| 
									
										
										
										
											2013-06-04 23:18:48 +02:00
										 |  |  |             c->bzs.avail_in = (unsigned int)Py_MIN(len, UINT_MAX); | 
					
						
							| 
									
										
										
										
											2011-04-12 23:02:42 +02:00
										 |  |  |             len -= c->bzs.avail_in; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-02 23:05:56 +01:00
										 |  |  |         /* In regular compression mode, stop when input data is exhausted. */ | 
					
						
							|  |  |  |         if (action == BZ_RUN && c->bzs.avail_in == 0) | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (c->bzs.avail_out == 0) { | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |             if (OutputBuffer_Grow(&buffer, &c->bzs.next_out, &c->bzs.avail_out) < 0) { | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  |                 goto error; | 
					
						
							| 
									
										
										
										
											2012-10-21 21:16:58 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-01-02 23:05:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Py_BEGIN_ALLOW_THREADS | 
					
						
							|  |  |  |         bzerror = BZ2_bzCompress(&c->bzs, action); | 
					
						
							|  |  |  |         Py_END_ALLOW_THREADS | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-02 23:05:56 +01:00
										 |  |  |         if (catch_bz2_error(bzerror)) | 
					
						
							|  |  |  |             goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* In flushing mode, stop when all buffered data has been flushed. */ | 
					
						
							|  |  |  |         if (action == BZ_FINISH && bzerror == BZ_STREAM_END) | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |     result = OutputBuffer_Finish(&buffer, c->bzs.avail_out); | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  |     if (result != NULL) { | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |     OutputBuffer_OnError(&buffer); | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | module _bz2 | 
					
						
							| 
									
										
										
										
											2014-01-25 20:43:29 -08:00
										 |  |  | class _bz2.BZ2Compressor "BZ2Compressor *" "&BZ2Compressor_Type" | 
					
						
							|  |  |  | class _bz2.BZ2Decompressor "BZ2Decompressor *" "&BZ2Decompressor_Type" | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							| 
									
										
										
										
											2015-04-03 23:53:51 +03:00
										 |  |  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dc7d7992a79f9cb7]*/ | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-25 21:30:37 -08:00
										 |  |  | #include "clinic/_bz2module.c.h"
 | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _bz2.BZ2Compressor.compress | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data: Py_buffer | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Provide data to the compressor object. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Returns a chunk of compressed data if possible, or b'' otherwise. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When you have finished providing data to the compressor, call the | 
					
						
							|  |  |  | flush() method to finish the compression process. | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | _bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data) | 
					
						
							| 
									
										
										
										
											2014-01-28 05:00:08 -08:00
										 |  |  | /*[clinic end generated code: output=59365426e941fbcc input=85c963218070fc4c]*/ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     PyObject *result = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ACQUIRE_LOCK(self); | 
					
						
							|  |  |  |     if (self->flushed) | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_ValueError, "Compressor has been flushed"); | 
					
						
							|  |  |  |     else | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  |         result = compress(self, data->buf, data->len, BZ_RUN); | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     RELEASE_LOCK(self); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _bz2.BZ2Compressor.flush | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Finish the compression process. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Returns the compressed data left in internal buffers. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The compressor object may not be used after this method is called. | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self) | 
					
						
							| 
									
										
										
										
											2014-01-28 05:00:08 -08:00
										 |  |  | /*[clinic end generated code: output=3ef03fc1b092a701 input=d64405d3c6f76691]*/ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     PyObject *result = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ACQUIRE_LOCK(self); | 
					
						
							|  |  |  |     if (self->flushed) | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_ValueError, "Repeated call to flush()"); | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         self->flushed = 1; | 
					
						
							|  |  |  |         result = compress(self, NULL, 0, BZ_FINISH); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     RELEASE_LOCK(self); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-07 16:50:27 +02:00
										 |  |  | static void* | 
					
						
							|  |  |  | BZ2_Malloc(void* ctx, int items, int size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (items < 0 || size < 0) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2018-10-28 19:45:50 +03:00
										 |  |  |     if (size != 0 && (size_t)items > (size_t)PY_SSIZE_T_MAX / (size_t)size) | 
					
						
							| 
									
										
										
										
											2013-07-07 16:50:27 +02:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     /* PyMem_Malloc() cannot be used: compress() and decompress()
 | 
					
						
							|  |  |  |        release the GIL */ | 
					
						
							| 
									
										
										
										
											2018-10-28 19:45:50 +03:00
										 |  |  |     return PyMem_RawMalloc((size_t)items * (size_t)size); | 
					
						
							| 
									
										
										
										
											2013-07-07 16:50:27 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | BZ2_Free(void* ctx, void *ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-07-07 17:10:34 +02:00
										 |  |  |     PyMem_RawFree(ptr); | 
					
						
							| 
									
										
										
										
											2013-07-07 16:50:27 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | /* Argument Clinic is not used since the Argument Clinic always want to
 | 
					
						
							|  |  |  |    check the type which would be wrong here */ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | _bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel) | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     int bzerror; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!(1 <= compresslevel && compresslevel <= 9)) { | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_ValueError, | 
					
						
							|  |  |  |                         "compresslevel must be between 1 and 9"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self->lock = PyThread_allocate_lock(); | 
					
						
							|  |  |  |     if (self->lock == NULL) { | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-07 16:50:27 +02:00
										 |  |  |     self->bzs.opaque = NULL; | 
					
						
							|  |  |  |     self->bzs.bzalloc = BZ2_Malloc; | 
					
						
							|  |  |  |     self->bzs.bzfree = BZ2_Free; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0); | 
					
						
							|  |  |  |     if (catch_bz2_error(bzerror)) | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  |     PyThread_free_lock(self->lock); | 
					
						
							|  |  |  |     self->lock = NULL; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | PyDoc_STRVAR(_bz2_BZ2Compressor___init____doc__, | 
					
						
							|  |  |  | "BZ2Compressor(compresslevel=9, /)\n" | 
					
						
							|  |  |  | "--\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "Create a compressor object for compressing data incrementally.\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "  compresslevel\n" | 
					
						
							|  |  |  | "    Compression level, as a number between 1 and 9.\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "For one-shot compression, use the compress() function instead."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _bz2_BZ2Compressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int return_value = -1; | 
					
						
							|  |  |  |     int compresslevel = 9; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!_PyArg_NoKeywords("BZ2Compressor", kwargs)) { | 
					
						
							|  |  |  |         goto exit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!_PyArg_CheckPositional("BZ2Compressor", PyTuple_GET_SIZE(args), 0, 1)) { | 
					
						
							|  |  |  |         goto exit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PyTuple_GET_SIZE(args) < 1) { | 
					
						
							|  |  |  |         goto skip_optional; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     compresslevel = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0)); | 
					
						
							|  |  |  |     if (compresslevel == -1 && PyErr_Occurred()) { | 
					
						
							|  |  |  |         goto exit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | skip_optional: | 
					
						
							|  |  |  |     return_value = _bz2_BZ2Compressor___init___impl((BZ2Compressor *)self, compresslevel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | exit: | 
					
						
							|  |  |  |     return return_value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | static void | 
					
						
							|  |  |  | BZ2Compressor_dealloc(BZ2Compressor *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     BZ2_bzCompressEnd(&self->bzs); | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     if (self->lock != NULL) { | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |         PyThread_free_lock(self->lock); | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     } | 
					
						
							|  |  |  |     PyTypeObject *tp = Py_TYPE(self); | 
					
						
							|  |  |  |     tp->tp_free((PyObject *)self); | 
					
						
							|  |  |  |     Py_DECREF(tp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | BZ2Compressor_traverse(BZ2Compressor *self, visitproc visit, void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Py_VISIT(Py_TYPE(self)); | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef BZ2Compressor_methods[] = { | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  |     _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF | 
					
						
							|  |  |  |     _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     {NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | static PyType_Slot bz2_compressor_type_slots[] = { | 
					
						
							|  |  |  |     {Py_tp_dealloc, BZ2Compressor_dealloc}, | 
					
						
							|  |  |  |     {Py_tp_methods, BZ2Compressor_methods}, | 
					
						
							|  |  |  |     {Py_tp_init, _bz2_BZ2Compressor___init__}, | 
					
						
							|  |  |  |     {Py_tp_new, PyType_GenericNew}, | 
					
						
							|  |  |  |     {Py_tp_doc, (char *)_bz2_BZ2Compressor___init____doc__}, | 
					
						
							|  |  |  |     {Py_tp_traverse, BZ2Compressor_traverse}, | 
					
						
							|  |  |  |     {0, 0} | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | static PyType_Spec bz2_compressor_type_spec = { | 
					
						
							|  |  |  |     .name = "_bz2.BZ2Compressor", | 
					
						
							|  |  |  |     .basicsize = sizeof(BZ2Compressor), | 
					
						
							|  |  |  |     // Calling PyType_GetModuleState() on a subclass is not safe.
 | 
					
						
							|  |  |  |     // bz2_compressor_type_spec does not have Py_TPFLAGS_BASETYPE flag
 | 
					
						
							|  |  |  |     // which prevents to create a subclass.
 | 
					
						
							|  |  |  |     // So calling PyType_GetModuleState() in this file is always safe.
 | 
					
						
							| 
									
										
										
										
											2021-06-17 12:06:09 +02:00
										 |  |  |     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE), | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     .slots = bz2_compressor_type_slots, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* BZ2Decompressor class. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | /* Decompress data of length d->bzs_avail_in_real in d->bzs.next_in.  The output
 | 
					
						
							|  |  |  |    buffer is allocated dynamically and returned.  At most max_length bytes are | 
					
						
							|  |  |  |    returned, so some of the input may not be consumed. d->bzs.next_in and | 
					
						
							|  |  |  |    d->bzs_avail_in_real are updated to reflect the consumed input. */ | 
					
						
							|  |  |  | static PyObject* | 
					
						
							|  |  |  | decompress_buf(BZ2Decompressor *d, Py_ssize_t max_length) | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |     /* data_size is strictly positive, but because we repeatedly have to
 | 
					
						
							|  |  |  |        compare against max_length and PyBytes_GET_SIZE we declare it as | 
					
						
							|  |  |  |        signed */ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     PyObject *result; | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  |     _BlocksOutputBuffer buffer = {.list = NULL}; | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |     bz_stream *bzs = &d->bzs; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |     if (OutputBuffer_InitAndGrow(&buffer, max_length, &bzs->next_out, &bzs->avail_out) < 0) { | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |         int bzret; | 
					
						
							|  |  |  |         /* On a 64-bit system, buffer length might not fit in avail_out, so we
 | 
					
						
							|  |  |  |            do decompression in chunks of no more than UINT_MAX bytes | 
					
						
							|  |  |  |            each. Note that the expression for `avail` is guaranteed to be | 
					
						
							|  |  |  |            positive, so the cast is safe. */ | 
					
						
							|  |  |  |         bzs->avail_in = (unsigned int)Py_MIN(d->bzs_avail_in_real, UINT_MAX); | 
					
						
							|  |  |  |         d->bzs_avail_in_real -= bzs->avail_in; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Py_BEGIN_ALLOW_THREADS | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |         bzret = BZ2_bzDecompress(bzs); | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |         Py_END_ALLOW_THREADS | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         d->bzs_avail_in_real += bzs->avail_in; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |         if (catch_bz2_error(bzret)) | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |             goto error; | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |         if (bzret == BZ_STREAM_END) { | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |             d->eof = 1; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |         } else if (d->bzs_avail_in_real == 0) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } else if (bzs->avail_out == 0) { | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |             if (OutputBuffer_GetDataSize(&buffer, bzs->avail_out) == max_length) { | 
					
						
							| 
									
										
										
										
											2011-04-12 23:02:42 +02:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |             } | 
					
						
							|  |  |  |             if (OutputBuffer_Grow(&buffer, &bzs->next_out, &bzs->avail_out) < 0) { | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |                 goto error; | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-04-12 23:02:42 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |     result = OutputBuffer_Finish(&buffer, bzs->avail_out); | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  |     if (result != NULL) { | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							| 
									
										
										
										
											2021-05-01 07:32:49 +08:00
										 |  |  |     OutputBuffer_OnError(&buffer); | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char input_buffer_in_use; | 
					
						
							|  |  |  |     PyObject *result; | 
					
						
							|  |  |  |     bz_stream *bzs = &d->bzs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Prepend unconsumed input if necessary */ | 
					
						
							|  |  |  |     if (bzs->next_in != NULL) { | 
					
						
							|  |  |  |         size_t avail_now, avail_total; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Number of bytes we can append to input buffer */ | 
					
						
							|  |  |  |         avail_now = (d->input_buffer + d->input_buffer_size) | 
					
						
							|  |  |  |             - (bzs->next_in + d->bzs_avail_in_real); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Number of bytes we can append if we move existing
 | 
					
						
							|  |  |  |            contents to beginning of buffer (overwriting | 
					
						
							|  |  |  |            consumed input) */ | 
					
						
							|  |  |  |         avail_total = d->input_buffer_size - d->bzs_avail_in_real; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (avail_total < len) { | 
					
						
							|  |  |  |             size_t offset = bzs->next_in - d->input_buffer; | 
					
						
							|  |  |  |             char *tmp; | 
					
						
							|  |  |  |             size_t new_size = d->input_buffer_size + len - avail_now; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Assign to temporary variable first, so we don't
 | 
					
						
							|  |  |  |                lose address of allocated buffer if realloc fails */ | 
					
						
							|  |  |  |             tmp = PyMem_Realloc(d->input_buffer, new_size); | 
					
						
							|  |  |  |             if (tmp == NULL) { | 
					
						
							|  |  |  |                 PyErr_SetNone(PyExc_MemoryError); | 
					
						
							|  |  |  |                 return NULL; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             d->input_buffer = tmp; | 
					
						
							|  |  |  |             d->input_buffer_size = new_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             bzs->next_in = d->input_buffer + offset; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (avail_now < len) { | 
					
						
							|  |  |  |             memmove(d->input_buffer, bzs->next_in, | 
					
						
							|  |  |  |                     d->bzs_avail_in_real); | 
					
						
							|  |  |  |             bzs->next_in = d->input_buffer; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         memcpy((void*)(bzs->next_in + d->bzs_avail_in_real), data, len); | 
					
						
							|  |  |  |         d->bzs_avail_in_real += len; | 
					
						
							|  |  |  |         input_buffer_in_use = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         bzs->next_in = data; | 
					
						
							|  |  |  |         d->bzs_avail_in_real = len; | 
					
						
							|  |  |  |         input_buffer_in_use = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     result = decompress_buf(d, max_length); | 
					
						
							| 
									
										
										
										
											2016-10-01 02:45:17 +00:00
										 |  |  |     if(result == NULL) { | 
					
						
							|  |  |  |         bzs->next_in = NULL; | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2016-10-01 02:45:17 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (d->eof) { | 
					
						
							|  |  |  |         d->needs_input = 0; | 
					
						
							|  |  |  |         if (d->bzs_avail_in_real > 0) { | 
					
						
							| 
									
										
										
										
											2016-04-06 09:45:48 +03:00
										 |  |  |             Py_XSETREF(d->unused_data, | 
					
						
							| 
									
										
										
										
											2015-12-27 12:36:18 +02:00
										 |  |  |                       PyBytes_FromStringAndSize(bzs->next_in, d->bzs_avail_in_real)); | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |             if (d->unused_data == NULL) | 
					
						
							|  |  |  |                 goto error; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (d->bzs_avail_in_real == 0) { | 
					
						
							|  |  |  |         bzs->next_in = NULL; | 
					
						
							|  |  |  |         d->needs_input = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         d->needs_input = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* If we did not use the input buffer, we now have
 | 
					
						
							|  |  |  |            to copy the tail from the caller's buffer into the | 
					
						
							|  |  |  |            input buffer */ | 
					
						
							|  |  |  |         if (!input_buffer_in_use) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Discard buffer if it's too small
 | 
					
						
							|  |  |  |                (resizing it may needlessly copy the current contents) */ | 
					
						
							|  |  |  |             if (d->input_buffer != NULL && | 
					
						
							|  |  |  |                 d->input_buffer_size < d->bzs_avail_in_real) { | 
					
						
							|  |  |  |                 PyMem_Free(d->input_buffer); | 
					
						
							|  |  |  |                 d->input_buffer = NULL; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* Allocate if necessary */ | 
					
						
							|  |  |  |             if (d->input_buffer == NULL) { | 
					
						
							|  |  |  |                 d->input_buffer = PyMem_Malloc(d->bzs_avail_in_real); | 
					
						
							|  |  |  |                 if (d->input_buffer == NULL) { | 
					
						
							|  |  |  |                     PyErr_SetNone(PyExc_MemoryError); | 
					
						
							| 
									
										
										
										
											2012-10-21 21:16:58 +02:00
										 |  |  |                     goto error; | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 d->input_buffer_size = d->bzs_avail_in_real; | 
					
						
							| 
									
										
										
										
											2012-10-21 21:16:58 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             /* Copy tail */ | 
					
						
							|  |  |  |             memcpy(d->input_buffer, bzs->next_in, d->bzs_avail_in_real); | 
					
						
							|  |  |  |             bzs->next_in = d->input_buffer; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  |     Py_XDECREF(result); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | _bz2.BZ2Decompressor.decompress | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data: Py_buffer | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |     max_length: Py_ssize_t=-1 | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | Decompress *data*, returning uncompressed data as bytes. | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | If *max_length* is nonnegative, returns at most *max_length* bytes of | 
					
						
							|  |  |  | decompressed data. If this limit is reached and further output can be | 
					
						
							|  |  |  | produced, *self.needs_input* will be set to ``False``. In this case, the next | 
					
						
							|  |  |  | call to *decompress()* may provide *data* as b'' to obtain more of the output. | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | If all of the input data was decompressed and returned (either because this | 
					
						
							|  |  |  | was less than *max_length* bytes, or because *max_length* was negative), | 
					
						
							|  |  |  | *self.needs_input* will be set to True. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Attempting to decompress data after the end of stream is reached raises an | 
					
						
							|  |  |  | EOFError.  Any data found after the end of the stream is ignored and saved in | 
					
						
							|  |  |  | the unused_data attribute. | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | [clinic start generated code]*/ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							| 
									
										
										
										
											2015-04-14 18:07:59 -04:00
										 |  |  | _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, | 
					
						
							|  |  |  |                                      Py_ssize_t max_length) | 
					
						
							| 
									
										
										
										
											2016-05-02 13:45:20 +03:00
										 |  |  | /*[clinic end generated code: output=23e41045deb240a3 input=52e1ffc66a8ea624]*/ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     PyObject *result = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ACQUIRE_LOCK(self); | 
					
						
							|  |  |  |     if (self->eof) | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_EOFError, "End of stream already reached"); | 
					
						
							|  |  |  |     else | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |         result = decompress(self, data->buf, data->len, max_length); | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     RELEASE_LOCK(self); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | /* Argument Clinic is not used since the Argument Clinic always want to
 | 
					
						
							|  |  |  |    check the type which would be wrong here */ | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | static int | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  | _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self) | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     int bzerror; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-23 10:35:23 +02:00
										 |  |  |     PyThread_type_lock lock = PyThread_allocate_lock(); | 
					
						
							|  |  |  |     if (lock == NULL) { | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |         PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-06-23 10:35:23 +02:00
										 |  |  |     if (self->lock != NULL) { | 
					
						
							|  |  |  |         PyThread_free_lock(self->lock); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     self->lock = lock; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |     self->needs_input = 1; | 
					
						
							|  |  |  |     self->bzs_avail_in_real = 0; | 
					
						
							|  |  |  |     self->input_buffer = NULL; | 
					
						
							|  |  |  |     self->input_buffer_size = 0; | 
					
						
							| 
									
										
										
										
											2018-02-13 12:28:33 +02:00
										 |  |  |     Py_XSETREF(self->unused_data, PyBytes_FromStringAndSize(NULL, 0)); | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     if (self->unused_data == NULL) | 
					
						
							|  |  |  |         goto error; | 
					
						
							| 
									
										
										
										
											2015-03-18 21:53:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0); | 
					
						
							|  |  |  |     if (catch_bz2_error(bzerror)) | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  |     Py_CLEAR(self->unused_data); | 
					
						
							|  |  |  |     PyThread_free_lock(self->lock); | 
					
						
							|  |  |  |     self->lock = NULL; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | static int | 
					
						
							|  |  |  | _bz2_BZ2Decompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int return_value = -1; | 
					
						
							| 
									
										
										
										
											2021-04-28 14:58:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     if (!_PyArg_NoPositional("BZ2Decompressor", args)) { | 
					
						
							|  |  |  |         goto exit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) { | 
					
						
							|  |  |  |         goto exit; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | exit: | 
					
						
							|  |  |  |     return return_value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(_bz2_BZ2Decompressor___init____doc__, | 
					
						
							|  |  |  | "BZ2Decompressor()\n" | 
					
						
							|  |  |  | "--\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "Create a decompressor object for decompressing data incrementally.\n" | 
					
						
							|  |  |  | "\n" | 
					
						
							|  |  |  | "For one-shot decompression, use the decompress() function instead."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | static void | 
					
						
							|  |  |  | BZ2Decompressor_dealloc(BZ2Decompressor *self) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     if(self->input_buffer != NULL) { | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |         PyMem_Free(self->input_buffer); | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     BZ2_bzDecompressEnd(&self->bzs); | 
					
						
							|  |  |  |     Py_CLEAR(self->unused_data); | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     if (self->lock != NULL) { | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |         PyThread_free_lock(self->lock); | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyTypeObject *tp = Py_TYPE(self); | 
					
						
							|  |  |  |     tp->tp_free((PyObject *)self); | 
					
						
							|  |  |  |     Py_DECREF(tp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | BZ2Decompressor_traverse(BZ2Decompressor *self, visitproc visit, void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Py_VISIT(Py_TYPE(self)); | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef BZ2Decompressor_methods[] = { | 
					
						
							| 
									
										
										
										
											2014-01-25 12:07:57 +02:00
										 |  |  |     _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     {NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(BZ2Decompressor_eof__doc__, | 
					
						
							|  |  |  | "True if the end-of-stream marker has been reached."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyDoc_STRVAR(BZ2Decompressor_unused_data__doc__, | 
					
						
							|  |  |  | "Data found after the end of the compressed stream."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  | PyDoc_STRVAR(BZ2Decompressor_needs_input_doc, | 
					
						
							|  |  |  | "True if more input is needed before more decompressed data can be produced."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | static PyMemberDef BZ2Decompressor_members[] = { | 
					
						
							|  |  |  |     {"eof", T_BOOL, offsetof(BZ2Decompressor, eof), | 
					
						
							|  |  |  |      READONLY, BZ2Decompressor_eof__doc__}, | 
					
						
							|  |  |  |     {"unused_data", T_OBJECT_EX, offsetof(BZ2Decompressor, unused_data), | 
					
						
							|  |  |  |      READONLY, BZ2Decompressor_unused_data__doc__}, | 
					
						
							| 
									
										
										
										
											2015-02-26 13:08:07 +01:00
										 |  |  |     {"needs_input", T_BOOL, offsetof(BZ2Decompressor, needs_input), READONLY, | 
					
						
							|  |  |  |      BZ2Decompressor_needs_input_doc}, | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  |     {NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | static PyType_Slot bz2_decompressor_type_slots[] = { | 
					
						
							|  |  |  |     {Py_tp_dealloc, BZ2Decompressor_dealloc}, | 
					
						
							|  |  |  |     {Py_tp_methods, BZ2Decompressor_methods}, | 
					
						
							|  |  |  |     {Py_tp_init, _bz2_BZ2Decompressor___init__}, | 
					
						
							|  |  |  |     {Py_tp_doc, (char *)_bz2_BZ2Decompressor___init____doc__}, | 
					
						
							|  |  |  |     {Py_tp_members, BZ2Decompressor_members}, | 
					
						
							|  |  |  |     {Py_tp_new, PyType_GenericNew}, | 
					
						
							|  |  |  |     {Py_tp_traverse, BZ2Decompressor_traverse}, | 
					
						
							|  |  |  |     {0, 0} | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | static PyType_Spec bz2_decompressor_type_spec = { | 
					
						
							|  |  |  |     .name = "_bz2.BZ2Decompressor", | 
					
						
							|  |  |  |     .basicsize = sizeof(BZ2Decompressor), | 
					
						
							|  |  |  |     // Calling PyType_GetModuleState() on a subclass is not safe.
 | 
					
						
							|  |  |  |     // bz2_decompressor_type_spec does not have Py_TPFLAGS_BASETYPE flag
 | 
					
						
							|  |  |  |     // which prevents to create a subclass.
 | 
					
						
							|  |  |  |     // So calling PyType_GetModuleState() in this file is always safe.
 | 
					
						
							| 
									
										
										
										
											2021-06-17 12:06:09 +02:00
										 |  |  |     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE), | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     .slots = bz2_decompressor_type_slots, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Module initialization. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 19:17:39 +08:00
										 |  |  | static int | 
					
						
							|  |  |  | _bz2_exec(PyObject *module) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     _bz2_state *state = get_bz2_state(module); | 
					
						
							|  |  |  |     state->bz2_compressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, | 
					
						
							|  |  |  |                                                             &bz2_compressor_type_spec, NULL); | 
					
						
							|  |  |  |     if (state->bz2_compressor_type == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (PyModule_AddType(module, state->bz2_compressor_type) < 0) { | 
					
						
							| 
									
										
										
										
											2020-02-18 19:17:39 +08:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     state->bz2_decompressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, | 
					
						
							|  |  |  |                                                          &bz2_decompressor_type_spec, NULL); | 
					
						
							|  |  |  |     if (state->bz2_decompressor_type == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (PyModule_AddType(module, state->bz2_decompressor_type) < 0) { | 
					
						
							| 
									
										
										
										
											2020-02-18 19:17:39 +08:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  | static int | 
					
						
							|  |  |  | _bz2_traverse(PyObject *module, visitproc visit, void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _bz2_state *state = get_bz2_state(module); | 
					
						
							|  |  |  |     Py_VISIT(state->bz2_compressor_type); | 
					
						
							|  |  |  |     Py_VISIT(state->bz2_decompressor_type); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _bz2_clear(PyObject *module) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _bz2_state *state = get_bz2_state(module); | 
					
						
							|  |  |  |     Py_CLEAR(state->bz2_compressor_type); | 
					
						
							|  |  |  |     Py_CLEAR(state->bz2_decompressor_type); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | _bz2_free(void *module) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _bz2_clear((PyObject *)module); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-18 19:17:39 +08:00
										 |  |  | static struct PyModuleDef_Slot _bz2_slots[] = { | 
					
						
							|  |  |  |     {Py_mod_exec, _bz2_exec}, | 
					
						
							|  |  |  |     {0, NULL} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | static struct PyModuleDef _bz2module = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							| 
									
										
										
										
											2020-06-20 00:56:13 +09:00
										 |  |  |     .m_name = "_bz2", | 
					
						
							|  |  |  |     .m_size = sizeof(_bz2_state), | 
					
						
							|  |  |  |     .m_slots = _bz2_slots, | 
					
						
							|  |  |  |     .m_traverse = _bz2_traverse, | 
					
						
							|  |  |  |     .m_clear = _bz2_clear, | 
					
						
							|  |  |  |     .m_free = _bz2_free, | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyMODINIT_FUNC | 
					
						
							|  |  |  | PyInit__bz2(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-18 19:17:39 +08:00
										 |  |  |     return PyModuleDef_Init(&_bz2module); | 
					
						
							| 
									
										
										
										
											2011-04-03 17:05:46 +02:00
										 |  |  | } |