PY: fix set_brotli_exception PiperOrigin-RevId: 803421474
diff --git a/python/_brotli.c b/python/_brotli.c index 7b1c227..6ddf9c8 100644 --- a/python/_brotli.c +++ b/python/_brotli.c
@@ -36,24 +36,21 @@ } #endif -static void set_brotli_exception(const char* message) { -#if PY_MAJOR_VERSION >= 3 - PyObject* module = PyImport_ImportModule("_brotli"); - if (module == NULL) { - PyErr_SetString(PyExc_RuntimeError, "Module not found"); - return; +static void set_brotli_exception(PyObject* context, const char* message) { + PyObject* module = NULL; + if (PyModule_Check(context)) { + module = context; + } else { + module = PyObject_GetAttrString(context, "__module__"); } +#if PY_MAJOR_VERSION >= 3 brotli_module_state* state = get_brotli_state(module); PyErr_SetString(state->BrotliError, message); #else /* For Python 2, use static global */ static PyObject* brotli_error = NULL; if (brotli_error == NULL) { - PyObject* module_dict = PyImport_GetModuleDict(); - PyObject* module = PyDict_GetItemString(module_dict, "_brotli"); - if (module != NULL) { - brotli_error = PyObject_GetAttrString(module, "error"); - } + brotli_error = PyObject_GetAttrString(module, "error"); } if (brotli_error != NULL) { PyErr_SetString(brotli_error, message); @@ -263,76 +260,23 @@ 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)) { +typedef struct { + int8_t value; + int8_t ok; /* -1 default, 0 error, 1 success */ +} brotli_maybe_int; + +static int int_convertor(PyObject* obj, brotli_maybe_int* rv) { + if (!PyInt_Check(obj)) { + rv->ok = 0; return 0; } - *result = (int)value; - return 1; -} - -static int mode_convertor(PyObject* o, BrotliEncoderMode* mode) { - if (!PyInt_Check(o)) { - set_brotli_exception("Invalid mode"); + long value = PyInt_AsLong(obj); + if ((value < -128) || (value > 127)) { + rv->ok = 0; return 0; } - - int mode_value = -1; - if (!as_bounded_int(o, &mode_value, 0, 255)) { - set_brotli_exception("Invalid mode"); - return 0; - } - *mode = (BrotliEncoderMode)mode_value; - if (*mode != BROTLI_MODE_GENERIC && *mode != BROTLI_MODE_TEXT && - *mode != BROTLI_MODE_FONT) { - set_brotli_exception("Invalid mode"); - return 0; - } - - return 1; -} - -static int quality_convertor(PyObject* o, int* quality) { - if (!PyInt_Check(o)) { - set_brotli_exception("Invalid quality"); - return 0; - } - - if (!as_bounded_int(o, quality, 0, 11)) { - set_brotli_exception("Invalid quality. Range is 0 to 11."); - return 0; - } - - return 1; -} - -static int lgwin_convertor(PyObject* o, int* lgwin) { - if (!PyInt_Check(o)) { - set_brotli_exception("Invalid lgwin"); - return 0; - } - - if (!as_bounded_int(o, lgwin, 10, 24)) { - set_brotli_exception("Invalid lgwin. Range is 10 to 24."); - return 0; - } - - return 1; -} - -static int lgblock_convertor(PyObject* o, int* lgblock) { - if (!PyInt_Check(o)) { - set_brotli_exception("Invalid lgblock"); - return 0; - } - - if (!as_bounded_int(o, lgblock, 0, 24) || (*lgblock != 0 && *lgblock < 16)) { - set_brotli_exception("Invalid lgblock. Can be 0 or in range 16 to 24."); - return 0; - } - + rv->value = (int8_t)value; + rv->ok = 1; return 1; } @@ -436,31 +380,60 @@ 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; + brotli_maybe_int mode = {-1, -1}; + brotli_maybe_int quality = {-1, -1}; + brotli_maybe_int lgwin = {-1, -1}; + brotli_maybe_int lgblock = {-1, -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); + ok = PyArg_ParseTupleAndKeywords(args, keywds, "|O&O&O&O&:Compressor", + (char**)kwlist, &int_convertor, &mode, + &int_convertor, &quality, &int_convertor, + &lgwin, &int_convertor, &lgblock); + if (!mode.ok || ((mode.ok == 1) && (mode.value != BROTLI_MODE_GENERIC && + mode.value != BROTLI_MODE_TEXT && + mode.value != BROTLI_MODE_FONT))) { + set_brotli_exception((PyObject*)self, "Invalid mode"); + return -1; + } + if (!quality.ok || + ((quality.ok == 1) && (quality.value < 0 || quality.value > 11))) { + set_brotli_exception((PyObject*)self, "Invalid quality; range is 0 to 11"); + return -1; + } + if (!lgwin.ok || + ((lgwin.ok == 1) && (lgwin.value < 10 || lgwin.value > 24))) { + set_brotli_exception((PyObject*)self, "Invalid lgwin; range is 10 to 24"); + return -1; + } + if (!lgblock.ok || + ((lgblock.ok == 1) && + ((lgblock.value < 16 && lgblock.value != 0) || lgblock.value > 24))) { + set_brotli_exception((PyObject*)self, + "Invalid lgblock; range is 16 to 24, or 0"); + return -1; + } 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) + if (mode.ok == 1) { + BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_MODE, + (uint32_t)mode.value); + } + if (quality.ok == 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) + (uint32_t)quality.value); + } + if (lgwin.ok == 1) { + BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGWIN, + (uint32_t)lgwin.value); + } + if (lgblock.ok == 1) { BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGBLOCK, - (uint32_t)lgblock); + (uint32_t)lgblock.value); + } return 0; } @@ -516,6 +489,7 @@ error: set_brotli_exception( + (PyObject*)self, "BrotliEncoderCompressStream failed while processing the stream"); ret = NULL; @@ -554,6 +528,7 @@ error: set_brotli_exception( + (PyObject*)self, "BrotliEncoderCompressStream failed while flushing the stream"); ret = NULL; finally: @@ -597,6 +572,7 @@ error: set_brotli_exception( + (PyObject*)self, "BrotliEncoderCompressStream failed while finishing the stream"); ret = NULL; finally: @@ -852,6 +828,7 @@ if (self->unconsumed_data_length > 0) { if (input.len > 0) { set_brotli_exception( + (PyObject*)self, "process called with data when accept_more_data is False"); ret = NULL; goto finally; @@ -870,6 +847,7 @@ error: set_brotli_exception( + (PyObject*)self, "BrotliDecoderDecompressStream failed while processing the stream"); ret = NULL; @@ -896,6 +874,7 @@ static PyObject* brotli_Decompressor_is_finished(brotli_Decompressor* self) { if (!self->dec) { set_brotli_exception( + (PyObject*)self, "BrotliDecoderState is NULL while checking is_finished"); return NULL; } @@ -1075,7 +1054,7 @@ error: BlocksOutputBuffer_OnError(&buffer); - set_brotli_exception("BrotliDecompress failed"); + set_brotli_exception((PyObject*)self, "BrotliDecompress failed"); ret = NULL; finally: