00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "Python.h"
00036
00037 #include "roslz4/lz4s.h"
00038
00039 struct module_state {
00040 PyObject *error;
00041 };
00042
00043 #if PY_MAJOR_VERSION >= 3
00044 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
00045 #else
00046 #define GETSTATE(m) (&_state)
00047 static struct module_state _state;
00048 #endif
00049
00050
00051 static int
00052 grow_buffer(PyObject **buf)
00053 {
00054
00055
00056
00057 size_t size = PyBytes_GET_SIZE(*buf);
00058 size_t new_size = size + (size >> 3) + 6;
00059 if (new_size > size) {
00060 return _PyBytes_Resize(buf, new_size);
00061 } else {
00062 PyErr_SetString(PyExc_OverflowError,
00063 "Unable to allocate buffer - output too large");
00064 return -1;
00065 }
00066 }
00067
00068
00069
00070 typedef struct {
00071 PyObject_HEAD
00072 roslz4_stream stream;
00073 } LZ4Compressor;
00074
00075 static void
00076 LZ4Compressor_dealloc(LZ4Compressor *self)
00077 {
00078 roslz4_compressEnd(&self->stream);
00079 Py_TYPE(self)->tp_free((PyObject*)self);
00080 }
00081
00082 static int
00083 LZ4Compressor_init(LZ4Compressor *self, PyObject *args, PyObject *kwds)
00084 {
00085 (void)kwds;
00086 if (!PyArg_ParseTuple(args, ":__init__")) {
00087 return -1;
00088 }
00089
00090 int ret = roslz4_compressStart(&self->stream, 6);
00091 if (ret != ROSLZ4_OK) {
00092 PyErr_SetString(PyExc_RuntimeError, "error initializing roslz4 stream");
00093 return -1;
00094 }
00095 return 0;
00096 }
00097
00098 static PyObject *
00099 compress_impl(LZ4Compressor *self, Py_buffer *input, PyObject *output)
00100 {
00101
00102 int initial_size = roslz4_blockSizeFromIndex(self->stream.block_size_id) + 64;
00103 output = PyBytes_FromStringAndSize(NULL, initial_size);
00104 if (!output) {
00105 if (input != NULL) { PyBuffer_Release(input); }
00106 return NULL;
00107 }
00108
00109
00110 int action;
00111 if (input != NULL) {
00112 action = ROSLZ4_RUN;
00113 self->stream.input_next = input->buf;
00114 self->stream.input_left = input->len;
00115 } else {
00116 action = ROSLZ4_FINISH;
00117 self->stream.input_next = NULL;
00118 self->stream.input_left = 0;
00119 }
00120 self->stream.output_next = PyBytes_AS_STRING(output);
00121 self->stream.output_left = PyBytes_GET_SIZE(output);
00122
00123
00124 int status;
00125 int output_written = 0;
00126 while ((action == ROSLZ4_FINISH) ||
00127 (action == ROSLZ4_RUN && self->stream.input_left > 0)) {
00128 int out_start = self->stream.total_out;
00129 status = roslz4_compress(&self->stream, action);
00130 output_written += self->stream.total_out - out_start;
00131 if (status == ROSLZ4_OK) {
00132 continue;
00133 } else if (status == ROSLZ4_STREAM_END) {
00134 break;
00135 } else if (status == ROSLZ4_OUTPUT_SMALL) {
00136 if (grow_buffer(&output) < 0) {
00137 goto error;
00138 }
00139 self->stream.output_next = PyBytes_AS_STRING(output) + output_written;
00140 self->stream.output_left = PyBytes_GET_SIZE(output) - output_written;
00141 } else if (status == ROSLZ4_PARAM_ERROR) {
00142 PyErr_SetString(PyExc_IOError, "bad block size parameter");
00143 goto error;
00144 } else if (status == ROSLZ4_ERROR) {
00145 PyErr_SetString(PyExc_IOError, "error compressing");
00146 goto error;
00147 } else {
00148 PyErr_Format(PyExc_RuntimeError, "unhandled return code %i", status);
00149 goto error;
00150 }
00151 }
00152
00153
00154 if (output_written != PyBytes_GET_SIZE(output)) {
00155 _PyBytes_Resize(&output, output_written);
00156 }
00157
00158 if (input != NULL) { PyBuffer_Release(input); }
00159 return output;
00160
00161 error:
00162 if (input != NULL) { PyBuffer_Release(input); }
00163 Py_XDECREF(output);
00164 return NULL;
00165 }
00166
00167 static PyObject *
00168 LZ4Compressor_compress(LZ4Compressor *self, PyObject *args)
00169 {
00170 Py_buffer input;
00171 PyObject *output = NULL;
00172
00173
00174 if (!PyArg_ParseTuple(args, "s*:compress", &input)) {
00175 return NULL;
00176 }
00177
00178 return compress_impl(self, &input, output);
00179 }
00180
00181 static PyObject *
00182 LZ4Compressor_flush(LZ4Compressor *self, PyObject *args)
00183 {
00184 PyObject *output = NULL;
00185
00186 if (!PyArg_ParseTuple(args, ":flush")) {
00187 return NULL;
00188 }
00189
00190 return compress_impl(self, NULL, output);
00191 }
00192
00193
00194 static PyMethodDef LZ4Compressor_methods[] = {
00195 {"compress", (PyCFunction)LZ4Compressor_compress, METH_VARARGS, "method doc"},
00196 {"flush", (PyCFunction)LZ4Compressor_flush, METH_VARARGS, "method doc"},
00197 {NULL}
00198 };
00199
00200 static PyTypeObject LZ4Compressor_Type = {
00201 PyVarObject_HEAD_INIT(NULL, 0)
00202 "_roslz4.LZ4Compressor",
00203 sizeof(LZ4Compressor),
00204 0,
00205 (destructor)LZ4Compressor_dealloc,
00206 0,
00207 0,
00208 0,
00209 0,
00210 0,
00211 0,
00212 0,
00213 0,
00214 0,
00215 0,
00216 0,
00217 0,
00218 0,
00219 0,
00220 Py_TPFLAGS_DEFAULT,
00221 "LZ4Compressor objects",
00222 0,
00223 0,
00224 0,
00225 0,
00226 0,
00227 0,
00228 LZ4Compressor_methods,
00229 0,
00230 0,
00231 0,
00232 0,
00233 0,
00234 0,
00235 0,
00236 (initproc)LZ4Compressor_init
00237 };
00238
00239
00240
00241 typedef struct {
00242 PyObject_HEAD
00243 roslz4_stream stream;
00244 } LZ4Decompressor;
00245
00246 static void
00247 LZ4Decompressor_dealloc(LZ4Decompressor *self)
00248 {
00249 roslz4_decompressEnd(&self->stream);
00250 Py_TYPE(self)->tp_free((PyObject*)self);
00251 }
00252
00253 static int
00254 LZ4Decompressor_init(LZ4Decompressor *self, PyObject *args, PyObject *kwds)
00255 {
00256 (void)kwds;
00257 if (!PyArg_ParseTuple(args, ":__init__")) {
00258 return -1;
00259 }
00260
00261 int ret = roslz4_decompressStart(&self->stream);
00262 if (ret != ROSLZ4_OK) {
00263 PyErr_SetString(PyExc_RuntimeError, "error initializing roslz4 stream");
00264 return -1;
00265 }
00266 return 0;
00267 }
00268
00269 static PyObject *
00270 LZ4Decompressor_decompress(LZ4Decompressor *self, PyObject *args)
00271 {
00272 Py_buffer input;
00273 PyObject *output = NULL;
00274
00275
00276 if (!PyArg_ParseTuple(args, "s*:decompress", &input)) {
00277 return NULL;
00278 }
00279
00280
00281 int block_size;
00282 if (self->stream.block_size_id == -1 ) {
00283 block_size = roslz4_blockSizeFromIndex(6);
00284 } else {
00285 block_size = roslz4_blockSizeFromIndex(self->stream.block_size_id);
00286 }
00287
00288 output = PyBytes_FromStringAndSize(NULL, block_size);
00289 if (!output) {
00290 PyBuffer_Release(&input);
00291 return NULL;
00292 }
00293
00294
00295 self->stream.input_next = input.buf;
00296 self->stream.input_left = input.len;
00297 self->stream.output_next = PyBytes_AS_STRING(output);
00298 self->stream.output_left = PyBytes_GET_SIZE(output);
00299
00300 int output_written = 0;
00301 while (self->stream.input_left > 0) {
00302 int out_start = self->stream.total_out;
00303 int status = roslz4_decompress(&self->stream);
00304 output_written += self->stream.total_out - out_start;
00305 if (status == ROSLZ4_OK) {
00306 continue;
00307 } else if (status == ROSLZ4_STREAM_END) {
00308 break;
00309 } else if (status == ROSLZ4_OUTPUT_SMALL) {
00310 if (grow_buffer(&output) < 0) {
00311 goto error;
00312 }
00313 self->stream.output_next = PyBytes_AS_STRING(output) + output_written;
00314 self->stream.output_left = PyBytes_GET_SIZE(output) - output_written;
00315 } else if (status == ROSLZ4_ERROR) {
00316 PyErr_SetString(PyExc_IOError, "error decompressing");
00317 goto error;
00318 } else if (status == ROSLZ4_DATA_ERROR) {
00319 PyErr_SetString(PyExc_IOError, "malformed data to decompress");
00320 goto error;
00321 } else {
00322 PyErr_Format(PyExc_RuntimeError, "unhandled return code %i", status);
00323 goto error;
00324 }
00325 }
00326
00327 if (output_written != PyBytes_GET_SIZE(output)) {
00328 _PyBytes_Resize(&output, output_written);
00329 }
00330
00331 PyBuffer_Release(&input);
00332 return output;
00333
00334 error:
00335 PyBuffer_Release(&input);
00336 Py_XDECREF(output);
00337 return NULL;
00338 }
00339
00340 static PyMethodDef LZ4Decompressor_methods[] = {
00341 {"decompress", (PyCFunction)LZ4Decompressor_decompress, METH_VARARGS, "method doc"},
00342 {NULL}
00343 };
00344
00345 static PyTypeObject LZ4Decompressor_Type = {
00346 PyVarObject_HEAD_INIT(NULL, 0)
00347 "_roslz4.LZ4Decompressor",
00348 sizeof(LZ4Decompressor),
00349 0,
00350 (destructor)LZ4Decompressor_dealloc,
00351 0,
00352 0,
00353 0,
00354 0,
00355 0,
00356 0,
00357 0,
00358 0,
00359 0,
00360 0,
00361 0,
00362 0,
00363 0,
00364 0,
00365 Py_TPFLAGS_DEFAULT,
00366 "LZ4Decompressor objects",
00367 0,
00368 0,
00369 0,
00370 0,
00371 0,
00372 0,
00373 LZ4Decompressor_methods,
00374 0,
00375 0,
00376 0,
00377 0,
00378 0,
00379 0,
00380 0,
00381 (initproc)LZ4Decompressor_init
00382 };
00383
00384
00385
00386
00387 #if PY_MAJOR_VERSION >= 3
00388
00389 static int roslz4_traverse(PyObject *m, visitproc visit, void *arg) {
00390 Py_VISIT(GETSTATE(m)->error);
00391 return 0;
00392 }
00393
00394 static int roslz4_clear(PyObject *m) {
00395 Py_CLEAR(GETSTATE(m)->error);
00396 return 0;
00397 }
00398
00399 static struct PyModuleDef moduledef = {
00400 PyModuleDef_HEAD_INIT,
00401 "_roslz4",
00402 NULL,
00403 sizeof(struct module_state),
00404 NULL,
00405 NULL,
00406 roslz4_traverse,
00407 roslz4_clear,
00408 NULL
00409 };
00410 #define INITERROR return NULL
00411
00412 PyObject *
00413 PyInit__roslz4(void)
00414
00415 #else
00416 #define INITERROR return
00417
00418 void
00419 init_roslz4(void)
00420 #endif
00421 {
00422 PyObject *m;
00423
00424 LZ4Compressor_Type.tp_new = PyType_GenericNew;
00425 if (PyType_Ready(&LZ4Compressor_Type) < 0) {
00426 INITERROR;
00427 }
00428
00429 LZ4Decompressor_Type.tp_new = PyType_GenericNew;
00430 if (PyType_Ready(&LZ4Decompressor_Type) < 0) {
00431 INITERROR;
00432 }
00433
00434 #if PY_MAJOR_VERSION >= 3
00435 m = PyModule_Create(&moduledef);
00436 #else
00437 m = Py_InitModule("_roslz4", NULL);
00438 #endif
00439
00440 if (m == NULL) {
00441 INITERROR;
00442 }
00443
00444 Py_INCREF(&LZ4Compressor_Type);
00445 PyModule_AddObject(m, "LZ4Compressor", (PyObject *)&LZ4Compressor_Type);
00446 Py_INCREF(&LZ4Decompressor_Type);
00447 PyModule_AddObject(m, "LZ4Decompressor", (PyObject *)&LZ4Decompressor_Type);
00448
00449 #if PY_MAJOR_VERSION >= 3
00450 return m;
00451 #endif
00452 }