PyObject *pylzma_decompress_compat(PyObject *self, PyObject *args) { char *data; int length, blocksize=BLOCK_SIZE; PyObject *result = NULL; lzma_stream stream; int res; char *output; if (!PyArg_ParseTuple(args, "s#|i", &data, &length, &blocksize)) return NULL; memset(&stream, 0, sizeof(stream)); if (!(output = (char *)malloc(blocksize))) { PyErr_NoMemory(); goto exit; } lzmaCompatInit(&stream); stream.next_in = (Byte *)data; stream.avail_in = length; stream.next_out = (Byte *)output; stream.avail_out = blocksize; // decompress data while (1) { Py_BEGIN_ALLOW_THREADS res = lzmaCompatDecode(&stream); Py_END_ALLOW_THREADS if (res == LZMA_STREAM_END) { break; } else if (res == LZMA_NOT_ENOUGH_MEM) { // out of memory during decompression PyErr_NoMemory(); goto exit; } else if (res == LZMA_DATA_ERROR) { PyErr_SetString(PyExc_ValueError, "data error during decompression"); goto exit; } else if (res == LZMA_OK) { // check if we need to adjust the output buffer if (stream.avail_out == 0) { output = (char *)realloc(output, blocksize+BLOCK_SIZE); stream.avail_out = BLOCK_SIZE; stream.next_out = (Byte *)&output[blocksize]; blocksize += BLOCK_SIZE; }; } else { PyErr_Format(PyExc_ValueError, "unknown return code from lzmaDecode: %d", res); goto exit; } // if we exit here, decompression finished without returning LZMA_STREAM_END // XXX: why is this sometimes? if (stream.avail_in == 0) break; } result = PyBytes_FromStringAndSize(output, stream.totalOut); exit: free_lzma_stream(&stream); if (output != NULL) free(output); return result; }
static PyObject *pylzma_decomp_decompress(CCompatDecompressionObject *self, PyObject *args) { PyObject *result=NULL; char *data; PARSE_LENGTH_TYPE length, old_length; PY_LONG_LONG start_total_out; int res; PY_LONG_LONG max_length=BLOCK_SIZE; if (!PyArg_ParseTuple(args, "s#|L", &data, &length, &max_length)) return NULL; if (max_length < 0) { PyErr_SetString(PyExc_ValueError, "bufsize must be greater than zero"); return NULL; } start_total_out = self->stream.totalOut; if (self->unconsumed_length > 0) { self->unconsumed_tail = (char *)realloc(self->unconsumed_tail, self->unconsumed_length + length); self->stream.next_in = (Byte *)self->unconsumed_tail; memcpy(self->stream.next_in + self->unconsumed_length, data, length); } else self->stream.next_in = (Byte *)data; self->stream.avail_in = self->unconsumed_length + length; if (max_length && max_length < length) length = max_length; if (!(result = PyBytes_FromStringAndSize(NULL, length))) return NULL; self->stream.next_out = (unsigned char *) PyBytes_AS_STRING(result); self->stream.avail_out = length; Py_BEGIN_ALLOW_THREADS res = lzmaCompatDecode(&self->stream); Py_END_ALLOW_THREADS while (res == LZMA_OK && self->stream.avail_out == 0) { if (max_length && length >= max_length) break; old_length = length; length <<= 1; if (max_length && length > max_length) length = max_length; if (_PyBytes_Resize(&result, length) < 0) goto exit; self->stream.avail_out = length - old_length; self->stream.next_out = (Byte *) PyBytes_AS_STRING(result) + old_length; Py_BEGIN_ALLOW_THREADS res = lzmaCompatDecode(&self->stream); Py_END_ALLOW_THREADS } if (res == LZMA_NOT_ENOUGH_MEM) { // out of memory during decompression PyErr_NoMemory(); DEC_AND_NULL(result); goto exit; } else if (res == LZMA_DATA_ERROR) { PyErr_SetString(PyExc_ValueError, "data error during decompression"); DEC_AND_NULL(result); goto exit; } else if (res != LZMA_OK && res != LZMA_STREAM_END) { PyErr_Format(PyExc_ValueError, "unknown return code from lzmaDecode: %d", res); DEC_AND_NULL(result); goto exit; } /* Not all of the compressed data could be accomodated in the output buffer of specified size. Return the unconsumed tail in an attribute.*/ if (max_length != 0) { if (self->stream.avail_in > 0) { if (self->stream.avail_in != self->unconsumed_length) self->unconsumed_tail = (char *)realloc(self->unconsumed_tail, self->stream.avail_in); if (!self->unconsumed_tail) { PyErr_NoMemory(); DEC_AND_NULL(result); goto exit; } memcpy(self->unconsumed_tail, self->stream.next_in, self->stream.avail_in); } else FREE_AND_NULL(self->unconsumed_tail); self->unconsumed_length = self->stream.avail_in; } /* The end of the compressed data has been reached, so set the unused_data attribute to a string containing the remainder of the data in the string. Note that this is also a logical place to call inflateEnd, but the old behaviour of only calling it on flush() is preserved. */ if (res == LZMA_STREAM_END) { Py_XDECREF(self->unused_data); /* Free original empty string */ self->unused_data = PyBytes_FromStringAndSize((char *) self->stream.next_in, self->stream.avail_in); if (self->unused_data == NULL) { PyErr_NoMemory(); DEC_AND_NULL(result); goto exit; } } _PyBytes_Resize(&result, self->stream.totalOut - start_total_out); exit: return result; }