1
#include "liblzma_compressobj.h"
2
#include "liblzma_options.h"
3
#include "liblzma_util.h"
5
PyDoc_STRVAR(LZMAComp_compress__doc__,
6
"compress(data) -> string\n\
8
Feed the compressor object with data to compress sequently.\n\
9
This function will return the header for the compressed string for the first\n\
10
input provided, this header will be needed to concatenate with the rest of\n\
11
the stream when flushing to have a proper stream able to be decompressed\n\
15
LZMAComp_compress(LZMACompObject *self, PyObject *args)
18
Py_ssize_t datasize, bufsize = SMALLCHUNK;
20
uint64_t start_total_out;
22
lzma_stream *lzus = &self->lzus;
26
if (!PyArg_ParseTuple(args, "s*:compress", &pdata))
33
PyErr_SetString(PyExc_ValueError,
34
"this object was already flushed");
38
if (!(ret = PyString_FromStringAndSize(NULL, bufsize)))
41
start_total_out = lzus->total_out;
42
lzus->avail_in = (size_t)datasize;
44
lzus->avail_out = (size_t)bufsize;
45
lzus->next_out = (uint8_t *)PyString_AS_STRING(ret);
48
Py_BEGIN_ALLOW_THREADS
49
lzuerror = lzma_code(lzus, LZMA_RUN);
51
if (lzus->avail_in == 0 || lzus->avail_out != 0)
53
if (_PyString_Resize(&ret, bufsize << 1) < 0)
55
lzus->next_out = (uint8_t *)PyString_AS_STRING(ret) + datasize;
56
lzus->avail_out = (size_t)bufsize;
57
bufsize = bufsize << 1;
58
if(!Util_CatchLZMAError(lzuerror, lzus, true))
62
_PyString_Resize(&ret, (Py_ssize_t)lzus->total_out - (Py_ssize_t)start_total_out);
65
PyBuffer_Release(&pdata);
70
PyBuffer_Release(&pdata);
75
PyDoc_STRVAR(LZMAComp_flush__doc__,
76
"flush( [mode] ) -> string\n\
78
Returns a string containing any remaining compressed data.\n\
80
'mode' can be one of the constants LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, LZMA_FINISH; the\n\
81
default value used when mode is not specified is LZMA_FINISH.\n\
82
If mode == LZMA_FINISH, the compressor object can no longer be used after\n\
83
calling the flush() method. Otherwise, more data can still be compressed.\n");
86
LZMAComp_flush(LZMACompObject *self, PyObject *args)
88
Py_ssize_t bufsize = SMALLCHUNK;
90
lzma_action flushmode = LZMA_FINISH;
91
uint64_t start_total_out;
92
lzma_stream *lzus = &self->lzus;
96
if (!PyArg_ParseTuple(args, "|i:flush", &flushmode))
100
if (!self->running) {
101
PyErr_SetString(PyExc_ValueError, "object was already flushed");
106
case(LZMA_SYNC_FLUSH):
107
case(LZMA_FULL_FLUSH):
108
if(self->filters[0].id == LZMA_FILTER_LZMA1) {
109
PyErr_Format(LZMAError, "%d is not supported as flush mode for LZMA_Alone format", flushmode);
112
/* Flushing with LZMA_RUN is a no-op, so there's no point in
113
* doing any work at all; just return an empty string.
116
ret = PyString_FromStringAndSize(NULL, 0);
121
PyErr_Format(LZMAError, "Invalid flush mode: %d", flushmode);
125
self->running = false;
126
if (!(ret = PyString_FromStringAndSize(NULL, bufsize)))
129
start_total_out = lzus->total_out;
131
lzus->avail_out = (size_t)bufsize;
132
lzus->next_out = (uint8_t *)PyString_AS_STRING(ret);
135
Py_BEGIN_ALLOW_THREADS
136
lzuerror = lzma_code(lzus, flushmode);
138
if (lzus->avail_in == 0 || lzus->avail_out != 0)
140
if (_PyString_Resize(&ret, bufsize << 1) < 0)
142
lzus->next_out = (uint8_t *)PyString_AS_STRING(ret) + bufsize;
143
lzus->avail_out = (size_t)bufsize;
144
bufsize = bufsize << 1;
145
if(!Util_CatchLZMAError(lzuerror, lzus, true))
149
_PyString_Resize(&ret, (Py_ssize_t)self->lzus.total_out - (Py_ssize_t)start_total_out);
160
PyDoc_STRVAR(LZMAComp_reset__doc__,
161
"reset(["DEFAULT_OPTIONS_STRING"]) -> None\n\
163
Resets the compression object keeping the compression settings.\n\
164
These existing settings can be overriden by providing\n\
168
LZMAComp_reset(LZMACompObject *self, PyObject *args, PyObject *kwargs)
170
PyObject *result = NULL, *options_dict = NULL;
171
lzma_stream *lzus = &self->lzus;
172
lzma_ret lzuerror = LZMA_OK;
174
static char *kwlist[] = {"options", NULL};
177
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:reset", kwlist,
181
if(!init_lzma_options("reset", options_dict, self->filters))
184
self->lzma_options = LZMA_options_get(self->filters[0]);
191
if(self->filters[0].id == LZMA_FILTER_LZMA2)
192
lzuerror = lzma_stream_encoder(lzus, self->filters, self->filters[LZMA_FILTERS_MAX + 1].id);
193
else if(self->filters[0].id == LZMA_FILTER_LZMA1)
194
lzuerror = lzma_alone_encoder(lzus, self->filters[0].options);
196
if(!Util_CatchLZMAError(lzuerror, lzus, true))
198
self->running = true;
207
PyDoc_STRVAR(LZMAComp_lzma_options__doc__,
208
"Dictionary containing the lzma encoder options.");
210
static PyMemberDef LZMAComp_members[] = {
211
{"lzma_options", T_OBJECT, offsetof(LZMACompObject, lzma_options),
212
RO, LZMAComp_lzma_options__doc__},
213
{NULL, 0, 0, 0, NULL} /* Sentinel */
216
static PyMethodDef LZMAComp_methods[] =
218
{"compress", (PyCFunction)LZMAComp_compress, METH_VARARGS,
219
LZMAComp_compress__doc__},
220
{"flush", (PyCFunction)LZMAComp_flush, METH_VARARGS,
221
LZMAComp_flush__doc__},
222
{"reset", (PyCFunction)LZMAComp_reset, METH_VARARGS | METH_KEYWORDS,
223
LZMAComp_reset__doc__},
228
LZMAComp_init(LZMACompObject *self, PyObject *args, PyObject *kwargs)
230
PyObject *options_dict = NULL;
231
lzma_stream *lzus = &self->lzus;
232
lzma_ret lzuerror = LZMA_OK;
234
static char *kwlist[] = {"options", NULL};
236
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:LZMACompressor", kwlist,
240
if(!init_lzma_options("LZMACompressor", options_dict, self->filters))
243
self->lzma_options = LZMA_options_get(self->filters[0]);
246
self->lock = PyThread_allocate_lock();
248
PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
253
if(self->filters[0].id == LZMA_FILTER_LZMA2)
254
lzuerror = lzma_stream_encoder(lzus, self->filters, self->filters[LZMA_FILTERS_MAX + 1].id);
255
else if(self->filters[0].id == LZMA_FILTER_LZMA1)
256
lzuerror = lzma_alone_encoder(lzus, self->filters[0].options);
258
if(!Util_CatchLZMAError(lzuerror, lzus, true))
261
self->is_initialised = true;
262
self->running = true;
269
PyThread_free_lock(self->lock);
277
LZMACompObject_new(PyTypeObject *type, __attribute__((unused)) PyObject *args, __attribute__((unused)) PyObject *kwargs)
279
LZMACompObject *self;
280
self = (LZMACompObject *)type->tp_alloc(type, 0);
282
self->is_initialised = false;
283
self->running = false;
284
lzma_stream tmp = LZMA_STREAM_INIT;
286
self->filters[0].options = &self->options;
291
return (PyObject *)self;
295
LZMAComp_dealloc(LZMACompObject *self)
299
PyThread_free_lock(self->lock);
301
if (self->is_initialised)
302
lzma_end(&self->lzus);
303
Py_XDECREF(self->lzma_options);
304
Py_TYPE(self)->tp_free((PyObject *)self);
307
PyDoc_STRVAR(LZMAComp__doc__,
308
"LZMACompressor(["DEFAULT_OPTIONS_STRING"]) -> compressor object\n\
309
Create a new compressor object. This object may be used to compress\n\
310
data sequentially. If you want to compress data in one shot, use the\n\
311
compress() function instead.\n");
313
PyTypeObject LZMAComp_Type = {
314
PyObject_HEAD_INIT(NULL)
316
"lzma.LZMACompressor", /*tp_name*/
317
sizeof(LZMACompObject), /*tp_basicsize*/
319
(destructor)LZMAComp_dealloc, /*tp_dealloc*/
326
0, /*tp_as_sequence*/
331
PyObject_GenericGetAttr, /*tp_getattro*/
332
PyObject_GenericSetAttr, /*tp_setattro*/
334
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
335
LZMAComp__doc__, /*tp_doc*/
338
0, /*tp_richcompare*/
339
0, /*tp_weaklistoffset*/
342
LZMAComp_methods, /*tp_methods*/
343
LZMAComp_members, /*tp_members*/
350
(initproc)LZMAComp_init, /*tp_init*/
351
PyType_GenericAlloc, /*tp_alloc*/
352
LZMACompObject_new, /*tp_new*/
353
_PyObject_Del, /*tp_free*/