3131#include "../sdk/C/Bra.h"
3232#include "../sdk/C/Bcj2.h"
3333#include "../sdk/C/Delta.h"
34+ #include "../sdk/C/Ppmd7.h"
3435
3536#include "pylzma.h"
3637#include "pylzma_compress.h"
4546#include "pylzma_decompress_compat.h"
4647#include "pylzma_decompressobj_compat.h"
4748#endif
49+ #include "pylzma_streams.h"
4850
4951#if defined(WITH_THREAD ) && !defined(PYLZMA_USE_GILSTATE )
5052PyInterpreterState * _pylzma_interpreterState = NULL ;
@@ -350,6 +352,137 @@ pylzma_delta_encode(PyObject *self, PyObject *args)
350352 return result ;
351353}
352354
355+ const char
356+ doc_ppmd_decompress [] =
357+ "ppmd_decompress(data, properties, outsize) -- Decompress PPMd stream." ;
358+
359+ typedef struct
360+ {
361+ IByteIn vt ;
362+ const Byte * cur ;
363+ const Byte * end ;
364+ const Byte * begin ;
365+ UInt64 processed ;
366+ BoolInt extra ;
367+ SRes res ;
368+ const ILookInStream * inStream ;
369+ } CByteInToLook ;
370+
371+ static Byte
372+ ReadByte (const IByteIn * pp ) {
373+ CByteInToLook * p = CONTAINER_FROM_VTBL (pp , CByteInToLook , vt );
374+ if (p -> cur != p -> end ) {
375+ return * p -> cur ++ ;
376+ }
377+
378+ if (p -> res == SZ_OK ) {
379+ size_t size = p -> cur - p -> begin ;
380+ p -> processed += size ;
381+ p -> res = ILookInStream_Skip (p -> inStream , size );
382+ size = (1 << 25 );
383+ p -> res = ILookInStream_Look (p -> inStream , (const void * * )& p -> begin , & size );
384+ p -> cur = p -> begin ;
385+ p -> end = p -> begin + size ;
386+ if (size != 0 ) {
387+ return * p -> cur ++ ;;
388+ }
389+ }
390+ p -> extra = True ;
391+ return 0 ;
392+ }
393+
394+ static PyObject *
395+ pylzma_ppmd_decompress (PyObject * self , PyObject * args )
396+ {
397+ char * data ;
398+ PARSE_LENGTH_TYPE length ;
399+ char * props ;
400+ PARSE_LENGTH_TYPE propssize ;
401+ unsigned int outsize ;
402+ PyObject * result ;
403+ Byte * tmp ;
404+ unsigned order ;
405+ UInt32 memSize ;
406+ CPpmd7 ppmd ;
407+ CPpmd7z_RangeDec rc ;
408+ CByteInToLook s ;
409+ SRes res = SZ_OK ;
410+ CMemoryLookInStream stream ;
411+
412+ if (!PyArg_ParseTuple (args , "s#s#I" , & data , & length , & props , & propssize , & outsize )) {
413+ return NULL ;
414+ }
415+
416+ if (propssize != 5 ) {
417+ PyErr_Format (PyExc_TypeError , "properties must be exactly 5 bytes, got %ld" , propssize );
418+ return NULL ;
419+ }
420+
421+ order = props [0 ];
422+ memSize = GetUi32 (props + 1 );
423+ if (order < PPMD7_MIN_ORDER ||
424+ order > PPMD7_MAX_ORDER ||
425+ memSize < PPMD7_MIN_MEM_SIZE ||
426+ memSize > PPMD7_MAX_MEM_SIZE ) {
427+ PyErr_SetString (PyExc_TypeError , "unsupporter compression properties" );
428+ return NULL ;
429+ }
430+
431+ if (!outsize ) {
432+ return PyBytes_FromString ("" );
433+ }
434+
435+ Ppmd7_Construct (& ppmd );
436+ if (!Ppmd7_Alloc (& ppmd , memSize , & allocator )) {
437+ return PyErr_NoMemory ();
438+ }
439+ Ppmd7_Init (& ppmd , order );
440+
441+ result = PyBytes_FromStringAndSize (NULL , outsize );
442+ if (!result ) {
443+ return NULL ;
444+ }
445+
446+ CreateMemoryLookInStream (& stream , (Byte * ) data , length );
447+ tmp = (Byte * ) PyBytes_AS_STRING (result );
448+ Py_BEGIN_ALLOW_THREADS
449+ Ppmd7z_RangeDec_CreateVTable (& rc );
450+ s .vt .Read = ReadByte ;
451+ s .inStream = & stream .s ;
452+ s .begin = s .end = s .cur = NULL ;
453+ s .extra = False ;
454+ s .res = SZ_OK ;
455+ s .processed = 0 ;
456+ rc .Stream = & s .vt ;
457+ if (!Ppmd7z_RangeDec_Init (& rc )) {
458+ res = SZ_ERROR_DATA ;
459+ } else if (s .extra ) {
460+ res = (s .res != SZ_OK ? s .res : SZ_ERROR_DATA );
461+ } else {
462+ SizeT i ;
463+ for (i = 0 ; i < outsize ; i ++ ) {
464+ int sym = Ppmd7_DecodeSymbol (& ppmd , & rc .vt );
465+ if (s .extra || sym < 0 ) {
466+ break ;
467+ }
468+ tmp [i ] = (Byte )sym ;
469+ }
470+ if (i != outsize ) {
471+ res = (s .res != SZ_OK ? s .res : SZ_ERROR_DATA );
472+ } else if (s .processed + (s .cur - s .begin ) != length || !Ppmd7z_RangeDec_IsFinishedOK (& rc )) {
473+ res = SZ_ERROR_DATA ;
474+ }
475+ }
476+ Py_END_ALLOW_THREADS
477+ Ppmd7_Free (& ppmd , & allocator );
478+ if (res != SZ_OK ) {
479+ Py_DECREF (result );
480+ PyErr_SetString (PyExc_TypeError , "error during decompression" );
481+ result = NULL ;
482+ }
483+ return result ;
484+ }
485+
353486PyMethodDef
354487methods [] = {
355488 // exported functions
@@ -372,6 +505,8 @@ methods[] = {
372505 // Delta
373506 {"delta_decode" , (PyCFunction )pylzma_delta_decode , METH_VARARGS , (char * )& doc_delta_decode },
374507 {"delta_encode" , (PyCFunction )pylzma_delta_encode , METH_VARARGS , (char * )& doc_delta_encode },
508+ // PPMd
509+ {"ppmd_decompress" , (PyCFunction )pylzma_ppmd_decompress , METH_VARARGS , (char * )& doc_ppmd_decompress },
375510 {NULL , NULL },
376511};
377512
0 commit comments