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