contrib/python-zstandard/c-ext/decompressobj.c
changeset 30435 b86a448a2965
child 30895 c32454d69b85
equal deleted inserted replaced
30434:2e484bdea8c4 30435:b86a448a2965
       
     1 /**
       
     2 * Copyright (c) 2016-present, Gregory Szorc
       
     3 * All rights reserved.
       
     4 *
       
     5 * This software may be modified and distributed under the terms
       
     6 * of the BSD license. See the LICENSE file for details.
       
     7 */
       
     8 
       
     9 #include "python-zstandard.h"
       
    10 
       
    11 extern PyObject* ZstdError;
       
    12 
       
    13 PyDoc_STRVAR(DecompressionObj__doc__,
       
    14 "Perform decompression using a standard library compatible API.\n"
       
    15 );
       
    16 
       
    17 static void DecompressionObj_dealloc(ZstdDecompressionObj* self) {
       
    18 	if (self->dstream) {
       
    19 		ZSTD_freeDStream(self->dstream);
       
    20 		self->dstream = NULL;
       
    21 	}
       
    22 
       
    23 	Py_XDECREF(self->decompressor);
       
    24 
       
    25 	PyObject_Del(self);
       
    26 }
       
    27 
       
    28 static PyObject* DecompressionObj_decompress(ZstdDecompressionObj* self, PyObject* args) {
       
    29 	const char* source;
       
    30 	Py_ssize_t sourceSize;
       
    31 	size_t zresult;
       
    32 	ZSTD_inBuffer input;
       
    33 	ZSTD_outBuffer output;
       
    34 	size_t outSize = ZSTD_DStreamOutSize();
       
    35 	PyObject* result = NULL;
       
    36 	Py_ssize_t resultSize = 0;
       
    37 
       
    38 	if (self->finished) {
       
    39 		PyErr_SetString(ZstdError, "cannot use a decompressobj multiple times");
       
    40 		return NULL;
       
    41 	}
       
    42 
       
    43 #if PY_MAJOR_VERSION >= 3
       
    44 	if (!PyArg_ParseTuple(args, "y#",
       
    45 #else
       
    46 	if (!PyArg_ParseTuple(args, "s#",
       
    47 #endif
       
    48 		&source, &sourceSize)) {
       
    49 		return NULL;
       
    50 	}
       
    51 
       
    52 	input.src = source;
       
    53 	input.size = sourceSize;
       
    54 	input.pos = 0;
       
    55 
       
    56 	output.dst = PyMem_Malloc(outSize);
       
    57 	if (!output.dst) {
       
    58 		PyErr_NoMemory();
       
    59 		return NULL;
       
    60 	}
       
    61 	output.size = outSize;
       
    62 	output.pos = 0;
       
    63 
       
    64 	/* Read input until exhausted. */
       
    65 	while (input.pos < input.size) {
       
    66 		Py_BEGIN_ALLOW_THREADS
       
    67 		zresult = ZSTD_decompressStream(self->dstream, &output, &input);
       
    68 		Py_END_ALLOW_THREADS
       
    69 
       
    70 		if (ZSTD_isError(zresult)) {
       
    71 			PyErr_Format(ZstdError, "zstd decompressor error: %s",
       
    72 				ZSTD_getErrorName(zresult));
       
    73 			result = NULL;
       
    74 			goto finally;
       
    75 		}
       
    76 
       
    77 		if (0 == zresult) {
       
    78 			self->finished = 1;
       
    79 		}
       
    80 
       
    81 		if (output.pos) {
       
    82 			if (result) {
       
    83 				resultSize = PyBytes_GET_SIZE(result);
       
    84 				if (-1 == _PyBytes_Resize(&result, resultSize + output.pos)) {
       
    85 					goto except;
       
    86 				}
       
    87 
       
    88 				memcpy(PyBytes_AS_STRING(result) + resultSize,
       
    89 					output.dst, output.pos);
       
    90 			}
       
    91 			else {
       
    92 				result = PyBytes_FromStringAndSize(output.dst, output.pos);
       
    93 				if (!result) {
       
    94 					goto except;
       
    95 				}
       
    96 			}
       
    97 
       
    98 			output.pos = 0;
       
    99 		}
       
   100 	}
       
   101 
       
   102 	if (!result) {
       
   103 		result = PyBytes_FromString("");
       
   104 	}
       
   105 
       
   106 	goto finally;
       
   107 
       
   108 except:
       
   109 	Py_DecRef(result);
       
   110 	result = NULL;
       
   111 
       
   112 finally:
       
   113 	PyMem_Free(output.dst);
       
   114 
       
   115 	return result;
       
   116 }
       
   117 
       
   118 static PyMethodDef DecompressionObj_methods[] = {
       
   119 	{ "decompress", (PyCFunction)DecompressionObj_decompress,
       
   120 	  METH_VARARGS, PyDoc_STR("decompress data") },
       
   121 	{ NULL, NULL }
       
   122 };
       
   123 
       
   124 PyTypeObject ZstdDecompressionObjType = {
       
   125 	PyVarObject_HEAD_INIT(NULL, 0)
       
   126 	"zstd.ZstdDecompressionObj",    /* tp_name */
       
   127 	sizeof(ZstdDecompressionObj),   /* tp_basicsize */
       
   128 	0,                              /* tp_itemsize */
       
   129 	(destructor)DecompressionObj_dealloc, /* tp_dealloc */
       
   130 	0,                              /* tp_print */
       
   131 	0,                              /* tp_getattr */
       
   132 	0,                              /* tp_setattr */
       
   133 	0,                              /* tp_compare */
       
   134 	0,                              /* tp_repr */
       
   135 	0,                              /* tp_as_number */
       
   136 	0,                              /* tp_as_sequence */
       
   137 	0,                              /* tp_as_mapping */
       
   138 	0,                              /* tp_hash */
       
   139 	0,                              /* tp_call */
       
   140 	0,                              /* tp_str */
       
   141 	0,                              /* tp_getattro */
       
   142 	0,                              /* tp_setattro */
       
   143 	0,                              /* tp_as_buffer */
       
   144 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
       
   145 	DecompressionObj__doc__,        /* tp_doc */
       
   146 	0,                              /* tp_traverse */
       
   147 	0,                              /* tp_clear */
       
   148 	0,                              /* tp_richcompare */
       
   149 	0,                              /* tp_weaklistoffset */
       
   150 	0,                              /* tp_iter */
       
   151 	0,                              /* tp_iternext */
       
   152 	DecompressionObj_methods,       /* tp_methods */
       
   153 	0,                              /* tp_members */
       
   154 	0,                              /* tp_getset */
       
   155 	0,                              /* tp_base */
       
   156 	0,                              /* tp_dict */
       
   157 	0,                              /* tp_descr_get */
       
   158 	0,                              /* tp_descr_set */
       
   159 	0,                              /* tp_dictoffset */
       
   160 	0,                              /* tp_init */
       
   161 	0,                              /* tp_alloc */
       
   162 	PyType_GenericNew,              /* tp_new */
       
   163 };
       
   164 
       
   165 void decompressobj_module_init(PyObject* module) {
       
   166 	Py_TYPE(&ZstdDecompressionObjType) = &PyType_Type;
       
   167 	if (PyType_Ready(&ZstdDecompressionObjType) < 0) {
       
   168 		return;
       
   169 	}
       
   170 }