1 /* 2 * Copyright (c) Yann Collet, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under both the BSD-style license (found in the 6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 * in the COPYING file in the root directory of this source tree). 8 * You may select, at your option, one of the above-listed licenses. 9 */ 10 11 /*-************************************* 12 * Dependencies 13 ***************************************/ 14 #include "../common/zstd_deps.h" /* INT_MAX, ZSTD_memset, ZSTD_memcpy */ 15 #include "../common/cpu.h" 16 #include "../common/mem.h" 17 #include "hist.h" /* HIST_countFast_wksp */ 18 #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ 19 #include "../common/fse.h" 20 #define HUF_STATIC_LINKING_ONLY 21 #include "../common/huf.h" 22 #include "zstd_compress_internal.h" 23 #include "zstd_compress_sequences.h" 24 #include "zstd_compress_literals.h" 25 #include "zstd_fast.h" 26 #include "zstd_double_fast.h" 27 #include "zstd_lazy.h" 28 #include "zstd_opt.h" 29 #include "zstd_ldm.h" 30 #include "zstd_compress_superblock.h" 31 32 /* *************************************************************** 33 * Tuning parameters 34 *****************************************************************/ 35 /*! 36 * COMPRESS_HEAPMODE : 37 * Select how default decompression function ZSTD_compress() allocates its context, 38 * on stack (0, default), or into heap (1). 39 * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected. 40 */ 41 42 43 /*-************************************* 44 * Helper functions 45 ***************************************/ 46 /* ZSTD_compressBound() 47 * Note that the result from this function is only compatible with the "normal" 48 * full-block strategy. 49 * When there are a lot of small blocks due to frequent flush in streaming mode 50 * the overhead of headers can make the compressed data to be larger than the 51 * return value of ZSTD_compressBound(). 52 */ 53 size_t ZSTD_compressBound(size_t srcSize) { 54 return ZSTD_COMPRESSBOUND(srcSize); 55 } 56 57 58 /*-************************************* 59 * Context memory management 60 ***************************************/ 61 struct ZSTD_CDict_s { 62 const void* dictContent; 63 size_t dictContentSize; 64 ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */ 65 U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ 66 ZSTD_cwksp workspace; 67 ZSTD_matchState_t matchState; 68 ZSTD_compressedBlockState_t cBlockState; 69 ZSTD_customMem customMem; 70 U32 dictID; 71 int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */ 72 }; /* typedef'd to ZSTD_CDict within "zstd.h" */ 73 74 ZSTD_CCtx* ZSTD_createCCtx(void) 75 { 76 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); 77 } 78 79 static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) 80 { 81 assert(cctx != NULL); 82 ZSTD_memset(cctx, 0, sizeof(*cctx)); 83 cctx->customMem = memManager; 84 cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 85 { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); 86 assert(!ZSTD_isError(err)); 87 (void)err; 88 } 89 } 90 91 ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) 92 { 93 ZSTD_STATIC_ASSERT(zcss_init==0); 94 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); 95 if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; 96 { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem); 97 if (!cctx) return NULL; 98 ZSTD_initCCtx(cctx, customMem); 99 return cctx; 100 } 101 } 102 103 ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) 104 { 105 ZSTD_cwksp ws; 106 ZSTD_CCtx* cctx; 107 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ 108 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ 109 ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); 110 111 cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx)); 112 if (cctx == NULL) return NULL; 113 114 ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx)); 115 ZSTD_cwksp_move(&cctx->workspace, &ws); 116 cctx->staticSize = workspaceSize; 117 118 /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ 119 if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; 120 cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); 121 cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); 122 cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE); 123 cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 124 return cctx; 125 } 126 127 /* 128 * Clears and frees all of the dictionaries in the CCtx. 129 */ 130 static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) 131 { 132 ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem); 133 ZSTD_freeCDict(cctx->localDict.cdict); 134 ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict)); 135 ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); 136 cctx->cdict = NULL; 137 } 138 139 static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict) 140 { 141 size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0; 142 size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict); 143 return bufferSize + cdictSize; 144 } 145 146 static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) 147 { 148 assert(cctx != NULL); 149 assert(cctx->staticSize == 0); 150 ZSTD_clearAllDicts(cctx); 151 ZSTD_cwksp_free(&cctx->workspace, cctx->customMem); 152 } 153 154 size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 155 { 156 if (cctx==NULL) return 0; /* support free on NULL */ 157 RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 158 "not compatible with static CCtx"); 159 { 160 int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); 161 ZSTD_freeCCtxContent(cctx); 162 if (!cctxInWorkspace) { 163 ZSTD_customFree(cctx, cctx->customMem); 164 } 165 } 166 return 0; 167 } 168 169 170 static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) 171 { 172 (void)cctx; 173 return 0; 174 } 175 176 177 size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 178 { 179 if (cctx==NULL) return 0; /* support sizeof on NULL */ 180 /* cctx may be in the workspace */ 181 return (cctx->workspace.workspace == cctx ? 0 : sizeof(*cctx)) 182 + ZSTD_cwksp_sizeof(&cctx->workspace) 183 + ZSTD_sizeof_localDict(cctx->localDict) 184 + ZSTD_sizeof_mtctx(cctx); 185 } 186 187 size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) 188 { 189 return ZSTD_sizeof_CCtx(zcs); /* same object */ 190 } 191 192 /* private API call, for dictBuilder only */ 193 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } 194 195 /* Returns 1 if compression parameters are such that we should 196 * enable long distance matching (wlog >= 27, strategy >= btopt). 197 * Returns 0 otherwise. 198 */ 199 static U32 ZSTD_CParams_shouldEnableLdm(const ZSTD_compressionParameters* const cParams) { 200 return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27; 201 } 202 203 static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( 204 ZSTD_compressionParameters cParams) 205 { 206 ZSTD_CCtx_params cctxParams; 207 /* should not matter, as all cParams are presumed properly defined */ 208 ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT); 209 cctxParams.cParams = cParams; 210 211 if (ZSTD_CParams_shouldEnableLdm(&cParams)) { 212 DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including LDM into cctx params"); 213 cctxParams.ldmParams.enableLdm = 1; 214 /* LDM is enabled by default for optimal parser and window size >= 128MB */ 215 ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams); 216 assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog); 217 assert(cctxParams.ldmParams.hashRateLog < 32); 218 } 219 220 assert(!ZSTD_checkCParams(cParams)); 221 return cctxParams; 222 } 223 224 static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( 225 ZSTD_customMem customMem) 226 { 227 ZSTD_CCtx_params* params; 228 if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; 229 params = (ZSTD_CCtx_params*)ZSTD_customCalloc( 230 sizeof(ZSTD_CCtx_params), customMem); 231 if (!params) { return NULL; } 232 ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 233 params->customMem = customMem; 234 return params; 235 } 236 237 ZSTD_CCtx_params* ZSTD_createCCtxParams(void) 238 { 239 return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); 240 } 241 242 size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) 243 { 244 if (params == NULL) { return 0; } 245 ZSTD_customFree(params, params->customMem); 246 return 0; 247 } 248 249 size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) 250 { 251 return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 252 } 253 254 size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { 255 RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); 256 ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); 257 cctxParams->compressionLevel = compressionLevel; 258 cctxParams->fParams.contentSizeFlag = 1; 259 return 0; 260 } 261 262 #define ZSTD_NO_CLEVEL 0 263 264 /* 265 * Initializes the cctxParams from params and compressionLevel. 266 * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. 267 */ 268 static void ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, ZSTD_parameters const* params, int compressionLevel) 269 { 270 assert(!ZSTD_checkCParams(params->cParams)); 271 ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); 272 cctxParams->cParams = params->cParams; 273 cctxParams->fParams = params->fParams; 274 /* Should not matter, as all cParams are presumed properly defined. 275 * But, set it for tracing anyway. 276 */ 277 cctxParams->compressionLevel = compressionLevel; 278 } 279 280 size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) 281 { 282 RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); 283 FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); 284 ZSTD_CCtxParams_init_internal(cctxParams, ¶ms, ZSTD_NO_CLEVEL); 285 return 0; 286 } 287 288 /* 289 * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone. 290 * @param param Validated zstd parameters. 291 */ 292 static void ZSTD_CCtxParams_setZstdParams( 293 ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params) 294 { 295 assert(!ZSTD_checkCParams(params->cParams)); 296 cctxParams->cParams = params->cParams; 297 cctxParams->fParams = params->fParams; 298 /* Should not matter, as all cParams are presumed properly defined. 299 * But, set it for tracing anyway. 300 */ 301 cctxParams->compressionLevel = ZSTD_NO_CLEVEL; 302 } 303 304 ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) 305 { 306 ZSTD_bounds bounds = { 0, 0, 0 }; 307 308 switch(param) 309 { 310 case ZSTD_c_compressionLevel: 311 bounds.lowerBound = ZSTD_minCLevel(); 312 bounds.upperBound = ZSTD_maxCLevel(); 313 return bounds; 314 315 case ZSTD_c_windowLog: 316 bounds.lowerBound = ZSTD_WINDOWLOG_MIN; 317 bounds.upperBound = ZSTD_WINDOWLOG_MAX; 318 return bounds; 319 320 case ZSTD_c_hashLog: 321 bounds.lowerBound = ZSTD_HASHLOG_MIN; 322 bounds.upperBound = ZSTD_HASHLOG_MAX; 323 return bounds; 324 325 case ZSTD_c_chainLog: 326 bounds.lowerBound = ZSTD_CHAINLOG_MIN; 327 bounds.upperBound = ZSTD_CHAINLOG_MAX; 328 return bounds; 329 330 case ZSTD_c_searchLog: 331 bounds.lowerBound = ZSTD_SEARCHLOG_MIN; 332 bounds.upperBound = ZSTD_SEARCHLOG_MAX; 333 return bounds; 334 335 case ZSTD_c_minMatch: 336 bounds.lowerBound = ZSTD_MINMATCH_MIN; 337 bounds.upperBound = ZSTD_MINMATCH_MAX; 338 return bounds; 339 340 case ZSTD_c_targetLength: 341 bounds.lowerBound = ZSTD_TARGETLENGTH_MIN; 342 bounds.upperBound = ZSTD_TARGETLENGTH_MAX; 343 return bounds; 344 345 case ZSTD_c_strategy: 346 bounds.lowerBound = ZSTD_STRATEGY_MIN; 347 bounds.upperBound = ZSTD_STRATEGY_MAX; 348 return bounds; 349 350 case ZSTD_c_contentSizeFlag: 351 bounds.lowerBound = 0; 352 bounds.upperBound = 1; 353 return bounds; 354 355 case ZSTD_c_checksumFlag: 356 bounds.lowerBound = 0; 357 bounds.upperBound = 1; 358 return bounds; 359 360 case ZSTD_c_dictIDFlag: 361 bounds.lowerBound = 0; 362 bounds.upperBound = 1; 363 return bounds; 364 365 case ZSTD_c_nbWorkers: 366 bounds.lowerBound = 0; 367 bounds.upperBound = 0; 368 return bounds; 369 370 case ZSTD_c_jobSize: 371 bounds.lowerBound = 0; 372 bounds.upperBound = 0; 373 return bounds; 374 375 case ZSTD_c_overlapLog: 376 bounds.lowerBound = 0; 377 bounds.upperBound = 0; 378 return bounds; 379 380 case ZSTD_c_enableDedicatedDictSearch: 381 bounds.lowerBound = 0; 382 bounds.upperBound = 1; 383 return bounds; 384 385 case ZSTD_c_enableLongDistanceMatching: 386 bounds.lowerBound = 0; 387 bounds.upperBound = 1; 388 return bounds; 389 390 case ZSTD_c_ldmHashLog: 391 bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN; 392 bounds.upperBound = ZSTD_LDM_HASHLOG_MAX; 393 return bounds; 394 395 case ZSTD_c_ldmMinMatch: 396 bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN; 397 bounds.upperBound = ZSTD_LDM_MINMATCH_MAX; 398 return bounds; 399 400 case ZSTD_c_ldmBucketSizeLog: 401 bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN; 402 bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX; 403 return bounds; 404 405 case ZSTD_c_ldmHashRateLog: 406 bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN; 407 bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX; 408 return bounds; 409 410 /* experimental parameters */ 411 case ZSTD_c_rsyncable: 412 bounds.lowerBound = 0; 413 bounds.upperBound = 1; 414 return bounds; 415 416 case ZSTD_c_forceMaxWindow : 417 bounds.lowerBound = 0; 418 bounds.upperBound = 1; 419 return bounds; 420 421 case ZSTD_c_format: 422 ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); 423 bounds.lowerBound = ZSTD_f_zstd1; 424 bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */ 425 return bounds; 426 427 case ZSTD_c_forceAttachDict: 428 ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad); 429 bounds.lowerBound = ZSTD_dictDefaultAttach; 430 bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */ 431 return bounds; 432 433 case ZSTD_c_literalCompressionMode: 434 ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed); 435 bounds.lowerBound = ZSTD_lcm_auto; 436 bounds.upperBound = ZSTD_lcm_uncompressed; 437 return bounds; 438 439 case ZSTD_c_targetCBlockSize: 440 bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN; 441 bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX; 442 return bounds; 443 444 case ZSTD_c_srcSizeHint: 445 bounds.lowerBound = ZSTD_SRCSIZEHINT_MIN; 446 bounds.upperBound = ZSTD_SRCSIZEHINT_MAX; 447 return bounds; 448 449 case ZSTD_c_stableInBuffer: 450 case ZSTD_c_stableOutBuffer: 451 bounds.lowerBound = (int)ZSTD_bm_buffered; 452 bounds.upperBound = (int)ZSTD_bm_stable; 453 return bounds; 454 455 case ZSTD_c_blockDelimiters: 456 bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters; 457 bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters; 458 return bounds; 459 460 case ZSTD_c_validateSequences: 461 bounds.lowerBound = 0; 462 bounds.upperBound = 1; 463 return bounds; 464 465 default: 466 bounds.error = ERROR(parameter_unsupported); 467 return bounds; 468 } 469 } 470 471 /* ZSTD_cParam_clampBounds: 472 * Clamps the value into the bounded range. 473 */ 474 static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) 475 { 476 ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); 477 if (ZSTD_isError(bounds.error)) return bounds.error; 478 if (*value < bounds.lowerBound) *value = bounds.lowerBound; 479 if (*value > bounds.upperBound) *value = bounds.upperBound; 480 return 0; 481 } 482 483 #define BOUNDCHECK(cParam, val) { \ 484 RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ 485 parameter_outOfBound, "Param out of bounds"); \ 486 } 487 488 489 static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) 490 { 491 switch(param) 492 { 493 case ZSTD_c_compressionLevel: 494 case ZSTD_c_hashLog: 495 case ZSTD_c_chainLog: 496 case ZSTD_c_searchLog: 497 case ZSTD_c_minMatch: 498 case ZSTD_c_targetLength: 499 case ZSTD_c_strategy: 500 return 1; 501 502 case ZSTD_c_format: 503 case ZSTD_c_windowLog: 504 case ZSTD_c_contentSizeFlag: 505 case ZSTD_c_checksumFlag: 506 case ZSTD_c_dictIDFlag: 507 case ZSTD_c_forceMaxWindow : 508 case ZSTD_c_nbWorkers: 509 case ZSTD_c_jobSize: 510 case ZSTD_c_overlapLog: 511 case ZSTD_c_rsyncable: 512 case ZSTD_c_enableDedicatedDictSearch: 513 case ZSTD_c_enableLongDistanceMatching: 514 case ZSTD_c_ldmHashLog: 515 case ZSTD_c_ldmMinMatch: 516 case ZSTD_c_ldmBucketSizeLog: 517 case ZSTD_c_ldmHashRateLog: 518 case ZSTD_c_forceAttachDict: 519 case ZSTD_c_literalCompressionMode: 520 case ZSTD_c_targetCBlockSize: 521 case ZSTD_c_srcSizeHint: 522 case ZSTD_c_stableInBuffer: 523 case ZSTD_c_stableOutBuffer: 524 case ZSTD_c_blockDelimiters: 525 case ZSTD_c_validateSequences: 526 default: 527 return 0; 528 } 529 } 530 531 size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) 532 { 533 DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value); 534 if (cctx->streamStage != zcss_init) { 535 if (ZSTD_isUpdateAuthorized(param)) { 536 cctx->cParamsChanged = 1; 537 } else { 538 RETURN_ERROR(stage_wrong, "can only set params in ctx init stage"); 539 } } 540 541 switch(param) 542 { 543 case ZSTD_c_nbWorkers: 544 RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported, 545 "MT not compatible with static alloc"); 546 break; 547 548 case ZSTD_c_compressionLevel: 549 case ZSTD_c_windowLog: 550 case ZSTD_c_hashLog: 551 case ZSTD_c_chainLog: 552 case ZSTD_c_searchLog: 553 case ZSTD_c_minMatch: 554 case ZSTD_c_targetLength: 555 case ZSTD_c_strategy: 556 case ZSTD_c_ldmHashRateLog: 557 case ZSTD_c_format: 558 case ZSTD_c_contentSizeFlag: 559 case ZSTD_c_checksumFlag: 560 case ZSTD_c_dictIDFlag: 561 case ZSTD_c_forceMaxWindow: 562 case ZSTD_c_forceAttachDict: 563 case ZSTD_c_literalCompressionMode: 564 case ZSTD_c_jobSize: 565 case ZSTD_c_overlapLog: 566 case ZSTD_c_rsyncable: 567 case ZSTD_c_enableDedicatedDictSearch: 568 case ZSTD_c_enableLongDistanceMatching: 569 case ZSTD_c_ldmHashLog: 570 case ZSTD_c_ldmMinMatch: 571 case ZSTD_c_ldmBucketSizeLog: 572 case ZSTD_c_targetCBlockSize: 573 case ZSTD_c_srcSizeHint: 574 case ZSTD_c_stableInBuffer: 575 case ZSTD_c_stableOutBuffer: 576 case ZSTD_c_blockDelimiters: 577 case ZSTD_c_validateSequences: 578 break; 579 580 default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 581 } 582 return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value); 583 } 584 585 size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, 586 ZSTD_cParameter param, int value) 587 { 588 DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value); 589 switch(param) 590 { 591 case ZSTD_c_format : 592 BOUNDCHECK(ZSTD_c_format, value); 593 CCtxParams->format = (ZSTD_format_e)value; 594 return (size_t)CCtxParams->format; 595 596 case ZSTD_c_compressionLevel : { 597 FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); 598 if (value == 0) 599 CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 600 else 601 CCtxParams->compressionLevel = value; 602 if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel; 603 return 0; /* return type (size_t) cannot represent negative values */ 604 } 605 606 case ZSTD_c_windowLog : 607 if (value!=0) /* 0 => use default */ 608 BOUNDCHECK(ZSTD_c_windowLog, value); 609 CCtxParams->cParams.windowLog = (U32)value; 610 return CCtxParams->cParams.windowLog; 611 612 case ZSTD_c_hashLog : 613 if (value!=0) /* 0 => use default */ 614 BOUNDCHECK(ZSTD_c_hashLog, value); 615 CCtxParams->cParams.hashLog = (U32)value; 616 return CCtxParams->cParams.hashLog; 617 618 case ZSTD_c_chainLog : 619 if (value!=0) /* 0 => use default */ 620 BOUNDCHECK(ZSTD_c_chainLog, value); 621 CCtxParams->cParams.chainLog = (U32)value; 622 return CCtxParams->cParams.chainLog; 623 624 case ZSTD_c_searchLog : 625 if (value!=0) /* 0 => use default */ 626 BOUNDCHECK(ZSTD_c_searchLog, value); 627 CCtxParams->cParams.searchLog = (U32)value; 628 return (size_t)value; 629 630 case ZSTD_c_minMatch : 631 if (value!=0) /* 0 => use default */ 632 BOUNDCHECK(ZSTD_c_minMatch, value); 633 CCtxParams->cParams.minMatch = value; 634 return CCtxParams->cParams.minMatch; 635 636 case ZSTD_c_targetLength : 637 BOUNDCHECK(ZSTD_c_targetLength, value); 638 CCtxParams->cParams.targetLength = value; 639 return CCtxParams->cParams.targetLength; 640 641 case ZSTD_c_strategy : 642 if (value!=0) /* 0 => use default */ 643 BOUNDCHECK(ZSTD_c_strategy, value); 644 CCtxParams->cParams.strategy = (ZSTD_strategy)value; 645 return (size_t)CCtxParams->cParams.strategy; 646 647 case ZSTD_c_contentSizeFlag : 648 /* Content size written in frame header _when known_ (default:1) */ 649 DEBUGLOG(4, "set content size flag = %u", (value!=0)); 650 CCtxParams->fParams.contentSizeFlag = value != 0; 651 return CCtxParams->fParams.contentSizeFlag; 652 653 case ZSTD_c_checksumFlag : 654 /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ 655 CCtxParams->fParams.checksumFlag = value != 0; 656 return CCtxParams->fParams.checksumFlag; 657 658 case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ 659 DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); 660 CCtxParams->fParams.noDictIDFlag = !value; 661 return !CCtxParams->fParams.noDictIDFlag; 662 663 case ZSTD_c_forceMaxWindow : 664 CCtxParams->forceWindow = (value != 0); 665 return CCtxParams->forceWindow; 666 667 case ZSTD_c_forceAttachDict : { 668 const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; 669 BOUNDCHECK(ZSTD_c_forceAttachDict, pref); 670 CCtxParams->attachDictPref = pref; 671 return CCtxParams->attachDictPref; 672 } 673 674 case ZSTD_c_literalCompressionMode : { 675 const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value; 676 BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm); 677 CCtxParams->literalCompressionMode = lcm; 678 return CCtxParams->literalCompressionMode; 679 } 680 681 case ZSTD_c_nbWorkers : 682 RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 683 return 0; 684 685 case ZSTD_c_jobSize : 686 RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 687 return 0; 688 689 case ZSTD_c_overlapLog : 690 RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 691 return 0; 692 693 case ZSTD_c_rsyncable : 694 RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 695 return 0; 696 697 case ZSTD_c_enableDedicatedDictSearch : 698 CCtxParams->enableDedicatedDictSearch = (value!=0); 699 return CCtxParams->enableDedicatedDictSearch; 700 701 case ZSTD_c_enableLongDistanceMatching : 702 CCtxParams->ldmParams.enableLdm = (value!=0); 703 return CCtxParams->ldmParams.enableLdm; 704 705 case ZSTD_c_ldmHashLog : 706 if (value!=0) /* 0 ==> auto */ 707 BOUNDCHECK(ZSTD_c_ldmHashLog, value); 708 CCtxParams->ldmParams.hashLog = value; 709 return CCtxParams->ldmParams.hashLog; 710 711 case ZSTD_c_ldmMinMatch : 712 if (value!=0) /* 0 ==> default */ 713 BOUNDCHECK(ZSTD_c_ldmMinMatch, value); 714 CCtxParams->ldmParams.minMatchLength = value; 715 return CCtxParams->ldmParams.minMatchLength; 716 717 case ZSTD_c_ldmBucketSizeLog : 718 if (value!=0) /* 0 ==> default */ 719 BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); 720 CCtxParams->ldmParams.bucketSizeLog = value; 721 return CCtxParams->ldmParams.bucketSizeLog; 722 723 case ZSTD_c_ldmHashRateLog : 724 if (value!=0) /* 0 ==> default */ 725 BOUNDCHECK(ZSTD_c_ldmHashRateLog, value); 726 CCtxParams->ldmParams.hashRateLog = value; 727 return CCtxParams->ldmParams.hashRateLog; 728 729 case ZSTD_c_targetCBlockSize : 730 if (value!=0) /* 0 ==> default */ 731 BOUNDCHECK(ZSTD_c_targetCBlockSize, value); 732 CCtxParams->targetCBlockSize = value; 733 return CCtxParams->targetCBlockSize; 734 735 case ZSTD_c_srcSizeHint : 736 if (value!=0) /* 0 ==> default */ 737 BOUNDCHECK(ZSTD_c_srcSizeHint, value); 738 CCtxParams->srcSizeHint = value; 739 return CCtxParams->srcSizeHint; 740 741 case ZSTD_c_stableInBuffer: 742 BOUNDCHECK(ZSTD_c_stableInBuffer, value); 743 CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value; 744 return CCtxParams->inBufferMode; 745 746 case ZSTD_c_stableOutBuffer: 747 BOUNDCHECK(ZSTD_c_stableOutBuffer, value); 748 CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value; 749 return CCtxParams->outBufferMode; 750 751 case ZSTD_c_blockDelimiters: 752 BOUNDCHECK(ZSTD_c_blockDelimiters, value); 753 CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value; 754 return CCtxParams->blockDelimiters; 755 756 case ZSTD_c_validateSequences: 757 BOUNDCHECK(ZSTD_c_validateSequences, value); 758 CCtxParams->validateSequences = value; 759 return CCtxParams->validateSequences; 760 761 default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 762 } 763 } 764 765 size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value) 766 { 767 return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); 768 } 769 770 size_t ZSTD_CCtxParams_getParameter( 771 ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value) 772 { 773 switch(param) 774 { 775 case ZSTD_c_format : 776 *value = CCtxParams->format; 777 break; 778 case ZSTD_c_compressionLevel : 779 *value = CCtxParams->compressionLevel; 780 break; 781 case ZSTD_c_windowLog : 782 *value = (int)CCtxParams->cParams.windowLog; 783 break; 784 case ZSTD_c_hashLog : 785 *value = (int)CCtxParams->cParams.hashLog; 786 break; 787 case ZSTD_c_chainLog : 788 *value = (int)CCtxParams->cParams.chainLog; 789 break; 790 case ZSTD_c_searchLog : 791 *value = CCtxParams->cParams.searchLog; 792 break; 793 case ZSTD_c_minMatch : 794 *value = CCtxParams->cParams.minMatch; 795 break; 796 case ZSTD_c_targetLength : 797 *value = CCtxParams->cParams.targetLength; 798 break; 799 case ZSTD_c_strategy : 800 *value = (unsigned)CCtxParams->cParams.strategy; 801 break; 802 case ZSTD_c_contentSizeFlag : 803 *value = CCtxParams->fParams.contentSizeFlag; 804 break; 805 case ZSTD_c_checksumFlag : 806 *value = CCtxParams->fParams.checksumFlag; 807 break; 808 case ZSTD_c_dictIDFlag : 809 *value = !CCtxParams->fParams.noDictIDFlag; 810 break; 811 case ZSTD_c_forceMaxWindow : 812 *value = CCtxParams->forceWindow; 813 break; 814 case ZSTD_c_forceAttachDict : 815 *value = CCtxParams->attachDictPref; 816 break; 817 case ZSTD_c_literalCompressionMode : 818 *value = CCtxParams->literalCompressionMode; 819 break; 820 case ZSTD_c_nbWorkers : 821 assert(CCtxParams->nbWorkers == 0); 822 *value = CCtxParams->nbWorkers; 823 break; 824 case ZSTD_c_jobSize : 825 RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 826 case ZSTD_c_overlapLog : 827 RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 828 case ZSTD_c_rsyncable : 829 RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 830 case ZSTD_c_enableDedicatedDictSearch : 831 *value = CCtxParams->enableDedicatedDictSearch; 832 break; 833 case ZSTD_c_enableLongDistanceMatching : 834 *value = CCtxParams->ldmParams.enableLdm; 835 break; 836 case ZSTD_c_ldmHashLog : 837 *value = CCtxParams->ldmParams.hashLog; 838 break; 839 case ZSTD_c_ldmMinMatch : 840 *value = CCtxParams->ldmParams.minMatchLength; 841 break; 842 case ZSTD_c_ldmBucketSizeLog : 843 *value = CCtxParams->ldmParams.bucketSizeLog; 844 break; 845 case ZSTD_c_ldmHashRateLog : 846 *value = CCtxParams->ldmParams.hashRateLog; 847 break; 848 case ZSTD_c_targetCBlockSize : 849 *value = (int)CCtxParams->targetCBlockSize; 850 break; 851 case ZSTD_c_srcSizeHint : 852 *value = (int)CCtxParams->srcSizeHint; 853 break; 854 case ZSTD_c_stableInBuffer : 855 *value = (int)CCtxParams->inBufferMode; 856 break; 857 case ZSTD_c_stableOutBuffer : 858 *value = (int)CCtxParams->outBufferMode; 859 break; 860 case ZSTD_c_blockDelimiters : 861 *value = (int)CCtxParams->blockDelimiters; 862 break; 863 case ZSTD_c_validateSequences : 864 *value = (int)CCtxParams->validateSequences; 865 break; 866 default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 867 } 868 return 0; 869 } 870 871 /* ZSTD_CCtx_setParametersUsingCCtxParams() : 872 * just applies `params` into `cctx` 873 * no action is performed, parameters are merely stored. 874 * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx. 875 * This is possible even if a compression is ongoing. 876 * In which case, new parameters will be applied on the fly, starting with next compression job. 877 */ 878 size_t ZSTD_CCtx_setParametersUsingCCtxParams( 879 ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) 880 { 881 DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); 882 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 883 "The context is in the wrong stage!"); 884 RETURN_ERROR_IF(cctx->cdict, stage_wrong, 885 "Can't override parameters with cdict attached (some must " 886 "be inherited from the cdict)."); 887 888 cctx->requestedParams = *params; 889 return 0; 890 } 891 892 ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) 893 { 894 DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); 895 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 896 "Can't set pledgedSrcSize when not in init stage."); 897 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 898 return 0; 899 } 900 901 static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams( 902 int const compressionLevel, 903 size_t const dictSize); 904 static int ZSTD_dedicatedDictSearch_isSupported( 905 const ZSTD_compressionParameters* cParams); 906 static void ZSTD_dedicatedDictSearch_revertCParams( 907 ZSTD_compressionParameters* cParams); 908 909 /* 910 * Initializes the local dict using the requested parameters. 911 * NOTE: This does not use the pledged src size, because it may be used for more 912 * than one compression. 913 */ 914 static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) 915 { 916 ZSTD_localDict* const dl = &cctx->localDict; 917 if (dl->dict == NULL) { 918 /* No local dictionary. */ 919 assert(dl->dictBuffer == NULL); 920 assert(dl->cdict == NULL); 921 assert(dl->dictSize == 0); 922 return 0; 923 } 924 if (dl->cdict != NULL) { 925 assert(cctx->cdict == dl->cdict); 926 /* Local dictionary already initialized. */ 927 return 0; 928 } 929 assert(dl->dictSize > 0); 930 assert(cctx->cdict == NULL); 931 assert(cctx->prefixDict.dict == NULL); 932 933 dl->cdict = ZSTD_createCDict_advanced2( 934 dl->dict, 935 dl->dictSize, 936 ZSTD_dlm_byRef, 937 dl->dictContentType, 938 &cctx->requestedParams, 939 cctx->customMem); 940 RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed"); 941 cctx->cdict = dl->cdict; 942 return 0; 943 } 944 945 size_t ZSTD_CCtx_loadDictionary_advanced( 946 ZSTD_CCtx* cctx, const void* dict, size_t dictSize, 947 ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) 948 { 949 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 950 "Can't load a dictionary when ctx is not in init stage."); 951 DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); 952 ZSTD_clearAllDicts(cctx); /* in case one already exists */ 953 if (dict == NULL || dictSize == 0) /* no dictionary mode */ 954 return 0; 955 if (dictLoadMethod == ZSTD_dlm_byRef) { 956 cctx->localDict.dict = dict; 957 } else { 958 void* dictBuffer; 959 RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 960 "no malloc for static CCtx"); 961 dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem); 962 RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!"); 963 ZSTD_memcpy(dictBuffer, dict, dictSize); 964 cctx->localDict.dictBuffer = dictBuffer; 965 cctx->localDict.dict = dictBuffer; 966 } 967 cctx->localDict.dictSize = dictSize; 968 cctx->localDict.dictContentType = dictContentType; 969 return 0; 970 } 971 972 ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( 973 ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 974 { 975 return ZSTD_CCtx_loadDictionary_advanced( 976 cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); 977 } 978 979 ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 980 { 981 return ZSTD_CCtx_loadDictionary_advanced( 982 cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); 983 } 984 985 986 size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 987 { 988 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 989 "Can't ref a dict when ctx not in init stage."); 990 /* Free the existing local cdict (if any) to save memory. */ 991 ZSTD_clearAllDicts(cctx); 992 cctx->cdict = cdict; 993 return 0; 994 } 995 996 size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool) 997 { 998 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 999 "Can't ref a pool when ctx not in init stage."); 1000 cctx->pool = pool; 1001 return 0; 1002 } 1003 1004 size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) 1005 { 1006 return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); 1007 } 1008 1009 size_t ZSTD_CCtx_refPrefix_advanced( 1010 ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) 1011 { 1012 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1013 "Can't ref a prefix when ctx not in init stage."); 1014 ZSTD_clearAllDicts(cctx); 1015 if (prefix != NULL && prefixSize > 0) { 1016 cctx->prefixDict.dict = prefix; 1017 cctx->prefixDict.dictSize = prefixSize; 1018 cctx->prefixDict.dictContentType = dictContentType; 1019 } 1020 return 0; 1021 } 1022 1023 /*! ZSTD_CCtx_reset() : 1024 * Also dumps dictionary */ 1025 size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) 1026 { 1027 if ( (reset == ZSTD_reset_session_only) 1028 || (reset == ZSTD_reset_session_and_parameters) ) { 1029 cctx->streamStage = zcss_init; 1030 cctx->pledgedSrcSizePlusOne = 0; 1031 } 1032 if ( (reset == ZSTD_reset_parameters) 1033 || (reset == ZSTD_reset_session_and_parameters) ) { 1034 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1035 "Can't reset parameters only when not in init stage."); 1036 ZSTD_clearAllDicts(cctx); 1037 return ZSTD_CCtxParams_reset(&cctx->requestedParams); 1038 } 1039 return 0; 1040 } 1041 1042 1043 /* ZSTD_checkCParams() : 1044 control CParam values remain within authorized range. 1045 @return : 0, or an error code if one value is beyond authorized range */ 1046 size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) 1047 { 1048 BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog); 1049 BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog); 1050 BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog); 1051 BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog); 1052 BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch); 1053 BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength); 1054 BOUNDCHECK(ZSTD_c_strategy, cParams.strategy); 1055 return 0; 1056 } 1057 1058 /* ZSTD_clampCParams() : 1059 * make CParam values within valid range. 1060 * @return : valid CParams */ 1061 static ZSTD_compressionParameters 1062 ZSTD_clampCParams(ZSTD_compressionParameters cParams) 1063 { 1064 # define CLAMP_TYPE(cParam, val, type) { \ 1065 ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ 1066 if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \ 1067 else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \ 1068 } 1069 # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned) 1070 CLAMP(ZSTD_c_windowLog, cParams.windowLog); 1071 CLAMP(ZSTD_c_chainLog, cParams.chainLog); 1072 CLAMP(ZSTD_c_hashLog, cParams.hashLog); 1073 CLAMP(ZSTD_c_searchLog, cParams.searchLog); 1074 CLAMP(ZSTD_c_minMatch, cParams.minMatch); 1075 CLAMP(ZSTD_c_targetLength,cParams.targetLength); 1076 CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy); 1077 return cParams; 1078 } 1079 1080 /* ZSTD_cycleLog() : 1081 * condition for correct operation : hashLog > 1 */ 1082 U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) 1083 { 1084 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); 1085 return hashLog - btScale; 1086 } 1087 1088 /* ZSTD_dictAndWindowLog() : 1089 * Returns an adjusted window log that is large enough to fit the source and the dictionary. 1090 * The zstd format says that the entire dictionary is valid if one byte of the dictionary 1091 * is within the window. So the hashLog and chainLog should be large enough to reference both 1092 * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing 1093 * the hashLog and windowLog. 1094 * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN. 1095 */ 1096 static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize) 1097 { 1098 const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX; 1099 /* No dictionary ==> No change */ 1100 if (dictSize == 0) { 1101 return windowLog; 1102 } 1103 assert(windowLog <= ZSTD_WINDOWLOG_MAX); 1104 assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */ 1105 { 1106 U64 const windowSize = 1ULL << windowLog; 1107 U64 const dictAndWindowSize = dictSize + windowSize; 1108 /* If the window size is already large enough to fit both the source and the dictionary 1109 * then just use the window size. Otherwise adjust so that it fits the dictionary and 1110 * the window. 1111 */ 1112 if (windowSize >= dictSize + srcSize) { 1113 return windowLog; /* Window size large enough already */ 1114 } else if (dictAndWindowSize >= maxWindowSize) { 1115 return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */ 1116 } else { 1117 return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1; 1118 } 1119 } 1120 } 1121 1122 /* ZSTD_adjustCParams_internal() : 1123 * optimize `cPar` for a specified input (`srcSize` and `dictSize`). 1124 * mostly downsize to reduce memory consumption and initialization latency. 1125 * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. 1126 * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`. 1127 * note : `srcSize==0` means 0! 1128 * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ 1129 static ZSTD_compressionParameters 1130 ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, 1131 unsigned long long srcSize, 1132 size_t dictSize, 1133 ZSTD_cParamMode_e mode) 1134 { 1135 const U64 minSrcSize = 513; /* (1<<9) + 1 */ 1136 const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); 1137 assert(ZSTD_checkCParams(cPar)==0); 1138 1139 switch (mode) { 1140 case ZSTD_cpm_unknown: 1141 case ZSTD_cpm_noAttachDict: 1142 /* If we don't know the source size, don't make any 1143 * assumptions about it. We will already have selected 1144 * smaller parameters if a dictionary is in use. 1145 */ 1146 break; 1147 case ZSTD_cpm_createCDict: 1148 /* Assume a small source size when creating a dictionary 1149 * with an unkown source size. 1150 */ 1151 if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN) 1152 srcSize = minSrcSize; 1153 break; 1154 case ZSTD_cpm_attachDict: 1155 /* Dictionary has its own dedicated parameters which have 1156 * already been selected. We are selecting parameters 1157 * for only the source. 1158 */ 1159 dictSize = 0; 1160 break; 1161 default: 1162 assert(0); 1163 break; 1164 } 1165 1166 /* resize windowLog if input is small enough, to use less memory */ 1167 if ( (srcSize < maxWindowResize) 1168 && (dictSize < maxWindowResize) ) { 1169 U32 const tSize = (U32)(srcSize + dictSize); 1170 static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; 1171 U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : 1172 ZSTD_highbit32(tSize-1) + 1; 1173 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; 1174 } 1175 if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 1176 U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize); 1177 U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); 1178 if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1; 1179 if (cycleLog > dictAndWindowLog) 1180 cPar.chainLog -= (cycleLog - dictAndWindowLog); 1181 } 1182 1183 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) 1184 cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ 1185 1186 return cPar; 1187 } 1188 1189 ZSTD_compressionParameters 1190 ZSTD_adjustCParams(ZSTD_compressionParameters cPar, 1191 unsigned long long srcSize, 1192 size_t dictSize) 1193 { 1194 cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ 1195 if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN; 1196 return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown); 1197 } 1198 1199 static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); 1200 static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); 1201 1202 static void ZSTD_overrideCParams( 1203 ZSTD_compressionParameters* cParams, 1204 const ZSTD_compressionParameters* overrides) 1205 { 1206 if (overrides->windowLog) cParams->windowLog = overrides->windowLog; 1207 if (overrides->hashLog) cParams->hashLog = overrides->hashLog; 1208 if (overrides->chainLog) cParams->chainLog = overrides->chainLog; 1209 if (overrides->searchLog) cParams->searchLog = overrides->searchLog; 1210 if (overrides->minMatch) cParams->minMatch = overrides->minMatch; 1211 if (overrides->targetLength) cParams->targetLength = overrides->targetLength; 1212 if (overrides->strategy) cParams->strategy = overrides->strategy; 1213 } 1214 1215 ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( 1216 const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) 1217 { 1218 ZSTD_compressionParameters cParams; 1219 if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) { 1220 srcSizeHint = CCtxParams->srcSizeHint; 1221 } 1222 cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode); 1223 if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; 1224 ZSTD_overrideCParams(&cParams, &CCtxParams->cParams); 1225 assert(!ZSTD_checkCParams(cParams)); 1226 /* srcSizeHint == 0 means 0 */ 1227 return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode); 1228 } 1229 1230 static size_t 1231 ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, 1232 const U32 forCCtx) 1233 { 1234 size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 1235 size_t const hSize = ((size_t)1) << cParams->hashLog; 1236 U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 1237 size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; 1238 /* We don't use ZSTD_cwksp_alloc_size() here because the tables aren't 1239 * surrounded by redzones in ASAN. */ 1240 size_t const tableSpace = chainSize * sizeof(U32) 1241 + hSize * sizeof(U32) 1242 + h3Size * sizeof(U32); 1243 size_t const optPotentialSpace = 1244 ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32)) 1245 + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32)) 1246 + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32)) 1247 + ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32)) 1248 + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t)) 1249 + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t)); 1250 size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt)) 1251 ? optPotentialSpace 1252 : 0; 1253 DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", 1254 (U32)chainSize, (U32)hSize, (U32)h3Size); 1255 return tableSpace + optSpace; 1256 } 1257 1258 static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( 1259 const ZSTD_compressionParameters* cParams, 1260 const ldmParams_t* ldmParams, 1261 const int isStatic, 1262 const size_t buffInSize, 1263 const size_t buffOutSize, 1264 const U64 pledgedSrcSize) 1265 { 1266 size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << cParams->windowLog), pledgedSrcSize)); 1267 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 1268 U32 const divider = (cParams->minMatch==3) ? 3 : 4; 1269 size_t const maxNbSeq = blockSize / divider; 1270 size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) 1271 + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) 1272 + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); 1273 size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE); 1274 size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); 1275 size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, /* forCCtx */ 1); 1276 1277 size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams); 1278 size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize); 1279 size_t const ldmSeqSpace = ldmParams->enableLdm ? 1280 ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0; 1281 1282 1283 size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) 1284 + ZSTD_cwksp_alloc_size(buffOutSize); 1285 1286 size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; 1287 1288 size_t const neededSpace = 1289 cctxSpace + 1290 entropySpace + 1291 blockStateSpace + 1292 ldmSpace + 1293 ldmSeqSpace + 1294 matchStateSize + 1295 tokenSpace + 1296 bufferSpace; 1297 1298 DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); 1299 return neededSpace; 1300 } 1301 1302 size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) 1303 { 1304 ZSTD_compressionParameters const cParams = 1305 ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); 1306 1307 RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 1308 /* estimateCCtxSize is for one-shot compression. So no buffers should 1309 * be needed. However, we still allocate two 0-sized buffers, which can 1310 * take space under ASAN. */ 1311 return ZSTD_estimateCCtxSize_usingCCtxParams_internal( 1312 &cParams, ¶ms->ldmParams, 1, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN); 1313 } 1314 1315 size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) 1316 { 1317 ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 1318 return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); 1319 } 1320 1321 static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) 1322 { 1323 int tier = 0; 1324 size_t largestSize = 0; 1325 static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN}; 1326 for (; tier < 4; ++tier) { 1327 /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */ 1328 ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict); 1329 largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize); 1330 } 1331 return largestSize; 1332 } 1333 1334 size_t ZSTD_estimateCCtxSize(int compressionLevel) 1335 { 1336 int level; 1337 size_t memBudget = 0; 1338 for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 1339 /* Ensure monotonically increasing memory usage as compression level increases */ 1340 size_t const newMB = ZSTD_estimateCCtxSize_internal(level); 1341 if (newMB > memBudget) memBudget = newMB; 1342 } 1343 return memBudget; 1344 } 1345 1346 size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) 1347 { 1348 RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 1349 { ZSTD_compressionParameters const cParams = 1350 ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); 1351 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 1352 size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered) 1353 ? ((size_t)1 << cParams.windowLog) + blockSize 1354 : 0; 1355 size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered) 1356 ? ZSTD_compressBound(blockSize) + 1 1357 : 0; 1358 1359 return ZSTD_estimateCCtxSize_usingCCtxParams_internal( 1360 &cParams, ¶ms->ldmParams, 1, inBuffSize, outBuffSize, 1361 ZSTD_CONTENTSIZE_UNKNOWN); 1362 } 1363 } 1364 1365 size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) 1366 { 1367 ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 1368 return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); 1369 } 1370 1371 static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) 1372 { 1373 ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); 1374 return ZSTD_estimateCStreamSize_usingCParams(cParams); 1375 } 1376 1377 size_t ZSTD_estimateCStreamSize(int compressionLevel) 1378 { 1379 int level; 1380 size_t memBudget = 0; 1381 for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 1382 size_t const newMB = ZSTD_estimateCStreamSize_internal(level); 1383 if (newMB > memBudget) memBudget = newMB; 1384 } 1385 return memBudget; 1386 } 1387 1388 /* ZSTD_getFrameProgression(): 1389 * tells how much data has been consumed (input) and produced (output) for current frame. 1390 * able to count progression inside worker threads (non-blocking mode). 1391 */ 1392 ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx) 1393 { 1394 { ZSTD_frameProgression fp; 1395 size_t const buffered = (cctx->inBuff == NULL) ? 0 : 1396 cctx->inBuffPos - cctx->inToCompress; 1397 if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress); 1398 assert(buffered <= ZSTD_BLOCKSIZE_MAX); 1399 fp.ingested = cctx->consumedSrcSize + buffered; 1400 fp.consumed = cctx->consumedSrcSize; 1401 fp.produced = cctx->producedCSize; 1402 fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */ 1403 fp.currentJobID = 0; 1404 fp.nbActiveWorkers = 0; 1405 return fp; 1406 } } 1407 1408 /*! ZSTD_toFlushNow() 1409 * Only useful for multithreading scenarios currently (nbWorkers >= 1). 1410 */ 1411 size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx) 1412 { 1413 (void)cctx; 1414 return 0; /* over-simplification; could also check if context is currently running in streaming mode, and in which case, report how many bytes are left to be flushed within output buffer */ 1415 } 1416 1417 static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, 1418 ZSTD_compressionParameters cParams2) 1419 { 1420 (void)cParams1; 1421 (void)cParams2; 1422 assert(cParams1.windowLog == cParams2.windowLog); 1423 assert(cParams1.chainLog == cParams2.chainLog); 1424 assert(cParams1.hashLog == cParams2.hashLog); 1425 assert(cParams1.searchLog == cParams2.searchLog); 1426 assert(cParams1.minMatch == cParams2.minMatch); 1427 assert(cParams1.targetLength == cParams2.targetLength); 1428 assert(cParams1.strategy == cParams2.strategy); 1429 } 1430 1431 void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) 1432 { 1433 int i; 1434 for (i = 0; i < ZSTD_REP_NUM; ++i) 1435 bs->rep[i] = repStartValue[i]; 1436 bs->entropy.huf.repeatMode = HUF_repeat_none; 1437 bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; 1438 bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; 1439 bs->entropy.fse.litlength_repeatMode = FSE_repeat_none; 1440 } 1441 1442 /*! ZSTD_invalidateMatchState() 1443 * Invalidate all the matches in the match finder tables. 1444 * Requires nextSrc and base to be set (can be NULL). 1445 */ 1446 static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) 1447 { 1448 ZSTD_window_clear(&ms->window); 1449 1450 ms->nextToUpdate = ms->window.dictLimit; 1451 ms->loadedDictEnd = 0; 1452 ms->opt.litLengthSum = 0; /* force reset of btopt stats */ 1453 ms->dictMatchState = NULL; 1454 } 1455 1456 /* 1457 * Controls, for this matchState reset, whether the tables need to be cleared / 1458 * prepared for the coming compression (ZSTDcrp_makeClean), or whether the 1459 * tables can be left unclean (ZSTDcrp_leaveDirty), because we know that a 1460 * subsequent operation will overwrite the table space anyways (e.g., copying 1461 * the matchState contents in from a CDict). 1462 */ 1463 typedef enum { 1464 ZSTDcrp_makeClean, 1465 ZSTDcrp_leaveDirty 1466 } ZSTD_compResetPolicy_e; 1467 1468 /* 1469 * Controls, for this matchState reset, whether indexing can continue where it 1470 * left off (ZSTDirp_continue), or whether it needs to be restarted from zero 1471 * (ZSTDirp_reset). 1472 */ 1473 typedef enum { 1474 ZSTDirp_continue, 1475 ZSTDirp_reset 1476 } ZSTD_indexResetPolicy_e; 1477 1478 typedef enum { 1479 ZSTD_resetTarget_CDict, 1480 ZSTD_resetTarget_CCtx 1481 } ZSTD_resetTarget_e; 1482 1483 static size_t 1484 ZSTD_reset_matchState(ZSTD_matchState_t* ms, 1485 ZSTD_cwksp* ws, 1486 const ZSTD_compressionParameters* cParams, 1487 const ZSTD_compResetPolicy_e crp, 1488 const ZSTD_indexResetPolicy_e forceResetIndex, 1489 const ZSTD_resetTarget_e forWho) 1490 { 1491 size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 1492 size_t const hSize = ((size_t)1) << cParams->hashLog; 1493 U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 1494 size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; 1495 1496 DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset); 1497 if (forceResetIndex == ZSTDirp_reset) { 1498 ZSTD_window_init(&ms->window); 1499 ZSTD_cwksp_mark_tables_dirty(ws); 1500 } 1501 1502 ms->hashLog3 = hashLog3; 1503 1504 ZSTD_invalidateMatchState(ms); 1505 1506 assert(!ZSTD_cwksp_reserve_failed(ws)); /* check that allocation hasn't already failed */ 1507 1508 ZSTD_cwksp_clear_tables(ws); 1509 1510 DEBUGLOG(5, "reserving table space"); 1511 /* table Space */ 1512 ms->hashTable = (U32*)ZSTD_cwksp_reserve_table(ws, hSize * sizeof(U32)); 1513 ms->chainTable = (U32*)ZSTD_cwksp_reserve_table(ws, chainSize * sizeof(U32)); 1514 ms->hashTable3 = (U32*)ZSTD_cwksp_reserve_table(ws, h3Size * sizeof(U32)); 1515 RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, 1516 "failed a workspace allocation in ZSTD_reset_matchState"); 1517 1518 DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_leaveDirty); 1519 if (crp!=ZSTDcrp_leaveDirty) { 1520 /* reset tables only */ 1521 ZSTD_cwksp_clean_tables(ws); 1522 } 1523 1524 /* opt parser space */ 1525 if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) { 1526 DEBUGLOG(4, "reserving optimal parser space"); 1527 ms->opt.litFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (1<<Litbits) * sizeof(unsigned)); 1528 ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned)); 1529 ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned)); 1530 ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned)); 1531 ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t)); 1532 ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t)); 1533 } 1534 1535 ms->cParams = *cParams; 1536 1537 RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, 1538 "failed a workspace allocation in ZSTD_reset_matchState"); 1539 1540 return 0; 1541 } 1542 1543 /* ZSTD_indexTooCloseToMax() : 1544 * minor optimization : prefer memset() rather than reduceIndex() 1545 * which is measurably slow in some circumstances (reported for Visual Studio). 1546 * Works when re-using a context for a lot of smallish inputs : 1547 * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN, 1548 * memset() will be triggered before reduceIndex(). 1549 */ 1550 #define ZSTD_INDEXOVERFLOW_MARGIN (16 MB) 1551 static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) 1552 { 1553 return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); 1554 } 1555 1556 /*! ZSTD_resetCCtx_internal() : 1557 note : `params` are assumed fully validated at this stage */ 1558 static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, 1559 ZSTD_CCtx_params params, 1560 U64 const pledgedSrcSize, 1561 ZSTD_compResetPolicy_e const crp, 1562 ZSTD_buffered_policy_e const zbuff) 1563 { 1564 ZSTD_cwksp* const ws = &zc->workspace; 1565 DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", 1566 (U32)pledgedSrcSize, params.cParams.windowLog); 1567 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 1568 1569 zc->isFirstBlock = 1; 1570 1571 if (params.ldmParams.enableLdm) { 1572 /* Adjust long distance matching parameters */ 1573 ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); 1574 assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); 1575 assert(params.ldmParams.hashRateLog < 32); 1576 } 1577 1578 { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 1579 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 1580 U32 const divider = (params.cParams.minMatch==3) ? 3 : 4; 1581 size_t const maxNbSeq = blockSize / divider; 1582 size_t const buffOutSize = (zbuff == ZSTDb_buffered && params.outBufferMode == ZSTD_bm_buffered) 1583 ? ZSTD_compressBound(blockSize) + 1 1584 : 0; 1585 size_t const buffInSize = (zbuff == ZSTDb_buffered && params.inBufferMode == ZSTD_bm_buffered) 1586 ? windowSize + blockSize 1587 : 0; 1588 size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); 1589 1590 int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window); 1591 ZSTD_indexResetPolicy_e needsIndexReset = 1592 (!indexTooClose && zc->initialized) ? ZSTDirp_continue : ZSTDirp_reset; 1593 1594 size_t const neededSpace = 1595 ZSTD_estimateCCtxSize_usingCCtxParams_internal( 1596 ¶ms.cParams, ¶ms.ldmParams, zc->staticSize != 0, 1597 buffInSize, buffOutSize, pledgedSrcSize); 1598 FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); 1599 1600 if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0); 1601 1602 /* Check if workspace is large enough, alloc a new one if needed */ 1603 { 1604 int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace; 1605 int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace); 1606 1607 DEBUGLOG(4, "Need %zu B workspace", neededSpace); 1608 DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); 1609 1610 if (workspaceTooSmall || workspaceWasteful) { 1611 DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB", 1612 ZSTD_cwksp_sizeof(ws) >> 10, 1613 neededSpace >> 10); 1614 1615 RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize"); 1616 1617 needsIndexReset = ZSTDirp_reset; 1618 1619 ZSTD_cwksp_free(ws, zc->customMem); 1620 FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem), ""); 1621 1622 DEBUGLOG(5, "reserving object space"); 1623 /* Statically sized space. 1624 * entropyWorkspace never moves, 1625 * though prev/next block swap places */ 1626 assert(ZSTD_cwksp_check_available(ws, 2 * sizeof(ZSTD_compressedBlockState_t))); 1627 zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); 1628 RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock"); 1629 zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); 1630 RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock"); 1631 zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE); 1632 RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); 1633 } } 1634 1635 ZSTD_cwksp_clear(ws); 1636 1637 /* init params */ 1638 zc->appliedParams = params; 1639 zc->blockState.matchState.cParams = params.cParams; 1640 zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; 1641 zc->consumedSrcSize = 0; 1642 zc->producedCSize = 0; 1643 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 1644 zc->appliedParams.fParams.contentSizeFlag = 0; 1645 DEBUGLOG(4, "pledged content size : %u ; flag : %u", 1646 (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); 1647 zc->blockSize = blockSize; 1648 1649 xxh64_reset(&zc->xxhState, 0); 1650 zc->stage = ZSTDcs_init; 1651 zc->dictID = 0; 1652 zc->dictContentSize = 0; 1653 1654 ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); 1655 1656 /* ZSTD_wildcopy() is used to copy into the literals buffer, 1657 * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. 1658 */ 1659 zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH); 1660 zc->seqStore.maxNbLit = blockSize; 1661 1662 /* buffers */ 1663 zc->bufferedPolicy = zbuff; 1664 zc->inBuffSize = buffInSize; 1665 zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize); 1666 zc->outBuffSize = buffOutSize; 1667 zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize); 1668 1669 /* ldm bucketOffsets table */ 1670 if (params.ldmParams.enableLdm) { 1671 /* TODO: avoid memset? */ 1672 size_t const numBuckets = 1673 ((size_t)1) << (params.ldmParams.hashLog - 1674 params.ldmParams.bucketSizeLog); 1675 zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets); 1676 ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets); 1677 } 1678 1679 /* sequences storage */ 1680 ZSTD_referenceExternalSequences(zc, NULL, 0); 1681 zc->seqStore.maxNbSeq = maxNbSeq; 1682 zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 1683 zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 1684 zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 1685 zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); 1686 1687 FORWARD_IF_ERROR(ZSTD_reset_matchState( 1688 &zc->blockState.matchState, 1689 ws, 1690 ¶ms.cParams, 1691 crp, 1692 needsIndexReset, 1693 ZSTD_resetTarget_CCtx), ""); 1694 1695 /* ldm hash table */ 1696 if (params.ldmParams.enableLdm) { 1697 /* TODO: avoid memset? */ 1698 size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; 1699 zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); 1700 ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); 1701 zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); 1702 zc->maxNbLdmSequences = maxNbLdmSeq; 1703 1704 ZSTD_window_init(&zc->ldmState.window); 1705 ZSTD_window_clear(&zc->ldmState.window); 1706 zc->ldmState.loadedDictEnd = 0; 1707 } 1708 1709 /* Due to alignment, when reusing a workspace, we can actually consume 1710 * up to 3 extra bytes for alignment. See the comments in zstd_cwksp.h 1711 */ 1712 assert(ZSTD_cwksp_used(ws) >= neededSpace && 1713 ZSTD_cwksp_used(ws) <= neededSpace + 3); 1714 1715 DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); 1716 zc->initialized = 1; 1717 1718 return 0; 1719 } 1720 } 1721 1722 /* ZSTD_invalidateRepCodes() : 1723 * ensures next compression will not use repcodes from previous block. 1724 * Note : only works with regular variant; 1725 * do not use with extDict variant ! */ 1726 void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { 1727 int i; 1728 for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0; 1729 assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); 1730 } 1731 1732 /* These are the approximate sizes for each strategy past which copying the 1733 * dictionary tables into the working context is faster than using them 1734 * in-place. 1735 */ 1736 static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = { 1737 8 KB, /* unused */ 1738 8 KB, /* ZSTD_fast */ 1739 16 KB, /* ZSTD_dfast */ 1740 32 KB, /* ZSTD_greedy */ 1741 32 KB, /* ZSTD_lazy */ 1742 32 KB, /* ZSTD_lazy2 */ 1743 32 KB, /* ZSTD_btlazy2 */ 1744 32 KB, /* ZSTD_btopt */ 1745 8 KB, /* ZSTD_btultra */ 1746 8 KB /* ZSTD_btultra2 */ 1747 }; 1748 1749 static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, 1750 const ZSTD_CCtx_params* params, 1751 U64 pledgedSrcSize) 1752 { 1753 size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; 1754 int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch; 1755 return dedicatedDictSearch 1756 || ( ( pledgedSrcSize <= cutoff 1757 || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 1758 || params->attachDictPref == ZSTD_dictForceAttach ) 1759 && params->attachDictPref != ZSTD_dictForceCopy 1760 && !params->forceWindow ); /* dictMatchState isn't correctly 1761 * handled in _enforceMaxDist */ 1762 } 1763 1764 static size_t 1765 ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, 1766 const ZSTD_CDict* cdict, 1767 ZSTD_CCtx_params params, 1768 U64 pledgedSrcSize, 1769 ZSTD_buffered_policy_e zbuff) 1770 { 1771 { 1772 ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams; 1773 unsigned const windowLog = params.cParams.windowLog; 1774 assert(windowLog != 0); 1775 /* Resize working context table params for input only, since the dict 1776 * has its own tables. */ 1777 /* pledgedSrcSize == 0 means 0! */ 1778 1779 if (cdict->matchState.dedicatedDictSearch) { 1780 ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams); 1781 } 1782 1783 params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize, 1784 cdict->dictContentSize, ZSTD_cpm_attachDict); 1785 params.cParams.windowLog = windowLog; 1786 FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 1787 ZSTDcrp_makeClean, zbuff), ""); 1788 assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy); 1789 } 1790 1791 { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc 1792 - cdict->matchState.window.base); 1793 const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit; 1794 if (cdictLen == 0) { 1795 /* don't even attach dictionaries with no contents */ 1796 DEBUGLOG(4, "skipping attaching empty dictionary"); 1797 } else { 1798 DEBUGLOG(4, "attaching dictionary into context"); 1799 cctx->blockState.matchState.dictMatchState = &cdict->matchState; 1800 1801 /* prep working match state so dict matches never have negative indices 1802 * when they are translated to the working context's index space. */ 1803 if (cctx->blockState.matchState.window.dictLimit < cdictEnd) { 1804 cctx->blockState.matchState.window.nextSrc = 1805 cctx->blockState.matchState.window.base + cdictEnd; 1806 ZSTD_window_clear(&cctx->blockState.matchState.window); 1807 } 1808 /* loadedDictEnd is expressed within the referential of the active context */ 1809 cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit; 1810 } } 1811 1812 cctx->dictID = cdict->dictID; 1813 cctx->dictContentSize = cdict->dictContentSize; 1814 1815 /* copy block state */ 1816 ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 1817 1818 return 0; 1819 } 1820 1821 static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, 1822 const ZSTD_CDict* cdict, 1823 ZSTD_CCtx_params params, 1824 U64 pledgedSrcSize, 1825 ZSTD_buffered_policy_e zbuff) 1826 { 1827 const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; 1828 1829 assert(!cdict->matchState.dedicatedDictSearch); 1830 1831 DEBUGLOG(4, "copying dictionary into context"); 1832 1833 { unsigned const windowLog = params.cParams.windowLog; 1834 assert(windowLog != 0); 1835 /* Copy only compression parameters related to tables. */ 1836 params.cParams = *cdict_cParams; 1837 params.cParams.windowLog = windowLog; 1838 FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 1839 ZSTDcrp_leaveDirty, zbuff), ""); 1840 assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 1841 assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); 1842 assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); 1843 } 1844 1845 ZSTD_cwksp_mark_tables_dirty(&cctx->workspace); 1846 1847 /* copy tables */ 1848 { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); 1849 size_t const hSize = (size_t)1 << cdict_cParams->hashLog; 1850 1851 ZSTD_memcpy(cctx->blockState.matchState.hashTable, 1852 cdict->matchState.hashTable, 1853 hSize * sizeof(U32)); 1854 ZSTD_memcpy(cctx->blockState.matchState.chainTable, 1855 cdict->matchState.chainTable, 1856 chainSize * sizeof(U32)); 1857 } 1858 1859 /* Zero the hashTable3, since the cdict never fills it */ 1860 { int const h3log = cctx->blockState.matchState.hashLog3; 1861 size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; 1862 assert(cdict->matchState.hashLog3 == 0); 1863 ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); 1864 } 1865 1866 ZSTD_cwksp_mark_tables_clean(&cctx->workspace); 1867 1868 /* copy dictionary offsets */ 1869 { ZSTD_matchState_t const* srcMatchState = &cdict->matchState; 1870 ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; 1871 dstMatchState->window = srcMatchState->window; 1872 dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 1873 dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 1874 } 1875 1876 cctx->dictID = cdict->dictID; 1877 cctx->dictContentSize = cdict->dictContentSize; 1878 1879 /* copy block state */ 1880 ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 1881 1882 return 0; 1883 } 1884 1885 /* We have a choice between copying the dictionary context into the working 1886 * context, or referencing the dictionary context from the working context 1887 * in-place. We decide here which strategy to use. */ 1888 static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, 1889 const ZSTD_CDict* cdict, 1890 const ZSTD_CCtx_params* params, 1891 U64 pledgedSrcSize, 1892 ZSTD_buffered_policy_e zbuff) 1893 { 1894 1895 DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)", 1896 (unsigned)pledgedSrcSize); 1897 1898 if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) { 1899 return ZSTD_resetCCtx_byAttachingCDict( 1900 cctx, cdict, *params, pledgedSrcSize, zbuff); 1901 } else { 1902 return ZSTD_resetCCtx_byCopyingCDict( 1903 cctx, cdict, *params, pledgedSrcSize, zbuff); 1904 } 1905 } 1906 1907 /*! ZSTD_copyCCtx_internal() : 1908 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 1909 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 1910 * The "context", in this case, refers to the hash and chain tables, 1911 * entropy tables, and dictionary references. 1912 * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx. 1913 * @return : 0, or an error code */ 1914 static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, 1915 const ZSTD_CCtx* srcCCtx, 1916 ZSTD_frameParameters fParams, 1917 U64 pledgedSrcSize, 1918 ZSTD_buffered_policy_e zbuff) 1919 { 1920 DEBUGLOG(5, "ZSTD_copyCCtx_internal"); 1921 RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong, 1922 "Can't copy a ctx that's not in init stage."); 1923 1924 ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); 1925 { ZSTD_CCtx_params params = dstCCtx->requestedParams; 1926 /* Copy only compression parameters related to tables. */ 1927 params.cParams = srcCCtx->appliedParams.cParams; 1928 params.fParams = fParams; 1929 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, 1930 ZSTDcrp_leaveDirty, zbuff); 1931 assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); 1932 assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); 1933 assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog); 1934 assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog); 1935 assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3); 1936 } 1937 1938 ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace); 1939 1940 /* copy tables */ 1941 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); 1942 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; 1943 int const h3log = srcCCtx->blockState.matchState.hashLog3; 1944 size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; 1945 1946 ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable, 1947 srcCCtx->blockState.matchState.hashTable, 1948 hSize * sizeof(U32)); 1949 ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable, 1950 srcCCtx->blockState.matchState.chainTable, 1951 chainSize * sizeof(U32)); 1952 ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3, 1953 srcCCtx->blockState.matchState.hashTable3, 1954 h3Size * sizeof(U32)); 1955 } 1956 1957 ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace); 1958 1959 /* copy dictionary offsets */ 1960 { 1961 const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState; 1962 ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; 1963 dstMatchState->window = srcMatchState->window; 1964 dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 1965 dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 1966 } 1967 dstCCtx->dictID = srcCCtx->dictID; 1968 dstCCtx->dictContentSize = srcCCtx->dictContentSize; 1969 1970 /* copy block state */ 1971 ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); 1972 1973 return 0; 1974 } 1975 1976 /*! ZSTD_copyCCtx() : 1977 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 1978 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 1979 * pledgedSrcSize==0 means "unknown". 1980 * @return : 0, or an error code */ 1981 size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) 1982 { 1983 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 1984 ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy; 1985 ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); 1986 if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 1987 fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); 1988 1989 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, 1990 fParams, pledgedSrcSize, 1991 zbuff); 1992 } 1993 1994 1995 #define ZSTD_ROWSIZE 16 1996 /*! ZSTD_reduceTable() : 1997 * reduce table indexes by `reducerValue`, or squash to zero. 1998 * PreserveMark preserves "unsorted mark" for btlazy2 strategy. 1999 * It must be set to a clear 0/1 value, to remove branch during inlining. 2000 * Presume table size is a multiple of ZSTD_ROWSIZE 2001 * to help auto-vectorization */ 2002 FORCE_INLINE_TEMPLATE void 2003 ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark) 2004 { 2005 int const nbRows = (int)size / ZSTD_ROWSIZE; 2006 int cellNb = 0; 2007 int rowNb; 2008 assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ 2009 assert(size < (1U<<31)); /* can be casted to int */ 2010 2011 2012 for (rowNb=0 ; rowNb < nbRows ; rowNb++) { 2013 int column; 2014 for (column=0; column<ZSTD_ROWSIZE; column++) { 2015 if (preserveMark) { 2016 U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0; 2017 table[cellNb] += adder; 2018 } 2019 if (table[cellNb] < reducerValue) table[cellNb] = 0; 2020 else table[cellNb] -= reducerValue; 2021 cellNb++; 2022 } } 2023 } 2024 2025 static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue) 2026 { 2027 ZSTD_reduceTable_internal(table, size, reducerValue, 0); 2028 } 2029 2030 static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue) 2031 { 2032 ZSTD_reduceTable_internal(table, size, reducerValue, 1); 2033 } 2034 2035 /*! ZSTD_reduceIndex() : 2036 * rescale all indexes to avoid future overflow (indexes are U32) */ 2037 static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue) 2038 { 2039 { U32 const hSize = (U32)1 << params->cParams.hashLog; 2040 ZSTD_reduceTable(ms->hashTable, hSize, reducerValue); 2041 } 2042 2043 if (params->cParams.strategy != ZSTD_fast) { 2044 U32 const chainSize = (U32)1 << params->cParams.chainLog; 2045 if (params->cParams.strategy == ZSTD_btlazy2) 2046 ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); 2047 else 2048 ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue); 2049 } 2050 2051 if (ms->hashLog3) { 2052 U32 const h3Size = (U32)1 << ms->hashLog3; 2053 ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue); 2054 } 2055 } 2056 2057 2058 /*-******************************************************* 2059 * Block entropic compression 2060 *********************************************************/ 2061 2062 /* See doc/zstd_compression_format.md for detailed format description */ 2063 2064 void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) 2065 { 2066 const seqDef* const sequences = seqStorePtr->sequencesStart; 2067 BYTE* const llCodeTable = seqStorePtr->llCode; 2068 BYTE* const ofCodeTable = seqStorePtr->ofCode; 2069 BYTE* const mlCodeTable = seqStorePtr->mlCode; 2070 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 2071 U32 u; 2072 assert(nbSeq <= seqStorePtr->maxNbSeq); 2073 for (u=0; u<nbSeq; u++) { 2074 U32 const llv = sequences[u].litLength; 2075 U32 const mlv = sequences[u].matchLength; 2076 llCodeTable[u] = (BYTE)ZSTD_LLcode(llv); 2077 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset); 2078 mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv); 2079 } 2080 if (seqStorePtr->longLengthID==1) 2081 llCodeTable[seqStorePtr->longLengthPos] = MaxLL; 2082 if (seqStorePtr->longLengthID==2) 2083 mlCodeTable[seqStorePtr->longLengthPos] = MaxML; 2084 } 2085 2086 /* ZSTD_useTargetCBlockSize(): 2087 * Returns if target compressed block size param is being used. 2088 * If used, compression will do best effort to make a compressed block size to be around targetCBlockSize. 2089 * Returns 1 if true, 0 otherwise. */ 2090 static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams) 2091 { 2092 DEBUGLOG(5, "ZSTD_useTargetCBlockSize (targetCBlockSize=%zu)", cctxParams->targetCBlockSize); 2093 return (cctxParams->targetCBlockSize != 0); 2094 } 2095 2096 /* ZSTD_entropyCompressSequences_internal(): 2097 * actually compresses both literals and sequences */ 2098 MEM_STATIC size_t 2099 ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr, 2100 const ZSTD_entropyCTables_t* prevEntropy, 2101 ZSTD_entropyCTables_t* nextEntropy, 2102 const ZSTD_CCtx_params* cctxParams, 2103 void* dst, size_t dstCapacity, 2104 void* entropyWorkspace, size_t entropyWkspSize, 2105 const int bmi2) 2106 { 2107 const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; 2108 ZSTD_strategy const strategy = cctxParams->cParams.strategy; 2109 unsigned* count = (unsigned*)entropyWorkspace; 2110 FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; 2111 FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; 2112 FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; 2113 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ 2114 const seqDef* const sequences = seqStorePtr->sequencesStart; 2115 const BYTE* const ofCodeTable = seqStorePtr->ofCode; 2116 const BYTE* const llCodeTable = seqStorePtr->llCode; 2117 const BYTE* const mlCodeTable = seqStorePtr->mlCode; 2118 BYTE* const ostart = (BYTE*)dst; 2119 BYTE* const oend = ostart + dstCapacity; 2120 BYTE* op = ostart; 2121 size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 2122 BYTE* seqHead; 2123 BYTE* lastNCount = NULL; 2124 2125 entropyWorkspace = count + (MaxSeq + 1); 2126 entropyWkspSize -= (MaxSeq + 1) * sizeof(*count); 2127 2128 DEBUGLOG(4, "ZSTD_entropyCompressSequences_internal (nbSeq=%zu)", nbSeq); 2129 ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 2130 assert(entropyWkspSize >= HUF_WORKSPACE_SIZE); 2131 2132 /* Compress literals */ 2133 { const BYTE* const literals = seqStorePtr->litStart; 2134 size_t const litSize = (size_t)(seqStorePtr->lit - literals); 2135 size_t const cSize = ZSTD_compressLiterals( 2136 &prevEntropy->huf, &nextEntropy->huf, 2137 cctxParams->cParams.strategy, 2138 ZSTD_disableLiteralsCompression(cctxParams), 2139 op, dstCapacity, 2140 literals, litSize, 2141 entropyWorkspace, entropyWkspSize, 2142 bmi2); 2143 FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed"); 2144 assert(cSize <= dstCapacity); 2145 op += cSize; 2146 } 2147 2148 /* Sequences Header */ 2149 RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, 2150 dstSize_tooSmall, "Can't fit seq hdr in output buf!"); 2151 if (nbSeq < 128) { 2152 *op++ = (BYTE)nbSeq; 2153 } else if (nbSeq < LONGNBSEQ) { 2154 op[0] = (BYTE)((nbSeq>>8) + 0x80); 2155 op[1] = (BYTE)nbSeq; 2156 op+=2; 2157 } else { 2158 op[0]=0xFF; 2159 MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)); 2160 op+=3; 2161 } 2162 assert(op <= oend); 2163 if (nbSeq==0) { 2164 /* Copy the old tables over as if we repeated them */ 2165 ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); 2166 return (size_t)(op - ostart); 2167 } 2168 2169 /* seqHead : flags for FSE encoding type */ 2170 seqHead = op++; 2171 assert(op <= oend); 2172 2173 /* convert length/distances into codes */ 2174 ZSTD_seqToCodes(seqStorePtr); 2175 /* build CTable for Literal Lengths */ 2176 { unsigned max = MaxLL; 2177 size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 2178 DEBUGLOG(5, "Building LL table"); 2179 nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; 2180 LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, 2181 count, max, mostFrequent, nbSeq, 2182 LLFSELog, prevEntropy->fse.litlengthCTable, 2183 LL_defaultNorm, LL_defaultNormLog, 2184 ZSTD_defaultAllowed, strategy); 2185 assert(set_basic < set_compressed && set_rle < set_compressed); 2186 assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2187 { size_t const countSize = ZSTD_buildCTable( 2188 op, (size_t)(oend - op), 2189 CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, 2190 count, max, llCodeTable, nbSeq, 2191 LL_defaultNorm, LL_defaultNormLog, MaxLL, 2192 prevEntropy->fse.litlengthCTable, 2193 sizeof(prevEntropy->fse.litlengthCTable), 2194 entropyWorkspace, entropyWkspSize); 2195 FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed"); 2196 if (LLtype == set_compressed) 2197 lastNCount = op; 2198 op += countSize; 2199 assert(op <= oend); 2200 } } 2201 /* build CTable for Offsets */ 2202 { unsigned max = MaxOff; 2203 size_t const mostFrequent = HIST_countFast_wksp( 2204 count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 2205 /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ 2206 ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; 2207 DEBUGLOG(5, "Building OF table"); 2208 nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; 2209 Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, 2210 count, max, mostFrequent, nbSeq, 2211 OffFSELog, prevEntropy->fse.offcodeCTable, 2212 OF_defaultNorm, OF_defaultNormLog, 2213 defaultPolicy, strategy); 2214 assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2215 { size_t const countSize = ZSTD_buildCTable( 2216 op, (size_t)(oend - op), 2217 CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, 2218 count, max, ofCodeTable, nbSeq, 2219 OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 2220 prevEntropy->fse.offcodeCTable, 2221 sizeof(prevEntropy->fse.offcodeCTable), 2222 entropyWorkspace, entropyWkspSize); 2223 FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed"); 2224 if (Offtype == set_compressed) 2225 lastNCount = op; 2226 op += countSize; 2227 assert(op <= oend); 2228 } } 2229 /* build CTable for MatchLengths */ 2230 { unsigned max = MaxML; 2231 size_t const mostFrequent = HIST_countFast_wksp( 2232 count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 2233 DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); 2234 nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; 2235 MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, 2236 count, max, mostFrequent, nbSeq, 2237 MLFSELog, prevEntropy->fse.matchlengthCTable, 2238 ML_defaultNorm, ML_defaultNormLog, 2239 ZSTD_defaultAllowed, strategy); 2240 assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2241 { size_t const countSize = ZSTD_buildCTable( 2242 op, (size_t)(oend - op), 2243 CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, 2244 count, max, mlCodeTable, nbSeq, 2245 ML_defaultNorm, ML_defaultNormLog, MaxML, 2246 prevEntropy->fse.matchlengthCTable, 2247 sizeof(prevEntropy->fse.matchlengthCTable), 2248 entropyWorkspace, entropyWkspSize); 2249 FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed"); 2250 if (MLtype == set_compressed) 2251 lastNCount = op; 2252 op += countSize; 2253 assert(op <= oend); 2254 } } 2255 2256 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 2257 2258 { size_t const bitstreamSize = ZSTD_encodeSequences( 2259 op, (size_t)(oend - op), 2260 CTable_MatchLength, mlCodeTable, 2261 CTable_OffsetBits, ofCodeTable, 2262 CTable_LitLength, llCodeTable, 2263 sequences, nbSeq, 2264 longOffsets, bmi2); 2265 FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed"); 2266 op += bitstreamSize; 2267 assert(op <= oend); 2268 /* zstd versions <= 1.3.4 mistakenly report corruption when 2269 * FSE_readNCount() receives a buffer < 4 bytes. 2270 * Fixed by https://github.com/facebook/zstd/pull/1146. 2271 * This can happen when the last set_compressed table present is 2 2272 * bytes and the bitstream is only one byte. 2273 * In this exceedingly rare case, we will simply emit an uncompressed 2274 * block, since it isn't worth optimizing. 2275 */ 2276 if (lastNCount && (op - lastNCount) < 4) { 2277 /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ 2278 assert(op - lastNCount == 3); 2279 DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " 2280 "emitting an uncompressed block."); 2281 return 0; 2282 } 2283 } 2284 2285 DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart)); 2286 return (size_t)(op - ostart); 2287 } 2288 2289 MEM_STATIC size_t 2290 ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr, 2291 const ZSTD_entropyCTables_t* prevEntropy, 2292 ZSTD_entropyCTables_t* nextEntropy, 2293 const ZSTD_CCtx_params* cctxParams, 2294 void* dst, size_t dstCapacity, 2295 size_t srcSize, 2296 void* entropyWorkspace, size_t entropyWkspSize, 2297 int bmi2) 2298 { 2299 size_t const cSize = ZSTD_entropyCompressSequences_internal( 2300 seqStorePtr, prevEntropy, nextEntropy, cctxParams, 2301 dst, dstCapacity, 2302 entropyWorkspace, entropyWkspSize, bmi2); 2303 if (cSize == 0) return 0; 2304 /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. 2305 * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. 2306 */ 2307 if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) 2308 return 0; /* block not compressed */ 2309 FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSequences_internal failed"); 2310 2311 /* Check compressibility */ 2312 { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); 2313 if (cSize >= maxCSize) return 0; /* block not compressed */ 2314 } 2315 DEBUGLOG(4, "ZSTD_entropyCompressSequences() cSize: %zu\n", cSize); 2316 return cSize; 2317 } 2318 2319 /* ZSTD_selectBlockCompressor() : 2320 * Not static, but internal use only (used by long distance matcher) 2321 * assumption : strat is a valid strategy */ 2322 ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) 2323 { 2324 static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = { 2325 { ZSTD_compressBlock_fast /* default for 0 */, 2326 ZSTD_compressBlock_fast, 2327 ZSTD_compressBlock_doubleFast, 2328 ZSTD_compressBlock_greedy, 2329 ZSTD_compressBlock_lazy, 2330 ZSTD_compressBlock_lazy2, 2331 ZSTD_compressBlock_btlazy2, 2332 ZSTD_compressBlock_btopt, 2333 ZSTD_compressBlock_btultra, 2334 ZSTD_compressBlock_btultra2 }, 2335 { ZSTD_compressBlock_fast_extDict /* default for 0 */, 2336 ZSTD_compressBlock_fast_extDict, 2337 ZSTD_compressBlock_doubleFast_extDict, 2338 ZSTD_compressBlock_greedy_extDict, 2339 ZSTD_compressBlock_lazy_extDict, 2340 ZSTD_compressBlock_lazy2_extDict, 2341 ZSTD_compressBlock_btlazy2_extDict, 2342 ZSTD_compressBlock_btopt_extDict, 2343 ZSTD_compressBlock_btultra_extDict, 2344 ZSTD_compressBlock_btultra_extDict }, 2345 { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, 2346 ZSTD_compressBlock_fast_dictMatchState, 2347 ZSTD_compressBlock_doubleFast_dictMatchState, 2348 ZSTD_compressBlock_greedy_dictMatchState, 2349 ZSTD_compressBlock_lazy_dictMatchState, 2350 ZSTD_compressBlock_lazy2_dictMatchState, 2351 ZSTD_compressBlock_btlazy2_dictMatchState, 2352 ZSTD_compressBlock_btopt_dictMatchState, 2353 ZSTD_compressBlock_btultra_dictMatchState, 2354 ZSTD_compressBlock_btultra_dictMatchState }, 2355 { NULL /* default for 0 */, 2356 NULL, 2357 NULL, 2358 ZSTD_compressBlock_greedy_dedicatedDictSearch, 2359 ZSTD_compressBlock_lazy_dedicatedDictSearch, 2360 ZSTD_compressBlock_lazy2_dedicatedDictSearch, 2361 NULL, 2362 NULL, 2363 NULL, 2364 NULL } 2365 }; 2366 ZSTD_blockCompressor selectedCompressor; 2367 ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); 2368 2369 assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); 2370 selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; 2371 assert(selectedCompressor != NULL); 2372 return selectedCompressor; 2373 } 2374 2375 static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, 2376 const BYTE* anchor, size_t lastLLSize) 2377 { 2378 ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize); 2379 seqStorePtr->lit += lastLLSize; 2380 } 2381 2382 void ZSTD_resetSeqStore(seqStore_t* ssPtr) 2383 { 2384 ssPtr->lit = ssPtr->litStart; 2385 ssPtr->sequences = ssPtr->sequencesStart; 2386 ssPtr->longLengthID = 0; 2387 } 2388 2389 typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; 2390 2391 static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) 2392 { 2393 ZSTD_matchState_t* const ms = &zc->blockState.matchState; 2394 DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize); 2395 assert(srcSize <= ZSTD_BLOCKSIZE_MAX); 2396 /* Assert that we have correctly flushed the ctx params into the ms's copy */ 2397 ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); 2398 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { 2399 if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) { 2400 ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize); 2401 } else { 2402 ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); 2403 } 2404 return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ 2405 } 2406 ZSTD_resetSeqStore(&(zc->seqStore)); 2407 /* required for optimal parser to read stats from dictionary */ 2408 ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; 2409 /* tell the optimal parser how we expect to compress literals */ 2410 ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode; 2411 /* a gap between an attached dict and the current window is not safe, 2412 * they must remain adjacent, 2413 * and when that stops being the case, the dict must be unset */ 2414 assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit); 2415 2416 /* limited update after a very long match */ 2417 { const BYTE* const base = ms->window.base; 2418 const BYTE* const istart = (const BYTE*)src; 2419 const U32 curr = (U32)(istart-base); 2420 if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ 2421 if (curr > ms->nextToUpdate + 384) 2422 ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384)); 2423 } 2424 2425 /* select and store sequences */ 2426 { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms); 2427 size_t lastLLSize; 2428 { int i; 2429 for (i = 0; i < ZSTD_REP_NUM; ++i) 2430 zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; 2431 } 2432 if (zc->externSeqStore.pos < zc->externSeqStore.size) { 2433 assert(!zc->appliedParams.ldmParams.enableLdm); 2434 /* Updates ldmSeqStore.pos */ 2435 lastLLSize = 2436 ZSTD_ldm_blockCompress(&zc->externSeqStore, 2437 ms, &zc->seqStore, 2438 zc->blockState.nextCBlock->rep, 2439 src, srcSize); 2440 assert(zc->externSeqStore.pos <= zc->externSeqStore.size); 2441 } else if (zc->appliedParams.ldmParams.enableLdm) { 2442 rawSeqStore_t ldmSeqStore = kNullRawSeqStore; 2443 2444 ldmSeqStore.seq = zc->ldmSequences; 2445 ldmSeqStore.capacity = zc->maxNbLdmSequences; 2446 /* Updates ldmSeqStore.size */ 2447 FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, 2448 &zc->appliedParams.ldmParams, 2449 src, srcSize), ""); 2450 /* Updates ldmSeqStore.pos */ 2451 lastLLSize = 2452 ZSTD_ldm_blockCompress(&ldmSeqStore, 2453 ms, &zc->seqStore, 2454 zc->blockState.nextCBlock->rep, 2455 src, srcSize); 2456 assert(ldmSeqStore.pos == ldmSeqStore.size); 2457 } else { /* not long range mode */ 2458 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); 2459 ms->ldmSeqStore = NULL; 2460 lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); 2461 } 2462 { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; 2463 ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); 2464 } } 2465 return ZSTDbss_compress; 2466 } 2467 2468 static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc) 2469 { 2470 const seqStore_t* seqStore = ZSTD_getSeqStore(zc); 2471 const seqDef* seqStoreSeqs = seqStore->sequencesStart; 2472 size_t seqStoreSeqSize = seqStore->sequences - seqStoreSeqs; 2473 size_t seqStoreLiteralsSize = (size_t)(seqStore->lit - seqStore->litStart); 2474 size_t literalsRead = 0; 2475 size_t lastLLSize; 2476 2477 ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex]; 2478 size_t i; 2479 repcodes_t updatedRepcodes; 2480 2481 assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences); 2482 /* Ensure we have enough space for last literals "sequence" */ 2483 assert(zc->seqCollector.maxSequences >= seqStoreSeqSize + 1); 2484 ZSTD_memcpy(updatedRepcodes.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); 2485 for (i = 0; i < seqStoreSeqSize; ++i) { 2486 U32 rawOffset = seqStoreSeqs[i].offset - ZSTD_REP_NUM; 2487 outSeqs[i].litLength = seqStoreSeqs[i].litLength; 2488 outSeqs[i].matchLength = seqStoreSeqs[i].matchLength + MINMATCH; 2489 outSeqs[i].rep = 0; 2490 2491 if (i == seqStore->longLengthPos) { 2492 if (seqStore->longLengthID == 1) { 2493 outSeqs[i].litLength += 0x10000; 2494 } else if (seqStore->longLengthID == 2) { 2495 outSeqs[i].matchLength += 0x10000; 2496 } 2497 } 2498 2499 if (seqStoreSeqs[i].offset <= ZSTD_REP_NUM) { 2500 /* Derive the correct offset corresponding to a repcode */ 2501 outSeqs[i].rep = seqStoreSeqs[i].offset; 2502 if (outSeqs[i].litLength != 0) { 2503 rawOffset = updatedRepcodes.rep[outSeqs[i].rep - 1]; 2504 } else { 2505 if (outSeqs[i].rep == 3) { 2506 rawOffset = updatedRepcodes.rep[0] - 1; 2507 } else { 2508 rawOffset = updatedRepcodes.rep[outSeqs[i].rep]; 2509 } 2510 } 2511 } 2512 outSeqs[i].offset = rawOffset; 2513 /* seqStoreSeqs[i].offset == offCode+1, and ZSTD_updateRep() expects offCode 2514 so we provide seqStoreSeqs[i].offset - 1 */ 2515 updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, 2516 seqStoreSeqs[i].offset - 1, 2517 seqStoreSeqs[i].litLength == 0); 2518 literalsRead += outSeqs[i].litLength; 2519 } 2520 /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0. 2521 * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker 2522 * for the block boundary, according to the API. 2523 */ 2524 assert(seqStoreLiteralsSize >= literalsRead); 2525 lastLLSize = seqStoreLiteralsSize - literalsRead; 2526 outSeqs[i].litLength = (U32)lastLLSize; 2527 outSeqs[i].matchLength = outSeqs[i].offset = outSeqs[i].rep = 0; 2528 seqStoreSeqSize++; 2529 zc->seqCollector.seqIndex += seqStoreSeqSize; 2530 } 2531 2532 size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, 2533 size_t outSeqsSize, const void* src, size_t srcSize) 2534 { 2535 const size_t dstCapacity = ZSTD_compressBound(srcSize); 2536 void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem); 2537 SeqCollector seqCollector; 2538 2539 RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!"); 2540 2541 seqCollector.collectSequences = 1; 2542 seqCollector.seqStart = outSeqs; 2543 seqCollector.seqIndex = 0; 2544 seqCollector.maxSequences = outSeqsSize; 2545 zc->seqCollector = seqCollector; 2546 2547 ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); 2548 ZSTD_customFree(dst, ZSTD_defaultCMem); 2549 return zc->seqCollector.seqIndex; 2550 } 2551 2552 size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) { 2553 size_t in = 0; 2554 size_t out = 0; 2555 for (; in < seqsSize; ++in) { 2556 if (sequences[in].offset == 0 && sequences[in].matchLength == 0) { 2557 if (in != seqsSize - 1) { 2558 sequences[in+1].litLength += sequences[in].litLength; 2559 } 2560 } else { 2561 sequences[out] = sequences[in]; 2562 ++out; 2563 } 2564 } 2565 return out; 2566 } 2567 2568 /* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */ 2569 static int ZSTD_isRLE(const BYTE* src, size_t length) { 2570 const BYTE* ip = src; 2571 const BYTE value = ip[0]; 2572 const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL); 2573 const size_t unrollSize = sizeof(size_t) * 4; 2574 const size_t unrollMask = unrollSize - 1; 2575 const size_t prefixLength = length & unrollMask; 2576 size_t i; 2577 size_t u; 2578 if (length == 1) return 1; 2579 /* Check if prefix is RLE first before using unrolled loop */ 2580 if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) { 2581 return 0; 2582 } 2583 for (i = prefixLength; i != length; i += unrollSize) { 2584 for (u = 0; u < unrollSize; u += sizeof(size_t)) { 2585 if (MEM_readST(ip + i + u) != valueST) { 2586 return 0; 2587 } 2588 } 2589 } 2590 return 1; 2591 } 2592 2593 /* Returns true if the given block may be RLE. 2594 * This is just a heuristic based on the compressibility. 2595 * It may return both false positives and false negatives. 2596 */ 2597 static int ZSTD_maybeRLE(seqStore_t const* seqStore) 2598 { 2599 size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); 2600 size_t const nbLits = (size_t)(seqStore->lit - seqStore->litStart); 2601 2602 return nbSeqs < 4 && nbLits < 10; 2603 } 2604 2605 static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc) 2606 { 2607 ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; 2608 zc->blockState.prevCBlock = zc->blockState.nextCBlock; 2609 zc->blockState.nextCBlock = tmp; 2610 } 2611 2612 static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, 2613 void* dst, size_t dstCapacity, 2614 const void* src, size_t srcSize, U32 frame) 2615 { 2616 /* This the upper bound for the length of an rle block. 2617 * This isn't the actual upper bound. Finding the real threshold 2618 * needs further investigation. 2619 */ 2620 const U32 rleMaxLength = 25; 2621 size_t cSize; 2622 const BYTE* ip = (const BYTE*)src; 2623 BYTE* op = (BYTE*)dst; 2624 DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", 2625 (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, 2626 (unsigned)zc->blockState.matchState.nextToUpdate); 2627 2628 { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); 2629 FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); 2630 if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } 2631 } 2632 2633 if (zc->seqCollector.collectSequences) { 2634 ZSTD_copyBlockSequences(zc); 2635 ZSTD_confirmRepcodesAndEntropyTables(zc); 2636 return 0; 2637 } 2638 2639 /* encode sequences and literals */ 2640 cSize = ZSTD_entropyCompressSequences(&zc->seqStore, 2641 &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, 2642 &zc->appliedParams, 2643 dst, dstCapacity, 2644 srcSize, 2645 zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, 2646 zc->bmi2); 2647 2648 if (zc->seqCollector.collectSequences) { 2649 ZSTD_copyBlockSequences(zc); 2650 return 0; 2651 } 2652 2653 2654 if (frame && 2655 /* We don't want to emit our first block as a RLE even if it qualifies because 2656 * doing so will cause the decoder (cli only) to throw a "should consume all input error." 2657 * This is only an issue for zstd <= v1.4.3 2658 */ 2659 !zc->isFirstBlock && 2660 cSize < rleMaxLength && 2661 ZSTD_isRLE(ip, srcSize)) 2662 { 2663 cSize = 1; 2664 op[0] = ip[0]; 2665 } 2666 2667 out: 2668 if (!ZSTD_isError(cSize) && cSize > 1) { 2669 ZSTD_confirmRepcodesAndEntropyTables(zc); 2670 } 2671 /* We check that dictionaries have offset codes available for the first 2672 * block. After the first block, the offcode table might not have large 2673 * enough codes to represent the offsets in the data. 2674 */ 2675 if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 2676 zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 2677 2678 return cSize; 2679 } 2680 2681 static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, 2682 void* dst, size_t dstCapacity, 2683 const void* src, size_t srcSize, 2684 const size_t bss, U32 lastBlock) 2685 { 2686 DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()"); 2687 if (bss == ZSTDbss_compress) { 2688 if (/* We don't want to emit our first block as a RLE even if it qualifies because 2689 * doing so will cause the decoder (cli only) to throw a "should consume all input error." 2690 * This is only an issue for zstd <= v1.4.3 2691 */ 2692 !zc->isFirstBlock && 2693 ZSTD_maybeRLE(&zc->seqStore) && 2694 ZSTD_isRLE((BYTE const*)src, srcSize)) 2695 { 2696 return ZSTD_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock); 2697 } 2698 /* Attempt superblock compression. 2699 * 2700 * Note that compressed size of ZSTD_compressSuperBlock() is not bound by the 2701 * standard ZSTD_compressBound(). This is a problem, because even if we have 2702 * space now, taking an extra byte now could cause us to run out of space later 2703 * and violate ZSTD_compressBound(). 2704 * 2705 * Define blockBound(blockSize) = blockSize + ZSTD_blockHeaderSize. 2706 * 2707 * In order to respect ZSTD_compressBound() we must attempt to emit a raw 2708 * uncompressed block in these cases: 2709 * * cSize == 0: Return code for an uncompressed block. 2710 * * cSize == dstSize_tooSmall: We may have expanded beyond blockBound(srcSize). 2711 * ZSTD_noCompressBlock() will return dstSize_tooSmall if we are really out of 2712 * output space. 2713 * * cSize >= blockBound(srcSize): We have expanded the block too much so 2714 * emit an uncompressed block. 2715 */ 2716 { 2717 size_t const cSize = ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock); 2718 if (cSize != ERROR(dstSize_tooSmall)) { 2719 size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy); 2720 FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed"); 2721 if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) { 2722 ZSTD_confirmRepcodesAndEntropyTables(zc); 2723 return cSize; 2724 } 2725 } 2726 } 2727 } 2728 2729 DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()"); 2730 /* Superblock compression failed, attempt to emit a single no compress block. 2731 * The decoder will be able to stream this block since it is uncompressed. 2732 */ 2733 return ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock); 2734 } 2735 2736 static size_t ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx* zc, 2737 void* dst, size_t dstCapacity, 2738 const void* src, size_t srcSize, 2739 U32 lastBlock) 2740 { 2741 size_t cSize = 0; 2742 const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); 2743 DEBUGLOG(5, "ZSTD_compressBlock_targetCBlockSize (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u, srcSize=%zu)", 2744 (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate, srcSize); 2745 FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); 2746 2747 cSize = ZSTD_compressBlock_targetCBlockSize_body(zc, dst, dstCapacity, src, srcSize, bss, lastBlock); 2748 FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize_body failed"); 2749 2750 if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 2751 zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 2752 2753 return cSize; 2754 } 2755 2756 static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, 2757 ZSTD_cwksp* ws, 2758 ZSTD_CCtx_params const* params, 2759 void const* ip, 2760 void const* iend) 2761 { 2762 if (ZSTD_window_needOverflowCorrection(ms->window, iend)) { 2763 U32 const maxDist = (U32)1 << params->cParams.windowLog; 2764 U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); 2765 U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); 2766 ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 2767 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 2768 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 2769 ZSTD_cwksp_mark_tables_dirty(ws); 2770 ZSTD_reduceIndex(ms, params, correction); 2771 ZSTD_cwksp_mark_tables_clean(ws); 2772 if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 2773 else ms->nextToUpdate -= correction; 2774 /* invalidate dictionaries on overflow correction */ 2775 ms->loadedDictEnd = 0; 2776 ms->dictMatchState = NULL; 2777 } 2778 } 2779 2780 /*! ZSTD_compress_frameChunk() : 2781 * Compress a chunk of data into one or multiple blocks. 2782 * All blocks will be terminated, all input will be consumed. 2783 * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. 2784 * Frame is supposed already started (header already produced) 2785 * @return : compressed size, or an error code 2786 */ 2787 static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, 2788 void* dst, size_t dstCapacity, 2789 const void* src, size_t srcSize, 2790 U32 lastFrameChunk) 2791 { 2792 size_t blockSize = cctx->blockSize; 2793 size_t remaining = srcSize; 2794 const BYTE* ip = (const BYTE*)src; 2795 BYTE* const ostart = (BYTE*)dst; 2796 BYTE* op = ostart; 2797 U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; 2798 2799 assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); 2800 2801 DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); 2802 if (cctx->appliedParams.fParams.checksumFlag && srcSize) 2803 xxh64_update(&cctx->xxhState, src, srcSize); 2804 2805 while (remaining) { 2806 ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 2807 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); 2808 2809 RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE, 2810 dstSize_tooSmall, 2811 "not enough space to store compressed block"); 2812 if (remaining < blockSize) blockSize = remaining; 2813 2814 ZSTD_overflowCorrectIfNeeded( 2815 ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize); 2816 ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); 2817 2818 /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ 2819 if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; 2820 2821 { size_t cSize; 2822 if (ZSTD_useTargetCBlockSize(&cctx->appliedParams)) { 2823 cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock); 2824 FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed"); 2825 assert(cSize > 0); 2826 assert(cSize <= blockSize + ZSTD_blockHeaderSize); 2827 } else { 2828 cSize = ZSTD_compressBlock_internal(cctx, 2829 op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, 2830 ip, blockSize, 1 /* frame */); 2831 FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed"); 2832 2833 if (cSize == 0) { /* block is not compressible */ 2834 cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 2835 FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); 2836 } else { 2837 U32 const cBlockHeader = cSize == 1 ? 2838 lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : 2839 lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 2840 MEM_writeLE24(op, cBlockHeader); 2841 cSize += ZSTD_blockHeaderSize; 2842 } 2843 } 2844 2845 2846 ip += blockSize; 2847 assert(remaining >= blockSize); 2848 remaining -= blockSize; 2849 op += cSize; 2850 assert(dstCapacity >= cSize); 2851 dstCapacity -= cSize; 2852 cctx->isFirstBlock = 0; 2853 DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u", 2854 (unsigned)cSize); 2855 } } 2856 2857 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; 2858 return (size_t)(op-ostart); 2859 } 2860 2861 2862 static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, 2863 const ZSTD_CCtx_params* params, U64 pledgedSrcSize, U32 dictID) 2864 { BYTE* const op = (BYTE*)dst; 2865 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ 2866 U32 const dictIDSizeCode = params->fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ 2867 U32 const checksumFlag = params->fParams.checksumFlag>0; 2868 U32 const windowSize = (U32)1 << params->cParams.windowLog; 2869 U32 const singleSegment = params->fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); 2870 BYTE const windowLogByte = (BYTE)((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); 2871 U32 const fcsCode = params->fParams.contentSizeFlag ? 2872 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ 2873 BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); 2874 size_t pos=0; 2875 2876 assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); 2877 RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall, 2878 "dst buf is too small to fit worst-case frame header size."); 2879 DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", 2880 !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); 2881 if (params->format == ZSTD_f_zstd1) { 2882 MEM_writeLE32(dst, ZSTD_MAGICNUMBER); 2883 pos = 4; 2884 } 2885 op[pos++] = frameHeaderDescriptionByte; 2886 if (!singleSegment) op[pos++] = windowLogByte; 2887 switch(dictIDSizeCode) 2888 { 2889 default: 2890 assert(0); /* impossible */ 2891 ZSTD_FALLTHROUGH; 2892 case 0 : break; 2893 case 1 : op[pos] = (BYTE)(dictID); pos++; break; 2894 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; 2895 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break; 2896 } 2897 switch(fcsCode) 2898 { 2899 default: 2900 assert(0); /* impossible */ 2901 ZSTD_FALLTHROUGH; 2902 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; 2903 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; 2904 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; 2905 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break; 2906 } 2907 return pos; 2908 } 2909 2910 /* ZSTD_writeSkippableFrame_advanced() : 2911 * Writes out a skippable frame with the specified magic number variant (16 are supported), 2912 * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data. 2913 * 2914 * Returns the total number of bytes written, or a ZSTD error code. 2915 */ 2916 size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, 2917 const void* src, size_t srcSize, unsigned magicVariant) { 2918 BYTE* op = (BYTE*)dst; 2919 RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */, 2920 dstSize_tooSmall, "Not enough room for skippable frame"); 2921 RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame"); 2922 RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported"); 2923 2924 MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant)); 2925 MEM_writeLE32(op+4, (U32)srcSize); 2926 ZSTD_memcpy(op+8, src, srcSize); 2927 return srcSize + ZSTD_SKIPPABLEHEADERSIZE; 2928 } 2929 2930 /* ZSTD_writeLastEmptyBlock() : 2931 * output an empty Block with end-of-frame mark to complete a frame 2932 * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) 2933 * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize) 2934 */ 2935 size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) 2936 { 2937 RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, 2938 "dst buf is too small to write frame trailer empty block."); 2939 { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ 2940 MEM_writeLE24(dst, cBlockHeader24); 2941 return ZSTD_blockHeaderSize; 2942 } 2943 } 2944 2945 size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) 2946 { 2947 RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong, 2948 "wrong cctx stage"); 2949 RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm, 2950 parameter_unsupported, 2951 "incompatible with ldm"); 2952 cctx->externSeqStore.seq = seq; 2953 cctx->externSeqStore.size = nbSeq; 2954 cctx->externSeqStore.capacity = nbSeq; 2955 cctx->externSeqStore.pos = 0; 2956 cctx->externSeqStore.posInSequence = 0; 2957 return 0; 2958 } 2959 2960 2961 static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, 2962 void* dst, size_t dstCapacity, 2963 const void* src, size_t srcSize, 2964 U32 frame, U32 lastFrameChunk) 2965 { 2966 ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 2967 size_t fhSize = 0; 2968 2969 DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u", 2970 cctx->stage, (unsigned)srcSize); 2971 RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong, 2972 "missing init (ZSTD_compressBegin)"); 2973 2974 if (frame && (cctx->stage==ZSTDcs_init)) { 2975 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 2976 cctx->pledgedSrcSizePlusOne-1, cctx->dictID); 2977 FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); 2978 assert(fhSize <= dstCapacity); 2979 dstCapacity -= fhSize; 2980 dst = (char*)dst + fhSize; 2981 cctx->stage = ZSTDcs_ongoing; 2982 } 2983 2984 if (!srcSize) return fhSize; /* do not generate an empty block if no input */ 2985 2986 if (!ZSTD_window_update(&ms->window, src, srcSize)) { 2987 ms->nextToUpdate = ms->window.dictLimit; 2988 } 2989 if (cctx->appliedParams.ldmParams.enableLdm) { 2990 ZSTD_window_update(&cctx->ldmState.window, src, srcSize); 2991 } 2992 2993 if (!frame) { 2994 /* overflow check and correction for block mode */ 2995 ZSTD_overflowCorrectIfNeeded( 2996 ms, &cctx->workspace, &cctx->appliedParams, 2997 src, (BYTE const*)src + srcSize); 2998 } 2999 3000 DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize); 3001 { size_t const cSize = frame ? 3002 ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : 3003 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */); 3004 FORWARD_IF_ERROR(cSize, "%s", frame ? "ZSTD_compress_frameChunk failed" : "ZSTD_compressBlock_internal failed"); 3005 cctx->consumedSrcSize += srcSize; 3006 cctx->producedCSize += (cSize + fhSize); 3007 assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 3008 if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 3009 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 3010 RETURN_ERROR_IF( 3011 cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne, 3012 srcSize_wrong, 3013 "error : pledgedSrcSize = %u, while realSrcSize >= %u", 3014 (unsigned)cctx->pledgedSrcSizePlusOne-1, 3015 (unsigned)cctx->consumedSrcSize); 3016 } 3017 return cSize + fhSize; 3018 } 3019 } 3020 3021 size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, 3022 void* dst, size_t dstCapacity, 3023 const void* src, size_t srcSize) 3024 { 3025 DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize); 3026 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); 3027 } 3028 3029 3030 size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) 3031 { 3032 ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; 3033 assert(!ZSTD_checkCParams(cParams)); 3034 return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); 3035 } 3036 3037 size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 3038 { 3039 DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize); 3040 { size_t const blockSizeMax = ZSTD_getBlockSize(cctx); 3041 RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); } 3042 3043 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); 3044 } 3045 3046 /*! ZSTD_loadDictionaryContent() : 3047 * @return : 0, or an error code 3048 */ 3049 static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, 3050 ldmState_t* ls, 3051 ZSTD_cwksp* ws, 3052 ZSTD_CCtx_params const* params, 3053 const void* src, size_t srcSize, 3054 ZSTD_dictTableLoadMethod_e dtlm) 3055 { 3056 const BYTE* ip = (const BYTE*) src; 3057 const BYTE* const iend = ip + srcSize; 3058 3059 ZSTD_window_update(&ms->window, src, srcSize); 3060 ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); 3061 3062 if (params->ldmParams.enableLdm && ls != NULL) { 3063 ZSTD_window_update(&ls->window, src, srcSize); 3064 ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base); 3065 } 3066 3067 /* Assert that we the ms params match the params we're being given */ 3068 ZSTD_assertEqualCParams(params->cParams, ms->cParams); 3069 3070 if (srcSize <= HASH_READ_SIZE) return 0; 3071 3072 while (iend - ip > HASH_READ_SIZE) { 3073 size_t const remaining = (size_t)(iend - ip); 3074 size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX); 3075 const BYTE* const ichunk = ip + chunk; 3076 3077 ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk); 3078 3079 if (params->ldmParams.enableLdm && ls != NULL) 3080 ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, ¶ms->ldmParams); 3081 3082 switch(params->cParams.strategy) 3083 { 3084 case ZSTD_fast: 3085 ZSTD_fillHashTable(ms, ichunk, dtlm); 3086 break; 3087 case ZSTD_dfast: 3088 ZSTD_fillDoubleHashTable(ms, ichunk, dtlm); 3089 break; 3090 3091 case ZSTD_greedy: 3092 case ZSTD_lazy: 3093 case ZSTD_lazy2: 3094 if (chunk >= HASH_READ_SIZE && ms->dedicatedDictSearch) { 3095 assert(chunk == remaining); /* must load everything in one go */ 3096 ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, ichunk-HASH_READ_SIZE); 3097 } else if (chunk >= HASH_READ_SIZE) { 3098 ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE); 3099 } 3100 break; 3101 3102 case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ 3103 case ZSTD_btopt: 3104 case ZSTD_btultra: 3105 case ZSTD_btultra2: 3106 if (chunk >= HASH_READ_SIZE) 3107 ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk); 3108 break; 3109 3110 default: 3111 assert(0); /* not possible : not a valid strategy id */ 3112 } 3113 3114 ip = ichunk; 3115 } 3116 3117 ms->nextToUpdate = (U32)(iend - ms->window.base); 3118 return 0; 3119 } 3120 3121 3122 /* Dictionaries that assign zero probability to symbols that show up causes problems 3123 * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check 3124 * and only dictionaries with 100% valid symbols can be assumed valid. 3125 */ 3126 static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) 3127 { 3128 U32 s; 3129 if (dictMaxSymbolValue < maxSymbolValue) { 3130 return FSE_repeat_check; 3131 } 3132 for (s = 0; s <= maxSymbolValue; ++s) { 3133 if (normalizedCounter[s] == 0) { 3134 return FSE_repeat_check; 3135 } 3136 } 3137 return FSE_repeat_valid; 3138 } 3139 3140 size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, 3141 const void* const dict, size_t dictSize) 3142 { 3143 short offcodeNCount[MaxOff+1]; 3144 unsigned offcodeMaxValue = MaxOff; 3145 const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */ 3146 const BYTE* const dictEnd = dictPtr + dictSize; 3147 dictPtr += 8; 3148 bs->entropy.huf.repeatMode = HUF_repeat_check; 3149 3150 { unsigned maxSymbolValue = 255; 3151 unsigned hasZeroWeights = 1; 3152 size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, 3153 dictEnd-dictPtr, &hasZeroWeights); 3154 3155 /* We only set the loaded table as valid if it contains all non-zero 3156 * weights. Otherwise, we set it to check */ 3157 if (!hasZeroWeights) 3158 bs->entropy.huf.repeatMode = HUF_repeat_valid; 3159 3160 RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, ""); 3161 RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, ""); 3162 dictPtr += hufHeaderSize; 3163 } 3164 3165 { unsigned offcodeLog; 3166 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); 3167 RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); 3168 RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); 3169 /* fill all offset symbols to avoid garbage at end of table */ 3170 RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 3171 bs->entropy.fse.offcodeCTable, 3172 offcodeNCount, MaxOff, offcodeLog, 3173 workspace, HUF_WORKSPACE_SIZE)), 3174 dictionary_corrupted, ""); 3175 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ 3176 dictPtr += offcodeHeaderSize; 3177 } 3178 3179 { short matchlengthNCount[MaxML+1]; 3180 unsigned matchlengthMaxValue = MaxML, matchlengthLog; 3181 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); 3182 RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); 3183 RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); 3184 RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 3185 bs->entropy.fse.matchlengthCTable, 3186 matchlengthNCount, matchlengthMaxValue, matchlengthLog, 3187 workspace, HUF_WORKSPACE_SIZE)), 3188 dictionary_corrupted, ""); 3189 bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML); 3190 dictPtr += matchlengthHeaderSize; 3191 } 3192 3193 { short litlengthNCount[MaxLL+1]; 3194 unsigned litlengthMaxValue = MaxLL, litlengthLog; 3195 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); 3196 RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); 3197 RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); 3198 RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 3199 bs->entropy.fse.litlengthCTable, 3200 litlengthNCount, litlengthMaxValue, litlengthLog, 3201 workspace, HUF_WORKSPACE_SIZE)), 3202 dictionary_corrupted, ""); 3203 bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL); 3204 dictPtr += litlengthHeaderSize; 3205 } 3206 3207 RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); 3208 bs->rep[0] = MEM_readLE32(dictPtr+0); 3209 bs->rep[1] = MEM_readLE32(dictPtr+4); 3210 bs->rep[2] = MEM_readLE32(dictPtr+8); 3211 dictPtr += 12; 3212 3213 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 3214 U32 offcodeMax = MaxOff; 3215 if (dictContentSize <= ((U32)-1) - 128 KB) { 3216 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ 3217 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ 3218 } 3219 /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */ 3220 bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)); 3221 3222 /* All repCodes must be <= dictContentSize and != 0 */ 3223 { U32 u; 3224 for (u=0; u<3; u++) { 3225 RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, ""); 3226 RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, ""); 3227 } } } 3228 3229 return dictPtr - (const BYTE*)dict; 3230 } 3231 3232 /* Dictionary format : 3233 * See : 3234 * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format 3235 */ 3236 /*! ZSTD_loadZstdDictionary() : 3237 * @return : dictID, or an error code 3238 * assumptions : magic number supposed already checked 3239 * dictSize supposed >= 8 3240 */ 3241 static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, 3242 ZSTD_matchState_t* ms, 3243 ZSTD_cwksp* ws, 3244 ZSTD_CCtx_params const* params, 3245 const void* dict, size_t dictSize, 3246 ZSTD_dictTableLoadMethod_e dtlm, 3247 void* workspace) 3248 { 3249 const BYTE* dictPtr = (const BYTE*)dict; 3250 const BYTE* const dictEnd = dictPtr + dictSize; 3251 size_t dictID; 3252 size_t eSize; 3253 3254 ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 3255 assert(dictSize >= 8); 3256 assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); 3257 3258 dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ ); 3259 eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize); 3260 FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed"); 3261 dictPtr += eSize; 3262 3263 { 3264 size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 3265 FORWARD_IF_ERROR(ZSTD_loadDictionaryContent( 3266 ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), ""); 3267 } 3268 return dictID; 3269 } 3270 3271 /* ZSTD_compress_insertDictionary() : 3272 * @return : dictID, or an error code */ 3273 static size_t 3274 ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, 3275 ZSTD_matchState_t* ms, 3276 ldmState_t* ls, 3277 ZSTD_cwksp* ws, 3278 const ZSTD_CCtx_params* params, 3279 const void* dict, size_t dictSize, 3280 ZSTD_dictContentType_e dictContentType, 3281 ZSTD_dictTableLoadMethod_e dtlm, 3282 void* workspace) 3283 { 3284 DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); 3285 if ((dict==NULL) || (dictSize<8)) { 3286 RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); 3287 return 0; 3288 } 3289 3290 ZSTD_reset_compressedBlockState(bs); 3291 3292 /* dict restricted modes */ 3293 if (dictContentType == ZSTD_dct_rawContent) 3294 return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm); 3295 3296 if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { 3297 if (dictContentType == ZSTD_dct_auto) { 3298 DEBUGLOG(4, "raw content dictionary detected"); 3299 return ZSTD_loadDictionaryContent( 3300 ms, ls, ws, params, dict, dictSize, dtlm); 3301 } 3302 RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); 3303 assert(0); /* impossible */ 3304 } 3305 3306 /* dict as full zstd dictionary */ 3307 return ZSTD_loadZstdDictionary( 3308 bs, ms, ws, params, dict, dictSize, dtlm, workspace); 3309 } 3310 3311 #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB) 3312 #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL) 3313 3314 /*! ZSTD_compressBegin_internal() : 3315 * @return : 0, or an error code */ 3316 static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 3317 const void* dict, size_t dictSize, 3318 ZSTD_dictContentType_e dictContentType, 3319 ZSTD_dictTableLoadMethod_e dtlm, 3320 const ZSTD_CDict* cdict, 3321 const ZSTD_CCtx_params* params, U64 pledgedSrcSize, 3322 ZSTD_buffered_policy_e zbuff) 3323 { 3324 DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog); 3325 /* params are supposed to be fully validated at this point */ 3326 assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); 3327 assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 3328 if ( (cdict) 3329 && (cdict->dictContentSize > 0) 3330 && ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF 3331 || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER 3332 || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 3333 || cdict->compressionLevel == 0) 3334 && (params->attachDictPref != ZSTD_dictForceLoad) ) { 3335 return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); 3336 } 3337 3338 FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize, 3339 ZSTDcrp_makeClean, zbuff) , ""); 3340 { size_t const dictID = cdict ? 3341 ZSTD_compress_insertDictionary( 3342 cctx->blockState.prevCBlock, &cctx->blockState.matchState, 3343 &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent, 3344 cdict->dictContentSize, cdict->dictContentType, dtlm, 3345 cctx->entropyWorkspace) 3346 : ZSTD_compress_insertDictionary( 3347 cctx->blockState.prevCBlock, &cctx->blockState.matchState, 3348 &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize, 3349 dictContentType, dtlm, cctx->entropyWorkspace); 3350 FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); 3351 assert(dictID <= UINT_MAX); 3352 cctx->dictID = (U32)dictID; 3353 cctx->dictContentSize = cdict ? cdict->dictContentSize : dictSize; 3354 } 3355 return 0; 3356 } 3357 3358 size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, 3359 const void* dict, size_t dictSize, 3360 ZSTD_dictContentType_e dictContentType, 3361 ZSTD_dictTableLoadMethod_e dtlm, 3362 const ZSTD_CDict* cdict, 3363 const ZSTD_CCtx_params* params, 3364 unsigned long long pledgedSrcSize) 3365 { 3366 DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog); 3367 /* compression parameters verification and optimization */ 3368 FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , ""); 3369 return ZSTD_compressBegin_internal(cctx, 3370 dict, dictSize, dictContentType, dtlm, 3371 cdict, 3372 params, pledgedSrcSize, 3373 ZSTDb_not_buffered); 3374 } 3375 3376 /*! ZSTD_compressBegin_advanced() : 3377 * @return : 0, or an error code */ 3378 size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, 3379 const void* dict, size_t dictSize, 3380 ZSTD_parameters params, unsigned long long pledgedSrcSize) 3381 { 3382 ZSTD_CCtx_params cctxParams; 3383 ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, ZSTD_NO_CLEVEL); 3384 return ZSTD_compressBegin_advanced_internal(cctx, 3385 dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, 3386 NULL /*cdict*/, 3387 &cctxParams, pledgedSrcSize); 3388 } 3389 3390 size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 3391 { 3392 ZSTD_CCtx_params cctxParams; 3393 { 3394 ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict); 3395 ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel); 3396 } 3397 DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); 3398 return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 3399 &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); 3400 } 3401 3402 size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) 3403 { 3404 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); 3405 } 3406 3407 3408 /*! ZSTD_writeEpilogue() : 3409 * Ends a frame. 3410 * @return : nb of bytes written into dst (or an error code) */ 3411 static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) 3412 { 3413 BYTE* const ostart = (BYTE*)dst; 3414 BYTE* op = ostart; 3415 size_t fhSize = 0; 3416 3417 DEBUGLOG(4, "ZSTD_writeEpilogue"); 3418 RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing"); 3419 3420 /* special case : empty frame */ 3421 if (cctx->stage == ZSTDcs_init) { 3422 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); 3423 FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); 3424 dstCapacity -= fhSize; 3425 op += fhSize; 3426 cctx->stage = ZSTDcs_ongoing; 3427 } 3428 3429 if (cctx->stage != ZSTDcs_ending) { 3430 /* write one last empty block, make it the "last" block */ 3431 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; 3432 RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue"); 3433 MEM_writeLE32(op, cBlockHeader24); 3434 op += ZSTD_blockHeaderSize; 3435 dstCapacity -= ZSTD_blockHeaderSize; 3436 } 3437 3438 if (cctx->appliedParams.fParams.checksumFlag) { 3439 U32 const checksum = (U32) xxh64_digest(&cctx->xxhState); 3440 RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); 3441 DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum); 3442 MEM_writeLE32(op, checksum); 3443 op += 4; 3444 } 3445 3446 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */ 3447 return op-ostart; 3448 } 3449 3450 void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize) 3451 { 3452 (void)cctx; 3453 (void)extraCSize; 3454 } 3455 3456 size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, 3457 void* dst, size_t dstCapacity, 3458 const void* src, size_t srcSize) 3459 { 3460 size_t endResult; 3461 size_t const cSize = ZSTD_compressContinue_internal(cctx, 3462 dst, dstCapacity, src, srcSize, 3463 1 /* frame mode */, 1 /* last chunk */); 3464 FORWARD_IF_ERROR(cSize, "ZSTD_compressContinue_internal failed"); 3465 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); 3466 FORWARD_IF_ERROR(endResult, "ZSTD_writeEpilogue failed"); 3467 assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 3468 if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 3469 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 3470 DEBUGLOG(4, "end of frame : controlling src size"); 3471 RETURN_ERROR_IF( 3472 cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1, 3473 srcSize_wrong, 3474 "error : pledgedSrcSize = %u, while realSrcSize = %u", 3475 (unsigned)cctx->pledgedSrcSizePlusOne-1, 3476 (unsigned)cctx->consumedSrcSize); 3477 } 3478 ZSTD_CCtx_trace(cctx, endResult); 3479 return cSize + endResult; 3480 } 3481 3482 size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, 3483 void* dst, size_t dstCapacity, 3484 const void* src, size_t srcSize, 3485 const void* dict,size_t dictSize, 3486 ZSTD_parameters params) 3487 { 3488 ZSTD_CCtx_params cctxParams; 3489 DEBUGLOG(4, "ZSTD_compress_advanced"); 3490 FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); 3491 ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, ZSTD_NO_CLEVEL); 3492 return ZSTD_compress_advanced_internal(cctx, 3493 dst, dstCapacity, 3494 src, srcSize, 3495 dict, dictSize, 3496 &cctxParams); 3497 } 3498 3499 /* Internal */ 3500 size_t ZSTD_compress_advanced_internal( 3501 ZSTD_CCtx* cctx, 3502 void* dst, size_t dstCapacity, 3503 const void* src, size_t srcSize, 3504 const void* dict,size_t dictSize, 3505 const ZSTD_CCtx_params* params) 3506 { 3507 DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize); 3508 FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 3509 dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 3510 params, srcSize, ZSTDb_not_buffered) , ""); 3511 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 3512 } 3513 3514 size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, 3515 void* dst, size_t dstCapacity, 3516 const void* src, size_t srcSize, 3517 const void* dict, size_t dictSize, 3518 int compressionLevel) 3519 { 3520 ZSTD_CCtx_params cctxParams; 3521 { 3522 ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict); 3523 assert(params.fParams.contentSizeFlag == 1); 3524 ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel); 3525 } 3526 DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize); 3527 return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams); 3528 } 3529 3530 size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, 3531 void* dst, size_t dstCapacity, 3532 const void* src, size_t srcSize, 3533 int compressionLevel) 3534 { 3535 DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize); 3536 assert(cctx != NULL); 3537 return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); 3538 } 3539 3540 size_t ZSTD_compress(void* dst, size_t dstCapacity, 3541 const void* src, size_t srcSize, 3542 int compressionLevel) 3543 { 3544 size_t result; 3545 ZSTD_CCtx* cctx = ZSTD_createCCtx(); 3546 RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed"); 3547 result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel); 3548 ZSTD_freeCCtx(cctx); 3549 return result; 3550 } 3551 3552 3553 /* ===== Dictionary API ===== */ 3554 3555 /*! ZSTD_estimateCDictSize_advanced() : 3556 * Estimate amount of memory that will be needed to create a dictionary with following arguments */ 3557 size_t ZSTD_estimateCDictSize_advanced( 3558 size_t dictSize, ZSTD_compressionParameters cParams, 3559 ZSTD_dictLoadMethod_e dictLoadMethod) 3560 { 3561 DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); 3562 return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) 3563 + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) 3564 + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) 3565 + (dictLoadMethod == ZSTD_dlm_byRef ? 0 3566 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *)))); 3567 } 3568 3569 size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) 3570 { 3571 ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 3572 return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); 3573 } 3574 3575 size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 3576 { 3577 if (cdict==NULL) return 0; /* support sizeof on NULL */ 3578 DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict)); 3579 /* cdict may be in the workspace */ 3580 return (cdict->workspace.workspace == cdict ? 0 : sizeof(*cdict)) 3581 + ZSTD_cwksp_sizeof(&cdict->workspace); 3582 } 3583 3584 static size_t ZSTD_initCDict_internal( 3585 ZSTD_CDict* cdict, 3586 const void* dictBuffer, size_t dictSize, 3587 ZSTD_dictLoadMethod_e dictLoadMethod, 3588 ZSTD_dictContentType_e dictContentType, 3589 ZSTD_CCtx_params params) 3590 { 3591 DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); 3592 assert(!ZSTD_checkCParams(params.cParams)); 3593 cdict->matchState.cParams = params.cParams; 3594 cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch; 3595 if (cdict->matchState.dedicatedDictSearch && dictSize > ZSTD_CHUNKSIZE_MAX) { 3596 cdict->matchState.dedicatedDictSearch = 0; 3597 } 3598 if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { 3599 cdict->dictContent = dictBuffer; 3600 } else { 3601 void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*))); 3602 RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!"); 3603 cdict->dictContent = internalBuffer; 3604 ZSTD_memcpy(internalBuffer, dictBuffer, dictSize); 3605 } 3606 cdict->dictContentSize = dictSize; 3607 cdict->dictContentType = dictContentType; 3608 3609 cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE); 3610 3611 3612 /* Reset the state to no dictionary */ 3613 ZSTD_reset_compressedBlockState(&cdict->cBlockState); 3614 FORWARD_IF_ERROR(ZSTD_reset_matchState( 3615 &cdict->matchState, 3616 &cdict->workspace, 3617 ¶ms.cParams, 3618 ZSTDcrp_makeClean, 3619 ZSTDirp_reset, 3620 ZSTD_resetTarget_CDict), ""); 3621 /* (Maybe) load the dictionary 3622 * Skips loading the dictionary if it is < 8 bytes. 3623 */ 3624 { params.compressionLevel = ZSTD_CLEVEL_DEFAULT; 3625 params.fParams.contentSizeFlag = 1; 3626 { size_t const dictID = ZSTD_compress_insertDictionary( 3627 &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace, 3628 ¶ms, cdict->dictContent, cdict->dictContentSize, 3629 dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace); 3630 FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); 3631 assert(dictID <= (size_t)(U32)-1); 3632 cdict->dictID = (U32)dictID; 3633 } 3634 } 3635 3636 return 0; 3637 } 3638 3639 static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize, 3640 ZSTD_dictLoadMethod_e dictLoadMethod, 3641 ZSTD_compressionParameters cParams, ZSTD_customMem customMem) 3642 { 3643 if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; 3644 3645 { size_t const workspaceSize = 3646 ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + 3647 ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + 3648 ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + 3649 (dictLoadMethod == ZSTD_dlm_byRef ? 0 3650 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))); 3651 void* const workspace = ZSTD_customMalloc(workspaceSize, customMem); 3652 ZSTD_cwksp ws; 3653 ZSTD_CDict* cdict; 3654 3655 if (!workspace) { 3656 ZSTD_customFree(workspace, customMem); 3657 return NULL; 3658 } 3659 3660 ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc); 3661 3662 cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); 3663 assert(cdict != NULL); 3664 ZSTD_cwksp_move(&cdict->workspace, &ws); 3665 cdict->customMem = customMem; 3666 cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */ 3667 3668 return cdict; 3669 } 3670 } 3671 3672 ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, 3673 ZSTD_dictLoadMethod_e dictLoadMethod, 3674 ZSTD_dictContentType_e dictContentType, 3675 ZSTD_compressionParameters cParams, 3676 ZSTD_customMem customMem) 3677 { 3678 ZSTD_CCtx_params cctxParams; 3679 ZSTD_memset(&cctxParams, 0, sizeof(cctxParams)); 3680 ZSTD_CCtxParams_init(&cctxParams, 0); 3681 cctxParams.cParams = cParams; 3682 cctxParams.customMem = customMem; 3683 return ZSTD_createCDict_advanced2( 3684 dictBuffer, dictSize, 3685 dictLoadMethod, dictContentType, 3686 &cctxParams, customMem); 3687 } 3688 3689 ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2( 3690 const void* dict, size_t dictSize, 3691 ZSTD_dictLoadMethod_e dictLoadMethod, 3692 ZSTD_dictContentType_e dictContentType, 3693 const ZSTD_CCtx_params* originalCctxParams, 3694 ZSTD_customMem customMem) 3695 { 3696 ZSTD_CCtx_params cctxParams = *originalCctxParams; 3697 ZSTD_compressionParameters cParams; 3698 ZSTD_CDict* cdict; 3699 3700 DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType); 3701 if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 3702 3703 if (cctxParams.enableDedicatedDictSearch) { 3704 cParams = ZSTD_dedicatedDictSearch_getCParams( 3705 cctxParams.compressionLevel, dictSize); 3706 ZSTD_overrideCParams(&cParams, &cctxParams.cParams); 3707 } else { 3708 cParams = ZSTD_getCParamsFromCCtxParams( 3709 &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 3710 } 3711 3712 if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) { 3713 /* Fall back to non-DDSS params */ 3714 cctxParams.enableDedicatedDictSearch = 0; 3715 cParams = ZSTD_getCParamsFromCCtxParams( 3716 &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 3717 } 3718 3719 cctxParams.cParams = cParams; 3720 3721 cdict = ZSTD_createCDict_advanced_internal(dictSize, 3722 dictLoadMethod, cctxParams.cParams, 3723 customMem); 3724 3725 if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 3726 dict, dictSize, 3727 dictLoadMethod, dictContentType, 3728 cctxParams) )) { 3729 ZSTD_freeCDict(cdict); 3730 return NULL; 3731 } 3732 3733 return cdict; 3734 } 3735 3736 ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 3737 { 3738 ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 3739 ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, 3740 ZSTD_dlm_byCopy, ZSTD_dct_auto, 3741 cParams, ZSTD_defaultCMem); 3742 if (cdict) 3743 cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; 3744 return cdict; 3745 } 3746 3747 ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) 3748 { 3749 ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 3750 ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, 3751 ZSTD_dlm_byRef, ZSTD_dct_auto, 3752 cParams, ZSTD_defaultCMem); 3753 if (cdict) 3754 cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; 3755 return cdict; 3756 } 3757 3758 size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 3759 { 3760 if (cdict==NULL) return 0; /* support free on NULL */ 3761 { ZSTD_customMem const cMem = cdict->customMem; 3762 int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict); 3763 ZSTD_cwksp_free(&cdict->workspace, cMem); 3764 if (!cdictInWorkspace) { 3765 ZSTD_customFree(cdict, cMem); 3766 } 3767 return 0; 3768 } 3769 } 3770 3771 /*! ZSTD_initStaticCDict_advanced() : 3772 * Generate a digested dictionary in provided memory area. 3773 * workspace: The memory area to emplace the dictionary into. 3774 * Provided pointer must 8-bytes aligned. 3775 * It must outlive dictionary usage. 3776 * workspaceSize: Use ZSTD_estimateCDictSize() 3777 * to determine how large workspace must be. 3778 * cParams : use ZSTD_getCParams() to transform a compression level 3779 * into its relevants cParams. 3780 * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) 3781 * Note : there is no corresponding "free" function. 3782 * Since workspace was allocated externally, it must be freed externally. 3783 */ 3784 const ZSTD_CDict* ZSTD_initStaticCDict( 3785 void* workspace, size_t workspaceSize, 3786 const void* dict, size_t dictSize, 3787 ZSTD_dictLoadMethod_e dictLoadMethod, 3788 ZSTD_dictContentType_e dictContentType, 3789 ZSTD_compressionParameters cParams) 3790 { 3791 size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 3792 size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) 3793 + (dictLoadMethod == ZSTD_dlm_byRef ? 0 3794 : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))) 3795 + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) 3796 + matchStateSize; 3797 ZSTD_CDict* cdict; 3798 ZSTD_CCtx_params params; 3799 3800 if ((size_t)workspace & 7) return NULL; /* 8-aligned */ 3801 3802 { 3803 ZSTD_cwksp ws; 3804 ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); 3805 cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); 3806 if (cdict == NULL) return NULL; 3807 ZSTD_cwksp_move(&cdict->workspace, &ws); 3808 } 3809 3810 DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u", 3811 (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); 3812 if (workspaceSize < neededSize) return NULL; 3813 3814 ZSTD_CCtxParams_init(¶ms, 0); 3815 params.cParams = cParams; 3816 3817 if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 3818 dict, dictSize, 3819 dictLoadMethod, dictContentType, 3820 params) )) 3821 return NULL; 3822 3823 return cdict; 3824 } 3825 3826 ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) 3827 { 3828 assert(cdict != NULL); 3829 return cdict->matchState.cParams; 3830 } 3831 3832 /*! ZSTD_getDictID_fromCDict() : 3833 * Provides the dictID of the dictionary loaded into `cdict`. 3834 * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. 3835 * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ 3836 unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict) 3837 { 3838 if (cdict==NULL) return 0; 3839 return cdict->dictID; 3840 } 3841 3842 3843 /* ZSTD_compressBegin_usingCDict_advanced() : 3844 * cdict must be != NULL */ 3845 size_t ZSTD_compressBegin_usingCDict_advanced( 3846 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, 3847 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) 3848 { 3849 ZSTD_CCtx_params cctxParams; 3850 DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); 3851 RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!"); 3852 /* Initialize the cctxParams from the cdict */ 3853 { 3854 ZSTD_parameters params; 3855 params.fParams = fParams; 3856 params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF 3857 || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER 3858 || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 3859 || cdict->compressionLevel == 0 ) ? 3860 ZSTD_getCParamsFromCDict(cdict) 3861 : ZSTD_getCParams(cdict->compressionLevel, 3862 pledgedSrcSize, 3863 cdict->dictContentSize); 3864 ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, cdict->compressionLevel); 3865 } 3866 /* Increase window log to fit the entire dictionary and source if the 3867 * source size is known. Limit the increase to 19, which is the 3868 * window log for compression level 1 with the largest source size. 3869 */ 3870 if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 3871 U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); 3872 U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; 3873 cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog); 3874 } 3875 return ZSTD_compressBegin_internal(cctx, 3876 NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, 3877 cdict, 3878 &cctxParams, pledgedSrcSize, 3879 ZSTDb_not_buffered); 3880 } 3881 3882 /* ZSTD_compressBegin_usingCDict() : 3883 * pledgedSrcSize=0 means "unknown" 3884 * if pledgedSrcSize>0, it will enable contentSizeFlag */ 3885 size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 3886 { 3887 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 3888 DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); 3889 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); 3890 } 3891 3892 size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, 3893 void* dst, size_t dstCapacity, 3894 const void* src, size_t srcSize, 3895 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) 3896 { 3897 FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ 3898 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 3899 } 3900 3901 /*! ZSTD_compress_usingCDict() : 3902 * Compression using a digested Dictionary. 3903 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. 3904 * Note that compression parameters are decided at CDict creation time 3905 * while frame parameters are hardcoded */ 3906 size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, 3907 void* dst, size_t dstCapacity, 3908 const void* src, size_t srcSize, 3909 const ZSTD_CDict* cdict) 3910 { 3911 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 3912 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); 3913 } 3914 3915 3916 3917 /* ****************************************************************** 3918 * Streaming 3919 ********************************************************************/ 3920 3921 ZSTD_CStream* ZSTD_createCStream(void) 3922 { 3923 DEBUGLOG(3, "ZSTD_createCStream"); 3924 return ZSTD_createCStream_advanced(ZSTD_defaultCMem); 3925 } 3926 3927 ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) 3928 { 3929 return ZSTD_initStaticCCtx(workspace, workspaceSize); 3930 } 3931 3932 ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) 3933 { /* CStream and CCtx are now same object */ 3934 return ZSTD_createCCtx_advanced(customMem); 3935 } 3936 3937 size_t ZSTD_freeCStream(ZSTD_CStream* zcs) 3938 { 3939 return ZSTD_freeCCtx(zcs); /* same object */ 3940 } 3941 3942 3943 3944 /*====== Initialization ======*/ 3945 3946 size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } 3947 3948 size_t ZSTD_CStreamOutSize(void) 3949 { 3950 return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; 3951 } 3952 3953 static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize) 3954 { 3955 if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) 3956 return ZSTD_cpm_attachDict; 3957 else 3958 return ZSTD_cpm_noAttachDict; 3959 } 3960 3961 /* ZSTD_resetCStream(): 3962 * pledgedSrcSize == 0 means "unknown" */ 3963 size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss) 3964 { 3965 /* temporary : 0 interpreted as "unknown" during transition period. 3966 * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 3967 * 0 will be interpreted as "empty" in the future. 3968 */ 3969 U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 3970 DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize); 3971 FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 3972 FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 3973 return 0; 3974 } 3975 3976 /*! ZSTD_initCStream_internal() : 3977 * Note : for lib/compress only. Used by zstdmt_compress.c. 3978 * Assumption 1 : params are valid 3979 * Assumption 2 : either dict, or cdict, is defined, not both */ 3980 size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, 3981 const void* dict, size_t dictSize, const ZSTD_CDict* cdict, 3982 const ZSTD_CCtx_params* params, 3983 unsigned long long pledgedSrcSize) 3984 { 3985 DEBUGLOG(4, "ZSTD_initCStream_internal"); 3986 FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 3987 FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 3988 assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); 3989 zcs->requestedParams = *params; 3990 assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 3991 if (dict) { 3992 FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); 3993 } else { 3994 /* Dictionary is cleared if !cdict */ 3995 FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); 3996 } 3997 return 0; 3998 } 3999 4000 /* ZSTD_initCStream_usingCDict_advanced() : 4001 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ 4002 size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, 4003 const ZSTD_CDict* cdict, 4004 ZSTD_frameParameters fParams, 4005 unsigned long long pledgedSrcSize) 4006 { 4007 DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); 4008 FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 4009 FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 4010 zcs->requestedParams.fParams = fParams; 4011 FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); 4012 return 0; 4013 } 4014 4015 /* note : cdict must outlive compression session */ 4016 size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) 4017 { 4018 DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); 4019 FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 4020 FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); 4021 return 0; 4022 } 4023 4024 4025 /* ZSTD_initCStream_advanced() : 4026 * pledgedSrcSize must be exact. 4027 * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. 4028 * dict is loaded with default parameters ZSTD_dct_auto and ZSTD_dlm_byCopy. */ 4029 size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, 4030 const void* dict, size_t dictSize, 4031 ZSTD_parameters params, unsigned long long pss) 4032 { 4033 /* for compatibility with older programs relying on this behavior. 4034 * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. 4035 * This line will be removed in the future. 4036 */ 4037 U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 4038 DEBUGLOG(4, "ZSTD_initCStream_advanced"); 4039 FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 4040 FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 4041 FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); 4042 ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, ¶ms); 4043 FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); 4044 return 0; 4045 } 4046 4047 size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 4048 { 4049 DEBUGLOG(4, "ZSTD_initCStream_usingDict"); 4050 FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 4051 FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); 4052 FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); 4053 return 0; 4054 } 4055 4056 size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) 4057 { 4058 /* temporary : 0 interpreted as "unknown" during transition period. 4059 * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 4060 * 0 will be interpreted as "empty" in the future. 4061 */ 4062 U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 4063 DEBUGLOG(4, "ZSTD_initCStream_srcSize"); 4064 FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 4065 FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , ""); 4066 FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); 4067 FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 4068 return 0; 4069 } 4070 4071 size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 4072 { 4073 DEBUGLOG(4, "ZSTD_initCStream"); 4074 FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 4075 FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , ""); 4076 FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); 4077 return 0; 4078 } 4079 4080 /*====== Compression ======*/ 4081 4082 static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) 4083 { 4084 size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; 4085 if (hintInSize==0) hintInSize = cctx->blockSize; 4086 return hintInSize; 4087 } 4088 4089 /* ZSTD_compressStream_generic(): 4090 * internal function for all *compressStream*() variants 4091 * non-static, because can be called from zstdmt_compress.c 4092 * @return : hint size for next input */ 4093 static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, 4094 ZSTD_outBuffer* output, 4095 ZSTD_inBuffer* input, 4096 ZSTD_EndDirective const flushMode) 4097 { 4098 const char* const istart = (const char*)input->src; 4099 const char* const iend = input->size != 0 ? istart + input->size : istart; 4100 const char* ip = input->pos != 0 ? istart + input->pos : istart; 4101 char* const ostart = (char*)output->dst; 4102 char* const oend = output->size != 0 ? ostart + output->size : ostart; 4103 char* op = output->pos != 0 ? ostart + output->pos : ostart; 4104 U32 someMoreWork = 1; 4105 4106 /* check expectations */ 4107 DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode); 4108 if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { 4109 assert(zcs->inBuff != NULL); 4110 assert(zcs->inBuffSize > 0); 4111 } 4112 if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) { 4113 assert(zcs->outBuff != NULL); 4114 assert(zcs->outBuffSize > 0); 4115 } 4116 assert(output->pos <= output->size); 4117 assert(input->pos <= input->size); 4118 assert((U32)flushMode <= (U32)ZSTD_e_end); 4119 4120 while (someMoreWork) { 4121 switch(zcs->streamStage) 4122 { 4123 case zcss_init: 4124 RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!"); 4125 4126 case zcss_load: 4127 if ( (flushMode == ZSTD_e_end) 4128 && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip) /* Enough output space */ 4129 || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) /* OR we are allowed to return dstSizeTooSmall */ 4130 && (zcs->inBuffPos == 0) ) { 4131 /* shortcut to compression pass directly into output buffer */ 4132 size_t const cSize = ZSTD_compressEnd(zcs, 4133 op, oend-op, ip, iend-ip); 4134 DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); 4135 FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed"); 4136 ip = iend; 4137 op += cSize; 4138 zcs->frameEnded = 1; 4139 ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 4140 someMoreWork = 0; break; 4141 } 4142 /* complete loading into inBuffer in buffered mode */ 4143 if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { 4144 size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; 4145 size_t const loaded = ZSTD_limitCopy( 4146 zcs->inBuff + zcs->inBuffPos, toLoad, 4147 ip, iend-ip); 4148 zcs->inBuffPos += loaded; 4149 if (loaded != 0) 4150 ip += loaded; 4151 if ( (flushMode == ZSTD_e_continue) 4152 && (zcs->inBuffPos < zcs->inBuffTarget) ) { 4153 /* not enough input to fill full block : stop here */ 4154 someMoreWork = 0; break; 4155 } 4156 if ( (flushMode == ZSTD_e_flush) 4157 && (zcs->inBuffPos == zcs->inToCompress) ) { 4158 /* empty */ 4159 someMoreWork = 0; break; 4160 } 4161 } 4162 /* compress current block (note : this stage cannot be stopped in the middle) */ 4163 DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); 4164 { int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered); 4165 void* cDst; 4166 size_t cSize; 4167 size_t oSize = oend-op; 4168 size_t const iSize = inputBuffered 4169 ? zcs->inBuffPos - zcs->inToCompress 4170 : MIN((size_t)(iend - ip), zcs->blockSize); 4171 if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) 4172 cDst = op; /* compress into output buffer, to skip flush stage */ 4173 else 4174 cDst = zcs->outBuff, oSize = zcs->outBuffSize; 4175 if (inputBuffered) { 4176 unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); 4177 cSize = lastBlock ? 4178 ZSTD_compressEnd(zcs, cDst, oSize, 4179 zcs->inBuff + zcs->inToCompress, iSize) : 4180 ZSTD_compressContinue(zcs, cDst, oSize, 4181 zcs->inBuff + zcs->inToCompress, iSize); 4182 FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); 4183 zcs->frameEnded = lastBlock; 4184 /* prepare next block */ 4185 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; 4186 if (zcs->inBuffTarget > zcs->inBuffSize) 4187 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; 4188 DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", 4189 (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); 4190 if (!lastBlock) 4191 assert(zcs->inBuffTarget <= zcs->inBuffSize); 4192 zcs->inToCompress = zcs->inBuffPos; 4193 } else { 4194 unsigned const lastBlock = (ip + iSize == iend); 4195 assert(flushMode == ZSTD_e_end /* Already validated */); 4196 cSize = lastBlock ? 4197 ZSTD_compressEnd(zcs, cDst, oSize, ip, iSize) : 4198 ZSTD_compressContinue(zcs, cDst, oSize, ip, iSize); 4199 /* Consume the input prior to error checking to mirror buffered mode. */ 4200 if (iSize > 0) 4201 ip += iSize; 4202 FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); 4203 zcs->frameEnded = lastBlock; 4204 if (lastBlock) 4205 assert(ip == iend); 4206 } 4207 if (cDst == op) { /* no need to flush */ 4208 op += cSize; 4209 if (zcs->frameEnded) { 4210 DEBUGLOG(5, "Frame completed directly in outBuffer"); 4211 someMoreWork = 0; 4212 ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 4213 } 4214 break; 4215 } 4216 zcs->outBuffContentSize = cSize; 4217 zcs->outBuffFlushedSize = 0; 4218 zcs->streamStage = zcss_flush; /* pass-through to flush stage */ 4219 } 4220 ZSTD_FALLTHROUGH; 4221 case zcss_flush: 4222 DEBUGLOG(5, "flush stage"); 4223 assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered); 4224 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; 4225 size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), 4226 zcs->outBuff + zcs->outBuffFlushedSize, toFlush); 4227 DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", 4228 (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed); 4229 if (flushed) 4230 op += flushed; 4231 zcs->outBuffFlushedSize += flushed; 4232 if (toFlush!=flushed) { 4233 /* flush not fully completed, presumably because dst is too small */ 4234 assert(op==oend); 4235 someMoreWork = 0; 4236 break; 4237 } 4238 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 4239 if (zcs->frameEnded) { 4240 DEBUGLOG(5, "Frame completed on flush"); 4241 someMoreWork = 0; 4242 ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 4243 break; 4244 } 4245 zcs->streamStage = zcss_load; 4246 break; 4247 } 4248 4249 default: /* impossible */ 4250 assert(0); 4251 } 4252 } 4253 4254 input->pos = ip - istart; 4255 output->pos = op - ostart; 4256 if (zcs->frameEnded) return 0; 4257 return ZSTD_nextInputSizeHint(zcs); 4258 } 4259 4260 static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx) 4261 { 4262 return ZSTD_nextInputSizeHint(cctx); 4263 4264 } 4265 4266 size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) 4267 { 4268 FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) , ""); 4269 return ZSTD_nextInputSizeHint_MTorST(zcs); 4270 } 4271 4272 /* After a compression call set the expected input/output buffer. 4273 * This is validated at the start of the next compression call. 4274 */ 4275 static void ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, ZSTD_outBuffer const* output, ZSTD_inBuffer const* input) 4276 { 4277 if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { 4278 cctx->expectedInBuffer = *input; 4279 } 4280 if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { 4281 cctx->expectedOutBufferSize = output->size - output->pos; 4282 } 4283 } 4284 4285 /* Validate that the input/output buffers match the expectations set by 4286 * ZSTD_setBufferExpectations. 4287 */ 4288 static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx, 4289 ZSTD_outBuffer const* output, 4290 ZSTD_inBuffer const* input, 4291 ZSTD_EndDirective endOp) 4292 { 4293 if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { 4294 ZSTD_inBuffer const expect = cctx->expectedInBuffer; 4295 if (expect.src != input->src || expect.pos != input->pos || expect.size != input->size) 4296 RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer enabled but input differs!"); 4297 if (endOp != ZSTD_e_end) 4298 RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer can only be used with ZSTD_e_end!"); 4299 } 4300 if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { 4301 size_t const outBufferSize = output->size - output->pos; 4302 if (cctx->expectedOutBufferSize != outBufferSize) 4303 RETURN_ERROR(dstBuffer_wrong, "ZSTD_c_stableOutBuffer enabled but output size differs!"); 4304 } 4305 return 0; 4306 } 4307 4308 static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, 4309 ZSTD_EndDirective endOp, 4310 size_t inSize) { 4311 ZSTD_CCtx_params params = cctx->requestedParams; 4312 ZSTD_prefixDict const prefixDict = cctx->prefixDict; 4313 FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */ 4314 ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ 4315 assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ 4316 if (cctx->cdict) 4317 params.compressionLevel = cctx->cdict->compressionLevel; /* let cdict take priority in terms of compression level */ 4318 DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); 4319 if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-fix pledgedSrcSize */ 4320 { 4321 size_t const dictSize = prefixDict.dict 4322 ? prefixDict.dictSize 4323 : (cctx->cdict ? cctx->cdict->dictContentSize : 0); 4324 ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, ¶ms, cctx->pledgedSrcSizePlusOne - 1); 4325 params.cParams = ZSTD_getCParamsFromCCtxParams( 4326 ¶ms, cctx->pledgedSrcSizePlusOne-1, 4327 dictSize, mode); 4328 } 4329 4330 if (ZSTD_CParams_shouldEnableLdm(¶ms.cParams)) { 4331 /* Enable LDM by default for optimal parser and window size >= 128MB */ 4332 DEBUGLOG(4, "LDM enabled by default (window size >= 128MB, strategy >= btopt)"); 4333 params.ldmParams.enableLdm = 1; 4334 } 4335 4336 { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1; 4337 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 4338 FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 4339 prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast, 4340 cctx->cdict, 4341 ¶ms, pledgedSrcSize, 4342 ZSTDb_buffered) , ""); 4343 assert(cctx->appliedParams.nbWorkers == 0); 4344 cctx->inToCompress = 0; 4345 cctx->inBuffPos = 0; 4346 if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) { 4347 /* for small input: avoid automatic flush on reaching end of block, since 4348 * it would require to add a 3-bytes null block to end frame 4349 */ 4350 cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize); 4351 } else { 4352 cctx->inBuffTarget = 0; 4353 } 4354 cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; 4355 cctx->streamStage = zcss_load; 4356 cctx->frameEnded = 0; 4357 } 4358 return 0; 4359 } 4360 4361 size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, 4362 ZSTD_outBuffer* output, 4363 ZSTD_inBuffer* input, 4364 ZSTD_EndDirective endOp) 4365 { 4366 DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); 4367 /* check conditions */ 4368 RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer"); 4369 RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer"); 4370 RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective"); 4371 assert(cctx != NULL); 4372 4373 /* transparent initialization stage */ 4374 if (cctx->streamStage == zcss_init) { 4375 FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, input->size), "CompressStream2 initialization failed"); 4376 ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */ 4377 } 4378 /* end of transparent initialization stage */ 4379 4380 FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers"); 4381 /* compression stage */ 4382 FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , ""); 4383 DEBUGLOG(5, "completed ZSTD_compressStream2"); 4384 ZSTD_setBufferExpectations(cctx, output, input); 4385 return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ 4386 } 4387 4388 size_t ZSTD_compressStream2_simpleArgs ( 4389 ZSTD_CCtx* cctx, 4390 void* dst, size_t dstCapacity, size_t* dstPos, 4391 const void* src, size_t srcSize, size_t* srcPos, 4392 ZSTD_EndDirective endOp) 4393 { 4394 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; 4395 ZSTD_inBuffer input = { src, srcSize, *srcPos }; 4396 /* ZSTD_compressStream2() will check validity of dstPos and srcPos */ 4397 size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); 4398 *dstPos = output.pos; 4399 *srcPos = input.pos; 4400 return cErr; 4401 } 4402 4403 size_t ZSTD_compress2(ZSTD_CCtx* cctx, 4404 void* dst, size_t dstCapacity, 4405 const void* src, size_t srcSize) 4406 { 4407 ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode; 4408 ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode; 4409 DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize); 4410 ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 4411 /* Enable stable input/output buffers. */ 4412 cctx->requestedParams.inBufferMode = ZSTD_bm_stable; 4413 cctx->requestedParams.outBufferMode = ZSTD_bm_stable; 4414 { size_t oPos = 0; 4415 size_t iPos = 0; 4416 size_t const result = ZSTD_compressStream2_simpleArgs(cctx, 4417 dst, dstCapacity, &oPos, 4418 src, srcSize, &iPos, 4419 ZSTD_e_end); 4420 /* Reset to the original values. */ 4421 cctx->requestedParams.inBufferMode = originalInBufferMode; 4422 cctx->requestedParams.outBufferMode = originalOutBufferMode; 4423 FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed"); 4424 if (result != 0) { /* compression not completed, due to lack of output space */ 4425 assert(oPos == dstCapacity); 4426 RETURN_ERROR(dstSize_tooSmall, ""); 4427 } 4428 assert(iPos == srcSize); /* all input is expected consumed */ 4429 return oPos; 4430 } 4431 } 4432 4433 typedef struct { 4434 U32 idx; /* Index in array of ZSTD_Sequence */ 4435 U32 posInSequence; /* Position within sequence at idx */ 4436 size_t posInSrc; /* Number of bytes given by sequences provided so far */ 4437 } ZSTD_sequencePosition; 4438 4439 /* Returns a ZSTD error code if sequence is not valid */ 4440 static size_t ZSTD_validateSequence(U32 offCode, U32 matchLength, 4441 size_t posInSrc, U32 windowLog, size_t dictSize, U32 minMatch) { 4442 size_t offsetBound; 4443 U32 windowSize = 1 << windowLog; 4444 /* posInSrc represents the amount of data the the decoder would decode up to this point. 4445 * As long as the amount of data decoded is less than or equal to window size, offsets may be 4446 * larger than the total length of output decoded in order to reference the dict, even larger than 4447 * window size. After output surpasses windowSize, we're limited to windowSize offsets again. 4448 */ 4449 offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize; 4450 RETURN_ERROR_IF(offCode > offsetBound + ZSTD_REP_MOVE, corruption_detected, "Offset too large!"); 4451 RETURN_ERROR_IF(matchLength < minMatch, corruption_detected, "Matchlength too small"); 4452 return 0; 4453 } 4454 4455 /* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */ 4456 static U32 ZSTD_finalizeOffCode(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) { 4457 U32 offCode = rawOffset + ZSTD_REP_MOVE; 4458 U32 repCode = 0; 4459 4460 if (!ll0 && rawOffset == rep[0]) { 4461 repCode = 1; 4462 } else if (rawOffset == rep[1]) { 4463 repCode = 2 - ll0; 4464 } else if (rawOffset == rep[2]) { 4465 repCode = 3 - ll0; 4466 } else if (ll0 && rawOffset == rep[0] - 1) { 4467 repCode = 3; 4468 } 4469 if (repCode) { 4470 /* ZSTD_storeSeq expects a number in the range [0, 2] to represent a repcode */ 4471 offCode = repCode - 1; 4472 } 4473 return offCode; 4474 } 4475 4476 /* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of 4477 * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter. 4478 */ 4479 static size_t ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, 4480 const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, 4481 const void* src, size_t blockSize) { 4482 U32 idx = seqPos->idx; 4483 BYTE const* ip = (BYTE const*)(src); 4484 const BYTE* const iend = ip + blockSize; 4485 repcodes_t updatedRepcodes; 4486 U32 dictSize; 4487 U32 litLength; 4488 U32 matchLength; 4489 U32 ll0; 4490 U32 offCode; 4491 4492 if (cctx->cdict) { 4493 dictSize = (U32)cctx->cdict->dictContentSize; 4494 } else if (cctx->prefixDict.dict) { 4495 dictSize = (U32)cctx->prefixDict.dictSize; 4496 } else { 4497 dictSize = 0; 4498 } 4499 ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); 4500 for (; (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0) && idx < inSeqsSize; ++idx) { 4501 litLength = inSeqs[idx].litLength; 4502 matchLength = inSeqs[idx].matchLength; 4503 ll0 = litLength == 0; 4504 offCode = ZSTD_finalizeOffCode(inSeqs[idx].offset, updatedRepcodes.rep, ll0); 4505 updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0); 4506 4507 DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength); 4508 if (cctx->appliedParams.validateSequences) { 4509 seqPos->posInSrc += litLength + matchLength; 4510 FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc, 4511 cctx->appliedParams.cParams.windowLog, dictSize, 4512 cctx->appliedParams.cParams.minMatch), 4513 "Sequence validation failed"); 4514 } 4515 RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation, 4516 "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); 4517 ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH); 4518 ip += matchLength + litLength; 4519 } 4520 ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); 4521 4522 if (inSeqs[idx].litLength) { 4523 DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength); 4524 ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength); 4525 ip += inSeqs[idx].litLength; 4526 seqPos->posInSrc += inSeqs[idx].litLength; 4527 } 4528 RETURN_ERROR_IF(ip != iend, corruption_detected, "Blocksize doesn't agree with block delimiter!"); 4529 seqPos->idx = idx+1; 4530 return 0; 4531 } 4532 4533 /* Returns the number of bytes to move the current read position back by. Only non-zero 4534 * if we ended up splitting a sequence. Otherwise, it may return a ZSTD error if something 4535 * went wrong. 4536 * 4537 * This function will attempt to scan through blockSize bytes represented by the sequences 4538 * in inSeqs, storing any (partial) sequences. 4539 * 4540 * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to 4541 * avoid splitting a match, or to avoid splitting a match such that it would produce a match 4542 * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block. 4543 */ 4544 static size_t ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, 4545 const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, 4546 const void* src, size_t blockSize) { 4547 U32 idx = seqPos->idx; 4548 U32 startPosInSequence = seqPos->posInSequence; 4549 U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize; 4550 size_t dictSize; 4551 BYTE const* ip = (BYTE const*)(src); 4552 BYTE const* iend = ip + blockSize; /* May be adjusted if we decide to process fewer than blockSize bytes */ 4553 repcodes_t updatedRepcodes; 4554 U32 bytesAdjustment = 0; 4555 U32 finalMatchSplit = 0; 4556 U32 litLength; 4557 U32 matchLength; 4558 U32 rawOffset; 4559 U32 offCode; 4560 4561 if (cctx->cdict) { 4562 dictSize = cctx->cdict->dictContentSize; 4563 } else if (cctx->prefixDict.dict) { 4564 dictSize = cctx->prefixDict.dictSize; 4565 } else { 4566 dictSize = 0; 4567 } 4568 DEBUGLOG(5, "ZSTD_copySequencesToSeqStore: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize); 4569 DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); 4570 ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); 4571 while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) { 4572 const ZSTD_Sequence currSeq = inSeqs[idx]; 4573 litLength = currSeq.litLength; 4574 matchLength = currSeq.matchLength; 4575 rawOffset = currSeq.offset; 4576 4577 /* Modify the sequence depending on where endPosInSequence lies */ 4578 if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) { 4579 if (startPosInSequence >= litLength) { 4580 startPosInSequence -= litLength; 4581 litLength = 0; 4582 matchLength -= startPosInSequence; 4583 } else { 4584 litLength -= startPosInSequence; 4585 } 4586 /* Move to the next sequence */ 4587 endPosInSequence -= currSeq.litLength + currSeq.matchLength; 4588 startPosInSequence = 0; 4589 idx++; 4590 } else { 4591 /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence 4592 does not reach the end of the match. So, we have to split the sequence */ 4593 DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u", 4594 currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence); 4595 if (endPosInSequence > litLength) { 4596 U32 firstHalfMatchLength; 4597 litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence; 4598 firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength; 4599 if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) { 4600 /* Only ever split the match if it is larger than the block size */ 4601 U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence; 4602 if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) { 4603 /* Move the endPosInSequence backward so that it creates match of minMatch length */ 4604 endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; 4605 bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; 4606 firstHalfMatchLength -= bytesAdjustment; 4607 } 4608 matchLength = firstHalfMatchLength; 4609 /* Flag that we split the last match - after storing the sequence, exit the loop, 4610 but keep the value of endPosInSequence */ 4611 finalMatchSplit = 1; 4612 } else { 4613 /* Move the position in sequence backwards so that we don't split match, and break to store 4614 * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence 4615 * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so 4616 * would cause the first half of the match to be too small 4617 */ 4618 bytesAdjustment = endPosInSequence - currSeq.litLength; 4619 endPosInSequence = currSeq.litLength; 4620 break; 4621 } 4622 } else { 4623 /* This sequence ends inside the literals, break to store the last literals */ 4624 break; 4625 } 4626 } 4627 /* Check if this offset can be represented with a repcode */ 4628 { U32 ll0 = (litLength == 0); 4629 offCode = ZSTD_finalizeOffCode(rawOffset, updatedRepcodes.rep, ll0); 4630 updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0); 4631 } 4632 4633 if (cctx->appliedParams.validateSequences) { 4634 seqPos->posInSrc += litLength + matchLength; 4635 FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc, 4636 cctx->appliedParams.cParams.windowLog, dictSize, 4637 cctx->appliedParams.cParams.minMatch), 4638 "Sequence validation failed"); 4639 } 4640 DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength); 4641 RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation, 4642 "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); 4643 ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH); 4644 ip += matchLength + litLength; 4645 } 4646 DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); 4647 assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength); 4648 seqPos->idx = idx; 4649 seqPos->posInSequence = endPosInSequence; 4650 ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); 4651 4652 iend -= bytesAdjustment; 4653 if (ip != iend) { 4654 /* Store any last literals */ 4655 U32 lastLLSize = (U32)(iend - ip); 4656 assert(ip <= iend); 4657 DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize); 4658 ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize); 4659 seqPos->posInSrc += lastLLSize; 4660 } 4661 4662 return bytesAdjustment; 4663 } 4664 4665 typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, 4666 const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, 4667 const void* src, size_t blockSize); 4668 static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) { 4669 ZSTD_sequenceCopier sequenceCopier = NULL; 4670 assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode)); 4671 if (mode == ZSTD_sf_explicitBlockDelimiters) { 4672 return ZSTD_copySequencesToSeqStoreExplicitBlockDelim; 4673 } else if (mode == ZSTD_sf_noBlockDelimiters) { 4674 return ZSTD_copySequencesToSeqStoreNoBlockDelim; 4675 } 4676 assert(sequenceCopier != NULL); 4677 return sequenceCopier; 4678 } 4679 4680 /* Compress, block-by-block, all of the sequences given. 4681 * 4682 * Returns the cumulative size of all compressed blocks (including their headers), otherwise a ZSTD error. 4683 */ 4684 static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx, 4685 void* dst, size_t dstCapacity, 4686 const ZSTD_Sequence* inSeqs, size_t inSeqsSize, 4687 const void* src, size_t srcSize) { 4688 size_t cSize = 0; 4689 U32 lastBlock; 4690 size_t blockSize; 4691 size_t compressedSeqsSize; 4692 size_t remaining = srcSize; 4693 ZSTD_sequencePosition seqPos = {0, 0, 0}; 4694 4695 BYTE const* ip = (BYTE const*)src; 4696 BYTE* op = (BYTE*)dst; 4697 ZSTD_sequenceCopier sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters); 4698 4699 DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize); 4700 /* Special case: empty frame */ 4701 if (remaining == 0) { 4702 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1); 4703 RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header"); 4704 MEM_writeLE32(op, cBlockHeader24); 4705 op += ZSTD_blockHeaderSize; 4706 dstCapacity -= ZSTD_blockHeaderSize; 4707 cSize += ZSTD_blockHeaderSize; 4708 } 4709 4710 while (remaining) { 4711 size_t cBlockSize; 4712 size_t additionalByteAdjustment; 4713 lastBlock = remaining <= cctx->blockSize; 4714 blockSize = lastBlock ? (U32)remaining : (U32)cctx->blockSize; 4715 ZSTD_resetSeqStore(&cctx->seqStore); 4716 DEBUGLOG(4, "Working on new block. Blocksize: %zu", blockSize); 4717 4718 additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize); 4719 FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy"); 4720 blockSize -= additionalByteAdjustment; 4721 4722 /* If blocks are too small, emit as a nocompress block */ 4723 if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { 4724 cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 4725 FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed"); 4726 DEBUGLOG(4, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize); 4727 cSize += cBlockSize; 4728 ip += blockSize; 4729 op += cBlockSize; 4730 remaining -= blockSize; 4731 dstCapacity -= cBlockSize; 4732 continue; 4733 } 4734 4735 compressedSeqsSize = ZSTD_entropyCompressSequences(&cctx->seqStore, 4736 &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy, 4737 &cctx->appliedParams, 4738 op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize, 4739 blockSize, 4740 cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, 4741 cctx->bmi2); 4742 FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed"); 4743 DEBUGLOG(4, "Compressed sequences size: %zu", compressedSeqsSize); 4744 4745 if (!cctx->isFirstBlock && 4746 ZSTD_maybeRLE(&cctx->seqStore) && 4747 ZSTD_isRLE((BYTE const*)src, srcSize)) { 4748 /* We don't want to emit our first block as a RLE even if it qualifies because 4749 * doing so will cause the decoder (cli only) to throw a "should consume all input error." 4750 * This is only an issue for zstd <= v1.4.3 4751 */ 4752 compressedSeqsSize = 1; 4753 } 4754 4755 if (compressedSeqsSize == 0) { 4756 /* ZSTD_noCompressBlock writes the block header as well */ 4757 cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 4758 FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed"); 4759 DEBUGLOG(4, "Writing out nocompress block, size: %zu", cBlockSize); 4760 } else if (compressedSeqsSize == 1) { 4761 cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock); 4762 FORWARD_IF_ERROR(cBlockSize, "RLE compress block failed"); 4763 DEBUGLOG(4, "Writing out RLE block, size: %zu", cBlockSize); 4764 } else { 4765 U32 cBlockHeader; 4766 /* Error checking and repcodes update */ 4767 ZSTD_confirmRepcodesAndEntropyTables(cctx); 4768 if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 4769 cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 4770 4771 /* Write block header into beginning of block*/ 4772 cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3); 4773 MEM_writeLE24(op, cBlockHeader); 4774 cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize; 4775 DEBUGLOG(4, "Writing out compressed block, size: %zu", cBlockSize); 4776 } 4777 4778 cSize += cBlockSize; 4779 DEBUGLOG(4, "cSize running total: %zu", cSize); 4780 4781 if (lastBlock) { 4782 break; 4783 } else { 4784 ip += blockSize; 4785 op += cBlockSize; 4786 remaining -= blockSize; 4787 dstCapacity -= cBlockSize; 4788 cctx->isFirstBlock = 0; 4789 } 4790 } 4791 4792 return cSize; 4793 } 4794 4795 size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstCapacity, 4796 const ZSTD_Sequence* inSeqs, size_t inSeqsSize, 4797 const void* src, size_t srcSize) { 4798 BYTE* op = (BYTE*)dst; 4799 size_t cSize = 0; 4800 size_t compressedBlocksSize = 0; 4801 size_t frameHeaderSize = 0; 4802 4803 /* Transparent initialization stage, same as compressStream2() */ 4804 DEBUGLOG(3, "ZSTD_compressSequences()"); 4805 assert(cctx != NULL); 4806 FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed"); 4807 /* Begin writing output, starting with frame header */ 4808 frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID); 4809 op += frameHeaderSize; 4810 dstCapacity -= frameHeaderSize; 4811 cSize += frameHeaderSize; 4812 if (cctx->appliedParams.fParams.checksumFlag && srcSize) { 4813 xxh64_update(&cctx->xxhState, src, srcSize); 4814 } 4815 /* cSize includes block header size and compressed sequences size */ 4816 compressedBlocksSize = ZSTD_compressSequences_internal(cctx, 4817 op, dstCapacity, 4818 inSeqs, inSeqsSize, 4819 src, srcSize); 4820 FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!"); 4821 cSize += compressedBlocksSize; 4822 dstCapacity -= compressedBlocksSize; 4823 4824 if (cctx->appliedParams.fParams.checksumFlag) { 4825 U32 const checksum = (U32) xxh64_digest(&cctx->xxhState); 4826 RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); 4827 DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum); 4828 MEM_writeLE32((char*)dst + cSize, checksum); 4829 cSize += 4; 4830 } 4831 4832 DEBUGLOG(3, "Final compressed size: %zu", cSize); 4833 return cSize; 4834 } 4835 4836 /*====== Finalize ======*/ 4837 4838 /*! ZSTD_flushStream() : 4839 * @return : amount of data remaining to flush */ 4840 size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 4841 { 4842 ZSTD_inBuffer input = { NULL, 0, 0 }; 4843 return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); 4844 } 4845 4846 4847 size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 4848 { 4849 ZSTD_inBuffer input = { NULL, 0, 0 }; 4850 size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); 4851 FORWARD_IF_ERROR( remainingToFlush , "ZSTD_compressStream2 failed"); 4852 if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ 4853 /* single thread mode : attempt to calculate remaining to flush more precisely */ 4854 { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; 4855 size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4); 4856 size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize; 4857 DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush); 4858 return toFlush; 4859 } 4860 } 4861 4862 4863 /*-===== Pre-defined compression levels =====-*/ 4864 4865 #define ZSTD_MAX_CLEVEL 22 4866 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } 4867 int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } 4868 4869 static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { 4870 { /* "default" - for any srcSize > 256 KB */ 4871 /* W, C, H, S, L, TL, strat */ 4872 { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ 4873 { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ 4874 { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ 4875 { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ 4876 { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ 4877 { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */ 4878 { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ 4879 { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */ 4880 { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ 4881 { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ 4882 { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ 4883 { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ 4884 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ 4885 { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */ 4886 { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ 4887 { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ 4888 { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ 4889 { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ 4890 { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ 4891 { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ 4892 { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ 4893 { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ 4894 { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ 4895 }, 4896 { /* for srcSize <= 256 KB */ 4897 /* W, C, H, S, L, T, strat */ 4898 { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 4899 { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ 4900 { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ 4901 { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ 4902 { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ 4903 { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ 4904 { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ 4905 { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ 4906 { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 4907 { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 4908 { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 4909 { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ 4910 { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ 4911 { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ 4912 { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 4913 { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ 4914 { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 4915 { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 4916 { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ 4917 { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 4918 { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ 4919 { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ 4920 { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ 4921 }, 4922 { /* for srcSize <= 128 KB */ 4923 /* W, C, H, S, L, T, strat */ 4924 { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 4925 { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ 4926 { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ 4927 { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ 4928 { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ 4929 { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ 4930 { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ 4931 { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ 4932 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 4933 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 4934 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 4935 { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ 4936 { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ 4937 { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ 4938 { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 4939 { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ 4940 { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 4941 { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 4942 { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ 4943 { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ 4944 { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ 4945 { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 4946 { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ 4947 }, 4948 { /* for srcSize <= 16 KB */ 4949 /* W, C, H, S, L, T, strat */ 4950 { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 4951 { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ 4952 { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ 4953 { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ 4954 { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ 4955 { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ 4956 { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ 4957 { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ 4958 { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ 4959 { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ 4960 { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ 4961 { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ 4962 { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ 4963 { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ 4964 { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ 4965 { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ 4966 { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ 4967 { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ 4968 { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ 4969 { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 4970 { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ 4971 { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 4972 { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ 4973 }, 4974 }; 4975 4976 static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize) 4977 { 4978 ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict); 4979 switch (cParams.strategy) { 4980 case ZSTD_fast: 4981 case ZSTD_dfast: 4982 break; 4983 case ZSTD_greedy: 4984 case ZSTD_lazy: 4985 case ZSTD_lazy2: 4986 cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG; 4987 break; 4988 case ZSTD_btlazy2: 4989 case ZSTD_btopt: 4990 case ZSTD_btultra: 4991 case ZSTD_btultra2: 4992 break; 4993 } 4994 return cParams; 4995 } 4996 4997 static int ZSTD_dedicatedDictSearch_isSupported( 4998 ZSTD_compressionParameters const* cParams) 4999 { 5000 return (cParams->strategy >= ZSTD_greedy) 5001 && (cParams->strategy <= ZSTD_lazy2) 5002 && (cParams->hashLog >= cParams->chainLog) 5003 && (cParams->chainLog <= 24); 5004 } 5005 5006 /* 5007 * Reverses the adjustment applied to cparams when enabling dedicated dict 5008 * search. This is used to recover the params set to be used in the working 5009 * context. (Otherwise, those tables would also grow.) 5010 */ 5011 static void ZSTD_dedicatedDictSearch_revertCParams( 5012 ZSTD_compressionParameters* cParams) { 5013 switch (cParams->strategy) { 5014 case ZSTD_fast: 5015 case ZSTD_dfast: 5016 break; 5017 case ZSTD_greedy: 5018 case ZSTD_lazy: 5019 case ZSTD_lazy2: 5020 cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG; 5021 break; 5022 case ZSTD_btlazy2: 5023 case ZSTD_btopt: 5024 case ZSTD_btultra: 5025 case ZSTD_btultra2: 5026 break; 5027 } 5028 } 5029 5030 static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) 5031 { 5032 switch (mode) { 5033 case ZSTD_cpm_unknown: 5034 case ZSTD_cpm_noAttachDict: 5035 case ZSTD_cpm_createCDict: 5036 break; 5037 case ZSTD_cpm_attachDict: 5038 dictSize = 0; 5039 break; 5040 default: 5041 assert(0); 5042 break; 5043 } 5044 { int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN; 5045 size_t const addedSize = unknown && dictSize > 0 ? 500 : 0; 5046 return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize; 5047 } 5048 } 5049 5050 /*! ZSTD_getCParams_internal() : 5051 * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 5052 * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown. 5053 * Use dictSize == 0 for unknown or unused. 5054 * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */ 5055 static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) 5056 { 5057 U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode); 5058 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); 5059 int row; 5060 DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel); 5061 5062 /* row */ 5063 if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 5064 else if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ 5065 else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; 5066 else row = compressionLevel; 5067 5068 { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; 5069 /* acceleration factor */ 5070 if (compressionLevel < 0) { 5071 int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel); 5072 cp.targetLength = (unsigned)(-clampedCompressionLevel); 5073 } 5074 /* refine parameters based on srcSize & dictSize */ 5075 return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode); 5076 } 5077 } 5078 5079 /*! ZSTD_getCParams() : 5080 * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 5081 * Size values are optional, provide 0 if not known or unused */ 5082 ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) 5083 { 5084 if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; 5085 return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); 5086 } 5087 5088 /*! ZSTD_getParams() : 5089 * same idea as ZSTD_getCParams() 5090 * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). 5091 * Fields of `ZSTD_frameParameters` are set to default values */ 5092 static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { 5093 ZSTD_parameters params; 5094 ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode); 5095 DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); 5096 ZSTD_memset(¶ms, 0, sizeof(params)); 5097 params.cParams = cParams; 5098 params.fParams.contentSizeFlag = 1; 5099 return params; 5100 } 5101 5102 /*! ZSTD_getParams() : 5103 * same idea as ZSTD_getCParams() 5104 * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). 5105 * Fields of `ZSTD_frameParameters` are set to default values */ 5106 ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { 5107 if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; 5108 return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); 5109 } 5110