From 3d92a8bf05a359841e57d914aa81a03026255e45 Mon Sep 17 00:00:00 2001 From: kjdev Date: Fri, 18 Apr 2025 08:14:31 +0900 Subject: [PATCH 01/11] refactor: zstd_uncompress_dict() --- zstd.c | 61 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/zstd.c b/zstd.c index 4b1ba25..9c6ad55 100644 --- a/zstd.c +++ b/zstd.c @@ -345,51 +345,70 @@ ZEND_FUNCTION(zstd_uncompress_dict) { char *input, *dict; size_t input_len, dict_len; + uint8_t streaming = 0; zend_string *output; + size_t result; + unsigned long long size; + ZSTD_DDict *ddict; + ZSTD_DCtx *dctx; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_STRING(input, input_len) Z_PARAM_STRING(dict, dict_len) ZEND_PARSE_PARAMETERS_END(); - unsigned long long const rSize = ZSTD_getFrameContentSize(input, - input_len); - - if (rSize == 0 || rSize == ZSTD_CONTENTSIZE_ERROR) { + size = ZSTD_getFrameContentSize(input, input_len); + if (size == 0 || size == ZSTD_CONTENTSIZE_ERROR) { ZSTD_WARNING("it was not compressed by zstd"); RETURN_FALSE; + } else if (size == ZSTD_CONTENTSIZE_UNKNOWN) { + streaming = 1; + size = ZSTD_DStreamOutSize(); } - ZSTD_DCtx* const dctx = ZSTD_createDCtx(); - if (dctx == NULL) { - ZSTD_WARNING("ZSTD_createDCtx() error"); - RETURN_FALSE; - } - ZSTD_DDict* const ddict = ZSTD_createDDict(dict, - dict_len); + ddict = ZSTD_createDDict(dict, dict_len); if (!ddict) { - ZSTD_freeDStream(dctx); ZSTD_WARNING("ZSTD_createDDict() error"); RETURN_FALSE; } - output = zend_string_alloc(rSize, 0); + output = zend_string_alloc(size, 0); - size_t const dSize = ZSTD_decompress_usingDDict(dctx, ZSTR_VAL(output), rSize, - input, - input_len, - ddict); - if (dSize != rSize) { - ZSTD_freeDStream(dctx); + dctx = ZSTD_createDCtx(); + if (dctx == NULL) { + zend_string_efree(output); ZSTD_freeDDict(ddict); + ZSTD_WARNING("ZSTD_createDCtx() error"); + RETURN_FALSE; + } + + if (!streaming) { + result = ZSTD_decompress_usingDDict(dctx, ZSTR_VAL(output), size, + input, input_len, ddict); + if (ZSTD_IS_ERROR(result)) { + zend_string_efree(output); + ZSTD_freeDCtx(dctx); + ZSTD_freeDDict(ddict); + ZSTD_WARNING("%s", ZSTD_getErrorName(result)); + RETURN_FALSE; + } else if (result != size) { + zend_string_efree(output); + ZSTD_freeDCtx(dctx); + ZSTD_freeDDict(ddict); + ZSTD_WARNING("failed to decompress"); + RETURN_FALSE; + } + } else { zend_string_efree(output); - ZSTD_WARNING("%s", ZSTD_getErrorName(dSize)); + ZSTD_freeDDict(ddict); + ZSTD_WARNING("can not decompress stream"); RETURN_FALSE; } + ZSTD_freeDCtx(dctx); ZSTD_freeDDict(ddict); - output = zstd_string_output_truncate(output, dSize); + output = zstd_string_output_truncate(output, result); RETVAL_NEW_STR(output); } From 0e6f92e4b85f1f73ce734d650a1e45cc3ac6bb43 Mon Sep 17 00:00:00 2001 From: kjdev Date: Fri, 18 Apr 2025 09:05:22 +0900 Subject: [PATCH 02/11] refactor: zstd_compress_dict() --- zstd.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/zstd.c b/zstd.c index 9c6ad55..207eb3a 100644 --- a/zstd.c +++ b/zstd.c @@ -289,10 +289,11 @@ ZEND_FUNCTION(zstd_uncompress) ZEND_FUNCTION(zstd_compress_dict) { zend_long level = DEFAULT_COMPRESS_LEVEL; - zend_string *output; char *input, *dict; - size_t input_len, dict_len; + size_t input_len, dict_len, size, result; + ZSTD_CCtx *cctx; + ZSTD_CDict *cdict; ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(input, input_len) @@ -305,40 +306,37 @@ ZEND_FUNCTION(zstd_compress_dict) RETURN_FALSE; } - ZSTD_CCtx* const cctx = ZSTD_createCCtx(); + cctx = ZSTD_createCCtx(); if (cctx == NULL) { ZSTD_WARNING("ZSTD_createCCtx() error"); RETURN_FALSE; } - ZSTD_CDict* const cdict = ZSTD_createCDict(dict, - dict_len, - (int)level); + + cdict = ZSTD_createCDict(dict, dict_len, (int) level); if (!cdict) { ZSTD_freeCStream(cctx); ZSTD_WARNING("ZSTD_createCDict() error"); RETURN_FALSE; } - size_t const cBuffSize = ZSTD_compressBound(input_len); - output = zend_string_alloc(cBuffSize, 0); + size = ZSTD_compressBound(input_len); + output = zend_string_alloc(size, 0); - size_t const cSize = ZSTD_compress_usingCDict(cctx, ZSTR_VAL(output), cBuffSize, - input, - input_len, - cdict); - if (ZSTD_IS_ERROR(cSize)) { + result = ZSTD_compress_usingCDict(cctx, ZSTR_VAL(output), size, + input, input_len, cdict); + if (ZSTD_IS_ERROR(result)) { ZSTD_freeCStream(cctx); ZSTD_freeCDict(cdict); zend_string_efree(output); - ZSTD_WARNING("%s", ZSTD_getErrorName(cSize)); + ZSTD_WARNING("%s", ZSTD_getErrorName(result)); RETURN_FALSE; } - output = zstd_string_output_truncate(output, cSize); - RETVAL_NEW_STR(output); - ZSTD_freeCCtx(cctx); ZSTD_freeCDict(cdict); + + output = zstd_string_output_truncate(output, result); + RETVAL_NEW_STR(output); } ZEND_FUNCTION(zstd_uncompress_dict) From a2903dbbf6b6f70e21e64821bfbd920248764df1 Mon Sep 17 00:00:00 2001 From: kjdev Date: Fri, 18 Apr 2025 08:24:05 +0900 Subject: [PATCH 03/11] feat: support stream with zstd_uncompress_dict() --- zstd.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/zstd.c b/zstd.c index 207eb3a..29a7522 100644 --- a/zstd.c +++ b/zstd.c @@ -397,10 +397,42 @@ ZEND_FUNCTION(zstd_uncompress_dict) RETURN_FALSE; } } else { - zend_string_efree(output); - ZSTD_freeDDict(ddict); - ZSTD_WARNING("can not decompress stream"); - RETURN_FALSE; + ZSTD_inBuffer in = { NULL, 0, 0 }; + ZSTD_outBuffer out = { NULL, 0, 0 }; + + ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only); + ZSTD_DCtx_refDDict(dctx, ddict); + + in.src = input; + in.size = input_len; + in.pos = 0; + + out.dst = ZSTR_VAL(output); + out.size = size; + out.pos = 0; + + while (in.pos < in.size) { + if (out.pos == out.size) { + out.size += size; + output = zend_string_extend(output, out.size, 0); + out.dst = ZSTR_VAL(output); + } + + result = ZSTD_decompressStream(dctx, &out, &in); + if (ZSTD_IS_ERROR(result)) { + zend_string_efree(output); + ZSTD_freeDCtx(dctx); + ZSTD_freeDDict(ddict); + ZSTD_WARNING("%s", ZSTD_getErrorName(result)); + RETURN_FALSE; + } + + if (result == 0) { + break; + } + } + + result = out.pos; } ZSTD_freeDCtx(dctx); From 2c079cd6a52f01eee7573cbd75f52415579abe07 Mon Sep 17 00:00:00 2001 From: kjdev Date: Fri, 18 Apr 2025 08:29:11 +0900 Subject: [PATCH 04/11] test: add stream for zstd_uncompress_dict() --- tests/dictionary_02.phpt | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/dictionary_02.phpt diff --git a/tests/dictionary_02.phpt b/tests/dictionary_02.phpt new file mode 100644 index 0000000..9139542 --- /dev/null +++ b/tests/dictionary_02.phpt @@ -0,0 +1,35 @@ +--TEST-- +zstd_uncompress_dict(): streaming archive +--FILE-- + array( + "level" => ZSTD_COMPRESS_LEVEL_DEFAULT, + "dict" => $dictionary, + ) + ) +); + +var_dump(file_put_contents('compress.zstd://' . $file, $data, 0, $ctx) == strlen($data)); + +echo "Decompression\n"; + +var_dump(zstd_uncompress_dict(file_get_contents($file), $dictionary) === $data); + +@unlink($file); +?> +===Done=== +--EXPECTF-- +Compression +bool(true) +Decompression +bool(true) +===Done=== From adbd406b2a053865e433e2e888c5b69e00990332 Mon Sep 17 00:00:00 2001 From: kjdev Date: Fri, 18 Apr 2025 08:31:39 +0900 Subject: [PATCH 05/11] test: change to fit the minimum system libzstd library version --- tests/008.phpt | 72 ---------------------------------------- tests/009.phpt | 4 --- tests/dictionary_01.phpt | 4 --- tests/streams_5.phpt | 4 --- 4 files changed, 84 deletions(-) delete mode 100644 tests/008.phpt diff --git a/tests/008.phpt b/tests/008.phpt deleted file mode 100644 index a319049..0000000 --- a/tests/008.phpt +++ /dev/null @@ -1,72 +0,0 @@ ---TEST-- -zstd_compress(): compress level ---SKIPIF-- -= 10304) die("skip needs libzstd 1.3.3 or older"); -?> ---FILE-- - -===Done=== ---EXPECTF-- -*** Data size *** -3547 -*** Compression Level *** -1 -- 1%d -- true -2 -- 1%d -- true -3 -- 1%d -- true -4 -- 1%d -- true -5 -- 1%d -- true -6 -- 1%d -- true -7 -- 1%d -- true -8 -- 1%d -- true -9 -- 1%d -- true -10 -- 1%d -- true -11 -- 1%d -- true -12 -- 1%d -- true -13 -- 1%d -- true -14 -- 1%d -- true -15 -- 1%d -- true -16 -- 1%d -- true -17 -- 1%d -- true -18 -- 1%d -- true -19 -- 1%d -- true -20 -- 1%d -- true -21 -- 1%d -- true -22 -- 1%d -- true -*** Invalid Compression Level *** - -Warning: zstd_compress: compression level (100) must be within 1..22 in %s on line %d -100 -- 0 -- -Warning: zstd_uncompress: it was not compressed by zstd in %s on line %d -false - -Warning: zstd_compress: compression level (-1) must be within 1..22 in %s on line %d --1 -- 0 -- -Warning: zstd_uncompress: it was not compressed by zstd in %s on line %d -false -===Done=== diff --git a/tests/009.phpt b/tests/009.phpt index b12233b..293c1df 100644 --- a/tests/009.phpt +++ b/tests/009.phpt @@ -1,9 +1,5 @@ --TEST-- zstd_compress(): compress level ---SKIPIF-- - --FILE-- --FILE-- --FILE-- Date: Fri, 18 Apr 2025 08:35:16 +0900 Subject: [PATCH 06/11] docs: add minimu system libzstd library version to README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 92c91ae..88195d4 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ To use the system library % ./configure --with-libzstd ``` +> minimum system libzstd library version to 1.4.0 + Install from [pecl](https://pecl.php.net/package/zstd): ``` bash From 147b93dc84053e56f6eb83340e7e20b0bfa9f94c Mon Sep 17 00:00:00 2001 From: kjdev Date: Fri, 18 Apr 2025 08:40:15 +0900 Subject: [PATCH 07/11] chore: update built-in zstd library to 1.5.7 --- config.m4 | 1 + config.w32 | 2 +- zstd | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config.m4 b/config.m4 index f0a12cf..304eccd 100644 --- a/config.m4 +++ b/config.m4 @@ -73,6 +73,7 @@ if test "$PHP_ZSTD" != "no"; then zstd/lib/compress/zstd_lazy.c zstd/lib/compress/zstd_ldm.c zstd/lib/compress/zstd_opt.c + zstd/lib/compress/zstd_preSplit.c zstd/lib/compress/zstdmt_compress.c " ZSTD_DECOMPRESS_SOURCES=" diff --git a/config.w32 b/config.w32 index 07443f9..466da7c 100644 --- a/config.w32 +++ b/config.w32 @@ -20,7 +20,7 @@ if (PHP_ZSTD != "no") { EXTENSION("zstd", "zstd.c", null, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); ADD_SOURCES("zstd/lib/common", "debug.c entropy_common.c error_private.c fse_decompress.c pool.c threading.c xxhash.c zstd_common.c", "zstd"); - ADD_SOURCES("zstd/lib/compress", "fse_compress.c hist.c huf_compress.c zstd_compress.c zstd_compress_literals.c zstd_compress_sequences.c zstd_compress_superblock.c zstd_double_fast.c zstd_fast.c zstd_lazy.c zstd_ldm.c zstd_opt.c zstdmt_compress.c", "zstd"); + ADD_SOURCES("zstd/lib/compress", "fse_compress.c hist.c huf_compress.c zstd_compress.c zstd_compress_literals.c zstd_compress_sequences.c zstd_compress_superblock.c zstd_double_fast.c zstd_fast.c zstd_lazy.c zstd_ldm.c zstd_opt.c zstd_preSplit.c zstdmt_compress.c", "zstd"); ADD_SOURCES("zstd/lib/decompress", "huf_decompress.c zstd_ddict.c zstd_decompress.c zstd_decompress_block.c", "zstd"); ADD_FLAG("CFLAGS_ZSTD", " /I" + configure_module_dirname + " /I" + configure_module_dirname + "/zstd/lib/common" + " /I" + configure_module_dirname + "/zstd/lib"); diff --git a/zstd b/zstd index 794ea1b..f8745da 160000 --- a/zstd +++ b/zstd @@ -1 +1 @@ -Subproject commit 794ea1b0afca0f020f4e57b6732332231fb23c70 +Subproject commit f8745da6ff1ad1e7bab384bd1f9d742439278e99 From 596872901b93d6e893dd9ba98f42df6dbc0895b5 Mon Sep 17 00:00:00 2001 From: kjdev Date: Fri, 18 Apr 2025 08:54:45 +0900 Subject: [PATCH 08/11] change: error message --- zstd.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/zstd.c b/zstd.c index 29a7522..ea96127 100644 --- a/zstd.c +++ b/zstd.c @@ -225,7 +225,7 @@ ZEND_FUNCTION(zstd_uncompress) if (ZSTD_IS_ERROR(result)) { zend_string_efree(output); - ZSTD_WARNING("can not decompress stream"); + ZSTD_WARNING("%s", ZSTD_getErrorName(result)); RETURN_FALSE; } @@ -237,7 +237,7 @@ ZEND_FUNCTION(zstd_uncompress) stream = ZSTD_createDStream(); if (stream == NULL) { zend_string_efree(output); - ZSTD_WARNING("can not create stream"); + ZSTD_WARNING("failed to create decompress context"); RETURN_FALSE; } @@ -245,7 +245,7 @@ ZEND_FUNCTION(zstd_uncompress) if (ZSTD_IS_ERROR(result)) { zend_string_efree(output); ZSTD_freeDStream(stream); - ZSTD_WARNING("can not init stream"); + ZSTD_WARNING("%s", ZSTD_getErrorName(result)); RETURN_FALSE; } @@ -268,7 +268,7 @@ ZEND_FUNCTION(zstd_uncompress) if (ZSTD_IS_ERROR(result)) { zend_string_efree(output); ZSTD_freeDStream(stream); - ZSTD_WARNING("can not decompress stream"); + ZSTD_WARNING("%s", ZSTD_getErrorName(result)); RETURN_FALSE; } @@ -308,14 +308,14 @@ ZEND_FUNCTION(zstd_compress_dict) cctx = ZSTD_createCCtx(); if (cctx == NULL) { - ZSTD_WARNING("ZSTD_createCCtx() error"); + ZSTD_WARNING("failed to create compress context"); RETURN_FALSE; } cdict = ZSTD_createCDict(dict, dict_len, (int) level); if (!cdict) { ZSTD_freeCStream(cctx); - ZSTD_WARNING("ZSTD_createCDict() error"); + ZSTD_WARNING("failed to load dictionary"); RETURN_FALSE; } @@ -366,7 +366,7 @@ ZEND_FUNCTION(zstd_uncompress_dict) ddict = ZSTD_createDDict(dict, dict_len); if (!ddict) { - ZSTD_WARNING("ZSTD_createDDict() error"); + ZSTD_WARNING("failed to load dictionary"); RETURN_FALSE; } @@ -376,7 +376,7 @@ ZEND_FUNCTION(zstd_uncompress_dict) if (dctx == NULL) { zend_string_efree(output); ZSTD_freeDDict(ddict); - ZSTD_WARNING("ZSTD_createDCtx() error"); + ZSTD_WARNING("failed to create decompress context"); RETURN_FALSE; } @@ -496,8 +496,7 @@ static int php_zstd_comp_flush_or_end(php_zstd_stream_data *self, int end) res = ZSTD_compressStream2(self->cctx, &self->output, &in, end ? ZSTD_e_end : ZSTD_e_flush); if (ZSTD_isError(res)) { - php_error_docref(NULL, E_WARNING, - "libzstd error %s\n", ZSTD_getErrorName(res)); + ZSTD_WARNING("zstd: %s\n", ZSTD_getErrorName(res)); ret = EOF; } php_stream_write(self->stream, self->output.dst, self->output.pos); @@ -578,8 +577,7 @@ static ssize_t php_zstd_decomp_read(php_stream *stream, char *buf, size_t count) res = ZSTD_decompressStream(self->dctx, &self->output, &self->input); if (ZSTD_IS_ERROR(res)) { - php_error_docref(NULL, E_WARNING, - "libzstd error %s\n", ZSTD_getErrorName(res)); + ZSTD_WARNING("zstd: %s\n", ZSTD_getErrorName(res)); #if PHP_VERSION_ID >= 70400 return -1; #endif @@ -619,8 +617,7 @@ php_zstd_comp_write(php_stream *stream, const char *buf, size_t count) res = ZSTD_compressStream2(self->cctx, &self->output, &in, ZSTD_e_continue); if (ZSTD_isError(res)) { - php_error_docref(NULL, E_WARNING, - "libzstd error %s\n", ZSTD_getErrorName(res)); + ZSTD_WARNING("zstd: %s\n", ZSTD_getErrorName(res)); #if PHP_VERSION_ID >= 70400 return -1; #endif @@ -717,9 +714,8 @@ php_stream_zstd_opener( } if (level > ZSTD_maxCLevel()) { - php_error_docref(NULL, E_WARNING, - "zstd: compression level (%d) must be less than %d", - level, ZSTD_maxCLevel()); + ZSTD_WARNING("zstd: compression level (%d) must be less than %d", + level, ZSTD_maxCLevel()); level = ZSTD_maxCLevel(); } @@ -736,8 +732,7 @@ php_stream_zstd_opener( self->dctx = NULL; self->cctx = ZSTD_createCCtx(); if (!self->cctx) { - php_error_docref(NULL, E_WARNING, - "zstd: compression context failed"); + ZSTD_WARNING("zstd: compression context failed"); php_stream_close(self->stream); efree(self); return NULL; @@ -755,8 +750,7 @@ php_stream_zstd_opener( } else { self->dctx = ZSTD_createDCtx(); if (!self->dctx) { - php_error_docref(NULL, E_WARNING, - "zstd: compression context failed"); + ZSTD_WARNING("zstd: compression context failed"); php_stream_close(self->stream); efree(self); return NULL; @@ -941,7 +935,7 @@ php_zstd_output_handler_load_dict(php_zstd_context *ctx, int level) REPORT_ERRORS, // | USE_PATH NULL, context); if (!stream) { - ZSTD_WARNING("could not open dictionary stream: %s", dict); + ZSTD_WARNING("failed to open dictionary stream: %s", dict); return; } From e8bde67fedbf55470077200c344c63f1a70d41a2 Mon Sep 17 00:00:00 2001 From: kjdev Date: Mon, 21 Apr 2025 07:21:53 +0900 Subject: [PATCH 09/11] fixup! refactor: zstd_compress_dict() --- zstd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zstd.c b/zstd.c index ea96127..5afb9af 100644 --- a/zstd.c +++ b/zstd.c @@ -314,7 +314,7 @@ ZEND_FUNCTION(zstd_compress_dict) cdict = ZSTD_createCDict(dict, dict_len, (int) level); if (!cdict) { - ZSTD_freeCStream(cctx); + ZSTD_freeCCtx(cctx); ZSTD_WARNING("failed to load dictionary"); RETURN_FALSE; } @@ -325,7 +325,7 @@ ZEND_FUNCTION(zstd_compress_dict) result = ZSTD_compress_usingCDict(cctx, ZSTR_VAL(output), size, input, input_len, cdict); if (ZSTD_IS_ERROR(result)) { - ZSTD_freeCStream(cctx); + ZSTD_freeCCtx(cctx); ZSTD_freeCDict(cdict); zend_string_efree(output); ZSTD_WARNING("%s", ZSTD_getErrorName(result)); From d72bd9603b4a8671431303590791e4e0d1bcb0db Mon Sep 17 00:00:00 2001 From: kjdev Date: Mon, 21 Apr 2025 07:31:32 +0900 Subject: [PATCH 10/11] fixup! refactor: zstd_uncompress_dict() --- zstd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zstd.c b/zstd.c index 5afb9af..7232c4c 100644 --- a/zstd.c +++ b/zstd.c @@ -356,7 +356,9 @@ ZEND_FUNCTION(zstd_uncompress_dict) ZEND_PARSE_PARAMETERS_END(); size = ZSTD_getFrameContentSize(input, input_len); - if (size == 0 || size == ZSTD_CONTENTSIZE_ERROR) { + if (size == 0) { + RETURN_EMPTY_STRING(); + } else if (size == ZSTD_CONTENTSIZE_ERROR) { ZSTD_WARNING("it was not compressed by zstd"); RETURN_FALSE; } else if (size == ZSTD_CONTENTSIZE_UNKNOWN) { From 72307786b240943e183152c4214c8492cac62a43 Mon Sep 17 00:00:00 2001 From: kjdev Date: Mon, 21 Apr 2025 07:49:01 +0900 Subject: [PATCH 11/11] fixup! refactor: zstd_uncompress_dict() --- zstd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zstd.c b/zstd.c index 7232c4c..f4e4fb8 100644 --- a/zstd.c +++ b/zstd.c @@ -363,7 +363,7 @@ ZEND_FUNCTION(zstd_uncompress_dict) RETURN_FALSE; } else if (size == ZSTD_CONTENTSIZE_UNKNOWN) { streaming = 1; - size = ZSTD_DStreamOutSize(); + size = ZSTD_DStreamOutSize() + input_len; } ddict = ZSTD_createDDict(dict, dict_len); @@ -401,6 +401,7 @@ ZEND_FUNCTION(zstd_uncompress_dict) } else { ZSTD_inBuffer in = { NULL, 0, 0 }; ZSTD_outBuffer out = { NULL, 0, 0 }; + size_t chunk = ZSTD_DStreamOutSize(); ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only); ZSTD_DCtx_refDDict(dctx, ddict); @@ -415,7 +416,7 @@ ZEND_FUNCTION(zstd_uncompress_dict) while (in.pos < in.size) { if (out.pos == out.size) { - out.size += size; + out.size += chunk; output = zend_string_extend(output, out.size, 0); out.dst = ZSTR_VAL(output); }