@@ -147,7 +147,7 @@ cdef arrange_output_buffer_with_maximum(stream_or_state *stream,
147
147
occupied = stream.next_out - buffer [0 ]
148
148
if length == occupied:
149
149
if length == max_length:
150
- raise MemoryError ( " Buffer has reached maximum size " )
150
+ return - 2
151
151
if length <= max_length >> 1 :
152
152
new_length = length << 1
153
153
else :
@@ -166,6 +166,8 @@ cdef arrange_output_buffer_with_maximum(stream_or_state *stream,
166
166
cdef arrange_output_buffer(stream_or_state * stream, unsigned char ** buffer , Py_ssize_t length):
167
167
cdef Py_ssize_t ret
168
168
ret = arrange_output_buffer_with_maximum(stream, buffer , length, PY_SSIZE_T_MAX)
169
+ if ret == - 2 :
170
+ raise MemoryError (" Output buffer has reached maximum size" )
169
171
return ret
170
172
171
173
cdef void arrange_input_buffer(stream_or_state * stream, Py_ssize_t * remains):
@@ -511,8 +513,6 @@ cdef class Decompress:
511
513
cdef public bint eof
512
514
cdef bint is_initialised
513
515
cdef inflate_state stream
514
- cdef unsigned char * obuf
515
- cdef unsigned int obuflen
516
516
cdef bint method_set
517
517
518
518
def __cinit__ (self , wbits = ISAL_DEF_MAX_HIST_BITS, zdict = None ):
@@ -534,17 +534,11 @@ cdef class Decompress:
534
534
err = isal_inflate_set_dict(& self .stream, zdict, zdict_length)
535
535
if err != COMP_OK:
536
536
check_isal_deflate_rc(err)
537
- self .obuflen = DEF_BUF_SIZE
538
- self .obuf = < unsigned char * > PyMem_Malloc(self .obuflen * sizeof(char ))
539
537
self .unused_data = b" "
540
538
self .unconsumed_tail = b" "
541
- self .eof = 0
539
+ self .eof = False
542
540
self .is_initialised = 1
543
541
544
- def __dealloc__ (self ):
545
- if self .obuf is not NULL :
546
- PyMem_Free(self .obuf)
547
-
548
542
def _view_bitbuffer (self ):
549
543
""" Shows the 64-bitbuffer of the internal inflate_state. It contains
550
544
a maximum of 8 bytes. This data is already read-in so is not part
@@ -594,11 +588,13 @@ cdef class Decompress:
594
588
unconsumed_tail attribute.
595
589
"""
596
590
597
- cdef Py_ssize_t total_bytes = 0
591
+ cdef Py_ssize_t hard_limit
598
592
if max_length == 0 :
599
- max_length = PY_SSIZE_T_MAX
593
+ hard_limit = PY_SSIZE_T_MAX
600
594
elif max_length < 0 :
601
595
raise ValueError (" max_length can not be smaller than 0" )
596
+ else :
597
+ hard_limit = max_length
602
598
603
599
if not self .method_set:
604
600
# Try to detect method from the first two bytes of the data.
@@ -613,50 +609,42 @@ cdef class Decompress:
613
609
cdef Py_ssize_t ibuflen = buffer .len
614
610
cdef unsigned char * ibuf = < unsigned char * > buffer .buf
615
611
self .stream.next_in = ibuf
616
- self .stream.avail_out = 0
617
- cdef unsigned int prev_avail_out
618
- cdef unsigned int bytes_written
619
- cdef Py_ssize_t unused_bytes
612
+
620
613
cdef int err
614
+ cdef bint max_length_reached = False
621
615
622
616
# Initialise output buffer
623
- out = []
617
+ cdef unsigned char * obuf = NULL
618
+ cdef Py_ssize_t obuflen = DEF_BUF_SIZE
619
+ if obuflen > max_length:
620
+ obuflen = max_length
624
621
625
- cdef bint last_round = 0
626
622
try :
627
623
# This loop reads all the input bytes. If there are no input bytes
628
624
# anymore the output is written.
629
625
while True :
630
626
arrange_input_buffer(& self .stream, & ibuflen)
631
- while (self .stream.avail_out == 0 or self .stream.avail_in != 0 ):
632
- self .stream.next_out = self .obuf # Reset output buffer.
633
- if total_bytes >= max_length:
627
+ while True :# (self.stream.avail_out == 0 or self.stream.avail_in != 0):
628
+ obuflen = arrange_output_buffer_with_maximum(
629
+ & self .stream, & obuf, obuflen, hard_limit)
630
+ if obuflen == - 2 :
631
+ max_length_reached = True
634
632
break
635
- elif total_bytes + self .obuflen >= max_length:
636
- self .stream.avail_out = max_length - total_bytes
637
- # The inflate process may not fill all available bytes so
638
- # we make sure this is the last round.
639
- last_round = 1
640
- else :
641
- self .stream.avail_out = self .obuflen
642
- prev_avail_out = self .stream.avail_out
643
633
err = isal_inflate(& self .stream)
644
634
if err != ISAL_DECOMP_OK:
645
635
# There is some python interacting when possible exceptions
646
636
# Are raised. So we remain in pure C code if we check for
647
637
# COMP_OK first.
648
638
check_isal_inflate_rc(err)
649
- bytes_written = prev_avail_out - self .stream.avail_out
650
- total_bytes += bytes_written
651
- out.append(self .obuf[:bytes_written])
652
- if self .stream.block_state == ISAL_BLOCK_FINISH or last_round:
639
+ if self .stream.avail_out != 0 :
653
640
break
654
- if self .stream.block_state == ISAL_BLOCK_FINISH or ibuflen == 0 :
641
+ if self .stream.block_state == ISAL_BLOCK_FINISH or ibuflen == 0 or max_length_reached :
655
642
break
656
643
self .save_unconsumed_input(buffer )
657
- return b " " .join(out )
644
+ return PyBytes_FromStringAndSize( < char * > obuf, self .stream.next_out - obuf )
658
645
finally :
659
646
PyBuffer_Release(buffer )
647
+ PyMem_Free(obuf)
660
648
661
649
def flush (self , Py_ssize_t length = DEF_BUF_SIZE):
662
650
"""
@@ -667,8 +655,7 @@ cdef class Decompress:
667
655
"""
668
656
if length <= 0 :
669
657
raise ValueError (" Length must be greater than 0" )
670
- if length > UINT32_MAX:
671
- raise ValueError (" Length should not be larger than 4GB." )
658
+
672
659
cdef Py_buffer buffer_data
673
660
cdef Py_buffer* buffer = & buffer_data
674
661
if PyObject_GetBuffer(self .unconsumed_tail, buffer , PyBUF_READ & PyBUF_C_CONTIGUOUS) != 0 :
@@ -677,19 +664,14 @@ cdef class Decompress:
677
664
cdef unsigned char * ibuf = < unsigned char * > buffer .buf
678
665
self .stream.next_in = ibuf
679
666
680
- cdef unsigned int total_bytes = 0
681
- cdef unsigned int bytes_written
682
- out = []
683
667
cdef unsigned int obuflen = length
684
- cdef unsigned char * obuf = < unsigned char * > PyMem_Malloc(obuflen * sizeof(char ))
685
- cdef Py_ssize_t unused_bytes
668
+ cdef unsigned char * obuf = NULL
686
669
687
670
try :
688
671
while True :
689
672
arrange_input_buffer(& self .stream, & ibuflen)
690
673
while True :
691
- self .stream.next_out = obuf # Reset output buffer.
692
- self .stream.avail_out = obuflen
674
+ obuflen = arrange_output_buffer(& self .stream, & obuf, obuflen)
693
675
err = isal_inflate(& self .stream)
694
676
if err != ISAL_DECOMP_OK:
695
677
# There is some python interacting when possible exceptions
@@ -699,18 +681,14 @@ cdef class Decompress:
699
681
# Instead of output buffer resizing as the zlibmodule.c example
700
682
# the data is appended to a list.
701
683
# TODO: Improve this with the buffer protocol.
702
- if self .stream.avail_out == obuflen:
703
- break
704
- bytes_written = obuflen - self .stream.avail_out
705
- total_bytes += bytes_written
706
- out.append(obuf[:bytes_written])
707
684
if self .stream.avail_out != 0 :
708
685
break
709
686
if self .stream.block_state == ISAL_BLOCK_FINISH or ibuflen == 0 :
710
687
break
711
688
self .save_unconsumed_input(buffer )
712
- return b " " .join(out )
689
+ return PyBytes_FromStringAndSize( < char * > obuf, self .stream.next_out - obuf )
713
690
finally :
691
+ PyBuffer_Release(buffer )
714
692
PyMem_Free(obuf)
715
693
716
694
0 commit comments