decompressobj.c
202 lines
| 5.3 KiB
| text/x-c
|
CLexer
Gregory Szorc
|
r30435 | /** | ||
* Copyright (c) 2016-present, Gregory Szorc | ||||
* All rights reserved. | ||||
* | ||||
* This software may be modified and distributed under the terms | ||||
* of the BSD license. See the LICENSE file for details. | ||||
*/ | ||||
#include "python-zstandard.h" | ||||
extern PyObject* ZstdError; | ||||
PyDoc_STRVAR(DecompressionObj__doc__, | ||||
"Perform decompression using a standard library compatible API.\n" | ||||
); | ||||
static void DecompressionObj_dealloc(ZstdDecompressionObj* self) { | ||||
Py_XDECREF(self->decompressor); | ||||
PyObject_Del(self); | ||||
} | ||||
Gregory Szorc
|
r37513 | static PyObject* DecompressionObj_decompress(ZstdDecompressionObj* self, PyObject* args, PyObject* kwargs) { | ||
static char* kwlist[] = { | ||||
"data", | ||||
NULL | ||||
}; | ||||
Py_buffer source; | ||||
Gregory Szorc
|
r30435 | size_t zresult; | ||
ZSTD_inBuffer input; | ||||
ZSTD_outBuffer output; | ||||
PyObject* result = NULL; | ||||
Py_ssize_t resultSize = 0; | ||||
Gregory Szorc
|
r40157 | output.dst = NULL; | ||
Gregory Szorc
|
r30435 | if (self->finished) { | ||
PyErr_SetString(ZstdError, "cannot use a decompressobj multiple times"); | ||||
return NULL; | ||||
} | ||||
#if PY_MAJOR_VERSION >= 3 | ||||
Gregory Szorc
|
r37513 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*:decompress", | ||
Gregory Szorc
|
r30435 | #else | ||
Gregory Szorc
|
r37513 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s*:decompress", | ||
Gregory Szorc
|
r30435 | #endif | ||
Gregory Szorc
|
r37513 | kwlist, &source)) { | ||
Gregory Szorc
|
r30435 | return NULL; | ||
} | ||||
Gregory Szorc
|
r37513 | if (!PyBuffer_IsContiguous(&source, 'C') || source.ndim > 1) { | ||
PyErr_SetString(PyExc_ValueError, | ||||
"data buffer should be contiguous and have at most one dimension"); | ||||
goto finally; | ||||
} | ||||
Gregory Szorc
|
r40157 | /* Special case of empty input. Output will always be empty. */ | ||
if (source.len == 0) { | ||||
result = PyBytes_FromString(""); | ||||
goto finally; | ||||
} | ||||
Gregory Szorc
|
r37513 | input.src = source.buf; | ||
input.size = source.len; | ||||
Gregory Szorc
|
r30435 | input.pos = 0; | ||
Gregory Szorc
|
r37513 | output.dst = PyMem_Malloc(self->outSize); | ||
Gregory Szorc
|
r30435 | if (!output.dst) { | ||
PyErr_NoMemory(); | ||||
Gregory Szorc
|
r37513 | goto except; | ||
Gregory Szorc
|
r30435 | } | ||
Gregory Szorc
|
r37513 | output.size = self->outSize; | ||
Gregory Szorc
|
r30435 | output.pos = 0; | ||
Gregory Szorc
|
r40157 | while (1) { | ||
Gregory Szorc
|
r30435 | Py_BEGIN_ALLOW_THREADS | ||
Gregory Szorc
|
r42237 | zresult = ZSTD_decompressStream(self->decompressor->dctx, &output, &input); | ||
Gregory Szorc
|
r30435 | Py_END_ALLOW_THREADS | ||
if (ZSTD_isError(zresult)) { | ||||
PyErr_Format(ZstdError, "zstd decompressor error: %s", | ||||
ZSTD_getErrorName(zresult)); | ||||
Gregory Szorc
|
r37513 | goto except; | ||
Gregory Szorc
|
r30435 | } | ||
if (0 == zresult) { | ||||
self->finished = 1; | ||||
} | ||||
if (output.pos) { | ||||
if (result) { | ||||
resultSize = PyBytes_GET_SIZE(result); | ||||
Gregory Szorc
|
r37513 | if (-1 == safe_pybytes_resize(&result, resultSize + output.pos)) { | ||
Py_XDECREF(result); | ||||
Gregory Szorc
|
r30435 | goto except; | ||
} | ||||
memcpy(PyBytes_AS_STRING(result) + resultSize, | ||||
output.dst, output.pos); | ||||
} | ||||
else { | ||||
result = PyBytes_FromStringAndSize(output.dst, output.pos); | ||||
if (!result) { | ||||
goto except; | ||||
} | ||||
} | ||||
Gregory Szorc
|
r40157 | } | ||
Gregory Szorc
|
r30435 | |||
Gregory Szorc
|
r40157 | if (zresult == 0 || (input.pos == input.size && output.pos == 0)) { | ||
break; | ||||
Gregory Szorc
|
r30435 | } | ||
Gregory Szorc
|
r40157 | |||
output.pos = 0; | ||||
Gregory Szorc
|
r30435 | } | ||
if (!result) { | ||||
result = PyBytes_FromString(""); | ||||
} | ||||
goto finally; | ||||
except: | ||||
Gregory Szorc
|
r31796 | Py_CLEAR(result); | ||
Gregory Szorc
|
r30435 | |||
finally: | ||||
PyMem_Free(output.dst); | ||||
Gregory Szorc
|
r37513 | PyBuffer_Release(&source); | ||
Gregory Szorc
|
r30435 | |||
return result; | ||||
} | ||||
Gregory Szorc
|
r42237 | static PyObject* DecompressionObj_flush(ZstdDecompressionObj* self, PyObject* args, PyObject* kwargs) { | ||
static char* kwlist[] = { | ||||
"length", | ||||
NULL | ||||
}; | ||||
PyObject* length = NULL; | ||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:flush", kwlist, &length)) { | ||||
return NULL; | ||||
} | ||||
Py_RETURN_NONE; | ||||
} | ||||
Gregory Szorc
|
r30435 | static PyMethodDef DecompressionObj_methods[] = { | ||
{ "decompress", (PyCFunction)DecompressionObj_decompress, | ||||
Gregory Szorc
|
r37513 | METH_VARARGS | METH_KEYWORDS, PyDoc_STR("decompress data") }, | ||
Gregory Szorc
|
r42237 | { "flush", (PyCFunction)DecompressionObj_flush, | ||
METH_VARARGS | METH_KEYWORDS, PyDoc_STR("no-op") }, | ||||
Gregory Szorc
|
r30435 | { NULL, NULL } | ||
}; | ||||
PyTypeObject ZstdDecompressionObjType = { | ||||
PyVarObject_HEAD_INIT(NULL, 0) | ||||
"zstd.ZstdDecompressionObj", /* tp_name */ | ||||
sizeof(ZstdDecompressionObj), /* tp_basicsize */ | ||||
0, /* tp_itemsize */ | ||||
(destructor)DecompressionObj_dealloc, /* tp_dealloc */ | ||||
0, /* tp_print */ | ||||
0, /* tp_getattr */ | ||||
0, /* tp_setattr */ | ||||
0, /* tp_compare */ | ||||
0, /* tp_repr */ | ||||
0, /* tp_as_number */ | ||||
0, /* tp_as_sequence */ | ||||
0, /* tp_as_mapping */ | ||||
0, /* tp_hash */ | ||||
0, /* tp_call */ | ||||
0, /* tp_str */ | ||||
0, /* tp_getattro */ | ||||
0, /* tp_setattro */ | ||||
0, /* tp_as_buffer */ | ||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ | ||||
DecompressionObj__doc__, /* tp_doc */ | ||||
0, /* tp_traverse */ | ||||
0, /* tp_clear */ | ||||
0, /* tp_richcompare */ | ||||
0, /* tp_weaklistoffset */ | ||||
0, /* tp_iter */ | ||||
0, /* tp_iternext */ | ||||
DecompressionObj_methods, /* tp_methods */ | ||||
0, /* tp_members */ | ||||
0, /* tp_getset */ | ||||
0, /* tp_base */ | ||||
0, /* tp_dict */ | ||||
0, /* tp_descr_get */ | ||||
0, /* tp_descr_set */ | ||||
0, /* tp_dictoffset */ | ||||
0, /* tp_init */ | ||||
0, /* tp_alloc */ | ||||
PyType_GenericNew, /* tp_new */ | ||||
}; | ||||
void decompressobj_module_init(PyObject* module) { | ||||
Victor Stinner
|
r47090 | Py_SET_TYPE(&ZstdDecompressionObjType, &PyType_Type); | ||
Gregory Szorc
|
r30435 | if (PyType_Ready(&ZstdDecompressionObjType) < 0) { | ||
return; | ||||
} | ||||
} | ||||