Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(93)

Unified Diff: Modules/lzmamodule.c

Issue 2724043: py3k lzma patch Base URL: http://svn.python.org/view/*checkout*/python/branches/py3k/
Patch Set: Created 13 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« Doc/library/lzma.rst ('K') | « Lib/test/teststring.xz ('k') | setup.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Modules/lzmamodule.c
===================================================================
--- Modules/lzmamodule.c (revisjon 0)
+++ Modules/lzmamodule.c (revisjon 0)
@@ -0,0 +1,3605 @@
+/*
+
+pyliblzma - python liblzma interface
+
+Copyright (c) 2007-2010 Per Øyvind Karlsen <peroyvind@mandriva.org>
+
+Based on:
+python-bz2 - python bz2 library interface
+
+Copyright (c) 2002 Gustavo Niemeyer <niemeyer@conectiva.com>
+Copyright (c) 2002 Python Software Foundation; All Rights Reserved
+
+*/
+
+/* To handle length as ssize_t in stead of int, otherwise we'd have to
+ * use the internal _PyArg_ParseTuple_SizeT function to avoid screwups
+ */
+#define PY_SSIZE_T_CLEAN 1
+#include "Python.h"
+#include <lzma.h>
+#include "structmember.h"
+
+#ifdef WITH_THREAD
+#include "pythread.h"
+#endif
+
+#define VERSION "0.6.0"
Martin v. Löwis 2010/10/31 16:33:38 I recommend that this is version 1.0 (or doesn't g
+
+static const char __author__[] =
+"The lzma python module was written by:\n\
+\n\
+ Per Øyvind Karlsen <peroyvind@mandriva.org>\n\
+";
+
+/* Our very own off_t-like type, 64-bit if possible */
+/* copied from Objects/fileobject.c */
+#if !defined(HAVE_LARGEFILE_SUPPORT)
+typedef off_t Py_off_t;
+#elif SIZEOF_OFF_T >= 8
+typedef off_t Py_off_t;
+#elif SIZEOF_FPOS_T >= 8
+typedef fpos_t Py_off_t;
+#else
+#error "Large file support, but neither off_t nor fpos_t is large enough."
+#endif
+
+#define BUF(v) PyBytes_AS_STRING(v)
+
+#define LZMAFileObject_Check(v) (Py_TYPE(v) == &LZMAFile_Type)
+
+typedef enum file_mode_e {
+ MODE_CLOSED = 0,
+ MODE_READ = 1,
+ MODE_READ_EOF = 2,
+ MODE_WRITE = 3
+} file_mode;
+
+#ifdef WITH_THREAD
+#define ACQUIRE_LOCK(obj) do { \
+ if (!PyThread_acquire_lock(obj->lock, 0)) { \
Martin v. Löwis 2010/10/31 16:33:38 I recommend to put the acquire/release object lock
+ Py_BEGIN_ALLOW_THREADS \
+ PyThread_acquire_lock(obj->lock, 1); \
+ Py_END_ALLOW_THREADS \
+ } } while(0)
+#define RELEASE_LOCK(obj) PyThread_release_lock(obj->lock)
+#else
+#define ACQUIRE_LOCK(obj)
+#define RELEASE_LOCK(obj)
+#endif
+
+#define INITCHECK \
+ if (!self->is_initialised) {\
+ PyErr_Format(PyExc_RuntimeError, "%s object not initialised!", \
+ Py_TYPE(self)->tp_name); \
+ return NULL; \
+ }
+
+/* ===================================================================== */
+/* liblzma has no FILE-like interface, so we need to define our own */
+
+typedef struct lzma_file {
+ unsigned char buf[1<<15];
+ lzma_stream strm;
+ FILE *fp;
+ int encoding;
+ int eof;
+} lzma_FILE;
+
+static lzma_FILE *
+lzma_open(lzma_ret *lzma_error, lzma_filter *filters, lzma_check check,
+ FILE *fp, unsigned long long memlimit)
+{
+ lzma_ret *ret = lzma_error;
+ int encoding = filters[0].options ? 1 : 0;
+ lzma_FILE *lzma_file;
+ lzma_stream tmp = LZMA_STREAM_INIT;
+
+ if (!fp)
+ return NULL;
+
+ lzma_file = PyMem_Malloc(sizeof(*lzma_file));
+
+ if (!lzma_file)
+ return NULL;
+
+ lzma_file->fp = fp;
+ lzma_file->encoding = encoding;
+ lzma_file->eof = 0;
+ lzma_file->strm = tmp;
+
+ if (encoding) {
+ if(filters[0].id == LZMA_FILTER_LZMA1)
+ *ret = lzma_alone_encoder(&lzma_file->strm, filters[0].options);
+ else if(check == (lzma_check)-1)
+ *ret = lzma_raw_encoder(&lzma_file->strm, filters);
+ else
+ *ret = lzma_stream_encoder(&lzma_file->strm, filters, check);
+ } else
+ *ret = lzma_auto_decoder(&lzma_file->strm, memlimit, 0);
+
+ if (*ret != LZMA_OK) {
+ PyMem_Free(lzma_file);
+ return NULL;
+ }
+ return lzma_file;
+}
+
+static int
+lzma_close(lzma_ret *lzma_error, lzma_FILE *lzma_file)
+{
+ lzma_ret *ret = lzma_error;
+ int retval = 0;
+ size_t n;
+
+ if (!lzma_file)
+ return -1;
+ if (lzma_file->encoding) {
+ for (;;) {
+ lzma_file->strm.avail_out = sizeof(lzma_file->buf);
+ lzma_file->strm.next_out = (unsigned char *)lzma_file->buf;
+ *ret = lzma_code(&lzma_file->strm, LZMA_FINISH);
+ if (*ret != LZMA_OK && *ret != LZMA_STREAM_END)
+ {
+ retval = -1;
+ break;
+ }
+ n = sizeof(lzma_file->buf) - lzma_file->strm.avail_out;
+ if (n && fwrite(lzma_file->buf, 1, n, lzma_file->fp) != n)
+ {
+ retval = -1;
+ break;
+ }
+ if (*ret == LZMA_STREAM_END)
+ break;
+ }
+ } else
+ *ret = LZMA_OK;
+
+ lzma_end(&lzma_file->strm);
+ return retval;
+}
+
+static ssize_t
+lzma_read(lzma_ret *lzma_error, lzma_FILE *lzma_file, void *buf, size_t len)
+{
+ lzma_ret *ret = lzma_error;
+ int eof = 0;
+
+ if (!lzma_file || lzma_file->encoding)
+ return -1;
+ if (lzma_file->eof)
+ return 0;
+
+ lzma_file->strm.next_out = buf;
+ lzma_file->strm.avail_out = len;
+ for (;;) {
+ if (!lzma_file->strm.avail_in) {
+ lzma_file->strm.next_in = (unsigned char *)lzma_file->buf;
+ lzma_file->strm.avail_in = fread(lzma_file->buf, 1,
+ sizeof(lzma_file->buf), lzma_file->fp);
+ if (!lzma_file->strm.avail_in)
+ eof = 1;
+ }
+ *ret = lzma_code(&lzma_file->strm, LZMA_RUN);
+ if (*ret == LZMA_STREAM_END) {
+ lzma_file->eof = 1;
+ return len - lzma_file->strm.avail_out;
+ }
+ if (*ret != LZMA_OK)
+ return -1;
+ if (!lzma_file->strm.avail_out)
+ return len;
+ if (eof)
+ return -1;
+ }
+}
+
+static ssize_t
+lzma_write(lzma_ret *lzma_error, lzma_FILE *lzma_file, void *buf, size_t len)
+{
+ lzma_ret *ret = lzma_error;
+ size_t n;
+
+ if (!lzma_file || !lzma_file->encoding)
+ return -1;
+ if (!len)
+ return 0;
+
+ lzma_file->strm.next_in = buf;
+ lzma_file->strm.avail_in = len;
+ for (;;) {
+ lzma_file->strm.next_out = (unsigned char *)lzma_file->buf;
+ lzma_file->strm.avail_out = sizeof(lzma_file->buf);
+ *ret = lzma_code(&lzma_file->strm, LZMA_RUN);
+ if (*ret != LZMA_OK)
+ return -1;
+ n = sizeof(lzma_file->buf) - lzma_file->strm.avail_out;
+ if (n && fwrite(lzma_file->buf, 1, n, lzma_file->fp) != n)
+ return -1;
+ if (!lzma_file->strm.avail_in)
+ return len;
+ }
+}
+
+/* ===================================================================== */
+/* Structure definitions. */
+
+typedef struct
Martin v. Löwis 2010/10/31 16:33:38 I find the option handling fairly involved and unr
+{
+ PyObject_HEAD
+ PyObject *format,
+ *format_dict,
+ *check,
+ *check_dict,
+ *filter_dict,
+ *filter_dictSwap,
+ *filter,
+ *compresslevel,
+ *dict_size,
+ *lc,
+ *lp,
+ *pb,
+ *mode_dict,
+ *mode_dictSwap,
+ *mode,
+ *nice_len,
+ *mf_dict,
+ *mf_dictSwap,
+ *mf,
+ *depth,
+ *dist,
+ *start,
+ *threads;
+} LZMAOptionsObject;
+
+typedef struct {
+ PyObject_HEAD
+ FILE *rawfp;
+
+ char* f_buf; /* Allocated readahead buffer */
+ char* f_bufend; /* Points after last occupied position */
+ char* f_bufptr; /* Current buffer position */
+
+ lzma_FILE *fp;
Martin v. Löwis 2010/10/31 16:33:38 I suggest that struct lzma_FILE is inlined here -
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+ lzma_check check;
+ unsigned long long memlimit;
+
+ file_mode mode;
+ Py_off_t pos;
+ Py_off_t size;
+#ifdef WITH_THREAD
+ PyThread_type_lock lock;
+#endif
+} LZMAFileObject;
+
+typedef struct
+{
+ PyObject_HEAD
+ lzma_stream lzus;
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+ lzma_check check;
+ int is_initialised, running;
+#ifdef WITH_THREAD
+ PyThread_type_lock lock;
+#endif
+} LZMACompObject;
+
+typedef struct
+{
+ PyObject_HEAD
+ lzma_stream lzus;
+ PyObject *unused_data;
+ PyObject *unconsumed_tail;
+ Py_ssize_t max_length;
+ int is_initialised, running;
+ unsigned long long memlimit;
+#ifdef WITH_THREAD
+ PyThread_type_lock lock;
+#endif
+} LZMADecompObject;
+
+/* ===================================================================== */
+/* Utility functions. */
+
+/* Refuse regular I/O if there's data in the iteration-buffer.
+ * Mixing them would cause data to arrive out of order, as the read*
+ * methods don't use the iteration buffer. */
+static int
+check_iterbuffered(LZMAFileObject *f)
+{
+ if (f->f_buf != NULL &&
+ (f->f_bufend - f->f_bufptr) > 0 &&
+ f->f_buf[0] != '\0') {
+ PyErr_SetString(PyExc_ValueError,
+ "Mixing iteration and read methods would lose data");
+ return -1;
+ }
+ return 0;
+}
+
+static PyObject *LZMAError = NULL;
+
+static int
+Util_CatchLZMAError(lzma_ret lzuerror, lzma_stream *lzus, int encoding)
+{
+ int ret = 1;
+ switch(lzuerror) {
+ case LZMA_OK:
+ case LZMA_STREAM_END:
+ break;
+
+ case LZMA_NO_CHECK:
+ PyErr_WarnEx(LZMAError, "stream has no integrity check", 1);
+ break;
+
+ case LZMA_UNSUPPORTED_CHECK:
+ if(encoding)
+ {
+ PyErr_SetString(LZMAError, "Cannot calculate the integrity check");
+ ret = 0;
+ }
+ else if(!encoding)
+ {
+ char warning[64];
+ sprintf(warning,
+ "check type '%d' is unsupported, check will not be validated",
+ lzma_get_check(lzus));
+ PyErr_SetString(LZMAError, warning);
+ }
+ break;
+
+ case LZMA_GET_CHECK:
+ /*TODO: ?*/
+ break;
+
+ case LZMA_MEM_ERROR:
+ PyErr_SetString(PyExc_MemoryError, "cannot allocate memory");
+ ret = 0;
+ break;
+
+ case LZMA_MEMLIMIT_ERROR:
+ PyErr_SetString(PyExc_MemoryError, "memory usage limit was reached");
+ ret = 0;
+ break;
+
+ case LZMA_FORMAT_ERROR:
+ PyErr_SetString(LZMAError, "unknown file format");
+ ret = 0;
+ break;
+
+ case LZMA_OPTIONS_ERROR:
+ PyErr_SetString(LZMAError, "invalid or unsupported options");
+ ret = 0;
+ break;
+
+ case LZMA_DATA_ERROR:
+ PyErr_SetString(PyExc_IOError, "invalid data stream");
+ ret = 0;
+ break;
+
+ case LZMA_BUF_ERROR:
+ if (lzus != NULL && lzus->avail_out > 0) {
+ PyErr_SetString(PyExc_IOError, "unknown BUF error");
+ ret = 0;
+ }
+ break;
+
+ /*case LZMA_HEADER_ERROR:
+ PyErr_SetString(PyExc_RuntimeError, "invalid or unsupported header");
+ ret = 0;
+ break;*/
+
+ case LZMA_PROG_ERROR:
+ /*FIXME: fix more accurate error message..*/
+ PyErr_SetString(PyExc_ValueError,
+ "the lzma library has received wrong "
+ "options");
+ ret = 0;
+ break;
+
+ default:
+ ret = 0;
+ PyErr_SetString(LZMAError, "unknown error!");
+ break;
+
+ }
+ return ret;
+}
+
+#if BUFSIZ <= 1024
+#define SMALLCHUNK 8192
+#else
+#define SMALLCHUNK BUFSIZ
+#endif
+
+#if SIZEOF_INT < 4
+#define BIGCHUNK (512 * 32)
+#else
+#define BIGCHUNK (512 * 1024)
+#endif
+
+/* This is a hacked version of Python's fileobject.c:new_buffersize(). */
+static size_t
+Util_NewBufferSize(size_t currentsize)
+{
+ if (currentsize > SMALLCHUNK) {
+ /* Keep doubling until we reach BIGCHUNK;
+ then keep adding BIGCHUNK. */
+ if (currentsize <= BIGCHUNK)
+ return currentsize + currentsize;
+ else
+ return currentsize + BIGCHUNK;
+ }
+ return currentsize + SMALLCHUNK;
+}
+
+/* This is a hacked version of Python's fileobject.c:get_line(). */
+static PyObject *
+Util_GetLine(LZMAFileObject *f, int n)
+{
+ char c;
+ char *buf, *end;
+ size_t total_v_size; /* total # of slots in buffer */
+ size_t used_v_size = 0; /* # used slots in buffer */
+ size_t increment; /* amount to increment the buffer */
+ PyObject *v;
+ lzma_ret lzuerror = LZMA_OK;
+ int bytes_read;
+
+ total_v_size = n > 0 ? n : 100;
+ v = PyBytes_FromStringAndSize((char *)NULL, total_v_size);
+ if (v == NULL)
+ return NULL;
+
+ buf = BUF(v);
+ end = buf + total_v_size;
+
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ do {
+ bytes_read = lzma_read(&lzuerror, f->fp, &c, 1);
+ f->pos++;
+ if (bytes_read == 0)
+ break;
+ *buf++ = c;
+ } while (lzuerror == LZMA_OK && c != '\n' && buf != end);
+ Py_END_ALLOW_THREADS
+ if (lzuerror == LZMA_STREAM_END) {
+ f->size = f->pos;
+ break;
+ } else if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &f->fp->strm, f->fp->encoding);
+ Py_DECREF(v);
+ return NULL;
+ }
+ if (c == '\n')
+ break;
+ /* Must be because buf == end */
+ if (n > 0)
+ break;
+ used_v_size = total_v_size;
+ increment = total_v_size >> 2; /* mild exponential growth */
+ total_v_size += increment;
+ if (total_v_size > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "line is longer than a Python string can hold");
+ Py_DECREF(v);
+ return NULL;
+ }
+ if (_PyBytes_Resize(&v, total_v_size) < 0) {
+ return NULL;
+ }
+ buf = BUF(v) + used_v_size;
+ end = BUF(v) + total_v_size;
+ }
+
+ used_v_size = buf - BUF(v);
+ if (used_v_size != total_v_size) {
+ if (_PyBytes_Resize(&v, used_v_size) < 0) {
+ v = NULL;
+ }
+ }
+
+ return v;
+}
+
+/* This is a hacked version of Python's fileobject.c:drop_readahead(). */
+static void
+Util_DropReadAhead(LZMAFileObject *f)
+{
+ if (f->f_buf != NULL) {
+ PyMem_Free(f->f_buf);
+ f->f_buf = NULL;
+ }
+}
+
+/* This is a hacked version of Python's fileobject.c:readahead(). */
+static int
+Util_ReadAhead(LZMAFileObject *f, int bufsize)
+{
+ int chunksize;
+ lzma_ret lzuerror = LZMA_OK;
+
+ if (f->f_buf != NULL) {
+ if((f->f_bufend - f->f_bufptr) >= 1)
+ return 0;
+ else
+ Util_DropReadAhead(f);
+ }
+ if (f->fp->eof) {
+ f->f_bufptr = f->f_buf;
+ f->f_bufend = f->f_buf;
+ return 0;
+ }
+ if ((f->f_buf = PyMem_Malloc(bufsize)) == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ Py_BEGIN_ALLOW_THREADS
+ chunksize = lzma_read(&lzuerror, f->fp, f->f_buf, bufsize);
+ Py_END_ALLOW_THREADS
+ f->pos += chunksize;
+ if (lzuerror == LZMA_STREAM_END) {
+ f->size = f->pos;
+ } else if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &f->fp->strm, f->fp->encoding);
+ Util_DropReadAhead(f);
+ return -1;
+ }
+ f->f_bufptr = f->f_buf;
+ f->f_bufend = f->f_buf + chunksize;
+ return 0;
+}
+
+/* This is a hacked version of Python's
+ * fileobject.c:readahead_get_line_skip(). */
+static PyObject *
+Util_ReadAheadGetLineSkip(LZMAFileObject *f, int skip, int bufsize)
+{
+ PyObject* s;
+ char *bufptr;
+ char *buf;
+ int len;
+
+ if (f->f_buf == NULL)
+ if (Util_ReadAhead(f, bufsize) < 0)
+ return NULL;
+
+ len = f->f_bufend - f->f_bufptr;
+ if (len == 0)
+ return PyBytes_FromStringAndSize(NULL, skip);
+ bufptr = memchr(f->f_bufptr, '\n', len);
+ if (bufptr != NULL) {
+ bufptr++; /* Count the '\n' */
+ len = bufptr - f->f_bufptr;
+ s = PyBytes_FromStringAndSize(NULL, skip+len);
+ if (s == NULL)
+ return NULL;
+ memcpy(PyBytes_AS_STRING(s)+skip, f->f_bufptr, len);
+ f->f_bufptr = bufptr;
+ if (bufptr == f->f_bufend)
+ Util_DropReadAhead(f);
+ } else {
+ bufptr = f->f_bufptr;
+ buf = f->f_buf;
+ f->f_buf = NULL; /* Force new readahead buffer */
+ s = Util_ReadAheadGetLineSkip(f, skip+len,
+ bufsize + (bufsize>>2));
+ if (s == NULL) {
+ PyMem_Free(buf);
+ return NULL;
+ }
+ memcpy(PyBytes_AS_STRING(s)+skip, bufptr, len);
+ PyMem_Free(buf);
+ }
+ return s;
+}
+
+/* ===================================================================== */
+/* Methods of LZMAOptions. */
+
+static int
+check_range(unsigned int x, unsigned int a, unsigned int b){
+ return (x < a || x > b);
+}
+#define CHECK_RANGE(x, a, b, msg) if (check_range(x, a, b)) \
+ { PyErr_Format(PyExc_ValueError, msg, a, b, (int)x); goto end; }
+
+static char*
+tostring(const char* text, PyObject *variable) {
+ PyObject *format = PyUnicode_FromString(text);
+ PyObject *str = PyUnicode_Format(format, variable);
+ PyObject *ascii = PyUnicode_AsASCIIString(str);
+ char *cstr = PyBytes_AsString(ascii);
+ Py_DECREF(str);
+ Py_DECREF(format);
+ return cstr;
+}
+
+static PyMemberDef
+memberDef(char *name, int type, Py_ssize_t offset, int flags, char *doc) {
+ PyMemberDef tmp;
+ tmp.name = name, tmp.type = type, tmp.offset = offset,
+ tmp.flags = flags, tmp.doc = doc;
+ return tmp;
+}
+#define MEMBER_DESCRIPTOR(name, type, variable, text) \
+ memberDef(name, type, offsetof(LZMAOptionsObject, variable),\
+ READONLY, tostring(text, self->variable))
+
+#define LZMA_BEST_SPEED 0
+#define LZMA_BEST_COMPRESSION 9
+#define LZMA_MODE_DEFAULT LZMA_MODE_NORMAL
+#define LZMA_MODE_INVALID -1
+#define LZMA_MF_INVALID -1
+
+#define LZMA_MF_DEFAULT LZMA_MF_BT4
+#define LZMA_MF_CYCLES_DEFAULT 0
+#define LZMA_DICT_SIZE_MAX (UINT32_C(1) << 30) + (UINT32_C(1) << 29)
+#define LZMA_NICE_LEN_MIN 5
+#define LZMA_NICE_LEN_MAX 273
+#define LZMA_NICE_LEN_DEFAULT 128
+
+static void
+free_lzma_options(lzma_filter *filters)
+{
+ int i;
+ for(i = 0; filters[i].id != LZMA_VLI_UNKNOWN && i < LZMA_FILTERS_MAX; i++)
+ if(filters[i].options != NULL) {
+ PyMem_Free(filters[i].options);
+ filters[i].options = NULL;
+ }
+}
+
+#define DEFAULT_OPTIONS_STRING \
+"compresslevel=6, format='xz', check='crc64', threads=1, filter=({'id':'lzma2',\n"\
+"'extreme':False, 'dict_size':23, 'lc':3 'lp':0, 'pb':2, 'mode':2,\n"\
+"'nice_len':128, 'mf':'bt4', 'depth':0})"
+
+PyDoc_STRVAR(LZMAOptions__doc__,
+"This class describes the different LZMA compression options and holds the\n\
+different min and max value constants for these in the variables.\n\
+\n\
+\n");
+
+static PyMemberDef LZMAOptions_members[16];
+
+static LZMAOptionsObject *Options = NULL;
+
+static PyObject *
+LZMAOptions_repr(LZMAOptionsObject *obj)
+{
+ return PyUnicode_FromFormat("%s singleton for accessing descriptors",
+ Py_TYPE(obj)->tp_name);
+}
+
+static void
+LZMAOptions_decref(LZMAOptionsObject* self)
+{
+ Py_XDECREF(self->format);
+ Py_XDECREF(self->check);
+ Py_XDECREF(self->check_dict);
+ Py_XDECREF(self->filter_dict);
+ Py_XDECREF(self->filter_dictSwap);
+ Py_XDECREF(self->filter);
+ Py_XDECREF(self->compresslevel);
+ Py_XDECREF(self->dict_size);
+ Py_XDECREF(self->lc);
+ Py_XDECREF(self->lp);
+ Py_XDECREF(self->pb);
+ Py_XDECREF(self->mode_dict);
+ Py_XDECREF(self->mode_dictSwap);
+ Py_XDECREF(self->mode);
+ Py_XDECREF(self->nice_len);
+ Py_XDECREF(self->mf_dict);
+ Py_XDECREF(self->mf_dictSwap);
+ Py_XDECREF(self->mf);
+ Py_XDECREF(self->depth);
+ Py_XDECREF(self->dist);
+ Py_XDECREF(self->start);
+ Py_XDECREF(self->threads);
+}
+
+static void
+LZMAOptions_dealloc(LZMAOptionsObject* self)
+{
+ LZMAOptions_decref(self);
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject *
+LZMA_options_get(lzma_filter *filters, LZMAOptionsObject *optionsObj)
+{
+ Py_ssize_t size;
+ PyObject *filtersTuple;
+
+ for(size = 0; size <= LZMA_FILTERS_MAX; size++)
+ if(filters[size].id == LZMA_VLI_UNKNOWN)
+ break;
+ filtersTuple = PyTuple_New(size);
+ for(size--; size >= 0; size--) {
+ PyObject *filter = PyDict_New();
+ switch(filters[size].id) {
+ case LZMA_FILTER_LZMA1:
+ case LZMA_FILTER_LZMA2: {
+ lzma_options_lzma lzma_options;
+
+ lzma_options = *((lzma_options_lzma*)filters[size].options);
+ if(PyDict_SetItemString(filter, "dict_size",
+ PyLong_FromLong((long)lzma_options.dict_size)) ||
+ PyDict_SetItemString(filter, "lc",
+ PyLong_FromLong((long)lzma_options.lc)) ||
+ PyDict_SetItemString(filter, "lp",
+ PyLong_FromLong((long)lzma_options.lp)) ||
+ PyDict_SetItemString(filter, "pb",
+ PyLong_FromLong((long)lzma_options.pb)) ||
+ PyDict_SetItemString(filter, "mode",
+ PyDict_GetItem(optionsObj->mode_dictSwap,
+ PyLong_FromLong((long)lzma_options.mode))) ||
+ PyDict_SetItemString(filter, "nice_len",
+ PyLong_FromLong((long)lzma_options.nice_len)) ||
+ PyDict_SetItemString(filter, "mf",
+ PyDict_GetItem(optionsObj->mf_dictSwap,
+ PyLong_FromLong((long)lzma_options.mf))) ||
+ PyDict_SetItemString(filter, "depth",
+ PyLong_FromLong((long)lzma_options.depth)))
+ goto error;
+ break;
+ }
+ case LZMA_FILTER_X86:
+ case LZMA_FILTER_POWERPC:
+ case LZMA_FILTER_ARM:
+ case LZMA_FILTER_ARMTHUMB:
+ case LZMA_FILTER_SPARC: {
+ lzma_options_bcj bcj_options;
+
+ bcj_options = *((lzma_options_bcj*)filters[size].options);
+ if(PyDict_SetItemString(filter, "start",
+ PyLong_FromLong((long)bcj_options.start_offset)))
+ goto error;
+ break;
+ }
+ case LZMA_FILTER_DELTA: {
+ lzma_options_delta delta_options;
+
+ delta_options = *((lzma_options_delta*)filters[size].options);
+ if(delta_options.type == LZMA_DELTA_TYPE_BYTE)
+ if(PyDict_SetItemString(filter, "type",
+ PyUnicode_FromString("byte")))
+ goto error;
+ if(PyDict_SetItemString(filter, "dist",
+ PyLong_FromLong((long)delta_options.dist)))
+ goto error;
+ break;
+ }
+ /*case LZMA_FILTER_SUBBLOCK:*/
+ default:
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromFormat(
+ "'%d' unknown filter", filters[size].id));
+ }
+ if(PyDict_SetItemString(filter, "id", PyDict_GetItem(
+ optionsObj->filter_dictSwap,
+ PyLong_FromLong((long)filters[size].id))))
+ goto error;
+ Py_INCREF(filter);
+ PyTuple_SetItem(filtersTuple, size, filter);
+ }
+ Py_INCREF(filtersTuple);
+
+ return filtersTuple;
+error:
+ return NULL;
+}
+
+static int
+init_delta_filter(const char *funcName, PyObject *args,
+ PyObject *kwargs, void **optionsPtr)
+{
+ char argString[64];
+ static char *kwlist[] = {"type", "dist"};
+ PyObject *type = NULL;
+ int ret = 0;
+ lzma_options_delta *options;
+
+ options = *optionsPtr = PyMem_Malloc(sizeof(lzma_options_delta));
+
+ options->type = LZMA_DELTA_TYPE_BYTE;
+ options->dist = LZMA_DELTA_DIST_MIN;
+
+ PyOS_snprintf(argString, sizeof(argString), "|Ui:%s", funcName);
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, argString, kwlist, &type, &options->dist))
+ goto end;
+ CHECK_RANGE(options->dist, LZMA_DELTA_DIST_MIN, LZMA_DELTA_DIST_MAX,
+ "dist must be between %d and %d, got %d");
+ if(type){
+ /* There's only one type supported for now, but let's add support for setting the type
+ * anyways for future compatibility in case of support for addtional types gets added
+ */
+ if(PyUnicode_CompareWithASCIIString(type, "byte") == 0)
+ options->type = LZMA_DELTA_TYPE_BYTE;
+ else {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromString("Only byte-wise delta ('byte') is currently "
+ "supported for type of delta calculation"));
+ goto end;
+ }
+ }
+
+ ret = 1;
+end:
+ return ret;
+}
+
+static int
+init_bcj_filter(const char *funcName, PyObject *args, PyObject *kwargs,
+ void **optionsPtr)
+{
+ char argString[64];
+ static char *kwlist[] = {"start"};
+ lzma_options_bcj *options;
+
+ options = *optionsPtr = PyMem_Malloc(sizeof(lzma_options_bcj));
+
+ options->start_offset = 0;
+
+ PyOS_snprintf(argString, sizeof(argString), "|i:%s", funcName);
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, argString, kwlist,
+ &options->start_offset))
+ return 0;
+
+ return 1;
+}
+
+static int
+init_lzma_filter(const char *funcName, PyObject *args, PyObject *kwargs,
+ int compresslevel, void **optionsPtr)
+{
+ PyObject *mf_key = NULL, *mode_key = NULL;
+ char argString[64];
+ static char *kwlist[] = {"dict_size", "lc", "lp", "pb", "nice_len",
+ "depth", "mode", "mf", NULL};
+ int ret = 0;
+ lzma_options_lzma *options;
+
+ options = *optionsPtr = PyMem_Malloc(sizeof(lzma_options_lzma));
+
+ CHECK_RANGE(compresslevel, LZMA_BEST_SPEED, LZMA_BEST_COMPRESSION,
+ "compresslevel must be between %d and %d, got %d");
+
+ if(kwargs != NULL) {
+ if(PyMapping_HasKeyString(kwargs, "extreme")){
+ if(PyBool_Check(PyDict_GetItemString(kwargs, "extreme")))
+ compresslevel |= LZMA_PRESET_EXTREME;
+ PyDict_DelItemString(kwargs, "extreme");
+ }
+ }
+
+ lzma_lzma_preset(options, compresslevel);
+ if(kwargs == NULL)
+ return 1;
+
+ PyOS_snprintf(argString, sizeof(argString), "|iiiiiiUU:%s", funcName);
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, argString, kwlist,
+ &options->dict_size, &options->lc, &options->lp, &options->pb,
+ &options->nice_len, &options->depth, &mode_key, &mf_key))
+ goto end;
+
+ CHECK_RANGE(options->dict_size, LZMA_DICT_SIZE_MIN, LZMA_DICT_SIZE_MAX,
+ "dict_size must be between %d and %d, got %d");
+ CHECK_RANGE(options->lc, LZMA_LCLP_MIN, LZMA_LCLP_MAX,
+ "lc must be between %d and %d, got %d");
+ CHECK_RANGE(options->lp, LZMA_LCLP_MIN, LZMA_LCLP_MAX,
+ "lp must be between %d and %d, got %d");
+ CHECK_RANGE(options->pb, LZMA_PB_MIN, LZMA_PB_MAX,
+ "pb must be between %d and %d, got %d");
+ CHECK_RANGE(options->nice_len, LZMA_NICE_LEN_MIN, LZMA_NICE_LEN_MAX,
+ "nice_len must be between %d and %d, got %d");
+ if((int)options->depth < 0){
+ PyErr_Format(PyExc_ValueError, "depth must be >= 0");
+ goto end;
+ }
+
+ if(mode_key) {
+ if(PyDict_Contains(Options->mode_dict, mode_key))
+ options->mode = PyLong_AsLong(PyDict_GetItem(Options->mode_dict,
+ mode_key));
+ else {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromFormat("mode invalid '%S'", mode_key));
+ goto end;
+ }
+ }
+ if(mf_key) {
+ if(PyDict_Contains(Options->mf_dict, mf_key))
+ options->mf = PyLong_AsLong(PyDict_GetItem(Options->mf_dict,
+ mf_key));
+ else {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromFormat("mf invalid '%S'", mf_key));
+ goto end;
+ }
+ }
+
+ ret = 1;
+end:
+ return ret;
+}
+
+/* This function is for parsing the options given for compression, since we
+ * have both a one shot compress function and a sequential compressor object
+ * class, we'll share this code amongst them.
+ */
+static int
+init_lzma_options(const char *funcName, lzma_filter *filters, lzma_check *check,
+ int compresslevel, PyObject *format, PyObject *myCheck,
+ int threads, PyObject *filter)
+{
+ PyObject *args = NULL;
+ int ret = 0;
+ Py_ssize_t filterSize = 1;
+
+ filters[0].id = filters[1].id = filters[2].id = filters[3].id =
+ LZMA_VLI_UNKNOWN;
+ filters[0].options = filters[1].options = filters[2].options =
+ filters[3].options = NULL;
+
+ /* We create an empty tuple since we only want to parse keywords */
+ args = PyTuple_New(0);
+
+ if(format){
+ if(PyDict_Contains(Options->format_dict, format)) {
+ PyObject *formatTuple = PyDict_GetItem(Options->format_dict,
+ format);
+ filters[0].id = PyLong_AsLong(PyTuple_GetItem(formatTuple,0));
+ *check = PyLong_AsLong(PyTuple_GetItem(formatTuple,1));
+ }
+ else {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromFormat("Unsupported format '%S'",
+ format));
+ goto end;
+ }
+ }
+ else {
+ PyObject *formatTuple = PyDict_GetItemString(Options->format_dict,
+ "xz");
+ filters[0].id = PyLong_AsLong(PyTuple_GetItem(formatTuple,0));
+ *check = PyLong_AsLong(PyTuple_GetItem(formatTuple,1));
+ }
+
+ if(myCheck){
+ if(filters[0].id == LZMA_FILTER_LZMA1 || *check == LZMA_CHECK_NONE) {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromFormat(
+ "Integrity checking not supported for '%S' format",
+ format));
+ return 0;
+
+ }
+ if(PyDict_Contains(Options->check_dict, myCheck))
+ *check = PyLong_AsLong(PyDict_GetItem(Options->check_dict,
+ myCheck));
+ else {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromFormat(
+ "Unsupported integrity check type '%s'",
+ myCheck));
+ return 0;
+ }
+ }
+
+ if(filter == NULL)
+ ret = init_lzma_filter(funcName, args, NULL, compresslevel,
+ &(filters[0].options));
+ else {
+ char filterString[64];
+ int i;
+ PyObject *filterDict[LZMA_FILTERS_MAX] = {NULL, NULL, NULL, NULL};
+
+ PyOS_snprintf(filterString, sizeof(filterString), "O|OOO:%s", funcName);
+
+ if(PyDict_Check(filter)) {
+ filterDict[0] = filter;
+ }
+ else if(PyTuple_Check(filter)) {
+ if(filters[0].id == LZMA_FILTER_LZMA1) {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromString(
+ "LZMA_Alone ('alone') format doesn't support multiple filters"));
+ goto end;
+ }
+
+ if (!PyArg_ParseTuple(filter, filterString, &filterDict[0],
+ &filterDict[1], &filterDict[2], &filterDict[3]))
+ goto end;
+ filterSize = PyTuple_Size(filter);
+ }
+
+ for(filter = filterDict[i = 0]; i < filterSize; filter = filterDict[++i])
+ {
+ PyObject *id = NULL;
+ ret = 0;
+
+ if(PyMapping_HasKeyString(filter, "id")){
+ id = PyDict_GetItemString(filter, "id");
+ PyDict_DelItemString(filter, "id");
+ }
+
+ if(id){
+ if(PyDict_Contains(Options->filter_dict, id)){
+ filters[i].id = PyLong_AsLong(PyDict_GetItem(
+ Options->filter_dict, id));
+ }
+ else {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromFormat(
+ "Unsupported filter: '%S'", id));
+ break;
+ }
+ if(format && PyUnicode_CompareWithASCIIString(
+ format, "alone") == 0) {
+ if(filters[i].id != LZMA_FILTER_LZMA1) {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromString(
+ "LZMA_Alone ('alone') format only supports 'lzma1' filter"));
+ break;
+ }
+ }
+ else {
+ if(filters[i].id == LZMA_FILTER_LZMA1) {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromString(
+ "Only LZMA_Alone ('alone') format supports 'lzma1' filter"));
+ break;
+ }
+ }
+ if(i != filterSize-1 && filters[i].id == LZMA_FILTER_LZMA2) {
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromString(
+ "'lzma2' filter may only be specified as the last filter"));
+ break;
+ }
+
+ }
+ switch(filters[i].id) {
+ case LZMA_FILTER_LZMA1:
+ case LZMA_FILTER_LZMA2:
+ ret = init_lzma_filter(funcName, args, filter,
+ compresslevel, &(filters[i].options));
+ break;
+ case LZMA_FILTER_X86:
+ case LZMA_FILTER_POWERPC:
+ case LZMA_FILTER_ARM:
+ case LZMA_FILTER_ARMTHUMB:
+ case LZMA_FILTER_SPARC:
+ ret = init_bcj_filter(funcName, args, filter,
+ &(filters[i].options));
+ break;
+ case LZMA_FILTER_DELTA:
+ ret = init_delta_filter(funcName, args, filter,
+ &(filters[i].options));
+ break;
+ /*case LZMA_FILTER_SUBBLOCK:*/
+ default:
+ PyErr_SetObject(PyExc_ValueError,
+ PyUnicode_FromFormat(
+ "Support for '%S' filter not implemented yet",
+ id));
+ }
+ if(!ret)
+ break;
+ }
+ }
+ filters[filterSize].id = LZMA_VLI_UNKNOWN;
+
+end:
+ Py_DECREF(args);
+ if(!ret)
+ free_lzma_options(filters);
+
+ return ret;
+}
+
+static PyObject *
+swapDict(PyObject *dict)
+{
+ PyObject *keys, *values, *newDict;
+ Py_ssize_t i;
+
+ keys = PyDict_Keys(dict);
+ values = PyDict_Values(dict);
+ newDict = PyDict_New();
+ for(i = PyDict_Size(dict)-1; i >= 0; i--) {
+ if(PyDict_SetItem(newDict, PyList_GetItem(values, i),
+ PyList_GetItem(keys, i)))
+ break;
+ }
+ Py_DECREF(keys);
+ Py_DECREF(values);
+
+ if(i < 0)
+ return newDict;
+
+ Py_DECREF(newDict);
+ return NULL;
+}
+
+static int
+dictSetItem_Sort(PyObject *dict, const char *key, PyObject *value,
+ PyObject **tuple)
+{
+ Py_ssize_t size = PyTuple_Size(*tuple);
+
+ if(PyDict_SetItemString(dict, key, value) ||
+ _PyTuple_Resize(tuple, size+1) ||
+ PyTuple_SetItem(*tuple, size, PyUnicode_FromString(key)))
+ return -1;
+
+ return 0;
+}
+
+/* Maybe not the best way, but it will at least prevent new instances.. */
+static PyObject *
+LZMAOptions_alloc(PyTypeObject *type, Py_ssize_t nitems)
+{
+ PyObject *compresslevelopts, *compresslevelString;
+ LZMAOptionsObject *self;
+
+ self = (LZMAOptionsObject*)PyType_GenericAlloc(type, nitems);
+ if(self == NULL)
+ return NULL;
+
+ self->format = self->check = self->check_dict = self->filter_dict =
+ self->filter_dictSwap = self->filter = self->compresslevel =
+ self->dict_size = self->lc = self->lp = self->pb = self->mode_dict =
+ self->mode_dictSwap = self->mode = self->nice_len = self->mf_dict =
+ self->mf_dictSwap = self->mf = self->depth = self->dist = self->start =
+ self->threads = NULL;
+
+ self->format_dict = PyDict_New();
+ self->format = PyTuple_New(0);
+ if(dictSetItem_Sort(self->format_dict, "xz", PyTuple_Pack(2,
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_LZMA2),
Martin v. Löwis 2010/10/31 16:33:38 This (and all other PyTuple_Pack calls) leak refer
+ PyLong_FromLong(LZMA_CHECK_CRC64)), &self->format) ||
+ dictSetItem_Sort(self->format_dict, "alone", PyTuple_Pack(2,
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_LZMA1),
+ PyLong_FromLong(LZMA_CHECK_NONE)), &self->format) ||
+ dictSetItem_Sort(self->format_dict, "raw", PyTuple_Pack(2,
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_LZMA2),
+ PyLong_FromLong((lzma_check)-1)), &self->format))
+ goto error;
+
+ self->check_dict = PyDict_New();
+ self->check = PyTuple_New(0);
+ if(dictSetItem_Sort(self->check_dict, "crc32",
+ PyLong_FromLong(LZMA_CHECK_CRC32), &self->check) ||
+ dictSetItem_Sort(self->check_dict, "crc64",
+ PyLong_FromLong(LZMA_CHECK_CRC64), &self->check) ||
+ dictSetItem_Sort(self->check_dict, "sha256",
+ PyLong_FromLong(LZMA_CHECK_SHA256), &self->check) ||
+ dictSetItem_Sort(self->check_dict, "none",
+ PyLong_FromLong((lzma_check)-1), &self->check))
+ goto error;
+
+ self->threads = PyTuple_Pack(2, PyLong_FromLong(1), PyLong_FromLong(1));
+
+ self->filter_dict = PyDict_New();
+ self->filter = PyTuple_New(0);
+ if(dictSetItem_Sort(self->filter_dict, "lzma1",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_LZMA1), &self->filter) ||
+ dictSetItem_Sort(self->filter_dict, "lzma2",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_LZMA2), &self->filter) ||
+ dictSetItem_Sort(self->filter_dict, "x86",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_X86), &self->filter) ||
+ dictSetItem_Sort(self->filter_dict, "powerpc",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_POWERPC), &self->filter) ||
+ dictSetItem_Sort(self->filter_dict, "ia64",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_IA64), &self->filter) ||
+ dictSetItem_Sort(self->filter_dict, "arm",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_ARM), &self->filter) ||
+ dictSetItem_Sort(self->filter_dict, "armthumb",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_ARMTHUMB), &self->filter) ||
+ dictSetItem_Sort(self->filter_dict, "sparc",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_SPARC), &self->filter) ||
+ dictSetItem_Sort(self->filter_dict, "delta",
+ PyLong_FromUnsignedLongLong(LZMA_FILTER_DELTA), &self->filter))
+ goto error;
+ self->filter_dictSwap = swapDict(self->filter_dict);
+
+ self->compresslevel = PyTuple_Pack(2, PyLong_FromLong(LZMA_BEST_SPEED),
+ PyLong_FromLong(LZMA_BEST_COMPRESSION));
+ self->dict_size = PyTuple_Pack(2, PyLong_FromLong(LZMA_DICT_SIZE_MIN),
+ PyLong_FromLong(LZMA_DICT_SIZE_MAX));
+ self->lc = PyTuple_Pack(2, PyLong_FromLong(LZMA_LCLP_MIN),
+ PyLong_FromLong(LZMA_LCLP_MAX));
+ self->lp = PyTuple_Pack(2, PyLong_FromLong(LZMA_LCLP_MIN),
+ PyLong_FromLong(LZMA_LCLP_MAX));
+ self->pb = PyTuple_Pack(2, PyLong_FromLong(LZMA_PB_MIN),
+ PyLong_FromLong(LZMA_PB_MAX));
+ self->nice_len = PyTuple_Pack(2, PyLong_FromLong(LZMA_NICE_LEN_MIN),
+ PyLong_FromLong(LZMA_NICE_LEN_MAX));
+ self->depth = PyLong_FromLong(0);
+
+ self->mode_dict = PyDict_New();
+ self->mode = PyTuple_New(0);
+ if(dictSetItem_Sort(self->mode_dict, "fast",
+ PyLong_FromLong(LZMA_MODE_FAST), &self->mode) ||
+ dictSetItem_Sort(self->mode_dict, "normal",
+ PyLong_FromLong(LZMA_MODE_NORMAL), &self->mode))
+ goto error;
+ self->mode_dictSwap = swapDict(self->mode_dict);
+
+ self->mf_dict = PyDict_New();
+ self->mf = PyTuple_New(0);
+ if(dictSetItem_Sort(self->mf_dict, "hc3",
+ PyLong_FromLong(LZMA_MF_HC3), &self->mf) ||
+ dictSetItem_Sort(self->mf_dict, "hc4",
+ PyLong_FromLong(LZMA_MF_HC4), &self->mf) ||
+ dictSetItem_Sort(self->mf_dict, "bt2",
+ PyLong_FromLong(LZMA_MF_BT2), &self->mf) ||
+ dictSetItem_Sort(self->mf_dict, "bt3",
+ PyLong_FromLong(LZMA_MF_BT3), &self->mf) ||
+ dictSetItem_Sort(self->mf_dict, "bt4",
+ PyLong_FromLong(LZMA_MF_BT4), &self->mf))
+ goto error;
+ self->mf_dictSwap = swapDict(self->mf_dict);
+
+
+ self->dist = PyTuple_Pack(2, PyLong_FromLong(LZMA_DELTA_DIST_MIN),
+ PyLong_FromLong(LZMA_DELTA_DIST_MAX));
+ self->start = PyLong_FromLong(0);
+
+ Py_INCREF(self);
+
+ compresslevelString = PyBytes_FromString(
+ "Compression preset level (%u - %u, LZMA)\n"
+ "This will automatically set the values for the various compression options.\n"
+ "Setting any of the other compression options at the same time as well will\n"
+ "override the specific value set by this preset level.\n"
+ "\n"
+ "Preset level settings:\n"
+ "compresslevel\t lc\t lp\t pb\t mode\t mf\t nice_len\t depth\t dict_size\n");
+ compresslevelopts = PyUnicode_FromString(
+ "%d\t\t %u\t %u\t %u\t %s\t %s\t %u\t\t %u\t %u\n");
+
+ {
+ int compresslevelNum;
+ lzma_options_lzma options;
+ lzma_filter filter[LZMA_FILTERS_MAX + 1];
+
+ filter[0].id = LZMA_FILTER_LZMA2;
+ filter[0].options = &options;
+ filter[1].id = LZMA_VLI_UNKNOWN;
+
+ for(compresslevelNum = LZMA_BEST_COMPRESSION;
+ compresslevelNum >= LZMA_BEST_SPEED;
+ compresslevelNum--){
+ PyObject *filters_tuple,
+ *options_dict,
+ *options_tuple,
+ *settingsUnicode,
+ *settingsAscii;
+
+ lzma_lzma_preset(&options, compresslevelNum);
+ filters_tuple = LZMA_options_get(filter, self);
+ options_dict = PyTuple_GetItem(filters_tuple, 0);
+ options_tuple = PyTuple_Pack(9,
+ PyLong_FromLong(compresslevelNum),
+ PyMapping_GetItemString(options_dict, "lc"),
+ PyMapping_GetItemString(options_dict, "lp"),
+ PyMapping_GetItemString(options_dict, "pb"),
+ PyMapping_GetItemString(options_dict, "mode"),
+ PyMapping_GetItemString(options_dict, "mf"),
+ PyMapping_GetItemString(options_dict, "nice_len"),
+ PyMapping_GetItemString(options_dict, "depth"),
+ PyMapping_GetItemString(options_dict, "dict_size"));
+
+ settingsUnicode = PyUnicode_Format(compresslevelopts, options_tuple);
+ settingsAscii = PyUnicode_AsASCIIString(settingsUnicode);
+ PyBytes_ConcatAndDel(&compresslevelString, settingsAscii);
+
+ Py_DECREF(options_tuple);
+ Py_DECREF(options_dict);
+ Py_DECREF(filters_tuple);
+ Py_DECREF(settingsUnicode);
+ }}
+ Py_DECREF(compresslevelopts);
+ LZMAOptions_members[0] = MEMBER_DESCRIPTOR("format", T_OBJECT, format,
+ "File format to use for compression:\n"
+ "'%s': XZ format used by new xz tool. (default)\n"
+ "'%s': LZMA_Alone format used by older lzma utils.\n"
+ "'%s': Raw format.\n");
+ LZMAOptions_members[1] = MEMBER_DESCRIPTOR("check", T_OBJECT, check,
+ "Type of integrity check to use (XZ format only):\n"
+ "'%s': CRC32 using the polynomial from the IEEE 802.3 standard.\n"
+ "'%s': CRC64 using the polynomial from the ECMA-182 standard. (default)\n"
+ "'%s': SHA-256.\n"
+ "'%s': Don't use any integrity check.\n");
+ LZMAOptions_members[2] = MEMBER_DESCRIPTOR("threads", T_OBJECT, threads,
+ "Number of threads used for compression.\n"
+ "A value of 0 means one thread per available CPU.\n"
+ "\n"
+ "Default: %d\n"
+ "Available CPUs: %d\n"
+ "\n"
+ "This feature is currently not implemented yet.\n");
+ LZMAOptions_members[3] = MEMBER_DESCRIPTOR("id", T_OBJECT, filter,
+ "Filter id\n"
+ "Available filters:\n"
+ "'%s': LZMA1 [LZMA]\n"
+ "'%s': LZMA2 [LZMA]\n"
+ "'%s': x86 [BCJ]\n"
+ "'%s': PowerPC (big endian only) [BCJ]\n"
+ "'%s': IA64 (Itanium) [BCJ]\n"
+ "'%s': ARM (little endian only) [BCJ]\n"
+ "'%s': ARM-Thumb (little endian only) [BCJ]\n"
+ "'%s': SPARC [BCJ]\n"
+ "'%s': Delta [Delta]\n");
+ LZMAOptions_members[4] = MEMBER_DESCRIPTOR("compresslevel", T_OBJECT,
+ compresslevel, PyBytes_AsString(compresslevelString));
+ LZMAOptions_members[5] = MEMBER_DESCRIPTOR("dict_size", T_OBJECT, dict_size,
+ "Dictionary size in bytes (%u - %u, LZMA)\n"
+ "Dictionary size indicates how many bytes of the recently processed\n"
+ "uncompressed data is kept in memory. One method to reduce size of\n"
+ "the uncompressed data is to store distance-length pairs, which\n"
+ "indicate what data to repeat from the dictionary buffer. Thus,\n"
+ "the bigger the dictionary, the better compression ratio usually is.\n");
+ LZMAOptions_members[6] = MEMBER_DESCRIPTOR("lc", T_OBJECT, lc,
+ "Number of literal context bits (%u - %u, LZMA)\n"
+ "How many of the highest bits of the previous uncompressed\n"
+ "eight-bit byte (also known as `literal') are taken into\n"
+ "account when predicting the bits of the next literal.\n"
+ "\n"
+ "There is a limit that applies to literal context bits and literal\n"
+ "position bits together: lc + lp <= 4. Without this limit the\n"
+ "decoding could become very slow, which could have security related\n"
+ "results in some cases like email servers doing virus scanning.");
+ LZMAOptions_members[7] = MEMBER_DESCRIPTOR("lp", T_OBJECT, lp,
+ "Number of literal position bits (%u - %u, LZMA)\n"
+ "How many of the lowest bits of the current position (number\n"
+ "of bytes from the beginning of the uncompressed data) in the\n"
+ "uncompressed data is taken into account when predicting the\n"
+ "bits of the next literal (a single eight-bit byte).\n");
+ LZMAOptions_members[8] = MEMBER_DESCRIPTOR("pb", T_OBJECT, pb,
+ "Number of position bits Position bits (%u - %u, LZMA)\n"
+ "How many of the lowest bits of the current position in the\n"
+ "uncompressed data is taken into account when estimating\n"
+ "probabilities of matches. A match is a sequence of bytes for\n"
+ "which a matching sequence is found from the dictionary and\n"
+ "thus can be stored as distance-length pair.\n"
+ "\n"
+ "Example: If most of the matches occur at byte positions\n"
+ "of 8 * n + 3, that is, 3, 11, 19, ... set pb to 3,\n"
+ "because 2**3 == 8.\n");
+ LZMAOptions_members[9] = MEMBER_DESCRIPTOR("mode", T_OBJECT, mode,
+ "Available modes: ('%s' or '%s', LZMA).\n"
+ "Fast mode is usually at its best when combined with a hash chain match finder.\n"
+ "Best is usually notably slower than fast mode. Use this together with binary\n"
+ "tree match finders to expose the full potential of the LZMA encoder.");
+ LZMAOptions_members[10] = MEMBER_DESCRIPTOR("nice_len", T_OBJECT, nice_len,
+ "Nice length of a match (also known as number of fast bytes) (%u - %u, LZMA)\n"
+ "Nice length of match determines how many bytes the encoder\n"
+ "compares from the match candidates when looking for the best\n"
+ "match. Bigger fast bytes value usually increase both compression\n"
+ "ratio and time.\n");
+ LZMAOptions_members[11] = MEMBER_DESCRIPTOR("mf", T_OBJECT, mf,
+ "Match Finder (LZMA)\n"
+ "Match finder has major effect on both speed and compression ratio.\n"
+ "Usually hash chains are faster than binary trees.\n"
+ "Available match finders:\n"
+ "'%s': Binary Tree with 2 bytes hashing\n"
+ "Memory requirements: 9.5 * dict_size + 4 MiB\n"
+ "'%s': Binary Tree with 3 bytes hashing\n"
+ "Memory requirements: 11.5 * dict_size + 4 MiB\n"
+ "'%s': Binary Tree with 4 bytes hashing\n"
+ "Memory requirements: 11.5 * dict_size + 4 MiB\n"
+ "'%s': Hash Chain with 3 bytes hashing\n"
+ "'%s': Hash Chain with 4 bytes hashing\n"
+ "Memory requirements: 7.5 * dict_size + 4 MiB\n");
+ LZMAOptions_members[12] = MEMBER_DESCRIPTOR("depth", T_OBJECT, depth,
+ "Depth (also known as match finder cycles, LZMA)\n"
+ "Higher values give slightly better compression ratio but\n"
+ "decrease speed. Use special value %u to let liblzma use\n"
+ "match-finder-dependent default value.\n");
+ LZMAOptions_members[13] = MEMBER_DESCRIPTOR("dist", T_OBJECT, dist,
+ "Delta distance (%u - %u, Delta)\n"
+ "With the only currently supported type, 'bytes',\n"
+ "the distance is as bytes.\n"
+ "\n"
+ "Examples:\n"
+ "- 16-bit stereo audio: distance = 4 bytes\n"
+ "- 24-bit RGB image data: distance = 3 bytes\n"
+ "\n"
+ "Default: 1\n");
+ LZMAOptions_members[14] = MEMBER_DESCRIPTOR("start", T_OBJECT, start,
+ "Start offset for conversions (BCJ)\n"
+ "This setting is useful only when the same filter is used\n"
+ "_separately_ for multiple sections of the same executable file,\n"
+ "and the sections contain cross-section branch/call/jump\n"
+ "instructions. In that case it is benefical to set the start\n"
+ "offset of the non-first sections so that the relative addresses\n"
+ "of the cross-section branch/call/jump instructions will use the\n"
+ "same absolute addresses as in the first section.\n"
+ "\n"
+ "Default: %u\n");
+
+ LZMAOptions_members[15] = memberDef(NULL, 0, 0, 0, NULL); /* sentinel */
+
+ Py_DECREF(compresslevelString);
+ return (PyObject*)self;
+
+error:
+ LZMAOptions_decref(self);
+ return NULL;
+}
+
+/* Don't allow messing with this data.. */
+static int
+LZMAOptions_setattr(LZMAOptionsObject *self, const char *name)
+{
+ (void)PyErr_Format(PyExc_RuntimeError, "Read-only attribute: %s\n", name);
+ return -1;
+}
+
+static PyTypeObject LZMAOptions_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "lzma.LZMAOptions", /*tp_name*/
+ sizeof(LZMAOptionsObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)LZMAOptions_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ (setattrfunc)LZMAOptions_setattr, /*tp_setattr*/
+ 0, /*tp_reserved*/
+ (reprfunc)LZMAOptions_repr, /*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*/
+ 0, /*tp_flags*/
+ LZMAOptions__doc__, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ 0, /*tp_methods*/
+ LZMAOptions_members, /*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*/
+ LZMAOptions_alloc, /*tp_alloc*/
+ 0, /*tp_new*/
+ 0, /*tp_free*/
+ 0, /*tp_is_gc*/
+ 0, /*tp_bases*/
+ 0, /*tp_mro*/
+ 0, /*tp_cache*/
+ 0, /*tp_subclasses*/
+ 0, /*tp_weaklist*/
+ 0, /*tp_del*/
+ 0 /*tp_version_tag*/
+};
+
+/* ===================================================================== */
+/* Methods of LZMAFile. */
+
+PyDoc_STRVAR(LZMAFile_read__doc__,
+"read([size]) -> string\n\
+\n\
+Read at most size uncompressed bytes, returned as a string. If the size\n\
+argument is negative or omitted, read until EOF is reached.\n\
+");
+
+/* This is a hacked version of Python's fileobject.c:file_read(). */
+static PyObject *
+LZMAFile_read(LZMAFileObject *self, PyObject *args)
+{
+ long bytesrequested = -1;
+ size_t bytesread, buffersize, chunksize;
+ lzma_ret lzuerror = LZMA_OK;
+ PyObject *ret = NULL;
+
+ if (!PyArg_ParseTuple(args, "|l:read", &bytesrequested))
+ return NULL;
+
+ ACQUIRE_LOCK(self);
+ switch (self->mode) {
+ case MODE_READ:
+ break;
+ case MODE_READ_EOF:
+ ret = PyBytes_FromStringAndSize("", 0);
+ goto cleanup;
+ case MODE_CLOSED:
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ goto cleanup;
+ default:
+ PyErr_SetString(PyExc_IOError,
+ "file is not ready for reading");
+ goto cleanup;
+ case MODE_WRITE:
+ break;
+ }
+
+ /* refuse to mix with f.next() */
+ if (check_iterbuffered(self))
+ goto cleanup;
+
+ if (bytesrequested < 0)
+ buffersize = Util_NewBufferSize((size_t)0);
+ else
+ buffersize = bytesrequested;
+ if (buffersize > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "requested number of bytes is "
+ "more than a Python string can hold");
+ goto cleanup;
+ }
+ ret = PyBytes_FromStringAndSize((char *)NULL, buffersize);
+ if (ret == NULL || buffersize == 0)
+ goto cleanup;
+ bytesread = 0;
+
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ chunksize = lzma_read(&lzuerror, self->fp,
+ BUF(ret)+bytesread,
+ buffersize-bytesread);
+ self->pos += chunksize;
+ Py_END_ALLOW_THREADS
+ bytesread += chunksize;
+ if (lzuerror == LZMA_STREAM_END) {
+ self->size = self->pos;
+ self->mode = MODE_READ_EOF;
+ break;
+ } else if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &self->fp->strm, self->fp->encoding);
+ Py_DECREF(ret);
+ ret = NULL;
+ goto cleanup;
+ }
+ if (bytesrequested < 0) {
+ buffersize = Util_NewBufferSize(buffersize);
+ if (_PyBytes_Resize(&ret, buffersize) < 0) {
+ ret = NULL;
+ goto cleanup;
+ }
+ } else {
+ break;
+ }
+ }
+ if (bytesread != buffersize) {
+ if (_PyBytes_Resize(&ret, bytesread) < 0) {
+ ret = NULL;
+ }
+ }
+
+cleanup:
+ RELEASE_LOCK(self);
+ return ret;
+}
+
+
+PyDoc_STRVAR(LZMAFile_readline__doc__,
+"readline([size]) -> string\n\
+\n\
+Return the next line from the file, as a string, retaining newline.\n\
+A non-negative size argument will limit the maximum number of bytes to\n\
+return (an incomplete line may be returned then). Return an empty\n\
+string at EOF.\n\
+");
+
+static PyObject *
+LZMAFile_readline(LZMAFileObject *self, PyObject *args)
+{
+ PyObject *ret = NULL;
+ int sizehint = -1;
+
+ if (!PyArg_ParseTuple(args, "|i:readline", &sizehint))
+ return NULL;
+
+ ACQUIRE_LOCK(self);
+ switch (self->mode) {
+ case MODE_READ:
+ break;
+ case MODE_READ_EOF:
+ ret = PyBytes_FromStringAndSize("", 0);
+ goto cleanup;
+ case MODE_CLOSED:
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ goto cleanup;
+ case MODE_WRITE:
+ default:
+ PyErr_SetString(PyExc_IOError,
+ "file is not ready for reading");
+ goto cleanup;
+ }
+
+ /* refuse to mix with f.next() */
+ if (check_iterbuffered(self))
+ goto cleanup;
+
+ if (sizehint == 0)
+ ret = PyBytes_FromStringAndSize("", 0);
+ else
+ ret = Util_GetLine(self, (sizehint < 0) ? 0 : sizehint);
+
+cleanup:
+ RELEASE_LOCK(self);
+ return ret;
+}
+
+PyDoc_STRVAR(LZMAFile_readlines__doc__,
+"readlines([size]) -> list\n\
+\n\
+Call readline() repeatedly and return a list of lines read.\n\
+The optional size argument, if given, is an approximate bound on the\n\
+total number of bytes in the lines returned.\n\
+");
+
+/* This is a hacked version of Python's fileobject.c:file_readlines(). */
+static PyObject *
+LZMAFile_readlines(LZMAFileObject *self, PyObject *args)
+{
+ long sizehint = 0;
+ PyObject *list = NULL;
+ PyObject *line;
+ char small_buffer[SMALLCHUNK];
+ char *buffer = small_buffer;
+ size_t buffersize = SMALLCHUNK;
+ PyObject *big_buffer = NULL;
+ size_t nfilled = 0;
+ size_t nread;
+ size_t totalread = 0;
+ char *p, *q, *end;
+ int err;
+ int shortread = 0;
+ lzma_ret lzuerror = LZMA_OK;
+
+ if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint))
+ return NULL;
+
+ ACQUIRE_LOCK(self);
+ switch (self->mode) {
+ case MODE_READ:
+ break;
+ case MODE_READ_EOF:
+ list = PyList_New(0);
+ goto cleanup;
+ case MODE_CLOSED:
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ goto cleanup;
+ case MODE_WRITE:
+ default:
+ PyErr_SetString(PyExc_IOError,
+ "file is not ready for reading");
+ goto cleanup;
+ }
+
+ /* refuse to mix with f.next() */
+ if (check_iterbuffered(self))
+ goto cleanup;
+
+ if ((list = PyList_New(0)) == NULL)
+ goto cleanup;
+
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ nread = lzma_read(&lzuerror, self->fp,
+ buffer+nfilled, buffersize-nfilled);
+ self->pos += nread;
+ Py_END_ALLOW_THREADS
+ if (lzuerror == LZMA_STREAM_END) {
+ self->size = self->pos;
+ self->mode = MODE_READ_EOF;
+ if (nread == 0) {
+ sizehint = 0;
+ break;
+ }
+ shortread = 1;
+ } else if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &self->fp->strm,
+ self->fp->encoding);
+error:
+ Py_DECREF(list);
+ list = NULL;
+ goto cleanup;
+ }
+ totalread += nread;
+ p = memchr(buffer+nfilled, '\n', nread);
+ if (!shortread && p == NULL) {
+ /* Need a larger buffer to fit this line */
+ nfilled += nread;
+ buffersize *= 2;
+ if (buffersize > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "line is longer than a Python string can hold");
+ goto error;
+ }
+ if (big_buffer == NULL) {
+ /* Create the big buffer */
+ big_buffer = PyBytes_FromStringAndSize(
+ NULL, buffersize);
+ if (big_buffer == NULL)
+ goto error;
+ buffer = PyBytes_AS_STRING(big_buffer);
+ memcpy(buffer, small_buffer, nfilled);
+ }
+ else {
+ /* Grow the big buffer */
+ if (_PyBytes_Resize(&big_buffer, buffersize) < 0){
+ big_buffer = NULL;
+ goto error;
+ }
+ buffer = PyBytes_AS_STRING(big_buffer);
+ }
+ continue;
+ }
+ end = buffer+nfilled+nread;
+ q = buffer;
+ while (p != NULL) {
+ /* Process complete lines */
+ p++;
+ line = PyBytes_FromStringAndSize(q, p-q);
+ if (line == NULL)
+ goto error;
+ err = PyList_Append(list, line);
+ Py_DECREF(line);
+ if (err != 0)
+ goto error;
+ q = p;
+ p = memchr(q, '\n', end-q);
+ }
+ /* Move the remaining incomplete line to the start */
+ nfilled = end-q;
+ memmove(buffer, q, nfilled);
+ if (sizehint > 0)
+ if (totalread >= (size_t)sizehint)
+ break;
+ if (shortread) {
+ sizehint = 0;
+ break;
+ }
+ }
+ if (nfilled != 0) {
+ /* Partial last line */
+ line = PyBytes_FromStringAndSize(buffer, nfilled);
+ if (line == NULL)
+ goto error;
+ if (sizehint > 0) {
+ /* Need to complete the last line */
+ PyObject *rest = Util_GetLine(self, 0);
+ if (rest == NULL) {
+ Py_DECREF(line);
+ goto error;
+ }
+ PyBytes_Concat(&line, rest);
+ Py_DECREF(rest);
+ if (line == NULL)
+ goto error;
+ }
+ err = PyList_Append(list, line);
+ Py_DECREF(line);
+ if (err != 0)
+ goto error;
+ }
+
+cleanup:
+ RELEASE_LOCK(self);
+ if (big_buffer) {
+ Py_DECREF(big_buffer);
+ }
+ return list;
+}
+
+PyDoc_STRVAR(LZMAFile_write__doc__,
+"write(data) -> None\n\
+\n\
+Write the 'data' string to file. Note that due to buffering, close() may\n\
+be needed before the file on disk reflects the data written.\n\
+");
+
+/* This is a hacked version of Python's fileobject.c:file_write(). */
+static PyObject *
+LZMAFile_write(LZMAFileObject *self, PyObject *args)
+{
+ PyObject *ret = NULL;
+ Py_buffer pbuf;
+ char *buf;
+ Py_ssize_t len;
+ lzma_ret lzuerror = LZMA_OK;
+
+ if (!PyArg_ParseTuple(args, "y*:write", &pbuf))
+ return NULL;
+ buf = pbuf.buf;
+ len = pbuf.len;
+
+ ACQUIRE_LOCK(self);
+ switch (self->mode) {
+ case MODE_WRITE:
+ break;
+
+ case MODE_CLOSED:
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ goto cleanup;
+
+ case MODE_READ_EOF:
+ case MODE_READ:
+ default:
+ PyErr_SetString(PyExc_IOError,
+ "file is not ready for writing");
+ goto cleanup;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ lzma_write (&lzuerror, self->fp, buf, len);
+ self->pos += len;
+ Py_END_ALLOW_THREADS
+
+ if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &self->fp->strm, self->fp->encoding);
+ goto cleanup;
+ }
+
+ Py_INCREF(Py_None);
+ ret = Py_None;
+
+cleanup:
+ PyBuffer_Release(&pbuf);
+ RELEASE_LOCK(self);
+ return ret;
+}
+
+PyDoc_STRVAR(LZMAFile_writelines__doc__,
+"writelines(sequence_of_strings) -> None\n\
+\n\
+Write the sequence of strings to the file. Note that newlines are not\n\
+added. The sequence can be any iterable object producing strings. This is\n\
+equivalent to calling write() for each string.\n\
+");
+
+/* This is a hacked version of Python's fileobject.c:file_writelines(). */
+static PyObject *
+LZMAFile_writelines(LZMAFileObject *self, PyObject *seq)
+{
+#define CHUNKSIZE 1000
+ PyObject *list = NULL;
+ PyObject *iter = NULL;
+ PyObject *ret = NULL;
+ PyObject *line;
+ int i, j, index, len, islist;
+ lzma_ret lzuerror = LZMA_OK;
+
+ ACQUIRE_LOCK(self);
+ switch (self->mode) {
+ case MODE_WRITE:
+ break;
+
+ case MODE_CLOSED:
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ goto error;
+
+ case MODE_READ:
+ case MODE_READ_EOF:
+ default:
+ PyErr_SetString(PyExc_IOError,
+ "file is not ready for writing");
+ goto error;
+ }
+
+ islist = PyList_Check(seq);
+ if (!islist) {
+ iter = PyObject_GetIter(seq);
+ if (iter == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "writelines() requires an iterable argument");
+ goto error;
+ }
+ list = PyList_New(CHUNKSIZE);
+ if (list == NULL)
+ goto error;
+ }
+
+ /* Strategy: slurp CHUNKSIZE lines into a private list,
+ checking that they are all strings, then write that list
+ without holding the interpreter lock, then come back for more. */
+ for (index = 0; ; index += CHUNKSIZE) {
+ if (islist) {
+ Py_XDECREF(list);
+ list = PyList_GetSlice(seq, index, index+CHUNKSIZE);
+ if (list == NULL)
+ goto error;
+ j = PyList_GET_SIZE(list);
+ }
+ else {
+ for (j = 0; j < CHUNKSIZE; j++) {
+ line = PyIter_Next(iter);
+ if (line == NULL) {
+ if (PyErr_Occurred())
+ goto error;
+ break;
+ }
+ PyList_SetItem(list, j, line);
+ }
+ }
+ if (j == 0)
+ break;
+
+ /* Check that all entries are indeed byte string. If not,
+ apply the same rules as for file.write() and
+ convert the rets to strings. This is slow, but
+ seems to be the only way since all conversion APIs
+ could potentially execute Python code. */
+ for (i = 0; i < j; i++) {
+ PyObject *v = PyList_GET_ITEM(list, i);
+
+ if (!PyBytes_Check(v)) {
+ const char *buffer;
+ Py_ssize_t len;
+ if (PyObject_AsCharBuffer(v, &buffer, &len)) {
+ PyErr_SetString(PyExc_TypeError,
+ "writelines() "
+ "argument must be "
+ "a sequence of "
+ "strings");
+ goto error;
+ }
+ line = PyBytes_FromStringAndSize(buffer,
+ len);
+ if (line == NULL)
+ goto error;
+ Py_DECREF(v);
+ PyList_SET_ITEM(list, i, line);
+ }
+ }
+
+ /* Since we are releasing the global lock, the
+ following code may *not* execute Python code. */
+ Py_BEGIN_ALLOW_THREADS
+ for (i = 0; i < j; i++) {
+ line = PyList_GET_ITEM(list, i);
+ len = PyBytes_GET_SIZE(line);
+ lzma_write (&lzuerror, self->fp,
+ PyBytes_AS_STRING(line), len);
+ if (lzuerror != LZMA_OK) {
+ Py_BLOCK_THREADS
+ Util_CatchLZMAError(lzuerror, &self->fp->strm,
+ self->fp->encoding);
+ goto error;
+ }
+ }
+ Py_END_ALLOW_THREADS
+
+ if (j < CHUNKSIZE)
+ break;
+ }
+
+ Py_INCREF(Py_None);
+ ret = Py_None;
+
+error:
+ RELEASE_LOCK(self);
+ Py_XDECREF(list);
+ Py_XDECREF(iter);
+ return ret;
+#undef CHUNKSIZE
+}
+
+PyDoc_STRVAR(LZMAFile_seek__doc__,
+"seek(offset [, whence]) -> None\n\
+\n\
+Move to new file position. Argument offset is a byte count. Optional\n\
+argument whence defaults to 0 (offset from start of file, offset\n\
+should be >= 0); other values are 1 (move relative to current position,\n\
+positive or negative), and 2 (move relative to end of file, usually\n\
+negative, although many platforms allow seeking beyond the end of a file).\n\
+\n\
+Note that seeking of lzma files is emulated, and depending on the parameters\n\
+the operation may be extremely slow.\n\
+");
+
+static PyObject *
+LZMAFile_seek(LZMAFileObject *self, PyObject *args)
+{
+ int where = 0;
+ PyObject *offobj;
+ Py_off_t offset;
+ char small_buffer[SMALLCHUNK];
+ char *buffer = small_buffer;
+ Py_ssize_t buffersize = SMALLCHUNK;
+ Py_off_t bytesread = 0;
+ size_t readsize;
+ int chunksize;
+ lzma_ret lzuerror = LZMA_OK;
+ PyObject *ret = NULL;
+
+ if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &where))
+ return NULL;
+#if !defined(HAVE_LARGEFILE_SUPPORT)
+ offset = PyLong_AsLong(offobj);
+#else
+ offset = PyLong_Check(offobj) ?
+ PyLong_AsLongLong(offobj) : PyLong_AsLong(offobj);
+#endif
+ if (PyErr_Occurred())
+ return NULL;
+
+ ACQUIRE_LOCK(self);
+ Util_DropReadAhead(self);
+ switch (self->mode) {
+ case MODE_READ:
+ case MODE_READ_EOF:
+ break;
+
+ case MODE_CLOSED:
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ goto cleanup;
+
+ case MODE_WRITE:
+ default:
+ PyErr_SetString(PyExc_IOError,
+ "seek works only while reading");
+ goto cleanup;
+ }
+
+ if (where == 2) {
+ if (self->size == -1) {
+ assert(self->mode != MODE_READ_EOF);
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ chunksize = lzma_read(&lzuerror, self->fp,
+ buffer, buffersize);
+ self->pos += chunksize;
+ Py_END_ALLOW_THREADS
+
+ bytesread += chunksize;
+ if (lzuerror == LZMA_STREAM_END) {
+ break;
+ } else if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &self->fp->strm,
+ self->fp->encoding);
+ goto cleanup;
+ }
+ }
+ self->mode = MODE_READ_EOF;
+ self->size = self->pos;
+ bytesread = 0;
+ }
+ offset = self->size + offset;
+ } else if (where == 1) {
+ offset = self->pos + offset;
+ }
+
+ /* Before getting here, offset must be the absolute position the file
+ * pointer should be set to. */
+
+ if (offset >= self->pos) {
+ /* we can move forward */
+ offset -= self->pos;
+ } else {
+ /* we cannot move back, so rewind the stream */
+ lzma_close(&lzuerror, self->fp);
+ if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &self->fp->strm, self->fp->encoding);
+ goto cleanup;
+ }
+ PyMem_Free(self->fp);
+ rewind(self->rawfp);
+ self->pos = 0;
+ self->fp = lzma_open(&lzuerror, self->filters, self->check,
+ self->rawfp, self->memlimit);
+ if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &self->fp->strm, self->fp->encoding);
+ goto cleanup;
+ }
+ self->mode = MODE_READ;
+ }
+
+ if (offset <= 0 || self->mode == MODE_READ_EOF )
+ goto exit;
+
+ /* Before getting here, offset must be set to the number of bytes
+ * to walk forward. */
+ for (;;) {
+ if (offset-bytesread > buffersize)
+ readsize = buffersize;
+ else
+ /* offset might be wider that readsize, but the result
+ * of the subtraction is bound by buffersize (see the
+ * condition above). buffersize is 8192. */
+ readsize = (size_t)(offset-bytesread);
+ Py_BEGIN_ALLOW_THREADS
+ chunksize = lzma_read(&lzuerror, self->fp, buffer, readsize);
+ self->pos += chunksize;
+ Py_END_ALLOW_THREADS
+ bytesread += chunksize;
+ if (lzuerror == LZMA_STREAM_END) {
+ self->size = self->pos;
+ self->mode = MODE_READ_EOF;
+ break;
+ } else if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &self->fp->strm, self->fp->encoding);
+ goto cleanup;
+ }
+ if (bytesread == offset)
+ break;
+ }
+
+exit:
+ Py_INCREF(Py_None);
+ ret = Py_None;
+
+cleanup:
+ RELEASE_LOCK(self);
+ return ret;
+}
+
+PyDoc_STRVAR(LZMAFile_tell__doc__,
+"tell() -> int\n\
+\n\
+Return the current file position, an integer (may be a long integer).\n\
+");
+
+static PyObject *
+LZMAFile_tell(LZMAFileObject *self, PyObject *args)
+{
+ PyObject *ret = NULL;
+
+ if (self->mode == MODE_CLOSED) {
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ goto cleanup;
+ }
+
+#if !defined(HAVE_LARGEFILE_SUPPORT)
+ ret = PyLong_FromLong(self->pos);
+#else
+ ret = PyLong_FromLongLong(self->pos);
+#endif
+
+cleanup:
+ return ret;
+}
+
+PyDoc_STRVAR(LZMAFile_close__doc__,
+"close() -> None or (perhaps) an integer\n\
+\n\
+Close the file. Sets data attribute .closed to true. A closed file\n\
+cannot be used for further I/O operations. close() may be called more\n\
+than once without error.\n\
+");
+
+static PyObject *
+LZMAFile_close(LZMAFileObject *self)
+{
+ PyObject *ret = NULL;
+ lzma_ret lzuerror = LZMA_OK;
+
+ if (self->mode == MODE_CLOSED) {
+ Py_RETURN_NONE;
+ }
+
+ ACQUIRE_LOCK(self);
+ lzma_close(&lzuerror, self->fp);
+ PyMem_Free(self->fp);
+ self->fp = NULL;
+ self->mode = MODE_CLOSED;
+ fclose(self->rawfp);
+ self->rawfp = NULL;
+ if (lzuerror == LZMA_OK || lzuerror == LZMA_STREAM_END) {
+ Py_INCREF(Py_None);
+ ret = Py_None;
+ }
+ else {
+ Util_CatchLZMAError(lzuerror, NULL, self->fp->encoding);
+ }
+
+ RELEASE_LOCK(self);
+ return ret;
+}
+
+PyDoc_STRVAR(LZMAFile_enter_doc,
+"__enter__() -> self.");
+
+static PyObject *
+LZMAFile_enter(LZMAFileObject *self)
+{
+ if (self->mode == MODE_CLOSED) {
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ return NULL;
+ }
+ Py_INCREF(self);
+ return (PyObject *) self;
+}
+
+PyDoc_STRVAR(LZMAFile_exit_doc,
+"__exit__(*excinfo) -> None. Closes the file.");
+
+static PyObject *
+LZMAFile_exit(LZMAFileObject *self, PyObject *args)
+{
+ PyObject *ret = PyObject_CallMethod((PyObject *) self, "close", NULL);
+
+ if (!ret)
+ /* If error occurred, pass through */
+ return NULL;
+ Py_DECREF(ret);
+ Py_RETURN_NONE;
+}
+
+static PyObject *LZMAFile_getiter(LZMAFileObject *self);
+
+static PyMethodDef LZMAFile_methods[] = {
+ {"read", (PyCFunction)LZMAFile_read, METH_VARARGS,
+ LZMAFile_read__doc__},
+ {"readline", (PyCFunction)LZMAFile_readline, METH_VARARGS,
+ LZMAFile_readline__doc__},
+ {"readlines", (PyCFunction)LZMAFile_readlines, METH_VARARGS,
+ LZMAFile_readlines__doc__},
+ {"write", (PyCFunction)LZMAFile_write, METH_VARARGS,
+ LZMAFile_write__doc__},
+ {"writelines", (PyCFunction)LZMAFile_writelines, METH_O,
+ LZMAFile_writelines__doc__},
+ {"seek", (PyCFunction)LZMAFile_seek, METH_VARARGS,
+ LZMAFile_seek__doc__},
+ {"tell", (PyCFunction)LZMAFile_tell, METH_NOARGS,
+ LZMAFile_tell__doc__},
+ {"close", (PyCFunction)LZMAFile_close, METH_NOARGS,
+ LZMAFile_close__doc__},
+ {"__enter__", (PyCFunction)LZMAFile_enter, METH_NOARGS,
+ LZMAFile_enter_doc},
+ {"__exit__", (PyCFunction)LZMAFile_exit, METH_VARARGS,
+ LZMAFile_exit_doc},
+ {NULL, NULL, 0, NULL} /* sentinel */
+};
+
+
+/* ===================================================================== */
+/* Getters and setters of LZMAFile. */
+
+static PyObject *
+LZMAFile_get_closed(LZMAFileObject *self, void *closure)
+{
+ return PyLong_FromLong(self->mode == MODE_CLOSED);
+}
+
+static PyGetSetDef LZMAFile_getset[] = {
+ {"closed", (getter)LZMAFile_get_closed, NULL,
+ "True if the file is closed", NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* sentinel */
+};
+
+
+/* ===================================================================== */
+/* Slot definitions for LZMAFile_Type. */
+
+static int
+LZMAFile_init(LZMAFileObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *name_obj = NULL, *myFilters = NULL,
+ *myFormat = NULL, *myCheck = NULL;
+ int compresslevel = LZMA_PRESET_DEFAULT, threads = 1;
+ char *name, *mode = "r";
+ int buffering = -1;
+ lzma_ret lzuerror = LZMA_OK;
+ static char *kwlist[] = {"name", "mode", "buffering", "compresslevel", "format",
+ "check", "threads", "filter", "memlimit", NULL};
+
+ self->filters[0].options = NULL;
+
+ self->size = -1;
+ self->memlimit = -1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|sKiUUiO:LZMAFile", kwlist,
+ PyUnicode_FSConverter, &name_obj,
+ &mode, &buffering, &compresslevel, &myCheck, &threads,
+ &self->memlimit, &myFilters))
+ return -1;
+ name = PyBytes_AsString(name_obj);
+
+ for (;;) {
+ int error = 0;
+
+ switch (*mode) {
+ case 'w':
+ if(!self->filters[0].options)
+ {
+ if(!init_lzma_options("LZMAFile", self->filters,
+ &self->check, compresslevel, myFormat, myCheck,
+ threads, myFilters)) {
+ Py_DECREF(name_obj);
+ return -1;
+ }
+ }
+ break;
+
+ case 'r':
+ if(self->filters[0].options)
+ error = 1;
+ case 'b':
+ break;
+
+ default:
+ error = 1;
+ break;
+ }
+ if (error) {
+ free_lzma_options(self->filters);
+ PyErr_Format(PyExc_ValueError,
+ "invalid mode char %c", *mode);
+ Py_DECREF(name_obj);
+ return -1;
+ }
+ mode++;
+ if (*mode == '\0')
+ break;
+ }
+
+ mode = self->filters[0].options ? "wb" : "rb";
+
+ self->rawfp = fopen(name, mode);
+ Py_DECREF(name_obj);
+ if (self->rawfp == NULL) {
+ PyErr_SetFromErrno(PyExc_IOError);
+ return -1;
+ }
+ /* XXX Ignore buffering */
+
+ /* From now on, we have stuff to dealloc, so jump to error label
+ * instead of returning */
+
+#ifdef WITH_THREAD
+ self->lock = PyThread_allocate_lock();
+ if (!self->lock) {
+ PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
+ goto error;
+ }
+#endif
+
+ self->fp = lzma_open(&lzuerror, self->filters, self->check, self->rawfp,
+ self->memlimit);
+
+ if (lzuerror != LZMA_OK) {
+ Util_CatchLZMAError(lzuerror, &self->fp->strm, self->fp->encoding);
+ goto error;
+ }
+
+ self->mode = self->filters[0].options ? MODE_WRITE : MODE_READ;
+
+ return 0;
+
+error:
+ fclose(self->rawfp);
+ self->rawfp = NULL;
+#ifdef WITH_THREAD
+ if (self->lock) {
+ PyThread_free_lock(self->lock);
+ self->lock = NULL;
+ }
+#endif
+ return -1;
+}
+
+static void
+LZMAFile_dealloc(LZMAFileObject *self)
+{
+ lzma_ret lzuerror = LZMA_OK;
+
+#ifdef WITH_THREAD
+ if (self->lock)
+ PyThread_free_lock(self->lock);
+#endif
+ lzma_close(&lzuerror, self->fp);
+ if(self->fp)
+ PyMem_Free(self->fp);
+ free_lzma_options(self->filters);
+ Util_DropReadAhead(self);
+ if (self->rawfp != NULL)
+ fclose(self->rawfp);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+/* This is a hacked version of Python's fileobject.c:file_getiter(). */
+static PyObject *
+LZMAFile_getiter(LZMAFileObject *self)
+{
+ if (self->mode == MODE_CLOSED) {
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ return NULL;
+ }
+ Py_INCREF((PyObject*)self);
+ return (PyObject *)self;
+}
+
+/* This is a hacked version of Python's fileobject.c:file_iternext(). */
+#define READAHEAD_BUFSIZE 8192
+static PyObject *
+LZMAFile_iternext(LZMAFileObject *self)
+{
+ PyObject* ret;
+
+ ACQUIRE_LOCK(self);
+ if (self->mode == MODE_CLOSED) {
+ RELEASE_LOCK(self);
+ PyErr_SetString(PyExc_ValueError,
+ "I/O operation on closed file");
+ return NULL;
+ }
+ ret = Util_ReadAheadGetLineSkip(self, 0, READAHEAD_BUFSIZE);
+ RELEASE_LOCK(self);
+ if (ret == NULL || PyBytes_GET_SIZE(ret) == 0) {
+ Py_XDECREF(ret);
+ return NULL;
+ }
+ return (PyObject *)ret;
+}
+
+/* ===================================================================== */
+/* LZMAFile_Type definition. */
+
+PyDoc_VAR(LZMAFile__doc__) =
+PyDoc_STR(
+"LZMAFile(name , mode='r', buffering=0, memlimit=-1,\n"
+DEFAULT_OPTIONS_STRING") -> file object\n\
+\n\
+Open a lzma file. The mode can be 'r' or 'w', for reading (default) or\n\
+writing. When opened for writing, the file will be created if it doesn't\n\
+exist, and truncated otherwise. If the buffering argument is given, 0 means\n\
+unbuffered, and larger numbers specify the buffer size.\n\
+Data read is always returned in bytes; data written ought to be bytes.\n\
+");
+
+static PyTypeObject LZMAFile_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "lzma.LZMAFile", /*tp_name*/
+ sizeof(LZMAFileObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)LZMAFile_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*/
+ PyObject_GenericGetAttr, /*tp_getattro*/
+ PyObject_GenericSetAttr, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ LZMAFile__doc__, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ (getiterfunc)LZMAFile_getiter, /*tp_iter*/
+ (iternextfunc)LZMAFile_iternext, /*tp_iternext*/
+ LZMAFile_methods, /*tp_methods*/
+ 0, /*tp_members*/
+ LZMAFile_getset, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ (initproc)LZMAFile_init, /*tp_init*/
+ PyType_GenericAlloc, /*tp_alloc*/
+ PyType_GenericNew, /*tp_new*/
+ PyObject_Free, /*tp_free*/
+ 0, /*tp_is_gc*/
+ 0, /*tp_bases*/
+ 0, /*tp_mro*/
+ 0, /*tp_cache*/
+ 0, /*tp_subclasses*/
+ 0, /*tp_weaklist*/
+ 0, /*tp_del*/
+ 0 /*tp_version_tag*/
+};
+
+/* ===================================================================== */
+/* Methods of LZMAComp. */
+
+PyDoc_STRVAR(LZMAComp_compress__doc__,
+"compress(data) -> string\n\
+\n\
+Feed the compressor object with data to compress sequently.\n\
+This function will return the header for the compressed string for the first\n\
+input provided, this header will be needed to concatenate with the rest of\n\
+the stream when flushing to have a proper stream able to be decompressed\n\
+again.\n");
+
+static PyObject *
+LZMAComp_compress(LZMACompObject *self, PyObject *args)
+{
+ Py_buffer pdata;
+ Py_ssize_t datasize, bufsize = SMALLCHUNK;
+ unsigned char *data;
+ unsigned long long totalout;
+ PyObject *ret = NULL;
+ lzma_stream *lzus = &self->lzus;
+ lzma_ret lzuerror = LZMA_OK;
+
+ INITCHECK
+ if (!PyArg_ParseTuple(args, "y*:compress", &pdata))
+ return NULL;
+ data = pdata.buf;
+ datasize = pdata.len;
+
+ if (datasize == 0) {
+ PyBuffer_Release(&pdata);
+ return PyBytes_FromStringAndSize("", 0);
+ }
+
+ ACQUIRE_LOCK(self);
+ if (!self->running) {
+ PyErr_SetString(PyExc_ValueError,
+ "this object was already flushed");
+ goto error;
+ }
+
+ if (!(ret = PyBytes_FromStringAndSize(NULL, bufsize)))
+ goto error;
+
+ lzus->avail_in = (size_t)datasize;
+ lzus->next_in = data;
+ lzus->avail_out = (size_t)bufsize;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret);
+
+ totalout = lzus->total_out;
+
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ lzuerror = lzma_code(lzus, LZMA_RUN);
+ Py_END_ALLOW_THREADS
+ if (!Util_CatchLZMAError(lzuerror, lzus, 1))
+ goto error;
+ if (lzus->avail_in == 0)
+ break; /* no more input data */
+ if (lzus->avail_out == 0) {
+ bufsize = Util_NewBufferSize(bufsize);
+ if (_PyBytes_Resize(&ret, bufsize) < 0)
+ goto error;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret) +
+ (lzus->total_out - totalout);
+ lzus->avail_out = (size_t)bufsize - (lzus->next_out -
+ (unsigned char *)PyBytes_AS_STRING(ret));
+ }
+ }
+
+ if (_PyBytes_Resize(&ret,
+ (Py_ssize_t)((Py_ssize_t)lzus->total_out -
+ (Py_ssize_t)totalout)) < 0)
+ goto error;
+
+ RELEASE_LOCK(self);
+ PyBuffer_Release(&pdata);
+ return ret;
+
+error:
+ RELEASE_LOCK(self);
+ PyBuffer_Release(&pdata);
+ Py_XDECREF(ret);
+ return NULL;
+}
+
+PyDoc_STRVAR(LZMAComp_flush__doc__,
+"flush(mode=LZMA_FINISH) -> string\n\
+\n\
+Returns a string containing any remaining compressed data.\n\
+\n\
+'mode' can be one of the constants LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH,\n\
+LZMA_FINISH; the default value used when mode is not specified is LZMA_FINISH.\n\
+If mode == LZMA_FINISH, the compressor object can no longer be used after\n\
+calling the flush() method. Otherwise, more data can still be compressed.\n");
+
+static PyObject *
+LZMAComp_flush(LZMACompObject *self, PyObject *args, PyObject *kwargs)
+{
+ Py_ssize_t bufsize = SMALLCHUNK;
+ PyObject *ret = NULL;
+ lzma_action flushmode = LZMA_FINISH;
+ unsigned long long totalout;
+ lzma_stream *lzus = &self->lzus;
+ lzma_ret lzuerror = LZMA_OK;
+
+ static char *kwlist[] = {"mode", NULL};
+
+ INITCHECK
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:flush", kwlist,
+ &flushmode))
+ return NULL;
+
+ ACQUIRE_LOCK(self);
+ if (!self->running) {
+ PyErr_SetString(PyExc_ValueError, "object was already flushed");
+ goto error;
+ }
+
+ switch(flushmode){
+ case(LZMA_SYNC_FLUSH):
+ case(LZMA_FULL_FLUSH):
+ if(self->filters[0].id == LZMA_FILTER_LZMA1) {
+ PyErr_Format(LZMAError,
+ "%d is not supported as flush mode for LZMA_Alone format",
+ flushmode);
+ goto error;
+ }
+ /* Flushing with LZMA_RUN is a no-op, so there's no point in
+ * doing any work at all; just return an empty string.
+ */
+ case(LZMA_RUN):
+ ret = PyBytes_FromStringAndSize(NULL, 0);
+ goto error;
+ case(LZMA_FINISH):
+ break;
+ default:
+ PyErr_Format(LZMAError, "Invalid flush mode: %d", flushmode);
+ goto error;
+ }
+
+ self->running = 0;
+ if (!(ret = PyBytes_FromStringAndSize(NULL, bufsize)))
+ goto error;
+
+ lzus->avail_in = 0;
+ lzus->avail_out = (size_t)bufsize;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret);
+
+ totalout = lzus->total_out;
+
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ lzuerror = lzma_code(lzus, flushmode);
+ Py_END_ALLOW_THREADS
+ if (!Util_CatchLZMAError(lzuerror, lzus, 1))
+ goto error;
+ if(lzuerror == LZMA_STREAM_END)
+ break; /* no more input data */
+ if (lzus->avail_out == 0) {
+ bufsize = Util_NewBufferSize(bufsize);
+ if (_PyBytes_Resize(&ret, bufsize) < 0)
+ goto error;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret) +
+ (lzus->total_out - totalout);;
+ lzus->avail_out = (size_t)bufsize -
+ (lzus->next_out - (unsigned char *)PyBytes_AS_STRING(ret));
+ }
+ }
+
+ if (lzus->avail_out != 0) {
+ if (_PyBytes_Resize(&ret,
+ (Py_ssize_t)((Py_ssize_t)lzus->total_out -
+ (Py_ssize_t)totalout)) < 0)
+ goto error;
+ }
+
+ RELEASE_LOCK(self);
+ return ret;
+
+error:
+ RELEASE_LOCK(self);
+ Py_XDECREF(ret);
+ return ret;
+}
+
+static PyMethodDef LZMAComp_methods[] =
+{
+ {"compress", (PyCFunction)LZMAComp_compress, METH_VARARGS,
+ LZMAComp_compress__doc__},
+ {"flush", (PyCFunction)LZMAComp_flush, METH_VARARGS|METH_KEYWORDS,
+ LZMAComp_flush__doc__},
+ {0, 0, 0, 0}
+};
+
+static int
+LZMAComp_init(LZMACompObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *myFilters = NULL, *myFormat = NULL, *myCheck = NULL;
+ int compresslevel = LZMA_PRESET_DEFAULT, threads = 1;
+ lzma_stream *lzus = &self->lzus;
+ lzma_ret lzuerror = LZMA_OK;
+ static char *kwlist[] = {"compresslevel", "format", "check", "threads",
+ "filter", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iUUiO:LZMACompressor",
+ kwlist, &compresslevel, &myFormat, &myCheck, &threads,
+ &myFilters))
+ return -1;
+
+ if(!init_lzma_options("LZMACompressor", self->filters, &self->check,
+ compresslevel, myFormat, myCheck, threads, myFilters))
+ goto error;
+
+#ifdef WITH_THREAD
+ self->lock = PyThread_allocate_lock();
+ if (!self->lock) {
+ PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
+ goto error;
+ }
+#endif
+
+ if(self->filters[0].id == LZMA_FILTER_LZMA1)
+ lzuerror = lzma_alone_encoder(lzus, self->filters[0].options);
+ else if(self->check == (lzma_check)-1)
+ lzuerror = lzma_raw_encoder(lzus, self->filters);
+ else
+ lzuerror = lzma_stream_encoder(lzus, self->filters, self->check);
+
+ if(!Util_CatchLZMAError(lzuerror, lzus, 1))
+ goto error;
+
+ self->is_initialised = 1;
+ self->running = 1;
+
+ return 0;
+
+error:
+#ifdef WITH_THREAD
+ if (self->lock) {
+ PyThread_free_lock(self->lock);
+ self->lock = NULL;
+ }
+#endif
+ return -1;
+}
+
+static PyObject *
+LZMACompObject_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ LZMACompObject *self;
+ self = (LZMACompObject *)type->tp_alloc(type, 0);
+ if (self != NULL){
+ lzma_stream tmp = LZMA_STREAM_INIT;
+
+ self->is_initialised = 0;
+ self->running = 0;
+ self->lzus = tmp;
+ self->filters[0].options = NULL;
+ self->check = LZMA_CHECK_NONE;
+ }
+ else
+ return NULL;
+
+ return (PyObject *)self;
+}
+
+static void
+LZMAComp_dealloc(LZMACompObject *self)
+{
+#ifdef WITH_THREAD
+ if (self->lock)
+ PyThread_free_lock(self->lock);
+#endif
+ if (self->is_initialised)
+ lzma_end(&self->lzus);
+ free_lzma_options(self->filters);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+PyDoc_STRVAR(LZMAComp__doc__,
+"LZMACompressor("DEFAULT_OPTIONS_STRING") -> compressor object\n\
+Create a new compressor object. This object may be used to compress\n\
+data sequentially. If you want to compress data in one shot, use the\n\
+compress() function instead.\n");
+
+static PyTypeObject LZMAComp_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "lzma.LZMACompressor", /*tp_name*/
+ sizeof(LZMACompObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)LZMAComp_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_reserved*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ PyObject_GenericGetAttr, /*tp_getattro*/
+ PyObject_GenericSetAttr, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ LZMAComp__doc__, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ LZMAComp_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*/
+ (initproc)LZMAComp_init, /*tp_init*/
+ PyType_GenericAlloc, /*tp_alloc*/
+ LZMACompObject_new, /*tp_new*/
+ PyObject_Free, /*tp_free*/
+ 0, /*tp_is_gc*/
+ 0, /*tp_bases*/
+ 0, /*tp_mro*/
+ 0, /*tp_cache*/
+ 0, /*tp_subclasses*/
+ 0, /*tp_weaklist*/
+ 0, /*tp_del*/
+ 0 /*tp_version_tag*/
+};
+
+/* ===================================================================== */
+/* Members of LZMADecomp. */
+
+PyDoc_STRVAR(LZMADecomp_decompress__doc__,
+"decompress(data, max_length=0) -> string\n\
+\n\
+Return a string containing the decompressed version of the data.\n\
+\n\
+After calling this function, some of the input data may still be stored in\n\
+internal buffers for later processing.\n\
+Call the flush() method to clear these buffers.\n\
+If the max_length parameter is specified then the return value will be\n\
+no longer than max_length. Unconsumed input data will be stored in\n\
+the unconsumed_tail data descriptor.");
+
+static PyObject *
+LZMADecomp_decompress(LZMADecompObject *self, PyObject *args, PyObject *kwargs)
+{
+ Py_buffer pdata;
+ Py_ssize_t datasize, oldbufsize, bufsize = SMALLCHUNK;
+ unsigned char *data;
+ unsigned long long start_total_out;
+ PyObject *ret = NULL;
+ lzma_stream *lzus = &self->lzus;
+ lzma_ret lzuerror = LZMA_OK;
+ static char *kwlist[] = {"data", "max_length", NULL};
+
+ INITCHECK
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|l:decompress", kwlist,
+ &pdata, &self->max_length))
+ return NULL;
+ data = pdata.buf;
+ datasize = pdata.len;
+
+ ACQUIRE_LOCK(self);
+ if (!self->running) {
+ PyErr_SetString(PyExc_EOFError,
+ "end of stream was already found");
+ goto error;
+ }
+
+ if (self->max_length < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "max_length must be greater than zero");
+ goto error;
+ }
+
+ /* limit amount of data allocated to max_length */
+ if (self->max_length && bufsize > self->max_length)
+ bufsize = self->max_length;
+
+ if(!(ret = PyBytes_FromStringAndSize(NULL, bufsize)))
+ goto error;
+
+ start_total_out = lzus->total_out;
+ lzus->avail_in = (size_t)datasize;
+ lzus->next_in = data;
+ lzus->avail_out = (size_t)bufsize;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret);
+
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ lzuerror = lzma_code(lzus, LZMA_RUN);
+ Py_END_ALLOW_THREADS
+
+ if (lzus->avail_in == 0 || lzus->avail_out != 0)
+ break; /* no more input data */
+
+ /* If max_length set, don't continue decompressing if we've already
+ * reached the limit.
+ */
+ if (self->max_length && bufsize >= self->max_length)
+ break;
+
+ /* otherwise, ... */
+ oldbufsize= bufsize;
+ bufsize = bufsize << 1;
+ if (self->max_length && bufsize > self->max_length)
+ bufsize = self->max_length;
+
+ if (_PyBytes_Resize(&ret, bufsize) < 0)
+ goto error;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret) + oldbufsize;
+ lzus->avail_out = (size_t)bufsize - (size_t)oldbufsize;
+ if(!Util_CatchLZMAError(lzuerror, lzus, 0))
+ goto error;
+ }
+
+ /* Not all of the compressed data could be accommodated in the output
+ * buffer of specified size. Return the unconsumed tail in an attribute.
+ */
+ if(self->max_length) {
+ Py_DECREF(self->unconsumed_tail);
+ self->unconsumed_tail = PyBytes_FromStringAndSize(
+ (const char *)lzus->next_in, (Py_ssize_t)lzus->avail_in);
+ if(!self->unconsumed_tail) {
+ goto error;
+ }
+ }
+
+ /* 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
+ * lzma_end, but the old behaviour of only calling it on flush() is
+ * preserved.
+ */
+ if (lzuerror == LZMA_STREAM_END) {
+ Py_XDECREF(self->unused_data); /* Free original empty string */
+ self->unused_data = PyBytes_FromStringAndSize(
+ (const char *)lzus->next_in, (Py_ssize_t)lzus->avail_in);
+ if (self->unused_data == NULL) {
+ goto error;
+ }
+ /* We will only get LZMA_BUF_ERROR if the output buffer was full
+ * but there wasn't more output when we tried again, so it is
+ * not an error condition.
+ */
+ } else if(!Util_CatchLZMAError(lzuerror, lzus, 0))
+ goto error;
+
+ if(_PyBytes_Resize(&ret, (Py_ssize_t)lzus->total_out -
+ (Py_ssize_t)start_total_out) < 0)
+ goto error;
+
+ RELEASE_LOCK(self);
+ PyBuffer_Release(&pdata);
+ return ret;
+
+error:
+ RELEASE_LOCK(self);
+ PyBuffer_Release(&pdata);
+ Py_XDECREF(ret);
+ return NULL;
+}
+
+PyDoc_STRVAR(LZMADecomp_flush__doc__,
+"flush(mode=LZMA_FINISH [, bufsize]) -> string\n\
+\n\
+Return a string containing any remaining decompressed data.\n\
+\n\
+If 'bufsize' is given, is the initial size of the output buffer.\n\
+\n\
+The decompressor object cannot be used again after this call.");
+
+static PyObject *
+LZMADecomp_flush(LZMADecompObject *self, PyObject *args, PyObject *kwargs)
+{
+ Py_ssize_t bufsize = SMALLCHUNK;
+
+ PyObject *ret = NULL;
+ lzma_action flushmode = LZMA_FINISH;
+ unsigned long long start_total_out;
+ lzma_stream *lzus = &self->lzus;
+ lzma_ret lzuerror = LZMA_OK;
+
+ static char *kwlist[] = {"mode", "bufsize", NULL};
+
+ INITCHECK
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:flush", kwlist,
+ &flushmode, &bufsize))
+ return NULL;
+
+ ACQUIRE_LOCK(self);
+ if (!self->running) {
+ PyErr_SetString(PyExc_ValueError, "object was already flushed");
+ goto error;
+ }
+
+ switch(flushmode){
+ case(LZMA_SYNC_FLUSH):
+ case(LZMA_FULL_FLUSH):
+ PyErr_Format(LZMAError,
+ "%d is not supported as flush mode for decoding",
+ flushmode);
+ goto error;
+ case(LZMA_RUN):
+ case(LZMA_FINISH):
+ break;
+ default:
+ PyErr_Format(LZMAError, "Invalid flush mode: %d", flushmode);
+ goto error;
+ }
+
+ if (!(ret = PyBytes_FromStringAndSize(NULL, bufsize)))
+ goto error;
+
+
+ start_total_out = lzus->total_out;
+ lzus->avail_out = (size_t)bufsize;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret);
+
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ lzuerror = lzma_code(lzus, flushmode);
+ Py_END_ALLOW_THREADS
+
+ if (lzus->avail_in == 0 || lzus->avail_out != 0)
+ break; /* no more input data */
+
+ if (_PyBytes_Resize(&ret, bufsize << 1) < 0)
+ goto error;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret) + bufsize;
+ lzus->avail_out = (size_t)bufsize;
+ bufsize = bufsize << 1;
+
+ if(!Util_CatchLZMAError(lzuerror, lzus, 0))
+ goto error;
+ }
+
+
+ /* If flushmode is LZMA_FINISH, we also have to call lzma_end() to free
+ * various data structures. Note we should only get LZMA_STREAM_END when
+ * flushmode is LZMA_FINISH
+ */
+ if (lzuerror == LZMA_STREAM_END) {
+ lzma_end(lzus);
+ self->running = 0;
+ if(!Util_CatchLZMAError(lzuerror, lzus, 0))
+ goto error;
+ }
+ _PyBytes_Resize(&ret, (Py_ssize_t)lzus->total_out -
+ (Py_ssize_t)start_total_out);
+
+ RELEASE_LOCK(self);
+ return ret;
+
+error:
+ RELEASE_LOCK(self);
+ Py_XDECREF(ret);
+ return ret;
+}
+
+static PyMemberDef LZMADecomp_members[] = {
+ {"unused_data", T_OBJECT, offsetof(LZMADecompObject, unused_data),
+ READONLY, NULL},
+ {"unconsumed_tail", T_OBJECT, offsetof(LZMADecompObject,
+ unconsumed_tail), READONLY, NULL},
+ {NULL, 0, 0, 0, NULL} /* sentinel */
+};
+
+static PyMethodDef LZMADecomp_methods[4] =
+{
+ {"decompress", (PyCFunction)LZMADecomp_decompress,
+ METH_VARARGS|METH_KEYWORDS, LZMADecomp_decompress__doc__},
+ {"flush", (PyCFunction)LZMADecomp_flush,
+ METH_VARARGS|METH_KEYWORDS, LZMADecomp_flush__doc__},
+ {NULL, NULL, 0, NULL} /* sentinel */
+};
+
+static PyObject *
+LZMADecompObject_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ LZMADecompObject *self;
+ self = (LZMADecompObject *)type->tp_alloc(type, 0);
+
+ if (self != NULL){
+ lzma_stream tmp = LZMA_STREAM_INIT;
+
+ self->is_initialised = 0;
+ self->running = 0;
+ self->max_length = 0;
+ self->memlimit = -1;
+ if((self->unused_data = PyBytes_FromString("")) == NULL)
+ goto error;
+ if((self->unconsumed_tail = PyBytes_FromString("")) == NULL)
+ goto error;
+ self->lzus = tmp;
+ }
+ else
+ return NULL;
+
+ return (PyObject *)self;
+error:
+ Py_DECREF(self);
+ return NULL;
+}
+
+static void
+LZMADecomp_dealloc(LZMADecompObject *self)
+{
+#ifdef WITH_THREAD
+ if (self->lock)
+ PyThread_free_lock(self->lock);
+#endif
+ if (self->is_initialised)
+ lzma_end(&self->lzus);
+ Py_XDECREF(self->unused_data);
+ Py_XDECREF(self->unconsumed_tail);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static int
+LZMADecomp_init(LZMADecompObject *self, PyObject *args, PyObject *kwargs)
+{
+ lzma_stream *lzus = &self->lzus;
+ lzma_ret lzuerror = LZMA_OK;
+ static char *kwlist[] = {"max_length", "memlimit", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|lK:LZMADecompressor",
+ kwlist, &self->max_length, &self->memlimit))
+ return -1;
+
+#ifdef WITH_THREAD
+ self->lock = PyThread_allocate_lock();
+ if (!self->lock) {
+ PyErr_SetString(PyExc_MemoryError, "unable to allocate lock");
+ goto error;
+ }
+#endif
+
+ if (self->max_length < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "max_length must be greater than zero");
+ goto error;
+ }
+
+ lzuerror = lzma_auto_decoder(lzus, self->memlimit, LZMA_CONCATENATED);
+ if(!Util_CatchLZMAError(lzuerror, lzus, 0))
+ goto error;
+
+ self->is_initialised = 1;
+ self->running = 1;
+
+ return 0;
+
+error:
+#ifdef WITH_THREAD
+ if (self->lock) {
+ PyThread_free_lock(self->lock);
+ self->lock = NULL;
+ }
+#endif
+ Py_CLEAR(self->unused_data);
+ return -1;
+}
+
+PyDoc_STRVAR(LZMADecomp__doc__,
+"LZMADecompressor(max_length=0, memlimit=-1) -> decompressor object\n\
+\n\
+Create a new decompressor object. This object may be used to decompress\n\
+data sequentially. If you want to decompress data in one shot, use the\n\
+decompress() function instead.\n");
+
+static PyTypeObject LZMADecomp_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "lzma.LZMADecompressor", /*tp_name*/
+ sizeof(LZMADecompObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)LZMADecomp_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_reserved*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ PyObject_GenericGetAttr, /*tp_getattro*/
+ PyObject_GenericSetAttr, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ LZMADecomp__doc__, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ 0, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ LZMADecomp_methods, /*tp_methods*/
+ LZMADecomp_members, /*tp_members*/
+ 0, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ (initproc)LZMADecomp_init, /*tp_init*/
+ PyType_GenericAlloc, /*tp_alloc*/
+ LZMADecompObject_new, /*tp_new*/
+ PyObject_Free, /*tp_free*/
+ 0, /*tp_is_gc*/
+ 0, /*tp_bases*/
+ 0, /*tp_mro*/
+ 0, /*tp_cache*/
+ 0, /*tp_subclasses*/
+ 0, /*tp_weaklist*/
+ 0, /*tp_del*/
+ 0 /*tp_version_tag*/
+};
+
+/* ===================================================================== */
+/* Module functions. */
+
+PyDoc_STRVAR(LZMA_compress__doc__,
+"compress(data, "DEFAULT_OPTIONS_STRING") -> string\n\
+\n\
+Compress data using the given parameters, returning a string\n\
+containing the compressed data.");
+
+static PyObject *
+LZMA_compress(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *ret = NULL, *myFilters = NULL,
+ *myFormat = NULL, *myCheck = NULL;
+ Py_buffer pdata;
+ int compresslevel = LZMA_PRESET_DEFAULT, threads = 1;
+ const unsigned char *data;
+ Py_ssize_t datasize, bufsize;
+ lzma_ret lzuerror = LZMA_OK;
+ lzma_stream _lzus;
+ lzma_stream *lzus = &_lzus;
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+ lzma_check check = LZMA_CHECK_NONE;
+ lzma_stream tmp = LZMA_STREAM_INIT;
+ static char *kwlist[] = {"data", "compresslevel", "format", "check",
+ "threads", "filter", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|iUUiO:compress",
+ kwlist, &pdata, &compresslevel, &myFormat, &myCheck, &threads,
+ &myFilters))
+ return NULL;
+
+ if(!init_lzma_options("compress", filters, &check, compresslevel,
+ myFormat, myCheck, threads, myFilters))
+ return NULL;
+
+ data = pdata.buf;
+ datasize = pdata.len;
+
+ *lzus = tmp;
+ bufsize = lzma_stream_buffer_bound(datasize);
+ /* TODO: if(bufsize == 0) goto error; */
+
+ if (!(ret = PyBytes_FromStringAndSize(NULL, bufsize)))
+ return NULL;
+
+ if(filters[0].id == LZMA_FILTER_LZMA1)
+ {
+ lzuerror = lzma_alone_encoder(lzus, filters[0].options);
+
+ if(!Util_CatchLZMAError(lzuerror, lzus, 1))
+ goto error;
+
+ lzus->avail_in = (size_t)datasize;
+ lzus->next_in = data;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret);
+ lzus->avail_out = (size_t)bufsize;
+
+ for (;;) {
+ Py_BEGIN_ALLOW_THREADS
+ lzuerror = lzma_code(lzus, LZMA_FINISH);
+ Py_END_ALLOW_THREADS
+ if (!Util_CatchLZMAError(lzuerror, lzus, 1))
+ goto error;
+ if(lzuerror == LZMA_STREAM_END)
+ break; /* no more input data */
+ if (lzus->avail_out == 0) {
+ bufsize = Util_NewBufferSize(bufsize);
+ if (_PyBytes_Resize(&ret, bufsize) < 0)
+ goto error;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret) +
+ lzus->total_out;
+ lzus->avail_out = (size_t)bufsize -
+ (lzus->next_out - (unsigned char *)PyBytes_AS_STRING(ret));
+ }
+ }
+
+ lzma_end(lzus);
+ if (lzuerror == LZMA_STREAM_END) {
+ if(_PyBytes_Resize(&ret, (Py_ssize_t)lzus->total_out) < 0) {
+ ret = NULL;
+ }
+ }
+ }
+ else {
+ size_t loc = 0;
+
+ Py_BEGIN_ALLOW_THREADS
+ if(check == (lzma_check)-1)
+ lzuerror = lzma_raw_buffer_encode(filters, NULL, data,
+ (size_t)datasize, (unsigned char *)PyBytes_AS_STRING(ret),
+ &loc, (size_t)bufsize);
+ else
+ lzuerror = lzma_stream_buffer_encode(filters, check, NULL, data,
+ (size_t)datasize, (unsigned char *)PyBytes_AS_STRING(ret),
+ &loc, (size_t)bufsize);
+ Py_END_ALLOW_THREADS
+ _PyBytes_Resize(&ret, (Py_ssize_t)loc);
+ }
+
+ PyBuffer_Release(&pdata);
+ free_lzma_options(filters);
+
+ return ret;
+
+error:
+ if(lzuerror != LZMA_MEM_ERROR && lzuerror != LZMA_PROG_ERROR)
+ lzma_end(lzus);
+ Py_XDECREF(ret);
+ PyBuffer_Release(&pdata);
+ free_lzma_options(filters);
+
+ return NULL;
+}
+
+PyDoc_STRVAR(LZMA_decompress__doc__,
+"decompress(data, bufsize=8192, memlimit=-1, \n\
+ flags=LZMA_CONCATENATED|LZMA_TELL_UNSUPPORTED_CHECK) -> string\n\
+\n\
+Decompress data in one shot. If you want to decompress data sequentially,\n\
+use an instance of LZMADecompressor instead.\n\
+\n\
+Optional arg 'bufsize' is the initial output buffer size.\n\
+Optional arg 'memlimit' is the maximum amount of memory the decoder may use,\n\
+-1 means no limit.");
+
+static PyObject *
+LZMA_decompress(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *ret = NULL;
+ Py_buffer pdata;
+ const unsigned char *data;
+ Py_ssize_t datasize, bufsize = SMALLCHUNK;
+ unsigned long long memlimit = -1;
+ unsigned int flags = LZMA_CONCATENATED|LZMA_TELL_UNSUPPORTED_CHECK;
+ lzma_ret lzuerror = LZMA_OK;
+ lzma_stream _lzus;
+ lzma_stream *lzus = &_lzus;
+ lzma_stream tmp = LZMA_STREAM_INIT;
+
+ static char *kwlist[] = {"data", "bufsize", "memlimit", "flags", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|lKi:decompress", kwlist,
+ &pdata, &bufsize, &memlimit, &flags))
+ return NULL;
+ data = pdata.buf;
+ datasize = pdata.len;
+
+ if (datasize == 0) {
+ PyBuffer_Release(&pdata);
+ return PyBytes_FromStringAndSize("", 0);
+ }
+
+ ret = PyBytes_FromStringAndSize(NULL, bufsize);
+ if (!ret) {
+ PyBuffer_Release(&pdata);
+ return NULL;
+ }
+
+ *lzus = tmp;
+
+ lzus->avail_in = (size_t)datasize;
+ lzus->avail_out = (size_t)bufsize;
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret);
+ lzus->next_in = data;
+
+ lzuerror = lzma_auto_decoder(lzus, memlimit, flags);
+ if(!Util_CatchLZMAError(lzuerror, lzus, 0))
+ goto error;
+
+ while (lzuerror != LZMA_STREAM_END){
+ Py_BEGIN_ALLOW_THREADS
+ lzuerror=lzma_code(lzus, LZMA_FINISH);
+ Py_END_ALLOW_THREADS
+
+ if(!Util_CatchLZMAError(lzuerror, lzus, 0))
+ goto error;
+ if(lzuerror == LZMA_STREAM_END)
+ break;
+ if(lzuerror == LZMA_OK){
+ if (_PyBytes_Resize(&ret, Util_NewBufferSize(bufsize)) < 0) {
+ goto error;
+ }
+ lzus->next_out = (unsigned char *)PyBytes_AS_STRING(ret) + bufsize;
+ lzus->avail_out = (size_t)bufsize;
+ bufsize = Util_NewBufferSize(bufsize);
+ }
+ }
+
+ if(_PyBytes_Resize(&ret, (Py_ssize_t)lzus->total_out) < 0)
+ ret = NULL;
+ lzma_end(lzus);
+ PyBuffer_Release(&pdata);
+
+ return ret;
+
+error:
+ if(lzuerror != LZMA_MEM_ERROR && lzuerror != LZMA_PROG_ERROR)
+ lzma_end(lzus);
+ Py_XDECREF(ret);
+ PyBuffer_Release(&pdata);
+
+ return NULL;
+}
+
+PyDoc_STRVAR(LZMA_crc32__doc__,
+"crc32(data[, start]) -> int\n\
+\n\
+Compute a CRC-32 checksum of string.\n\
+\n\
+An optional starting value 'start' can be specified.");
+
+static PyObject *
+LZMA_crc32(PyObject *self, PyObject *args)
+{
+ unsigned int crc32val = lzma_crc32(NULL, (size_t)0, (unsigned int)0);
+ const unsigned char *buf;
+ Py_ssize_t size;
+
+ if (!PyArg_ParseTuple(args, "s#|I:crc32", &buf, &size, &crc32val))
+ return NULL;
+ crc32val = lzma_crc32(buf, (size_t)size, crc32val);
+ return PyLong_FromUnsignedLong((unsigned long)crc32val);
+}
+
+PyDoc_STRVAR(LZMA_crc64__doc__,
+"crc64(data[, start]) -> int\n\
+\n\
+Compute a CRC-64 checksum of string.\n\
+\n\
+An optional starting value 'start' can be specified.");
+
+static PyObject *
+LZMA_crc64(PyObject *self, PyObject *args)
+{
+ unsigned long long crc64val = lzma_crc64(NULL, (size_t)0,
+ (unsigned long long)0);
+ const unsigned char *buf;
+ Py_ssize_t size;
+
+ if (!PyArg_ParseTuple(args, "s#|K:crc64", &buf, &size, &crc64val))
+ return NULL;
+ crc64val = lzma_crc64(buf, (size_t)size, crc64val);
+ return PyLong_FromUnsignedLongLong(crc64val);
+}
+
+static PyMethodDef lzma_methods[] = {
+ {"compress", (PyCFunction)LZMA_compress,
+ METH_VARARGS|METH_KEYWORDS, LZMA_compress__doc__},
+ {"crc32", (PyCFunction)LZMA_crc32,
Martin v. Löwis 2010/10/31 16:33:38 Is it really necessary to expose another set of CR
+ METH_VARARGS, LZMA_crc32__doc__},
+ {"crc64", (PyCFunction)LZMA_crc64,
+ METH_VARARGS, LZMA_crc64__doc__},
+ {"decompress", (PyCFunction)LZMA_decompress,
+ METH_VARARGS|METH_KEYWORDS, LZMA_decompress__doc__},
+ {0, 0, 0, 0}
+};
+
+PyDoc_STRVAR(lzma_module_documentation,
+"The python lzma module provides a comprehensive interface for\n\
+the lzma compression library. It implements one shot (de)compression\n\
+functions, CRC-32 & CRC-64 checksum computations, types for sequential\n\
+(de)compression, and advanced options for lzma compression.\n\
+");
+
+static struct PyModuleDef lzmamodule = {
+ PyModuleDef_HEAD_INIT,
+ "lzma",
+ lzma_module_documentation,
+ -1,
+ lzma_methods,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* ===================================================================== */
+/* Initialization function. */
+
+/* declare function before defining it to avoid compile warnings */
+PyMODINIT_FUNC
+PyInit_lzma(void)
+{
+ PyObject *optionsSingleton, *module;
+
+ Options = (LZMAOptionsObject*)(optionsSingleton = PyType_GenericNew(
+ &LZMAOptions_Type, NULL, NULL));
+
+ if (PyType_Ready(&LZMAFile_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&LZMAComp_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&LZMADecomp_Type) < 0)
+ return NULL;
+ if (PyType_Ready(&LZMAOptions_Type) < 0)
+ return NULL;
+
+ module = PyModule_Create(&lzmamodule);
+ if (module == NULL)
+ return NULL;
+
+ LZMAError = PyErr_NewException("LZMA.error", NULL, NULL);
+ if (LZMAError != NULL) {
+ Py_INCREF(LZMAError);
+ PyModule_AddObject(module, "error", LZMAError);
+ }
+
+ Py_INCREF(&LZMAOptions_Type);
+ PyModule_AddObject(module, "LZMAOptions",
+ (PyObject *)&LZMAOptions_Type);
+
+ Py_INCREF(&LZMAComp_Type);
+ PyModule_AddObject(module, "LZMACompressor",
+ (PyObject *)&LZMAComp_Type);
+
+ Py_INCREF(&LZMADecomp_Type);
+ PyModule_AddObject(module, "LZMADecompressor",
+ (PyObject *)&LZMADecomp_Type);
+
+ Py_INCREF(&LZMAFile_Type);
+ PyModule_AddObject(module, "LZMAFile",
+ (PyObject *)&LZMAFile_Type);
+
+ PyModule_AddObject(module, "options",
+ optionsSingleton);
+ PyModule_AddIntConstant(module, "LZMA_RUN",
+ LZMA_RUN);
+ PyModule_AddIntConstant(module, "LZMA_SYNC_FLUSH",
+ LZMA_SYNC_FLUSH);
+ PyModule_AddIntConstant(module, "LZMA_FULL_FLUSH",
+ LZMA_FULL_FLUSH);
+ PyModule_AddIntConstant(module, "LZMA_FINISH",
+ LZMA_FINISH);
+
+ /* Decoding flags */
+ PyModule_AddIntConstant(module, "LZMA_TELL_NO_CHECK",
+ LZMA_TELL_NO_CHECK);
+ PyModule_AddIntConstant(module, "LZMA_TELL_UNSUPPORTED_CHECK",
+ LZMA_TELL_UNSUPPORTED_CHECK);
+ PyModule_AddIntConstant(module, "LZMA_TELL_ANY_CHECK",
+ LZMA_TELL_ANY_CHECK);
+ PyModule_AddIntConstant(module, "LZMA_CONCATENATED",
+ LZMA_CONCATENATED);
+
+ PyModule_AddObject(module, "__author__",
+ PyUnicode_FromString(__author__));
+ PyModule_AddObject(module, "LZMA_VERSION",
+ PyUnicode_FromString(LZMA_VERSION_STRING));
+ PyModule_AddStringConstant(module, "__version__",
+ VERSION);
+
+ return module;
+}
« Doc/library/lzma.rst ('K') | « Lib/test/teststring.xz ('k') | setup.py » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b