1*3117ece4Schristos /* 2*3117ece4Schristos * Copyright (c) Meta Platforms, Inc. and affiliates. 3*3117ece4Schristos * All rights reserved. 4*3117ece4Schristos * 5*3117ece4Schristos * This source code is licensed under both the BSD-style license (found in the 6*3117ece4Schristos * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*3117ece4Schristos * in the COPYING file in the root directory of this source tree). 8*3117ece4Schristos * You may select, at your option, one of the above-listed licenses. 9*3117ece4Schristos */ 10*3117ece4Schristos 11*3117ece4Schristos /*-************************************* 12*3117ece4Schristos * Dependencies 13*3117ece4Schristos ***************************************/ 14*3117ece4Schristos #include "zstd_compress_literals.h" 15*3117ece4Schristos 16*3117ece4Schristos 17*3117ece4Schristos /* ************************************************************** 18*3117ece4Schristos * Debug Traces 19*3117ece4Schristos ****************************************************************/ 20*3117ece4Schristos #if DEBUGLEVEL >= 2 21*3117ece4Schristos 22*3117ece4Schristos static size_t showHexa(const void* src, size_t srcSize) 23*3117ece4Schristos { 24*3117ece4Schristos const BYTE* const ip = (const BYTE*)src; 25*3117ece4Schristos size_t u; 26*3117ece4Schristos for (u=0; u<srcSize; u++) { 27*3117ece4Schristos RAWLOG(5, " %02X", ip[u]); (void)ip; 28*3117ece4Schristos } 29*3117ece4Schristos RAWLOG(5, " \n"); 30*3117ece4Schristos return srcSize; 31*3117ece4Schristos } 32*3117ece4Schristos 33*3117ece4Schristos #endif 34*3117ece4Schristos 35*3117ece4Schristos 36*3117ece4Schristos /* ************************************************************** 37*3117ece4Schristos * Literals compression - special cases 38*3117ece4Schristos ****************************************************************/ 39*3117ece4Schristos size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 40*3117ece4Schristos { 41*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 42*3117ece4Schristos U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); 43*3117ece4Schristos 44*3117ece4Schristos DEBUGLOG(5, "ZSTD_noCompressLiterals: srcSize=%zu, dstCapacity=%zu", srcSize, dstCapacity); 45*3117ece4Schristos 46*3117ece4Schristos RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall, ""); 47*3117ece4Schristos 48*3117ece4Schristos switch(flSize) 49*3117ece4Schristos { 50*3117ece4Schristos case 1: /* 2 - 1 - 5 */ 51*3117ece4Schristos ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3)); 52*3117ece4Schristos break; 53*3117ece4Schristos case 2: /* 2 - 2 - 12 */ 54*3117ece4Schristos MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4))); 55*3117ece4Schristos break; 56*3117ece4Schristos case 3: /* 2 - 2 - 20 */ 57*3117ece4Schristos MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4))); 58*3117ece4Schristos break; 59*3117ece4Schristos default: /* not necessary : flSize is {1,2,3} */ 60*3117ece4Schristos assert(0); 61*3117ece4Schristos } 62*3117ece4Schristos 63*3117ece4Schristos ZSTD_memcpy(ostart + flSize, src, srcSize); 64*3117ece4Schristos DEBUGLOG(5, "Raw (uncompressed) literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); 65*3117ece4Schristos return srcSize + flSize; 66*3117ece4Schristos } 67*3117ece4Schristos 68*3117ece4Schristos static int allBytesIdentical(const void* src, size_t srcSize) 69*3117ece4Schristos { 70*3117ece4Schristos assert(srcSize >= 1); 71*3117ece4Schristos assert(src != NULL); 72*3117ece4Schristos { const BYTE b = ((const BYTE*)src)[0]; 73*3117ece4Schristos size_t p; 74*3117ece4Schristos for (p=1; p<srcSize; p++) { 75*3117ece4Schristos if (((const BYTE*)src)[p] != b) return 0; 76*3117ece4Schristos } 77*3117ece4Schristos return 1; 78*3117ece4Schristos } 79*3117ece4Schristos } 80*3117ece4Schristos 81*3117ece4Schristos size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 82*3117ece4Schristos { 83*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 84*3117ece4Schristos U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); 85*3117ece4Schristos 86*3117ece4Schristos assert(dstCapacity >= 4); (void)dstCapacity; 87*3117ece4Schristos assert(allBytesIdentical(src, srcSize)); 88*3117ece4Schristos 89*3117ece4Schristos switch(flSize) 90*3117ece4Schristos { 91*3117ece4Schristos case 1: /* 2 - 1 - 5 */ 92*3117ece4Schristos ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3)); 93*3117ece4Schristos break; 94*3117ece4Schristos case 2: /* 2 - 2 - 12 */ 95*3117ece4Schristos MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4))); 96*3117ece4Schristos break; 97*3117ece4Schristos case 3: /* 2 - 2 - 20 */ 98*3117ece4Schristos MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4))); 99*3117ece4Schristos break; 100*3117ece4Schristos default: /* not necessary : flSize is {1,2,3} */ 101*3117ece4Schristos assert(0); 102*3117ece4Schristos } 103*3117ece4Schristos 104*3117ece4Schristos ostart[flSize] = *(const BYTE*)src; 105*3117ece4Schristos DEBUGLOG(5, "RLE : Repeated Literal (%02X: %u times) -> %u bytes encoded", ((const BYTE*)src)[0], (U32)srcSize, (U32)flSize + 1); 106*3117ece4Schristos return flSize+1; 107*3117ece4Schristos } 108*3117ece4Schristos 109*3117ece4Schristos /* ZSTD_minLiteralsToCompress() : 110*3117ece4Schristos * returns minimal amount of literals 111*3117ece4Schristos * for literal compression to even be attempted. 112*3117ece4Schristos * Minimum is made tighter as compression strategy increases. 113*3117ece4Schristos */ 114*3117ece4Schristos static size_t 115*3117ece4Schristos ZSTD_minLiteralsToCompress(ZSTD_strategy strategy, HUF_repeat huf_repeat) 116*3117ece4Schristos { 117*3117ece4Schristos assert((int)strategy >= 0); 118*3117ece4Schristos assert((int)strategy <= 9); 119*3117ece4Schristos /* btultra2 : min 8 bytes; 120*3117ece4Schristos * then 2x larger for each successive compression strategy 121*3117ece4Schristos * max threshold 64 bytes */ 122*3117ece4Schristos { int const shift = MIN(9-(int)strategy, 3); 123*3117ece4Schristos size_t const mintc = (huf_repeat == HUF_repeat_valid) ? 6 : (size_t)8 << shift; 124*3117ece4Schristos DEBUGLOG(7, "minLiteralsToCompress = %zu", mintc); 125*3117ece4Schristos return mintc; 126*3117ece4Schristos } 127*3117ece4Schristos } 128*3117ece4Schristos 129*3117ece4Schristos size_t ZSTD_compressLiterals ( 130*3117ece4Schristos void* dst, size_t dstCapacity, 131*3117ece4Schristos const void* src, size_t srcSize, 132*3117ece4Schristos void* entropyWorkspace, size_t entropyWorkspaceSize, 133*3117ece4Schristos const ZSTD_hufCTables_t* prevHuf, 134*3117ece4Schristos ZSTD_hufCTables_t* nextHuf, 135*3117ece4Schristos ZSTD_strategy strategy, 136*3117ece4Schristos int disableLiteralCompression, 137*3117ece4Schristos int suspectUncompressible, 138*3117ece4Schristos int bmi2) 139*3117ece4Schristos { 140*3117ece4Schristos size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); 141*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 142*3117ece4Schristos U32 singleStream = srcSize < 256; 143*3117ece4Schristos symbolEncodingType_e hType = set_compressed; 144*3117ece4Schristos size_t cLitSize; 145*3117ece4Schristos 146*3117ece4Schristos DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i, srcSize=%u, dstCapacity=%zu)", 147*3117ece4Schristos disableLiteralCompression, (U32)srcSize, dstCapacity); 148*3117ece4Schristos 149*3117ece4Schristos DEBUGLOG(6, "Completed literals listing (%zu bytes)", showHexa(src, srcSize)); 150*3117ece4Schristos 151*3117ece4Schristos /* Prepare nextEntropy assuming reusing the existing table */ 152*3117ece4Schristos ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 153*3117ece4Schristos 154*3117ece4Schristos if (disableLiteralCompression) 155*3117ece4Schristos return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 156*3117ece4Schristos 157*3117ece4Schristos /* if too small, don't even attempt compression (speed opt) */ 158*3117ece4Schristos if (srcSize < ZSTD_minLiteralsToCompress(strategy, prevHuf->repeatMode)) 159*3117ece4Schristos return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 160*3117ece4Schristos 161*3117ece4Schristos RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression"); 162*3117ece4Schristos { HUF_repeat repeat = prevHuf->repeatMode; 163*3117ece4Schristos int const flags = 0 164*3117ece4Schristos | (bmi2 ? HUF_flags_bmi2 : 0) 165*3117ece4Schristos | (strategy < ZSTD_lazy && srcSize <= 1024 ? HUF_flags_preferRepeat : 0) 166*3117ece4Schristos | (strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD ? HUF_flags_optimalDepth : 0) 167*3117ece4Schristos | (suspectUncompressible ? HUF_flags_suspectUncompressible : 0); 168*3117ece4Schristos 169*3117ece4Schristos typedef size_t (*huf_compress_f)(void*, size_t, const void*, size_t, unsigned, unsigned, void*, size_t, HUF_CElt*, HUF_repeat*, int); 170*3117ece4Schristos huf_compress_f huf_compress; 171*3117ece4Schristos if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; 172*3117ece4Schristos huf_compress = singleStream ? HUF_compress1X_repeat : HUF_compress4X_repeat; 173*3117ece4Schristos cLitSize = huf_compress(ostart+lhSize, dstCapacity-lhSize, 174*3117ece4Schristos src, srcSize, 175*3117ece4Schristos HUF_SYMBOLVALUE_MAX, LitHufLog, 176*3117ece4Schristos entropyWorkspace, entropyWorkspaceSize, 177*3117ece4Schristos (HUF_CElt*)nextHuf->CTable, 178*3117ece4Schristos &repeat, flags); 179*3117ece4Schristos DEBUGLOG(5, "%zu literals compressed into %zu bytes (before header)", srcSize, cLitSize); 180*3117ece4Schristos if (repeat != HUF_repeat_none) { 181*3117ece4Schristos /* reused the existing table */ 182*3117ece4Schristos DEBUGLOG(5, "reusing statistics from previous huffman block"); 183*3117ece4Schristos hType = set_repeat; 184*3117ece4Schristos } 185*3117ece4Schristos } 186*3117ece4Schristos 187*3117ece4Schristos { size_t const minGain = ZSTD_minGain(srcSize, strategy); 188*3117ece4Schristos if ((cLitSize==0) || (cLitSize >= srcSize - minGain) || ERR_isError(cLitSize)) { 189*3117ece4Schristos ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 190*3117ece4Schristos return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 191*3117ece4Schristos } } 192*3117ece4Schristos if (cLitSize==1) { 193*3117ece4Schristos /* A return value of 1 signals that the alphabet consists of a single symbol. 194*3117ece4Schristos * However, in some rare circumstances, it could be the compressed size (a single byte). 195*3117ece4Schristos * For that outcome to have a chance to happen, it's necessary that `srcSize < 8`. 196*3117ece4Schristos * (it's also necessary to not generate statistics). 197*3117ece4Schristos * Therefore, in such a case, actively check that all bytes are identical. */ 198*3117ece4Schristos if ((srcSize >= 8) || allBytesIdentical(src, srcSize)) { 199*3117ece4Schristos ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 200*3117ece4Schristos return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); 201*3117ece4Schristos } } 202*3117ece4Schristos 203*3117ece4Schristos if (hType == set_compressed) { 204*3117ece4Schristos /* using a newly constructed table */ 205*3117ece4Schristos nextHuf->repeatMode = HUF_repeat_check; 206*3117ece4Schristos } 207*3117ece4Schristos 208*3117ece4Schristos /* Build header */ 209*3117ece4Schristos switch(lhSize) 210*3117ece4Schristos { 211*3117ece4Schristos case 3: /* 2 - 2 - 10 - 10 */ 212*3117ece4Schristos if (!singleStream) assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); 213*3117ece4Schristos { U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); 214*3117ece4Schristos MEM_writeLE24(ostart, lhc); 215*3117ece4Schristos break; 216*3117ece4Schristos } 217*3117ece4Schristos case 4: /* 2 - 2 - 14 - 14 */ 218*3117ece4Schristos assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); 219*3117ece4Schristos { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18); 220*3117ece4Schristos MEM_writeLE32(ostart, lhc); 221*3117ece4Schristos break; 222*3117ece4Schristos } 223*3117ece4Schristos case 5: /* 2 - 2 - 18 - 18 */ 224*3117ece4Schristos assert(srcSize >= MIN_LITERALS_FOR_4_STREAMS); 225*3117ece4Schristos { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); 226*3117ece4Schristos MEM_writeLE32(ostart, lhc); 227*3117ece4Schristos ostart[4] = (BYTE)(cLitSize >> 10); 228*3117ece4Schristos break; 229*3117ece4Schristos } 230*3117ece4Schristos default: /* not possible : lhSize is {3,4,5} */ 231*3117ece4Schristos assert(0); 232*3117ece4Schristos } 233*3117ece4Schristos DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)srcSize, (U32)(lhSize+cLitSize)); 234*3117ece4Schristos return lhSize+cLitSize; 235*3117ece4Schristos } 236