| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- /*
- Copyright (c) 2011, Andres Moreira <andres@andresmoreira.com>
- 2011, Felipe Cruz <felipecruz@loogica.net>
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the authors nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL ANDRES MOREIRA BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "Python.h"
- #include <string.h>
- #include <stdio.h>
- #include <snappy-c.h>
- #include "crc32c.h"
- #define MODULE_VERSION "0.4.1"
- #define RESIZE_TOLERATION 0.75
- struct module_state {
- PyObject *error;
- };
- #if PY_MAJOR_VERSION >= 3
- #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
- #else
- #define GETSTATE(m) (&_state)
- static struct module_state _state;
- #endif
- /* if support for Python 2.5 is dropped the bytesobject.h will do this for us */
- #if PY_MAJOR_VERSION < 3
- #define PyBytes_FromStringAndSize PyString_FromStringAndSize
- #define _PyBytes_Resize _PyString_Resize
- #define PyBytes_AS_STRING PyString_AS_STRING
- #endif
- static PyObject *SnappyCompressError,
- *SnappyUncompressError,
- *SnappyInvalidCompressedInputError,
- *SnappyCompressedLengthError;
- static inline PyObject *
- maybe_resize(PyObject *str, size_t expected_size, size_t actual_size)
- {
- // Tolerate up to 25% slop, to reduce the likelihood of
- // reallocation and copying.
- if (actual_size != expected_size) {
- if (actual_size < expected_size * RESIZE_TOLERATION) {
- _PyBytes_Resize(&str, actual_size);
- return str;
- }
- Py_SIZE(str) = actual_size;
- }
- return str;
- }
- static const char *
- snappy_strerror(snappy_status status)
- {
- switch (status) {
- case SNAPPY_OK:
- return "no error";
- case SNAPPY_INVALID_INPUT:
- return "invalid input";
- case SNAPPY_BUFFER_TOO_SMALL:
- return "buffer too small";
- default:
- return "unknown error";
- }
- }
- static PyObject *
- snappy__compress(PyObject *self, PyObject *args)
- {
- const char * input;
- int input_size;
- size_t compressed_size, actual_size;
- PyObject * result;
- snappy_status status;
- #if PY_MAJOR_VERSION >= 3
- if (!PyArg_ParseTuple(args, "y#", &input, &input_size))
- #else
- if (!PyArg_ParseTuple(args, "s#", &input, &input_size))
- #endif
- return NULL;
- // Ask for the max size of the compressed object.
- compressed_size = snappy_max_compressed_length(input_size);
- // Make snappy compression
- result = PyBytes_FromStringAndSize(NULL, compressed_size);
- if (result) {
- actual_size = compressed_size;
- status = snappy_compress(input, input_size, PyBytes_AS_STRING(result), &actual_size);
- if (status == SNAPPY_OK) {
- return maybe_resize(result, compressed_size, actual_size);
- }
- else {
- Py_DECREF(result);
- }
- PyErr_Format(SnappyCompressError,
- "Error while compressing: %s", snappy_strerror(status));
- }
- PyErr_Format(SnappyCompressError,
- "Error while compressing: unable to acquire output string");
- return NULL;
- }
- static PyObject *
- snappy__uncompress(PyObject *self, PyObject *args)
- {
- const char * compressed;
- int comp_size;
- size_t uncomp_size, actual_size;
- PyObject * result;
- snappy_status status;
- #if PY_MAJOR_VERSION >=3
- if (!PyArg_ParseTuple(args, "y#", &compressed, &comp_size))
- #else
- if (!PyArg_ParseTuple(args, "s#", &compressed, &comp_size))
- #endif
- return NULL;
- status = snappy_uncompressed_length(compressed, comp_size, &uncomp_size);
- if (status != SNAPPY_OK) {
- PyErr_SetString(SnappyCompressedLengthError,
- "Can not calculate uncompressed length");
- return NULL;
- }
- result = PyBytes_FromStringAndSize(NULL, uncomp_size);
- if (result) {
- actual_size = uncomp_size;
- status = snappy_uncompress(compressed, comp_size, PyBytes_AS_STRING(result), &actual_size);
- if (SNAPPY_OK == status) {
- return maybe_resize(result, uncomp_size, actual_size);
- }
- else {
- Py_DECREF(result);
- }
- }
- PyErr_Format(SnappyUncompressError,
- "Error while decompressing: %s", snappy_strerror(status));
- return NULL;
- }
- static PyObject *
- snappy__is_valid_compressed_buffer(PyObject *self, PyObject *args)
- {
- const char * compressed;
- int comp_size;
- snappy_status status;
- if (!PyArg_ParseTuple(args, "s#", &compressed, &comp_size))
- return NULL;
- status = snappy_validate_compressed_buffer(compressed, comp_size);
- if (status == SNAPPY_OK)
- Py_RETURN_TRUE;
- Py_RETURN_FALSE;
- }
- static PyObject *
- snappy__crc32c(PyObject *self, PyObject *args)
- {
- const unsigned char * input;
- int input_size;
- #if PY_MAJOR_VERSION >= 3
- if (!PyArg_ParseTuple(args, "y#", &input, &input_size))
- #else
- if (!PyArg_ParseTuple(args, "s#", &input, &input_size))
- #endif
- return NULL;
- return PyLong_FromUnsignedLong(
- crc_finalize(crc_update(crc_init(), input, input_size)));
- }
- static PyMethodDef snappy_methods[] = {
- {"compress", snappy__compress, METH_VARARGS,
- "Compress a string using the snappy library."},
- {"uncompress", snappy__uncompress, METH_VARARGS,
- "Uncompress a string compressed with the snappy library."},
- {"decompress", snappy__uncompress, METH_VARARGS,
- "Alias to Uncompress method, to be compatible with zlib."},
- {"isValidCompressed", snappy__is_valid_compressed_buffer, METH_VARARGS,
- "Returns True if the compressed buffer is valid, False otherwise"},
- {"_crc32c", snappy__crc32c, METH_VARARGS,
- "Generate an RFC3720, section 12.1 CRC-32C"},
- {NULL, NULL, 0, NULL} /* Sentinel */
- };
- #if PY_MAJOR_VERSION >= 3
- static int snappy_traverse(PyObject *m, visitproc visit, void *arg) {
- Py_VISIT(GETSTATE(m)->error);
- return 0;
- }
- static int snappy_clear(PyObject *m) {
- Py_CLEAR(GETSTATE(m)->error);
- return 0;
- }
- static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- "_snappy",
- NULL,
- sizeof(struct module_state),
- snappy_methods,
- NULL,
- snappy_traverse,
- snappy_clear,
- NULL
- };
- #define INITERROR return NULL
- PyMODINIT_FUNC
- PyInit__snappy(void)
- #else
- #define INITERROR return
- PyMODINIT_FUNC
- init_snappy(void)
- #endif
- {
- PyObject *m;
- #if PY_MAJOR_VERSION >= 3
- m = PyModule_Create(&moduledef);
- #else
- m = Py_InitModule("_snappy", snappy_methods);
- #endif
- if (m == NULL)
- INITERROR;
- SnappyCompressError = PyErr_NewException((char*)"snappy.CompressError",
- NULL, NULL);
- SnappyUncompressError = PyErr_NewException((char*)"snappy.UncompressError",
- NULL, NULL);
- SnappyInvalidCompressedInputError = PyErr_NewException(
- (char*)"snappy.InvalidCompressedInputError", NULL, NULL);
- SnappyCompressedLengthError = PyErr_NewException(
- (char*)"snappy.CompressedLengthError", NULL, NULL);
- Py_INCREF(SnappyCompressError);
- Py_INCREF(SnappyUncompressError);
- Py_INCREF(SnappyInvalidCompressedInputError);
- Py_INCREF(SnappyCompressedLengthError);
- PyModule_AddObject(m, "CompressError", SnappyCompressError);
- PyModule_AddObject(m, "UncompressError", SnappyUncompressError);
- PyModule_AddObject(m, "InvalidCompressedInputError",
- SnappyInvalidCompressedInputError);
- PyModule_AddObject(m, "CompressedLengthError", SnappyCompressedLengthError);
- /* Version = MODULE_VERSION */
- if (PyModule_AddStringConstant(m, "__version__", MODULE_VERSION))
- INITERROR;
- #if PY_MAJOR_VERSION >= 3
- return m;
- #endif
- }
|