Skip to content

Commit 80a5099

Browse files
committed
fix: streaming compressed data with zstd_uncompress_dict()
1 parent 044cc55 commit 80a5099

File tree

1 file changed

+73
-24
lines changed

1 file changed

+73
-24
lines changed

zstd.c

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -543,51 +543,100 @@ ZEND_FUNCTION(zstd_uncompress_dict)
543543
char *input, *dict;
544544
size_t input_len, dict_len;
545545
zend_string *output;
546+
uint8_t streaming = 0;
547+
size_t result;
548+
unsigned long long size;
549+
ZSTD_DCtx *dctx;
550+
ZSTD_DDict *ddict;
546551

547552
ZEND_PARSE_PARAMETERS_START(2, 2)
548553
Z_PARAM_STRING(input, input_len)
549554
Z_PARAM_STRING(dict, dict_len)
550555
ZEND_PARSE_PARAMETERS_END();
551556

552-
unsigned long long const rSize = ZSTD_getFrameContentSize(input,
553-
input_len);
554-
555-
if (rSize == 0 || rSize == ZSTD_CONTENTSIZE_ERROR) {
557+
size = ZSTD_getFrameContentSize(input, input_len);
558+
if (size == 0) {
559+
RETURN_EMPTY_STRING();
560+
} else if (size == ZSTD_CONTENTSIZE_ERROR) {
556561
ZSTD_WARNING("it was not compressed by zstd");
557562
RETURN_FALSE;
563+
} else if (size == ZSTD_CONTENTSIZE_UNKNOWN) {
564+
streaming = 1;
565+
size = input_len + ZSTD_DStreamOutSize();
558566
}
559567

560-
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
568+
dctx = ZSTD_createDCtx();
561569
if (dctx == NULL) {
562-
ZSTD_WARNING("ZSTD_createDCtx() error");
570+
ZSTD_WARNING("failed to prepare uncompression");
563571
RETURN_FALSE;
564572
}
565-
ZSTD_DDict* const ddict = ZSTD_createDDict(dict,
566-
dict_len);
573+
ddict = ZSTD_createDDict(dict, dict_len);
567574
if (!ddict) {
568-
ZSTD_freeDStream(dctx);
569-
ZSTD_WARNING("ZSTD_createDDict() error");
575+
ZSTD_freeDCtx(dctx);
576+
ZSTD_WARNING("failed to load dictionary");
570577
RETURN_FALSE;
571578
}
572579

573-
output = zend_string_alloc(rSize, 0);
580+
output = zend_string_alloc(size, 0);
574581

575-
size_t const dSize = ZSTD_decompress_usingDDict(dctx, ZSTR_VAL(output), rSize,
576-
input,
577-
input_len,
578-
ddict);
579-
if (dSize != rSize) {
580-
ZSTD_freeDStream(dctx);
581-
ZSTD_freeDDict(ddict);
582-
zend_string_efree(output);
583-
ZSTD_WARNING("%s", ZSTD_getErrorName(dSize));
584-
RETURN_FALSE;
582+
if (!streaming) {
583+
result = ZSTD_decompress_usingDDict(dctx, ZSTR_VAL(output), size,
584+
input, input_len, ddict);
585+
if (ZSTD_IS_ERROR(result)) {
586+
zend_string_efree(output);
587+
ZSTD_WARNING("%s", ZSTD_getErrorName(result));
588+
RETVAL_FALSE;
589+
} else if (result != size) {
590+
zend_string_efree(output);
591+
ZSTD_WARNING("failed to uncompress");
592+
RETVAL_FALSE;
593+
} else {
594+
output = zstd_string_output_truncate(output, result);
595+
RETVAL_NEW_STR(output);
596+
}
597+
} else {
598+
ZSTD_inBuffer in = { NULL, 0, 0 };
599+
ZSTD_outBuffer out = { NULL, 0, 0 };
600+
size_t chunk = ZSTD_DStreamOutSize();
601+
602+
ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
603+
ZSTD_DCtx_refDDict(dctx, ddict);
604+
605+
in.src = input;
606+
in.size = input_len;
607+
in.pos = 0;
608+
609+
out.dst = ZSTR_VAL(output);
610+
out.size = size;
611+
out.pos = 0;
612+
613+
while (in.pos < in.size) {
614+
if (out.pos == out.size) {
615+
out.size += chunk;
616+
output = zend_string_extend(output, out.size, 0);
617+
out.dst = ZSTR_VAL(output);
618+
}
619+
620+
result = ZSTD_decompressStream(dctx, &out, &in);
621+
if (ZSTD_IS_ERROR(result)) {
622+
zend_string_efree(output);
623+
ZSTD_freeDCtx(dctx);
624+
ZSTD_freeDDict(ddict);
625+
ZSTD_WARNING("%s", ZSTD_getErrorName(result));
626+
RETURN_FALSE;
627+
}
628+
629+
if (result == 0) {
630+
break;
631+
}
632+
}
633+
634+
output = zstd_string_output_truncate(output, out.pos);
635+
RETVAL_NEW_STR(output);
585636
}
637+
586638
ZSTD_freeDCtx(dctx);
587639
ZSTD_freeDDict(ddict);
588-
589-
output = zstd_string_output_truncate(output, dSize);
590-
RETVAL_NEW_STR(output);
591640
}
592641

593642
ZEND_FUNCTION(zstd_compress_init)

0 commit comments

Comments
 (0)