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_superblock.h" 15*3117ece4Schristos 16*3117ece4Schristos #include "../common/zstd_internal.h" /* ZSTD_getSequenceLength */ 17*3117ece4Schristos #include "hist.h" /* HIST_countFast_wksp */ 18*3117ece4Schristos #include "zstd_compress_internal.h" /* ZSTD_[huf|fse|entropy]CTablesMetadata_t */ 19*3117ece4Schristos #include "zstd_compress_sequences.h" 20*3117ece4Schristos #include "zstd_compress_literals.h" 21*3117ece4Schristos 22*3117ece4Schristos /** ZSTD_compressSubBlock_literal() : 23*3117ece4Schristos * Compresses literals section for a sub-block. 24*3117ece4Schristos * When we have to write the Huffman table we will sometimes choose a header 25*3117ece4Schristos * size larger than necessary. This is because we have to pick the header size 26*3117ece4Schristos * before we know the table size + compressed size, so we have a bound on the 27*3117ece4Schristos * table size. If we guessed incorrectly, we fall back to uncompressed literals. 28*3117ece4Schristos * 29*3117ece4Schristos * We write the header when writeEntropy=1 and set entropyWritten=1 when we succeeded 30*3117ece4Schristos * in writing the header, otherwise it is set to 0. 31*3117ece4Schristos * 32*3117ece4Schristos * hufMetadata->hType has literals block type info. 33*3117ece4Schristos * If it is set_basic, all sub-blocks literals section will be Raw_Literals_Block. 34*3117ece4Schristos * If it is set_rle, all sub-blocks literals section will be RLE_Literals_Block. 35*3117ece4Schristos * If it is set_compressed, first sub-block's literals section will be Compressed_Literals_Block 36*3117ece4Schristos * If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block 37*3117ece4Schristos * and the following sub-blocks' literals sections will be Treeless_Literals_Block. 38*3117ece4Schristos * @return : compressed size of literals section of a sub-block 39*3117ece4Schristos * Or 0 if unable to compress. 40*3117ece4Schristos * Or error code */ 41*3117ece4Schristos static size_t 42*3117ece4Schristos ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, 43*3117ece4Schristos const ZSTD_hufCTablesMetadata_t* hufMetadata, 44*3117ece4Schristos const BYTE* literals, size_t litSize, 45*3117ece4Schristos void* dst, size_t dstSize, 46*3117ece4Schristos const int bmi2, int writeEntropy, int* entropyWritten) 47*3117ece4Schristos { 48*3117ece4Schristos size_t const header = writeEntropy ? 200 : 0; 49*3117ece4Schristos size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header)); 50*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 51*3117ece4Schristos BYTE* const oend = ostart + dstSize; 52*3117ece4Schristos BYTE* op = ostart + lhSize; 53*3117ece4Schristos U32 const singleStream = lhSize == 3; 54*3117ece4Schristos symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat; 55*3117ece4Schristos size_t cLitSize = 0; 56*3117ece4Schristos 57*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy); 58*3117ece4Schristos 59*3117ece4Schristos *entropyWritten = 0; 60*3117ece4Schristos if (litSize == 0 || hufMetadata->hType == set_basic) { 61*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal"); 62*3117ece4Schristos return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); 63*3117ece4Schristos } else if (hufMetadata->hType == set_rle) { 64*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_literal using rle literal"); 65*3117ece4Schristos return ZSTD_compressRleLiteralsBlock(dst, dstSize, literals, litSize); 66*3117ece4Schristos } 67*3117ece4Schristos 68*3117ece4Schristos assert(litSize > 0); 69*3117ece4Schristos assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat); 70*3117ece4Schristos 71*3117ece4Schristos if (writeEntropy && hufMetadata->hType == set_compressed) { 72*3117ece4Schristos ZSTD_memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize); 73*3117ece4Schristos op += hufMetadata->hufDesSize; 74*3117ece4Schristos cLitSize += hufMetadata->hufDesSize; 75*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize); 76*3117ece4Schristos } 77*3117ece4Schristos 78*3117ece4Schristos { int const flags = bmi2 ? HUF_flags_bmi2 : 0; 79*3117ece4Schristos const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags) 80*3117ece4Schristos : HUF_compress4X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags); 81*3117ece4Schristos op += cSize; 82*3117ece4Schristos cLitSize += cSize; 83*3117ece4Schristos if (cSize == 0 || ERR_isError(cSize)) { 84*3117ece4Schristos DEBUGLOG(5, "Failed to write entropy tables %s", ZSTD_getErrorName(cSize)); 85*3117ece4Schristos return 0; 86*3117ece4Schristos } 87*3117ece4Schristos /* If we expand and we aren't writing a header then emit uncompressed */ 88*3117ece4Schristos if (!writeEntropy && cLitSize >= litSize) { 89*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal because uncompressible"); 90*3117ece4Schristos return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); 91*3117ece4Schristos } 92*3117ece4Schristos /* If we are writing headers then allow expansion that doesn't change our header size. */ 93*3117ece4Schristos if (lhSize < (size_t)(3 + (cLitSize >= 1 KB) + (cLitSize >= 16 KB))) { 94*3117ece4Schristos assert(cLitSize > litSize); 95*3117ece4Schristos DEBUGLOG(5, "Literals expanded beyond allowed header size"); 96*3117ece4Schristos return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); 97*3117ece4Schristos } 98*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_literal (cSize=%zu)", cSize); 99*3117ece4Schristos } 100*3117ece4Schristos 101*3117ece4Schristos /* Build header */ 102*3117ece4Schristos switch(lhSize) 103*3117ece4Schristos { 104*3117ece4Schristos case 3: /* 2 - 2 - 10 - 10 */ 105*3117ece4Schristos { U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14); 106*3117ece4Schristos MEM_writeLE24(ostart, lhc); 107*3117ece4Schristos break; 108*3117ece4Schristos } 109*3117ece4Schristos case 4: /* 2 - 2 - 14 - 14 */ 110*3117ece4Schristos { U32 const lhc = hType + (2 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<18); 111*3117ece4Schristos MEM_writeLE32(ostart, lhc); 112*3117ece4Schristos break; 113*3117ece4Schristos } 114*3117ece4Schristos case 5: /* 2 - 2 - 18 - 18 */ 115*3117ece4Schristos { U32 const lhc = hType + (3 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<22); 116*3117ece4Schristos MEM_writeLE32(ostart, lhc); 117*3117ece4Schristos ostart[4] = (BYTE)(cLitSize >> 10); 118*3117ece4Schristos break; 119*3117ece4Schristos } 120*3117ece4Schristos default: /* not possible : lhSize is {3,4,5} */ 121*3117ece4Schristos assert(0); 122*3117ece4Schristos } 123*3117ece4Schristos *entropyWritten = 1; 124*3117ece4Schristos DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart)); 125*3117ece4Schristos return (size_t)(op-ostart); 126*3117ece4Schristos } 127*3117ece4Schristos 128*3117ece4Schristos static size_t 129*3117ece4Schristos ZSTD_seqDecompressedSize(seqStore_t const* seqStore, 130*3117ece4Schristos const seqDef* sequences, size_t nbSeqs, 131*3117ece4Schristos size_t litSize, int lastSubBlock) 132*3117ece4Schristos { 133*3117ece4Schristos size_t matchLengthSum = 0; 134*3117ece4Schristos size_t litLengthSum = 0; 135*3117ece4Schristos size_t n; 136*3117ece4Schristos for (n=0; n<nbSeqs; n++) { 137*3117ece4Schristos const ZSTD_sequenceLength seqLen = ZSTD_getSequenceLength(seqStore, sequences+n); 138*3117ece4Schristos litLengthSum += seqLen.litLength; 139*3117ece4Schristos matchLengthSum += seqLen.matchLength; 140*3117ece4Schristos } 141*3117ece4Schristos DEBUGLOG(5, "ZSTD_seqDecompressedSize: %u sequences from %p: %u literals + %u matchlength", 142*3117ece4Schristos (unsigned)nbSeqs, (const void*)sequences, 143*3117ece4Schristos (unsigned)litLengthSum, (unsigned)matchLengthSum); 144*3117ece4Schristos if (!lastSubBlock) 145*3117ece4Schristos assert(litLengthSum == litSize); 146*3117ece4Schristos else 147*3117ece4Schristos assert(litLengthSum <= litSize); 148*3117ece4Schristos (void)litLengthSum; 149*3117ece4Schristos return matchLengthSum + litSize; 150*3117ece4Schristos } 151*3117ece4Schristos 152*3117ece4Schristos /** ZSTD_compressSubBlock_sequences() : 153*3117ece4Schristos * Compresses sequences section for a sub-block. 154*3117ece4Schristos * fseMetadata->llType, fseMetadata->ofType, and fseMetadata->mlType have 155*3117ece4Schristos * symbol compression modes for the super-block. 156*3117ece4Schristos * The first successfully compressed block will have these in its header. 157*3117ece4Schristos * We set entropyWritten=1 when we succeed in compressing the sequences. 158*3117ece4Schristos * The following sub-blocks will always have repeat mode. 159*3117ece4Schristos * @return : compressed size of sequences section of a sub-block 160*3117ece4Schristos * Or 0 if it is unable to compress 161*3117ece4Schristos * Or error code. */ 162*3117ece4Schristos static size_t 163*3117ece4Schristos ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, 164*3117ece4Schristos const ZSTD_fseCTablesMetadata_t* fseMetadata, 165*3117ece4Schristos const seqDef* sequences, size_t nbSeq, 166*3117ece4Schristos const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, 167*3117ece4Schristos const ZSTD_CCtx_params* cctxParams, 168*3117ece4Schristos void* dst, size_t dstCapacity, 169*3117ece4Schristos const int bmi2, int writeEntropy, int* entropyWritten) 170*3117ece4Schristos { 171*3117ece4Schristos const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; 172*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 173*3117ece4Schristos BYTE* const oend = ostart + dstCapacity; 174*3117ece4Schristos BYTE* op = ostart; 175*3117ece4Schristos BYTE* seqHead; 176*3117ece4Schristos 177*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (nbSeq=%zu, writeEntropy=%d, longOffsets=%d)", nbSeq, writeEntropy, longOffsets); 178*3117ece4Schristos 179*3117ece4Schristos *entropyWritten = 0; 180*3117ece4Schristos /* Sequences Header */ 181*3117ece4Schristos RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, 182*3117ece4Schristos dstSize_tooSmall, ""); 183*3117ece4Schristos if (nbSeq < 128) 184*3117ece4Schristos *op++ = (BYTE)nbSeq; 185*3117ece4Schristos else if (nbSeq < LONGNBSEQ) 186*3117ece4Schristos op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; 187*3117ece4Schristos else 188*3117ece4Schristos op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; 189*3117ece4Schristos if (nbSeq==0) { 190*3117ece4Schristos return (size_t)(op - ostart); 191*3117ece4Schristos } 192*3117ece4Schristos 193*3117ece4Schristos /* seqHead : flags for FSE encoding type */ 194*3117ece4Schristos seqHead = op++; 195*3117ece4Schristos 196*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (seqHeadSize=%u)", (unsigned)(op-ostart)); 197*3117ece4Schristos 198*3117ece4Schristos if (writeEntropy) { 199*3117ece4Schristos const U32 LLtype = fseMetadata->llType; 200*3117ece4Schristos const U32 Offtype = fseMetadata->ofType; 201*3117ece4Schristos const U32 MLtype = fseMetadata->mlType; 202*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize); 203*3117ece4Schristos *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 204*3117ece4Schristos ZSTD_memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize); 205*3117ece4Schristos op += fseMetadata->fseTablesSize; 206*3117ece4Schristos } else { 207*3117ece4Schristos const U32 repeat = set_repeat; 208*3117ece4Schristos *seqHead = (BYTE)((repeat<<6) + (repeat<<4) + (repeat<<2)); 209*3117ece4Schristos } 210*3117ece4Schristos 211*3117ece4Schristos { size_t const bitstreamSize = ZSTD_encodeSequences( 212*3117ece4Schristos op, (size_t)(oend - op), 213*3117ece4Schristos fseTables->matchlengthCTable, mlCode, 214*3117ece4Schristos fseTables->offcodeCTable, ofCode, 215*3117ece4Schristos fseTables->litlengthCTable, llCode, 216*3117ece4Schristos sequences, nbSeq, 217*3117ece4Schristos longOffsets, bmi2); 218*3117ece4Schristos FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed"); 219*3117ece4Schristos op += bitstreamSize; 220*3117ece4Schristos /* zstd versions <= 1.3.4 mistakenly report corruption when 221*3117ece4Schristos * FSE_readNCount() receives a buffer < 4 bytes. 222*3117ece4Schristos * Fixed by https://github.com/facebook/zstd/pull/1146. 223*3117ece4Schristos * This can happen when the last set_compressed table present is 2 224*3117ece4Schristos * bytes and the bitstream is only one byte. 225*3117ece4Schristos * In this exceedingly rare case, we will simply emit an uncompressed 226*3117ece4Schristos * block, since it isn't worth optimizing. 227*3117ece4Schristos */ 228*3117ece4Schristos #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 229*3117ece4Schristos if (writeEntropy && fseMetadata->lastCountSize && fseMetadata->lastCountSize + bitstreamSize < 4) { 230*3117ece4Schristos /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ 231*3117ece4Schristos assert(fseMetadata->lastCountSize + bitstreamSize == 3); 232*3117ece4Schristos DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " 233*3117ece4Schristos "emitting an uncompressed block."); 234*3117ece4Schristos return 0; 235*3117ece4Schristos } 236*3117ece4Schristos #endif 237*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (bitstreamSize=%zu)", bitstreamSize); 238*3117ece4Schristos } 239*3117ece4Schristos 240*3117ece4Schristos /* zstd versions <= 1.4.0 mistakenly report error when 241*3117ece4Schristos * sequences section body size is less than 3 bytes. 242*3117ece4Schristos * Fixed by https://github.com/facebook/zstd/pull/1664. 243*3117ece4Schristos * This can happen when the previous sequences section block is compressed 244*3117ece4Schristos * with rle mode and the current block's sequences section is compressed 245*3117ece4Schristos * with repeat mode where sequences section body size can be 1 byte. 246*3117ece4Schristos */ 247*3117ece4Schristos #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 248*3117ece4Schristos if (op-seqHead < 4) { 249*3117ece4Schristos DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.4.0 by emitting " 250*3117ece4Schristos "an uncompressed block when sequences are < 4 bytes"); 251*3117ece4Schristos return 0; 252*3117ece4Schristos } 253*3117ece4Schristos #endif 254*3117ece4Schristos 255*3117ece4Schristos *entropyWritten = 1; 256*3117ece4Schristos return (size_t)(op - ostart); 257*3117ece4Schristos } 258*3117ece4Schristos 259*3117ece4Schristos /** ZSTD_compressSubBlock() : 260*3117ece4Schristos * Compresses a single sub-block. 261*3117ece4Schristos * @return : compressed size of the sub-block 262*3117ece4Schristos * Or 0 if it failed to compress. */ 263*3117ece4Schristos static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy, 264*3117ece4Schristos const ZSTD_entropyCTablesMetadata_t* entropyMetadata, 265*3117ece4Schristos const seqDef* sequences, size_t nbSeq, 266*3117ece4Schristos const BYTE* literals, size_t litSize, 267*3117ece4Schristos const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, 268*3117ece4Schristos const ZSTD_CCtx_params* cctxParams, 269*3117ece4Schristos void* dst, size_t dstCapacity, 270*3117ece4Schristos const int bmi2, 271*3117ece4Schristos int writeLitEntropy, int writeSeqEntropy, 272*3117ece4Schristos int* litEntropyWritten, int* seqEntropyWritten, 273*3117ece4Schristos U32 lastBlock) 274*3117ece4Schristos { 275*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 276*3117ece4Schristos BYTE* const oend = ostart + dstCapacity; 277*3117ece4Schristos BYTE* op = ostart + ZSTD_blockHeaderSize; 278*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)", 279*3117ece4Schristos litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock); 280*3117ece4Schristos { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable, 281*3117ece4Schristos &entropyMetadata->hufMetadata, literals, litSize, 282*3117ece4Schristos op, (size_t)(oend-op), 283*3117ece4Schristos bmi2, writeLitEntropy, litEntropyWritten); 284*3117ece4Schristos FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed"); 285*3117ece4Schristos if (cLitSize == 0) return 0; 286*3117ece4Schristos op += cLitSize; 287*3117ece4Schristos } 288*3117ece4Schristos { size_t cSeqSize = ZSTD_compressSubBlock_sequences(&entropy->fse, 289*3117ece4Schristos &entropyMetadata->fseMetadata, 290*3117ece4Schristos sequences, nbSeq, 291*3117ece4Schristos llCode, mlCode, ofCode, 292*3117ece4Schristos cctxParams, 293*3117ece4Schristos op, (size_t)(oend-op), 294*3117ece4Schristos bmi2, writeSeqEntropy, seqEntropyWritten); 295*3117ece4Schristos FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed"); 296*3117ece4Schristos if (cSeqSize == 0) return 0; 297*3117ece4Schristos op += cSeqSize; 298*3117ece4Schristos } 299*3117ece4Schristos /* Write block header */ 300*3117ece4Schristos { size_t cSize = (size_t)(op-ostart) - ZSTD_blockHeaderSize; 301*3117ece4Schristos U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 302*3117ece4Schristos MEM_writeLE24(ostart, cBlockHeader24); 303*3117ece4Schristos } 304*3117ece4Schristos return (size_t)(op-ostart); 305*3117ece4Schristos } 306*3117ece4Schristos 307*3117ece4Schristos static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize, 308*3117ece4Schristos const ZSTD_hufCTables_t* huf, 309*3117ece4Schristos const ZSTD_hufCTablesMetadata_t* hufMetadata, 310*3117ece4Schristos void* workspace, size_t wkspSize, 311*3117ece4Schristos int writeEntropy) 312*3117ece4Schristos { 313*3117ece4Schristos unsigned* const countWksp = (unsigned*)workspace; 314*3117ece4Schristos unsigned maxSymbolValue = 255; 315*3117ece4Schristos size_t literalSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ 316*3117ece4Schristos 317*3117ece4Schristos if (hufMetadata->hType == set_basic) return litSize; 318*3117ece4Schristos else if (hufMetadata->hType == set_rle) return 1; 319*3117ece4Schristos else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { 320*3117ece4Schristos size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); 321*3117ece4Schristos if (ZSTD_isError(largest)) return litSize; 322*3117ece4Schristos { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); 323*3117ece4Schristos if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; 324*3117ece4Schristos return cLitSizeEstimate + literalSectionHeaderSize; 325*3117ece4Schristos } } 326*3117ece4Schristos assert(0); /* impossible */ 327*3117ece4Schristos return 0; 328*3117ece4Schristos } 329*3117ece4Schristos 330*3117ece4Schristos static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type, 331*3117ece4Schristos const BYTE* codeTable, unsigned maxCode, 332*3117ece4Schristos size_t nbSeq, const FSE_CTable* fseCTable, 333*3117ece4Schristos const U8* additionalBits, 334*3117ece4Schristos short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, 335*3117ece4Schristos void* workspace, size_t wkspSize) 336*3117ece4Schristos { 337*3117ece4Schristos unsigned* const countWksp = (unsigned*)workspace; 338*3117ece4Schristos const BYTE* ctp = codeTable; 339*3117ece4Schristos const BYTE* const ctStart = ctp; 340*3117ece4Schristos const BYTE* const ctEnd = ctStart + nbSeq; 341*3117ece4Schristos size_t cSymbolTypeSizeEstimateInBits = 0; 342*3117ece4Schristos unsigned max = maxCode; 343*3117ece4Schristos 344*3117ece4Schristos HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ 345*3117ece4Schristos if (type == set_basic) { 346*3117ece4Schristos /* We selected this encoding type, so it must be valid. */ 347*3117ece4Schristos assert(max <= defaultMax); 348*3117ece4Schristos cSymbolTypeSizeEstimateInBits = max <= defaultMax 349*3117ece4Schristos ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max) 350*3117ece4Schristos : ERROR(GENERIC); 351*3117ece4Schristos } else if (type == set_rle) { 352*3117ece4Schristos cSymbolTypeSizeEstimateInBits = 0; 353*3117ece4Schristos } else if (type == set_compressed || type == set_repeat) { 354*3117ece4Schristos cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); 355*3117ece4Schristos } 356*3117ece4Schristos if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) return nbSeq * 10; 357*3117ece4Schristos while (ctp < ctEnd) { 358*3117ece4Schristos if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; 359*3117ece4Schristos else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ 360*3117ece4Schristos ctp++; 361*3117ece4Schristos } 362*3117ece4Schristos return cSymbolTypeSizeEstimateInBits / 8; 363*3117ece4Schristos } 364*3117ece4Schristos 365*3117ece4Schristos static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable, 366*3117ece4Schristos const BYTE* llCodeTable, 367*3117ece4Schristos const BYTE* mlCodeTable, 368*3117ece4Schristos size_t nbSeq, 369*3117ece4Schristos const ZSTD_fseCTables_t* fseTables, 370*3117ece4Schristos const ZSTD_fseCTablesMetadata_t* fseMetadata, 371*3117ece4Schristos void* workspace, size_t wkspSize, 372*3117ece4Schristos int writeEntropy) 373*3117ece4Schristos { 374*3117ece4Schristos size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ 375*3117ece4Schristos size_t cSeqSizeEstimate = 0; 376*3117ece4Schristos if (nbSeq == 0) return sequencesSectionHeaderSize; 377*3117ece4Schristos cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff, 378*3117ece4Schristos nbSeq, fseTables->offcodeCTable, NULL, 379*3117ece4Schristos OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 380*3117ece4Schristos workspace, wkspSize); 381*3117ece4Schristos cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL, 382*3117ece4Schristos nbSeq, fseTables->litlengthCTable, LL_bits, 383*3117ece4Schristos LL_defaultNorm, LL_defaultNormLog, MaxLL, 384*3117ece4Schristos workspace, wkspSize); 385*3117ece4Schristos cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML, 386*3117ece4Schristos nbSeq, fseTables->matchlengthCTable, ML_bits, 387*3117ece4Schristos ML_defaultNorm, ML_defaultNormLog, MaxML, 388*3117ece4Schristos workspace, wkspSize); 389*3117ece4Schristos if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; 390*3117ece4Schristos return cSeqSizeEstimate + sequencesSectionHeaderSize; 391*3117ece4Schristos } 392*3117ece4Schristos 393*3117ece4Schristos typedef struct { 394*3117ece4Schristos size_t estLitSize; 395*3117ece4Schristos size_t estBlockSize; 396*3117ece4Schristos } EstimatedBlockSize; 397*3117ece4Schristos static EstimatedBlockSize ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, 398*3117ece4Schristos const BYTE* ofCodeTable, 399*3117ece4Schristos const BYTE* llCodeTable, 400*3117ece4Schristos const BYTE* mlCodeTable, 401*3117ece4Schristos size_t nbSeq, 402*3117ece4Schristos const ZSTD_entropyCTables_t* entropy, 403*3117ece4Schristos const ZSTD_entropyCTablesMetadata_t* entropyMetadata, 404*3117ece4Schristos void* workspace, size_t wkspSize, 405*3117ece4Schristos int writeLitEntropy, int writeSeqEntropy) 406*3117ece4Schristos { 407*3117ece4Schristos EstimatedBlockSize ebs; 408*3117ece4Schristos ebs.estLitSize = ZSTD_estimateSubBlockSize_literal(literals, litSize, 409*3117ece4Schristos &entropy->huf, &entropyMetadata->hufMetadata, 410*3117ece4Schristos workspace, wkspSize, writeLitEntropy); 411*3117ece4Schristos ebs.estBlockSize = ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, 412*3117ece4Schristos nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, 413*3117ece4Schristos workspace, wkspSize, writeSeqEntropy); 414*3117ece4Schristos ebs.estBlockSize += ebs.estLitSize + ZSTD_blockHeaderSize; 415*3117ece4Schristos return ebs; 416*3117ece4Schristos } 417*3117ece4Schristos 418*3117ece4Schristos static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata) 419*3117ece4Schristos { 420*3117ece4Schristos if (fseMetadata->llType == set_compressed || fseMetadata->llType == set_rle) 421*3117ece4Schristos return 1; 422*3117ece4Schristos if (fseMetadata->mlType == set_compressed || fseMetadata->mlType == set_rle) 423*3117ece4Schristos return 1; 424*3117ece4Schristos if (fseMetadata->ofType == set_compressed || fseMetadata->ofType == set_rle) 425*3117ece4Schristos return 1; 426*3117ece4Schristos return 0; 427*3117ece4Schristos } 428*3117ece4Schristos 429*3117ece4Schristos static size_t countLiterals(seqStore_t const* seqStore, const seqDef* sp, size_t seqCount) 430*3117ece4Schristos { 431*3117ece4Schristos size_t n, total = 0; 432*3117ece4Schristos assert(sp != NULL); 433*3117ece4Schristos for (n=0; n<seqCount; n++) { 434*3117ece4Schristos total += ZSTD_getSequenceLength(seqStore, sp+n).litLength; 435*3117ece4Schristos } 436*3117ece4Schristos DEBUGLOG(6, "countLiterals for %zu sequences from %p => %zu bytes", seqCount, (const void*)sp, total); 437*3117ece4Schristos return total; 438*3117ece4Schristos } 439*3117ece4Schristos 440*3117ece4Schristos #define BYTESCALE 256 441*3117ece4Schristos 442*3117ece4Schristos static size_t sizeBlockSequences(const seqDef* sp, size_t nbSeqs, 443*3117ece4Schristos size_t targetBudget, size_t avgLitCost, size_t avgSeqCost, 444*3117ece4Schristos int firstSubBlock) 445*3117ece4Schristos { 446*3117ece4Schristos size_t n, budget = 0, inSize=0; 447*3117ece4Schristos /* entropy headers */ 448*3117ece4Schristos size_t const headerSize = (size_t)firstSubBlock * 120 * BYTESCALE; /* generous estimate */ 449*3117ece4Schristos assert(firstSubBlock==0 || firstSubBlock==1); 450*3117ece4Schristos budget += headerSize; 451*3117ece4Schristos 452*3117ece4Schristos /* first sequence => at least one sequence*/ 453*3117ece4Schristos budget += sp[0].litLength * avgLitCost + avgSeqCost; 454*3117ece4Schristos if (budget > targetBudget) return 1; 455*3117ece4Schristos inSize = sp[0].litLength + (sp[0].mlBase+MINMATCH); 456*3117ece4Schristos 457*3117ece4Schristos /* loop over sequences */ 458*3117ece4Schristos for (n=1; n<nbSeqs; n++) { 459*3117ece4Schristos size_t currentCost = sp[n].litLength * avgLitCost + avgSeqCost; 460*3117ece4Schristos budget += currentCost; 461*3117ece4Schristos inSize += sp[n].litLength + (sp[n].mlBase+MINMATCH); 462*3117ece4Schristos /* stop when sub-block budget is reached */ 463*3117ece4Schristos if ( (budget > targetBudget) 464*3117ece4Schristos /* though continue to expand until the sub-block is deemed compressible */ 465*3117ece4Schristos && (budget < inSize * BYTESCALE) ) 466*3117ece4Schristos break; 467*3117ece4Schristos } 468*3117ece4Schristos 469*3117ece4Schristos return n; 470*3117ece4Schristos } 471*3117ece4Schristos 472*3117ece4Schristos /** ZSTD_compressSubBlock_multi() : 473*3117ece4Schristos * Breaks super-block into multiple sub-blocks and compresses them. 474*3117ece4Schristos * Entropy will be written into the first block. 475*3117ece4Schristos * The following blocks use repeat_mode to compress. 476*3117ece4Schristos * Sub-blocks are all compressed, except the last one when beneficial. 477*3117ece4Schristos * @return : compressed size of the super block (which features multiple ZSTD blocks) 478*3117ece4Schristos * or 0 if it failed to compress. */ 479*3117ece4Schristos static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, 480*3117ece4Schristos const ZSTD_compressedBlockState_t* prevCBlock, 481*3117ece4Schristos ZSTD_compressedBlockState_t* nextCBlock, 482*3117ece4Schristos const ZSTD_entropyCTablesMetadata_t* entropyMetadata, 483*3117ece4Schristos const ZSTD_CCtx_params* cctxParams, 484*3117ece4Schristos void* dst, size_t dstCapacity, 485*3117ece4Schristos const void* src, size_t srcSize, 486*3117ece4Schristos const int bmi2, U32 lastBlock, 487*3117ece4Schristos void* workspace, size_t wkspSize) 488*3117ece4Schristos { 489*3117ece4Schristos const seqDef* const sstart = seqStorePtr->sequencesStart; 490*3117ece4Schristos const seqDef* const send = seqStorePtr->sequences; 491*3117ece4Schristos const seqDef* sp = sstart; /* tracks progresses within seqStorePtr->sequences */ 492*3117ece4Schristos size_t const nbSeqs = (size_t)(send - sstart); 493*3117ece4Schristos const BYTE* const lstart = seqStorePtr->litStart; 494*3117ece4Schristos const BYTE* const lend = seqStorePtr->lit; 495*3117ece4Schristos const BYTE* lp = lstart; 496*3117ece4Schristos size_t const nbLiterals = (size_t)(lend - lstart); 497*3117ece4Schristos BYTE const* ip = (BYTE const*)src; 498*3117ece4Schristos BYTE const* const iend = ip + srcSize; 499*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 500*3117ece4Schristos BYTE* const oend = ostart + dstCapacity; 501*3117ece4Schristos BYTE* op = ostart; 502*3117ece4Schristos const BYTE* llCodePtr = seqStorePtr->llCode; 503*3117ece4Schristos const BYTE* mlCodePtr = seqStorePtr->mlCode; 504*3117ece4Schristos const BYTE* ofCodePtr = seqStorePtr->ofCode; 505*3117ece4Schristos size_t const minTarget = ZSTD_TARGETCBLOCKSIZE_MIN; /* enforce minimum size, to reduce undesirable side effects */ 506*3117ece4Schristos size_t const targetCBlockSize = MAX(minTarget, cctxParams->targetCBlockSize); 507*3117ece4Schristos int writeLitEntropy = (entropyMetadata->hufMetadata.hType == set_compressed); 508*3117ece4Schristos int writeSeqEntropy = 1; 509*3117ece4Schristos 510*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_multi (srcSize=%u, litSize=%u, nbSeq=%u)", 511*3117ece4Schristos (unsigned)srcSize, (unsigned)(lend-lstart), (unsigned)(send-sstart)); 512*3117ece4Schristos 513*3117ece4Schristos /* let's start by a general estimation for the full block */ 514*3117ece4Schristos if (nbSeqs > 0) { 515*3117ece4Schristos EstimatedBlockSize const ebs = 516*3117ece4Schristos ZSTD_estimateSubBlockSize(lp, nbLiterals, 517*3117ece4Schristos ofCodePtr, llCodePtr, mlCodePtr, nbSeqs, 518*3117ece4Schristos &nextCBlock->entropy, entropyMetadata, 519*3117ece4Schristos workspace, wkspSize, 520*3117ece4Schristos writeLitEntropy, writeSeqEntropy); 521*3117ece4Schristos /* quick estimation */ 522*3117ece4Schristos size_t const avgLitCost = nbLiterals ? (ebs.estLitSize * BYTESCALE) / nbLiterals : BYTESCALE; 523*3117ece4Schristos size_t const avgSeqCost = ((ebs.estBlockSize - ebs.estLitSize) * BYTESCALE) / nbSeqs; 524*3117ece4Schristos const size_t nbSubBlocks = MAX((ebs.estBlockSize + (targetCBlockSize/2)) / targetCBlockSize, 1); 525*3117ece4Schristos size_t n, avgBlockBudget, blockBudgetSupp=0; 526*3117ece4Schristos avgBlockBudget = (ebs.estBlockSize * BYTESCALE) / nbSubBlocks; 527*3117ece4Schristos DEBUGLOG(5, "estimated fullblock size=%u bytes ; avgLitCost=%.2f ; avgSeqCost=%.2f ; targetCBlockSize=%u, nbSubBlocks=%u ; avgBlockBudget=%.0f bytes", 528*3117ece4Schristos (unsigned)ebs.estBlockSize, (double)avgLitCost/BYTESCALE, (double)avgSeqCost/BYTESCALE, 529*3117ece4Schristos (unsigned)targetCBlockSize, (unsigned)nbSubBlocks, (double)avgBlockBudget/BYTESCALE); 530*3117ece4Schristos /* simplification: if estimates states that the full superblock doesn't compress, just bail out immediately 531*3117ece4Schristos * this will result in the production of a single uncompressed block covering @srcSize.*/ 532*3117ece4Schristos if (ebs.estBlockSize > srcSize) return 0; 533*3117ece4Schristos 534*3117ece4Schristos /* compress and write sub-blocks */ 535*3117ece4Schristos assert(nbSubBlocks>0); 536*3117ece4Schristos for (n=0; n < nbSubBlocks-1; n++) { 537*3117ece4Schristos /* determine nb of sequences for current sub-block + nbLiterals from next sequence */ 538*3117ece4Schristos size_t const seqCount = sizeBlockSequences(sp, (size_t)(send-sp), 539*3117ece4Schristos avgBlockBudget + blockBudgetSupp, avgLitCost, avgSeqCost, n==0); 540*3117ece4Schristos /* if reached last sequence : break to last sub-block (simplification) */ 541*3117ece4Schristos assert(seqCount <= (size_t)(send-sp)); 542*3117ece4Schristos if (sp + seqCount == send) break; 543*3117ece4Schristos assert(seqCount > 0); 544*3117ece4Schristos /* compress sub-block */ 545*3117ece4Schristos { int litEntropyWritten = 0; 546*3117ece4Schristos int seqEntropyWritten = 0; 547*3117ece4Schristos size_t litSize = countLiterals(seqStorePtr, sp, seqCount); 548*3117ece4Schristos const size_t decompressedSize = 549*3117ece4Schristos ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 0); 550*3117ece4Schristos size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, 551*3117ece4Schristos sp, seqCount, 552*3117ece4Schristos lp, litSize, 553*3117ece4Schristos llCodePtr, mlCodePtr, ofCodePtr, 554*3117ece4Schristos cctxParams, 555*3117ece4Schristos op, (size_t)(oend-op), 556*3117ece4Schristos bmi2, writeLitEntropy, writeSeqEntropy, 557*3117ece4Schristos &litEntropyWritten, &seqEntropyWritten, 558*3117ece4Schristos 0); 559*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); 560*3117ece4Schristos 561*3117ece4Schristos /* check compressibility, update state components */ 562*3117ece4Schristos if (cSize > 0 && cSize < decompressedSize) { 563*3117ece4Schristos DEBUGLOG(5, "Committed sub-block compressing %u bytes => %u bytes", 564*3117ece4Schristos (unsigned)decompressedSize, (unsigned)cSize); 565*3117ece4Schristos assert(ip + decompressedSize <= iend); 566*3117ece4Schristos ip += decompressedSize; 567*3117ece4Schristos lp += litSize; 568*3117ece4Schristos op += cSize; 569*3117ece4Schristos llCodePtr += seqCount; 570*3117ece4Schristos mlCodePtr += seqCount; 571*3117ece4Schristos ofCodePtr += seqCount; 572*3117ece4Schristos /* Entropy only needs to be written once */ 573*3117ece4Schristos if (litEntropyWritten) { 574*3117ece4Schristos writeLitEntropy = 0; 575*3117ece4Schristos } 576*3117ece4Schristos if (seqEntropyWritten) { 577*3117ece4Schristos writeSeqEntropy = 0; 578*3117ece4Schristos } 579*3117ece4Schristos sp += seqCount; 580*3117ece4Schristos blockBudgetSupp = 0; 581*3117ece4Schristos } } 582*3117ece4Schristos /* otherwise : do not compress yet, coalesce current sub-block with following one */ 583*3117ece4Schristos } 584*3117ece4Schristos } /* if (nbSeqs > 0) */ 585*3117ece4Schristos 586*3117ece4Schristos /* write last block */ 587*3117ece4Schristos DEBUGLOG(5, "Generate last sub-block: %u sequences remaining", (unsigned)(send - sp)); 588*3117ece4Schristos { int litEntropyWritten = 0; 589*3117ece4Schristos int seqEntropyWritten = 0; 590*3117ece4Schristos size_t litSize = (size_t)(lend - lp); 591*3117ece4Schristos size_t seqCount = (size_t)(send - sp); 592*3117ece4Schristos const size_t decompressedSize = 593*3117ece4Schristos ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 1); 594*3117ece4Schristos size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, 595*3117ece4Schristos sp, seqCount, 596*3117ece4Schristos lp, litSize, 597*3117ece4Schristos llCodePtr, mlCodePtr, ofCodePtr, 598*3117ece4Schristos cctxParams, 599*3117ece4Schristos op, (size_t)(oend-op), 600*3117ece4Schristos bmi2, writeLitEntropy, writeSeqEntropy, 601*3117ece4Schristos &litEntropyWritten, &seqEntropyWritten, 602*3117ece4Schristos lastBlock); 603*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); 604*3117ece4Schristos 605*3117ece4Schristos /* update pointers, the nb of literals borrowed from next sequence must be preserved */ 606*3117ece4Schristos if (cSize > 0 && cSize < decompressedSize) { 607*3117ece4Schristos DEBUGLOG(5, "Last sub-block compressed %u bytes => %u bytes", 608*3117ece4Schristos (unsigned)decompressedSize, (unsigned)cSize); 609*3117ece4Schristos assert(ip + decompressedSize <= iend); 610*3117ece4Schristos ip += decompressedSize; 611*3117ece4Schristos lp += litSize; 612*3117ece4Schristos op += cSize; 613*3117ece4Schristos llCodePtr += seqCount; 614*3117ece4Schristos mlCodePtr += seqCount; 615*3117ece4Schristos ofCodePtr += seqCount; 616*3117ece4Schristos /* Entropy only needs to be written once */ 617*3117ece4Schristos if (litEntropyWritten) { 618*3117ece4Schristos writeLitEntropy = 0; 619*3117ece4Schristos } 620*3117ece4Schristos if (seqEntropyWritten) { 621*3117ece4Schristos writeSeqEntropy = 0; 622*3117ece4Schristos } 623*3117ece4Schristos sp += seqCount; 624*3117ece4Schristos } 625*3117ece4Schristos } 626*3117ece4Schristos 627*3117ece4Schristos 628*3117ece4Schristos if (writeLitEntropy) { 629*3117ece4Schristos DEBUGLOG(5, "Literal entropy tables were never written"); 630*3117ece4Schristos ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf)); 631*3117ece4Schristos } 632*3117ece4Schristos if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) { 633*3117ece4Schristos /* If we haven't written our entropy tables, then we've violated our contract and 634*3117ece4Schristos * must emit an uncompressed block. 635*3117ece4Schristos */ 636*3117ece4Schristos DEBUGLOG(5, "Sequence entropy tables were never written => cancel, emit an uncompressed block"); 637*3117ece4Schristos return 0; 638*3117ece4Schristos } 639*3117ece4Schristos 640*3117ece4Schristos if (ip < iend) { 641*3117ece4Schristos /* some data left : last part of the block sent uncompressed */ 642*3117ece4Schristos size_t const rSize = (size_t)((iend - ip)); 643*3117ece4Schristos size_t const cSize = ZSTD_noCompressBlock(op, (size_t)(oend - op), ip, rSize, lastBlock); 644*3117ece4Schristos DEBUGLOG(5, "Generate last uncompressed sub-block of %u bytes", (unsigned)(rSize)); 645*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); 646*3117ece4Schristos assert(cSize != 0); 647*3117ece4Schristos op += cSize; 648*3117ece4Schristos /* We have to regenerate the repcodes because we've skipped some sequences */ 649*3117ece4Schristos if (sp < send) { 650*3117ece4Schristos const seqDef* seq; 651*3117ece4Schristos repcodes_t rep; 652*3117ece4Schristos ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep)); 653*3117ece4Schristos for (seq = sstart; seq < sp; ++seq) { 654*3117ece4Schristos ZSTD_updateRep(rep.rep, seq->offBase, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0); 655*3117ece4Schristos } 656*3117ece4Schristos ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep)); 657*3117ece4Schristos } 658*3117ece4Schristos } 659*3117ece4Schristos 660*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed all subBlocks: total compressed size = %u", 661*3117ece4Schristos (unsigned)(op-ostart)); 662*3117ece4Schristos return (size_t)(op-ostart); 663*3117ece4Schristos } 664*3117ece4Schristos 665*3117ece4Schristos size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, 666*3117ece4Schristos void* dst, size_t dstCapacity, 667*3117ece4Schristos const void* src, size_t srcSize, 668*3117ece4Schristos unsigned lastBlock) 669*3117ece4Schristos { 670*3117ece4Schristos ZSTD_entropyCTablesMetadata_t entropyMetadata; 671*3117ece4Schristos 672*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore, 673*3117ece4Schristos &zc->blockState.prevCBlock->entropy, 674*3117ece4Schristos &zc->blockState.nextCBlock->entropy, 675*3117ece4Schristos &zc->appliedParams, 676*3117ece4Schristos &entropyMetadata, 677*3117ece4Schristos zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); 678*3117ece4Schristos 679*3117ece4Schristos return ZSTD_compressSubBlock_multi(&zc->seqStore, 680*3117ece4Schristos zc->blockState.prevCBlock, 681*3117ece4Schristos zc->blockState.nextCBlock, 682*3117ece4Schristos &entropyMetadata, 683*3117ece4Schristos &zc->appliedParams, 684*3117ece4Schristos dst, dstCapacity, 685*3117ece4Schristos src, srcSize, 686*3117ece4Schristos zc->bmi2, lastBlock, 687*3117ece4Schristos zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */); 688*3117ece4Schristos } 689