diff --git a/SOURCES/CVE-2025-6176.patch b/SOURCES/CVE-2025-6176.patch new file mode 100644 index 0000000..e9da589 --- /dev/null +++ b/SOURCES/CVE-2025-6176.patch @@ -0,0 +1,2057 @@ +diff -urN brotli-1.0.6/python/bro.py brotli-1.0.6-modified/python/bro.py +--- brotli-1.0.6/python/bro.py 2018-09-13 23:01:23.000000000 +0530 ++++ brotli-1.0.6-modified/python/bro.py 2023-08-29 16:30:29.000000000 +0530 +@@ -1,16 +1,21 @@ + #! /usr/bin/env python + """Compression/decompression utility using the Brotli algorithm.""" + ++# Note: Python2 has been deprecated long ago, but some projects out in ++# the wide world may still use it nevertheless. This should not ++# deprive them from being able to run Brotli. + from __future__ import print_function ++ + import argparse +-import sys + import os + import platform ++import sys + + import brotli + ++ + # default values of encoder parameters +-DEFAULT_PARAMS = { ++_DEFAULT_PARAMS = { + 'mode': brotli.MODE_GENERIC, + 'quality': 11, + 'lgwin': 22, +@@ -19,17 +24,32 @@ + + + def get_binary_stdio(stream): +- """ Return the specified standard input, output or errors stream as a +- 'raw' buffer object suitable for reading/writing binary data from/to it. ++ """Return the specified stdin/stdout/stderr stream. ++ ++ If the stdio stream requested (i.e. sys.(stdin|stdout|stderr)) ++ has been replaced with a stream object that does not have a `.buffer` ++ attribute, this will return the original stdio stream's buffer, i.e. ++ `sys.__(stdin|stdout|stderr)__.buffer`. ++ ++ Args: ++ stream: One of 'stdin', 'stdout', 'stderr'. ++ ++ Returns: ++ The stream, as a 'raw' buffer object (i.e. io.BufferedIOBase subclass ++ instance such as io.Bufferedreader/io.BufferedWriter), suitable for ++ reading/writing binary data from/to it. + """ +- assert stream in ['stdin', 'stdout', 'stderr'], 'invalid stream name' +- stdio = getattr(sys, stream) ++ if stream == 'stdin': stdio = sys.stdin ++ elif stream == 'stdout': stdio = sys.stdout ++ elif stream == 'stderr': stdio = sys.stderr ++ else: ++ raise ValueError('invalid stream name: %s' % (stream,)) + if sys.version_info[0] < 3: + if sys.platform == 'win32': + # set I/O stream binary flag on python2.x (Windows) + runtime = platform.python_implementation() + if runtime == 'PyPy': +- # the msvcrt trick doesn't work in pypy, so I use fdopen ++ # the msvcrt trick doesn't work in pypy, so use fdopen(). + mode = 'rb' if stream == 'stdin' else 'wb' + stdio = os.fdopen(stdio.fileno(), mode, 0) + else: +@@ -38,12 +58,20 @@ + msvcrt.setmode(stdio.fileno(), os.O_BINARY) + return stdio + else: +- # get 'buffer' attribute to read/write binary data on python3.x +- if hasattr(stdio, 'buffer'): ++ try: + return stdio.buffer +- else: +- orig_stdio = getattr(sys, '__%s__' % stream) +- return orig_stdio.buffer ++ except AttributeError: ++ # The Python reference explains ++ # (-> https://docs.python.org/3/library/sys.html#sys.stdin) ++ # that the `.buffer` attribute might not exist, since ++ # the standard streams might have been replaced by something else ++ # (such as an `io.StringIO()` - perhaps via ++ # `contextlib.redirect_stdout()`). ++ # We fall back to the original stdio in these cases. ++ if stream == 'stdin': return sys.__stdin__.buffer ++ if stream == 'stdout': return sys.__stdout__.buffer ++ if stream == 'stderr': return sys.__stderr__.buffer ++ assert False, 'Impossible Situation.' + + + def main(args=None): +@@ -51,7 +79,7 @@ + parser = argparse.ArgumentParser( + prog=os.path.basename(__file__), description=__doc__) + parser.add_argument( +- '--version', action='version', version=brotli.__version__) ++ '--version', action='version', version=brotli.version) + parser.add_argument( + '-i', + '--input', +@@ -114,46 +142,52 @@ + help='Base 2 logarithm of the maximum input block size. ' + 'Range is 16 to 24. If set to 0, the value will be set based ' + 'on the quality. Defaults to 0.') +- # set default values using global DEFAULT_PARAMS dictionary +- parser.set_defaults(**DEFAULT_PARAMS) ++ # set default values using global _DEFAULT_PARAMS dictionary ++ parser.set_defaults(**_DEFAULT_PARAMS) + + options = parser.parse_args(args=args) + + if options.infile: +- if not os.path.isfile(options.infile): +- parser.error('file "%s" not found' % options.infile) +- with open(options.infile, 'rb') as infile: +- data = infile.read() ++ try: ++ with open(options.infile, 'rb') as infile: ++ data = infile.read() ++ except OSError: ++ parser.error('Could not read --infile: %s' % (infile,)) + else: + if sys.stdin.isatty(): + # interactive console, just quit +- parser.error('no input') ++ parser.error('No input (called from interactive terminal).') + infile = get_binary_stdio('stdin') + data = infile.read() + + if options.outfile: +- if os.path.isfile(options.outfile) and not options.force: +- parser.error('output file exists') ++ # Caution! If `options.outfile` is a broken symlink, will try to ++ # redirect the write according to symlink. ++ if os.path.exists(options.outfile) and not options.force: ++ parser.error(('Target --outfile=%s already exists, ' ++ 'but --force was not requested.') % (outfile,)) + outfile = open(options.outfile, 'wb') ++ did_open_outfile = True + else: + outfile = get_binary_stdio('stdout') +- ++ did_open_outfile = False + try: +- if options.decompress: +- data = brotli.decompress(data) +- else: +- data = brotli.compress( +- data, +- mode=options.mode, +- quality=options.quality, +- lgwin=options.lgwin, +- lgblock=options.lgblock) ++ try: ++ if options.decompress: ++ data = brotli.decompress(data) ++ else: ++ data = brotli.compress( ++ data, ++ mode=options.mode, ++ quality=options.quality, ++ lgwin=options.lgwin, ++ lgblock=options.lgblock) ++ outfile.write(data) ++ finally: ++ if did_open_outfile: outfile.close() + except brotli.error as e: + parser.exit(1, +- 'bro: error: %s: %s' % (e, options.infile or 'sys.stdin')) +- +- outfile.write(data) +- outfile.close() ++ 'bro: error: %s: %s' % (e, options.infile or '{stdin}')) + + + if __name__ == '__main__': +diff -urN brotli-1.0.6/python/_brotli.c brotli-1.0.6-modified/python/_brotli.c +--- brotli-1.0.6/python/_brotli.c 1970-01-01 05:30:00.000000000 +0530 ++++ brotli-1.0.6-modified/python/_brotli.c 2026-01-27 14:34:57.771022855 +0530 +@@ -0,0 +1,1073 @@ ++#define PY_SSIZE_T_CLEAN 1 ++#include ++#include ++#include ++ ++#include ++#include ++ ++#if PY_MAJOR_VERSION >= 3 ++#define PyInt_Check PyLong_Check ++#define PyInt_AsLong PyLong_AsLong ++#else ++#define Py_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) ++#endif ++ ++static PyObject *BrotliError; ++ ++/* ----------------------------------- ++ BlocksOutputBuffer code ++ ----------------------------------- */ ++typedef struct { ++ /* List of blocks */ ++ PyObject *list; ++ /* Number of whole allocated size. */ ++ Py_ssize_t allocated; ++ Py_ssize_t size_limit; ++} BlocksOutputBuffer; ++ ++static const char unable_allocate_msg[] = "Unable to allocate output buffer."; ++ ++/* Block size sequence */ ++#define KB (1024) ++#define MB (1024*1024) ++static const Py_ssize_t BUFFER_BLOCK_SIZE[] = ++ { 32*KB, 64*KB, 256*KB, 1*MB, 4*MB, 8*MB, 16*MB, 16*MB, ++ 32*MB, 32*MB, 32*MB, 32*MB, 64*MB, 64*MB, 128*MB, 128*MB, ++ 256*MB }; ++#undef KB ++#undef MB ++ ++/* According to the block sizes defined by BUFFER_BLOCK_SIZE, the whole ++ allocated size growth step is: ++ 1 32 KB +32 KB ++ 2 96 KB +64 KB ++ 3 352 KB +256 KB ++ 4 1.34 MB +1 MB ++ 5 5.34 MB +4 MB ++ 6 13.34 MB +8 MB ++ 7 29.34 MB +16 MB ++ 8 45.34 MB +16 MB ++ 9 77.34 MB +32 MB ++ 10 109.34 MB +32 MB ++ 11 141.34 MB +32 MB ++ 12 173.34 MB +32 MB ++ 13 237.34 MB +64 MB ++ 14 301.34 MB +64 MB ++ 15 429.34 MB +128 MB ++ 16 557.34 MB +128 MB ++ 17 813.34 MB +256 MB ++ 18 1069.34 MB +256 MB ++ 19 1325.34 MB +256 MB ++ 20 1581.34 MB +256 MB ++ 21 1837.34 MB +256 MB ++ 22 2093.34 MB +256 MB ++ ... ++*/ ++ ++/* Initialize the buffer, and grow the buffer. ++ Return 0 on success ++ Return -1 on failure ++*/ ++static inline int ++BlocksOutputBuffer_InitAndGrow(BlocksOutputBuffer *buffer, Py_ssize_t size_limit, ++ size_t *avail_out, uint8_t **next_out) ++{ ++ PyObject *b; ++ Py_ssize_t block_size = BUFFER_BLOCK_SIZE[0]; ++ ++ assert(size_limit > 0); ++ ++ if (size_limit < block_size) { ++ block_size = size_limit; ++ } ++ ++ // Ensure .list was set to NULL, for BlocksOutputBuffer_OnError(). ++ assert(buffer->list == NULL); ++ ++ // The first block ++ b = PyBytes_FromStringAndSize(NULL, block_size); ++ if (b == NULL) { ++ return -1; ++ } ++ ++ // Create list ++ buffer->list = PyList_New(1); ++ if (buffer->list == NULL) { ++ Py_DECREF(b); ++ return -1; ++ } ++ PyList_SET_ITEM(buffer->list, 0, b); ++ ++ // Set variables ++ buffer->allocated = block_size; ++ buffer->size_limit = size_limit; ++ ++ *avail_out = (size_t) block_size; ++ *next_out = (uint8_t*) PyBytes_AS_STRING(b); ++ return 0; ++} ++ ++/* Grow the buffer. The avail_out must be 0, please check it before calling. ++ Return 0 on success ++ Return -1 on failure ++*/ ++static inline int ++BlocksOutputBuffer_Grow(BlocksOutputBuffer *buffer, ++ size_t *avail_out, uint8_t **next_out) ++{ ++ PyObject *b; ++ const Py_ssize_t list_len = Py_SIZE(buffer->list); ++ Py_ssize_t block_size; ++ ++ // Ensure no gaps in the data ++ assert(*avail_out == 0); ++ ++ // Get block size ++ if (list_len < (Py_ssize_t) Py_ARRAY_LENGTH(BUFFER_BLOCK_SIZE)) { ++ block_size = BUFFER_BLOCK_SIZE[list_len]; ++ } else { ++ block_size = BUFFER_BLOCK_SIZE[Py_ARRAY_LENGTH(BUFFER_BLOCK_SIZE) - 1]; ++ } ++ ++ if (block_size > buffer->size_limit - buffer->allocated) { ++ block_size = buffer->size_limit - buffer->allocated; ++ } ++ ++ if (block_size == 0) { ++ // We are at the size_limit (either the provided one, in which case we ++ // shouldn't have been called, or the implicit PY_SSIZE_T_MAX one, in ++ // which case we wouldn't be able to concatenate the blocks at the end). ++ PyErr_SetString(PyExc_MemoryError, "too long"); ++ return -1; ++ } ++ ++ // Create the block ++ b = PyBytes_FromStringAndSize(NULL, block_size); ++ if (b == NULL) { ++ PyErr_SetString(PyExc_MemoryError, unable_allocate_msg); ++ return -1; ++ } ++ if (PyList_Append(buffer->list, b) < 0) { ++ Py_DECREF(b); ++ return -1; ++ } ++ Py_DECREF(b); ++ ++ // Set variables ++ buffer->allocated += block_size; ++ ++ *avail_out = (size_t) block_size; ++ *next_out = (uint8_t*) PyBytes_AS_STRING(b); ++ return 0; ++} ++ ++/* Finish the buffer. ++ Return a bytes object on success ++ Return NULL on failure ++*/ ++static inline PyObject * ++BlocksOutputBuffer_Finish(BlocksOutputBuffer *buffer, size_t avail_out) ++{ ++ PyObject *result, *block; ++ const Py_ssize_t list_len = Py_SIZE(buffer->list); ++ ++ // Fast path for single block ++ if ((list_len == 1 && avail_out == 0) || ++ (list_len == 2 && Py_SIZE(PyList_GET_ITEM(buffer->list, 1)) == (Py_ssize_t) avail_out)) ++ { ++ block = PyList_GET_ITEM(buffer->list, 0); ++ Py_INCREF(block); ++ ++ Py_CLEAR(buffer->list); ++ return block; ++ } ++ ++ // Final bytes object ++ result = PyBytes_FromStringAndSize(NULL, buffer->allocated - avail_out); ++ if (result == NULL) { ++ PyErr_SetString(PyExc_MemoryError, unable_allocate_msg); ++ return NULL; ++ } ++ ++ // Memory copy ++ if (list_len > 0) { ++ char *posi = PyBytes_AS_STRING(result); ++ ++ // Blocks except the last one ++ Py_ssize_t i = 0; ++ for (; i < list_len-1; i++) { ++ block = PyList_GET_ITEM(buffer->list, i); ++ memcpy(posi, PyBytes_AS_STRING(block), Py_SIZE(block)); ++ posi += Py_SIZE(block); ++ } ++ // The last block ++ block = PyList_GET_ITEM(buffer->list, i); ++ memcpy(posi, PyBytes_AS_STRING(block), Py_SIZE(block) - avail_out); ++ } else { ++ assert(Py_SIZE(result) == 0); ++ } ++ ++ Py_CLEAR(buffer->list); ++ return result; ++} ++ ++/* Clean up the buffer */ ++static inline void ++BlocksOutputBuffer_OnError(BlocksOutputBuffer *buffer) ++{ ++ Py_CLEAR(buffer->list); ++} ++ ++ ++static int as_bounded_int(PyObject *o, int* result, int lower_bound, int upper_bound) { ++ long value = PyInt_AsLong(o); ++ if ((value < (long) lower_bound) || (value > (long) upper_bound)) { ++ return 0; ++ } ++ *result = (int) value; ++ return 1; ++} ++ ++static int mode_convertor(PyObject *o, BrotliEncoderMode *mode) { ++ if (!PyInt_Check(o)) { ++ PyErr_SetString(BrotliError, "Invalid mode"); ++ return 0; ++ } ++ ++ int mode_value = -1; ++ if (!as_bounded_int(o, &mode_value, 0, 255)) { ++ PyErr_SetString(BrotliError, "Invalid mode"); ++ return 0; ++ } ++ *mode = (BrotliEncoderMode) mode_value; ++ if (*mode != BROTLI_MODE_GENERIC && ++ *mode != BROTLI_MODE_TEXT && ++ *mode != BROTLI_MODE_FONT) { ++ PyErr_SetString(BrotliError, "Invalid mode"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int quality_convertor(PyObject *o, int *quality) { ++ if (!PyInt_Check(o)) { ++ PyErr_SetString(BrotliError, "Invalid quality"); ++ return 0; ++ } ++ ++ if (!as_bounded_int(o, quality, 0, 11)) { ++ PyErr_SetString(BrotliError, "Invalid quality. Range is 0 to 11."); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int lgwin_convertor(PyObject *o, int *lgwin) { ++ if (!PyInt_Check(o)) { ++ PyErr_SetString(BrotliError, "Invalid lgwin"); ++ return 0; ++ } ++ ++ if (!as_bounded_int(o, lgwin, 10, 24)) { ++ PyErr_SetString(BrotliError, "Invalid lgwin. Range is 10 to 24."); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int lgblock_convertor(PyObject *o, int *lgblock) { ++ if (!PyInt_Check(o)) { ++ PyErr_SetString(BrotliError, "Invalid lgblock"); ++ return 0; ++ } ++ ++ if (!as_bounded_int(o, lgblock, 0, 24) || (*lgblock != 0 && *lgblock < 16)) { ++ PyErr_SetString(BrotliError, "Invalid lgblock. Can be 0 or in range 16 to 24."); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static PyObject* compress_stream(BrotliEncoderState* enc, BrotliEncoderOperation op, ++ uint8_t* input, size_t input_length) { ++ BROTLI_BOOL ok; ++ ++ size_t available_in = input_length; ++ const uint8_t* next_in = input; ++ ++ size_t available_out; ++ uint8_t* next_out; ++ BlocksOutputBuffer buffer = {.list=NULL}; ++ PyObject *ret; ++ ++ if (BlocksOutputBuffer_InitAndGrow(&buffer, PY_SSIZE_T_MAX, &available_out, &next_out) < 0) { ++ goto error; ++ } ++ ++ while (1) { ++ Py_BEGIN_ALLOW_THREADS ++ ok = BrotliEncoderCompressStream(enc, op, ++ &available_in, &next_in, ++ &available_out, &next_out, NULL); ++ Py_END_ALLOW_THREADS ++ if (!ok) { ++ goto error; ++ } ++ ++ if (available_in || BrotliEncoderHasMoreOutput(enc)) { ++ if (available_out == 0) { ++ if (BlocksOutputBuffer_Grow(&buffer, &available_out, &next_out) < 0) { ++ goto error; ++ } ++ } ++ continue; ++ } ++ ++ break; ++ } ++ ++ ret = BlocksOutputBuffer_Finish(&buffer, available_out); ++ if (ret != NULL) { ++ return ret; ++ } ++ ++error: ++ BlocksOutputBuffer_OnError(&buffer); ++ return NULL; ++} ++ ++PyDoc_STRVAR(brotli_Compressor_doc, ++"An object to compress a byte string.\n" ++"\n" ++"Signature:\n" ++" Compressor(mode=MODE_GENERIC, quality=11, lgwin=22, lgblock=0)\n" ++"\n" ++"Args:\n" ++" mode (int, optional): The compression mode can be MODE_GENERIC (default),\n" ++" MODE_TEXT (for UTF-8 format text input) or MODE_FONT (for WOFF 2.0). \n" ++" quality (int, optional): Controls the compression-speed vs compression-\n" ++" density tradeoff. The higher the quality, the slower the compression.\n" ++" Range is 0 to 11. Defaults to 11.\n" ++" lgwin (int, optional): Base 2 logarithm of the sliding window size. Range\n" ++" is 10 to 24. Defaults to 22.\n" ++" lgblock (int, optional): Base 2 logarithm of the maximum input block size.\n" ++" Range is 16 to 24. If set to 0, the value will be set based on the\n" ++" quality. Defaults to 0.\n" ++"\n" ++"Raises:\n" ++" brotli.error: If arguments are invalid.\n"); ++ ++typedef struct { ++ PyObject_HEAD ++ BrotliEncoderState* enc; ++} brotli_Compressor; ++ ++static void brotli_Compressor_dealloc(brotli_Compressor* self) { ++ BrotliEncoderDestroyInstance(self->enc); ++ #if PY_MAJOR_VERSION >= 3 ++ Py_TYPE(self)->tp_free((PyObject*)self); ++ #else ++ self->ob_type->tp_free((PyObject*)self); ++ #endif ++} ++ ++static PyObject* brotli_Compressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) { ++ brotli_Compressor *self; ++ self = (brotli_Compressor *)type->tp_alloc(type, 0); ++ ++ if (self != NULL) { ++ self->enc = BrotliEncoderCreateInstance(0, 0, 0); ++ } ++ ++ return (PyObject *)self; ++} ++ ++static int brotli_Compressor_init(brotli_Compressor *self, PyObject *args, PyObject *keywds) { ++ BrotliEncoderMode mode = (BrotliEncoderMode) -1; ++ int quality = -1; ++ int lgwin = -1; ++ int lgblock = -1; ++ int ok; ++ ++ static const char *kwlist[] = {"mode", "quality", "lgwin", "lgblock", NULL}; ++ ++ ok = PyArg_ParseTupleAndKeywords(args, keywds, "|O&O&O&O&:Compressor", ++ (char **) kwlist, ++ &mode_convertor, &mode, ++ &quality_convertor, &quality, ++ &lgwin_convertor, &lgwin, ++ &lgblock_convertor, &lgblock); ++ if (!ok) ++ return -1; ++ if (!self->enc) ++ return -1; ++ ++ if ((int) mode != -1) ++ BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_MODE, (uint32_t)mode); ++ if (quality != -1) ++ BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_QUALITY, (uint32_t)quality); ++ if (lgwin != -1) ++ BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGWIN, (uint32_t)lgwin); ++ if (lgblock != -1) ++ BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGBLOCK, (uint32_t)lgblock); ++ ++ return 0; ++} ++ ++PyDoc_STRVAR(brotli_Compressor_process_doc, ++"Process \"string\" for compression, returning a string that contains \n" ++"compressed output data. This data should be concatenated to the output \n" ++"produced by any preceding calls to the \"process()\" or flush()\" methods. \n" ++"Some or all of the input may be kept in internal buffers for later \n" ++"processing, and the compressed output data may be empty until enough input \n" ++"has been accumulated.\n" ++"\n" ++"Signature:\n" ++" compress(string)\n" ++"\n" ++"Args:\n" ++" string (bytes): The input data\n" ++"\n" ++"Returns:\n" ++" The compressed output data (bytes)\n" ++"\n" ++"Raises:\n" ++" brotli.error: If compression fails\n"); ++ ++static PyObject* brotli_Compressor_process(brotli_Compressor *self, PyObject *args) { ++ PyObject* ret; ++ Py_buffer input; ++ int ok; ++ ++#if PY_MAJOR_VERSION >= 3 ++ ok = PyArg_ParseTuple(args, "y*:process", &input); ++#else ++ ok = PyArg_ParseTuple(args, "s*:process", &input); ++#endif ++ ++ if (!ok) { ++ return NULL; ++ } ++ ++ if (!self->enc) { ++ goto error; ++ } ++ ++ ret = compress_stream(self->enc, BROTLI_OPERATION_PROCESS, ++ (uint8_t*) input.buf, input.len); ++ if (ret != NULL) { ++ goto finally; ++ } ++ ++error: ++ PyErr_SetString(BrotliError, ++ "BrotliEncoderCompressStream failed while processing the stream"); ++ ret = NULL; ++ ++finally: ++ PyBuffer_Release(&input); ++ return ret; ++} ++ ++PyDoc_STRVAR(brotli_Compressor_flush_doc, ++"Process all pending input, returning a string containing the remaining\n" ++"compressed data. This data should be concatenated to the output produced by\n" ++"any preceding calls to the \"process()\" or \"flush()\" methods.\n" ++"\n" ++"Signature:\n" ++" flush()\n" ++"\n" ++"Returns:\n" ++" The compressed output data (bytes)\n" ++"\n" ++"Raises:\n" ++" brotli.error: If compression fails\n"); ++ ++static PyObject* brotli_Compressor_flush(brotli_Compressor *self) { ++ PyObject *ret; ++ ++ if (!self->enc) { ++ goto error; ++ } ++ ++ ret = compress_stream(self->enc, BROTLI_OPERATION_FLUSH, ++ NULL, 0); ++ if (ret != NULL) { ++ goto finally; ++ } ++ ++error: ++ PyErr_SetString(BrotliError, ++ "BrotliEncoderCompressStream failed while flushing the stream"); ++ ret = NULL; ++finally: ++ return ret; ++} ++ ++PyDoc_STRVAR(brotli_Compressor_finish_doc, ++"Process all pending input and complete all compression, returning a string\n" ++"containing the remaining compressed data. This data should be concatenated\n" ++"to the output produced by any preceding calls to the \"process()\" or\n" ++"\"flush()\" methods.\n" ++"After calling \"finish()\", the \"process()\" and \"flush()\" methods\n" ++"cannot be called again, and a new \"Compressor\" object should be created.\n" ++"\n" ++"Signature:\n" ++" finish(string)\n" ++"\n" ++"Returns:\n" ++" The compressed output data (bytes)\n" ++"\n" ++"Raises:\n" ++" brotli.error: If compression fails\n"); ++ ++static PyObject* brotli_Compressor_finish(brotli_Compressor *self) { ++ PyObject *ret; ++ ++ if (!self->enc) { ++ goto error; ++ } ++ ++ ret = compress_stream(self->enc, BROTLI_OPERATION_FINISH, ++ NULL, 0); ++ ++ if (ret == NULL || !BrotliEncoderIsFinished(self->enc)) { ++ goto error; ++ } ++ goto finally; ++ ++error: ++ PyErr_SetString(BrotliError, ++ "BrotliEncoderCompressStream failed while finishing the stream"); ++ ret = NULL; ++finally: ++ return ret; ++} ++ ++static PyMemberDef brotli_Compressor_members[] = { ++ {NULL} /* Sentinel */ ++}; ++ ++static PyMethodDef brotli_Compressor_methods[] = { ++ {"process", (PyCFunction)brotli_Compressor_process, METH_VARARGS, brotli_Compressor_process_doc}, ++ {"flush", (PyCFunction)brotli_Compressor_flush, METH_NOARGS, brotli_Compressor_flush_doc}, ++ {"finish", (PyCFunction)brotli_Compressor_finish, METH_NOARGS, brotli_Compressor_finish_doc}, ++ {NULL} /* Sentinel */ ++}; ++ ++static PyTypeObject brotli_CompressorType = { ++ #if PY_MAJOR_VERSION >= 3 ++ PyVarObject_HEAD_INIT(NULL, 0) ++ #else ++ PyObject_HEAD_INIT(NULL) ++ 0, /* ob_size*/ ++ #endif ++ "brotli.Compressor", /* tp_name */ ++ sizeof(brotli_Compressor), /* tp_basicsize */ ++ 0, /* tp_itemsize */ ++ (destructor)brotli_Compressor_dealloc, /* tp_dealloc */ ++ 0, /* tp_print */ ++ 0, /* tp_getattr */ ++ 0, /* tp_setattr */ ++ 0, /* tp_compare */ ++ 0, /* tp_repr */ ++ 0, /* tp_as_number */ ++ 0, /* tp_as_sequence */ ++ 0, /* tp_as_mapping */ ++ 0, /* tp_hash */ ++ 0, /* tp_call */ ++ 0, /* tp_str */ ++ 0, /* tp_getattro */ ++ 0, /* tp_setattro */ ++ 0, /* tp_as_buffer */ ++ Py_TPFLAGS_DEFAULT, /* tp_flags */ ++ brotli_Compressor_doc, /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ brotli_Compressor_methods, /* tp_methods */ ++ brotli_Compressor_members, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ (initproc)brotli_Compressor_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ brotli_Compressor_new, /* tp_new */ ++}; ++ ++PyDoc_STRVAR(brotli_Decompressor_doc, ++"An object to decompress a byte string.\n" ++"\n" ++"Signature:\n" ++" Decompressor()\n" ++"\n" ++"Raises:\n" ++" brotli.error: If arguments are invalid.\n"); ++ ++typedef struct { ++ PyObject_HEAD ++ BrotliDecoderState* dec; ++ uint8_t* unconsumed_data; ++ size_t unconsumed_data_length; ++} brotli_Decompressor; ++ ++static void brotli_Decompressor_dealloc(brotli_Decompressor* self) { ++ BrotliDecoderDestroyInstance(self->dec); ++ if (self->unconsumed_data) ++ free(self->unconsumed_data); ++ #if PY_MAJOR_VERSION >= 3 ++ Py_TYPE(self)->tp_free((PyObject*)self); ++ #else ++ self->ob_type->tp_free((PyObject*)self); ++ #endif ++} ++ ++static PyObject* brotli_Decompressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) { ++ brotli_Decompressor *self; ++ self = (brotli_Decompressor *)type->tp_alloc(type, 0); ++ ++ if (self != NULL) { ++ self->dec = BrotliDecoderCreateInstance(0, 0, 0); ++ } ++ ++ self->unconsumed_data = NULL; ++ self->unconsumed_data_length = 0; ++ ++ return (PyObject *)self; ++} ++ ++static int brotli_Decompressor_init(brotli_Decompressor *self, PyObject *args, PyObject *keywds) { ++ int ok; ++ ++ static const char *kwlist[] = {NULL}; ++ ++ ok = PyArg_ParseTupleAndKeywords(args, keywds, "|:Decompressor", ++ (char **) kwlist); ++ if (!ok) ++ return -1; ++ if (!self->dec) ++ return -1; ++ ++ return 0; ++} ++ ++static PyObject* decompress_stream(brotli_Decompressor* self, ++ uint8_t* input, size_t input_length, Py_ssize_t max_output_length) { ++ BrotliDecoderResult result; ++ ++ size_t available_in = input_length; ++ const uint8_t* next_in = input; ++ ++ size_t available_out; ++ uint8_t* next_out; ++ uint8_t* new_tail; ++ BlocksOutputBuffer buffer = {.list=NULL}; ++ PyObject *ret; ++ ++ if (BlocksOutputBuffer_InitAndGrow(&buffer, max_output_length, &available_out, &next_out) < 0) { ++ goto error; ++ } ++ ++ while (1) { ++ Py_BEGIN_ALLOW_THREADS ++ result = BrotliDecoderDecompressStream(self->dec, ++ &available_in, &next_in, ++ &available_out, &next_out, NULL); ++ Py_END_ALLOW_THREADS ++ ++ if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { ++ if (available_out == 0) { ++ if (buffer.allocated == PY_SSIZE_T_MAX) { ++ PyErr_SetString(PyExc_MemoryError, unable_allocate_msg); ++ goto error; ++ } ++ if (buffer.allocated == max_output_length) { ++ // We've reached the output length limit. ++ break; ++ } ++ if (BlocksOutputBuffer_Grow(&buffer, &available_out, &next_out) < 0) { ++ goto error; ++ } ++ } ++ continue; ++ } ++ ++ if (result == BROTLI_DECODER_RESULT_ERROR || available_in != 0) { ++ available_in = 0; ++ goto error; ++ } ++ ++ break; ++ } ++ ++ ret = BlocksOutputBuffer_Finish(&buffer, available_out); ++ if (ret != NULL) { ++ goto finally; ++ } ++ ++error: ++ BlocksOutputBuffer_OnError(&buffer); ++ ret = NULL; ++ ++finally: ++ new_tail = available_in > 0 ? malloc(available_in) : NULL; ++ if (available_in > 0) { ++ memcpy(new_tail, next_in, available_in); ++ } ++ if (self->unconsumed_data) { ++ free(self->unconsumed_data); ++ } ++ self->unconsumed_data = new_tail; ++ self->unconsumed_data_length = available_in; ++ ++ return ret; ++} ++ ++ ++PyDoc_STRVAR(brotli_Decompressor_process_doc, ++"Process \"string\" for decompression, returning a string that contains \n" ++"decompressed output data. This data should be concatenated to the output \n" ++"produced by any preceding calls to the \"process()\" method. \n" ++"Some or all of the input may be kept in internal buffers for later \n" ++"processing, and the decompressed output data may be empty until enough input \n" ++"has been accumulated.\n" ++"If max_output_length is set, no more than max_output_length bytes will be\n" ++"returned. If the limit is reached, further calls to process (potentially with\n" ++"empty input) will continue to yield more data. If, after returning a string of\n" ++"the length equal to limit, can_accept_more_data() returns False, process()\n" ++"must only be called with empty input until can_accept_more_data() once again\n" ++"returns True.\n" ++"\n" ++"Signature:\n" ++" decompress(string, max_output_length=int)\n" ++"\n" ++"Args:\n" ++" string (bytes): The input data\n" ++"\n""Returns:\n" ++" The decompressed output data (bytes)\n" ++"\n" ++"Raises:\n" ++" brotli.error: If decompression fails\n"); ++ ++static PyObject* brotli_Decompressor_process(brotli_Decompressor *self, PyObject *args, PyObject* keywds) { ++ PyObject* ret; ++ Py_buffer input; ++ int ok; ++ Py_ssize_t max_output_length = PY_SSIZE_T_MAX; ++ uint8_t* data; ++ size_t data_length; ++ ++ static char* kwlist[] = { "", "max_output_length", NULL }; ++ ++#if PY_MAJOR_VERSION >= 3 ++ ok = PyArg_ParseTupleAndKeywords(args, keywds, "y*|n:process", kwlist, &input, &max_output_length); ++#else ++ ok = PyArg_ParseTupleAndKeywords(args, keywds, "s*|n:process", kwlist, &input, &max_output_length); ++#endif ++ ++ if (!ok) { ++ return NULL; ++ } ++ ++ if (!self->dec) { ++ goto error; ++ } ++ ++ if (self->unconsumed_data_length > 0) { ++ if (input.len > 0) { ++ PyErr_SetString(BrotliError, "process called with data when accept_more_data is False"); ++ ret = NULL; ++ goto finally; ++ } ++ data = self->unconsumed_data; ++ data_length = self->unconsumed_data_length; ++ } else { ++ data = (uint8_t*)input.buf; ++ data_length = input.len; ++ } ++ ++ ret = decompress_stream(self, data, data_length, max_output_length); ++ if (ret != NULL) { ++ goto finally; ++ } ++ ++error: ++ PyErr_SetString(BrotliError, ++ "BrotliDecoderDecompressStream failed while processing the stream"); ++ ret = NULL; ++ ++finally: ++ PyBuffer_Release(&input); ++ return ret; ++} ++ ++PyDoc_STRVAR(brotli_Decompressor_is_finished_doc, ++"Checks if decoder instance reached the final state.\n" ++"\n" ++"Signature:\n" ++" is_finished()\n" ++"\n" ++"Returns:\n" ++" True if the decoder is in a state where it reached the end of the input\n" ++" and produced all of the output\n" ++" False otherwise\n" ++"\n" ++"Raises:\n" ++" brotli.error: If decompression fails\n"); ++ ++static PyObject* brotli_Decompressor_is_finished(brotli_Decompressor *self) { ++ if (!self->dec) { ++ PyErr_SetString(BrotliError, "BrotliDecoderState is NULL while checking is_finished"); ++ return NULL; ++ } ++ ++ if (BrotliDecoderIsFinished(self->dec)) { ++ Py_RETURN_TRUE; ++ } else { ++ Py_RETURN_FALSE; ++ } ++} ++ ++PyDoc_STRVAR(brotli_Decompressor_can_accept_more_data_doc, ++"Checks if the decoder instance can accept more compressed data. If the decompress()\n" ++"method on this instance of decompressor was never called with max_length,\n" ++"this method will always return True.\n" ++"\n" ++"Signature:" ++" can_accept_more_data()\n" ++"\n" ++"Returns:\n" ++" True if the decoder is ready to accept more compressed data via decompress()\n" ++" False if the decoder needs to output some data via decompress(b'') before\n" ++" being provided any more compressed data\n"); ++ ++static PyObject* brotli_Decompressor_can_accept_more_data(brotli_Decompressor* self) { ++ if (self->unconsumed_data_length > 0) { ++ Py_RETURN_FALSE; ++ } else { ++ Py_RETURN_TRUE; ++ } ++} ++ ++static PyMemberDef brotli_Decompressor_members[] = { ++ {NULL} /* Sentinel */ ++}; ++ ++static PyMethodDef brotli_Decompressor_methods[] = { ++ {"process", (PyCFunction)brotli_Decompressor_process, METH_VARARGS | METH_KEYWORDS, brotli_Decompressor_process_doc}, ++ {"is_finished", (PyCFunction)brotli_Decompressor_is_finished, METH_NOARGS, brotli_Decompressor_is_finished_doc}, ++ {"can_accept_more_data", (PyCFunction)brotli_Decompressor_can_accept_more_data, METH_NOARGS, brotli_Decompressor_can_accept_more_data_doc}, ++ {NULL} /* Sentinel */ ++}; ++ ++static PyTypeObject brotli_DecompressorType = { ++ #if PY_MAJOR_VERSION >= 3 ++ PyVarObject_HEAD_INIT(NULL, 0) ++ #else ++ PyObject_HEAD_INIT(NULL) ++ 0, /* ob_size*/ ++ #endif ++ "brotli.Decompressor", /* tp_name */ ++ sizeof(brotli_Decompressor), /* tp_basicsize */ ++ 0, /* tp_itemsize */ ++ (destructor)brotli_Decompressor_dealloc, /* tp_dealloc */ ++ 0, /* tp_print */ ++ 0, /* tp_getattr */ ++ 0, /* tp_setattr */ ++ 0, /* tp_compare */ ++ 0, /* tp_repr */ ++ 0, /* tp_as_number */ ++ 0, /* tp_as_sequence */ ++ 0, /* tp_as_mapping */ ++ 0, /* tp_hash */ ++ 0, /* tp_call */ ++ 0, /* tp_str */ ++ 0, /* tp_getattro */ ++ 0, /* tp_setattro */ ++ 0, /* tp_as_buffer */ ++ Py_TPFLAGS_DEFAULT, /* tp_flags */ ++ brotli_Decompressor_doc, /* tp_doc */ ++ 0, /* tp_traverse */ ++ 0, /* tp_clear */ ++ 0, /* tp_richcompare */ ++ 0, /* tp_weaklistoffset */ ++ 0, /* tp_iter */ ++ 0, /* tp_iternext */ ++ brotli_Decompressor_methods, /* tp_methods */ ++ brotli_Decompressor_members, /* tp_members */ ++ 0, /* tp_getset */ ++ 0, /* tp_base */ ++ 0, /* tp_dict */ ++ 0, /* tp_descr_get */ ++ 0, /* tp_descr_set */ ++ 0, /* tp_dictoffset */ ++ (initproc)brotli_Decompressor_init, /* tp_init */ ++ 0, /* tp_alloc */ ++ brotli_Decompressor_new, /* tp_new */ ++}; ++ ++PyDoc_STRVAR(brotli_decompress__doc__, ++"Decompress a compressed byte string.\n" ++"\n" ++"Signature:\n" ++" decompress(string)\n" ++"\n" ++"Args:\n" ++" string (bytes): The compressed input data.\n" ++"\n" ++"Returns:\n" ++" The decompressed byte string.\n" ++"\n" ++"Raises:\n" ++" brotli.error: If decompressor fails.\n"); ++ ++static PyObject* brotli_decompress(PyObject *self, PyObject *args, PyObject *keywds) { ++ BrotliDecoderState* state; ++ BrotliDecoderResult result; ++ ++ const uint8_t* next_in; ++ size_t available_in; ++ ++ uint8_t* next_out; ++ size_t available_out; ++ BlocksOutputBuffer buffer = {.list=NULL}; ++ PyObject *ret; ++ ++ static const char *kwlist[] = {"string", NULL}; ++ Py_buffer input; ++ int ok; ++ ++#if PY_MAJOR_VERSION >= 3 ++ ok = PyArg_ParseTupleAndKeywords(args, keywds, "y*|:decompress", ++ (char**) kwlist, &input); ++#else ++ ok = PyArg_ParseTupleAndKeywords(args, keywds, "s*|:decompress", ++ (char**) kwlist, &input); ++#endif ++ ++ if (!ok) { ++ return NULL; ++ } ++ ++ state = BrotliDecoderCreateInstance(0, 0, 0); ++ ++ next_in = (uint8_t*) input.buf; ++ available_in = input.len; ++ ++ if (BlocksOutputBuffer_InitAndGrow(&buffer, PY_SSIZE_T_MAX, &available_out, &next_out) < 0) { ++ goto error; ++ } ++ ++ while (1) { ++ Py_BEGIN_ALLOW_THREADS ++ result = BrotliDecoderDecompressStream(state, &available_in, &next_in, ++ &available_out, &next_out, 0); ++ Py_END_ALLOW_THREADS ++ ++ if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { ++ if (available_out == 0) { ++ if (BlocksOutputBuffer_Grow(&buffer, &available_out, &next_out) < 0) { ++ goto error; ++ } ++ } ++ continue; ++ } ++ ++ break; ++ } ++ ++ if (result != BROTLI_DECODER_RESULT_SUCCESS || available_in != 0) { ++ goto error; ++ } ++ ++ ret = BlocksOutputBuffer_Finish(&buffer, available_out); ++ if (ret != NULL) { ++ goto finally; ++ } ++ ++error: ++ BlocksOutputBuffer_OnError(&buffer); ++ PyErr_SetString(BrotliError, "BrotliDecompress failed"); ++ ret = NULL; ++ ++finally: ++ BrotliDecoderDestroyInstance(state); ++ PyBuffer_Release(&input); ++ return ret; ++} ++ ++static PyMethodDef brotli_methods[] = { ++ {"decompress", (PyCFunction)brotli_decompress, METH_VARARGS | METH_KEYWORDS, brotli_decompress__doc__}, ++ {NULL, NULL, 0, NULL} ++}; ++ ++PyDoc_STRVAR(brotli_doc, "Implementation module for the Brotli library."); ++ ++#if PY_MAJOR_VERSION >= 3 ++#define INIT_BROTLI PyInit__brotli ++#define CREATE_BROTLI PyModule_Create(&brotli_module) ++#define RETURN_BROTLI return m ++#define RETURN_NULL return NULL ++ ++static struct PyModuleDef brotli_module = { ++ PyModuleDef_HEAD_INIT, ++ "_brotli", /* m_name */ ++ brotli_doc, /* m_doc */ ++ 0, /* m_size */ ++ brotli_methods, /* m_methods */ ++ NULL, /* m_reload */ ++ NULL, /* m_traverse */ ++ NULL, /* m_clear */ ++ NULL /* m_free */ ++}; ++#else ++#define INIT_BROTLI init_brotli ++#define CREATE_BROTLI Py_InitModule3("_brotli", brotli_methods, brotli_doc) ++#define RETURN_BROTLI return ++#define RETURN_NULL return ++#endif ++ ++PyMODINIT_FUNC INIT_BROTLI(void) { ++ PyObject *m = CREATE_BROTLI; ++ ++ BrotliError = PyErr_NewException((char*) "brotli.error", NULL, NULL); ++ if (BrotliError != NULL) { ++ Py_INCREF(BrotliError); ++ PyModule_AddObject(m, "error", BrotliError); ++ } ++ ++ if (PyType_Ready(&brotli_CompressorType) < 0) { ++ RETURN_NULL; ++ } ++ Py_INCREF(&brotli_CompressorType); ++ PyModule_AddObject(m, "Compressor", (PyObject *)&brotli_CompressorType); ++ ++ if (PyType_Ready(&brotli_DecompressorType) < 0) { ++ RETURN_NULL; ++ } ++ Py_INCREF(&brotli_DecompressorType); ++ PyModule_AddObject(m, "Decompressor", (PyObject *)&brotli_DecompressorType); ++ ++ PyModule_AddIntConstant(m, "MODE_GENERIC", (int) BROTLI_MODE_GENERIC); ++ PyModule_AddIntConstant(m, "MODE_TEXT", (int) BROTLI_MODE_TEXT); ++ PyModule_AddIntConstant(m, "MODE_FONT", (int) BROTLI_MODE_FONT); ++ ++ char version[16]; ++ uint32_t decoderVersion = BrotliDecoderVersion(); ++ snprintf(version, sizeof(version), "%d.%d.%d", ++ decoderVersion >> 24, (decoderVersion >> 12) & 0xFFF, decoderVersion & 0xFFF); ++ PyModule_AddStringConstant(m, "__version__", version); ++ ++ RETURN_BROTLI; ++} +diff -urN brotli-1.0.6/python/_brotli.cc brotli-1.0.6-modified/python/_brotli.cc +--- brotli-1.0.6/python/_brotli.cc 2018-09-13 23:01:23.000000000 +0530 ++++ brotli-1.0.6-modified/python/_brotli.cc 1970-01-01 05:30:00.000000000 +0530 +@@ -1,752 +0,0 @@ +-#define PY_SSIZE_T_CLEAN 1 +-#include +-#include +-#include +-#include +-#include "../common/version.h" +-#include +-#include +- +-#if PY_MAJOR_VERSION >= 3 +-#define PyInt_Check PyLong_Check +-#define PyInt_AsLong PyLong_AsLong +-#endif +- +-static PyObject *BrotliError; +- +-static int as_bounded_int(PyObject *o, int* result, int lower_bound, int upper_bound) { +- long value = PyInt_AsLong(o); +- if ((value < (long) lower_bound) || (value > (long) upper_bound)) { +- return 0; +- } +- *result = (int) value; +- return 1; +-} +- +-static int mode_convertor(PyObject *o, BrotliEncoderMode *mode) { +- if (!PyInt_Check(o)) { +- PyErr_SetString(BrotliError, "Invalid mode"); +- return 0; +- } +- +- int mode_value = -1; +- if (!as_bounded_int(o, &mode_value, 0, 255)) { +- PyErr_SetString(BrotliError, "Invalid mode"); +- return 0; +- } +- *mode = (BrotliEncoderMode) mode_value; +- if (*mode != BROTLI_MODE_GENERIC && +- *mode != BROTLI_MODE_TEXT && +- *mode != BROTLI_MODE_FONT) { +- PyErr_SetString(BrotliError, "Invalid mode"); +- return 0; +- } +- +- return 1; +-} +- +-static int quality_convertor(PyObject *o, int *quality) { +- if (!PyInt_Check(o)) { +- PyErr_SetString(BrotliError, "Invalid quality"); +- return 0; +- } +- +- if (!as_bounded_int(o, quality, 0, 11)) { +- PyErr_SetString(BrotliError, "Invalid quality. Range is 0 to 11."); +- return 0; +- } +- +- return 1; +-} +- +-static int lgwin_convertor(PyObject *o, int *lgwin) { +- if (!PyInt_Check(o)) { +- PyErr_SetString(BrotliError, "Invalid lgwin"); +- return 0; +- } +- +- if (!as_bounded_int(o, lgwin, 10, 24)) { +- PyErr_SetString(BrotliError, "Invalid lgwin. Range is 10 to 24."); +- return 0; +- } +- +- return 1; +-} +- +-static int lgblock_convertor(PyObject *o, int *lgblock) { +- if (!PyInt_Check(o)) { +- PyErr_SetString(BrotliError, "Invalid lgblock"); +- return 0; +- } +- +- if (!as_bounded_int(o, lgblock, 0, 24) || (*lgblock != 0 && *lgblock < 16)) { +- PyErr_SetString(BrotliError, "Invalid lgblock. Can be 0 or in range 16 to 24."); +- return 0; +- } +- +- return 1; +-} +- +-static BROTLI_BOOL compress_stream(BrotliEncoderState* enc, BrotliEncoderOperation op, +- std::vector* output, +- uint8_t* input, size_t input_length) { +- BROTLI_BOOL ok = BROTLI_TRUE; +- Py_BEGIN_ALLOW_THREADS +- +- size_t available_in = input_length; +- const uint8_t* next_in = input; +- size_t available_out = 0; +- uint8_t* next_out = NULL; +- +- while (ok) { +- ok = BrotliEncoderCompressStream(enc, op, +- &available_in, &next_in, +- &available_out, &next_out, NULL); +- if (!ok) +- break; +- +- size_t buffer_length = 0; // Request all available output. +- const uint8_t* buffer = BrotliEncoderTakeOutput(enc, &buffer_length); +- if (buffer_length) { +- (*output).insert((*output).end(), buffer, buffer + buffer_length); +- } +- +- if (available_in || BrotliEncoderHasMoreOutput(enc)) { +- continue; +- } +- +- break; +- } +- +- Py_END_ALLOW_THREADS +- return ok; +-} +- +-PyDoc_STRVAR(brotli_Compressor_doc, +-"An object to compress a byte string.\n" +-"\n" +-"Signature:\n" +-" Compressor(mode=MODE_GENERIC, quality=11, lgwin=22, lgblock=0)\n" +-"\n" +-"Args:\n" +-" mode (int, optional): The compression mode can be MODE_GENERIC (default),\n" +-" MODE_TEXT (for UTF-8 format text input) or MODE_FONT (for WOFF 2.0). \n" +-" quality (int, optional): Controls the compression-speed vs compression-\n" +-" density tradeoff. The higher the quality, the slower the compression.\n" +-" Range is 0 to 11. Defaults to 11.\n" +-" lgwin (int, optional): Base 2 logarithm of the sliding window size. Range\n" +-" is 10 to 24. Defaults to 22.\n" +-" lgblock (int, optional): Base 2 logarithm of the maximum input block size.\n" +-" Range is 16 to 24. If set to 0, the value will be set based on the\n" +-" quality. Defaults to 0.\n" +-"\n" +-"Raises:\n" +-" brotli.error: If arguments are invalid.\n"); +- +-typedef struct { +- PyObject_HEAD +- BrotliEncoderState* enc; +-} brotli_Compressor; +- +-static void brotli_Compressor_dealloc(brotli_Compressor* self) { +- BrotliEncoderDestroyInstance(self->enc); +- #if PY_MAJOR_VERSION >= 3 +- Py_TYPE(self)->tp_free((PyObject*)self); +- #else +- self->ob_type->tp_free((PyObject*)self); +- #endif +-} +- +-static PyObject* brotli_Compressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) { +- brotli_Compressor *self; +- self = (brotli_Compressor *)type->tp_alloc(type, 0); +- +- if (self != NULL) { +- self->enc = BrotliEncoderCreateInstance(0, 0, 0); +- } +- +- return (PyObject *)self; +-} +- +-static int brotli_Compressor_init(brotli_Compressor *self, PyObject *args, PyObject *keywds) { +- BrotliEncoderMode mode = (BrotliEncoderMode) -1; +- int quality = -1; +- int lgwin = -1; +- int lgblock = -1; +- int ok; +- +- static const char *kwlist[] = {"mode", "quality", "lgwin", "lgblock", NULL}; +- +- ok = PyArg_ParseTupleAndKeywords(args, keywds, "|O&O&O&O&:Compressor", +- const_cast(kwlist), +- &mode_convertor, &mode, +- &quality_convertor, &quality, +- &lgwin_convertor, &lgwin, +- &lgblock_convertor, &lgblock); +- if (!ok) +- return -1; +- if (!self->enc) +- return -1; +- +- if ((int) mode != -1) +- BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_MODE, (uint32_t)mode); +- if (quality != -1) +- BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_QUALITY, (uint32_t)quality); +- if (lgwin != -1) +- BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGWIN, (uint32_t)lgwin); +- if (lgblock != -1) +- BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGBLOCK, (uint32_t)lgblock); +- +- return 0; +-} +- +-PyDoc_STRVAR(brotli_Compressor_process_doc, +-"Process \"string\" for compression, returning a string that contains \n" +-"compressed output data. This data should be concatenated to the output \n" +-"produced by any preceding calls to the \"process()\" or flush()\" methods. \n" +-"Some or all of the input may be kept in internal buffers for later \n" +-"processing, and the compressed output data may be empty until enough input \n" +-"has been accumulated.\n" +-"\n" +-"Signature:\n" +-" compress(string)\n" +-"\n" +-"Args:\n" +-" string (bytes): The input data\n" +-"\n" +-"Returns:\n" +-" The compressed output data (bytes)\n" +-"\n" +-"Raises:\n" +-" brotli.error: If compression fails\n"); +- +-static PyObject* brotli_Compressor_process(brotli_Compressor *self, PyObject *args) { +- PyObject* ret = NULL; +- std::vector output; +- Py_buffer input; +- BROTLI_BOOL ok = BROTLI_TRUE; +- +-#if PY_MAJOR_VERSION >= 3 +- ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "y*:process", &input); +-#else +- ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "s*:process", &input); +-#endif +- +- if (!ok) +- return NULL; +- +- if (!self->enc) { +- ok = BROTLI_FALSE; +- goto end; +- } +- +- ok = compress_stream(self->enc, BROTLI_OPERATION_PROCESS, +- &output, static_cast(input.buf), input.len); +- +-end: +- PyBuffer_Release(&input); +- if (ok) { +- ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size()); +- } else { +- PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while processing the stream"); +- } +- +- return ret; +-} +- +-PyDoc_STRVAR(brotli_Compressor_flush_doc, +-"Process all pending input, returning a string containing the remaining\n" +-"compressed data. This data should be concatenated to the output produced by\n" +-"any preceding calls to the \"process()\" or \"flush()\" methods.\n" +-"\n" +-"Signature:\n" +-" flush()\n" +-"\n" +-"Returns:\n" +-" The compressed output data (bytes)\n" +-"\n" +-"Raises:\n" +-" brotli.error: If compression fails\n"); +- +-static PyObject* brotli_Compressor_flush(brotli_Compressor *self) { +- PyObject *ret = NULL; +- std::vector output; +- BROTLI_BOOL ok = BROTLI_TRUE; +- +- if (!self->enc) { +- ok = BROTLI_FALSE; +- goto end; +- } +- +- ok = compress_stream(self->enc, BROTLI_OPERATION_FLUSH, +- &output, NULL, 0); +- +-end: +- if (ok) { +- ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size()); +- } else { +- PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while flushing the stream"); +- } +- +- return ret; +-} +- +-PyDoc_STRVAR(brotli_Compressor_finish_doc, +-"Process all pending input and complete all compression, returning a string\n" +-"containing the remaining compressed data. This data should be concatenated\n" +-"to the output produced by any preceding calls to the \"process()\" or\n" +-"\"flush()\" methods.\n" +-"After calling \"finish()\", the \"process()\" and \"flush()\" methods\n" +-"cannot be called again, and a new \"Compressor\" object should be created.\n" +-"\n" +-"Signature:\n" +-" finish(string)\n" +-"\n" +-"Returns:\n" +-" The compressed output data (bytes)\n" +-"\n" +-"Raises:\n" +-" brotli.error: If compression fails\n"); +- +-static PyObject* brotli_Compressor_finish(brotli_Compressor *self) { +- PyObject *ret = NULL; +- std::vector output; +- BROTLI_BOOL ok = BROTLI_TRUE; +- +- if (!self->enc) { +- ok = BROTLI_FALSE; +- goto end; +- } +- +- ok = compress_stream(self->enc, BROTLI_OPERATION_FINISH, +- &output, NULL, 0); +- +- if (ok) { +- ok = BrotliEncoderIsFinished(self->enc); +- } +- +-end: +- if (ok) { +- ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size()); +- } else { +- PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while finishing the stream"); +- } +- +- return ret; +-} +- +-static PyMemberDef brotli_Compressor_members[] = { +- {NULL} /* Sentinel */ +-}; +- +-static PyMethodDef brotli_Compressor_methods[] = { +- {"process", (PyCFunction)brotli_Compressor_process, METH_VARARGS, brotli_Compressor_process_doc}, +- {"flush", (PyCFunction)brotli_Compressor_flush, METH_NOARGS, brotli_Compressor_flush_doc}, +- {"finish", (PyCFunction)brotli_Compressor_finish, METH_NOARGS, brotli_Compressor_finish_doc}, +- {NULL} /* Sentinel */ +-}; +- +-static PyTypeObject brotli_CompressorType = { +- #if PY_MAJOR_VERSION >= 3 +- PyVarObject_HEAD_INIT(NULL, 0) +- #else +- PyObject_HEAD_INIT(NULL) +- 0, /* ob_size*/ +- #endif +- "brotli.Compressor", /* tp_name */ +- sizeof(brotli_Compressor), /* tp_basicsize */ +- 0, /* tp_itemsize */ +- (destructor)brotli_Compressor_dealloc, /* tp_dealloc */ +- 0, /* tp_print */ +- 0, /* tp_getattr */ +- 0, /* tp_setattr */ +- 0, /* tp_compare */ +- 0, /* tp_repr */ +- 0, /* tp_as_number */ +- 0, /* tp_as_sequence */ +- 0, /* tp_as_mapping */ +- 0, /* tp_hash */ +- 0, /* tp_call */ +- 0, /* tp_str */ +- 0, /* tp_getattro */ +- 0, /* tp_setattro */ +- 0, /* tp_as_buffer */ +- Py_TPFLAGS_DEFAULT, /* tp_flags */ +- brotli_Compressor_doc, /* tp_doc */ +- 0, /* tp_traverse */ +- 0, /* tp_clear */ +- 0, /* tp_richcompare */ +- 0, /* tp_weaklistoffset */ +- 0, /* tp_iter */ +- 0, /* tp_iternext */ +- brotli_Compressor_methods, /* tp_methods */ +- brotli_Compressor_members, /* tp_members */ +- 0, /* tp_getset */ +- 0, /* tp_base */ +- 0, /* tp_dict */ +- 0, /* tp_descr_get */ +- 0, /* tp_descr_set */ +- 0, /* tp_dictoffset */ +- (initproc)brotli_Compressor_init, /* tp_init */ +- 0, /* tp_alloc */ +- brotli_Compressor_new, /* tp_new */ +-}; +- +-static BROTLI_BOOL decompress_stream(BrotliDecoderState* dec, +- std::vector* output, +- uint8_t* input, size_t input_length) { +- BROTLI_BOOL ok = BROTLI_TRUE; +- Py_BEGIN_ALLOW_THREADS +- +- size_t available_in = input_length; +- const uint8_t* next_in = input; +- size_t available_out = 0; +- uint8_t* next_out = NULL; +- +- BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; +- while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { +- result = BrotliDecoderDecompressStream(dec, +- &available_in, &next_in, +- &available_out, &next_out, NULL); +- size_t buffer_length = 0; // Request all available output. +- const uint8_t* buffer = BrotliDecoderTakeOutput(dec, &buffer_length); +- if (buffer_length) { +- (*output).insert((*output).end(), buffer, buffer + buffer_length); +- } +- } +- ok = result != BROTLI_DECODER_RESULT_ERROR; +- +- Py_END_ALLOW_THREADS +- return ok; +-} +- +-PyDoc_STRVAR(brotli_Decompressor_doc, +-"An object to decompress a byte string.\n" +-"\n" +-"Signature:\n" +-" Decompressor()\n" +-"\n" +-"Raises:\n" +-" brotli.error: If arguments are invalid.\n"); +- +-typedef struct { +- PyObject_HEAD +- BrotliDecoderState* dec; +-} brotli_Decompressor; +- +-static void brotli_Decompressor_dealloc(brotli_Decompressor* self) { +- BrotliDecoderDestroyInstance(self->dec); +- #if PY_MAJOR_VERSION >= 3 +- Py_TYPE(self)->tp_free((PyObject*)self); +- #else +- self->ob_type->tp_free((PyObject*)self); +- #endif +-} +- +-static PyObject* brotli_Decompressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) { +- brotli_Decompressor *self; +- self = (brotli_Decompressor *)type->tp_alloc(type, 0); +- +- if (self != NULL) { +- self->dec = BrotliDecoderCreateInstance(0, 0, 0); +- } +- +- return (PyObject *)self; +-} +- +-static int brotli_Decompressor_init(brotli_Decompressor *self, PyObject *args, PyObject *keywds) { +- int ok; +- +- static const char *kwlist[] = {NULL}; +- +- ok = PyArg_ParseTupleAndKeywords(args, keywds, "|:Decompressor", +- const_cast(kwlist)); +- if (!ok) +- return -1; +- if (!self->dec) +- return -1; +- +- return 0; +-} +- +-PyDoc_STRVAR(brotli_Decompressor_process_doc, +-"Process \"string\" for decompression, returning a string that contains \n" +-"decompressed output data. This data should be concatenated to the output \n" +-"produced by any preceding calls to the \"process()\" method. \n" +-"Some or all of the input may be kept in internal buffers for later \n" +-"processing, and the decompressed output data may be empty until enough input \n" +-"has been accumulated.\n" +-"\n" +-"Signature:\n" +-" decompress(string)\n" +-"\n" +-"Args:\n" +-" string (bytes): The input data\n" +-"\n" +-"Returns:\n" +-" The decompressed output data (bytes)\n" +-"\n" +-"Raises:\n" +-" brotli.error: If decompression fails\n"); +- +-static PyObject* brotli_Decompressor_process(brotli_Decompressor *self, PyObject *args) { +- PyObject* ret = NULL; +- std::vector output; +- Py_buffer input; +- BROTLI_BOOL ok = BROTLI_TRUE; +- +-#if PY_MAJOR_VERSION >= 3 +- ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "y*:process", &input); +-#else +- ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "s*:process", &input); +-#endif +- +- if (!ok) +- return NULL; +- +- if (!self->dec) { +- ok = BROTLI_FALSE; +- goto end; +- } +- +- ok = decompress_stream(self->dec, &output, static_cast(input.buf), input.len); +- +-end: +- PyBuffer_Release(&input); +- if (ok) { +- ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size()); +- } else { +- PyErr_SetString(BrotliError, "BrotliDecoderDecompressStream failed while processing the stream"); +- } +- +- return ret; +-} +- +-PyDoc_STRVAR(brotli_Decompressor_is_finished_doc, +-"Checks if decoder instance reached the final state.\n" +-"\n" +-"Signature:\n" +-" is_finished()\n" +-"\n" +-"Returns:\n" +-" True if the decoder is in a state where it reached the end of the input\n" +-" and produced all of the output\n" +-" False otherwise\n" +-"\n" +-"Raises:\n" +-" brotli.error: If decompression fails\n"); +- +-static PyObject* brotli_Decompressor_is_finished(brotli_Decompressor *self) { +- PyObject *ret = NULL; +- std::vector output; +- BROTLI_BOOL ok = BROTLI_TRUE; +- +- if (!self->dec) { +- ok = BROTLI_FALSE; +- PyErr_SetString(BrotliError, "BrotliDecoderState is NULL while checking is_finished"); +- goto end; +- } +- +- if (BrotliDecoderIsFinished(self->dec)) { +- Py_RETURN_TRUE; +- } else { +- Py_RETURN_FALSE; +- } +- +-end: +- if (ok) { +- ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size()); +- } else { +- PyErr_SetString(BrotliError, "BrotliDecoderDecompressStream failed while finishing the stream"); +- } +- +- return ret; +-} +- +-static PyMemberDef brotli_Decompressor_members[] = { +- {NULL} /* Sentinel */ +-}; +- +-static PyMethodDef brotli_Decompressor_methods[] = { +- {"process", (PyCFunction)brotli_Decompressor_process, METH_VARARGS, brotli_Decompressor_process_doc}, +- {"is_finished", (PyCFunction)brotli_Decompressor_is_finished, METH_NOARGS, brotli_Decompressor_is_finished_doc}, +- {NULL} /* Sentinel */ +-}; +- +-static PyTypeObject brotli_DecompressorType = { +- #if PY_MAJOR_VERSION >= 3 +- PyVarObject_HEAD_INIT(NULL, 0) +- #else +- PyObject_HEAD_INIT(NULL) +- 0, /* ob_size*/ +- #endif +- "brotli.Decompressor", /* tp_name */ +- sizeof(brotli_Decompressor), /* tp_basicsize */ +- 0, /* tp_itemsize */ +- (destructor)brotli_Decompressor_dealloc, /* tp_dealloc */ +- 0, /* tp_print */ +- 0, /* tp_getattr */ +- 0, /* tp_setattr */ +- 0, /* tp_compare */ +- 0, /* tp_repr */ +- 0, /* tp_as_number */ +- 0, /* tp_as_sequence */ +- 0, /* tp_as_mapping */ +- 0, /* tp_hash */ +- 0, /* tp_call */ +- 0, /* tp_str */ +- 0, /* tp_getattro */ +- 0, /* tp_setattro */ +- 0, /* tp_as_buffer */ +- Py_TPFLAGS_DEFAULT, /* tp_flags */ +- brotli_Decompressor_doc, /* tp_doc */ +- 0, /* tp_traverse */ +- 0, /* tp_clear */ +- 0, /* tp_richcompare */ +- 0, /* tp_weaklistoffset */ +- 0, /* tp_iter */ +- 0, /* tp_iternext */ +- brotli_Decompressor_methods, /* tp_methods */ +- brotli_Decompressor_members, /* tp_members */ +- 0, /* tp_getset */ +- 0, /* tp_base */ +- 0, /* tp_dict */ +- 0, /* tp_descr_get */ +- 0, /* tp_descr_set */ +- 0, /* tp_dictoffset */ +- (initproc)brotli_Decompressor_init, /* tp_init */ +- 0, /* tp_alloc */ +- brotli_Decompressor_new, /* tp_new */ +-}; +- +-PyDoc_STRVAR(brotli_decompress__doc__, +-"Decompress a compressed byte string.\n" +-"\n" +-"Signature:\n" +-" decompress(string)\n" +-"\n" +-"Args:\n" +-" string (bytes): The compressed input data.\n" +-"\n" +-"Returns:\n" +-" The decompressed byte string.\n" +-"\n" +-"Raises:\n" +-" brotli.error: If decompressor fails.\n"); +- +-static PyObject* brotli_decompress(PyObject *self, PyObject *args, PyObject *keywds) { +- PyObject *ret = NULL; +- Py_buffer input; +- const uint8_t* next_in; +- size_t available_in; +- int ok; +- +- static const char *kwlist[] = {"string", NULL}; +- +-#if PY_MAJOR_VERSION >= 3 +- ok = PyArg_ParseTupleAndKeywords(args, keywds, "y*|:decompress", +- const_cast(kwlist), &input); +-#else +- ok = PyArg_ParseTupleAndKeywords(args, keywds, "s*|:decompress", +- const_cast(kwlist), &input); +-#endif +- +- if (!ok) +- return NULL; +- +- std::vector output; +- +- /* >>> Pure C block; release python GIL. */ +- Py_BEGIN_ALLOW_THREADS +- +- BrotliDecoderState* state = BrotliDecoderCreateInstance(0, 0, 0); +- +- BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; +- next_in = static_cast(input.buf); +- available_in = input.len; +- while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { +- size_t available_out = 0; +- result = BrotliDecoderDecompressStream(state, &available_in, &next_in, +- &available_out, 0, 0); +- const uint8_t* next_out = BrotliDecoderTakeOutput(state, &available_out); +- if (available_out != 0) +- output.insert(output.end(), next_out, next_out + available_out); +- } +- ok = result == BROTLI_DECODER_RESULT_SUCCESS; +- BrotliDecoderDestroyInstance(state); +- +- Py_END_ALLOW_THREADS +- /* <<< Pure C block end. Python GIL reacquired. */ +- +- PyBuffer_Release(&input); +- if (ok) { +- ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size()); +- } else { +- PyErr_SetString(BrotliError, "BrotliDecompress failed"); +- } +- +- return ret; +-} +- +-static PyMethodDef brotli_methods[] = { +- {"decompress", (PyCFunction)brotli_decompress, METH_VARARGS | METH_KEYWORDS, brotli_decompress__doc__}, +- {NULL, NULL, 0, NULL} +-}; +- +-PyDoc_STRVAR(brotli_doc, "Implementation module for the Brotli library."); +- +-#if PY_MAJOR_VERSION >= 3 +-#define INIT_BROTLI PyInit__brotli +-#define CREATE_BROTLI PyModule_Create(&brotli_module) +-#define RETURN_BROTLI return m +-#define RETURN_NULL return NULL +- +-static struct PyModuleDef brotli_module = { +- PyModuleDef_HEAD_INIT, +- "_brotli", +- brotli_doc, +- 0, +- brotli_methods, +- NULL, +- NULL, +- NULL +-}; +-#else +-#define INIT_BROTLI init_brotli +-#define CREATE_BROTLI Py_InitModule3("_brotli", brotli_methods, brotli_doc) +-#define RETURN_BROTLI return +-#define RETURN_NULL return +-#endif +- +-PyMODINIT_FUNC INIT_BROTLI(void) { +- PyObject *m = CREATE_BROTLI; +- +- BrotliError = PyErr_NewException((char*) "brotli.error", NULL, NULL); +- if (BrotliError != NULL) { +- Py_INCREF(BrotliError); +- PyModule_AddObject(m, "error", BrotliError); +- } +- +- if (PyType_Ready(&brotli_CompressorType) < 0) { +- RETURN_NULL; +- } +- Py_INCREF(&brotli_CompressorType); +- PyModule_AddObject(m, "Compressor", (PyObject *)&brotli_CompressorType); +- +- if (PyType_Ready(&brotli_DecompressorType) < 0) { +- RETURN_NULL; +- } +- Py_INCREF(&brotli_DecompressorType); +- PyModule_AddObject(m, "Decompressor", (PyObject *)&brotli_DecompressorType); +- +- PyModule_AddIntConstant(m, "MODE_GENERIC", (int) BROTLI_MODE_GENERIC); +- PyModule_AddIntConstant(m, "MODE_TEXT", (int) BROTLI_MODE_TEXT); +- PyModule_AddIntConstant(m, "MODE_FONT", (int) BROTLI_MODE_FONT); +- +- char version[16]; +- snprintf(version, sizeof(version), "%d.%d.%d", +- BROTLI_VERSION >> 24, (BROTLI_VERSION >> 12) & 0xFFF, BROTLI_VERSION & 0xFFF); +- PyModule_AddStringConstant(m, "__version__", version); +- +- RETURN_BROTLI; +-} +diff -urN brotli-1.0.6/python/brotli.py brotli-1.0.6-modified/python/brotli.py +--- brotli-1.0.6/python/brotli.py 2018-09-13 23:01:23.000000000 +0530 ++++ brotli-1.0.6-modified/python/brotli.py 2023-08-29 16:30:29.000000000 +0530 +@@ -7,9 +7,8 @@ + + import _brotli + +- + # The library version. +-__version__ = _brotli.__version__ ++version = __version__ = _brotli.__version__ + + # The compression mode. + MODE_GENERIC = _brotli.MODE_GENERIC +diff -urN brotli-1.0.6/python/README.md brotli-1.0.6-modified/python/README.md +--- brotli-1.0.6/python/README.md 2018-09-13 23:01:23.000000000 +0530 ++++ brotli-1.0.6-modified/python/README.md 2023-08-29 16:30:29.000000000 +0530 +@@ -22,7 +22,7 @@ + You may run the following commands from this directory: + + $ make # Build the module in-place +- ++ + $ make test # Test the module + + $ make clean # Remove all temporary files and build output +diff -urN brotli-1.0.6/setup.py brotli-1.0.6-modified/setup.py +--- brotli-1.0.6/setup.py 2026-01-27 14:56:01.010289514 +0530 ++++ brotli-1.0.6-modified/setup.py 2026-01-27 14:57:44.458496228 +0530 +@@ -180,7 +180,7 @@ + Extension( + '_brotli', + sources=[ +- 'python/_brotli.cc', ++ 'python/_brotli.c', + 'c/common/constants.c', + 'c/common/dictionary.c', + 'c/common/transform.c', +@@ -263,8 +263,7 @@ + ], + include_dirs=[ + 'c/include', +- ], +- language='c++'), ++ ]), + ] + + TEST_SUITE = 'setup.get_test_suite' diff --git a/SPECS/brotli.spec b/SPECS/brotli.spec index e201b9c..c969b78 100644 --- a/SPECS/brotli.spec +++ b/SPECS/brotli.spec @@ -7,7 +7,7 @@ Name: brotli Version: 1.0.6 -Release: 3%{?dist} +Release: 4%{?dist} Summary: Lossless compression algorithm License: MIT @@ -15,6 +15,7 @@ URL: https://github.com/google/brotli Source0: https://github.com/google/brotli/archive/v%{version}.tar.gz Patch1: rhbz1881156.patch +Patch2: CVE-2025-6176.patch %if %{with python2} BuildRequires: python2-devel @@ -151,6 +152,10 @@ cd .. %changelog +* Wed Jan 28 2026 Parag Nemade - 1.0.6-4 +- Resolves: RHEL-133986 + CVE-2025-6176 Brotli decompression bomb DoS in scrapy + * Thu Oct 01 2020 Eike Rathke - 1.0.6-3 - Resolves: CVE-2020-8927