1*37f1f268SConrad Meyer /* 2*37f1f268SConrad Meyer * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc. 3*37f1f268SConrad Meyer * All rights reserved. 4*37f1f268SConrad Meyer * 5*37f1f268SConrad Meyer * This source code is licensed under both the BSD-style license (found in the 6*37f1f268SConrad Meyer * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*37f1f268SConrad Meyer * in the COPYING file in the root directory of this source tree). 8*37f1f268SConrad Meyer * You may select, at your option, one of the above-listed licenses. 9*37f1f268SConrad Meyer */ 10*37f1f268SConrad Meyer 11*37f1f268SConrad Meyer /*-************************************* 12*37f1f268SConrad Meyer * Dependencies 13*37f1f268SConrad Meyer ***************************************/ 14*37f1f268SConrad Meyer #include "zstd_compress_superblock.h" 15*37f1f268SConrad Meyer 16*37f1f268SConrad Meyer #include "../common/zstd_internal.h" /* ZSTD_getSequenceLength */ 17*37f1f268SConrad Meyer #include "hist.h" /* HIST_countFast_wksp */ 18*37f1f268SConrad Meyer #include "zstd_compress_internal.h" 19*37f1f268SConrad Meyer #include "zstd_compress_sequences.h" 20*37f1f268SConrad Meyer #include "zstd_compress_literals.h" 21*37f1f268SConrad Meyer 22*37f1f268SConrad Meyer /*-************************************* 23*37f1f268SConrad Meyer * Superblock entropy buffer structs 24*37f1f268SConrad Meyer ***************************************/ 25*37f1f268SConrad Meyer /** ZSTD_hufCTablesMetadata_t : 26*37f1f268SConrad Meyer * Stores Literals Block Type for a super-block in hType, and 27*37f1f268SConrad Meyer * huffman tree description in hufDesBuffer. 28*37f1f268SConrad Meyer * hufDesSize refers to the size of huffman tree description in bytes. 29*37f1f268SConrad Meyer * This metadata is populated in ZSTD_buildSuperBlockEntropy_literal() */ 30*37f1f268SConrad Meyer typedef struct { 31*37f1f268SConrad Meyer symbolEncodingType_e hType; 32*37f1f268SConrad Meyer BYTE hufDesBuffer[500]; /* TODO give name to this value */ 33*37f1f268SConrad Meyer size_t hufDesSize; 34*37f1f268SConrad Meyer } ZSTD_hufCTablesMetadata_t; 35*37f1f268SConrad Meyer 36*37f1f268SConrad Meyer /** ZSTD_fseCTablesMetadata_t : 37*37f1f268SConrad Meyer * Stores symbol compression modes for a super-block in {ll, ol, ml}Type, and 38*37f1f268SConrad Meyer * fse tables in fseTablesBuffer. 39*37f1f268SConrad Meyer * fseTablesSize refers to the size of fse tables in bytes. 40*37f1f268SConrad Meyer * This metadata is populated in ZSTD_buildSuperBlockEntropy_sequences() */ 41*37f1f268SConrad Meyer typedef struct { 42*37f1f268SConrad Meyer symbolEncodingType_e llType; 43*37f1f268SConrad Meyer symbolEncodingType_e ofType; 44*37f1f268SConrad Meyer symbolEncodingType_e mlType; 45*37f1f268SConrad Meyer BYTE fseTablesBuffer[500]; /* TODO give name to this value */ 46*37f1f268SConrad Meyer size_t fseTablesSize; 47*37f1f268SConrad Meyer size_t lastCountSize; /* This is to account for bug in 1.3.4. More detail in ZSTD_compressSubBlock_sequences() */ 48*37f1f268SConrad Meyer } ZSTD_fseCTablesMetadata_t; 49*37f1f268SConrad Meyer 50*37f1f268SConrad Meyer typedef struct { 51*37f1f268SConrad Meyer ZSTD_hufCTablesMetadata_t hufMetadata; 52*37f1f268SConrad Meyer ZSTD_fseCTablesMetadata_t fseMetadata; 53*37f1f268SConrad Meyer } ZSTD_entropyCTablesMetadata_t; 54*37f1f268SConrad Meyer 55*37f1f268SConrad Meyer 56*37f1f268SConrad Meyer /** ZSTD_buildSuperBlockEntropy_literal() : 57*37f1f268SConrad Meyer * Builds entropy for the super-block literals. 58*37f1f268SConrad Meyer * Stores literals block type (raw, rle, compressed, repeat) and 59*37f1f268SConrad Meyer * huffman description table to hufMetadata. 60*37f1f268SConrad Meyer * @return : size of huffman description table or error code */ 61*37f1f268SConrad Meyer static size_t ZSTD_buildSuperBlockEntropy_literal(void* const src, size_t srcSize, 62*37f1f268SConrad Meyer const ZSTD_hufCTables_t* prevHuf, 63*37f1f268SConrad Meyer ZSTD_hufCTables_t* nextHuf, 64*37f1f268SConrad Meyer ZSTD_hufCTablesMetadata_t* hufMetadata, 65*37f1f268SConrad Meyer const int disableLiteralsCompression, 66*37f1f268SConrad Meyer void* workspace, size_t wkspSize) 67*37f1f268SConrad Meyer { 68*37f1f268SConrad Meyer BYTE* const wkspStart = (BYTE*)workspace; 69*37f1f268SConrad Meyer BYTE* const wkspEnd = wkspStart + wkspSize; 70*37f1f268SConrad Meyer BYTE* const countWkspStart = wkspStart; 71*37f1f268SConrad Meyer unsigned* const countWksp = (unsigned*)workspace; 72*37f1f268SConrad Meyer const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); 73*37f1f268SConrad Meyer BYTE* const nodeWksp = countWkspStart + countWkspSize; 74*37f1f268SConrad Meyer const size_t nodeWkspSize = wkspEnd-nodeWksp; 75*37f1f268SConrad Meyer unsigned maxSymbolValue = 255; 76*37f1f268SConrad Meyer unsigned huffLog = HUF_TABLELOG_DEFAULT; 77*37f1f268SConrad Meyer HUF_repeat repeat = prevHuf->repeatMode; 78*37f1f268SConrad Meyer 79*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_literal (srcSize=%zu)", srcSize); 80*37f1f268SConrad Meyer 81*37f1f268SConrad Meyer /* Prepare nextEntropy assuming reusing the existing table */ 82*37f1f268SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 83*37f1f268SConrad Meyer 84*37f1f268SConrad Meyer if (disableLiteralsCompression) { 85*37f1f268SConrad Meyer DEBUGLOG(5, "set_basic - disabled"); 86*37f1f268SConrad Meyer hufMetadata->hType = set_basic; 87*37f1f268SConrad Meyer return 0; 88*37f1f268SConrad Meyer } 89*37f1f268SConrad Meyer 90*37f1f268SConrad Meyer /* small ? don't even attempt compression (speed opt) */ 91*37f1f268SConrad Meyer # define COMPRESS_LITERALS_SIZE_MIN 63 92*37f1f268SConrad Meyer { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; 93*37f1f268SConrad Meyer if (srcSize <= minLitSize) { 94*37f1f268SConrad Meyer DEBUGLOG(5, "set_basic - too small"); 95*37f1f268SConrad Meyer hufMetadata->hType = set_basic; 96*37f1f268SConrad Meyer return 0; 97*37f1f268SConrad Meyer } 98*37f1f268SConrad Meyer } 99*37f1f268SConrad Meyer 100*37f1f268SConrad Meyer /* Scan input and build symbol stats */ 101*37f1f268SConrad Meyer { size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)src, srcSize, workspace, wkspSize); 102*37f1f268SConrad Meyer FORWARD_IF_ERROR(largest, "HIST_count_wksp failed"); 103*37f1f268SConrad Meyer if (largest == srcSize) { 104*37f1f268SConrad Meyer DEBUGLOG(5, "set_rle"); 105*37f1f268SConrad Meyer hufMetadata->hType = set_rle; 106*37f1f268SConrad Meyer return 0; 107*37f1f268SConrad Meyer } 108*37f1f268SConrad Meyer if (largest <= (srcSize >> 7)+4) { 109*37f1f268SConrad Meyer DEBUGLOG(5, "set_basic - no gain"); 110*37f1f268SConrad Meyer hufMetadata->hType = set_basic; 111*37f1f268SConrad Meyer return 0; 112*37f1f268SConrad Meyer } 113*37f1f268SConrad Meyer } 114*37f1f268SConrad Meyer 115*37f1f268SConrad Meyer /* Validate the previous Huffman table */ 116*37f1f268SConrad Meyer if (repeat == HUF_repeat_check && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) { 117*37f1f268SConrad Meyer repeat = HUF_repeat_none; 118*37f1f268SConrad Meyer } 119*37f1f268SConrad Meyer 120*37f1f268SConrad Meyer /* Build Huffman Tree */ 121*37f1f268SConrad Meyer memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable)); 122*37f1f268SConrad Meyer huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); 123*37f1f268SConrad Meyer { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp, 124*37f1f268SConrad Meyer maxSymbolValue, huffLog, 125*37f1f268SConrad Meyer nodeWksp, nodeWkspSize); 126*37f1f268SConrad Meyer FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp"); 127*37f1f268SConrad Meyer huffLog = (U32)maxBits; 128*37f1f268SConrad Meyer { /* Build and write the CTable */ 129*37f1f268SConrad Meyer size_t const newCSize = HUF_estimateCompressedSize( 130*37f1f268SConrad Meyer (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue); 131*37f1f268SConrad Meyer size_t const hSize = HUF_writeCTable( 132*37f1f268SConrad Meyer hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer), 133*37f1f268SConrad Meyer (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog); 134*37f1f268SConrad Meyer /* Check against repeating the previous CTable */ 135*37f1f268SConrad Meyer if (repeat != HUF_repeat_none) { 136*37f1f268SConrad Meyer size_t const oldCSize = HUF_estimateCompressedSize( 137*37f1f268SConrad Meyer (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue); 138*37f1f268SConrad Meyer if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) { 139*37f1f268SConrad Meyer DEBUGLOG(5, "set_repeat - smaller"); 140*37f1f268SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 141*37f1f268SConrad Meyer hufMetadata->hType = set_repeat; 142*37f1f268SConrad Meyer return 0; 143*37f1f268SConrad Meyer } 144*37f1f268SConrad Meyer } 145*37f1f268SConrad Meyer if (newCSize + hSize >= srcSize) { 146*37f1f268SConrad Meyer DEBUGLOG(5, "set_basic - no gains"); 147*37f1f268SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 148*37f1f268SConrad Meyer hufMetadata->hType = set_basic; 149*37f1f268SConrad Meyer return 0; 150*37f1f268SConrad Meyer } 151*37f1f268SConrad Meyer DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize); 152*37f1f268SConrad Meyer hufMetadata->hType = set_compressed; 153*37f1f268SConrad Meyer nextHuf->repeatMode = HUF_repeat_check; 154*37f1f268SConrad Meyer return hSize; 155*37f1f268SConrad Meyer } 156*37f1f268SConrad Meyer } 157*37f1f268SConrad Meyer } 158*37f1f268SConrad Meyer 159*37f1f268SConrad Meyer /** ZSTD_buildSuperBlockEntropy_sequences() : 160*37f1f268SConrad Meyer * Builds entropy for the super-block sequences. 161*37f1f268SConrad Meyer * Stores symbol compression modes and fse table to fseMetadata. 162*37f1f268SConrad Meyer * @return : size of fse tables or error code */ 163*37f1f268SConrad Meyer static size_t ZSTD_buildSuperBlockEntropy_sequences(seqStore_t* seqStorePtr, 164*37f1f268SConrad Meyer const ZSTD_fseCTables_t* prevEntropy, 165*37f1f268SConrad Meyer ZSTD_fseCTables_t* nextEntropy, 166*37f1f268SConrad Meyer const ZSTD_CCtx_params* cctxParams, 167*37f1f268SConrad Meyer ZSTD_fseCTablesMetadata_t* fseMetadata, 168*37f1f268SConrad Meyer void* workspace, size_t wkspSize) 169*37f1f268SConrad Meyer { 170*37f1f268SConrad Meyer BYTE* const wkspStart = (BYTE*)workspace; 171*37f1f268SConrad Meyer BYTE* const wkspEnd = wkspStart + wkspSize; 172*37f1f268SConrad Meyer BYTE* const countWkspStart = wkspStart; 173*37f1f268SConrad Meyer unsigned* const countWksp = (unsigned*)workspace; 174*37f1f268SConrad Meyer const size_t countWkspSize = (MaxSeq + 1) * sizeof(unsigned); 175*37f1f268SConrad Meyer BYTE* const cTableWksp = countWkspStart + countWkspSize; 176*37f1f268SConrad Meyer const size_t cTableWkspSize = wkspEnd-cTableWksp; 177*37f1f268SConrad Meyer ZSTD_strategy const strategy = cctxParams->cParams.strategy; 178*37f1f268SConrad Meyer FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; 179*37f1f268SConrad Meyer FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; 180*37f1f268SConrad Meyer FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; 181*37f1f268SConrad Meyer const BYTE* const ofCodeTable = seqStorePtr->ofCode; 182*37f1f268SConrad Meyer const BYTE* const llCodeTable = seqStorePtr->llCode; 183*37f1f268SConrad Meyer const BYTE* const mlCodeTable = seqStorePtr->mlCode; 184*37f1f268SConrad Meyer size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; 185*37f1f268SConrad Meyer BYTE* const ostart = fseMetadata->fseTablesBuffer; 186*37f1f268SConrad Meyer BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer); 187*37f1f268SConrad Meyer BYTE* op = ostart; 188*37f1f268SConrad Meyer 189*37f1f268SConrad Meyer assert(cTableWkspSize >= (1 << MaxFSELog) * sizeof(FSE_FUNCTION_TYPE)); 190*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy_sequences (nbSeq=%zu)", nbSeq); 191*37f1f268SConrad Meyer memset(workspace, 0, wkspSize); 192*37f1f268SConrad Meyer 193*37f1f268SConrad Meyer fseMetadata->lastCountSize = 0; 194*37f1f268SConrad Meyer /* convert length/distances into codes */ 195*37f1f268SConrad Meyer ZSTD_seqToCodes(seqStorePtr); 196*37f1f268SConrad Meyer /* build CTable for Literal Lengths */ 197*37f1f268SConrad Meyer { U32 LLtype; 198*37f1f268SConrad Meyer unsigned max = MaxLL; 199*37f1f268SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 200*37f1f268SConrad Meyer DEBUGLOG(5, "Building LL table"); 201*37f1f268SConrad Meyer nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; 202*37f1f268SConrad Meyer LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, 203*37f1f268SConrad Meyer countWksp, max, mostFrequent, nbSeq, 204*37f1f268SConrad Meyer LLFSELog, prevEntropy->litlengthCTable, 205*37f1f268SConrad Meyer LL_defaultNorm, LL_defaultNormLog, 206*37f1f268SConrad Meyer ZSTD_defaultAllowed, strategy); 207*37f1f268SConrad Meyer assert(set_basic < set_compressed && set_rle < set_compressed); 208*37f1f268SConrad Meyer assert(!(LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 209*37f1f268SConrad Meyer { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, 210*37f1f268SConrad Meyer countWksp, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, 211*37f1f268SConrad Meyer prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable), 212*37f1f268SConrad Meyer cTableWksp, cTableWkspSize); 213*37f1f268SConrad Meyer FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed"); 214*37f1f268SConrad Meyer if (LLtype == set_compressed) 215*37f1f268SConrad Meyer fseMetadata->lastCountSize = countSize; 216*37f1f268SConrad Meyer op += countSize; 217*37f1f268SConrad Meyer fseMetadata->llType = (symbolEncodingType_e) LLtype; 218*37f1f268SConrad Meyer } } 219*37f1f268SConrad Meyer /* build CTable for Offsets */ 220*37f1f268SConrad Meyer { U32 Offtype; 221*37f1f268SConrad Meyer unsigned max = MaxOff; 222*37f1f268SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 223*37f1f268SConrad Meyer /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ 224*37f1f268SConrad Meyer ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; 225*37f1f268SConrad Meyer DEBUGLOG(5, "Building OF table"); 226*37f1f268SConrad Meyer nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; 227*37f1f268SConrad Meyer Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, 228*37f1f268SConrad Meyer countWksp, max, mostFrequent, nbSeq, 229*37f1f268SConrad Meyer OffFSELog, prevEntropy->offcodeCTable, 230*37f1f268SConrad Meyer OF_defaultNorm, OF_defaultNormLog, 231*37f1f268SConrad Meyer defaultPolicy, strategy); 232*37f1f268SConrad Meyer assert(!(Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 233*37f1f268SConrad Meyer { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, 234*37f1f268SConrad Meyer countWksp, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 235*37f1f268SConrad Meyer prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable), 236*37f1f268SConrad Meyer cTableWksp, cTableWkspSize); 237*37f1f268SConrad Meyer FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed"); 238*37f1f268SConrad Meyer if (Offtype == set_compressed) 239*37f1f268SConrad Meyer fseMetadata->lastCountSize = countSize; 240*37f1f268SConrad Meyer op += countSize; 241*37f1f268SConrad Meyer fseMetadata->ofType = (symbolEncodingType_e) Offtype; 242*37f1f268SConrad Meyer } } 243*37f1f268SConrad Meyer /* build CTable for MatchLengths */ 244*37f1f268SConrad Meyer { U32 MLtype; 245*37f1f268SConrad Meyer unsigned max = MaxML; 246*37f1f268SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(countWksp, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 247*37f1f268SConrad Meyer DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); 248*37f1f268SConrad Meyer nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; 249*37f1f268SConrad Meyer MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, 250*37f1f268SConrad Meyer countWksp, max, mostFrequent, nbSeq, 251*37f1f268SConrad Meyer MLFSELog, prevEntropy->matchlengthCTable, 252*37f1f268SConrad Meyer ML_defaultNorm, ML_defaultNormLog, 253*37f1f268SConrad Meyer ZSTD_defaultAllowed, strategy); 254*37f1f268SConrad Meyer assert(!(MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 255*37f1f268SConrad Meyer { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, 256*37f1f268SConrad Meyer countWksp, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, 257*37f1f268SConrad Meyer prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable), 258*37f1f268SConrad Meyer cTableWksp, cTableWkspSize); 259*37f1f268SConrad Meyer FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed"); 260*37f1f268SConrad Meyer if (MLtype == set_compressed) 261*37f1f268SConrad Meyer fseMetadata->lastCountSize = countSize; 262*37f1f268SConrad Meyer op += countSize; 263*37f1f268SConrad Meyer fseMetadata->mlType = (symbolEncodingType_e) MLtype; 264*37f1f268SConrad Meyer } } 265*37f1f268SConrad Meyer assert((size_t) (op-ostart) <= sizeof(fseMetadata->fseTablesBuffer)); 266*37f1f268SConrad Meyer return op-ostart; 267*37f1f268SConrad Meyer } 268*37f1f268SConrad Meyer 269*37f1f268SConrad Meyer 270*37f1f268SConrad Meyer /** ZSTD_buildSuperBlockEntropy() : 271*37f1f268SConrad Meyer * Builds entropy for the super-block. 272*37f1f268SConrad Meyer * @return : 0 on success or error code */ 273*37f1f268SConrad Meyer static size_t 274*37f1f268SConrad Meyer ZSTD_buildSuperBlockEntropy(seqStore_t* seqStorePtr, 275*37f1f268SConrad Meyer const ZSTD_entropyCTables_t* prevEntropy, 276*37f1f268SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 277*37f1f268SConrad Meyer const ZSTD_CCtx_params* cctxParams, 278*37f1f268SConrad Meyer ZSTD_entropyCTablesMetadata_t* entropyMetadata, 279*37f1f268SConrad Meyer void* workspace, size_t wkspSize) 280*37f1f268SConrad Meyer { 281*37f1f268SConrad Meyer size_t const litSize = seqStorePtr->lit - seqStorePtr->litStart; 282*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_buildSuperBlockEntropy"); 283*37f1f268SConrad Meyer entropyMetadata->hufMetadata.hufDesSize = 284*37f1f268SConrad Meyer ZSTD_buildSuperBlockEntropy_literal(seqStorePtr->litStart, litSize, 285*37f1f268SConrad Meyer &prevEntropy->huf, &nextEntropy->huf, 286*37f1f268SConrad Meyer &entropyMetadata->hufMetadata, 287*37f1f268SConrad Meyer ZSTD_disableLiteralsCompression(cctxParams), 288*37f1f268SConrad Meyer workspace, wkspSize); 289*37f1f268SConrad Meyer FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildSuperBlockEntropy_literal failed"); 290*37f1f268SConrad Meyer entropyMetadata->fseMetadata.fseTablesSize = 291*37f1f268SConrad Meyer ZSTD_buildSuperBlockEntropy_sequences(seqStorePtr, 292*37f1f268SConrad Meyer &prevEntropy->fse, &nextEntropy->fse, 293*37f1f268SConrad Meyer cctxParams, 294*37f1f268SConrad Meyer &entropyMetadata->fseMetadata, 295*37f1f268SConrad Meyer workspace, wkspSize); 296*37f1f268SConrad Meyer FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildSuperBlockEntropy_sequences failed"); 297*37f1f268SConrad Meyer return 0; 298*37f1f268SConrad Meyer } 299*37f1f268SConrad Meyer 300*37f1f268SConrad Meyer /** ZSTD_compressSubBlock_literal() : 301*37f1f268SConrad Meyer * Compresses literals section for a sub-block. 302*37f1f268SConrad Meyer * When we have to write the Huffman table we will sometimes choose a header 303*37f1f268SConrad Meyer * size larger than necessary. This is because we have to pick the header size 304*37f1f268SConrad Meyer * before we know the table size + compressed size, so we have a bound on the 305*37f1f268SConrad Meyer * table size. If we guessed incorrectly, we fall back to uncompressed literals. 306*37f1f268SConrad Meyer * 307*37f1f268SConrad Meyer * We write the header when writeEntropy=1 and set entropyWrriten=1 when we succeeded 308*37f1f268SConrad Meyer * in writing the header, otherwise it is set to 0. 309*37f1f268SConrad Meyer * 310*37f1f268SConrad Meyer * hufMetadata->hType has literals block type info. 311*37f1f268SConrad Meyer * If it is set_basic, all sub-blocks literals section will be Raw_Literals_Block. 312*37f1f268SConrad Meyer * If it is set_rle, all sub-blocks literals section will be RLE_Literals_Block. 313*37f1f268SConrad Meyer * If it is set_compressed, first sub-block's literals section will be Compressed_Literals_Block 314*37f1f268SConrad Meyer * If it is set_compressed, first sub-block's literals section will be Treeless_Literals_Block 315*37f1f268SConrad Meyer * and the following sub-blocks' literals sections will be Treeless_Literals_Block. 316*37f1f268SConrad Meyer * @return : compressed size of literals section of a sub-block 317*37f1f268SConrad Meyer * Or 0 if it unable to compress. 318*37f1f268SConrad Meyer * Or error code */ 319*37f1f268SConrad Meyer static size_t ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable, 320*37f1f268SConrad Meyer const ZSTD_hufCTablesMetadata_t* hufMetadata, 321*37f1f268SConrad Meyer const BYTE* literals, size_t litSize, 322*37f1f268SConrad Meyer void* dst, size_t dstSize, 323*37f1f268SConrad Meyer const int bmi2, int writeEntropy, int* entropyWritten) 324*37f1f268SConrad Meyer { 325*37f1f268SConrad Meyer size_t const header = writeEntropy ? 200 : 0; 326*37f1f268SConrad Meyer size_t const lhSize = 3 + (litSize >= (1 KB - header)) + (litSize >= (16 KB - header)); 327*37f1f268SConrad Meyer BYTE* const ostart = (BYTE*)dst; 328*37f1f268SConrad Meyer BYTE* const oend = ostart + dstSize; 329*37f1f268SConrad Meyer BYTE* op = ostart + lhSize; 330*37f1f268SConrad Meyer U32 const singleStream = lhSize == 3; 331*37f1f268SConrad Meyer symbolEncodingType_e hType = writeEntropy ? hufMetadata->hType : set_repeat; 332*37f1f268SConrad Meyer size_t cLitSize = 0; 333*37f1f268SConrad Meyer 334*37f1f268SConrad Meyer (void)bmi2; /* TODO bmi2... */ 335*37f1f268SConrad Meyer 336*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_literal (litSize=%zu, lhSize=%zu, writeEntropy=%d)", litSize, lhSize, writeEntropy); 337*37f1f268SConrad Meyer 338*37f1f268SConrad Meyer *entropyWritten = 0; 339*37f1f268SConrad Meyer if (litSize == 0 || hufMetadata->hType == set_basic) { 340*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal"); 341*37f1f268SConrad Meyer return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); 342*37f1f268SConrad Meyer } else if (hufMetadata->hType == set_rle) { 343*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_literal using rle literal"); 344*37f1f268SConrad Meyer return ZSTD_compressRleLiteralsBlock(dst, dstSize, literals, litSize); 345*37f1f268SConrad Meyer } 346*37f1f268SConrad Meyer 347*37f1f268SConrad Meyer assert(litSize > 0); 348*37f1f268SConrad Meyer assert(hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat); 349*37f1f268SConrad Meyer 350*37f1f268SConrad Meyer if (writeEntropy && hufMetadata->hType == set_compressed) { 351*37f1f268SConrad Meyer memcpy(op, hufMetadata->hufDesBuffer, hufMetadata->hufDesSize); 352*37f1f268SConrad Meyer op += hufMetadata->hufDesSize; 353*37f1f268SConrad Meyer cLitSize += hufMetadata->hufDesSize; 354*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_literal (hSize=%zu)", hufMetadata->hufDesSize); 355*37f1f268SConrad Meyer } 356*37f1f268SConrad Meyer 357*37f1f268SConrad Meyer /* TODO bmi2 */ 358*37f1f268SConrad Meyer { const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable) 359*37f1f268SConrad Meyer : HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable); 360*37f1f268SConrad Meyer op += cSize; 361*37f1f268SConrad Meyer cLitSize += cSize; 362*37f1f268SConrad Meyer if (cSize == 0 || ERR_isError(cSize)) { 363*37f1f268SConrad Meyer DEBUGLOG(5, "Failed to write entropy tables %s", ZSTD_getErrorName(cSize)); 364*37f1f268SConrad Meyer return 0; 365*37f1f268SConrad Meyer } 366*37f1f268SConrad Meyer /* If we expand and we aren't writing a header then emit uncompressed */ 367*37f1f268SConrad Meyer if (!writeEntropy && cLitSize >= litSize) { 368*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_literal using raw literal because uncompressible"); 369*37f1f268SConrad Meyer return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); 370*37f1f268SConrad Meyer } 371*37f1f268SConrad Meyer /* If we are writing headers then allow expansion that doesn't change our header size. */ 372*37f1f268SConrad Meyer if (lhSize < (size_t)(3 + (cLitSize >= 1 KB) + (cLitSize >= 16 KB))) { 373*37f1f268SConrad Meyer assert(cLitSize > litSize); 374*37f1f268SConrad Meyer DEBUGLOG(5, "Literals expanded beyond allowed header size"); 375*37f1f268SConrad Meyer return ZSTD_noCompressLiterals(dst, dstSize, literals, litSize); 376*37f1f268SConrad Meyer } 377*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_literal (cSize=%zu)", cSize); 378*37f1f268SConrad Meyer } 379*37f1f268SConrad Meyer 380*37f1f268SConrad Meyer /* Build header */ 381*37f1f268SConrad Meyer switch(lhSize) 382*37f1f268SConrad Meyer { 383*37f1f268SConrad Meyer case 3: /* 2 - 2 - 10 - 10 */ 384*37f1f268SConrad Meyer { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14); 385*37f1f268SConrad Meyer MEM_writeLE24(ostart, lhc); 386*37f1f268SConrad Meyer break; 387*37f1f268SConrad Meyer } 388*37f1f268SConrad Meyer case 4: /* 2 - 2 - 14 - 14 */ 389*37f1f268SConrad Meyer { U32 const lhc = hType + (2 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<18); 390*37f1f268SConrad Meyer MEM_writeLE32(ostart, lhc); 391*37f1f268SConrad Meyer break; 392*37f1f268SConrad Meyer } 393*37f1f268SConrad Meyer case 5: /* 2 - 2 - 18 - 18 */ 394*37f1f268SConrad Meyer { U32 const lhc = hType + (3 << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<22); 395*37f1f268SConrad Meyer MEM_writeLE32(ostart, lhc); 396*37f1f268SConrad Meyer ostart[4] = (BYTE)(cLitSize >> 10); 397*37f1f268SConrad Meyer break; 398*37f1f268SConrad Meyer } 399*37f1f268SConrad Meyer default: /* not possible : lhSize is {3,4,5} */ 400*37f1f268SConrad Meyer assert(0); 401*37f1f268SConrad Meyer } 402*37f1f268SConrad Meyer *entropyWritten = 1; 403*37f1f268SConrad Meyer DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart)); 404*37f1f268SConrad Meyer return op-ostart; 405*37f1f268SConrad Meyer } 406*37f1f268SConrad Meyer 407*37f1f268SConrad Meyer static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef* sequences, size_t nbSeq, size_t litSize, int lastSequence) { 408*37f1f268SConrad Meyer const seqDef* const sstart = sequences; 409*37f1f268SConrad Meyer const seqDef* const send = sequences + nbSeq; 410*37f1f268SConrad Meyer const seqDef* sp = sstart; 411*37f1f268SConrad Meyer size_t matchLengthSum = 0; 412*37f1f268SConrad Meyer size_t litLengthSum = 0; 413*37f1f268SConrad Meyer while (send-sp > 0) { 414*37f1f268SConrad Meyer ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp); 415*37f1f268SConrad Meyer litLengthSum += seqLen.litLength; 416*37f1f268SConrad Meyer matchLengthSum += seqLen.matchLength; 417*37f1f268SConrad Meyer sp++; 418*37f1f268SConrad Meyer } 419*37f1f268SConrad Meyer assert(litLengthSum <= litSize); 420*37f1f268SConrad Meyer if (!lastSequence) { 421*37f1f268SConrad Meyer assert(litLengthSum == litSize); 422*37f1f268SConrad Meyer } 423*37f1f268SConrad Meyer return matchLengthSum + litSize; 424*37f1f268SConrad Meyer } 425*37f1f268SConrad Meyer 426*37f1f268SConrad Meyer /** ZSTD_compressSubBlock_sequences() : 427*37f1f268SConrad Meyer * Compresses sequences section for a sub-block. 428*37f1f268SConrad Meyer * fseMetadata->llType, fseMetadata->ofType, and fseMetadata->mlType have 429*37f1f268SConrad Meyer * symbol compression modes for the super-block. 430*37f1f268SConrad Meyer * The first successfully compressed block will have these in its header. 431*37f1f268SConrad Meyer * We set entropyWritten=1 when we succeed in compressing the sequences. 432*37f1f268SConrad Meyer * The following sub-blocks will always have repeat mode. 433*37f1f268SConrad Meyer * @return : compressed size of sequences section of a sub-block 434*37f1f268SConrad Meyer * Or 0 if it is unable to compress 435*37f1f268SConrad Meyer * Or error code. */ 436*37f1f268SConrad Meyer static size_t ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables, 437*37f1f268SConrad Meyer const ZSTD_fseCTablesMetadata_t* fseMetadata, 438*37f1f268SConrad Meyer const seqDef* sequences, size_t nbSeq, 439*37f1f268SConrad Meyer const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, 440*37f1f268SConrad Meyer const ZSTD_CCtx_params* cctxParams, 441*37f1f268SConrad Meyer void* dst, size_t dstCapacity, 442*37f1f268SConrad Meyer const int bmi2, int writeEntropy, int* entropyWritten) 443*37f1f268SConrad Meyer { 444*37f1f268SConrad Meyer const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; 445*37f1f268SConrad Meyer BYTE* const ostart = (BYTE*)dst; 446*37f1f268SConrad Meyer BYTE* const oend = ostart + dstCapacity; 447*37f1f268SConrad Meyer BYTE* op = ostart; 448*37f1f268SConrad Meyer BYTE* seqHead; 449*37f1f268SConrad Meyer 450*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (nbSeq=%zu, writeEntropy=%d, longOffsets=%d)", nbSeq, writeEntropy, longOffsets); 451*37f1f268SConrad Meyer 452*37f1f268SConrad Meyer *entropyWritten = 0; 453*37f1f268SConrad Meyer /* Sequences Header */ 454*37f1f268SConrad Meyer RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, 455*37f1f268SConrad Meyer dstSize_tooSmall, ""); 456*37f1f268SConrad Meyer if (nbSeq < 0x7F) 457*37f1f268SConrad Meyer *op++ = (BYTE)nbSeq; 458*37f1f268SConrad Meyer else if (nbSeq < LONGNBSEQ) 459*37f1f268SConrad Meyer op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; 460*37f1f268SConrad Meyer else 461*37f1f268SConrad Meyer op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; 462*37f1f268SConrad Meyer if (nbSeq==0) { 463*37f1f268SConrad Meyer return op - ostart; 464*37f1f268SConrad Meyer } 465*37f1f268SConrad Meyer 466*37f1f268SConrad Meyer /* seqHead : flags for FSE encoding type */ 467*37f1f268SConrad Meyer seqHead = op++; 468*37f1f268SConrad Meyer 469*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (seqHeadSize=%u)", (unsigned)(op-ostart)); 470*37f1f268SConrad Meyer 471*37f1f268SConrad Meyer if (writeEntropy) { 472*37f1f268SConrad Meyer const U32 LLtype = fseMetadata->llType; 473*37f1f268SConrad Meyer const U32 Offtype = fseMetadata->ofType; 474*37f1f268SConrad Meyer const U32 MLtype = fseMetadata->mlType; 475*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (fseTablesSize=%zu)", fseMetadata->fseTablesSize); 476*37f1f268SConrad Meyer *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 477*37f1f268SConrad Meyer memcpy(op, fseMetadata->fseTablesBuffer, fseMetadata->fseTablesSize); 478*37f1f268SConrad Meyer op += fseMetadata->fseTablesSize; 479*37f1f268SConrad Meyer } else { 480*37f1f268SConrad Meyer const U32 repeat = set_repeat; 481*37f1f268SConrad Meyer *seqHead = (BYTE)((repeat<<6) + (repeat<<4) + (repeat<<2)); 482*37f1f268SConrad Meyer } 483*37f1f268SConrad Meyer 484*37f1f268SConrad Meyer { size_t const bitstreamSize = ZSTD_encodeSequences( 485*37f1f268SConrad Meyer op, oend - op, 486*37f1f268SConrad Meyer fseTables->matchlengthCTable, mlCode, 487*37f1f268SConrad Meyer fseTables->offcodeCTable, ofCode, 488*37f1f268SConrad Meyer fseTables->litlengthCTable, llCode, 489*37f1f268SConrad Meyer sequences, nbSeq, 490*37f1f268SConrad Meyer longOffsets, bmi2); 491*37f1f268SConrad Meyer FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed"); 492*37f1f268SConrad Meyer op += bitstreamSize; 493*37f1f268SConrad Meyer /* zstd versions <= 1.3.4 mistakenly report corruption when 494*37f1f268SConrad Meyer * FSE_readNCount() receives a buffer < 4 bytes. 495*37f1f268SConrad Meyer * Fixed by https://github.com/facebook/zstd/pull/1146. 496*37f1f268SConrad Meyer * This can happen when the last set_compressed table present is 2 497*37f1f268SConrad Meyer * bytes and the bitstream is only one byte. 498*37f1f268SConrad Meyer * In this exceedingly rare case, we will simply emit an uncompressed 499*37f1f268SConrad Meyer * block, since it isn't worth optimizing. 500*37f1f268SConrad Meyer */ 501*37f1f268SConrad Meyer #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 502*37f1f268SConrad Meyer if (writeEntropy && fseMetadata->lastCountSize && fseMetadata->lastCountSize + bitstreamSize < 4) { 503*37f1f268SConrad Meyer /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ 504*37f1f268SConrad Meyer assert(fseMetadata->lastCountSize + bitstreamSize == 3); 505*37f1f268SConrad Meyer DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " 506*37f1f268SConrad Meyer "emitting an uncompressed block."); 507*37f1f268SConrad Meyer return 0; 508*37f1f268SConrad Meyer } 509*37f1f268SConrad Meyer #endif 510*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_sequences (bitstreamSize=%zu)", bitstreamSize); 511*37f1f268SConrad Meyer } 512*37f1f268SConrad Meyer 513*37f1f268SConrad Meyer /* zstd versions <= 1.4.0 mistakenly report error when 514*37f1f268SConrad Meyer * sequences section body size is less than 3 bytes. 515*37f1f268SConrad Meyer * Fixed by https://github.com/facebook/zstd/pull/1664. 516*37f1f268SConrad Meyer * This can happen when the previous sequences section block is compressed 517*37f1f268SConrad Meyer * with rle mode and the current block's sequences section is compressed 518*37f1f268SConrad Meyer * with repeat mode where sequences section body size can be 1 byte. 519*37f1f268SConrad Meyer */ 520*37f1f268SConrad Meyer #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 521*37f1f268SConrad Meyer if (op-seqHead < 4) { 522*37f1f268SConrad Meyer DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.4.0 by emitting " 523*37f1f268SConrad Meyer "an uncompressed block when sequences are < 4 bytes"); 524*37f1f268SConrad Meyer return 0; 525*37f1f268SConrad Meyer } 526*37f1f268SConrad Meyer #endif 527*37f1f268SConrad Meyer 528*37f1f268SConrad Meyer *entropyWritten = 1; 529*37f1f268SConrad Meyer return op - ostart; 530*37f1f268SConrad Meyer } 531*37f1f268SConrad Meyer 532*37f1f268SConrad Meyer /** ZSTD_compressSubBlock() : 533*37f1f268SConrad Meyer * Compresses a single sub-block. 534*37f1f268SConrad Meyer * @return : compressed size of the sub-block 535*37f1f268SConrad Meyer * Or 0 if it failed to compress. */ 536*37f1f268SConrad Meyer static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy, 537*37f1f268SConrad Meyer const ZSTD_entropyCTablesMetadata_t* entropyMetadata, 538*37f1f268SConrad Meyer const seqDef* sequences, size_t nbSeq, 539*37f1f268SConrad Meyer const BYTE* literals, size_t litSize, 540*37f1f268SConrad Meyer const BYTE* llCode, const BYTE* mlCode, const BYTE* ofCode, 541*37f1f268SConrad Meyer const ZSTD_CCtx_params* cctxParams, 542*37f1f268SConrad Meyer void* dst, size_t dstCapacity, 543*37f1f268SConrad Meyer const int bmi2, 544*37f1f268SConrad Meyer int writeLitEntropy, int writeSeqEntropy, 545*37f1f268SConrad Meyer int* litEntropyWritten, int* seqEntropyWritten, 546*37f1f268SConrad Meyer U32 lastBlock) 547*37f1f268SConrad Meyer { 548*37f1f268SConrad Meyer BYTE* const ostart = (BYTE*)dst; 549*37f1f268SConrad Meyer BYTE* const oend = ostart + dstCapacity; 550*37f1f268SConrad Meyer BYTE* op = ostart + ZSTD_blockHeaderSize; 551*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock (litSize=%zu, nbSeq=%zu, writeLitEntropy=%d, writeSeqEntropy=%d, lastBlock=%d)", 552*37f1f268SConrad Meyer litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock); 553*37f1f268SConrad Meyer { size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable, 554*37f1f268SConrad Meyer &entropyMetadata->hufMetadata, literals, litSize, 555*37f1f268SConrad Meyer op, oend-op, bmi2, writeLitEntropy, litEntropyWritten); 556*37f1f268SConrad Meyer FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed"); 557*37f1f268SConrad Meyer if (cLitSize == 0) return 0; 558*37f1f268SConrad Meyer op += cLitSize; 559*37f1f268SConrad Meyer } 560*37f1f268SConrad Meyer { size_t cSeqSize = ZSTD_compressSubBlock_sequences(&entropy->fse, 561*37f1f268SConrad Meyer &entropyMetadata->fseMetadata, 562*37f1f268SConrad Meyer sequences, nbSeq, 563*37f1f268SConrad Meyer llCode, mlCode, ofCode, 564*37f1f268SConrad Meyer cctxParams, 565*37f1f268SConrad Meyer op, oend-op, 566*37f1f268SConrad Meyer bmi2, writeSeqEntropy, seqEntropyWritten); 567*37f1f268SConrad Meyer FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed"); 568*37f1f268SConrad Meyer if (cSeqSize == 0) return 0; 569*37f1f268SConrad Meyer op += cSeqSize; 570*37f1f268SConrad Meyer } 571*37f1f268SConrad Meyer /* Write block header */ 572*37f1f268SConrad Meyer { size_t cSize = (op-ostart)-ZSTD_blockHeaderSize; 573*37f1f268SConrad Meyer U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 574*37f1f268SConrad Meyer MEM_writeLE24(ostart, cBlockHeader24); 575*37f1f268SConrad Meyer } 576*37f1f268SConrad Meyer return op-ostart; 577*37f1f268SConrad Meyer } 578*37f1f268SConrad Meyer 579*37f1f268SConrad Meyer static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize, 580*37f1f268SConrad Meyer const ZSTD_hufCTables_t* huf, 581*37f1f268SConrad Meyer const ZSTD_hufCTablesMetadata_t* hufMetadata, 582*37f1f268SConrad Meyer void* workspace, size_t wkspSize, 583*37f1f268SConrad Meyer int writeEntropy) 584*37f1f268SConrad Meyer { 585*37f1f268SConrad Meyer unsigned* const countWksp = (unsigned*)workspace; 586*37f1f268SConrad Meyer unsigned maxSymbolValue = 255; 587*37f1f268SConrad Meyer size_t literalSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ 588*37f1f268SConrad Meyer 589*37f1f268SConrad Meyer if (hufMetadata->hType == set_basic) return litSize; 590*37f1f268SConrad Meyer else if (hufMetadata->hType == set_rle) return 1; 591*37f1f268SConrad Meyer else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { 592*37f1f268SConrad Meyer size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); 593*37f1f268SConrad Meyer if (ZSTD_isError(largest)) return litSize; 594*37f1f268SConrad Meyer { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); 595*37f1f268SConrad Meyer if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; 596*37f1f268SConrad Meyer return cLitSizeEstimate + literalSectionHeaderSize; 597*37f1f268SConrad Meyer } } 598*37f1f268SConrad Meyer assert(0); /* impossible */ 599*37f1f268SConrad Meyer return 0; 600*37f1f268SConrad Meyer } 601*37f1f268SConrad Meyer 602*37f1f268SConrad Meyer static size_t ZSTD_estimateSubBlockSize_symbolType(symbolEncodingType_e type, 603*37f1f268SConrad Meyer const BYTE* codeTable, unsigned maxCode, 604*37f1f268SConrad Meyer size_t nbSeq, const FSE_CTable* fseCTable, 605*37f1f268SConrad Meyer const U32* additionalBits, 606*37f1f268SConrad Meyer short const* defaultNorm, U32 defaultNormLog, 607*37f1f268SConrad Meyer void* workspace, size_t wkspSize) 608*37f1f268SConrad Meyer { 609*37f1f268SConrad Meyer unsigned* const countWksp = (unsigned*)workspace; 610*37f1f268SConrad Meyer const BYTE* ctp = codeTable; 611*37f1f268SConrad Meyer const BYTE* const ctStart = ctp; 612*37f1f268SConrad Meyer const BYTE* const ctEnd = ctStart + nbSeq; 613*37f1f268SConrad Meyer size_t cSymbolTypeSizeEstimateInBits = 0; 614*37f1f268SConrad Meyer unsigned max = maxCode; 615*37f1f268SConrad Meyer 616*37f1f268SConrad Meyer HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ 617*37f1f268SConrad Meyer if (type == set_basic) { 618*37f1f268SConrad Meyer cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max); 619*37f1f268SConrad Meyer } else if (type == set_rle) { 620*37f1f268SConrad Meyer cSymbolTypeSizeEstimateInBits = 0; 621*37f1f268SConrad Meyer } else if (type == set_compressed || type == set_repeat) { 622*37f1f268SConrad Meyer cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); 623*37f1f268SConrad Meyer } 624*37f1f268SConrad Meyer if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) return nbSeq * 10; 625*37f1f268SConrad Meyer while (ctp < ctEnd) { 626*37f1f268SConrad Meyer if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; 627*37f1f268SConrad Meyer else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ 628*37f1f268SConrad Meyer ctp++; 629*37f1f268SConrad Meyer } 630*37f1f268SConrad Meyer return cSymbolTypeSizeEstimateInBits / 8; 631*37f1f268SConrad Meyer } 632*37f1f268SConrad Meyer 633*37f1f268SConrad Meyer static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable, 634*37f1f268SConrad Meyer const BYTE* llCodeTable, 635*37f1f268SConrad Meyer const BYTE* mlCodeTable, 636*37f1f268SConrad Meyer size_t nbSeq, 637*37f1f268SConrad Meyer const ZSTD_fseCTables_t* fseTables, 638*37f1f268SConrad Meyer const ZSTD_fseCTablesMetadata_t* fseMetadata, 639*37f1f268SConrad Meyer void* workspace, size_t wkspSize, 640*37f1f268SConrad Meyer int writeEntropy) 641*37f1f268SConrad Meyer { 642*37f1f268SConrad Meyer size_t sequencesSectionHeaderSize = 3; /* Use hard coded size of 3 bytes */ 643*37f1f268SConrad Meyer size_t cSeqSizeEstimate = 0; 644*37f1f268SConrad Meyer cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, MaxOff, 645*37f1f268SConrad Meyer nbSeq, fseTables->offcodeCTable, NULL, 646*37f1f268SConrad Meyer OF_defaultNorm, OF_defaultNormLog, 647*37f1f268SConrad Meyer workspace, wkspSize); 648*37f1f268SConrad Meyer cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->llType, llCodeTable, MaxLL, 649*37f1f268SConrad Meyer nbSeq, fseTables->litlengthCTable, LL_bits, 650*37f1f268SConrad Meyer LL_defaultNorm, LL_defaultNormLog, 651*37f1f268SConrad Meyer workspace, wkspSize); 652*37f1f268SConrad Meyer cSeqSizeEstimate += ZSTD_estimateSubBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, MaxML, 653*37f1f268SConrad Meyer nbSeq, fseTables->matchlengthCTable, ML_bits, 654*37f1f268SConrad Meyer ML_defaultNorm, ML_defaultNormLog, 655*37f1f268SConrad Meyer workspace, wkspSize); 656*37f1f268SConrad Meyer if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; 657*37f1f268SConrad Meyer return cSeqSizeEstimate + sequencesSectionHeaderSize; 658*37f1f268SConrad Meyer } 659*37f1f268SConrad Meyer 660*37f1f268SConrad Meyer static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize, 661*37f1f268SConrad Meyer const BYTE* ofCodeTable, 662*37f1f268SConrad Meyer const BYTE* llCodeTable, 663*37f1f268SConrad Meyer const BYTE* mlCodeTable, 664*37f1f268SConrad Meyer size_t nbSeq, 665*37f1f268SConrad Meyer const ZSTD_entropyCTables_t* entropy, 666*37f1f268SConrad Meyer const ZSTD_entropyCTablesMetadata_t* entropyMetadata, 667*37f1f268SConrad Meyer void* workspace, size_t wkspSize, 668*37f1f268SConrad Meyer int writeLitEntropy, int writeSeqEntropy) { 669*37f1f268SConrad Meyer size_t cSizeEstimate = 0; 670*37f1f268SConrad Meyer cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize, 671*37f1f268SConrad Meyer &entropy->huf, &entropyMetadata->hufMetadata, 672*37f1f268SConrad Meyer workspace, wkspSize, writeLitEntropy); 673*37f1f268SConrad Meyer cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, 674*37f1f268SConrad Meyer nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, 675*37f1f268SConrad Meyer workspace, wkspSize, writeSeqEntropy); 676*37f1f268SConrad Meyer return cSizeEstimate + ZSTD_blockHeaderSize; 677*37f1f268SConrad Meyer } 678*37f1f268SConrad Meyer 679*37f1f268SConrad Meyer static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata) 680*37f1f268SConrad Meyer { 681*37f1f268SConrad Meyer if (fseMetadata->llType == set_compressed || fseMetadata->llType == set_rle) 682*37f1f268SConrad Meyer return 1; 683*37f1f268SConrad Meyer if (fseMetadata->mlType == set_compressed || fseMetadata->mlType == set_rle) 684*37f1f268SConrad Meyer return 1; 685*37f1f268SConrad Meyer if (fseMetadata->ofType == set_compressed || fseMetadata->ofType == set_rle) 686*37f1f268SConrad Meyer return 1; 687*37f1f268SConrad Meyer return 0; 688*37f1f268SConrad Meyer } 689*37f1f268SConrad Meyer 690*37f1f268SConrad Meyer /** ZSTD_compressSubBlock_multi() : 691*37f1f268SConrad Meyer * Breaks super-block into multiple sub-blocks and compresses them. 692*37f1f268SConrad Meyer * Entropy will be written to the first block. 693*37f1f268SConrad Meyer * The following blocks will use repeat mode to compress. 694*37f1f268SConrad Meyer * All sub-blocks are compressed blocks (no raw or rle blocks). 695*37f1f268SConrad Meyer * @return : compressed size of the super block (which is multiple ZSTD blocks) 696*37f1f268SConrad Meyer * Or 0 if it failed to compress. */ 697*37f1f268SConrad Meyer static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr, 698*37f1f268SConrad Meyer const ZSTD_compressedBlockState_t* prevCBlock, 699*37f1f268SConrad Meyer ZSTD_compressedBlockState_t* nextCBlock, 700*37f1f268SConrad Meyer const ZSTD_entropyCTablesMetadata_t* entropyMetadata, 701*37f1f268SConrad Meyer const ZSTD_CCtx_params* cctxParams, 702*37f1f268SConrad Meyer void* dst, size_t dstCapacity, 703*37f1f268SConrad Meyer const void* src, size_t srcSize, 704*37f1f268SConrad Meyer const int bmi2, U32 lastBlock, 705*37f1f268SConrad Meyer void* workspace, size_t wkspSize) 706*37f1f268SConrad Meyer { 707*37f1f268SConrad Meyer const seqDef* const sstart = seqStorePtr->sequencesStart; 708*37f1f268SConrad Meyer const seqDef* const send = seqStorePtr->sequences; 709*37f1f268SConrad Meyer const seqDef* sp = sstart; 710*37f1f268SConrad Meyer const BYTE* const lstart = seqStorePtr->litStart; 711*37f1f268SConrad Meyer const BYTE* const lend = seqStorePtr->lit; 712*37f1f268SConrad Meyer const BYTE* lp = lstart; 713*37f1f268SConrad Meyer BYTE const* ip = (BYTE const*)src; 714*37f1f268SConrad Meyer BYTE const* const iend = ip + srcSize; 715*37f1f268SConrad Meyer BYTE* const ostart = (BYTE*)dst; 716*37f1f268SConrad Meyer BYTE* const oend = ostart + dstCapacity; 717*37f1f268SConrad Meyer BYTE* op = ostart; 718*37f1f268SConrad Meyer const BYTE* llCodePtr = seqStorePtr->llCode; 719*37f1f268SConrad Meyer const BYTE* mlCodePtr = seqStorePtr->mlCode; 720*37f1f268SConrad Meyer const BYTE* ofCodePtr = seqStorePtr->ofCode; 721*37f1f268SConrad Meyer size_t targetCBlockSize = cctxParams->targetCBlockSize; 722*37f1f268SConrad Meyer size_t litSize, seqCount; 723*37f1f268SConrad Meyer int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed; 724*37f1f268SConrad Meyer int writeSeqEntropy = 1; 725*37f1f268SConrad Meyer int lastSequence = 0; 726*37f1f268SConrad Meyer 727*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)", 728*37f1f268SConrad Meyer (unsigned)(lend-lp), (unsigned)(send-sstart)); 729*37f1f268SConrad Meyer 730*37f1f268SConrad Meyer litSize = 0; 731*37f1f268SConrad Meyer seqCount = 0; 732*37f1f268SConrad Meyer do { 733*37f1f268SConrad Meyer size_t cBlockSizeEstimate = 0; 734*37f1f268SConrad Meyer if (sstart == send) { 735*37f1f268SConrad Meyer lastSequence = 1; 736*37f1f268SConrad Meyer } else { 737*37f1f268SConrad Meyer const seqDef* const sequence = sp + seqCount; 738*37f1f268SConrad Meyer lastSequence = sequence == send - 1; 739*37f1f268SConrad Meyer litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength; 740*37f1f268SConrad Meyer seqCount++; 741*37f1f268SConrad Meyer } 742*37f1f268SConrad Meyer if (lastSequence) { 743*37f1f268SConrad Meyer assert(lp <= lend); 744*37f1f268SConrad Meyer assert(litSize <= (size_t)(lend - lp)); 745*37f1f268SConrad Meyer litSize = (size_t)(lend - lp); 746*37f1f268SConrad Meyer } 747*37f1f268SConrad Meyer /* I think there is an optimization opportunity here. 748*37f1f268SConrad Meyer * Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful 749*37f1f268SConrad Meyer * since it recalculates estimate from scratch. 750*37f1f268SConrad Meyer * For example, it would recount literal distribution and symbol codes everytime. 751*37f1f268SConrad Meyer */ 752*37f1f268SConrad Meyer cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount, 753*37f1f268SConrad Meyer &nextCBlock->entropy, entropyMetadata, 754*37f1f268SConrad Meyer workspace, wkspSize, writeLitEntropy, writeSeqEntropy); 755*37f1f268SConrad Meyer if (cBlockSizeEstimate > targetCBlockSize || lastSequence) { 756*37f1f268SConrad Meyer int litEntropyWritten = 0; 757*37f1f268SConrad Meyer int seqEntropyWritten = 0; 758*37f1f268SConrad Meyer const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence); 759*37f1f268SConrad Meyer const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata, 760*37f1f268SConrad Meyer sp, seqCount, 761*37f1f268SConrad Meyer lp, litSize, 762*37f1f268SConrad Meyer llCodePtr, mlCodePtr, ofCodePtr, 763*37f1f268SConrad Meyer cctxParams, 764*37f1f268SConrad Meyer op, oend-op, 765*37f1f268SConrad Meyer bmi2, writeLitEntropy, writeSeqEntropy, 766*37f1f268SConrad Meyer &litEntropyWritten, &seqEntropyWritten, 767*37f1f268SConrad Meyer lastBlock && lastSequence); 768*37f1f268SConrad Meyer FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed"); 769*37f1f268SConrad Meyer if (cSize > 0 && cSize < decompressedSize) { 770*37f1f268SConrad Meyer DEBUGLOG(5, "Committed the sub-block"); 771*37f1f268SConrad Meyer assert(ip + decompressedSize <= iend); 772*37f1f268SConrad Meyer ip += decompressedSize; 773*37f1f268SConrad Meyer sp += seqCount; 774*37f1f268SConrad Meyer lp += litSize; 775*37f1f268SConrad Meyer op += cSize; 776*37f1f268SConrad Meyer llCodePtr += seqCount; 777*37f1f268SConrad Meyer mlCodePtr += seqCount; 778*37f1f268SConrad Meyer ofCodePtr += seqCount; 779*37f1f268SConrad Meyer litSize = 0; 780*37f1f268SConrad Meyer seqCount = 0; 781*37f1f268SConrad Meyer /* Entropy only needs to be written once */ 782*37f1f268SConrad Meyer if (litEntropyWritten) { 783*37f1f268SConrad Meyer writeLitEntropy = 0; 784*37f1f268SConrad Meyer } 785*37f1f268SConrad Meyer if (seqEntropyWritten) { 786*37f1f268SConrad Meyer writeSeqEntropy = 0; 787*37f1f268SConrad Meyer } 788*37f1f268SConrad Meyer } 789*37f1f268SConrad Meyer } 790*37f1f268SConrad Meyer } while (!lastSequence); 791*37f1f268SConrad Meyer if (writeLitEntropy) { 792*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten"); 793*37f1f268SConrad Meyer memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf)); 794*37f1f268SConrad Meyer } 795*37f1f268SConrad Meyer if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) { 796*37f1f268SConrad Meyer /* If we haven't written our entropy tables, then we've violated our contract and 797*37f1f268SConrad Meyer * must emit an uncompressed block. 798*37f1f268SConrad Meyer */ 799*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten"); 800*37f1f268SConrad Meyer return 0; 801*37f1f268SConrad Meyer } 802*37f1f268SConrad Meyer if (ip < iend) { 803*37f1f268SConrad Meyer size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock); 804*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip)); 805*37f1f268SConrad Meyer FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); 806*37f1f268SConrad Meyer assert(cSize != 0); 807*37f1f268SConrad Meyer op += cSize; 808*37f1f268SConrad Meyer /* We have to regenerate the repcodes because we've skipped some sequences */ 809*37f1f268SConrad Meyer if (sp < send) { 810*37f1f268SConrad Meyer seqDef const* seq; 811*37f1f268SConrad Meyer repcodes_t rep; 812*37f1f268SConrad Meyer memcpy(&rep, prevCBlock->rep, sizeof(rep)); 813*37f1f268SConrad Meyer for (seq = sstart; seq < sp; ++seq) { 814*37f1f268SConrad Meyer rep = ZSTD_updateRep(rep.rep, seq->offset - 1, ZSTD_getSequenceLength(seqStorePtr, seq).litLength == 0); 815*37f1f268SConrad Meyer } 816*37f1f268SConrad Meyer memcpy(nextCBlock->rep, &rep, sizeof(rep)); 817*37f1f268SConrad Meyer } 818*37f1f268SConrad Meyer } 819*37f1f268SConrad Meyer DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed"); 820*37f1f268SConrad Meyer return op-ostart; 821*37f1f268SConrad Meyer } 822*37f1f268SConrad Meyer 823*37f1f268SConrad Meyer size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc, 824*37f1f268SConrad Meyer void* dst, size_t dstCapacity, 825*37f1f268SConrad Meyer void const* src, size_t srcSize, 826*37f1f268SConrad Meyer unsigned lastBlock) { 827*37f1f268SConrad Meyer ZSTD_entropyCTablesMetadata_t entropyMetadata; 828*37f1f268SConrad Meyer 829*37f1f268SConrad Meyer FORWARD_IF_ERROR(ZSTD_buildSuperBlockEntropy(&zc->seqStore, 830*37f1f268SConrad Meyer &zc->blockState.prevCBlock->entropy, 831*37f1f268SConrad Meyer &zc->blockState.nextCBlock->entropy, 832*37f1f268SConrad Meyer &zc->appliedParams, 833*37f1f268SConrad Meyer &entropyMetadata, 834*37f1f268SConrad Meyer zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */), ""); 835*37f1f268SConrad Meyer 836*37f1f268SConrad Meyer return ZSTD_compressSubBlock_multi(&zc->seqStore, 837*37f1f268SConrad Meyer zc->blockState.prevCBlock, 838*37f1f268SConrad Meyer zc->blockState.nextCBlock, 839*37f1f268SConrad Meyer &entropyMetadata, 840*37f1f268SConrad Meyer &zc->appliedParams, 841*37f1f268SConrad Meyer dst, dstCapacity, 842*37f1f268SConrad Meyer src, srcSize, 843*37f1f268SConrad Meyer zc->bmi2, lastBlock, 844*37f1f268SConrad Meyer zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */); 845*37f1f268SConrad Meyer } 846