@@ -71,10 +71,12 @@ cdef extern from "zstd.h":
7171 size_t ZSTD_freeDStream(ZSTD_DStream* zds) nogil
7272 size_t ZSTD_initDStream(ZSTD_DStream* zds) nogil
7373
74- cdef long ZSTD_CONTENTSIZE_UNKNOWN
75- cdef long ZSTD_CONTENTSIZE_ERROR
74+ cdef unsigned long long ZSTD_CONTENTSIZE_UNKNOWN
75+ cdef unsigned long long ZSTD_CONTENTSIZE_ERROR
76+
7677 unsigned long long ZSTD_getFrameContentSize(const void * src,
7778 size_t srcSize) nogil
79+ size_t ZSTD_findFrameCompressedSize(const void * src, size_t srcSize) nogil
7880
7981 int ZSTD_minCLevel() nogil
8082 int ZSTD_maxCLevel() nogil
@@ -218,7 +220,11 @@ def decompress(source, dest=None):
218220
219221 try :
220222 # determine uncompressed size using unsigned long long for full range
221- content_size = ZSTD_getFrameContentSize(source_ptr, source_size)
223+ try :
224+ content_size = findTotalContentSize(source_ptr, source_size)
225+ except RuntimeError :
226+ raise RuntimeError (' Zstd decompression error: invalid input data' )
227+
222228 if content_size == ZSTD_CONTENTSIZE_UNKNOWN and dest is None :
223229 return stream_decompress(source_pb)
224230 elif content_size == ZSTD_CONTENTSIZE_UNKNOWN:
@@ -362,6 +368,46 @@ cdef stream_decompress(const Py_buffer* source_pb):
362368
363369 return dest
364370
371+ cdef unsigned long long findTotalContentSize(const char * source_ptr, size_t source_size):
372+ """ Find the total uncompressed content size of all frames in the source buffer
373+
374+ Parameters
375+ ----------
376+ source_ptr : Pointer to the beginning of the buffer
377+ source_size : Size of the buffer containing the frame sizes to sum
378+
379+ Returns
380+ -------
381+ total_content_size: Sum of the content size of all frames within the source buffer
382+ If any of the frame sizes is unknown, return ZSTD_CONTENTSIZE_UNKNOWN.
383+ If any of the frames causes ZSTD_getFrameContentSize to error, return ZSTD_CONTENTSIZE_ERROR.
384+ """
385+ cdef:
386+ unsigned long long frame_content_size = 0
387+ unsigned long long total_content_size = 0
388+ size_t frame_compressed_size = 0
389+ size_t offset = 0
390+
391+ while offset < source_size:
392+ frame_compressed_size = ZSTD_findFrameCompressedSize(source_ptr + offset, source_size - offset);
393+
394+ if ZSTD_isError(frame_compressed_size):
395+ error = ZSTD_getErrorName(frame_compressed_size)
396+ raise RuntimeError (' Could not set determine zstd frame size: %s ' % error)
397+
398+ frame_content_size = ZSTD_getFrameContentSize(source_ptr + offset, frame_compressed_size);
399+
400+ if frame_content_size == ZSTD_CONTENTSIZE_ERROR:
401+ return ZSTD_CONTENTSIZE_ERROR
402+
403+ if frame_content_size == ZSTD_CONTENTSIZE_UNKNOWN:
404+ return ZSTD_CONTENTSIZE_UNKNOWN
405+
406+ total_content_size += frame_content_size
407+ offset += frame_compressed_size
408+
409+ return total_content_size
410+
365411class Zstd (Codec ):
366412 """ Codec providing compression using Zstandard.
367413
0 commit comments