2014-11-20 12:16:26 +00:00
|
|
|
#define PY_SSIZE_T_CLEAN 1
|
|
|
|
#include <Python.h>
|
|
|
|
#include <bytesobject.h>
|
2015-02-24 16:10:09 +00:00
|
|
|
#include "../enc/encode.h"
|
|
|
|
#include "../dec/decode.h"
|
2014-11-20 12:16:26 +00:00
|
|
|
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
|
|
#define PyInt_Check PyLong_Check
|
|
|
|
#define PyInt_AsLong PyLong_AsLong
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace brotli;
|
|
|
|
|
|
|
|
static PyObject *BrotliError;
|
|
|
|
|
|
|
|
static int mode_convertor(PyObject *o, BrotliParams::Mode *mode) {
|
|
|
|
if (!PyInt_Check(o)) {
|
|
|
|
PyErr_SetString(BrotliError, "Invalid mode");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*mode = (BrotliParams::Mode) PyInt_AsLong(o);
|
|
|
|
if (*mode != BrotliParams::Mode::MODE_TEXT &&
|
|
|
|
*mode != BrotliParams::Mode::MODE_FONT) {
|
|
|
|
PyErr_SetString(BrotliError, "Invalid mode");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyDoc_STRVAR(compress__doc__,
|
2015-05-08 10:23:08 +00:00
|
|
|
"compress(data[, mode=MODE_TEXT, enable_transforms=False])\n"
|
2014-11-20 12:16:26 +00:00
|
|
|
"\n"
|
2015-05-08 10:23:08 +00:00
|
|
|
"Args:\n"
|
|
|
|
" data (bytes): The input data.\n"
|
|
|
|
" mode (int, optional): The compression mode can be MODE_TEXT (default) or\n"
|
|
|
|
" MODE_FONT.\n"
|
2015-05-08 10:34:20 +00:00
|
|
|
" enable_dictionary (bool, optional): Controls whether to enable encoder\n"
|
|
|
|
" dictionary. Defaults to True. Respected only if quality > 9.\n"
|
2015-05-08 10:23:08 +00:00
|
|
|
" enable_transforms (bool, optional): Controls whether to enable encoder\n"
|
2015-05-08 10:34:20 +00:00
|
|
|
" transforms. Defaults to False. Respected only if quality > 9.\n"
|
2015-05-08 10:47:00 +00:00
|
|
|
" greedy_block_split (bool, optional): Controls whether to enable a faster\n"
|
|
|
|
" but less dense compression mode. Defaults to False. Respected only if\n"
|
|
|
|
" quality > 9.\n"
|
2015-05-08 10:23:08 +00:00
|
|
|
"\n"
|
|
|
|
"Returns:\n"
|
|
|
|
" The compressed string of bytes.\n"
|
|
|
|
"\n"
|
|
|
|
"Raises:\n"
|
|
|
|
" brotli.error: If mode is invalid, or compressor fails.\n");
|
2014-11-20 12:16:26 +00:00
|
|
|
|
2015-05-08 10:23:08 +00:00
|
|
|
static PyObject* brotli_compress(PyObject *self, PyObject *args, PyObject *keywds) {
|
2014-11-20 12:16:26 +00:00
|
|
|
PyObject *ret = NULL;
|
2015-05-08 10:47:00 +00:00
|
|
|
PyObject* enable_dictionary = NULL;
|
|
|
|
PyObject* enable_transforms = NULL;
|
|
|
|
PyObject* greedy_block_split = NULL;
|
2014-11-20 12:16:26 +00:00
|
|
|
uint8_t *input, *output;
|
|
|
|
size_t length, output_length;
|
|
|
|
BrotliParams::Mode mode = (BrotliParams::Mode) -1;
|
|
|
|
int ok;
|
|
|
|
|
2015-05-08 10:47:00 +00:00
|
|
|
static char *kwlist[] = {"data", "mode", "enable_dictionary", "enable_transforms",
|
|
|
|
"greedy_block_split", NULL};
|
2015-05-08 10:23:08 +00:00
|
|
|
|
2015-05-08 10:47:00 +00:00
|
|
|
ok = PyArg_ParseTupleAndKeywords(args, keywds, "s#|O&O!O!O!:compress", kwlist,
|
2014-11-20 12:16:26 +00:00
|
|
|
&input, &length,
|
|
|
|
&mode_convertor, &mode,
|
2015-05-08 10:47:00 +00:00
|
|
|
&PyBool_Type, &enable_dictionary,
|
|
|
|
&PyBool_Type, &enable_transforms,
|
|
|
|
&PyBool_Type, &greedy_block_split);
|
2014-11-20 12:16:26 +00:00
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
output_length = 1.2 * length + 10240;
|
|
|
|
output = new uint8_t[output_length];
|
|
|
|
|
|
|
|
BrotliParams params;
|
|
|
|
if (mode != -1)
|
|
|
|
params.mode = mode;
|
2015-05-08 10:47:00 +00:00
|
|
|
if (enable_dictionary)
|
|
|
|
params.enable_dictionary = PyObject_IsTrue(enable_dictionary);
|
|
|
|
if (enable_transforms)
|
|
|
|
params.enable_transforms = PyObject_IsTrue(enable_transforms);
|
|
|
|
if (greedy_block_split)
|
|
|
|
params.greedy_block_split = PyObject_IsTrue(greedy_block_split);
|
2014-11-20 12:16:26 +00:00
|
|
|
|
|
|
|
ok = BrotliCompressBuffer(params, length, input,
|
|
|
|
&output_length, output);
|
|
|
|
if (ok) {
|
|
|
|
ret = PyBytes_FromStringAndSize((char*)output, output_length);
|
|
|
|
} else {
|
|
|
|
PyErr_SetString(BrotliError, "BrotliCompressBuffer failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] output;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-03-13 21:55:03 +00:00
|
|
|
int output_callback(void* data, const uint8_t* buf, size_t count) {
|
|
|
|
std::vector<uint8_t> *output = (std::vector<uint8_t> *)data;
|
|
|
|
output->insert(output->end(), buf, buf + count);
|
|
|
|
return (int)count;
|
|
|
|
}
|
|
|
|
|
2014-11-20 12:16:26 +00:00
|
|
|
PyDoc_STRVAR(decompress__doc__,
|
2015-03-13 21:55:03 +00:00
|
|
|
"decompress(string) -- Return decompressed string.");
|
2014-11-20 12:16:26 +00:00
|
|
|
|
|
|
|
static PyObject* brotli_decompress(PyObject *self, PyObject *args) {
|
|
|
|
PyObject *ret = NULL;
|
2015-03-13 21:55:03 +00:00
|
|
|
uint8_t *input;
|
|
|
|
size_t length;
|
2014-11-20 12:16:26 +00:00
|
|
|
int ok;
|
|
|
|
|
2015-03-13 21:55:03 +00:00
|
|
|
ok = PyArg_ParseTuple(args, "s#:decompress", &input, &length);
|
2014-11-20 12:16:26 +00:00
|
|
|
if (!ok)
|
|
|
|
return NULL;
|
|
|
|
|
2015-03-13 21:55:03 +00:00
|
|
|
BrotliMemInput memin;
|
|
|
|
BrotliInput in = BrotliInitMemInput(input, length, &memin);
|
2014-11-20 12:16:26 +00:00
|
|
|
|
2015-03-13 21:55:03 +00:00
|
|
|
BrotliOutput out;
|
|
|
|
std::vector<uint8_t> output;
|
|
|
|
out.cb_ = &output_callback;
|
|
|
|
out.data_ = &output;
|
2014-11-20 12:16:26 +00:00
|
|
|
|
2015-03-13 21:55:03 +00:00
|
|
|
ok = BrotliDecompress(in, out);
|
2014-11-20 12:16:26 +00:00
|
|
|
if (ok) {
|
2015-03-13 21:55:03 +00:00
|
|
|
ret = PyBytes_FromStringAndSize((char*)output.data(), output.size());
|
2014-11-20 12:16:26 +00:00
|
|
|
} else {
|
2015-03-13 21:55:03 +00:00
|
|
|
PyErr_SetString(BrotliError, "BrotliDecompress failed");
|
2014-11-20 12:16:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyMethodDef brotli_methods[] = {
|
2015-05-08 10:23:08 +00:00
|
|
|
{"compress", (PyCFunction)brotli_compress, METH_VARARGS | METH_KEYWORDS, compress__doc__},
|
2014-11-20 12:16:26 +00:00
|
|
|
{"decompress", brotli_decompress, METH_VARARGS, decompress__doc__},
|
|
|
|
{NULL, NULL, 0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
PyDoc_STRVAR(brotli__doc__,
|
|
|
|
"The functions in this module allow compression and decompression using the\n"
|
|
|
|
"Brotli library.\n"
|
|
|
|
"\n"
|
|
|
|
"compress(string[, mode, transform]) -- Compress string.\n"
|
|
|
|
"decompress(string) -- Decompresses a compressed string.\n");
|
|
|
|
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
|
|
#define INIT_BROTLI PyInit_brotli
|
|
|
|
#define CREATE_BROTLI PyModule_Create(&brotli_module)
|
|
|
|
#define RETURN_BROTLI return m
|
|
|
|
|
|
|
|
static struct PyModuleDef brotli_module = {
|
|
|
|
PyModuleDef_HEAD_INIT,
|
|
|
|
"brotli",
|
|
|
|
brotli__doc__,
|
|
|
|
0,
|
|
|
|
brotli_methods,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
#else
|
|
|
|
#define INIT_BROTLI initbrotli
|
|
|
|
#define CREATE_BROTLI Py_InitModule3("brotli", brotli_methods, brotli__doc__)
|
|
|
|
#define RETURN_BROTLI return
|
|
|
|
#endif
|
|
|
|
|
|
|
|
PyMODINIT_FUNC INIT_BROTLI(void) {
|
|
|
|
PyObject *m = CREATE_BROTLI;
|
|
|
|
|
|
|
|
BrotliError = PyErr_NewException((char*) "brotli.error", NULL, NULL);
|
|
|
|
|
|
|
|
if (BrotliError != NULL) {
|
|
|
|
Py_INCREF(BrotliError);
|
|
|
|
PyModule_AddObject(m, "error", BrotliError);
|
|
|
|
}
|
|
|
|
|
|
|
|
PyModule_AddIntConstant(m, "MODE_TEXT", (int) BrotliParams::Mode::MODE_TEXT);
|
|
|
|
PyModule_AddIntConstant(m, "MODE_FONT", (int) BrotliParams::Mode::MODE_FONT);
|
|
|
|
|
|
|
|
RETURN_BROTLI;
|
|
|
|
}
|