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