Path: blob/main/sys/contrib/zstd/lib/compress/zstd_compress_superblock.c
48378 views
/*1* Copyright (c) Yann Collet, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under both the BSD-style license (found in the5* LICENSE file in the root directory of this source tree) and the GPLv2 (found6* in the COPYING file in the root directory of this source tree).7* You may select, at your option, one of the above-listed licenses.8*/910/*-*************************************11* Dependencies12***************************************/13#include "zstd_compress_superblock.h"1415#include "../common/zstd_internal.h" /* ZSTD_getSequenceLength */16#include "hist.h" /* HIST_countFast_wksp */17#include "zstd_compress_internal.h" /* ZSTD_[huf|fse|entropy]CTablesMetadata_t */18#include "zstd_compress_sequences.h"19#include "zstd_compress_literals.h"2021/** ZSTD_compressSubBlock_literal() :22* Compresses literals section for a sub-block.23* When we have to write the Huffman table we will sometimes choose a header24* size larger than necessary. This is because we have to pick the header size25* before we know the table size + compressed size, so we have a bound on the26* table size. If we guessed incorrectly, we fall back to uncompressed literals.27*28* We write the header when writeEntropy=1 and set entropyWritten=1 when we succeeded29* in writing the header, otherwise it is set to 0.30*31* hufMetadata->hType has literals block type info.32* If it is set_basic, all sub-blocks literals section will be Raw_Literals_Block.33* If it is set_rle, all sub-blocks literals section will be RLE_Literals_Block.34* If it is set_compressed, first sub-block's literals section will be Compressed_Literals_Block35* If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block36* and the following sub-blocks' literals sections will be Treeless_Literals_Block.37* @return : compressed size of literals section of a sub-block38* Or 0 if it unable to compress.39* Or error code */40static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,41const ZSTD_hufCTablesMetadata_t* hufMetadata,42const BYTE* literals, size_t litSize,43void* dst, size_t dstSize,44const int bmi2, int writeEntropy, int* entropyWritten)45{46size_t const header = writeEntropy ? 200 : 0;47size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header));48BYTE* const ostart = (BYTE*)dst;49BYTE* const oend = ostart + dstSize;50BYTE* op = ostart + lhSize;51U32 const singleStream = lhSize == 3;52symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat;53size_t cLitSize = 0;5455(void)bmi2; /* TODO bmi2... */5657DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy);5859*entropyWritten = 0;60if (litSize == 0 || hufMetadata->hType == set_basic) {61DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal");62return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);63} else if (hufMetadata->hType == set_rle) {64DEBUGLOG(5, "ZSTD_compressSubBlock_literal using rle literal");65return ZSTD_compressRleLiteralsBlock(dst, dstSize, literals, litSize);66}6768assert(litSize > 0);69assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat);7071if (writeEntropy && hufMetadata->hType == set_compressed) {72ZSTD_memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize);73op += hufMetadata->hufDesSize;74cLitSize += hufMetadata->hufDesSize;75DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize);76}7778/* TODO bmi2 */79{ const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable)80: HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable);81op += cSize;82cLitSize += cSize;83if (cSize == 0 || ERR_isError(cSize)) {84DEBUGLOG(5, "Failed to write entropy tables %s", ZSTD_getErrorName(cSize));85return 0;86}87/* If we expand and we aren't writing a header then emit uncompressed */88if (!writeEntropy && cLitSize >= litSize) {89DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal because uncompressible");90return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);91}92/* If we are writing headers then allow expansion that doesn't change our header size. */93if (lhSize < (size_t)(3 + (cLitSize >= 1 KB) + (cLitSize >= 16 KB))) {94assert(cLitSize > litSize);95DEBUGLOG(5, "Literals expanded beyond allowed header size");96return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);97}98DEBUGLOG(5, "ZSTD_compressSubBlock_literal (cSize=%zu)", cSize);99}100101/* Build header */102switch(lhSize)103{104case 3: /* 2 - 2 - 10 - 10 */105{ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);106MEM_writeLE24(ostart, lhc);107break;108}109case 4: /* 2 - 2 - 14 - 14 */110{ U32 const lhc = hType + (2 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<18);111MEM_writeLE32(ostart, lhc);112break;113}114case 5: /* 2 - 2 - 18 - 18 */115{ U32 const lhc = hType + (3 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<22);116MEM_writeLE32(ostart, lhc);117ostart[4] = (BYTE)(cLitSize >> 10);118break;119}120default: /* not possible : lhSize is {3,4,5} */121assert(0);122}123*entropyWritten = 1;124DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));125return op-ostart;126}127128static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef* sequences, size_t nbSeq, size_t litSize, int lastSequence) {129const seqDef* const sstart = sequences;130const seqDef* const send = sequences + nbSeq;131const seqDef* sp = sstart;132size_t matchLengthSum = 0;133size_t litLengthSum = 0;134(void)(litLengthSum); /* suppress unused variable warning on some environments */135while (send-sp > 0) {136ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp);137litLengthSum += seqLen.litLength;138matchLengthSum += seqLen.matchLength;139sp++;140}141assert(litLengthSum <= litSize);142if (!lastSequence) {143assert(litLengthSum == litSize);144}145return matchLengthSum + litSize;146}147148/** ZSTD_compressSubBlock_sequences() :149* Compresses sequences section for a sub-block.150* fseMetadata->llType, fseMetadata->ofType, and fseMetadata->mlType have151* symbol compression modes for the super-block.152* The first successfully compressed block will have these in its header.153* We set entropyWritten=1 when we succeed in compressing the sequences.154* The following sub-blocks will always have repeat mode.155* @return : compressed size of sequences section of a sub-block156* Or 0 if it is unable to compress157* Or error code. */158static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,159const ZSTD_fseCTablesMetadata_t* fseMetadata,160const seqDef* sequences, size_t nbSeq,161const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,162const ZSTD_CCtx_params* cctxParams,163void* dst, size_t dstCapacity,164const int bmi2, int writeEntropy, int* entropyWritten)165{166const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;167BYTE* const ostart = (BYTE*)dst;168BYTE* const oend = ostart + dstCapacity;169BYTE* op = ostart;170BYTE* seqHead;171172DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (nbSeq=%zu, writeEntropy=%d, longOffsets=%d)", nbSeq, writeEntropy, longOffsets);173174*entropyWritten = 0;175/* Sequences Header */176RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,177dstSize_tooSmall, "");178if (nbSeq < 0x7F)179*op++ = (BYTE)nbSeq;180else if (nbSeq < LONGNBSEQ)181op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;182else183op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;184if (nbSeq==0) {185return op - ostart;186}187188/* seqHead : flags for FSE encoding type */189seqHead = op++;190191DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (seqHeadSize=%u)", (unsigned)(op-ostart));192193if (writeEntropy) {194const U32 LLtype = fseMetadata->llType;195const U32 Offtype = fseMetadata->ofType;196const U32 MLtype = fseMetadata->mlType;197DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize);198*seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));199ZSTD_memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize);200op += fseMetadata->fseTablesSize;201} else {202const U32 repeat = set_repeat;203*seqHead = (BYTE)((repeat<<6) + (repeat<<4) + (repeat<<2));204}205206{ size_t const bitstreamSize = ZSTD_encodeSequences(207op, oend - op,208fseTables->matchlengthCTable, mlCode,209fseTables->offcodeCTable, ofCode,210fseTables->litlengthCTable, llCode,211sequences, nbSeq,212longOffsets, bmi2);213FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");214op += bitstreamSize;215/* zstd versions <= 1.3.4 mistakenly report corruption when216* FSE_readNCount() receives a buffer < 4 bytes.217* Fixed by https://github.com/facebook/zstd/pull/1146.218* This can happen when the last set_compressed table present is 2219* bytes and the bitstream is only one byte.220* In this exceedingly rare case, we will simply emit an uncompressed221* block, since it isn't worth optimizing.222*/223#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION224if (writeEntropy && fseMetadata->lastCountSize && fseMetadata->lastCountSize + bitstreamSize < 4) {225/* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */226assert(fseMetadata->lastCountSize + bitstreamSize == 3);227DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "228"emitting an uncompressed block.");229return 0;230}231#endif232DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (bitstreamSize=%zu)", bitstreamSize);233}234235/* zstd versions <= 1.4.0 mistakenly report error when236* sequences section body size is less than 3 bytes.237* Fixed by https://github.com/facebook/zstd/pull/1664.238* This can happen when the previous sequences section block is compressed239* with rle mode and the current block's sequences section is compressed240* with repeat mode where sequences section body size can be 1 byte.241*/242#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION243if (op-seqHead < 4) {244DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.4.0 by emitting "245"an uncompressed block when sequences are < 4 bytes");246return 0;247}248#endif249250*entropyWritten = 1;251return op - ostart;252}253254/** ZSTD_compressSubBlock() :255* Compresses a single sub-block.256* @return : compressed size of the sub-block257* Or 0 if it failed to compress. */258static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,259const ZSTD_entropyCTablesMetadata_t* entropyMetadata,260const seqDef* sequences, size_t nbSeq,261const BYTE* literals, size_t litSize,262const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,263const ZSTD_CCtx_params* cctxParams,264void* dst, size_t dstCapacity,265const int bmi2,266int writeLitEntropy, int writeSeqEntropy,267int* litEntropyWritten, int* seqEntropyWritten,268U32 lastBlock)269{270BYTE* const ostart = (BYTE*)dst;271BYTE* const oend = ostart + dstCapacity;272BYTE* op = ostart + ZSTD_blockHeaderSize;273DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)",274litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);275{ size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,276&entropyMetadata->hufMetadata, literals, litSize,277op, oend-op, bmi2, writeLitEntropy, litEntropyWritten);278FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");279if (cLitSize == 0) return 0;280op += cLitSize;281}282{ size_t cSeqSize = ZSTD_compressSubBlock_sequences(&entropy->fse,283&entropyMetadata->fseMetadata,284sequences, nbSeq,285llCode, mlCode, ofCode,286cctxParams,287op, oend-op,288bmi2, writeSeqEntropy, seqEntropyWritten);289FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");290if (cSeqSize == 0) return 0;291op += cSeqSize;292}293/* Write block header */294{ size_t cSize = (op-ostart)-ZSTD_blockHeaderSize;295U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);296MEM_writeLE24(ostart, cBlockHeader24);297}298return op-ostart;299}300301static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize,302const ZSTD_hufCTables_t* huf,303const ZSTD_hufCTablesMetadata_t* hufMetadata,304void* workspace, size_t wkspSize,305int writeEntropy)306{307unsigned* const countWksp = (unsigned*)workspace;308unsigned maxSymbolValue = 255;309size_t literalSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */310311if (hufMetadata->hType == set_basic) return litSize;312else if (hufMetadata->hType == set_rle) return 1;313else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) {314size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize);315if (ZSTD_isError(largest)) return litSize;316{ size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue);317if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize;318return cLitSizeEstimate + literalSectionHeaderSize;319} }320assert(0); /* impossible */321return 0;322}323324static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,325const BYTE* codeTable, unsigned maxCode,326size_t nbSeq, const FSE_CTable* fseCTable,327const U8* additionalBits,328short const* defaultNorm, U32 defaultNormLog, U32 defaultMax,329void* workspace, size_t wkspSize)330{331unsigned* const countWksp = (unsigned*)workspace;332const BYTE* ctp = codeTable;333const BYTE* const ctStart = ctp;334const BYTE* const ctEnd = ctStart + nbSeq;335size_t cSymbolTypeSizeEstimateInBits = 0;336unsigned max = maxCode;337338HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */339if (type == set_basic) {340/* We selected this encoding type, so it must be valid. */341assert(max <= defaultMax);342cSymbolTypeSizeEstimateInBits = max <= defaultMax343? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max)344: ERROR(GENERIC);345} else if (type == set_rle) {346cSymbolTypeSizeEstimateInBits = 0;347} else if (type == set_compressed || type == set_repeat) {348cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max);349}350if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) return nbSeq * 10;351while (ctp < ctEnd) {352if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp];353else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */354ctp++;355}356return cSymbolTypeSizeEstimateInBits / 8;357}358359static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,360const BYTE* llCodeTable,361const BYTE* mlCodeTable,362size_t nbSeq,363const ZSTD_fseCTables_t* fseTables,364const ZSTD_fseCTablesMetadata_t* fseMetadata,365void* workspace, size_t wkspSize,366int writeEntropy)367{368size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */369size_t cSeqSizeEstimate = 0;370if (nbSeq == 0) return sequencesSectionHeaderSize;371cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff,372nbSeq, fseTables->offcodeCTable, NULL,373OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,374workspace, wkspSize);375cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL,376nbSeq, fseTables->litlengthCTable, LL_bits,377LL_defaultNorm, LL_defaultNormLog, MaxLL,378workspace, wkspSize);379cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML,380nbSeq, fseTables->matchlengthCTable, ML_bits,381ML_defaultNorm, ML_defaultNormLog, MaxML,382workspace, wkspSize);383if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;384return cSeqSizeEstimate + sequencesSectionHeaderSize;385}386387static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,388const BYTE* ofCodeTable,389const BYTE* llCodeTable,390const BYTE* mlCodeTable,391size_t nbSeq,392const ZSTD_entropyCTables_t* entropy,393const ZSTD_entropyCTablesMetadata_t* entropyMetadata,394void* workspace, size_t wkspSize,395int writeLitEntropy, int writeSeqEntropy) {396size_t cSizeEstimate = 0;397cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize,398&entropy->huf, &entropyMetadata->hufMetadata,399workspace, wkspSize, writeLitEntropy);400cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,401nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,402workspace, wkspSize, writeSeqEntropy);403return cSizeEstimate + ZSTD_blockHeaderSize;404}405406static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)407{408if (fseMetadata->llType == set_compressed || fseMetadata->llType == set_rle)409return 1;410if (fseMetadata->mlType == set_compressed || fseMetadata->mlType == set_rle)411return 1;412if (fseMetadata->ofType == set_compressed || fseMetadata->ofType == set_rle)413return 1;414return 0;415}416417/** ZSTD_compressSubBlock_multi() :418* Breaks super-block into multiple sub-blocks and compresses them.419* Entropy will be written to the first block.420* The following blocks will use repeat mode to compress.421* All sub-blocks are compressed blocks (no raw or rle blocks).422* @return : compressed size of the super block (which is multiple ZSTD blocks)423* Or 0 if it failed to compress. */424static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,425const ZSTD_compressedBlockState_t* prevCBlock,426ZSTD_compressedBlockState_t* nextCBlock,427const ZSTD_entropyCTablesMetadata_t* entropyMetadata,428const ZSTD_CCtx_params* cctxParams,429void* dst, size_t dstCapacity,430const void* src, size_t srcSize,431const int bmi2, U32 lastBlock,432void* workspace, size_t wkspSize)433{434const seqDef* const sstart = seqStorePtr->sequencesStart;435const seqDef* const send = seqStorePtr->sequences;436const seqDef* sp = sstart;437const BYTE* const lstart = seqStorePtr->litStart;438const BYTE* const lend = seqStorePtr->lit;439const BYTE* lp = lstart;440BYTE const* ip = (BYTE const*)src;441BYTE const* const iend = ip + srcSize;442BYTE* const ostart = (BYTE*)dst;443BYTE* const oend = ostart + dstCapacity;444BYTE* op = ostart;445const BYTE* llCodePtr = seqStorePtr->llCode;446const BYTE* mlCodePtr = seqStorePtr->mlCode;447const BYTE* ofCodePtr = seqStorePtr->ofCode;448size_t targetCBlockSize = cctxParams->targetCBlockSize;449size_t litSize, seqCount;450int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed;451int writeSeqEntropy = 1;452int lastSequence = 0;453454DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)",455(unsigned)(lend-lp), (unsigned)(send-sstart));456457litSize = 0;458seqCount = 0;459do {460size_t cBlockSizeEstimate = 0;461if (sstart == send) {462lastSequence = 1;463} else {464const seqDef* const sequence = sp + seqCount;465lastSequence = sequence == send - 1;466litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength;467seqCount++;468}469if (lastSequence) {470assert(lp <= lend);471assert(litSize <= (size_t)(lend - lp));472litSize = (size_t)(lend - lp);473}474/* I think there is an optimization opportunity here.475* Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful476* since it recalculates estimate from scratch.477* For example, it would recount literal distribution and symbol codes every time.478*/479cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount,480&nextCBlock->entropy, entropyMetadata,481workspace, wkspSize, writeLitEntropy, writeSeqEntropy);482if (cBlockSizeEstimate > targetCBlockSize || lastSequence) {483int litEntropyWritten = 0;484int seqEntropyWritten = 0;485const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence);486const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,487sp, seqCount,488lp, litSize,489llCodePtr, mlCodePtr, ofCodePtr,490cctxParams,491op, oend-op,492bmi2, writeLitEntropy, writeSeqEntropy,493&litEntropyWritten, &seqEntropyWritten,494lastBlock && lastSequence);495FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");496if (cSize > 0 && cSize < decompressedSize) {497DEBUGLOG(5, "Committed the sub-block");498assert(ip + decompressedSize <= iend);499ip += decompressedSize;500sp += seqCount;501lp += litSize;502op += cSize;503llCodePtr += seqCount;504mlCodePtr += seqCount;505ofCodePtr += seqCount;506litSize = 0;507seqCount = 0;508/* Entropy only needs to be written once */509if (litEntropyWritten) {510writeLitEntropy = 0;511}512if (seqEntropyWritten) {513writeSeqEntropy = 0;514}515}516}517} while (!lastSequence);518if (writeLitEntropy) {519DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten");520ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));521}522if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {523/* If we haven't written our entropy tables, then we've violated our contract and524* must emit an uncompressed block.525*/526DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten");527return 0;528}529if (ip < iend) {530size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock);531DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip));532FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");533assert(cSize != 0);534op += cSize;535/* We have to regenerate the repcodes because we've skipped some sequences */536if (sp < send) {537seqDef const* seq;538repcodes_t rep;539ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep));540for (seq = sstart; seq < sp; ++seq) {541ZSTD_updateRep(rep.rep, seq->offBase - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0);542}543ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep));544}545}546DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed");547return op-ostart;548}549550size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,551void* dst, size_t dstCapacity,552void const* src, size_t srcSize,553unsigned lastBlock) {554ZSTD_entropyCTablesMetadata_t entropyMetadata;555556FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,557&zc->blockState.prevCBlock->entropy,558&zc->blockState.nextCBlock->entropy,559&zc->appliedParams,560&entropyMetadata,561zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");562563return ZSTD_compressSubBlock_multi(&zc->seqStore,564zc->blockState.prevCBlock,565zc->blockState.nextCBlock,566&entropyMetadata,567&zc->appliedParams,568dst, dstCapacity,569src, srcSize,570zc->bmi2, lastBlock,571zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */);572}573574575