1 #define PY_SSIZE_T_CLEAN 1 2 #include <Python.h> 3 #include <bytesobject.h> 4 #include <structmember.h> 5 #include <vector> 6 #include "../common/version.h" 7 #include <brotli/decode.h> 8 #include <brotli/encode.h> 9 10 #if PY_MAJOR_VERSION >= 3 11 #define PyInt_Check PyLong_Check 12 #define PyInt_AsLong PyLong_AsLong 13 #endif 14 15 static PyObject *BrotliError; 16 17 static int as_bounded_int(PyObject *o, int* result, int lower_bound, int upper_bound) { 18 long value = PyInt_AsLong(o); 19 if ((value < (long) lower_bound) || (value > (long) upper_bound)) { 20 return 0; 21 } 22 *result = (int) value; 23 return 1; 24 } 25 26 static int mode_convertor(PyObject *o, BrotliEncoderMode *mode) { 27 if (!PyInt_Check(o)) { 28 PyErr_SetString(BrotliError, "Invalid mode"); 29 return 0; 30 } 31 32 int mode_value = -1; 33 if (!as_bounded_int(o, &mode_value, 0, 255)) { 34 PyErr_SetString(BrotliError, "Invalid mode"); 35 return 0; 36 } 37 *mode = (BrotliEncoderMode) mode_value; 38 if (*mode != BROTLI_MODE_GENERIC && 39 *mode != BROTLI_MODE_TEXT && 40 *mode != BROTLI_MODE_FONT) { 41 PyErr_SetString(BrotliError, "Invalid mode"); 42 return 0; 43 } 44 45 return 1; 46 } 47 48 static int quality_convertor(PyObject *o, int *quality) { 49 if (!PyInt_Check(o)) { 50 PyErr_SetString(BrotliError, "Invalid quality"); 51 return 0; 52 } 53 54 if (!as_bounded_int(o, quality, 0, 11)) { 55 PyErr_SetString(BrotliError, "Invalid quality. Range is 0 to 11."); 56 return 0; 57 } 58 59 return 1; 60 } 61 62 static int lgwin_convertor(PyObject *o, int *lgwin) { 63 if (!PyInt_Check(o)) { 64 PyErr_SetString(BrotliError, "Invalid lgwin"); 65 return 0; 66 } 67 68 if (!as_bounded_int(o, lgwin, 10, 24)) { 69 PyErr_SetString(BrotliError, "Invalid lgwin. Range is 10 to 24."); 70 return 0; 71 } 72 73 return 1; 74 } 75 76 static int lgblock_convertor(PyObject *o, int *lgblock) { 77 if (!PyInt_Check(o)) { 78 PyErr_SetString(BrotliError, "Invalid lgblock"); 79 return 0; 80 } 81 82 if (!as_bounded_int(o, lgblock, 0, 24) || (*lgblock != 0 && *lgblock < 16)) { 83 PyErr_SetString(BrotliError, "Invalid lgblock. Can be 0 or in range 16 to 24."); 84 return 0; 85 } 86 87 return 1; 88 } 89 90 static BROTLI_BOOL compress_stream(BrotliEncoderState* enc, BrotliEncoderOperation op, 91 std::vector<uint8_t>* output, 92 uint8_t* input, size_t input_length) { 93 BROTLI_BOOL ok = BROTLI_TRUE; 94 Py_BEGIN_ALLOW_THREADS 95 96 size_t available_in = input_length; 97 const uint8_t* next_in = input; 98 size_t available_out = 0; 99 uint8_t* next_out = NULL; 100 101 while (ok) { 102 ok = BrotliEncoderCompressStream(enc, op, 103 &available_in, &next_in, 104 &available_out, &next_out, NULL); 105 if (!ok) 106 break; 107 108 size_t buffer_length = 0; // Request all available output. 109 const uint8_t* buffer = BrotliEncoderTakeOutput(enc, &buffer_length); 110 if (buffer_length) { 111 (*output).insert((*output).end(), buffer, buffer + buffer_length); 112 } 113 114 if (available_in || BrotliEncoderHasMoreOutput(enc)) { 115 continue; 116 } 117 118 break; 119 } 120 121 Py_END_ALLOW_THREADS 122 return ok; 123 } 124 125 PyDoc_STRVAR(brotli_Compressor_doc, 126 "An object to compress a byte string.\n" 127 "\n" 128 "Signature:\n" 129 " Compressor(mode=MODE_GENERIC, quality=11, lgwin=22, lgblock=0)\n" 130 "\n" 131 "Args:\n" 132 " mode (int, optional): The compression mode can be MODE_GENERIC (default),\n" 133 " MODE_TEXT (for UTF-8 format text input) or MODE_FONT (for WOFF 2.0). \n" 134 " quality (int, optional): Controls the compression-speed vs compression-\n" 135 " density tradeoff. The higher the quality, the slower the compression.\n" 136 " Range is 0 to 11. Defaults to 11.\n" 137 " lgwin (int, optional): Base 2 logarithm of the sliding window size. Range\n" 138 " is 10 to 24. Defaults to 22.\n" 139 " lgblock (int, optional): Base 2 logarithm of the maximum input block size.\n" 140 " Range is 16 to 24. If set to 0, the value will be set based on the\n" 141 " quality. Defaults to 0.\n" 142 "\n" 143 "Raises:\n" 144 " brotli.error: If arguments are invalid.\n"); 145 146 typedef struct { 147 PyObject_HEAD 148 BrotliEncoderState* enc; 149 } brotli_Compressor; 150 151 static void brotli_Compressor_dealloc(brotli_Compressor* self) { 152 BrotliEncoderDestroyInstance(self->enc); 153 #if PY_MAJOR_VERSION >= 3 154 Py_TYPE(self)->tp_free((PyObject*)self); 155 #else 156 self->ob_type->tp_free((PyObject*)self); 157 #endif 158 } 159 160 static PyObject* brotli_Compressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) { 161 brotli_Compressor *self; 162 self = (brotli_Compressor *)type->tp_alloc(type, 0); 163 164 if (self != NULL) { 165 self->enc = BrotliEncoderCreateInstance(0, 0, 0); 166 } 167 168 return (PyObject *)self; 169 } 170 171 static int brotli_Compressor_init(brotli_Compressor *self, PyObject *args, PyObject *keywds) { 172 BrotliEncoderMode mode = (BrotliEncoderMode) -1; 173 int quality = -1; 174 int lgwin = -1; 175 int lgblock = -1; 176 int ok; 177 178 static const char *kwlist[] = {"mode", "quality", "lgwin", "lgblock", NULL}; 179 180 ok = PyArg_ParseTupleAndKeywords(args, keywds, "|O&O&O&O&:Compressor", 181 const_cast<char **>(kwlist), 182 &mode_convertor, &mode, 183 &quality_convertor, &quality, 184 &lgwin_convertor, &lgwin, 185 &lgblock_convertor, &lgblock); 186 if (!ok) 187 return -1; 188 if (!self->enc) 189 return -1; 190 191 if ((int) mode != -1) 192 BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_MODE, (uint32_t)mode); 193 if (quality != -1) 194 BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_QUALITY, (uint32_t)quality); 195 if (lgwin != -1) 196 BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGWIN, (uint32_t)lgwin); 197 if (lgblock != -1) 198 BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGBLOCK, (uint32_t)lgblock); 199 200 return 0; 201 } 202 203 PyDoc_STRVAR(brotli_Compressor_process_doc, 204 "Process \"string\" for compression, returning a string that contains \n" 205 "compressed output data. This data should be concatenated to the output \n" 206 "produced by any preceding calls to the \"process()\" or flush()\" methods. \n" 207 "Some or all of the input may be kept in internal buffers for later \n" 208 "processing, and the compressed output data may be empty until enough input \n" 209 "has been accumulated.\n" 210 "\n" 211 "Signature:\n" 212 " compress(string)\n" 213 "\n" 214 "Args:\n" 215 " string (bytes): The input data\n" 216 "\n" 217 "Returns:\n" 218 " The compressed output data (bytes)\n" 219 "\n" 220 "Raises:\n" 221 " brotli.error: If compression fails\n"); 222 223 static PyObject* brotli_Compressor_process(brotli_Compressor *self, PyObject *args) { 224 PyObject* ret = NULL; 225 std::vector<uint8_t> output; 226 Py_buffer input; 227 BROTLI_BOOL ok = BROTLI_TRUE; 228 229 #if PY_MAJOR_VERSION >= 3 230 ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "y*:process", &input); 231 #else 232 ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "s*:process", &input); 233 #endif 234 235 if (!ok) 236 return NULL; 237 238 if (!self->enc) { 239 ok = BROTLI_FALSE; 240 goto end; 241 } 242 243 ok = compress_stream(self->enc, BROTLI_OPERATION_PROCESS, 244 &output, static_cast<uint8_t*>(input.buf), input.len); 245 246 end: 247 PyBuffer_Release(&input); 248 if (ok) { 249 ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size()); 250 } else { 251 PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while processing the stream"); 252 } 253 254 return ret; 255 } 256 257 PyDoc_STRVAR(brotli_Compressor_flush_doc, 258 "Process all pending input, returning a string containing the remaining\n" 259 "compressed data. This data should be concatenated to the output produced by\n" 260 "any preceding calls to the \"process()\" or \"flush()\" methods.\n" 261 "\n" 262 "Signature:\n" 263 " flush()\n" 264 "\n" 265 "Returns:\n" 266 " The compressed output data (bytes)\n" 267 "\n" 268 "Raises:\n" 269 " brotli.error: If compression fails\n"); 270 271 static PyObject* brotli_Compressor_flush(brotli_Compressor *self) { 272 PyObject *ret = NULL; 273 std::vector<uint8_t> output; 274 BROTLI_BOOL ok = BROTLI_TRUE; 275 276 if (!self->enc) { 277 ok = BROTLI_FALSE; 278 goto end; 279 } 280 281 ok = compress_stream(self->enc, BROTLI_OPERATION_FLUSH, 282 &output, NULL, 0); 283 284 end: 285 if (ok) { 286 ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size()); 287 } else { 288 PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while flushing the stream"); 289 } 290 291 return ret; 292 } 293 294 PyDoc_STRVAR(brotli_Compressor_finish_doc, 295 "Process all pending input and complete all compression, returning a string\n" 296 "containing the remaining compressed data. This data should be concatenated\n" 297 "to the output produced by any preceding calls to the \"process()\" or\n" 298 "\"flush()\" methods.\n" 299 "After calling \"finish()\", the \"process()\" and \"flush()\" methods\n" 300 "cannot be called again, and a new \"Compressor\" object should be created.\n" 301 "\n" 302 "Signature:\n" 303 " finish(string)\n" 304 "\n" 305 "Returns:\n" 306 " The compressed output data (bytes)\n" 307 "\n" 308 "Raises:\n" 309 " brotli.error: If compression fails\n"); 310 311 static PyObject* brotli_Compressor_finish(brotli_Compressor *self) { 312 PyObject *ret = NULL; 313 std::vector<uint8_t> output; 314 BROTLI_BOOL ok = BROTLI_TRUE; 315 316 if (!self->enc) { 317 ok = BROTLI_FALSE; 318 goto end; 319 } 320 321 ok = compress_stream(self->enc, BROTLI_OPERATION_FINISH, 322 &output, NULL, 0); 323 324 if (ok) { 325 ok = BrotliEncoderIsFinished(self->enc); 326 } 327 328 end: 329 if (ok) { 330 ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size()); 331 } else { 332 PyErr_SetString(BrotliError, "BrotliEncoderCompressStream failed while finishing the stream"); 333 } 334 335 return ret; 336 } 337 338 static PyMemberDef brotli_Compressor_members[] = { 339 {NULL} /* Sentinel */ 340 }; 341 342 static PyMethodDef brotli_Compressor_methods[] = { 343 {"process", (PyCFunction)brotli_Compressor_process, METH_VARARGS, brotli_Compressor_process_doc}, 344 {"flush", (PyCFunction)brotli_Compressor_flush, METH_NOARGS, brotli_Compressor_flush_doc}, 345 {"finish", (PyCFunction)brotli_Compressor_finish, METH_NOARGS, brotli_Compressor_finish_doc}, 346 {NULL} /* Sentinel */ 347 }; 348 349 static PyTypeObject brotli_CompressorType = { 350 #if PY_MAJOR_VERSION >= 3 351 PyVarObject_HEAD_INIT(NULL, 0) 352 #else 353 PyObject_HEAD_INIT(NULL) 354 0, /* ob_size*/ 355 #endif 356 "brotli.Compressor", /* tp_name */ 357 sizeof(brotli_Compressor), /* tp_basicsize */ 358 0, /* tp_itemsize */ 359 (destructor)brotli_Compressor_dealloc, /* tp_dealloc */ 360 0, /* tp_print */ 361 0, /* tp_getattr */ 362 0, /* tp_setattr */ 363 0, /* tp_compare */ 364 0, /* tp_repr */ 365 0, /* tp_as_number */ 366 0, /* tp_as_sequence */ 367 0, /* tp_as_mapping */ 368 0, /* tp_hash */ 369 0, /* tp_call */ 370 0, /* tp_str */ 371 0, /* tp_getattro */ 372 0, /* tp_setattro */ 373 0, /* tp_as_buffer */ 374 Py_TPFLAGS_DEFAULT, /* tp_flags */ 375 brotli_Compressor_doc, /* tp_doc */ 376 0, /* tp_traverse */ 377 0, /* tp_clear */ 378 0, /* tp_richcompare */ 379 0, /* tp_weaklistoffset */ 380 0, /* tp_iter */ 381 0, /* tp_iternext */ 382 brotli_Compressor_methods, /* tp_methods */ 383 brotli_Compressor_members, /* tp_members */ 384 0, /* tp_getset */ 385 0, /* tp_base */ 386 0, /* tp_dict */ 387 0, /* tp_descr_get */ 388 0, /* tp_descr_set */ 389 0, /* tp_dictoffset */ 390 (initproc)brotli_Compressor_init, /* tp_init */ 391 0, /* tp_alloc */ 392 brotli_Compressor_new, /* tp_new */ 393 }; 394 395 static BROTLI_BOOL decompress_stream(BrotliDecoderState* dec, 396 std::vector<uint8_t>* output, 397 uint8_t* input, size_t input_length) { 398 BROTLI_BOOL ok = BROTLI_TRUE; 399 Py_BEGIN_ALLOW_THREADS 400 401 size_t available_in = input_length; 402 const uint8_t* next_in = input; 403 size_t available_out = 0; 404 uint8_t* next_out = NULL; 405 406 BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; 407 while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { 408 result = BrotliDecoderDecompressStream(dec, 409 &available_in, &next_in, 410 &available_out, &next_out, NULL); 411 size_t buffer_length = 0; // Request all available output. 412 const uint8_t* buffer = BrotliDecoderTakeOutput(dec, &buffer_length); 413 if (buffer_length) { 414 (*output).insert((*output).end(), buffer, buffer + buffer_length); 415 } 416 } 417 ok = result != BROTLI_DECODER_RESULT_ERROR; 418 419 Py_END_ALLOW_THREADS 420 return ok; 421 } 422 423 PyDoc_STRVAR(brotli_Decompressor_doc, 424 "An object to decompress a byte string.\n" 425 "\n" 426 "Signature:\n" 427 " Decompressor()\n" 428 "\n" 429 "Raises:\n" 430 " brotli.error: If arguments are invalid.\n"); 431 432 typedef struct { 433 PyObject_HEAD 434 BrotliDecoderState* dec; 435 } brotli_Decompressor; 436 437 static void brotli_Decompressor_dealloc(brotli_Decompressor* self) { 438 BrotliDecoderDestroyInstance(self->dec); 439 #if PY_MAJOR_VERSION >= 3 440 Py_TYPE(self)->tp_free((PyObject*)self); 441 #else 442 self->ob_type->tp_free((PyObject*)self); 443 #endif 444 } 445 446 static PyObject* brotli_Decompressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) { 447 brotli_Decompressor *self; 448 self = (brotli_Decompressor *)type->tp_alloc(type, 0); 449 450 if (self != NULL) { 451 self->dec = BrotliDecoderCreateInstance(0, 0, 0); 452 } 453 454 return (PyObject *)self; 455 } 456 457 static int brotli_Decompressor_init(brotli_Decompressor *self, PyObject *args, PyObject *keywds) { 458 int ok; 459 460 static const char *kwlist[] = {NULL}; 461 462 ok = PyArg_ParseTupleAndKeywords(args, keywds, "|:Decompressor", 463 const_cast<char **>(kwlist)); 464 if (!ok) 465 return -1; 466 if (!self->dec) 467 return -1; 468 469 return 0; 470 } 471 472 PyDoc_STRVAR(brotli_Decompressor_process_doc, 473 "Process \"string\" for decompression, returning a string that contains \n" 474 "decompressed output data. This data should be concatenated to the output \n" 475 "produced by any preceding calls to the \"process()\" method. \n" 476 "Some or all of the input may be kept in internal buffers for later \n" 477 "processing, and the decompressed output data may be empty until enough input \n" 478 "has been accumulated.\n" 479 "\n" 480 "Signature:\n" 481 " decompress(string)\n" 482 "\n" 483 "Args:\n" 484 " string (bytes): The input data\n" 485 "\n" 486 "Returns:\n" 487 " The decompressed output data (bytes)\n" 488 "\n" 489 "Raises:\n" 490 " brotli.error: If decompression fails\n"); 491 492 static PyObject* brotli_Decompressor_process(brotli_Decompressor *self, PyObject *args) { 493 PyObject* ret = NULL; 494 std::vector<uint8_t> output; 495 Py_buffer input; 496 BROTLI_BOOL ok = BROTLI_TRUE; 497 498 #if PY_MAJOR_VERSION >= 3 499 ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "y*:process", &input); 500 #else 501 ok = (BROTLI_BOOL)PyArg_ParseTuple(args, "s*:process", &input); 502 #endif 503 504 if (!ok) 505 return NULL; 506 507 if (!self->dec) { 508 ok = BROTLI_FALSE; 509 goto end; 510 } 511 512 ok = decompress_stream(self->dec, &output, static_cast<uint8_t*>(input.buf), input.len); 513 514 end: 515 PyBuffer_Release(&input); 516 if (ok) { 517 ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size()); 518 } else { 519 PyErr_SetString(BrotliError, "BrotliDecoderDecompressStream failed while processing the stream"); 520 } 521 522 return ret; 523 } 524 525 PyDoc_STRVAR(brotli_Decompressor_is_finished_doc, 526 "Checks if decoder instance reached the final state.\n" 527 "\n" 528 "Signature:\n" 529 " is_finished()\n" 530 "\n" 531 "Returns:\n" 532 " True if the decoder is in a state where it reached the end of the input\n" 533 " and produced all of the output\n" 534 " False otherwise\n" 535 "\n" 536 "Raises:\n" 537 " brotli.error: If decompression fails\n"); 538 539 static PyObject* brotli_Decompressor_is_finished(brotli_Decompressor *self) { 540 PyObject *ret = NULL; 541 std::vector<uint8_t> output; 542 BROTLI_BOOL ok = BROTLI_TRUE; 543 544 if (!self->dec) { 545 ok = BROTLI_FALSE; 546 PyErr_SetString(BrotliError, "BrotliDecoderState is NULL while checking is_finished"); 547 goto end; 548 } 549 550 if (BrotliDecoderIsFinished(self->dec)) { 551 Py_RETURN_TRUE; 552 } else { 553 Py_RETURN_FALSE; 554 } 555 556 end: 557 if (ok) { 558 ret = PyBytes_FromStringAndSize((char*)(output.empty() ? NULL : &output[0]), output.size()); 559 } else { 560 PyErr_SetString(BrotliError, "BrotliDecoderDecompressStream failed while finishing the stream"); 561 } 562 563 return ret; 564 } 565 566 static PyMemberDef brotli_Decompressor_members[] = { 567 {NULL} /* Sentinel */ 568 }; 569 570 static PyMethodDef brotli_Decompressor_methods[] = { 571 {"process", (PyCFunction)brotli_Decompressor_process, METH_VARARGS, brotli_Decompressor_process_doc}, 572 {"is_finished", (PyCFunction)brotli_Decompressor_is_finished, METH_NOARGS, brotli_Decompressor_is_finished_doc}, 573 {NULL} /* Sentinel */ 574 }; 575 576 static PyTypeObject brotli_DecompressorType = { 577 #if PY_MAJOR_VERSION >= 3 578 PyVarObject_HEAD_INIT(NULL, 0) 579 #else 580 PyObject_HEAD_INIT(NULL) 581 0, /* ob_size*/ 582 #endif 583 "brotli.Decompressor", /* tp_name */ 584 sizeof(brotli_Decompressor), /* tp_basicsize */ 585 0, /* tp_itemsize */ 586 (destructor)brotli_Decompressor_dealloc, /* tp_dealloc */ 587 0, /* tp_print */ 588 0, /* tp_getattr */ 589 0, /* tp_setattr */ 590 0, /* tp_compare */ 591 0, /* tp_repr */ 592 0, /* tp_as_number */ 593 0, /* tp_as_sequence */ 594 0, /* tp_as_mapping */ 595 0, /* tp_hash */ 596 0, /* tp_call */ 597 0, /* tp_str */ 598 0, /* tp_getattro */ 599 0, /* tp_setattro */ 600 0, /* tp_as_buffer */ 601 Py_TPFLAGS_DEFAULT, /* tp_flags */ 602 brotli_Decompressor_doc, /* tp_doc */ 603 0, /* tp_traverse */ 604 0, /* tp_clear */ 605 0, /* tp_richcompare */ 606 0, /* tp_weaklistoffset */ 607 0, /* tp_iter */ 608 0, /* tp_iternext */ 609 brotli_Decompressor_methods, /* tp_methods */ 610 brotli_Decompressor_members, /* tp_members */ 611 0, /* tp_getset */ 612 0, /* tp_base */ 613 0, /* tp_dict */ 614 0, /* tp_descr_get */ 615 0, /* tp_descr_set */ 616 0, /* tp_dictoffset */ 617 (initproc)brotli_Decompressor_init, /* tp_init */ 618 0, /* tp_alloc */ 619 brotli_Decompressor_new, /* tp_new */ 620 }; 621 622 PyDoc_STRVAR(brotli_decompress__doc__, 623 "Decompress a compressed byte string.\n" 624 "\n" 625 "Signature:\n" 626 " decompress(string)\n" 627 "\n" 628 "Args:\n" 629 " string (bytes): The compressed input data.\n" 630 "\n" 631 "Returns:\n" 632 " The decompressed byte string.\n" 633 "\n" 634 "Raises:\n" 635 " brotli.error: If decompressor fails.\n"); 636 637 static PyObject* brotli_decompress(PyObject *self, PyObject *args, PyObject *keywds) { 638 PyObject *ret = NULL; 639 Py_buffer input; 640 const uint8_t* next_in; 641 size_t available_in; 642 int ok; 643 644 static const char *kwlist[] = {"string", NULL}; 645 646 #if PY_MAJOR_VERSION >= 3 647 ok = PyArg_ParseTupleAndKeywords(args, keywds, "y*|:decompress", 648 const_cast<char **>(kwlist), &input); 649 #else 650 ok = PyArg_ParseTupleAndKeywords(args, keywds, "s*|:decompress", 651 const_cast<char **>(kwlist), &input); 652 #endif 653 654 if (!ok) 655 return NULL; 656 657 std::vector<uint8_t> output; 658 659 /* >>> Pure C block; release python GIL. */ 660 Py_BEGIN_ALLOW_THREADS 661 662 BrotliDecoderState* state = BrotliDecoderCreateInstance(0, 0, 0); 663 664 BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; 665 next_in = static_cast<uint8_t*>(input.buf); 666 available_in = input.len; 667 while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { 668 size_t available_out = 0; 669 result = BrotliDecoderDecompressStream(state, &available_in, &next_in, 670 &available_out, 0, 0); 671 const uint8_t* next_out = BrotliDecoderTakeOutput(state, &available_out); 672 if (available_out != 0) 673 output.insert(output.end(), next_out, next_out + available_out); 674 } 675 ok = result == BROTLI_DECODER_RESULT_SUCCESS; 676 BrotliDecoderDestroyInstance(state); 677 678 Py_END_ALLOW_THREADS 679 /* <<< Pure C block end. Python GIL reacquired. */ 680 681 PyBuffer_Release(&input); 682 if (ok) { 683 ret = PyBytes_FromStringAndSize((char*)(output.size() ? &output[0] : NULL), output.size()); 684 } else { 685 PyErr_SetString(BrotliError, "BrotliDecompress failed"); 686 } 687 688 return ret; 689 } 690 691 static PyMethodDef brotli_methods[] = { 692 {"decompress", (PyCFunction)brotli_decompress, METH_VARARGS | METH_KEYWORDS, brotli_decompress__doc__}, 693 {NULL, NULL, 0, NULL} 694 }; 695 696 PyDoc_STRVAR(brotli_doc, "Implementation module for the Brotli library."); 697 698 #if PY_MAJOR_VERSION >= 3 699 #define INIT_BROTLI PyInit__brotli 700 #define CREATE_BROTLI PyModule_Create(&brotli_module) 701 #define RETURN_BROTLI return m 702 #define RETURN_NULL return NULL 703 704 static struct PyModuleDef brotli_module = { 705 PyModuleDef_HEAD_INIT, 706 "_brotli", 707 brotli_doc, 708 0, 709 brotli_methods, 710 NULL, 711 NULL, 712 NULL 713 }; 714 #else 715 #define INIT_BROTLI init_brotli 716 #define CREATE_BROTLI Py_InitModule3("_brotli", brotli_methods, brotli_doc) 717 #define RETURN_BROTLI return 718 #define RETURN_NULL return 719 #endif 720 721 PyMODINIT_FUNC INIT_BROTLI(void) { 722 PyObject *m = CREATE_BROTLI; 723 724 BrotliError = PyErr_NewException((char*) "brotli.error", NULL, NULL); 725 if (BrotliError != NULL) { 726 Py_INCREF(BrotliError); 727 PyModule_AddObject(m, "error", BrotliError); 728 } 729 730 if (PyType_Ready(&brotli_CompressorType) < 0) { 731 RETURN_NULL; 732 } 733 Py_INCREF(&brotli_CompressorType); 734 PyModule_AddObject(m, "Compressor", (PyObject *)&brotli_CompressorType); 735 736 if (PyType_Ready(&brotli_DecompressorType) < 0) { 737 RETURN_NULL; 738 } 739 Py_INCREF(&brotli_DecompressorType); 740 PyModule_AddObject(m, "Decompressor", (PyObject *)&brotli_DecompressorType); 741 742 PyModule_AddIntConstant(m, "MODE_GENERIC", (int) BROTLI_MODE_GENERIC); 743 PyModule_AddIntConstant(m, "MODE_TEXT", (int) BROTLI_MODE_TEXT); 744 PyModule_AddIntConstant(m, "MODE_FONT", (int) BROTLI_MODE_FONT); 745 746 char version[16]; 747 snprintf(version, sizeof(version), "%d.%d.%d", 748 BROTLI_VERSION >> 24, (BROTLI_VERSION >> 12) & 0xFFF, BROTLI_VERSION & 0xFFF); 749 PyModule_AddStringConstant(m, "__version__", version); 750 751 RETURN_BROTLI; 752 } 753