comparison mupdf-source/thirdparty/brotli/python/_brotli.c @ 2:b50eed0cc0ef upstream

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