Path: blob/master/Utilities/cmzstd/lib/compress/zstd_compress_superblock.c
3158 views
/*1* Copyright (c) Meta Platforms, Inc. and affiliates.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 unable to compress.39* Or error code */40static size_t41ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,42const ZSTD_hufCTablesMetadata_t* hufMetadata,43const BYTE* literals, size_t litSize,44void* dst, size_t dstSize,45const int bmi2, int writeEntropy, int* entropyWritten)46{47size_t const header = writeEntropy ? 200 : 0;48size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header));49BYTE* const ostart = (BYTE*)dst;50BYTE* const oend = ostart + dstSize;51BYTE* op = ostart + lhSize;52U32 const singleStream = lhSize == 3;53symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat;54size_t cLitSize = 0;5556DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy);5758*entropyWritten = 0;59if (litSize == 0 || hufMetadata->hType == set_basic) {60DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal");61return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);62} else if (hufMetadata->hType == set_rle) {63DEBUGLOG(5, "ZSTD_compressSubBlock_literal using rle literal");64return ZSTD_compressRleLiteralsBlock(dst, dstSize, literals, litSize);65}6667assert(litSize > 0);68assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat);6970if (writeEntropy && hufMetadata->hType == set_compressed) {71ZSTD_memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize);72op += hufMetadata->hufDesSize;73cLitSize += hufMetadata->hufDesSize;74DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize);75}7677{ int const flags = bmi2 ? HUF_flags_bmi2 : 0;78const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable, flags)79: HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable, flags);80op += cSize;81cLitSize += cSize;82if (cSize == 0 || ERR_isError(cSize)) {83DEBUGLOG(5, "Failed to write entropy tables %s", ZSTD_getErrorName(cSize));84return 0;85}86/* If we expand and we aren't writing a header then emit uncompressed */87if (!writeEntropy && cLitSize >= litSize) {88DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal because uncompressible");89return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);90}91/* If we are writing headers then allow expansion that doesn't change our header size. */92if (lhSize < (size_t)(3 + (cLitSize >= 1 KB) + (cLitSize >= 16 KB))) {93assert(cLitSize > litSize);94DEBUGLOG(5, "Literals expanded beyond allowed header size");95return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize);96}97DEBUGLOG(5, "ZSTD_compressSubBlock_literal (cSize=%zu)", cSize);98}99100/* Build header */101switch(lhSize)102{103case 3: /* 2 - 2 - 10 - 10 */104{ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);105MEM_writeLE24(ostart, lhc);106break;107}108case 4: /* 2 - 2 - 14 - 14 */109{ U32 const lhc = hType + (2 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<18);110MEM_writeLE32(ostart, lhc);111break;112}113case 5: /* 2 - 2 - 18 - 18 */114{ U32 const lhc = hType + (3 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<22);115MEM_writeLE32(ostart, lhc);116ostart[4] = (BYTE)(cLitSize >> 10);117break;118}119default: /* not possible : lhSize is {3,4,5} */120assert(0);121}122*entropyWritten = 1;123DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));124return op-ostart;125}126127static size_t128ZSTD_seqDecompressedSize(seqStore_t const* seqStore,129const seqDef* sequences, size_t nbSeq,130size_t litSize, int lastSequence)131{132const seqDef* const sstart = sequences;133const seqDef* const send = sequences + nbSeq;134const seqDef* sp = sstart;135size_t matchLengthSum = 0;136size_t litLengthSum = 0;137(void)(litLengthSum); /* suppress unused variable warning on some environments */138while (send-sp > 0) {139ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp);140litLengthSum += seqLen.litLength;141matchLengthSum += seqLen.matchLength;142sp++;143}144assert(litLengthSum <= litSize);145if (!lastSequence) {146assert(litLengthSum == litSize);147}148return matchLengthSum + litSize;149}150151/** ZSTD_compressSubBlock_sequences() :152* Compresses sequences section for a sub-block.153* fseMetadata->llType, fseMetadata->ofType, and fseMetadata->mlType have154* symbol compression modes for the super-block.155* The first successfully compressed block will have these in its header.156* We set entropyWritten=1 when we succeed in compressing the sequences.157* The following sub-blocks will always have repeat mode.158* @return : compressed size of sequences section of a sub-block159* Or 0 if it is unable to compress160* Or error code. */161static size_t162ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,163const ZSTD_fseCTablesMetadata_t* fseMetadata,164const seqDef* sequences, size_t nbSeq,165const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,166const ZSTD_CCtx_params* cctxParams,167void* dst, size_t dstCapacity,168const int bmi2, int writeEntropy, int* entropyWritten)169{170const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;171BYTE* const ostart = (BYTE*)dst;172BYTE* const oend = ostart + dstCapacity;173BYTE* op = ostart;174BYTE* seqHead;175176DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (nbSeq=%zu, writeEntropy=%d, longOffsets=%d)", nbSeq, writeEntropy, longOffsets);177178*entropyWritten = 0;179/* Sequences Header */180RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,181dstSize_tooSmall, "");182if (nbSeq < 0x7F)183*op++ = (BYTE)nbSeq;184else if (nbSeq < LONGNBSEQ)185op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;186else187op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;188if (nbSeq==0) {189return op - ostart;190}191192/* seqHead : flags for FSE encoding type */193seqHead = op++;194195DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (seqHeadSize=%u)", (unsigned)(op-ostart));196197if (writeEntropy) {198const U32 LLtype = fseMetadata->llType;199const U32 Offtype = fseMetadata->ofType;200const U32 MLtype = fseMetadata->mlType;201DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize);202*seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));203ZSTD_memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize);204op += fseMetadata->fseTablesSize;205} else {206const U32 repeat = set_repeat;207*seqHead = (BYTE)((repeat<<6) + (repeat<<4) + (repeat<<2));208}209210{ size_t const bitstreamSize = ZSTD_encodeSequences(211op, oend - op,212fseTables->matchlengthCTable, mlCode,213fseTables->offcodeCTable, ofCode,214fseTables->litlengthCTable, llCode,215sequences, nbSeq,216longOffsets, bmi2);217FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");218op += bitstreamSize;219/* zstd versions <= 1.3.4 mistakenly report corruption when220* FSE_readNCount() receives a buffer < 4 bytes.221* Fixed by https://github.com/facebook/zstd/pull/1146.222* This can happen when the last set_compressed table present is 2223* bytes and the bitstream is only one byte.224* In this exceedingly rare case, we will simply emit an uncompressed225* block, since it isn't worth optimizing.226*/227#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION228if (writeEntropy && fseMetadata->lastCountSize && fseMetadata->lastCountSize + bitstreamSize < 4) {229/* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */230assert(fseMetadata->lastCountSize + bitstreamSize == 3);231DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "232"emitting an uncompressed block.");233return 0;234}235#endif236DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (bitstreamSize=%zu)", bitstreamSize);237}238239/* zstd versions <= 1.4.0 mistakenly report error when240* sequences section body size is less than 3 bytes.241* Fixed by https://github.com/facebook/zstd/pull/1664.242* This can happen when the previous sequences section block is compressed243* with rle mode and the current block's sequences section is compressed244* with repeat mode where sequences section body size can be 1 byte.245*/246#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION247if (op-seqHead < 4) {248DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.4.0 by emitting "249"an uncompressed block when sequences are < 4 bytes");250return 0;251}252#endif253254*entropyWritten = 1;255return op - ostart;256}257258/** ZSTD_compressSubBlock() :259* Compresses a single sub-block.260* @return : compressed size of the sub-block261* Or 0 if it failed to compress. */262static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,263const ZSTD_entropyCTablesMetadata_t* entropyMetadata,264const seqDef* sequences, size_t nbSeq,265const BYTE* literals, size_t litSize,266const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode,267const ZSTD_CCtx_params* cctxParams,268void* dst, size_t dstCapacity,269const int bmi2,270int writeLitEntropy, int writeSeqEntropy,271int* litEntropyWritten, int* seqEntropyWritten,272U32 lastBlock)273{274BYTE* const ostart = (BYTE*)dst;275BYTE* const oend = ostart + dstCapacity;276BYTE* op = ostart + ZSTD_blockHeaderSize;277DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)",278litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);279{ size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,280&entropyMetadata->hufMetadata, literals, litSize,281op, oend-op, bmi2, writeLitEntropy, litEntropyWritten);282FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");283if (cLitSize == 0) return 0;284op += cLitSize;285}286{ size_t cSeqSize = ZSTD_compressSubBlock_sequences(&entropy->fse,287&entropyMetadata->fseMetadata,288sequences, nbSeq,289llCode, mlCode, ofCode,290cctxParams,291op, oend-op,292bmi2, writeSeqEntropy, seqEntropyWritten);293FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");294if (cSeqSize == 0) return 0;295op += cSeqSize;296}297/* Write block header */298{ size_t cSize = (op-ostart)-ZSTD_blockHeaderSize;299U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);300MEM_writeLE24(ostart, cBlockHeader24);301}302return op-ostart;303}304305static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize,306const ZSTD_hufCTables_t* huf,307const ZSTD_hufCTablesMetadata_t* hufMetadata,308void* workspace, size_t wkspSize,309int writeEntropy)310{311unsigned* const countWksp = (unsigned*)workspace;312unsigned maxSymbolValue = 255;313size_t literalSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */314315if (hufMetadata->hType == set_basic) return litSize;316else if (hufMetadata->hType == set_rle) return 1;317else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) {318size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize);319if (ZSTD_isError(largest)) return litSize;320{ size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue);321if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize;322return cLitSizeEstimate + literalSectionHeaderSize;323} }324assert(0); /* impossible */325return 0;326}327328static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type,329const BYTE* codeTable, unsigned maxCode,330size_t nbSeq, const FSE_CTable* fseCTable,331const U8* additionalBits,332short const* defaultNorm, U32 defaultNormLog, U32 defaultMax,333void* workspace, size_t wkspSize)334{335unsigned* const countWksp = (unsigned*)workspace;336const BYTE* ctp = codeTable;337const BYTE* const ctStart = ctp;338const BYTE* const ctEnd = ctStart + nbSeq;339size_t cSymbolTypeSizeEstimateInBits = 0;340unsigned max = maxCode;341342HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */343if (type == set_basic) {344/* We selected this encoding type, so it must be valid. */345assert(max <= defaultMax);346cSymbolTypeSizeEstimateInBits = max <= defaultMax347? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max)348: ERROR(GENERIC);349} else if (type == set_rle) {350cSymbolTypeSizeEstimateInBits = 0;351} else if (type == set_compressed || type == set_repeat) {352cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max);353}354if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) return nbSeq * 10;355while (ctp < ctEnd) {356if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp];357else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */358ctp++;359}360return cSymbolTypeSizeEstimateInBits / 8;361}362363static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,364const BYTE* llCodeTable,365const BYTE* mlCodeTable,366size_t nbSeq,367const ZSTD_fseCTables_t* fseTables,368const ZSTD_fseCTablesMetadata_t* fseMetadata,369void* workspace, size_t wkspSize,370int writeEntropy)371{372size_t const sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */373size_t cSeqSizeEstimate = 0;374if (nbSeq == 0) return sequencesSectionHeaderSize;375cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff,376nbSeq, fseTables->offcodeCTable, NULL,377OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,378workspace, wkspSize);379cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL,380nbSeq, fseTables->litlengthCTable, LL_bits,381LL_defaultNorm, LL_defaultNormLog, MaxLL,382workspace, wkspSize);383cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML,384nbSeq, fseTables->matchlengthCTable, ML_bits,385ML_defaultNorm, ML_defaultNormLog, MaxML,386workspace, wkspSize);387if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize;388return cSeqSizeEstimate + sequencesSectionHeaderSize;389}390391static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,392const BYTE* ofCodeTable,393const BYTE* llCodeTable,394const BYTE* mlCodeTable,395size_t nbSeq,396const ZSTD_entropyCTables_t* entropy,397const ZSTD_entropyCTablesMetadata_t* entropyMetadata,398void* workspace, size_t wkspSize,399int writeLitEntropy, int writeSeqEntropy) {400size_t cSizeEstimate = 0;401cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize,402&entropy->huf, &entropyMetadata->hufMetadata,403workspace, wkspSize, writeLitEntropy);404cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,405nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,406workspace, wkspSize, writeSeqEntropy);407return cSizeEstimate + ZSTD_blockHeaderSize;408}409410static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)411{412if (fseMetadata->llType == set_compressed || fseMetadata->llType == set_rle)413return 1;414if (fseMetadata->mlType == set_compressed || fseMetadata->mlType == set_rle)415return 1;416if (fseMetadata->ofType == set_compressed || fseMetadata->ofType == set_rle)417return 1;418return 0;419}420421/** ZSTD_compressSubBlock_multi() :422* Breaks super-block into multiple sub-blocks and compresses them.423* Entropy will be written to the first block.424* The following blocks will use repeat mode to compress.425* All sub-blocks are compressed blocks (no raw or rle blocks).426* @return : compressed size of the super block (which is multiple ZSTD blocks)427* Or 0 if it failed to compress. */428static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,429const ZSTD_compressedBlockState_t* prevCBlock,430ZSTD_compressedBlockState_t* nextCBlock,431const ZSTD_entropyCTablesMetadata_t* entropyMetadata,432const ZSTD_CCtx_params* cctxParams,433void* dst, size_t dstCapacity,434const void* src, size_t srcSize,435const int bmi2, U32 lastBlock,436void* workspace, size_t wkspSize)437{438const seqDef* const sstart = seqStorePtr->sequencesStart;439const seqDef* const send = seqStorePtr->sequences;440const seqDef* sp = sstart;441const BYTE* const lstart = seqStorePtr->litStart;442const BYTE* const lend = seqStorePtr->lit;443const BYTE* lp = lstart;444BYTE const* ip = (BYTE const*)src;445BYTE const* const iend = ip + srcSize;446BYTE* const ostart = (BYTE*)dst;447BYTE* const oend = ostart + dstCapacity;448BYTE* op = ostart;449const BYTE* llCodePtr = seqStorePtr->llCode;450const BYTE* mlCodePtr = seqStorePtr->mlCode;451const BYTE* ofCodePtr = seqStorePtr->ofCode;452size_t targetCBlockSize = cctxParams->targetCBlockSize;453size_t litSize, seqCount;454int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed;455int writeSeqEntropy = 1;456int lastSequence = 0;457458DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)",459(unsigned)(lend-lp), (unsigned)(send-sstart));460461litSize = 0;462seqCount = 0;463do {464size_t cBlockSizeEstimate = 0;465if (sstart == send) {466lastSequence = 1;467} else {468const seqDef* const sequence = sp + seqCount;469lastSequence = sequence == send - 1;470litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength;471seqCount++;472}473if (lastSequence) {474assert(lp <= lend);475assert(litSize <= (size_t)(lend - lp));476litSize = (size_t)(lend - lp);477}478/* I think there is an optimization opportunity here.479* Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful480* since it recalculates estimate from scratch.481* For example, it would recount literal distribution and symbol codes every time.482*/483cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount,484&nextCBlock->entropy, entropyMetadata,485workspace, wkspSize, writeLitEntropy, writeSeqEntropy);486if (cBlockSizeEstimate > targetCBlockSize || lastSequence) {487int litEntropyWritten = 0;488int seqEntropyWritten = 0;489const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence);490const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,491sp, seqCount,492lp, litSize,493llCodePtr, mlCodePtr, ofCodePtr,494cctxParams,495op, oend-op,496bmi2, writeLitEntropy, writeSeqEntropy,497&litEntropyWritten, &seqEntropyWritten,498lastBlock && lastSequence);499FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");500if (cSize > 0 && cSize < decompressedSize) {501DEBUGLOG(5, "Committed the sub-block");502assert(ip + decompressedSize <= iend);503ip += decompressedSize;504sp += seqCount;505lp += litSize;506op += cSize;507llCodePtr += seqCount;508mlCodePtr += seqCount;509ofCodePtr += seqCount;510litSize = 0;511seqCount = 0;512/* Entropy only needs to be written once */513if (litEntropyWritten) {514writeLitEntropy = 0;515}516if (seqEntropyWritten) {517writeSeqEntropy = 0;518}519}520}521} while (!lastSequence);522if (writeLitEntropy) {523DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten");524ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));525}526if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {527/* If we haven't written our entropy tables, then we've violated our contract and528* must emit an uncompressed block.529*/530DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten");531return 0;532}533if (ip < iend) {534size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock);535DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip));536FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");537assert(cSize != 0);538op += cSize;539/* We have to regenerate the repcodes because we've skipped some sequences */540if (sp < send) {541seqDef const* seq;542repcodes_t rep;543ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep));544for (seq = sstart; seq < sp; ++seq) {545ZSTD_updateRep(rep.rep, seq->offBase, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0);546}547ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep));548}549}550DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed");551return op-ostart;552}553554size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,555void* dst, size_t dstCapacity,556void const* src, size_t srcSize,557unsigned lastBlock) {558ZSTD_entropyCTablesMetadata_t entropyMetadata;559560FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,561&zc->blockState.prevCBlock->entropy,562&zc->blockState.nextCBlock->entropy,563&zc->appliedParams,564&entropyMetadata,565zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */), "");566567return ZSTD_compressSubBlock_multi(&zc->seqStore,568zc->blockState.prevCBlock,569zc->blockState.nextCBlock,570&entropyMetadata,571&zc->appliedParams,572dst, dstCapacity,573src, srcSize,574zc->bmi2, lastBlock,575zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */);576}577578579