1*0c16b537SWarner Losh /* 2*0c16b537SWarner Losh * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. 3*0c16b537SWarner Losh * All rights reserved. 4*0c16b537SWarner Losh * 5*0c16b537SWarner Losh * This source code is licensed under both the BSD-style license (found in the 6*0c16b537SWarner Losh * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*0c16b537SWarner Losh * in the COPYING file in the root directory of this source tree). 8*0c16b537SWarner Losh */ 9*0c16b537SWarner Losh 10*0c16b537SWarner Losh #include "zstd_ldm.h" 11*0c16b537SWarner Losh 12*0c16b537SWarner Losh #include "zstd_fast.h" /* ZSTD_fillHashTable() */ 13*0c16b537SWarner Losh #include "zstd_double_fast.h" /* ZSTD_fillDoubleHashTable() */ 14*0c16b537SWarner Losh 15*0c16b537SWarner Losh #define LDM_BUCKET_SIZE_LOG 3 16*0c16b537SWarner Losh #define LDM_MIN_MATCH_LENGTH 64 17*0c16b537SWarner Losh #define LDM_HASH_RLOG 7 18*0c16b537SWarner Losh #define LDM_HASH_CHAR_OFFSET 10 19*0c16b537SWarner Losh 20*0c16b537SWarner Losh size_t ZSTD_ldm_initializeParameters(ldmParams_t* params, U32 enableLdm) 21*0c16b537SWarner Losh { 22*0c16b537SWarner Losh ZSTD_STATIC_ASSERT(LDM_BUCKET_SIZE_LOG <= ZSTD_LDM_BUCKETSIZELOG_MAX); 23*0c16b537SWarner Losh params->enableLdm = enableLdm>0; 24*0c16b537SWarner Losh params->hashLog = 0; 25*0c16b537SWarner Losh params->bucketSizeLog = LDM_BUCKET_SIZE_LOG; 26*0c16b537SWarner Losh params->minMatchLength = LDM_MIN_MATCH_LENGTH; 27*0c16b537SWarner Losh params->hashEveryLog = ZSTD_LDM_HASHEVERYLOG_NOTSET; 28*0c16b537SWarner Losh return 0; 29*0c16b537SWarner Losh } 30*0c16b537SWarner Losh 31*0c16b537SWarner Losh void ZSTD_ldm_adjustParameters(ldmParams_t* params, U32 windowLog) 32*0c16b537SWarner Losh { 33*0c16b537SWarner Losh if (params->hashLog == 0) { 34*0c16b537SWarner Losh params->hashLog = MAX(ZSTD_HASHLOG_MIN, windowLog - LDM_HASH_RLOG); 35*0c16b537SWarner Losh assert(params->hashLog <= ZSTD_HASHLOG_MAX); 36*0c16b537SWarner Losh } 37*0c16b537SWarner Losh if (params->hashEveryLog == ZSTD_LDM_HASHEVERYLOG_NOTSET) { 38*0c16b537SWarner Losh params->hashEveryLog = 39*0c16b537SWarner Losh windowLog < params->hashLog ? 0 : windowLog - params->hashLog; 40*0c16b537SWarner Losh } 41*0c16b537SWarner Losh params->bucketSizeLog = MIN(params->bucketSizeLog, params->hashLog); 42*0c16b537SWarner Losh } 43*0c16b537SWarner Losh 44*0c16b537SWarner Losh size_t ZSTD_ldm_getTableSize(U32 hashLog, U32 bucketSizeLog) { 45*0c16b537SWarner Losh size_t const ldmHSize = ((size_t)1) << hashLog; 46*0c16b537SWarner Losh size_t const ldmBucketSizeLog = MIN(bucketSizeLog, hashLog); 47*0c16b537SWarner Losh size_t const ldmBucketSize = 48*0c16b537SWarner Losh ((size_t)1) << (hashLog - ldmBucketSizeLog); 49*0c16b537SWarner Losh return ldmBucketSize + (ldmHSize * (sizeof(ldmEntry_t))); 50*0c16b537SWarner Losh } 51*0c16b537SWarner Losh 52*0c16b537SWarner Losh /** ZSTD_ldm_getSmallHash() : 53*0c16b537SWarner Losh * numBits should be <= 32 54*0c16b537SWarner Losh * If numBits==0, returns 0. 55*0c16b537SWarner Losh * @return : the most significant numBits of value. */ 56*0c16b537SWarner Losh static U32 ZSTD_ldm_getSmallHash(U64 value, U32 numBits) 57*0c16b537SWarner Losh { 58*0c16b537SWarner Losh assert(numBits <= 32); 59*0c16b537SWarner Losh return numBits == 0 ? 0 : (U32)(value >> (64 - numBits)); 60*0c16b537SWarner Losh } 61*0c16b537SWarner Losh 62*0c16b537SWarner Losh /** ZSTD_ldm_getChecksum() : 63*0c16b537SWarner Losh * numBitsToDiscard should be <= 32 64*0c16b537SWarner Losh * @return : the next most significant 32 bits after numBitsToDiscard */ 65*0c16b537SWarner Losh static U32 ZSTD_ldm_getChecksum(U64 hash, U32 numBitsToDiscard) 66*0c16b537SWarner Losh { 67*0c16b537SWarner Losh assert(numBitsToDiscard <= 32); 68*0c16b537SWarner Losh return (hash >> (64 - 32 - numBitsToDiscard)) & 0xFFFFFFFF; 69*0c16b537SWarner Losh } 70*0c16b537SWarner Losh 71*0c16b537SWarner Losh /** ZSTD_ldm_getTag() ; 72*0c16b537SWarner Losh * Given the hash, returns the most significant numTagBits bits 73*0c16b537SWarner Losh * after (32 + hbits) bits. 74*0c16b537SWarner Losh * 75*0c16b537SWarner Losh * If there are not enough bits remaining, return the last 76*0c16b537SWarner Losh * numTagBits bits. */ 77*0c16b537SWarner Losh static U32 ZSTD_ldm_getTag(U64 hash, U32 hbits, U32 numTagBits) 78*0c16b537SWarner Losh { 79*0c16b537SWarner Losh assert(numTagBits < 32 && hbits <= 32); 80*0c16b537SWarner Losh if (32 - hbits < numTagBits) { 81*0c16b537SWarner Losh return hash & (((U32)1 << numTagBits) - 1); 82*0c16b537SWarner Losh } else { 83*0c16b537SWarner Losh return (hash >> (32 - hbits - numTagBits)) & (((U32)1 << numTagBits) - 1); 84*0c16b537SWarner Losh } 85*0c16b537SWarner Losh } 86*0c16b537SWarner Losh 87*0c16b537SWarner Losh /** ZSTD_ldm_getBucket() : 88*0c16b537SWarner Losh * Returns a pointer to the start of the bucket associated with hash. */ 89*0c16b537SWarner Losh static ldmEntry_t* ZSTD_ldm_getBucket( 90*0c16b537SWarner Losh ldmState_t* ldmState, size_t hash, ldmParams_t const ldmParams) 91*0c16b537SWarner Losh { 92*0c16b537SWarner Losh return ldmState->hashTable + (hash << ldmParams.bucketSizeLog); 93*0c16b537SWarner Losh } 94*0c16b537SWarner Losh 95*0c16b537SWarner Losh /** ZSTD_ldm_insertEntry() : 96*0c16b537SWarner Losh * Insert the entry with corresponding hash into the hash table */ 97*0c16b537SWarner Losh static void ZSTD_ldm_insertEntry(ldmState_t* ldmState, 98*0c16b537SWarner Losh size_t const hash, const ldmEntry_t entry, 99*0c16b537SWarner Losh ldmParams_t const ldmParams) 100*0c16b537SWarner Losh { 101*0c16b537SWarner Losh BYTE* const bucketOffsets = ldmState->bucketOffsets; 102*0c16b537SWarner Losh *(ZSTD_ldm_getBucket(ldmState, hash, ldmParams) + bucketOffsets[hash]) = entry; 103*0c16b537SWarner Losh bucketOffsets[hash]++; 104*0c16b537SWarner Losh bucketOffsets[hash] &= ((U32)1 << ldmParams.bucketSizeLog) - 1; 105*0c16b537SWarner Losh } 106*0c16b537SWarner Losh 107*0c16b537SWarner Losh /** ZSTD_ldm_makeEntryAndInsertByTag() : 108*0c16b537SWarner Losh * 109*0c16b537SWarner Losh * Gets the small hash, checksum, and tag from the rollingHash. 110*0c16b537SWarner Losh * 111*0c16b537SWarner Losh * If the tag matches (1 << ldmParams.hashEveryLog)-1, then 112*0c16b537SWarner Losh * creates an ldmEntry from the offset, and inserts it into the hash table. 113*0c16b537SWarner Losh * 114*0c16b537SWarner Losh * hBits is the length of the small hash, which is the most significant hBits 115*0c16b537SWarner Losh * of rollingHash. The checksum is the next 32 most significant bits, followed 116*0c16b537SWarner Losh * by ldmParams.hashEveryLog bits that make up the tag. */ 117*0c16b537SWarner Losh static void ZSTD_ldm_makeEntryAndInsertByTag(ldmState_t* ldmState, 118*0c16b537SWarner Losh U64 const rollingHash, 119*0c16b537SWarner Losh U32 const hBits, 120*0c16b537SWarner Losh U32 const offset, 121*0c16b537SWarner Losh ldmParams_t const ldmParams) 122*0c16b537SWarner Losh { 123*0c16b537SWarner Losh U32 const tag = ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog); 124*0c16b537SWarner Losh U32 const tagMask = ((U32)1 << ldmParams.hashEveryLog) - 1; 125*0c16b537SWarner Losh if (tag == tagMask) { 126*0c16b537SWarner Losh U32 const hash = ZSTD_ldm_getSmallHash(rollingHash, hBits); 127*0c16b537SWarner Losh U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); 128*0c16b537SWarner Losh ldmEntry_t entry; 129*0c16b537SWarner Losh entry.offset = offset; 130*0c16b537SWarner Losh entry.checksum = checksum; 131*0c16b537SWarner Losh ZSTD_ldm_insertEntry(ldmState, hash, entry, ldmParams); 132*0c16b537SWarner Losh } 133*0c16b537SWarner Losh } 134*0c16b537SWarner Losh 135*0c16b537SWarner Losh /** ZSTD_ldm_getRollingHash() : 136*0c16b537SWarner Losh * Get a 64-bit hash using the first len bytes from buf. 137*0c16b537SWarner Losh * 138*0c16b537SWarner Losh * Giving bytes s = s_1, s_2, ... s_k, the hash is defined to be 139*0c16b537SWarner Losh * H(s) = s_1*(a^(k-1)) + s_2*(a^(k-2)) + ... + s_k*(a^0) 140*0c16b537SWarner Losh * 141*0c16b537SWarner Losh * where the constant a is defined to be prime8bytes. 142*0c16b537SWarner Losh * 143*0c16b537SWarner Losh * The implementation adds an offset to each byte, so 144*0c16b537SWarner Losh * H(s) = (s_1 + HASH_CHAR_OFFSET)*(a^(k-1)) + ... */ 145*0c16b537SWarner Losh static U64 ZSTD_ldm_getRollingHash(const BYTE* buf, U32 len) 146*0c16b537SWarner Losh { 147*0c16b537SWarner Losh U64 ret = 0; 148*0c16b537SWarner Losh U32 i; 149*0c16b537SWarner Losh for (i = 0; i < len; i++) { 150*0c16b537SWarner Losh ret *= prime8bytes; 151*0c16b537SWarner Losh ret += buf[i] + LDM_HASH_CHAR_OFFSET; 152*0c16b537SWarner Losh } 153*0c16b537SWarner Losh return ret; 154*0c16b537SWarner Losh } 155*0c16b537SWarner Losh 156*0c16b537SWarner Losh /** ZSTD_ldm_ipow() : 157*0c16b537SWarner Losh * Return base^exp. */ 158*0c16b537SWarner Losh static U64 ZSTD_ldm_ipow(U64 base, U64 exp) 159*0c16b537SWarner Losh { 160*0c16b537SWarner Losh U64 ret = 1; 161*0c16b537SWarner Losh while (exp) { 162*0c16b537SWarner Losh if (exp & 1) { ret *= base; } 163*0c16b537SWarner Losh exp >>= 1; 164*0c16b537SWarner Losh base *= base; 165*0c16b537SWarner Losh } 166*0c16b537SWarner Losh return ret; 167*0c16b537SWarner Losh } 168*0c16b537SWarner Losh 169*0c16b537SWarner Losh U64 ZSTD_ldm_getHashPower(U32 minMatchLength) { 170*0c16b537SWarner Losh assert(minMatchLength >= ZSTD_LDM_MINMATCH_MIN); 171*0c16b537SWarner Losh return ZSTD_ldm_ipow(prime8bytes, minMatchLength - 1); 172*0c16b537SWarner Losh } 173*0c16b537SWarner Losh 174*0c16b537SWarner Losh /** ZSTD_ldm_updateHash() : 175*0c16b537SWarner Losh * Updates hash by removing toRemove and adding toAdd. */ 176*0c16b537SWarner Losh static U64 ZSTD_ldm_updateHash(U64 hash, BYTE toRemove, BYTE toAdd, U64 hashPower) 177*0c16b537SWarner Losh { 178*0c16b537SWarner Losh hash -= ((toRemove + LDM_HASH_CHAR_OFFSET) * hashPower); 179*0c16b537SWarner Losh hash *= prime8bytes; 180*0c16b537SWarner Losh hash += toAdd + LDM_HASH_CHAR_OFFSET; 181*0c16b537SWarner Losh return hash; 182*0c16b537SWarner Losh } 183*0c16b537SWarner Losh 184*0c16b537SWarner Losh /** ZSTD_ldm_countBackwardsMatch() : 185*0c16b537SWarner Losh * Returns the number of bytes that match backwards before pIn and pMatch. 186*0c16b537SWarner Losh * 187*0c16b537SWarner Losh * We count only bytes where pMatch >= pBase and pIn >= pAnchor. */ 188*0c16b537SWarner Losh static size_t ZSTD_ldm_countBackwardsMatch( 189*0c16b537SWarner Losh const BYTE* pIn, const BYTE* pAnchor, 190*0c16b537SWarner Losh const BYTE* pMatch, const BYTE* pBase) 191*0c16b537SWarner Losh { 192*0c16b537SWarner Losh size_t matchLength = 0; 193*0c16b537SWarner Losh while (pIn > pAnchor && pMatch > pBase && pIn[-1] == pMatch[-1]) { 194*0c16b537SWarner Losh pIn--; 195*0c16b537SWarner Losh pMatch--; 196*0c16b537SWarner Losh matchLength++; 197*0c16b537SWarner Losh } 198*0c16b537SWarner Losh return matchLength; 199*0c16b537SWarner Losh } 200*0c16b537SWarner Losh 201*0c16b537SWarner Losh /** ZSTD_ldm_fillFastTables() : 202*0c16b537SWarner Losh * 203*0c16b537SWarner Losh * Fills the relevant tables for the ZSTD_fast and ZSTD_dfast strategies. 204*0c16b537SWarner Losh * This is similar to ZSTD_loadDictionaryContent. 205*0c16b537SWarner Losh * 206*0c16b537SWarner Losh * The tables for the other strategies are filled within their 207*0c16b537SWarner Losh * block compressors. */ 208*0c16b537SWarner Losh static size_t ZSTD_ldm_fillFastTables(ZSTD_CCtx* zc, const void* end) 209*0c16b537SWarner Losh { 210*0c16b537SWarner Losh const BYTE* const iend = (const BYTE*)end; 211*0c16b537SWarner Losh const U32 mls = zc->appliedParams.cParams.searchLength; 212*0c16b537SWarner Losh 213*0c16b537SWarner Losh switch(zc->appliedParams.cParams.strategy) 214*0c16b537SWarner Losh { 215*0c16b537SWarner Losh case ZSTD_fast: 216*0c16b537SWarner Losh ZSTD_fillHashTable(zc, iend, mls); 217*0c16b537SWarner Losh zc->nextToUpdate = (U32)(iend - zc->base); 218*0c16b537SWarner Losh break; 219*0c16b537SWarner Losh 220*0c16b537SWarner Losh case ZSTD_dfast: 221*0c16b537SWarner Losh ZSTD_fillDoubleHashTable(zc, iend, mls); 222*0c16b537SWarner Losh zc->nextToUpdate = (U32)(iend - zc->base); 223*0c16b537SWarner Losh break; 224*0c16b537SWarner Losh 225*0c16b537SWarner Losh case ZSTD_greedy: 226*0c16b537SWarner Losh case ZSTD_lazy: 227*0c16b537SWarner Losh case ZSTD_lazy2: 228*0c16b537SWarner Losh case ZSTD_btlazy2: 229*0c16b537SWarner Losh case ZSTD_btopt: 230*0c16b537SWarner Losh case ZSTD_btultra: 231*0c16b537SWarner Losh break; 232*0c16b537SWarner Losh default: 233*0c16b537SWarner Losh assert(0); /* not possible : not a valid strategy id */ 234*0c16b537SWarner Losh } 235*0c16b537SWarner Losh 236*0c16b537SWarner Losh return 0; 237*0c16b537SWarner Losh } 238*0c16b537SWarner Losh 239*0c16b537SWarner Losh /** ZSTD_ldm_fillLdmHashTable() : 240*0c16b537SWarner Losh * 241*0c16b537SWarner Losh * Fills hashTable from (lastHashed + 1) to iend (non-inclusive). 242*0c16b537SWarner Losh * lastHash is the rolling hash that corresponds to lastHashed. 243*0c16b537SWarner Losh * 244*0c16b537SWarner Losh * Returns the rolling hash corresponding to position iend-1. */ 245*0c16b537SWarner Losh static U64 ZSTD_ldm_fillLdmHashTable(ldmState_t* state, 246*0c16b537SWarner Losh U64 lastHash, const BYTE* lastHashed, 247*0c16b537SWarner Losh const BYTE* iend, const BYTE* base, 248*0c16b537SWarner Losh U32 hBits, ldmParams_t const ldmParams) 249*0c16b537SWarner Losh { 250*0c16b537SWarner Losh U64 rollingHash = lastHash; 251*0c16b537SWarner Losh const BYTE* cur = lastHashed + 1; 252*0c16b537SWarner Losh 253*0c16b537SWarner Losh while (cur < iend) { 254*0c16b537SWarner Losh rollingHash = ZSTD_ldm_updateHash(rollingHash, cur[-1], 255*0c16b537SWarner Losh cur[ldmParams.minMatchLength-1], 256*0c16b537SWarner Losh state->hashPower); 257*0c16b537SWarner Losh ZSTD_ldm_makeEntryAndInsertByTag(state, 258*0c16b537SWarner Losh rollingHash, hBits, 259*0c16b537SWarner Losh (U32)(cur - base), ldmParams); 260*0c16b537SWarner Losh ++cur; 261*0c16b537SWarner Losh } 262*0c16b537SWarner Losh return rollingHash; 263*0c16b537SWarner Losh } 264*0c16b537SWarner Losh 265*0c16b537SWarner Losh 266*0c16b537SWarner Losh /** ZSTD_ldm_limitTableUpdate() : 267*0c16b537SWarner Losh * 268*0c16b537SWarner Losh * Sets cctx->nextToUpdate to a position corresponding closer to anchor 269*0c16b537SWarner Losh * if it is far way 270*0c16b537SWarner Losh * (after a long match, only update tables a limited amount). */ 271*0c16b537SWarner Losh static void ZSTD_ldm_limitTableUpdate(ZSTD_CCtx* cctx, const BYTE* anchor) 272*0c16b537SWarner Losh { 273*0c16b537SWarner Losh U32 const current = (U32)(anchor - cctx->base); 274*0c16b537SWarner Losh if (current > cctx->nextToUpdate + 1024) { 275*0c16b537SWarner Losh cctx->nextToUpdate = 276*0c16b537SWarner Losh current - MIN(512, current - cctx->nextToUpdate - 1024); 277*0c16b537SWarner Losh } 278*0c16b537SWarner Losh } 279*0c16b537SWarner Losh 280*0c16b537SWarner Losh typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize); 281*0c16b537SWarner Losh /* defined in zstd_compress.c */ 282*0c16b537SWarner Losh ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict); 283*0c16b537SWarner Losh 284*0c16b537SWarner Losh FORCE_INLINE_TEMPLATE 285*0c16b537SWarner Losh size_t ZSTD_compressBlock_ldm_generic(ZSTD_CCtx* cctx, 286*0c16b537SWarner Losh const void* src, size_t srcSize) 287*0c16b537SWarner Losh { 288*0c16b537SWarner Losh ldmState_t* const ldmState = &(cctx->ldmState); 289*0c16b537SWarner Losh const ldmParams_t ldmParams = cctx->appliedParams.ldmParams; 290*0c16b537SWarner Losh const U64 hashPower = ldmState->hashPower; 291*0c16b537SWarner Losh const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog; 292*0c16b537SWarner Losh const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog); 293*0c16b537SWarner Losh const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1; 294*0c16b537SWarner Losh seqStore_t* const seqStorePtr = &(cctx->seqStore); 295*0c16b537SWarner Losh const BYTE* const base = cctx->base; 296*0c16b537SWarner Losh const BYTE* const istart = (const BYTE*)src; 297*0c16b537SWarner Losh const BYTE* ip = istart; 298*0c16b537SWarner Losh const BYTE* anchor = istart; 299*0c16b537SWarner Losh const U32 lowestIndex = cctx->dictLimit; 300*0c16b537SWarner Losh const BYTE* const lowest = base + lowestIndex; 301*0c16b537SWarner Losh const BYTE* const iend = istart + srcSize; 302*0c16b537SWarner Losh const BYTE* const ilimit = iend - MAX(ldmParams.minMatchLength, HASH_READ_SIZE); 303*0c16b537SWarner Losh 304*0c16b537SWarner Losh const ZSTD_blockCompressor blockCompressor = 305*0c16b537SWarner Losh ZSTD_selectBlockCompressor(cctx->appliedParams.cParams.strategy, 0); 306*0c16b537SWarner Losh U32* const repToConfirm = seqStorePtr->repToConfirm; 307*0c16b537SWarner Losh U32 savedRep[ZSTD_REP_NUM]; 308*0c16b537SWarner Losh U64 rollingHash = 0; 309*0c16b537SWarner Losh const BYTE* lastHashed = NULL; 310*0c16b537SWarner Losh size_t i, lastLiterals; 311*0c16b537SWarner Losh 312*0c16b537SWarner Losh /* Save seqStorePtr->rep and copy repToConfirm */ 313*0c16b537SWarner Losh for (i = 0; i < ZSTD_REP_NUM; i++) 314*0c16b537SWarner Losh savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i]; 315*0c16b537SWarner Losh 316*0c16b537SWarner Losh /* Main Search Loop */ 317*0c16b537SWarner Losh while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */ 318*0c16b537SWarner Losh size_t mLength; 319*0c16b537SWarner Losh U32 const current = (U32)(ip - base); 320*0c16b537SWarner Losh size_t forwardMatchLength = 0, backwardMatchLength = 0; 321*0c16b537SWarner Losh ldmEntry_t* bestEntry = NULL; 322*0c16b537SWarner Losh if (ip != istart) { 323*0c16b537SWarner Losh rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0], 324*0c16b537SWarner Losh lastHashed[ldmParams.minMatchLength], 325*0c16b537SWarner Losh hashPower); 326*0c16b537SWarner Losh } else { 327*0c16b537SWarner Losh rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength); 328*0c16b537SWarner Losh } 329*0c16b537SWarner Losh lastHashed = ip; 330*0c16b537SWarner Losh 331*0c16b537SWarner Losh /* Do not insert and do not look for a match */ 332*0c16b537SWarner Losh if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) != 333*0c16b537SWarner Losh ldmTagMask) { 334*0c16b537SWarner Losh ip++; 335*0c16b537SWarner Losh continue; 336*0c16b537SWarner Losh } 337*0c16b537SWarner Losh 338*0c16b537SWarner Losh /* Get the best entry and compute the match lengths */ 339*0c16b537SWarner Losh { 340*0c16b537SWarner Losh ldmEntry_t* const bucket = 341*0c16b537SWarner Losh ZSTD_ldm_getBucket(ldmState, 342*0c16b537SWarner Losh ZSTD_ldm_getSmallHash(rollingHash, hBits), 343*0c16b537SWarner Losh ldmParams); 344*0c16b537SWarner Losh ldmEntry_t* cur; 345*0c16b537SWarner Losh size_t bestMatchLength = 0; 346*0c16b537SWarner Losh U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); 347*0c16b537SWarner Losh 348*0c16b537SWarner Losh for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { 349*0c16b537SWarner Losh const BYTE* const pMatch = cur->offset + base; 350*0c16b537SWarner Losh size_t curForwardMatchLength, curBackwardMatchLength, 351*0c16b537SWarner Losh curTotalMatchLength; 352*0c16b537SWarner Losh if (cur->checksum != checksum || cur->offset <= lowestIndex) { 353*0c16b537SWarner Losh continue; 354*0c16b537SWarner Losh } 355*0c16b537SWarner Losh 356*0c16b537SWarner Losh curForwardMatchLength = ZSTD_count(ip, pMatch, iend); 357*0c16b537SWarner Losh if (curForwardMatchLength < ldmParams.minMatchLength) { 358*0c16b537SWarner Losh continue; 359*0c16b537SWarner Losh } 360*0c16b537SWarner Losh curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch( 361*0c16b537SWarner Losh ip, anchor, pMatch, lowest); 362*0c16b537SWarner Losh curTotalMatchLength = curForwardMatchLength + 363*0c16b537SWarner Losh curBackwardMatchLength; 364*0c16b537SWarner Losh 365*0c16b537SWarner Losh if (curTotalMatchLength > bestMatchLength) { 366*0c16b537SWarner Losh bestMatchLength = curTotalMatchLength; 367*0c16b537SWarner Losh forwardMatchLength = curForwardMatchLength; 368*0c16b537SWarner Losh backwardMatchLength = curBackwardMatchLength; 369*0c16b537SWarner Losh bestEntry = cur; 370*0c16b537SWarner Losh } 371*0c16b537SWarner Losh } 372*0c16b537SWarner Losh } 373*0c16b537SWarner Losh 374*0c16b537SWarner Losh /* No match found -- continue searching */ 375*0c16b537SWarner Losh if (bestEntry == NULL) { 376*0c16b537SWarner Losh ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, 377*0c16b537SWarner Losh hBits, current, 378*0c16b537SWarner Losh ldmParams); 379*0c16b537SWarner Losh ip++; 380*0c16b537SWarner Losh continue; 381*0c16b537SWarner Losh } 382*0c16b537SWarner Losh 383*0c16b537SWarner Losh /* Match found */ 384*0c16b537SWarner Losh mLength = forwardMatchLength + backwardMatchLength; 385*0c16b537SWarner Losh ip -= backwardMatchLength; 386*0c16b537SWarner Losh 387*0c16b537SWarner Losh /* Call the block compressor on the remaining literals */ 388*0c16b537SWarner Losh { 389*0c16b537SWarner Losh U32 const matchIndex = bestEntry->offset; 390*0c16b537SWarner Losh const BYTE* const match = base + matchIndex - backwardMatchLength; 391*0c16b537SWarner Losh U32 const offset = (U32)(ip - match); 392*0c16b537SWarner Losh 393*0c16b537SWarner Losh /* Overwrite rep codes */ 394*0c16b537SWarner Losh for (i = 0; i < ZSTD_REP_NUM; i++) 395*0c16b537SWarner Losh seqStorePtr->rep[i] = repToConfirm[i]; 396*0c16b537SWarner Losh 397*0c16b537SWarner Losh /* Fill tables for block compressor */ 398*0c16b537SWarner Losh ZSTD_ldm_limitTableUpdate(cctx, anchor); 399*0c16b537SWarner Losh ZSTD_ldm_fillFastTables(cctx, anchor); 400*0c16b537SWarner Losh 401*0c16b537SWarner Losh /* Call block compressor and get remaining literals */ 402*0c16b537SWarner Losh lastLiterals = blockCompressor(cctx, anchor, ip - anchor); 403*0c16b537SWarner Losh cctx->nextToUpdate = (U32)(ip - base); 404*0c16b537SWarner Losh 405*0c16b537SWarner Losh /* Update repToConfirm with the new offset */ 406*0c16b537SWarner Losh for (i = ZSTD_REP_NUM - 1; i > 0; i--) 407*0c16b537SWarner Losh repToConfirm[i] = repToConfirm[i-1]; 408*0c16b537SWarner Losh repToConfirm[0] = offset; 409*0c16b537SWarner Losh 410*0c16b537SWarner Losh /* Store the sequence with the leftover literals */ 411*0c16b537SWarner Losh ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals, 412*0c16b537SWarner Losh offset + ZSTD_REP_MOVE, mLength - MINMATCH); 413*0c16b537SWarner Losh } 414*0c16b537SWarner Losh 415*0c16b537SWarner Losh /* Insert the current entry into the hash table */ 416*0c16b537SWarner Losh ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, 417*0c16b537SWarner Losh (U32)(lastHashed - base), 418*0c16b537SWarner Losh ldmParams); 419*0c16b537SWarner Losh 420*0c16b537SWarner Losh assert(ip + backwardMatchLength == lastHashed); 421*0c16b537SWarner Losh 422*0c16b537SWarner Losh /* Fill the hash table from lastHashed+1 to ip+mLength*/ 423*0c16b537SWarner Losh /* Heuristic: don't need to fill the entire table at end of block */ 424*0c16b537SWarner Losh if (ip + mLength < ilimit) { 425*0c16b537SWarner Losh rollingHash = ZSTD_ldm_fillLdmHashTable( 426*0c16b537SWarner Losh ldmState, rollingHash, lastHashed, 427*0c16b537SWarner Losh ip + mLength, base, hBits, ldmParams); 428*0c16b537SWarner Losh lastHashed = ip + mLength - 1; 429*0c16b537SWarner Losh } 430*0c16b537SWarner Losh ip += mLength; 431*0c16b537SWarner Losh anchor = ip; 432*0c16b537SWarner Losh /* Check immediate repcode */ 433*0c16b537SWarner Losh while ( (ip < ilimit) 434*0c16b537SWarner Losh && ( (repToConfirm[1] > 0) && (repToConfirm[1] <= (U32)(ip-lowest)) 435*0c16b537SWarner Losh && (MEM_read32(ip) == MEM_read32(ip - repToConfirm[1])) )) { 436*0c16b537SWarner Losh 437*0c16b537SWarner Losh size_t const rLength = ZSTD_count(ip+4, ip+4-repToConfirm[1], 438*0c16b537SWarner Losh iend) + 4; 439*0c16b537SWarner Losh /* Swap repToConfirm[1] <=> repToConfirm[0] */ 440*0c16b537SWarner Losh { 441*0c16b537SWarner Losh U32 const tmpOff = repToConfirm[1]; 442*0c16b537SWarner Losh repToConfirm[1] = repToConfirm[0]; 443*0c16b537SWarner Losh repToConfirm[0] = tmpOff; 444*0c16b537SWarner Losh } 445*0c16b537SWarner Losh 446*0c16b537SWarner Losh ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH); 447*0c16b537SWarner Losh 448*0c16b537SWarner Losh /* Fill the hash table from lastHashed+1 to ip+rLength*/ 449*0c16b537SWarner Losh if (ip + rLength < ilimit) { 450*0c16b537SWarner Losh rollingHash = ZSTD_ldm_fillLdmHashTable( 451*0c16b537SWarner Losh ldmState, rollingHash, lastHashed, 452*0c16b537SWarner Losh ip + rLength, base, hBits, ldmParams); 453*0c16b537SWarner Losh lastHashed = ip + rLength - 1; 454*0c16b537SWarner Losh } 455*0c16b537SWarner Losh ip += rLength; 456*0c16b537SWarner Losh anchor = ip; 457*0c16b537SWarner Losh } 458*0c16b537SWarner Losh } 459*0c16b537SWarner Losh 460*0c16b537SWarner Losh /* Overwrite rep */ 461*0c16b537SWarner Losh for (i = 0; i < ZSTD_REP_NUM; i++) 462*0c16b537SWarner Losh seqStorePtr->rep[i] = repToConfirm[i]; 463*0c16b537SWarner Losh 464*0c16b537SWarner Losh ZSTD_ldm_limitTableUpdate(cctx, anchor); 465*0c16b537SWarner Losh ZSTD_ldm_fillFastTables(cctx, anchor); 466*0c16b537SWarner Losh 467*0c16b537SWarner Losh lastLiterals = blockCompressor(cctx, anchor, iend - anchor); 468*0c16b537SWarner Losh cctx->nextToUpdate = (U32)(iend - base); 469*0c16b537SWarner Losh 470*0c16b537SWarner Losh /* Restore seqStorePtr->rep */ 471*0c16b537SWarner Losh for (i = 0; i < ZSTD_REP_NUM; i++) 472*0c16b537SWarner Losh seqStorePtr->rep[i] = savedRep[i]; 473*0c16b537SWarner Losh 474*0c16b537SWarner Losh /* Return the last literals size */ 475*0c16b537SWarner Losh return lastLiterals; 476*0c16b537SWarner Losh } 477*0c16b537SWarner Losh 478*0c16b537SWarner Losh size_t ZSTD_compressBlock_ldm(ZSTD_CCtx* ctx, 479*0c16b537SWarner Losh const void* src, size_t srcSize) 480*0c16b537SWarner Losh { 481*0c16b537SWarner Losh return ZSTD_compressBlock_ldm_generic(ctx, src, srcSize); 482*0c16b537SWarner Losh } 483*0c16b537SWarner Losh 484*0c16b537SWarner Losh static size_t ZSTD_compressBlock_ldm_extDict_generic( 485*0c16b537SWarner Losh ZSTD_CCtx* ctx, 486*0c16b537SWarner Losh const void* src, size_t srcSize) 487*0c16b537SWarner Losh { 488*0c16b537SWarner Losh ldmState_t* const ldmState = &(ctx->ldmState); 489*0c16b537SWarner Losh const ldmParams_t ldmParams = ctx->appliedParams.ldmParams; 490*0c16b537SWarner Losh const U64 hashPower = ldmState->hashPower; 491*0c16b537SWarner Losh const U32 hBits = ldmParams.hashLog - ldmParams.bucketSizeLog; 492*0c16b537SWarner Losh const U32 ldmBucketSize = ((U32)1 << ldmParams.bucketSizeLog); 493*0c16b537SWarner Losh const U32 ldmTagMask = ((U32)1 << ldmParams.hashEveryLog) - 1; 494*0c16b537SWarner Losh seqStore_t* const seqStorePtr = &(ctx->seqStore); 495*0c16b537SWarner Losh const BYTE* const base = ctx->base; 496*0c16b537SWarner Losh const BYTE* const dictBase = ctx->dictBase; 497*0c16b537SWarner Losh const BYTE* const istart = (const BYTE*)src; 498*0c16b537SWarner Losh const BYTE* ip = istart; 499*0c16b537SWarner Losh const BYTE* anchor = istart; 500*0c16b537SWarner Losh const U32 lowestIndex = ctx->lowLimit; 501*0c16b537SWarner Losh const BYTE* const dictStart = dictBase + lowestIndex; 502*0c16b537SWarner Losh const U32 dictLimit = ctx->dictLimit; 503*0c16b537SWarner Losh const BYTE* const lowPrefixPtr = base + dictLimit; 504*0c16b537SWarner Losh const BYTE* const dictEnd = dictBase + dictLimit; 505*0c16b537SWarner Losh const BYTE* const iend = istart + srcSize; 506*0c16b537SWarner Losh const BYTE* const ilimit = iend - MAX(ldmParams.minMatchLength, HASH_READ_SIZE); 507*0c16b537SWarner Losh 508*0c16b537SWarner Losh const ZSTD_blockCompressor blockCompressor = 509*0c16b537SWarner Losh ZSTD_selectBlockCompressor(ctx->appliedParams.cParams.strategy, 1); 510*0c16b537SWarner Losh U32* const repToConfirm = seqStorePtr->repToConfirm; 511*0c16b537SWarner Losh U32 savedRep[ZSTD_REP_NUM]; 512*0c16b537SWarner Losh U64 rollingHash = 0; 513*0c16b537SWarner Losh const BYTE* lastHashed = NULL; 514*0c16b537SWarner Losh size_t i, lastLiterals; 515*0c16b537SWarner Losh 516*0c16b537SWarner Losh /* Save seqStorePtr->rep and copy repToConfirm */ 517*0c16b537SWarner Losh for (i = 0; i < ZSTD_REP_NUM; i++) { 518*0c16b537SWarner Losh savedRep[i] = repToConfirm[i] = seqStorePtr->rep[i]; 519*0c16b537SWarner Losh } 520*0c16b537SWarner Losh 521*0c16b537SWarner Losh /* Search Loop */ 522*0c16b537SWarner Losh while (ip < ilimit) { /* < instead of <=, because (ip+1) */ 523*0c16b537SWarner Losh size_t mLength; 524*0c16b537SWarner Losh const U32 current = (U32)(ip-base); 525*0c16b537SWarner Losh size_t forwardMatchLength = 0, backwardMatchLength = 0; 526*0c16b537SWarner Losh ldmEntry_t* bestEntry = NULL; 527*0c16b537SWarner Losh if (ip != istart) { 528*0c16b537SWarner Losh rollingHash = ZSTD_ldm_updateHash(rollingHash, lastHashed[0], 529*0c16b537SWarner Losh lastHashed[ldmParams.minMatchLength], 530*0c16b537SWarner Losh hashPower); 531*0c16b537SWarner Losh } else { 532*0c16b537SWarner Losh rollingHash = ZSTD_ldm_getRollingHash(ip, ldmParams.minMatchLength); 533*0c16b537SWarner Losh } 534*0c16b537SWarner Losh lastHashed = ip; 535*0c16b537SWarner Losh 536*0c16b537SWarner Losh if (ZSTD_ldm_getTag(rollingHash, hBits, ldmParams.hashEveryLog) != 537*0c16b537SWarner Losh ldmTagMask) { 538*0c16b537SWarner Losh /* Don't insert and don't look for a match */ 539*0c16b537SWarner Losh ip++; 540*0c16b537SWarner Losh continue; 541*0c16b537SWarner Losh } 542*0c16b537SWarner Losh 543*0c16b537SWarner Losh /* Get the best entry and compute the match lengths */ 544*0c16b537SWarner Losh { 545*0c16b537SWarner Losh ldmEntry_t* const bucket = 546*0c16b537SWarner Losh ZSTD_ldm_getBucket(ldmState, 547*0c16b537SWarner Losh ZSTD_ldm_getSmallHash(rollingHash, hBits), 548*0c16b537SWarner Losh ldmParams); 549*0c16b537SWarner Losh ldmEntry_t* cur; 550*0c16b537SWarner Losh size_t bestMatchLength = 0; 551*0c16b537SWarner Losh U32 const checksum = ZSTD_ldm_getChecksum(rollingHash, hBits); 552*0c16b537SWarner Losh 553*0c16b537SWarner Losh for (cur = bucket; cur < bucket + ldmBucketSize; ++cur) { 554*0c16b537SWarner Losh const BYTE* const curMatchBase = 555*0c16b537SWarner Losh cur->offset < dictLimit ? dictBase : base; 556*0c16b537SWarner Losh const BYTE* const pMatch = curMatchBase + cur->offset; 557*0c16b537SWarner Losh const BYTE* const matchEnd = 558*0c16b537SWarner Losh cur->offset < dictLimit ? dictEnd : iend; 559*0c16b537SWarner Losh const BYTE* const lowMatchPtr = 560*0c16b537SWarner Losh cur->offset < dictLimit ? dictStart : lowPrefixPtr; 561*0c16b537SWarner Losh size_t curForwardMatchLength, curBackwardMatchLength, 562*0c16b537SWarner Losh curTotalMatchLength; 563*0c16b537SWarner Losh 564*0c16b537SWarner Losh if (cur->checksum != checksum || cur->offset <= lowestIndex) { 565*0c16b537SWarner Losh continue; 566*0c16b537SWarner Losh } 567*0c16b537SWarner Losh 568*0c16b537SWarner Losh curForwardMatchLength = ZSTD_count_2segments( 569*0c16b537SWarner Losh ip, pMatch, iend, 570*0c16b537SWarner Losh matchEnd, lowPrefixPtr); 571*0c16b537SWarner Losh if (curForwardMatchLength < ldmParams.minMatchLength) { 572*0c16b537SWarner Losh continue; 573*0c16b537SWarner Losh } 574*0c16b537SWarner Losh curBackwardMatchLength = ZSTD_ldm_countBackwardsMatch( 575*0c16b537SWarner Losh ip, anchor, pMatch, lowMatchPtr); 576*0c16b537SWarner Losh curTotalMatchLength = curForwardMatchLength + 577*0c16b537SWarner Losh curBackwardMatchLength; 578*0c16b537SWarner Losh 579*0c16b537SWarner Losh if (curTotalMatchLength > bestMatchLength) { 580*0c16b537SWarner Losh bestMatchLength = curTotalMatchLength; 581*0c16b537SWarner Losh forwardMatchLength = curForwardMatchLength; 582*0c16b537SWarner Losh backwardMatchLength = curBackwardMatchLength; 583*0c16b537SWarner Losh bestEntry = cur; 584*0c16b537SWarner Losh } 585*0c16b537SWarner Losh } 586*0c16b537SWarner Losh } 587*0c16b537SWarner Losh 588*0c16b537SWarner Losh /* No match found -- continue searching */ 589*0c16b537SWarner Losh if (bestEntry == NULL) { 590*0c16b537SWarner Losh ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, 591*0c16b537SWarner Losh (U32)(lastHashed - base), 592*0c16b537SWarner Losh ldmParams); 593*0c16b537SWarner Losh ip++; 594*0c16b537SWarner Losh continue; 595*0c16b537SWarner Losh } 596*0c16b537SWarner Losh 597*0c16b537SWarner Losh /* Match found */ 598*0c16b537SWarner Losh mLength = forwardMatchLength + backwardMatchLength; 599*0c16b537SWarner Losh ip -= backwardMatchLength; 600*0c16b537SWarner Losh 601*0c16b537SWarner Losh /* Call the block compressor on the remaining literals */ 602*0c16b537SWarner Losh { 603*0c16b537SWarner Losh /* ip = current - backwardMatchLength 604*0c16b537SWarner Losh * The match is at (bestEntry->offset - backwardMatchLength) */ 605*0c16b537SWarner Losh U32 const matchIndex = bestEntry->offset; 606*0c16b537SWarner Losh U32 const offset = current - matchIndex; 607*0c16b537SWarner Losh 608*0c16b537SWarner Losh /* Overwrite rep codes */ 609*0c16b537SWarner Losh for (i = 0; i < ZSTD_REP_NUM; i++) 610*0c16b537SWarner Losh seqStorePtr->rep[i] = repToConfirm[i]; 611*0c16b537SWarner Losh 612*0c16b537SWarner Losh /* Fill the hash table for the block compressor */ 613*0c16b537SWarner Losh ZSTD_ldm_limitTableUpdate(ctx, anchor); 614*0c16b537SWarner Losh ZSTD_ldm_fillFastTables(ctx, anchor); 615*0c16b537SWarner Losh 616*0c16b537SWarner Losh /* Call block compressor and get remaining literals */ 617*0c16b537SWarner Losh lastLiterals = blockCompressor(ctx, anchor, ip - anchor); 618*0c16b537SWarner Losh ctx->nextToUpdate = (U32)(ip - base); 619*0c16b537SWarner Losh 620*0c16b537SWarner Losh /* Update repToConfirm with the new offset */ 621*0c16b537SWarner Losh for (i = ZSTD_REP_NUM - 1; i > 0; i--) 622*0c16b537SWarner Losh repToConfirm[i] = repToConfirm[i-1]; 623*0c16b537SWarner Losh repToConfirm[0] = offset; 624*0c16b537SWarner Losh 625*0c16b537SWarner Losh /* Store the sequence with the leftover literals */ 626*0c16b537SWarner Losh ZSTD_storeSeq(seqStorePtr, lastLiterals, ip - lastLiterals, 627*0c16b537SWarner Losh offset + ZSTD_REP_MOVE, mLength - MINMATCH); 628*0c16b537SWarner Losh } 629*0c16b537SWarner Losh 630*0c16b537SWarner Losh /* Insert the current entry into the hash table */ 631*0c16b537SWarner Losh ZSTD_ldm_makeEntryAndInsertByTag(ldmState, rollingHash, hBits, 632*0c16b537SWarner Losh (U32)(lastHashed - base), 633*0c16b537SWarner Losh ldmParams); 634*0c16b537SWarner Losh 635*0c16b537SWarner Losh /* Fill the hash table from lastHashed+1 to ip+mLength */ 636*0c16b537SWarner Losh assert(ip + backwardMatchLength == lastHashed); 637*0c16b537SWarner Losh if (ip + mLength < ilimit) { 638*0c16b537SWarner Losh rollingHash = ZSTD_ldm_fillLdmHashTable( 639*0c16b537SWarner Losh ldmState, rollingHash, lastHashed, 640*0c16b537SWarner Losh ip + mLength, base, hBits, 641*0c16b537SWarner Losh ldmParams); 642*0c16b537SWarner Losh lastHashed = ip + mLength - 1; 643*0c16b537SWarner Losh } 644*0c16b537SWarner Losh ip += mLength; 645*0c16b537SWarner Losh anchor = ip; 646*0c16b537SWarner Losh 647*0c16b537SWarner Losh /* check immediate repcode */ 648*0c16b537SWarner Losh while (ip < ilimit) { 649*0c16b537SWarner Losh U32 const current2 = (U32)(ip-base); 650*0c16b537SWarner Losh U32 const repIndex2 = current2 - repToConfirm[1]; 651*0c16b537SWarner Losh const BYTE* repMatch2 = repIndex2 < dictLimit ? 652*0c16b537SWarner Losh dictBase + repIndex2 : base + repIndex2; 653*0c16b537SWarner Losh if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & 654*0c16b537SWarner Losh (repIndex2 > lowestIndex)) /* intentional overflow */ 655*0c16b537SWarner Losh && (MEM_read32(repMatch2) == MEM_read32(ip)) ) { 656*0c16b537SWarner Losh const BYTE* const repEnd2 = repIndex2 < dictLimit ? 657*0c16b537SWarner Losh dictEnd : iend; 658*0c16b537SWarner Losh size_t const repLength2 = 659*0c16b537SWarner Losh ZSTD_count_2segments(ip+4, repMatch2+4, iend, 660*0c16b537SWarner Losh repEnd2, lowPrefixPtr) + 4; 661*0c16b537SWarner Losh 662*0c16b537SWarner Losh U32 tmpOffset = repToConfirm[1]; 663*0c16b537SWarner Losh repToConfirm[1] = repToConfirm[0]; 664*0c16b537SWarner Losh repToConfirm[0] = tmpOffset; 665*0c16b537SWarner Losh 666*0c16b537SWarner Losh ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH); 667*0c16b537SWarner Losh 668*0c16b537SWarner Losh /* Fill the hash table from lastHashed+1 to ip+repLength2*/ 669*0c16b537SWarner Losh if (ip + repLength2 < ilimit) { 670*0c16b537SWarner Losh rollingHash = ZSTD_ldm_fillLdmHashTable( 671*0c16b537SWarner Losh ldmState, rollingHash, lastHashed, 672*0c16b537SWarner Losh ip + repLength2, base, hBits, 673*0c16b537SWarner Losh ldmParams); 674*0c16b537SWarner Losh lastHashed = ip + repLength2 - 1; 675*0c16b537SWarner Losh } 676*0c16b537SWarner Losh ip += repLength2; 677*0c16b537SWarner Losh anchor = ip; 678*0c16b537SWarner Losh continue; 679*0c16b537SWarner Losh } 680*0c16b537SWarner Losh break; 681*0c16b537SWarner Losh } 682*0c16b537SWarner Losh } 683*0c16b537SWarner Losh 684*0c16b537SWarner Losh /* Overwrite rep */ 685*0c16b537SWarner Losh for (i = 0; i < ZSTD_REP_NUM; i++) 686*0c16b537SWarner Losh seqStorePtr->rep[i] = repToConfirm[i]; 687*0c16b537SWarner Losh 688*0c16b537SWarner Losh ZSTD_ldm_limitTableUpdate(ctx, anchor); 689*0c16b537SWarner Losh ZSTD_ldm_fillFastTables(ctx, anchor); 690*0c16b537SWarner Losh 691*0c16b537SWarner Losh /* Call the block compressor one last time on the last literals */ 692*0c16b537SWarner Losh lastLiterals = blockCompressor(ctx, anchor, iend - anchor); 693*0c16b537SWarner Losh ctx->nextToUpdate = (U32)(iend - base); 694*0c16b537SWarner Losh 695*0c16b537SWarner Losh /* Restore seqStorePtr->rep */ 696*0c16b537SWarner Losh for (i = 0; i < ZSTD_REP_NUM; i++) 697*0c16b537SWarner Losh seqStorePtr->rep[i] = savedRep[i]; 698*0c16b537SWarner Losh 699*0c16b537SWarner Losh /* Return the last literals size */ 700*0c16b537SWarner Losh return lastLiterals; 701*0c16b537SWarner Losh } 702*0c16b537SWarner Losh 703*0c16b537SWarner Losh size_t ZSTD_compressBlock_ldm_extDict(ZSTD_CCtx* ctx, 704*0c16b537SWarner Losh const void* src, size_t srcSize) 705*0c16b537SWarner Losh { 706*0c16b537SWarner Losh return ZSTD_compressBlock_ldm_extDict_generic(ctx, src, srcSize); 707*0c16b537SWarner Losh } 708