1 /* 2 * Copyright (c) 2016-present, 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 #include "zstd_compress_internal.h" 12 #include "zstd_fast.h" 13 14 15 void ZSTD_fillHashTable(ZSTD_matchState_t* ms, 16 const void* const end, 17 ZSTD_dictTableLoadMethod_e dtlm) 18 { 19 const ZSTD_compressionParameters* const cParams = &ms->cParams; 20 U32* const hashTable = ms->hashTable; 21 U32 const hBits = cParams->hashLog; 22 U32 const mls = cParams->minMatch; 23 const BYTE* const base = ms->window.base; 24 const BYTE* ip = base + ms->nextToUpdate; 25 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE; 26 const U32 fastHashFillStep = 3; 27 28 /* Always insert every fastHashFillStep position into the hash table. 29 * Insert the other positions if their hash entry is empty. 30 */ 31 for ( ; ip + fastHashFillStep < iend + 2; ip += fastHashFillStep) { 32 U32 const current = (U32)(ip - base); 33 size_t const hash0 = ZSTD_hashPtr(ip, hBits, mls); 34 hashTable[hash0] = current; 35 if (dtlm == ZSTD_dtlm_fast) continue; 36 /* Only load extra positions for ZSTD_dtlm_full */ 37 { U32 p; 38 for (p = 1; p < fastHashFillStep; ++p) { 39 size_t const hash = ZSTD_hashPtr(ip + p, hBits, mls); 40 if (hashTable[hash] == 0) { /* not yet filled */ 41 hashTable[hash] = current + p; 42 } } } } 43 } 44 45 46 FORCE_INLINE_TEMPLATE 47 size_t ZSTD_compressBlock_fast_generic( 48 ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 49 void const* src, size_t srcSize, 50 U32 const mls) 51 { 52 const ZSTD_compressionParameters* const cParams = &ms->cParams; 53 U32* const hashTable = ms->hashTable; 54 U32 const hlog = cParams->hashLog; 55 /* support stepSize of 0 */ 56 size_t const stepSize = cParams->targetLength + !(cParams->targetLength) + 1; 57 const BYTE* const base = ms->window.base; 58 const BYTE* const istart = (const BYTE*)src; 59 /* We check ip0 (ip + 0) and ip1 (ip + 1) each loop */ 60 const BYTE* ip0 = istart; 61 const BYTE* ip1; 62 const BYTE* anchor = istart; 63 const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); 64 const U32 maxDistance = 1U << cParams->windowLog; 65 const U32 validStartIndex = ms->window.dictLimit; 66 const U32 prefixStartIndex = (endIndex - validStartIndex > maxDistance) ? endIndex - maxDistance : validStartIndex; 67 const BYTE* const prefixStart = base + prefixStartIndex; 68 const BYTE* const iend = istart + srcSize; 69 const BYTE* const ilimit = iend - HASH_READ_SIZE; 70 U32 offset_1=rep[0], offset_2=rep[1]; 71 U32 offsetSaved = 0; 72 73 /* init */ 74 ip0 += (ip0 == prefixStart); 75 ip1 = ip0 + 1; 76 { 77 U32 const maxRep = (U32)(ip0 - prefixStart); 78 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0; 79 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0; 80 } 81 82 /* Main Search Loop */ 83 while (ip1 < ilimit) { /* < instead of <=, because check at ip0+2 */ 84 size_t mLength; 85 BYTE const* ip2 = ip0 + 2; 86 size_t const h0 = ZSTD_hashPtr(ip0, hlog, mls); 87 U32 const val0 = MEM_read32(ip0); 88 size_t const h1 = ZSTD_hashPtr(ip1, hlog, mls); 89 U32 const val1 = MEM_read32(ip1); 90 U32 const current0 = (U32)(ip0-base); 91 U32 const current1 = (U32)(ip1-base); 92 U32 const matchIndex0 = hashTable[h0]; 93 U32 const matchIndex1 = hashTable[h1]; 94 BYTE const* repMatch = ip2-offset_1; 95 const BYTE* match0 = base + matchIndex0; 96 const BYTE* match1 = base + matchIndex1; 97 U32 offcode; 98 hashTable[h0] = current0; /* update hash table */ 99 hashTable[h1] = current1; /* update hash table */ 100 101 assert(ip0 + 1 == ip1); 102 103 if ((offset_1 > 0) & (MEM_read32(repMatch) == MEM_read32(ip2))) { 104 mLength = ip2[-1] == repMatch[-1] ? 1 : 0; 105 ip0 = ip2 - mLength; 106 match0 = repMatch - mLength; 107 offcode = 0; 108 goto _match; 109 } 110 if ((matchIndex0 > prefixStartIndex) && MEM_read32(match0) == val0) { 111 /* found a regular match */ 112 goto _offset; 113 } 114 if ((matchIndex1 > prefixStartIndex) && MEM_read32(match1) == val1) { 115 /* found a regular match after one literal */ 116 ip0 = ip1; 117 match0 = match1; 118 goto _offset; 119 } 120 { 121 size_t const step = ((ip0-anchor) >> (kSearchStrength - 1)) + stepSize; 122 assert(step >= 2); 123 ip0 += step; 124 ip1 += step; 125 continue; 126 } 127 _offset: /* Requires: ip0, match0 */ 128 /* Compute the offset code */ 129 offset_2 = offset_1; 130 offset_1 = (U32)(ip0-match0); 131 offcode = offset_1 + ZSTD_REP_MOVE; 132 mLength = 0; 133 /* Count the backwards match length */ 134 while (((ip0>anchor) & (match0>prefixStart)) 135 && (ip0[-1] == match0[-1])) { ip0--; match0--; mLength++; } /* catch up */ 136 137 _match: /* Requires: ip0, match0, offcode */ 138 /* Count the forward length */ 139 mLength += ZSTD_count(ip0+mLength+4, match0+mLength+4, iend) + 4; 140 ZSTD_storeSeq(seqStore, ip0-anchor, anchor, offcode, mLength-MINMATCH); 141 /* match found */ 142 ip0 += mLength; 143 anchor = ip0; 144 ip1 = ip0 + 1; 145 146 if (ip0 <= ilimit) { 147 /* Fill Table */ 148 assert(base+current0+2 > istart); /* check base overflow */ 149 hashTable[ZSTD_hashPtr(base+current0+2, hlog, mls)] = current0+2; /* here because current+2 could be > iend-8 */ 150 hashTable[ZSTD_hashPtr(ip0-2, hlog, mls)] = (U32)(ip0-2-base); 151 152 while ( (ip0 <= ilimit) 153 && ( (offset_2>0) 154 & (MEM_read32(ip0) == MEM_read32(ip0 - offset_2)) )) { 155 /* store sequence */ 156 size_t const rLength = ZSTD_count(ip0+4, ip0+4-offset_2, iend) + 4; 157 U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ 158 hashTable[ZSTD_hashPtr(ip0, hlog, mls)] = (U32)(ip0-base); 159 ip0 += rLength; 160 ip1 = ip0 + 1; 161 ZSTD_storeSeq(seqStore, 0, anchor, 0, rLength-MINMATCH); 162 anchor = ip0; 163 continue; /* faster when present (confirmed on gcc-8) ... (?) */ 164 } 165 } 166 } 167 168 /* save reps for next block */ 169 rep[0] = offset_1 ? offset_1 : offsetSaved; 170 rep[1] = offset_2 ? offset_2 : offsetSaved; 171 172 /* Return the last literals size */ 173 return (size_t)(iend - anchor); 174 } 175 176 177 size_t ZSTD_compressBlock_fast( 178 ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 179 void const* src, size_t srcSize) 180 { 181 ZSTD_compressionParameters const* cParams = &ms->cParams; 182 U32 const mls = cParams->minMatch; 183 assert(ms->dictMatchState == NULL); 184 switch(mls) 185 { 186 default: /* includes case 3 */ 187 case 4 : 188 return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 4); 189 case 5 : 190 return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 5); 191 case 6 : 192 return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 6); 193 case 7 : 194 return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, 7); 195 } 196 } 197 198 FORCE_INLINE_TEMPLATE 199 size_t ZSTD_compressBlock_fast_dictMatchState_generic( 200 ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 201 void const* src, size_t srcSize, U32 const mls) 202 { 203 const ZSTD_compressionParameters* const cParams = &ms->cParams; 204 U32* const hashTable = ms->hashTable; 205 U32 const hlog = cParams->hashLog; 206 /* support stepSize of 0 */ 207 U32 const stepSize = cParams->targetLength + !(cParams->targetLength); 208 const BYTE* const base = ms->window.base; 209 const BYTE* const istart = (const BYTE*)src; 210 const BYTE* ip = istart; 211 const BYTE* anchor = istart; 212 const U32 prefixStartIndex = ms->window.dictLimit; 213 const BYTE* const prefixStart = base + prefixStartIndex; 214 const BYTE* const iend = istart + srcSize; 215 const BYTE* const ilimit = iend - HASH_READ_SIZE; 216 U32 offset_1=rep[0], offset_2=rep[1]; 217 U32 offsetSaved = 0; 218 219 const ZSTD_matchState_t* const dms = ms->dictMatchState; 220 const ZSTD_compressionParameters* const dictCParams = &dms->cParams ; 221 const U32* const dictHashTable = dms->hashTable; 222 const U32 dictStartIndex = dms->window.dictLimit; 223 const BYTE* const dictBase = dms->window.base; 224 const BYTE* const dictStart = dictBase + dictStartIndex; 225 const BYTE* const dictEnd = dms->window.nextSrc; 226 const U32 dictIndexDelta = prefixStartIndex - (U32)(dictEnd - dictBase); 227 const U32 dictAndPrefixLength = (U32)(ip - prefixStart + dictEnd - dictStart); 228 const U32 dictHLog = dictCParams->hashLog; 229 230 /* if a dictionary is still attached, it necessarily means that 231 * it is within window size. So we just check it. */ 232 const U32 maxDistance = 1U << cParams->windowLog; 233 const U32 endIndex = (U32)((size_t)(ip - base) + srcSize); 234 assert(endIndex - prefixStartIndex <= maxDistance); 235 (void)maxDistance; (void)endIndex; /* these variables are not used when assert() is disabled */ 236 237 /* ensure there will be no no underflow 238 * when translating a dict index into a local index */ 239 assert(prefixStartIndex >= (U32)(dictEnd - dictBase)); 240 241 /* init */ 242 ip += (dictAndPrefixLength == 0); 243 /* dictMatchState repCode checks don't currently handle repCode == 0 244 * disabling. */ 245 assert(offset_1 <= dictAndPrefixLength); 246 assert(offset_2 <= dictAndPrefixLength); 247 248 /* Main Search Loop */ 249 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ 250 size_t mLength; 251 size_t const h = ZSTD_hashPtr(ip, hlog, mls); 252 U32 const current = (U32)(ip-base); 253 U32 const matchIndex = hashTable[h]; 254 const BYTE* match = base + matchIndex; 255 const U32 repIndex = current + 1 - offset_1; 256 const BYTE* repMatch = (repIndex < prefixStartIndex) ? 257 dictBase + (repIndex - dictIndexDelta) : 258 base + repIndex; 259 hashTable[h] = current; /* update hash table */ 260 261 if ( ((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow : ensure repIndex isn't overlapping dict + prefix */ 262 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { 263 const BYTE* const repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; 264 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; 265 ip++; 266 ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH); 267 } else if ( (matchIndex <= prefixStartIndex) ) { 268 size_t const dictHash = ZSTD_hashPtr(ip, dictHLog, mls); 269 U32 const dictMatchIndex = dictHashTable[dictHash]; 270 const BYTE* dictMatch = dictBase + dictMatchIndex; 271 if (dictMatchIndex <= dictStartIndex || 272 MEM_read32(dictMatch) != MEM_read32(ip)) { 273 assert(stepSize >= 1); 274 ip += ((ip-anchor) >> kSearchStrength) + stepSize; 275 continue; 276 } else { 277 /* found a dict match */ 278 U32 const offset = (U32)(current-dictMatchIndex-dictIndexDelta); 279 mLength = ZSTD_count_2segments(ip+4, dictMatch+4, iend, dictEnd, prefixStart) + 4; 280 while (((ip>anchor) & (dictMatch>dictStart)) 281 && (ip[-1] == dictMatch[-1])) { 282 ip--; dictMatch--; mLength++; 283 } /* catch up */ 284 offset_2 = offset_1; 285 offset_1 = offset; 286 ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); 287 } 288 } else if (MEM_read32(match) != MEM_read32(ip)) { 289 /* it's not a match, and we're not going to check the dictionary */ 290 assert(stepSize >= 1); 291 ip += ((ip-anchor) >> kSearchStrength) + stepSize; 292 continue; 293 } else { 294 /* found a regular match */ 295 U32 const offset = (U32)(ip-match); 296 mLength = ZSTD_count(ip+4, match+4, iend) + 4; 297 while (((ip>anchor) & (match>prefixStart)) 298 && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ 299 offset_2 = offset_1; 300 offset_1 = offset; 301 ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); 302 } 303 304 /* match found */ 305 ip += mLength; 306 anchor = ip; 307 308 if (ip <= ilimit) { 309 /* Fill Table */ 310 assert(base+current+2 > istart); /* check base overflow */ 311 hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; /* here because current+2 could be > iend-8 */ 312 hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); 313 314 /* check immediate repcode */ 315 while (ip <= ilimit) { 316 U32 const current2 = (U32)(ip-base); 317 U32 const repIndex2 = current2 - offset_2; 318 const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? 319 dictBase - dictIndexDelta + repIndex2 : 320 base + repIndex2; 321 if ( ((U32)((prefixStartIndex-1) - (U32)repIndex2) >= 3 /* intentional overflow */) 322 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { 323 const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; 324 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; 325 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ 326 ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH); 327 hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; 328 ip += repLength2; 329 anchor = ip; 330 continue; 331 } 332 break; 333 } 334 } 335 } 336 337 /* save reps for next block */ 338 rep[0] = offset_1 ? offset_1 : offsetSaved; 339 rep[1] = offset_2 ? offset_2 : offsetSaved; 340 341 /* Return the last literals size */ 342 return (size_t)(iend - anchor); 343 } 344 345 size_t ZSTD_compressBlock_fast_dictMatchState( 346 ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 347 void const* src, size_t srcSize) 348 { 349 ZSTD_compressionParameters const* cParams = &ms->cParams; 350 U32 const mls = cParams->minMatch; 351 assert(ms->dictMatchState != NULL); 352 switch(mls) 353 { 354 default: /* includes case 3 */ 355 case 4 : 356 return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 4); 357 case 5 : 358 return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 5); 359 case 6 : 360 return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 6); 361 case 7 : 362 return ZSTD_compressBlock_fast_dictMatchState_generic(ms, seqStore, rep, src, srcSize, 7); 363 } 364 } 365 366 367 static size_t ZSTD_compressBlock_fast_extDict_generic( 368 ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 369 void const* src, size_t srcSize, U32 const mls) 370 { 371 const ZSTD_compressionParameters* const cParams = &ms->cParams; 372 U32* const hashTable = ms->hashTable; 373 U32 const hlog = cParams->hashLog; 374 /* support stepSize of 0 */ 375 U32 const stepSize = cParams->targetLength + !(cParams->targetLength); 376 const BYTE* const base = ms->window.base; 377 const BYTE* const dictBase = ms->window.dictBase; 378 const BYTE* const istart = (const BYTE*)src; 379 const BYTE* ip = istart; 380 const BYTE* anchor = istart; 381 const U32 endIndex = (U32)((size_t)(istart - base) + srcSize); 382 const U32 maxDistance = 1U << cParams->windowLog; 383 const U32 validLow = ms->window.lowLimit; 384 const U32 lowLimit = (endIndex - validLow > maxDistance) ? endIndex - maxDistance : validLow; 385 const U32 dictStartIndex = lowLimit; 386 const BYTE* const dictStart = dictBase + dictStartIndex; 387 const U32 dictLimit = ms->window.dictLimit; 388 const U32 prefixStartIndex = dictLimit < lowLimit ? lowLimit : dictLimit; 389 const BYTE* const prefixStart = base + prefixStartIndex; 390 const BYTE* const dictEnd = dictBase + prefixStartIndex; 391 const BYTE* const iend = istart + srcSize; 392 const BYTE* const ilimit = iend - 8; 393 U32 offset_1=rep[0], offset_2=rep[1]; 394 395 /* switch to "regular" variant if extDict is invalidated due to maxDistance */ 396 if (prefixStartIndex == dictStartIndex) 397 return ZSTD_compressBlock_fast_generic(ms, seqStore, rep, src, srcSize, mls); 398 399 /* Search Loop */ 400 while (ip < ilimit) { /* < instead of <=, because (ip+1) */ 401 const size_t h = ZSTD_hashPtr(ip, hlog, mls); 402 const U32 matchIndex = hashTable[h]; 403 const BYTE* const matchBase = matchIndex < prefixStartIndex ? dictBase : base; 404 const BYTE* match = matchBase + matchIndex; 405 const U32 current = (U32)(ip-base); 406 const U32 repIndex = current + 1 - offset_1; 407 const BYTE* const repBase = repIndex < prefixStartIndex ? dictBase : base; 408 const BYTE* const repMatch = repBase + repIndex; 409 size_t mLength; 410 hashTable[h] = current; /* update hash table */ 411 assert(offset_1 <= current +1); /* check repIndex */ 412 413 if ( (((U32)((prefixStartIndex-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > dictStartIndex)) 414 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { 415 const BYTE* repMatchEnd = repIndex < prefixStartIndex ? dictEnd : iend; 416 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, prefixStart) + 4; 417 ip++; 418 ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, 0, mLength-MINMATCH); 419 } else { 420 if ( (matchIndex < dictStartIndex) || 421 (MEM_read32(match) != MEM_read32(ip)) ) { 422 assert(stepSize >= 1); 423 ip += ((ip-anchor) >> kSearchStrength) + stepSize; 424 continue; 425 } 426 { const BYTE* matchEnd = matchIndex < prefixStartIndex ? dictEnd : iend; 427 const BYTE* lowMatchPtr = matchIndex < prefixStartIndex ? dictStart : prefixStart; 428 U32 offset; 429 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, prefixStart) + 4; 430 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */ 431 offset = current - matchIndex; 432 offset_2 = offset_1; 433 offset_1 = offset; 434 ZSTD_storeSeq(seqStore, (size_t)(ip-anchor), anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH); 435 } } 436 437 /* found a match : store it */ 438 ip += mLength; 439 anchor = ip; 440 441 if (ip <= ilimit) { 442 /* Fill Table */ 443 hashTable[ZSTD_hashPtr(base+current+2, hlog, mls)] = current+2; 444 hashTable[ZSTD_hashPtr(ip-2, hlog, mls)] = (U32)(ip-2-base); 445 /* check immediate repcode */ 446 while (ip <= ilimit) { 447 U32 const current2 = (U32)(ip-base); 448 U32 const repIndex2 = current2 - offset_2; 449 const BYTE* repMatch2 = repIndex2 < prefixStartIndex ? dictBase + repIndex2 : base + repIndex2; 450 if ( (((U32)((prefixStartIndex-1) - repIndex2) >= 3) & (repIndex2 > dictStartIndex)) /* intentional overflow */ 451 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { 452 const BYTE* const repEnd2 = repIndex2 < prefixStartIndex ? dictEnd : iend; 453 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, prefixStart) + 4; 454 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */ 455 ZSTD_storeSeq(seqStore, 0, anchor, 0, repLength2-MINMATCH); 456 hashTable[ZSTD_hashPtr(ip, hlog, mls)] = current2; 457 ip += repLength2; 458 anchor = ip; 459 continue; 460 } 461 break; 462 } } } 463 464 /* save reps for next block */ 465 rep[0] = offset_1; 466 rep[1] = offset_2; 467 468 /* Return the last literals size */ 469 return (size_t)(iend - anchor); 470 } 471 472 473 size_t ZSTD_compressBlock_fast_extDict( 474 ZSTD_matchState_t* ms, seqStore_t* seqStore, U32 rep[ZSTD_REP_NUM], 475 void const* src, size_t srcSize) 476 { 477 ZSTD_compressionParameters const* cParams = &ms->cParams; 478 U32 const mls = cParams->minMatch; 479 switch(mls) 480 { 481 default: /* includes case 3 */ 482 case 4 : 483 return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 4); 484 case 5 : 485 return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 5); 486 case 6 : 487 return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 6); 488 case 7 : 489 return ZSTD_compressBlock_fast_extDict_generic(ms, seqStore, rep, src, srcSize, 7); 490 } 491 } 492