@@ -169,6 +169,8 @@ static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
169169#ifdef ZSTD_MULTITHREAD
170170 ZSTDMT_freeCCtx (cctx -> mtctx ); cctx -> mtctx = NULL ;
171171#endif
172+ ZSTD_customFree (cctx -> preBuff , cctx -> customMem );
173+ cctx -> preBuff = NULL ; cctx -> preFilled = 0 ;
172174 ZSTD_cwksp_free (& cctx -> workspace , cctx -> customMem );
173175}
174176
@@ -5318,8 +5320,12 @@ size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
53185320
53195321static size_t ZSTD_nextInputSizeHint (const ZSTD_CCtx * cctx )
53205322{
5321- size_t hintInSize = cctx -> inBuffTarget - cctx -> inBuffPos ;
5322- if (hintInSize == 0 ) hintInSize = cctx -> blockSize ;
5323+ size_t const hintInSize = cctx -> inBuffTarget - cctx -> inBuffPos ;
5324+ if (hintInSize == 0 ) return cctx -> blockSize ;
5325+ if (cctx -> streamStage == zcss_init ) {
5326+ assert (cctx -> preFilled < ZSTD_BLOCKSIZE_MAX );
5327+ return ZSTD_BLOCKSIZE_MAX - cctx -> preFilled ;
5328+ }
53235329 return hintInSize ;
53245330}
53255331
@@ -5503,7 +5509,6 @@ static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx)
55035509 }
55045510#endif
55055511 return ZSTD_nextInputSizeHint (cctx );
5506-
55075512}
55085513
55095514size_t ZSTD_compressStream (ZSTD_CStream * zcs , ZSTD_outBuffer * output , ZSTD_inBuffer * input )
@@ -5512,6 +5517,29 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf
55125517 return ZSTD_nextInputSizeHint_MTorST (zcs );
55135518}
55145519
5520+
5521+ /* Flush early input into a buffer before initialization, for late parameter adaptation
5522+ * @return provides a minimum amount of data remaining to be flushed
5523+ */
5524+ static size_t ZSTD_preBuff (ZSTD_CCtx * cctx , ZSTD_inBuffer * input )
5525+ {
5526+ assert (cctx != NULL );
5527+ assert (input != NULL );
5528+ if (cctx -> preBuff == NULL )
5529+ cctx -> preBuff = (char * )ZSTD_customMalloc (ZSTD_BLOCKSIZE_MAX , cctx -> customMem );
5530+ RETURN_ERROR_IF (cctx -> preBuff == NULL , memory_allocation , "" );
5531+ assert (input -> size >= input -> pos );
5532+ { size_t const toFill = input -> size - input -> pos ;
5533+ DEBUGLOG (5 , "ZSTD_preBuff :%4zu bytes (%5zu already buffered)" , toFill , cctx -> preFilled );
5534+ assert (cctx -> preFilled + toFill < ZSTD_BLOCKSIZE_MAX );
5535+ ZSTD_memcpy (cctx -> preBuff + cctx -> preFilled , (const char * )input -> src + input -> pos , toFill );
5536+ cctx -> preFilled += toFill ;
5537+ input -> pos = input -> size ;
5538+ }
5539+ return ZSTD_FRAMEHEADERSIZE_MIN (ZSTD_f_zstd1 ); /* frame not even started */
5540+ }
5541+
5542+
55155543/* After a compression call set the expected input/output buffer.
55165544 * This is validated at the start of the next compression call.
55175545 */
@@ -5550,7 +5578,8 @@ static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx,
55505578
55515579static size_t ZSTD_CCtx_init_compressStream2 (ZSTD_CCtx * cctx ,
55525580 ZSTD_EndDirective endOp ,
5553- size_t inSize ) {
5581+ size_t inSize )
5582+ {
55545583 ZSTD_CCtx_params params = cctx -> requestedParams ;
55555584 ZSTD_prefixDict const prefixDict = cctx -> prefixDict ;
55565585 FORWARD_IF_ERROR ( ZSTD_initLocalDict (cctx ) , "" ); /* Init the local dict if present. */
@@ -5565,6 +5594,7 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
55655594 }
55665595 DEBUGLOG (4 , "ZSTD_compressStream2 : transparent init stage" );
55675596 if (endOp == ZSTD_e_end ) cctx -> pledgedSrcSizePlusOne = inSize + 1 ; /* auto-fix pledgedSrcSize */
5597+ if (endOp == ZSTD_e_end ) DEBUGLOG (4 , "pledgedSrcSize automatically set to %zu" , inSize );
55685598 {
55695599 size_t const dictSize = prefixDict .dict
55705600 ? prefixDict .dictSize
@@ -5618,14 +5648,16 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
56185648 assert (cctx -> appliedParams .nbWorkers == 0 );
56195649 cctx -> inToCompress = 0 ;
56205650 cctx -> inBuffPos = 0 ;
5651+ DEBUGLOG (5 , "cctx->blockSize = %zu" , cctx -> blockSize );
56215652 if (cctx -> appliedParams .inBufferMode == ZSTD_bm_buffered ) {
56225653 /* for small input: avoid automatic flush on reaching end of block, since
5623- * it would require to add a 3-bytes null block to end frame
5624- */
5654+ * it would require to add a 3-bytes null block to end frame
5655+ */
56255656 cctx -> inBuffTarget = cctx -> blockSize + (cctx -> blockSize == pledgedSrcSize );
56265657 } else {
56275658 cctx -> inBuffTarget = 0 ;
56285659 }
5660+ DEBUGLOG (5 , "cctx->inBuffTarget = %zu" , cctx -> inBuffTarget );
56295661 cctx -> outBuffContentSize = cctx -> outBuffFlushedSize = 0 ;
56305662 cctx -> streamStage = zcss_load ;
56315663 cctx -> frameEnded = 0 ;
@@ -5638,7 +5670,7 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
56385670 ZSTD_inBuffer * input ,
56395671 ZSTD_EndDirective endOp )
56405672{
5641- DEBUGLOG (5 , "ZSTD_compressStream2, endOp=%u " , (unsigned )endOp );
5673+ DEBUGLOG (5 , "ZSTD_compressStream2, endOp=%u" , (unsigned )endOp );
56425674 /* check conditions */
56435675 RETURN_ERROR_IF (output -> pos > output -> size , dstSize_tooSmall , "invalid output buffer" );
56445676 RETURN_ERROR_IF (input -> pos > input -> size , srcSize_wrong , "invalid input buffer" );
@@ -5647,8 +5679,28 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
56475679
56485680 /* transparent initialization stage */
56495681 if (cctx -> streamStage == zcss_init ) {
5650- FORWARD_IF_ERROR (ZSTD_CCtx_init_compressStream2 (cctx , endOp , input -> size ), "CompressStream2 initialization failed" );
5651- ZSTD_setBufferExpectations (cctx , output , input ); /* Set initial buffer expectations now that we've initialized */
5682+ if ( (endOp == ZSTD_e_continue ) /* no immediate flush requested -> opportunity for buffering */
5683+ && (cctx -> staticSize == 0 ) /* not compatible with initStatic */
5684+ && (cctx -> requestedParams .inBufferMode == ZSTD_bm_buffered ) /* only for buffered mode */
5685+ && (cctx -> pledgedSrcSizePlusOne == 0 ) /* no need if srcSize is known */
5686+ && (cctx -> requestedParams .cParams .windowLog >= 17 ) /* not compatible with small window sizes (yet) */
5687+ && (cctx -> preFilled + (input -> size - input -> pos ) < ZSTD_BLOCKSIZE_MAX )
5688+ ) {
5689+ return ZSTD_preBuff (cctx , input ); /* pre-buffer input, initialization will happen later, a chance for better parameter adaptation */
5690+ }
5691+ { size_t const totalInput = cctx -> preFilled + input -> size - input -> pos ; /* only matters if ZSTD_e_end */
5692+ FORWARD_IF_ERROR (ZSTD_CCtx_init_compressStream2 (cctx , endOp , totalInput ), "CompressStream2 initialization failed" );
5693+ }
5694+ if (cctx -> preFilled ) { /* transfer pre-buffered input into inBuff */
5695+ ZSTD_inBuffer in ;
5696+ in .src = cctx -> preBuff ;
5697+ in .pos = 0 ;
5698+ in .size = cctx -> preFilled ;
5699+ cctx -> preFilled = 0 ;
5700+ ZSTD_compressStream2 (cctx , output , & in , ZSTD_e_continue );
5701+ assert (in .pos == in .size ); /* there should be enough space to ingest the entire preBuffed input */
5702+ }
5703+ ZSTD_setBufferExpectations (cctx , output , input ); /* Set initial buffer expectations now that we've initialized (ZSTD_bm_stable only) */
56525704 }
56535705 /* end of transparent initialization stage */
56545706
0 commit comments