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