pylzma_decompressobj_compat.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * Python Bindings for LZMA
  3. *
  4. * Copyright (c) 2004-2006 by Joachim Bauch, mail@joachim-bauch.de
  5. * 7-Zip Copyright (C) 1999-2005 Igor Pavlov
  6. * LZMA SDK Copyright (C) 1999-2005 Igor Pavlov
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. *
  22. * $Id: pylzma_decompressobj_compat.c 104 2006-01-08 18:17:14Z jojo $
  23. *
  24. */
  25. #include <Python.h>
  26. #include <7zip/LzmaCompatDecode.h>
  27. #include "pylzma.h"
  28. #include "pylzma_decompress_compat.h"
  29. #include "pylzma_decompressobj_compat.h"
  30. static const char doc_decomp_decompress[] = \
  31. "decompress(data[, bufsize]) -- Returns a string containing the up to bufsize decompressed bytes of the data.\n" \
  32. "After calling, some of the input data may be available in internal buffers for later processing.";
  33. static PyObject *pylzma_decomp_decompress(CCompatDecompressionObject *self, PyObject *args)
  34. {
  35. PyObject *result=NULL;
  36. char *data;
  37. int length, old_length, start_total_out, res, max_length=BLOCK_SIZE;
  38. if (!PyArg_ParseTuple(args, "s#|l", &data, &length, &max_length))
  39. return NULL;
  40. if (max_length < 0)
  41. {
  42. PyErr_SetString(PyExc_ValueError, "bufsize must be greater than zero");
  43. return NULL;
  44. }
  45. start_total_out = self->stream.totalOut;
  46. if (self->unconsumed_length > 0) {
  47. self->unconsumed_tail = (char *)realloc(self->unconsumed_tail, self->unconsumed_length + length);
  48. self->stream.next_in = (Byte *)self->unconsumed_tail;
  49. memcpy(self->stream.next_in + self->unconsumed_length, data, length);
  50. } else
  51. self->stream.next_in = (Byte *)data;
  52. self->stream.avail_in = self->unconsumed_length + length;
  53. if (max_length && max_length < length)
  54. length = max_length;
  55. if (!(result = PyString_FromStringAndSize(NULL, length)))
  56. return NULL;
  57. self->stream.next_out = (unsigned char *)PyString_AS_STRING(result);
  58. self->stream.avail_out = length;
  59. Py_BEGIN_ALLOW_THREADS
  60. res = lzmaCompatDecode(&self->stream);
  61. Py_END_ALLOW_THREADS
  62. while (res == LZMA_OK && self->stream.avail_out == 0)
  63. {
  64. if (max_length && length >= max_length)
  65. break;
  66. old_length = length;
  67. length <<= 1;
  68. if (max_length && length > max_length)
  69. length = max_length;
  70. if (_PyString_Resize(&result, length) < 0)
  71. goto exit;
  72. self->stream.avail_out = length - old_length;
  73. self->stream.next_out = (Byte *)PyString_AS_STRING(result) + old_length;
  74. Py_BEGIN_ALLOW_THREADS
  75. res = lzmaCompatDecode(&self->stream);
  76. Py_END_ALLOW_THREADS
  77. }
  78. if (res == LZMA_NOT_ENOUGH_MEM) {
  79. // out of memory during decompression
  80. PyErr_NoMemory();
  81. DEC_AND_NULL(result);
  82. goto exit;
  83. } else if (res == LZMA_DATA_ERROR) {
  84. PyErr_SetString(PyExc_ValueError, "data error during decompression");
  85. DEC_AND_NULL(result);
  86. goto exit;
  87. } else if (res != LZMA_OK && res != LZMA_STREAM_END) {
  88. PyErr_Format(PyExc_ValueError, "unknown return code from lzmaDecode: %d", res);
  89. DEC_AND_NULL(result);
  90. goto exit;
  91. }
  92. /* Not all of the compressed data could be accomodated in the output buffer
  93. of specified size. Return the unconsumed tail in an attribute.*/
  94. if (max_length != 0) {
  95. if (self->stream.avail_in > 0)
  96. {
  97. if (self->stream.avail_in != self->unconsumed_length)
  98. self->unconsumed_tail = (char *)realloc(self->unconsumed_tail, self->stream.avail_in);
  99. if (!self->unconsumed_tail) {
  100. PyErr_NoMemory();
  101. DEC_AND_NULL(result);
  102. goto exit;
  103. }
  104. memcpy(self->unconsumed_tail, self->stream.next_in, self->stream.avail_in);
  105. } else
  106. FREE_AND_NULL(self->unconsumed_tail);
  107. self->unconsumed_length = self->stream.avail_in;
  108. }
  109. /* The end of the compressed data has been reached, so set the
  110. unused_data attribute to a string containing the remainder of the
  111. data in the string. Note that this is also a logical place to call
  112. inflateEnd, but the old behaviour of only calling it on flush() is
  113. preserved.
  114. */
  115. if (res == LZMA_STREAM_END) {
  116. Py_XDECREF(self->unused_data); /* Free original empty string */
  117. self->unused_data = PyString_FromStringAndSize((char *)self->stream.next_in, self->stream.avail_in);
  118. if (self->unused_data == NULL) {
  119. PyErr_NoMemory();
  120. DEC_AND_NULL(result);
  121. goto exit;
  122. }
  123. }
  124. _PyString_Resize(&result, self->stream.totalOut - start_total_out);
  125. exit:
  126. return result;
  127. }
  128. static const char doc_decomp_reset[] = \
  129. "reset() -- Resets the decompression object.";
  130. static PyObject *pylzma_decomp_reset(CCompatDecompressionObject *self, PyObject *args)
  131. {
  132. PyObject *result=NULL;
  133. if (!PyArg_ParseTuple(args, ""))
  134. return NULL;
  135. lzmaCompatInit(&self->stream);
  136. FREE_AND_NULL(self->unconsumed_tail);
  137. self->unconsumed_length = 0;
  138. Py_DECREF(self->unused_data);
  139. self->unused_data = PyString_FromString("");
  140. CHECK_NULL(self->unused_data);
  141. result = Py_None;
  142. Py_XINCREF(result);
  143. exit:
  144. return result;
  145. }
  146. PyMethodDef pylzma_decomp_compat_methods[] = {
  147. {"decompress", (PyCFunction)pylzma_decomp_decompress, METH_VARARGS, (char *)&doc_decomp_decompress},
  148. {"reset", (PyCFunction)pylzma_decomp_reset, METH_VARARGS, (char *)&doc_decomp_reset},
  149. {NULL, NULL},
  150. };
  151. static void pylzma_decomp_dealloc(CCompatDecompressionObject *self)
  152. {
  153. free_lzma_stream(&self->stream);
  154. FREE_AND_NULL(self->unconsumed_tail);
  155. DEC_AND_NULL(self->unused_data);
  156. PyObject_Del(self);
  157. }
  158. static PyObject *pylzma_decomp_getattr(CCompatDecompressionObject *self, char *attrname)
  159. {
  160. if (strcmp(attrname, "unused_data") == 0) {
  161. Py_INCREF(self->unused_data);
  162. return self->unused_data;
  163. } else
  164. return Py_FindMethod(pylzma_decomp_compat_methods, (PyObject *)self, attrname);
  165. }
  166. static int pylzma_decomp_setattr(CCompatDecompressionObject *self, char *attrname, PyObject *value)
  167. {
  168. // disable setting of attributes
  169. PyErr_Format(PyExc_AttributeError, "no attribute named '%s'", attrname);
  170. return -1;
  171. }
  172. PyTypeObject CompatDecompressionObject_Type = {
  173. //PyObject_HEAD_INIT(&PyType_Type)
  174. PyObject_HEAD_INIT(NULL)
  175. 0,
  176. "LZMACompatDecompress", /* char *tp_name; */
  177. sizeof(CCompatDecompressionObject), /* int tp_basicsize; */
  178. 0, /* int tp_itemsize; // not used much */
  179. (destructor)pylzma_decomp_dealloc, /* destructor tp_dealloc; */
  180. NULL, /* printfunc tp_print; */
  181. (getattrfunc)pylzma_decomp_getattr, /* getattrfunc tp_getattr; // __getattr__ */
  182. (setattrfunc)pylzma_decomp_setattr, /* setattrfunc tp_setattr; // __setattr__ */
  183. NULL, /* cmpfunc tp_compare; // __cmp__ */
  184. NULL, /* reprfunc tp_repr; // __repr__ */
  185. NULL, /* PyNumberMethods *tp_as_number; */
  186. NULL, /* PySequenceMethods *tp_as_sequence; */
  187. NULL, /* PyMappingMethods *tp_as_mapping; */
  188. NULL, /* hashfunc tp_hash; // __hash__ */
  189. NULL, /* ternaryfunc tp_call; // __call__ */
  190. NULL, /* reprfunc tp_str; // __str__ */
  191. };
  192. const char doc_decompressobj_compat[] = \
  193. "decompressobj_compat() -- Returns object that can be used for decompression.";
  194. PyObject *pylzma_decompressobj_compat(PyObject *self, PyObject *args)
  195. {
  196. CCompatDecompressionObject *result=NULL;
  197. if (!PyArg_ParseTuple(args, ""))
  198. goto exit;
  199. result = PyObject_New(CCompatDecompressionObject, &CompatDecompressionObject_Type);
  200. CHECK_NULL(result);
  201. result->unconsumed_tail = NULL;
  202. result->unconsumed_length = 0;
  203. result->unused_data = PyString_FromString("");
  204. if (result->unused_data == NULL)
  205. {
  206. PyErr_NoMemory();
  207. PyObject_Del(result);
  208. result = NULL;
  209. goto exit;
  210. }
  211. memset(&result->stream, 0, sizeof(result->stream));
  212. lzmaCompatInit(&result->stream);
  213. exit:
  214. return (PyObject *)result;
  215. }