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 15static PyObject *BrotliError; 16 17static 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 26static 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 48static 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 62static 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 76static 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 90static 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 125PyDoc_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 146typedef struct { 147 PyObject_HEAD 148 BrotliEncoderState* enc; 149} brotli_Compressor; 150 151static 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 160static 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 171static 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 203PyDoc_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 223static 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 246end: 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 257PyDoc_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 271static 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 284end: 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 294PyDoc_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 311static 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 328end: 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 338static PyMemberDef brotli_Compressor_members[] = { 339 {NULL} /* Sentinel */ 340}; 341 342static 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 349static 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 395static 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 && !available_in; 418 419 Py_END_ALLOW_THREADS 420 return ok; 421} 422 423PyDoc_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 432typedef struct { 433 PyObject_HEAD 434 BrotliDecoderState* dec; 435} brotli_Decompressor; 436 437static 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 446static 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 457static 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 472PyDoc_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 492static 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 514end: 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 525PyDoc_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 539static 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 556end: 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 566static PyMemberDef brotli_Decompressor_members[] = { 567 {NULL} /* Sentinel */ 568}; 569 570static 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 576static 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 622PyDoc_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 637static 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 && !available_in; 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 691static PyMethodDef brotli_methods[] = { 692 {"decompress", (PyCFunction)brotli_decompress, METH_VARARGS | METH_KEYWORDS, brotli_decompress__doc__}, 693 {NULL, NULL, 0, NULL} 694}; 695 696PyDoc_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 704static struct PyModuleDef brotli_module = { 705 PyModuleDef_HEAD_INIT, 706 "_brotli", /* m_name */ 707 brotli_doc, /* m_doc */ 708 0, /* m_size */ 709 brotli_methods, /* m_methods */ 710 NULL, /* m_reload */ 711 NULL, /* m_traverse */ 712 NULL, /* m_clear */ 713 NULL /* m_free */ 714}; 715#else 716#define INIT_BROTLI init_brotli 717#define CREATE_BROTLI Py_InitModule3("_brotli", brotli_methods, brotli_doc) 718#define RETURN_BROTLI return 719#define RETURN_NULL return 720#endif 721 722PyMODINIT_FUNC INIT_BROTLI(void) { 723 PyObject *m = CREATE_BROTLI; 724 725 BrotliError = PyErr_NewException((char*) "brotli.error", NULL, NULL); 726 if (BrotliError != NULL) { 727 Py_INCREF(BrotliError); 728 PyModule_AddObject(m, "error", BrotliError); 729 } 730 731 if (PyType_Ready(&brotli_CompressorType) < 0) { 732 RETURN_NULL; 733 } 734 Py_INCREF(&brotli_CompressorType); 735 PyModule_AddObject(m, "Compressor", (PyObject *)&brotli_CompressorType); 736 737 if (PyType_Ready(&brotli_DecompressorType) < 0) { 738 RETURN_NULL; 739 } 740 Py_INCREF(&brotli_DecompressorType); 741 PyModule_AddObject(m, "Decompressor", (PyObject *)&brotli_DecompressorType); 742 743 PyModule_AddIntConstant(m, "MODE_GENERIC", (int) BROTLI_MODE_GENERIC); 744 PyModule_AddIntConstant(m, "MODE_TEXT", (int) BROTLI_MODE_TEXT); 745 PyModule_AddIntConstant(m, "MODE_FONT", (int) BROTLI_MODE_FONT); 746 747 char version[16]; 748 snprintf(version, sizeof(version), "%d.%d.%d", 749 BROTLI_VERSION >> 24, (BROTLI_VERSION >> 12) & 0xFFF, BROTLI_VERSION & 0xFFF); 750 PyModule_AddStringConstant(m, "__version__", version); 751 752 RETURN_BROTLI; 753} 754