1 #define PY_SSIZE_T_CLEAN 1
2 #include <Python.h>
3 #include <bytesobject.h>
4 #include <structmember.h>
5
6 #include <brotli/decode.h>
7 #include <brotli/encode.h>
8
9 #if PY_MAJOR_VERSION >= 3
10 #define PyInt_Check PyLong_Check
11 #define PyInt_AsLong PyLong_AsLong
12 #else
13 #define Py_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0]))
14 #endif
15
16 static PyObject *BrotliError;
17
18 /* -----------------------------------
19 BlocksOutputBuffer code
20 ----------------------------------- */
21 typedef struct {
22 /* List of blocks */
23 PyObject *list;
24 /* Number of whole allocated size. */
25 Py_ssize_t allocated;
26 } BlocksOutputBuffer;
27
28 static const char unable_allocate_msg[] = "Unable to allocate output buffer.";
29
30 /* Block size sequence */
31 #define KB (1024)
32 #define MB (1024*1024)
33 static const Py_ssize_t BUFFER_BLOCK_SIZE[] =
34 { 32*KB, 64*KB, 256*KB, 1*MB, 4*MB, 8*MB, 16*MB, 16*MB,
35 32*MB, 32*MB, 32*MB, 32*MB, 64*MB, 64*MB, 128*MB, 128*MB,
36 256*MB };
37 #undef KB
38 #undef MB
39
40 /* According to the block sizes defined by BUFFER_BLOCK_SIZE, the whole
41 allocated size growth step is:
42 1 32 KB +32 KB
43 2 96 KB +64 KB
44 3 352 KB +256 KB
45 4 1.34 MB +1 MB
46 5 5.34 MB +4 MB
47 6 13.34 MB +8 MB
48 7 29.34 MB +16 MB
49 8 45.34 MB +16 MB
50 9 77.34 MB +32 MB
51 10 109.34 MB +32 MB
52 11 141.34 MB +32 MB
53 12 173.34 MB +32 MB
54 13 237.34 MB +64 MB
55 14 301.34 MB +64 MB
56 15 429.34 MB +128 MB
57 16 557.34 MB +128 MB
58 17 813.34 MB +256 MB
59 18 1069.34 MB +256 MB
60 19 1325.34 MB +256 MB
61 20 1581.34 MB +256 MB
62 21 1837.34 MB +256 MB
63 22 2093.34 MB +256 MB
64 ...
65 */
66
67 /* Initialize the buffer, and grow the buffer.
68 Return 0 on success
69 Return -1 on failure
70 */
71 static inline int
BlocksOutputBuffer_InitAndGrow(BlocksOutputBuffer * buffer,size_t * avail_out,uint8_t ** next_out)72 BlocksOutputBuffer_InitAndGrow(BlocksOutputBuffer *buffer,
73 size_t *avail_out, uint8_t **next_out)
74 {
75 PyObject *b;
76 const Py_ssize_t block_size = BUFFER_BLOCK_SIZE[0];
77
78 // Ensure .list was set to NULL, for BlocksOutputBuffer_OnError().
79 assert(buffer->list == NULL);
80
81 // The first block
82 b = PyBytes_FromStringAndSize(NULL, block_size);
83 if (b == NULL) {
84 return -1;
85 }
86
87 // Create list
88 buffer->list = PyList_New(1);
89 if (buffer->list == NULL) {
90 Py_DECREF(b);
91 return -1;
92 }
93 PyList_SET_ITEM(buffer->list, 0, b);
94
95 // Set variables
96 buffer->allocated = block_size;
97
98 *avail_out = (size_t) block_size;
99 *next_out = (uint8_t*) PyBytes_AS_STRING(b);
100 return 0;
101 }
102
103 /* Grow the buffer. The avail_out must be 0, please check it before calling.
104 Return 0 on success
105 Return -1 on failure
106 */
107 static inline int
BlocksOutputBuffer_Grow(BlocksOutputBuffer * buffer,size_t * avail_out,uint8_t ** next_out)108 BlocksOutputBuffer_Grow(BlocksOutputBuffer *buffer,
109 size_t *avail_out, uint8_t **next_out)
110 {
111 PyObject *b;
112 const Py_ssize_t list_len = Py_SIZE(buffer->list);
113 Py_ssize_t block_size;
114
115 // Ensure no gaps in the data
116 assert(*avail_out == 0);
117
118 // Get block size
119 if (list_len < (Py_ssize_t) Py_ARRAY_LENGTH(BUFFER_BLOCK_SIZE)) {
120 block_size = BUFFER_BLOCK_SIZE[list_len];
121 } else {
122 block_size = BUFFER_BLOCK_SIZE[Py_ARRAY_LENGTH(BUFFER_BLOCK_SIZE) - 1];
123 }
124
125 // Check buffer->allocated overflow
126 if (block_size > PY_SSIZE_T_MAX - buffer->allocated) {
127 PyErr_SetString(PyExc_MemoryError, unable_allocate_msg);
128 return -1;
129 }
130
131 // Create the block
132 b = PyBytes_FromStringAndSize(NULL, block_size);
133 if (b == NULL) {
134 PyErr_SetString(PyExc_MemoryError, unable_allocate_msg);
135 return -1;
136 }
137 if (PyList_Append(buffer->list, b) < 0) {
138 Py_DECREF(b);
139 return -1;
140 }
141 Py_DECREF(b);
142
143 // Set variables
144 buffer->allocated += block_size;
145
146 *avail_out = (size_t) block_size;
147 *next_out = (uint8_t*) PyBytes_AS_STRING(b);
148 return 0;
149 }
150
151 /* Finish the buffer.
152 Return a bytes object on success
153 Return NULL on failure
154 */
155 static inline PyObject *
BlocksOutputBuffer_Finish(BlocksOutputBuffer * buffer,size_t avail_out)156 BlocksOutputBuffer_Finish(BlocksOutputBuffer *buffer, size_t avail_out)
157 {
158 PyObject *result, *block;
159 const Py_ssize_t list_len = Py_SIZE(buffer->list);
160
161 // Fast path for single block
162 if ((list_len == 1 && avail_out == 0) ||
163 (list_len == 2 && Py_SIZE(PyList_GET_ITEM(buffer->list, 1)) == (Py_ssize_t) avail_out))
164 {
165 block = PyList_GET_ITEM(buffer->list, 0);
166 Py_INCREF(block);
167
168 Py_CLEAR(buffer->list);
169 return block;
170 }
171
172 // Final bytes object
173 result = PyBytes_FromStringAndSize(NULL, buffer->allocated - avail_out);
174 if (result == NULL) {
175 PyErr_SetString(PyExc_MemoryError, unable_allocate_msg);
176 return NULL;
177 }
178
179 // Memory copy
180 if (list_len > 0) {
181 char *posi = PyBytes_AS_STRING(result);
182
183 // Blocks except the last one
184 Py_ssize_t i = 0;
185 for (; i < list_len-1; i++) {
186 block = PyList_GET_ITEM(buffer->list, i);
187 memcpy(posi, PyBytes_AS_STRING(block), Py_SIZE(block));
188 posi += Py_SIZE(block);
189 }
190 // The last block
191 block = PyList_GET_ITEM(buffer->list, i);
192 memcpy(posi, PyBytes_AS_STRING(block), Py_SIZE(block) - avail_out);
193 } else {
194 assert(Py_SIZE(result) == 0);
195 }
196
197 Py_CLEAR(buffer->list);
198 return result;
199 }
200
201 /* Clean up the buffer */
202 static inline void
BlocksOutputBuffer_OnError(BlocksOutputBuffer * buffer)203 BlocksOutputBuffer_OnError(BlocksOutputBuffer *buffer)
204 {
205 Py_CLEAR(buffer->list);
206 }
207
208
as_bounded_int(PyObject * o,int * result,int lower_bound,int upper_bound)209 static int as_bounded_int(PyObject *o, int* result, int lower_bound, int upper_bound) {
210 long value = PyInt_AsLong(o);
211 if ((value < (long) lower_bound) || (value > (long) upper_bound)) {
212 return 0;
213 }
214 *result = (int) value;
215 return 1;
216 }
217
mode_convertor(PyObject * o,BrotliEncoderMode * mode)218 static int mode_convertor(PyObject *o, BrotliEncoderMode *mode) {
219 if (!PyInt_Check(o)) {
220 PyErr_SetString(BrotliError, "Invalid mode");
221 return 0;
222 }
223
224 int mode_value = -1;
225 if (!as_bounded_int(o, &mode_value, 0, 255)) {
226 PyErr_SetString(BrotliError, "Invalid mode");
227 return 0;
228 }
229 *mode = (BrotliEncoderMode) mode_value;
230 if (*mode != BROTLI_MODE_GENERIC &&
231 *mode != BROTLI_MODE_TEXT &&
232 *mode != BROTLI_MODE_FONT) {
233 PyErr_SetString(BrotliError, "Invalid mode");
234 return 0;
235 }
236
237 return 1;
238 }
239
quality_convertor(PyObject * o,int * quality)240 static int quality_convertor(PyObject *o, int *quality) {
241 if (!PyInt_Check(o)) {
242 PyErr_SetString(BrotliError, "Invalid quality");
243 return 0;
244 }
245
246 if (!as_bounded_int(o, quality, 0, 11)) {
247 PyErr_SetString(BrotliError, "Invalid quality. Range is 0 to 11.");
248 return 0;
249 }
250
251 return 1;
252 }
253
lgwin_convertor(PyObject * o,int * lgwin)254 static int lgwin_convertor(PyObject *o, int *lgwin) {
255 if (!PyInt_Check(o)) {
256 PyErr_SetString(BrotliError, "Invalid lgwin");
257 return 0;
258 }
259
260 if (!as_bounded_int(o, lgwin, 10, 24)) {
261 PyErr_SetString(BrotliError, "Invalid lgwin. Range is 10 to 24.");
262 return 0;
263 }
264
265 return 1;
266 }
267
lgblock_convertor(PyObject * o,int * lgblock)268 static int lgblock_convertor(PyObject *o, int *lgblock) {
269 if (!PyInt_Check(o)) {
270 PyErr_SetString(BrotliError, "Invalid lgblock");
271 return 0;
272 }
273
274 if (!as_bounded_int(o, lgblock, 0, 24) || (*lgblock != 0 && *lgblock < 16)) {
275 PyErr_SetString(BrotliError, "Invalid lgblock. Can be 0 or in range 16 to 24.");
276 return 0;
277 }
278
279 return 1;
280 }
281
compress_stream(BrotliEncoderState * enc,BrotliEncoderOperation op,uint8_t * input,size_t input_length)282 static PyObject* compress_stream(BrotliEncoderState* enc, BrotliEncoderOperation op,
283 uint8_t* input, size_t input_length) {
284 BROTLI_BOOL ok;
285
286 size_t available_in = input_length;
287 const uint8_t* next_in = input;
288
289 size_t available_out;
290 uint8_t* next_out;
291 BlocksOutputBuffer buffer = {.list=NULL};
292 PyObject *ret;
293
294 if (BlocksOutputBuffer_InitAndGrow(&buffer, &available_out, &next_out) < 0) {
295 goto error;
296 }
297
298 while (1) {
299 Py_BEGIN_ALLOW_THREADS
300 ok = BrotliEncoderCompressStream(enc, op,
301 &available_in, &next_in,
302 &available_out, &next_out, NULL);
303 Py_END_ALLOW_THREADS
304 if (!ok) {
305 goto error;
306 }
307
308 if (available_in || BrotliEncoderHasMoreOutput(enc)) {
309 if (available_out == 0) {
310 if (BlocksOutputBuffer_Grow(&buffer, &available_out, &next_out) < 0) {
311 goto error;
312 }
313 }
314 continue;
315 }
316
317 break;
318 }
319
320 ret = BlocksOutputBuffer_Finish(&buffer, available_out);
321 if (ret != NULL) {
322 return ret;
323 }
324
325 error:
326 BlocksOutputBuffer_OnError(&buffer);
327 return NULL;
328 }
329
330 PyDoc_STRVAR(brotli_Compressor_doc,
331 "An object to compress a byte string.\n"
332 "\n"
333 "Signature:\n"
334 " Compressor(mode=MODE_GENERIC, quality=11, lgwin=22, lgblock=0)\n"
335 "\n"
336 "Args:\n"
337 " mode (int, optional): The compression mode can be MODE_GENERIC (default),\n"
338 " MODE_TEXT (for UTF-8 format text input) or MODE_FONT (for WOFF 2.0). \n"
339 " quality (int, optional): Controls the compression-speed vs compression-\n"
340 " density tradeoff. The higher the quality, the slower the compression.\n"
341 " Range is 0 to 11. Defaults to 11.\n"
342 " lgwin (int, optional): Base 2 logarithm of the sliding window size. Range\n"
343 " is 10 to 24. Defaults to 22.\n"
344 " lgblock (int, optional): Base 2 logarithm of the maximum input block size.\n"
345 " Range is 16 to 24. If set to 0, the value will be set based on the\n"
346 " quality. Defaults to 0.\n"
347 "\n"
348 "Raises:\n"
349 " brotli.error: If arguments are invalid.\n");
350
351 typedef struct {
352 PyObject_HEAD
353 BrotliEncoderState* enc;
354 } brotli_Compressor;
355
brotli_Compressor_dealloc(brotli_Compressor * self)356 static void brotli_Compressor_dealloc(brotli_Compressor* self) {
357 BrotliEncoderDestroyInstance(self->enc);
358 #if PY_MAJOR_VERSION >= 3
359 Py_TYPE(self)->tp_free((PyObject*)self);
360 #else
361 self->ob_type->tp_free((PyObject*)self);
362 #endif
363 }
364
brotli_Compressor_new(PyTypeObject * type,PyObject * args,PyObject * keywds)365 static PyObject* brotli_Compressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) {
366 brotli_Compressor *self;
367 self = (brotli_Compressor *)type->tp_alloc(type, 0);
368
369 if (self != NULL) {
370 self->enc = BrotliEncoderCreateInstance(0, 0, 0);
371 }
372
373 return (PyObject *)self;
374 }
375
brotli_Compressor_init(brotli_Compressor * self,PyObject * args,PyObject * keywds)376 static int brotli_Compressor_init(brotli_Compressor *self, PyObject *args, PyObject *keywds) {
377 BrotliEncoderMode mode = (BrotliEncoderMode) -1;
378 int quality = -1;
379 int lgwin = -1;
380 int lgblock = -1;
381 int ok;
382
383 static const char *kwlist[] = {"mode", "quality", "lgwin", "lgblock", NULL};
384
385 ok = PyArg_ParseTupleAndKeywords(args, keywds, "|O&O&O&O&:Compressor",
386 (char **) kwlist,
387 &mode_convertor, &mode,
388 &quality_convertor, &quality,
389 &lgwin_convertor, &lgwin,
390 &lgblock_convertor, &lgblock);
391 if (!ok)
392 return -1;
393 if (!self->enc)
394 return -1;
395
396 if ((int) mode != -1)
397 BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_MODE, (uint32_t)mode);
398 if (quality != -1)
399 BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_QUALITY, (uint32_t)quality);
400 if (lgwin != -1)
401 BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGWIN, (uint32_t)lgwin);
402 if (lgblock != -1)
403 BrotliEncoderSetParameter(self->enc, BROTLI_PARAM_LGBLOCK, (uint32_t)lgblock);
404
405 return 0;
406 }
407
408 PyDoc_STRVAR(brotli_Compressor_process_doc,
409 "Process \"string\" for compression, returning a string that contains \n"
410 "compressed output data. This data should be concatenated to the output \n"
411 "produced by any preceding calls to the \"process()\" or flush()\" methods. \n"
412 "Some or all of the input may be kept in internal buffers for later \n"
413 "processing, and the compressed output data may be empty until enough input \n"
414 "has been accumulated.\n"
415 "\n"
416 "Signature:\n"
417 " compress(string)\n"
418 "\n"
419 "Args:\n"
420 " string (bytes): The input data\n"
421 "\n"
422 "Returns:\n"
423 " The compressed output data (bytes)\n"
424 "\n"
425 "Raises:\n"
426 " brotli.error: If compression fails\n");
427
brotli_Compressor_process(brotli_Compressor * self,PyObject * args)428 static PyObject* brotli_Compressor_process(brotli_Compressor *self, PyObject *args) {
429 PyObject* ret;
430 Py_buffer input;
431 int ok;
432
433 #if PY_MAJOR_VERSION >= 3
434 ok = PyArg_ParseTuple(args, "y*:process", &input);
435 #else
436 ok = PyArg_ParseTuple(args, "s*:process", &input);
437 #endif
438
439 if (!ok) {
440 return NULL;
441 }
442
443 if (!self->enc) {
444 goto error;
445 }
446
447 ret = compress_stream(self->enc, BROTLI_OPERATION_PROCESS,
448 (uint8_t*) input.buf, input.len);
449 if (ret != NULL) {
450 goto finally;
451 }
452
453 error:
454 PyErr_SetString(BrotliError,
455 "BrotliEncoderCompressStream failed while processing the stream");
456 ret = NULL;
457
458 finally:
459 PyBuffer_Release(&input);
460 return ret;
461 }
462
463 PyDoc_STRVAR(brotli_Compressor_flush_doc,
464 "Process all pending input, returning a string containing the remaining\n"
465 "compressed data. This data should be concatenated to the output produced by\n"
466 "any preceding calls to the \"process()\" or \"flush()\" methods.\n"
467 "\n"
468 "Signature:\n"
469 " flush()\n"
470 "\n"
471 "Returns:\n"
472 " The compressed output data (bytes)\n"
473 "\n"
474 "Raises:\n"
475 " brotli.error: If compression fails\n");
476
brotli_Compressor_flush(brotli_Compressor * self)477 static PyObject* brotli_Compressor_flush(brotli_Compressor *self) {
478 PyObject *ret;
479
480 if (!self->enc) {
481 goto error;
482 }
483
484 ret = compress_stream(self->enc, BROTLI_OPERATION_FLUSH,
485 NULL, 0);
486 if (ret != NULL) {
487 goto finally;
488 }
489
490 error:
491 PyErr_SetString(BrotliError,
492 "BrotliEncoderCompressStream failed while flushing the stream");
493 ret = NULL;
494 finally:
495 return ret;
496 }
497
498 PyDoc_STRVAR(brotli_Compressor_finish_doc,
499 "Process all pending input and complete all compression, returning a string\n"
500 "containing the remaining compressed data. This data should be concatenated\n"
501 "to the output produced by any preceding calls to the \"process()\" or\n"
502 "\"flush()\" methods.\n"
503 "After calling \"finish()\", the \"process()\" and \"flush()\" methods\n"
504 "cannot be called again, and a new \"Compressor\" object should be created.\n"
505 "\n"
506 "Signature:\n"
507 " finish(string)\n"
508 "\n"
509 "Returns:\n"
510 " The compressed output data (bytes)\n"
511 "\n"
512 "Raises:\n"
513 " brotli.error: If compression fails\n");
514
brotli_Compressor_finish(brotli_Compressor * self)515 static PyObject* brotli_Compressor_finish(brotli_Compressor *self) {
516 PyObject *ret;
517
518 if (!self->enc) {
519 goto error;
520 }
521
522 ret = compress_stream(self->enc, BROTLI_OPERATION_FINISH,
523 NULL, 0);
524
525 if (ret == NULL || !BrotliEncoderIsFinished(self->enc)) {
526 goto error;
527 }
528 goto finally;
529
530 error:
531 PyErr_SetString(BrotliError,
532 "BrotliEncoderCompressStream failed while finishing the stream");
533 ret = NULL;
534 finally:
535 return ret;
536 }
537
538 static PyMemberDef brotli_Compressor_members[] = {
539 {NULL} /* Sentinel */
540 };
541
542 static PyMethodDef brotli_Compressor_methods[] = {
543 {"process", (PyCFunction)brotli_Compressor_process, METH_VARARGS, brotli_Compressor_process_doc},
544 {"flush", (PyCFunction)brotli_Compressor_flush, METH_NOARGS, brotli_Compressor_flush_doc},
545 {"finish", (PyCFunction)brotli_Compressor_finish, METH_NOARGS, brotli_Compressor_finish_doc},
546 {NULL} /* Sentinel */
547 };
548
549 static PyTypeObject brotli_CompressorType = {
550 #if PY_MAJOR_VERSION >= 3
551 PyVarObject_HEAD_INIT(NULL, 0)
552 #else
553 PyObject_HEAD_INIT(NULL)
554 0, /* ob_size*/
555 #endif
556 "brotli.Compressor", /* tp_name */
557 sizeof(brotli_Compressor), /* tp_basicsize */
558 0, /* tp_itemsize */
559 (destructor)brotli_Compressor_dealloc, /* tp_dealloc */
560 0, /* tp_print */
561 0, /* tp_getattr */
562 0, /* tp_setattr */
563 0, /* tp_compare */
564 0, /* tp_repr */
565 0, /* tp_as_number */
566 0, /* tp_as_sequence */
567 0, /* tp_as_mapping */
568 0, /* tp_hash */
569 0, /* tp_call */
570 0, /* tp_str */
571 0, /* tp_getattro */
572 0, /* tp_setattro */
573 0, /* tp_as_buffer */
574 Py_TPFLAGS_DEFAULT, /* tp_flags */
575 brotli_Compressor_doc, /* tp_doc */
576 0, /* tp_traverse */
577 0, /* tp_clear */
578 0, /* tp_richcompare */
579 0, /* tp_weaklistoffset */
580 0, /* tp_iter */
581 0, /* tp_iternext */
582 brotli_Compressor_methods, /* tp_methods */
583 brotli_Compressor_members, /* tp_members */
584 0, /* tp_getset */
585 0, /* tp_base */
586 0, /* tp_dict */
587 0, /* tp_descr_get */
588 0, /* tp_descr_set */
589 0, /* tp_dictoffset */
590 (initproc)brotli_Compressor_init, /* tp_init */
591 0, /* tp_alloc */
592 brotli_Compressor_new, /* tp_new */
593 };
594
decompress_stream(BrotliDecoderState * dec,uint8_t * input,size_t input_length)595 static PyObject* decompress_stream(BrotliDecoderState* dec,
596 uint8_t* input, size_t input_length) {
597 BrotliDecoderResult result;
598
599 size_t available_in = input_length;
600 const uint8_t* next_in = input;
601
602 size_t available_out;
603 uint8_t* next_out;
604 BlocksOutputBuffer buffer = {.list=NULL};
605 PyObject *ret;
606
607 if (BlocksOutputBuffer_InitAndGrow(&buffer, &available_out, &next_out) < 0) {
608 goto error;
609 }
610
611 while (1) {
612 Py_BEGIN_ALLOW_THREADS
613 result = BrotliDecoderDecompressStream(dec,
614 &available_in, &next_in,
615 &available_out, &next_out, NULL);
616 Py_END_ALLOW_THREADS
617
618 if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
619 if (available_out == 0) {
620 if (BlocksOutputBuffer_Grow(&buffer, &available_out, &next_out) < 0) {
621 goto error;
622 }
623 }
624 continue;
625 }
626
627 break;
628 }
629
630 if (result == BROTLI_DECODER_RESULT_ERROR || available_in != 0) {
631 goto error;
632 }
633
634 ret = BlocksOutputBuffer_Finish(&buffer, available_out);
635 if (ret != NULL) {
636 goto finally;
637 }
638
639 error:
640 BlocksOutputBuffer_OnError(&buffer);
641 ret = NULL;
642 finally:
643 return ret;
644 }
645
646 PyDoc_STRVAR(brotli_Decompressor_doc,
647 "An object to decompress a byte string.\n"
648 "\n"
649 "Signature:\n"
650 " Decompressor()\n"
651 "\n"
652 "Raises:\n"
653 " brotli.error: If arguments are invalid.\n");
654
655 typedef struct {
656 PyObject_HEAD
657 BrotliDecoderState* dec;
658 } brotli_Decompressor;
659
brotli_Decompressor_dealloc(brotli_Decompressor * self)660 static void brotli_Decompressor_dealloc(brotli_Decompressor* self) {
661 BrotliDecoderDestroyInstance(self->dec);
662 #if PY_MAJOR_VERSION >= 3
663 Py_TYPE(self)->tp_free((PyObject*)self);
664 #else
665 self->ob_type->tp_free((PyObject*)self);
666 #endif
667 }
668
brotli_Decompressor_new(PyTypeObject * type,PyObject * args,PyObject * keywds)669 static PyObject* brotli_Decompressor_new(PyTypeObject *type, PyObject *args, PyObject *keywds) {
670 brotli_Decompressor *self;
671 self = (brotli_Decompressor *)type->tp_alloc(type, 0);
672
673 if (self != NULL) {
674 self->dec = BrotliDecoderCreateInstance(0, 0, 0);
675 }
676
677 return (PyObject *)self;
678 }
679
brotli_Decompressor_init(brotli_Decompressor * self,PyObject * args,PyObject * keywds)680 static int brotli_Decompressor_init(brotli_Decompressor *self, PyObject *args, PyObject *keywds) {
681 int ok;
682
683 static const char *kwlist[] = {NULL};
684
685 ok = PyArg_ParseTupleAndKeywords(args, keywds, "|:Decompressor",
686 (char **) kwlist);
687 if (!ok)
688 return -1;
689 if (!self->dec)
690 return -1;
691
692 return 0;
693 }
694
695 PyDoc_STRVAR(brotli_Decompressor_process_doc,
696 "Process \"string\" for decompression, returning a string that contains \n"
697 "decompressed output data. This data should be concatenated to the output \n"
698 "produced by any preceding calls to the \"process()\" method. \n"
699 "Some or all of the input may be kept in internal buffers for later \n"
700 "processing, and the decompressed output data may be empty until enough input \n"
701 "has been accumulated.\n"
702 "\n"
703 "Signature:\n"
704 " decompress(string)\n"
705 "\n"
706 "Args:\n"
707 " string (bytes): The input data\n"
708 "\n"
709 "Returns:\n"
710 " The decompressed output data (bytes)\n"
711 "\n"
712 "Raises:\n"
713 " brotli.error: If decompression fails\n");
714
brotli_Decompressor_process(brotli_Decompressor * self,PyObject * args)715 static PyObject* brotli_Decompressor_process(brotli_Decompressor *self, PyObject *args) {
716 PyObject* ret;
717 Py_buffer input;
718 int ok;
719
720 #if PY_MAJOR_VERSION >= 3
721 ok = PyArg_ParseTuple(args, "y*:process", &input);
722 #else
723 ok = PyArg_ParseTuple(args, "s*:process", &input);
724 #endif
725
726 if (!ok) {
727 return NULL;
728 }
729
730 if (!self->dec) {
731 goto error;
732 }
733
734 ret = decompress_stream(self->dec, (uint8_t*) input.buf, input.len);
735 if (ret != NULL) {
736 goto finally;
737 }
738
739 error:
740 PyErr_SetString(BrotliError,
741 "BrotliDecoderDecompressStream failed while processing the stream");
742 ret = NULL;
743
744 finally:
745 PyBuffer_Release(&input);
746 return ret;
747 }
748
749 PyDoc_STRVAR(brotli_Decompressor_is_finished_doc,
750 "Checks if decoder instance reached the final state.\n"
751 "\n"
752 "Signature:\n"
753 " is_finished()\n"
754 "\n"
755 "Returns:\n"
756 " True if the decoder is in a state where it reached the end of the input\n"
757 " and produced all of the output\n"
758 " False otherwise\n"
759 "\n"
760 "Raises:\n"
761 " brotli.error: If decompression fails\n");
762
brotli_Decompressor_is_finished(brotli_Decompressor * self)763 static PyObject* brotli_Decompressor_is_finished(brotli_Decompressor *self) {
764 if (!self->dec) {
765 PyErr_SetString(BrotliError, "BrotliDecoderState is NULL while checking is_finished");
766 return NULL;
767 }
768
769 if (BrotliDecoderIsFinished(self->dec)) {
770 Py_RETURN_TRUE;
771 } else {
772 Py_RETURN_FALSE;
773 }
774 }
775
776 static PyMemberDef brotli_Decompressor_members[] = {
777 {NULL} /* Sentinel */
778 };
779
780 static PyMethodDef brotli_Decompressor_methods[] = {
781 {"process", (PyCFunction)brotli_Decompressor_process, METH_VARARGS, brotli_Decompressor_process_doc},
782 {"is_finished", (PyCFunction)brotli_Decompressor_is_finished, METH_NOARGS, brotli_Decompressor_is_finished_doc},
783 {NULL} /* Sentinel */
784 };
785
786 static PyTypeObject brotli_DecompressorType = {
787 #if PY_MAJOR_VERSION >= 3
788 PyVarObject_HEAD_INIT(NULL, 0)
789 #else
790 PyObject_HEAD_INIT(NULL)
791 0, /* ob_size*/
792 #endif
793 "brotli.Decompressor", /* tp_name */
794 sizeof(brotli_Decompressor), /* tp_basicsize */
795 0, /* tp_itemsize */
796 (destructor)brotli_Decompressor_dealloc, /* tp_dealloc */
797 0, /* tp_print */
798 0, /* tp_getattr */
799 0, /* tp_setattr */
800 0, /* tp_compare */
801 0, /* tp_repr */
802 0, /* tp_as_number */
803 0, /* tp_as_sequence */
804 0, /* tp_as_mapping */
805 0, /* tp_hash */
806 0, /* tp_call */
807 0, /* tp_str */
808 0, /* tp_getattro */
809 0, /* tp_setattro */
810 0, /* tp_as_buffer */
811 Py_TPFLAGS_DEFAULT, /* tp_flags */
812 brotli_Decompressor_doc, /* tp_doc */
813 0, /* tp_traverse */
814 0, /* tp_clear */
815 0, /* tp_richcompare */
816 0, /* tp_weaklistoffset */
817 0, /* tp_iter */
818 0, /* tp_iternext */
819 brotli_Decompressor_methods, /* tp_methods */
820 brotli_Decompressor_members, /* tp_members */
821 0, /* tp_getset */
822 0, /* tp_base */
823 0, /* tp_dict */
824 0, /* tp_descr_get */
825 0, /* tp_descr_set */
826 0, /* tp_dictoffset */
827 (initproc)brotli_Decompressor_init, /* tp_init */
828 0, /* tp_alloc */
829 brotli_Decompressor_new, /* tp_new */
830 };
831
832 PyDoc_STRVAR(brotli_decompress__doc__,
833 "Decompress a compressed byte string.\n"
834 "\n"
835 "Signature:\n"
836 " decompress(string)\n"
837 "\n"
838 "Args:\n"
839 " string (bytes): The compressed input data.\n"
840 "\n"
841 "Returns:\n"
842 " The decompressed byte string.\n"
843 "\n"
844 "Raises:\n"
845 " brotli.error: If decompressor fails.\n");
846
brotli_decompress(PyObject * self,PyObject * args,PyObject * keywds)847 static PyObject* brotli_decompress(PyObject *self, PyObject *args, PyObject *keywds) {
848 BrotliDecoderState* state;
849 BrotliDecoderResult result;
850
851 const uint8_t* next_in;
852 size_t available_in;
853
854 uint8_t* next_out;
855 size_t available_out;
856 BlocksOutputBuffer buffer = {.list=NULL};
857 PyObject *ret;
858
859 static const char *kwlist[] = {"string", NULL};
860 Py_buffer input;
861 int ok;
862
863 #if PY_MAJOR_VERSION >= 3
864 ok = PyArg_ParseTupleAndKeywords(args, keywds, "y*|:decompress",
865 (char**) kwlist, &input);
866 #else
867 ok = PyArg_ParseTupleAndKeywords(args, keywds, "s*|:decompress",
868 (char**) kwlist, &input);
869 #endif
870
871 if (!ok) {
872 return NULL;
873 }
874
875 state = BrotliDecoderCreateInstance(0, 0, 0);
876
877 next_in = (uint8_t*) input.buf;
878 available_in = input.len;
879
880 if (BlocksOutputBuffer_InitAndGrow(&buffer, &available_out, &next_out) < 0) {
881 goto error;
882 }
883
884 while (1) {
885 Py_BEGIN_ALLOW_THREADS
886 result = BrotliDecoderDecompressStream(state, &available_in, &next_in,
887 &available_out, &next_out, 0);
888 Py_END_ALLOW_THREADS
889
890 if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
891 if (available_out == 0) {
892 if (BlocksOutputBuffer_Grow(&buffer, &available_out, &next_out) < 0) {
893 goto error;
894 }
895 }
896 continue;
897 }
898
899 break;
900 }
901
902 if (result != BROTLI_DECODER_RESULT_SUCCESS || available_in != 0) {
903 goto error;
904 }
905
906 ret = BlocksOutputBuffer_Finish(&buffer, available_out);
907 if (ret != NULL) {
908 goto finally;
909 }
910
911 error:
912 BlocksOutputBuffer_OnError(&buffer);
913 PyErr_SetString(BrotliError, "BrotliDecompress failed");
914 ret = NULL;
915
916 finally:
917 BrotliDecoderDestroyInstance(state);
918 PyBuffer_Release(&input);
919 return ret;
920 }
921
922 static PyMethodDef brotli_methods[] = {
923 {"decompress", (PyCFunction)brotli_decompress, METH_VARARGS | METH_KEYWORDS, brotli_decompress__doc__},
924 {NULL, NULL, 0, NULL}
925 };
926
927 PyDoc_STRVAR(brotli_doc, "Implementation module for the Brotli library.");
928
929 #if PY_MAJOR_VERSION >= 3
930 #define INIT_BROTLI PyInit__brotli
931 #define CREATE_BROTLI PyModule_Create(&brotli_module)
932 #define RETURN_BROTLI return m
933 #define RETURN_NULL return NULL
934
935 static struct PyModuleDef brotli_module = {
936 PyModuleDef_HEAD_INIT,
937 "_brotli", /* m_name */
938 brotli_doc, /* m_doc */
939 0, /* m_size */
940 brotli_methods, /* m_methods */
941 NULL, /* m_reload */
942 NULL, /* m_traverse */
943 NULL, /* m_clear */
944 NULL /* m_free */
945 };
946 #else
947 #define INIT_BROTLI init_brotli
948 #define CREATE_BROTLI Py_InitModule3("_brotli", brotli_methods, brotli_doc)
949 #define RETURN_BROTLI return
950 #define RETURN_NULL return
951 #endif
952
INIT_BROTLI(void)953 PyMODINIT_FUNC INIT_BROTLI(void) {
954 PyObject *m = CREATE_BROTLI;
955
956 BrotliError = PyErr_NewException((char*) "brotli.error", NULL, NULL);
957 if (BrotliError != NULL) {
958 Py_INCREF(BrotliError);
959 PyModule_AddObject(m, "error", BrotliError);
960 }
961
962 if (PyType_Ready(&brotli_CompressorType) < 0) {
963 RETURN_NULL;
964 }
965 Py_INCREF(&brotli_CompressorType);
966 PyModule_AddObject(m, "Compressor", (PyObject *)&brotli_CompressorType);
967
968 if (PyType_Ready(&brotli_DecompressorType) < 0) {
969 RETURN_NULL;
970 }
971 Py_INCREF(&brotli_DecompressorType);
972 PyModule_AddObject(m, "Decompressor", (PyObject *)&brotli_DecompressorType);
973
974 PyModule_AddIntConstant(m, "MODE_GENERIC", (int) BROTLI_MODE_GENERIC);
975 PyModule_AddIntConstant(m, "MODE_TEXT", (int) BROTLI_MODE_TEXT);
976 PyModule_AddIntConstant(m, "MODE_FONT", (int) BROTLI_MODE_FONT);
977
978 char version[16];
979 uint32_t decoderVersion = BrotliDecoderVersion();
980 snprintf(version, sizeof(version), "%d.%d.%d",
981 decoderVersion >> 24, (decoderVersion >> 12) & 0xFFF, decoderVersion & 0xFFF);
982 PyModule_AddStringConstant(m, "__version__", version);
983
984 RETURN_BROTLI;
985 }
986