1*0c16b537SWarner Losh /* ****************************************************************** 2*0c16b537SWarner Losh Huffman encoder, part of New Generation Entropy library 3*0c16b537SWarner Losh Copyright (C) 2013-2016, Yann Collet. 4*0c16b537SWarner Losh 5*0c16b537SWarner Losh BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 6*0c16b537SWarner Losh 7*0c16b537SWarner Losh Redistribution and use in source and binary forms, with or without 8*0c16b537SWarner Losh modification, are permitted provided that the following conditions are 9*0c16b537SWarner Losh met: 10*0c16b537SWarner Losh 11*0c16b537SWarner Losh * Redistributions of source code must retain the above copyright 12*0c16b537SWarner Losh notice, this list of conditions and the following disclaimer. 13*0c16b537SWarner Losh * Redistributions in binary form must reproduce the above 14*0c16b537SWarner Losh copyright notice, this list of conditions and the following disclaimer 15*0c16b537SWarner Losh in the documentation and/or other materials provided with the 16*0c16b537SWarner Losh distribution. 17*0c16b537SWarner Losh 18*0c16b537SWarner Losh THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19*0c16b537SWarner Losh "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20*0c16b537SWarner Losh LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21*0c16b537SWarner Losh A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22*0c16b537SWarner Losh OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23*0c16b537SWarner Losh SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24*0c16b537SWarner Losh LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25*0c16b537SWarner Losh DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26*0c16b537SWarner Losh THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27*0c16b537SWarner Losh (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28*0c16b537SWarner Losh OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29*0c16b537SWarner Losh 30*0c16b537SWarner Losh You can contact the author at : 31*0c16b537SWarner Losh - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy 32*0c16b537SWarner Losh - Public forum : https://groups.google.com/forum/#!forum/lz4c 33*0c16b537SWarner Losh ****************************************************************** */ 34*0c16b537SWarner Losh 35*0c16b537SWarner Losh /* ************************************************************** 36*0c16b537SWarner Losh * Compiler specifics 37*0c16b537SWarner Losh ****************************************************************/ 38*0c16b537SWarner Losh #ifdef _MSC_VER /* Visual Studio */ 39*0c16b537SWarner Losh # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ 40*0c16b537SWarner Losh #endif 41*0c16b537SWarner Losh 42*0c16b537SWarner Losh 43*0c16b537SWarner Losh /* ************************************************************** 44*0c16b537SWarner Losh * Includes 45*0c16b537SWarner Losh ****************************************************************/ 46*0c16b537SWarner Losh #include <string.h> /* memcpy, memset */ 47*0c16b537SWarner Losh #include <stdio.h> /* printf (debug) */ 48*0c16b537SWarner Losh #include "bitstream.h" 49*0c16b537SWarner Losh #define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */ 50*0c16b537SWarner Losh #include "fse.h" /* header compression */ 51*0c16b537SWarner Losh #define HUF_STATIC_LINKING_ONLY 52*0c16b537SWarner Losh #include "huf.h" 53*0c16b537SWarner Losh #include "error_private.h" 54*0c16b537SWarner Losh 55*0c16b537SWarner Losh 56*0c16b537SWarner Losh /* ************************************************************** 57*0c16b537SWarner Losh * Error Management 58*0c16b537SWarner Losh ****************************************************************/ 59*0c16b537SWarner Losh #define HUF_isError ERR_isError 60*0c16b537SWarner Losh #define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ 61*0c16b537SWarner Losh #define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e 62*0c16b537SWarner Losh #define CHECK_F(f) { CHECK_V_F(_var_err__, f); } 63*0c16b537SWarner Losh 64*0c16b537SWarner Losh 65*0c16b537SWarner Losh /* ************************************************************** 66*0c16b537SWarner Losh * Utils 67*0c16b537SWarner Losh ****************************************************************/ 68*0c16b537SWarner Losh unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue) 69*0c16b537SWarner Losh { 70*0c16b537SWarner Losh return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); 71*0c16b537SWarner Losh } 72*0c16b537SWarner Losh 73*0c16b537SWarner Losh 74*0c16b537SWarner Losh /* ******************************************************* 75*0c16b537SWarner Losh * HUF : Huffman block compression 76*0c16b537SWarner Losh *********************************************************/ 77*0c16b537SWarner Losh /* HUF_compressWeights() : 78*0c16b537SWarner Losh * Same as FSE_compress(), but dedicated to huff0's weights compression. 79*0c16b537SWarner Losh * The use case needs much less stack memory. 80*0c16b537SWarner Losh * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX. 81*0c16b537SWarner Losh */ 82*0c16b537SWarner Losh #define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6 83*0c16b537SWarner Losh size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize) 84*0c16b537SWarner Losh { 85*0c16b537SWarner Losh BYTE* const ostart = (BYTE*) dst; 86*0c16b537SWarner Losh BYTE* op = ostart; 87*0c16b537SWarner Losh BYTE* const oend = ostart + dstSize; 88*0c16b537SWarner Losh 89*0c16b537SWarner Losh U32 maxSymbolValue = HUF_TABLELOG_MAX; 90*0c16b537SWarner Losh U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER; 91*0c16b537SWarner Losh 92*0c16b537SWarner Losh FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)]; 93*0c16b537SWarner Losh BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER]; 94*0c16b537SWarner Losh 95*0c16b537SWarner Losh U32 count[HUF_TABLELOG_MAX+1]; 96*0c16b537SWarner Losh S16 norm[HUF_TABLELOG_MAX+1]; 97*0c16b537SWarner Losh 98*0c16b537SWarner Losh /* init conditions */ 99*0c16b537SWarner Losh if (wtSize <= 1) return 0; /* Not compressible */ 100*0c16b537SWarner Losh 101*0c16b537SWarner Losh /* Scan input and build symbol stats */ 102*0c16b537SWarner Losh { CHECK_V_F(maxCount, FSE_count_simple(count, &maxSymbolValue, weightTable, wtSize) ); 103*0c16b537SWarner Losh if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */ 104*0c16b537SWarner Losh if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */ 105*0c16b537SWarner Losh } 106*0c16b537SWarner Losh 107*0c16b537SWarner Losh tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue); 108*0c16b537SWarner Losh CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) ); 109*0c16b537SWarner Losh 110*0c16b537SWarner Losh /* Write table description header */ 111*0c16b537SWarner Losh { CHECK_V_F(hSize, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) ); 112*0c16b537SWarner Losh op += hSize; 113*0c16b537SWarner Losh } 114*0c16b537SWarner Losh 115*0c16b537SWarner Losh /* Compress */ 116*0c16b537SWarner Losh CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) ); 117*0c16b537SWarner Losh { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) ); 118*0c16b537SWarner Losh if (cSize == 0) return 0; /* not enough space for compressed data */ 119*0c16b537SWarner Losh op += cSize; 120*0c16b537SWarner Losh } 121*0c16b537SWarner Losh 122*0c16b537SWarner Losh return op-ostart; 123*0c16b537SWarner Losh } 124*0c16b537SWarner Losh 125*0c16b537SWarner Losh 126*0c16b537SWarner Losh struct HUF_CElt_s { 127*0c16b537SWarner Losh U16 val; 128*0c16b537SWarner Losh BYTE nbBits; 129*0c16b537SWarner Losh }; /* typedef'd to HUF_CElt within "huf.h" */ 130*0c16b537SWarner Losh 131*0c16b537SWarner Losh /*! HUF_writeCTable() : 132*0c16b537SWarner Losh `CTable` : Huffman tree to save, using huf representation. 133*0c16b537SWarner Losh @return : size of saved CTable */ 134*0c16b537SWarner Losh size_t HUF_writeCTable (void* dst, size_t maxDstSize, 135*0c16b537SWarner Losh const HUF_CElt* CTable, U32 maxSymbolValue, U32 huffLog) 136*0c16b537SWarner Losh { 137*0c16b537SWarner Losh BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */ 138*0c16b537SWarner Losh BYTE huffWeight[HUF_SYMBOLVALUE_MAX]; 139*0c16b537SWarner Losh BYTE* op = (BYTE*)dst; 140*0c16b537SWarner Losh U32 n; 141*0c16b537SWarner Losh 142*0c16b537SWarner Losh /* check conditions */ 143*0c16b537SWarner Losh if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge); 144*0c16b537SWarner Losh 145*0c16b537SWarner Losh /* convert to weight */ 146*0c16b537SWarner Losh bitsToWeight[0] = 0; 147*0c16b537SWarner Losh for (n=1; n<huffLog+1; n++) 148*0c16b537SWarner Losh bitsToWeight[n] = (BYTE)(huffLog + 1 - n); 149*0c16b537SWarner Losh for (n=0; n<maxSymbolValue; n++) 150*0c16b537SWarner Losh huffWeight[n] = bitsToWeight[CTable[n].nbBits]; 151*0c16b537SWarner Losh 152*0c16b537SWarner Losh /* attempt weights compression by FSE */ 153*0c16b537SWarner Losh { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) ); 154*0c16b537SWarner Losh if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */ 155*0c16b537SWarner Losh op[0] = (BYTE)hSize; 156*0c16b537SWarner Losh return hSize+1; 157*0c16b537SWarner Losh } } 158*0c16b537SWarner Losh 159*0c16b537SWarner Losh /* write raw values as 4-bits (max : 15) */ 160*0c16b537SWarner Losh if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */ 161*0c16b537SWarner Losh if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */ 162*0c16b537SWarner Losh op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1)); 163*0c16b537SWarner Losh huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */ 164*0c16b537SWarner Losh for (n=0; n<maxSymbolValue; n+=2) 165*0c16b537SWarner Losh op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]); 166*0c16b537SWarner Losh return ((maxSymbolValue+1)/2) + 1; 167*0c16b537SWarner Losh } 168*0c16b537SWarner Losh 169*0c16b537SWarner Losh 170*0c16b537SWarner Losh size_t HUF_readCTable (HUF_CElt* CTable, U32* maxSymbolValuePtr, const void* src, size_t srcSize) 171*0c16b537SWarner Losh { 172*0c16b537SWarner Losh BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */ 173*0c16b537SWarner Losh U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */ 174*0c16b537SWarner Losh U32 tableLog = 0; 175*0c16b537SWarner Losh U32 nbSymbols = 0; 176*0c16b537SWarner Losh 177*0c16b537SWarner Losh /* get symbol weights */ 178*0c16b537SWarner Losh CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize)); 179*0c16b537SWarner Losh 180*0c16b537SWarner Losh /* check result */ 181*0c16b537SWarner Losh if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); 182*0c16b537SWarner Losh if (nbSymbols > *maxSymbolValuePtr+1) return ERROR(maxSymbolValue_tooSmall); 183*0c16b537SWarner Losh 184*0c16b537SWarner Losh /* Prepare base value per rank */ 185*0c16b537SWarner Losh { U32 n, nextRankStart = 0; 186*0c16b537SWarner Losh for (n=1; n<=tableLog; n++) { 187*0c16b537SWarner Losh U32 current = nextRankStart; 188*0c16b537SWarner Losh nextRankStart += (rankVal[n] << (n-1)); 189*0c16b537SWarner Losh rankVal[n] = current; 190*0c16b537SWarner Losh } } 191*0c16b537SWarner Losh 192*0c16b537SWarner Losh /* fill nbBits */ 193*0c16b537SWarner Losh { U32 n; for (n=0; n<nbSymbols; n++) { 194*0c16b537SWarner Losh const U32 w = huffWeight[n]; 195*0c16b537SWarner Losh CTable[n].nbBits = (BYTE)(tableLog + 1 - w); 196*0c16b537SWarner Losh } } 197*0c16b537SWarner Losh 198*0c16b537SWarner Losh /* fill val */ 199*0c16b537SWarner Losh { U16 nbPerRank[HUF_TABLELOG_MAX+2] = {0}; /* support w=0=>n=tableLog+1 */ 200*0c16b537SWarner Losh U16 valPerRank[HUF_TABLELOG_MAX+2] = {0}; 201*0c16b537SWarner Losh { U32 n; for (n=0; n<nbSymbols; n++) nbPerRank[CTable[n].nbBits]++; } 202*0c16b537SWarner Losh /* determine stating value per rank */ 203*0c16b537SWarner Losh valPerRank[tableLog+1] = 0; /* for w==0 */ 204*0c16b537SWarner Losh { U16 min = 0; 205*0c16b537SWarner Losh U32 n; for (n=tableLog; n>0; n--) { /* start at n=tablelog <-> w=1 */ 206*0c16b537SWarner Losh valPerRank[n] = min; /* get starting value within each rank */ 207*0c16b537SWarner Losh min += nbPerRank[n]; 208*0c16b537SWarner Losh min >>= 1; 209*0c16b537SWarner Losh } } 210*0c16b537SWarner Losh /* assign value within rank, symbol order */ 211*0c16b537SWarner Losh { U32 n; for (n=0; n<nbSymbols; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; } 212*0c16b537SWarner Losh } 213*0c16b537SWarner Losh 214*0c16b537SWarner Losh *maxSymbolValuePtr = nbSymbols - 1; 215*0c16b537SWarner Losh return readSize; 216*0c16b537SWarner Losh } 217*0c16b537SWarner Losh 218*0c16b537SWarner Losh 219*0c16b537SWarner Losh typedef struct nodeElt_s { 220*0c16b537SWarner Losh U32 count; 221*0c16b537SWarner Losh U16 parent; 222*0c16b537SWarner Losh BYTE byte; 223*0c16b537SWarner Losh BYTE nbBits; 224*0c16b537SWarner Losh } nodeElt; 225*0c16b537SWarner Losh 226*0c16b537SWarner Losh static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) 227*0c16b537SWarner Losh { 228*0c16b537SWarner Losh const U32 largestBits = huffNode[lastNonNull].nbBits; 229*0c16b537SWarner Losh if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */ 230*0c16b537SWarner Losh 231*0c16b537SWarner Losh /* there are several too large elements (at least >= 2) */ 232*0c16b537SWarner Losh { int totalCost = 0; 233*0c16b537SWarner Losh const U32 baseCost = 1 << (largestBits - maxNbBits); 234*0c16b537SWarner Losh U32 n = lastNonNull; 235*0c16b537SWarner Losh 236*0c16b537SWarner Losh while (huffNode[n].nbBits > maxNbBits) { 237*0c16b537SWarner Losh totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits)); 238*0c16b537SWarner Losh huffNode[n].nbBits = (BYTE)maxNbBits; 239*0c16b537SWarner Losh n --; 240*0c16b537SWarner Losh } /* n stops at huffNode[n].nbBits <= maxNbBits */ 241*0c16b537SWarner Losh while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */ 242*0c16b537SWarner Losh 243*0c16b537SWarner Losh /* renorm totalCost */ 244*0c16b537SWarner Losh totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */ 245*0c16b537SWarner Losh 246*0c16b537SWarner Losh /* repay normalized cost */ 247*0c16b537SWarner Losh { U32 const noSymbol = 0xF0F0F0F0; 248*0c16b537SWarner Losh U32 rankLast[HUF_TABLELOG_MAX+2]; 249*0c16b537SWarner Losh int pos; 250*0c16b537SWarner Losh 251*0c16b537SWarner Losh /* Get pos of last (smallest) symbol per rank */ 252*0c16b537SWarner Losh memset(rankLast, 0xF0, sizeof(rankLast)); 253*0c16b537SWarner Losh { U32 currentNbBits = maxNbBits; 254*0c16b537SWarner Losh for (pos=n ; pos >= 0; pos--) { 255*0c16b537SWarner Losh if (huffNode[pos].nbBits >= currentNbBits) continue; 256*0c16b537SWarner Losh currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ 257*0c16b537SWarner Losh rankLast[maxNbBits-currentNbBits] = pos; 258*0c16b537SWarner Losh } } 259*0c16b537SWarner Losh 260*0c16b537SWarner Losh while (totalCost > 0) { 261*0c16b537SWarner Losh U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1; 262*0c16b537SWarner Losh for ( ; nBitsToDecrease > 1; nBitsToDecrease--) { 263*0c16b537SWarner Losh U32 highPos = rankLast[nBitsToDecrease]; 264*0c16b537SWarner Losh U32 lowPos = rankLast[nBitsToDecrease-1]; 265*0c16b537SWarner Losh if (highPos == noSymbol) continue; 266*0c16b537SWarner Losh if (lowPos == noSymbol) break; 267*0c16b537SWarner Losh { U32 const highTotal = huffNode[highPos].count; 268*0c16b537SWarner Losh U32 const lowTotal = 2 * huffNode[lowPos].count; 269*0c16b537SWarner Losh if (highTotal <= lowTotal) break; 270*0c16b537SWarner Losh } } 271*0c16b537SWarner Losh /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */ 272*0c16b537SWarner Losh /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */ 273*0c16b537SWarner Losh while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) 274*0c16b537SWarner Losh nBitsToDecrease ++; 275*0c16b537SWarner Losh totalCost -= 1 << (nBitsToDecrease-1); 276*0c16b537SWarner Losh if (rankLast[nBitsToDecrease-1] == noSymbol) 277*0c16b537SWarner Losh rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */ 278*0c16b537SWarner Losh huffNode[rankLast[nBitsToDecrease]].nbBits ++; 279*0c16b537SWarner Losh if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */ 280*0c16b537SWarner Losh rankLast[nBitsToDecrease] = noSymbol; 281*0c16b537SWarner Losh else { 282*0c16b537SWarner Losh rankLast[nBitsToDecrease]--; 283*0c16b537SWarner Losh if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease) 284*0c16b537SWarner Losh rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */ 285*0c16b537SWarner Losh } } /* while (totalCost > 0) */ 286*0c16b537SWarner Losh 287*0c16b537SWarner Losh while (totalCost < 0) { /* Sometimes, cost correction overshoot */ 288*0c16b537SWarner Losh if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ 289*0c16b537SWarner Losh while (huffNode[n].nbBits == maxNbBits) n--; 290*0c16b537SWarner Losh huffNode[n+1].nbBits--; 291*0c16b537SWarner Losh rankLast[1] = n+1; 292*0c16b537SWarner Losh totalCost++; 293*0c16b537SWarner Losh continue; 294*0c16b537SWarner Losh } 295*0c16b537SWarner Losh huffNode[ rankLast[1] + 1 ].nbBits--; 296*0c16b537SWarner Losh rankLast[1]++; 297*0c16b537SWarner Losh totalCost ++; 298*0c16b537SWarner Losh } } } /* there are several too large elements (at least >= 2) */ 299*0c16b537SWarner Losh 300*0c16b537SWarner Losh return maxNbBits; 301*0c16b537SWarner Losh } 302*0c16b537SWarner Losh 303*0c16b537SWarner Losh 304*0c16b537SWarner Losh typedef struct { 305*0c16b537SWarner Losh U32 base; 306*0c16b537SWarner Losh U32 current; 307*0c16b537SWarner Losh } rankPos; 308*0c16b537SWarner Losh 309*0c16b537SWarner Losh static void HUF_sort(nodeElt* huffNode, const U32* count, U32 maxSymbolValue) 310*0c16b537SWarner Losh { 311*0c16b537SWarner Losh rankPos rank[32]; 312*0c16b537SWarner Losh U32 n; 313*0c16b537SWarner Losh 314*0c16b537SWarner Losh memset(rank, 0, sizeof(rank)); 315*0c16b537SWarner Losh for (n=0; n<=maxSymbolValue; n++) { 316*0c16b537SWarner Losh U32 r = BIT_highbit32(count[n] + 1); 317*0c16b537SWarner Losh rank[r].base ++; 318*0c16b537SWarner Losh } 319*0c16b537SWarner Losh for (n=30; n>0; n--) rank[n-1].base += rank[n].base; 320*0c16b537SWarner Losh for (n=0; n<32; n++) rank[n].current = rank[n].base; 321*0c16b537SWarner Losh for (n=0; n<=maxSymbolValue; n++) { 322*0c16b537SWarner Losh U32 const c = count[n]; 323*0c16b537SWarner Losh U32 const r = BIT_highbit32(c+1) + 1; 324*0c16b537SWarner Losh U32 pos = rank[r].current++; 325*0c16b537SWarner Losh while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) huffNode[pos]=huffNode[pos-1], pos--; 326*0c16b537SWarner Losh huffNode[pos].count = c; 327*0c16b537SWarner Losh huffNode[pos].byte = (BYTE)n; 328*0c16b537SWarner Losh } 329*0c16b537SWarner Losh } 330*0c16b537SWarner Losh 331*0c16b537SWarner Losh 332*0c16b537SWarner Losh /** HUF_buildCTable_wksp() : 333*0c16b537SWarner Losh * Same as HUF_buildCTable(), but using externally allocated scratch buffer. 334*0c16b537SWarner Losh * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned. 335*0c16b537SWarner Losh */ 336*0c16b537SWarner Losh #define STARTNODE (HUF_SYMBOLVALUE_MAX+1) 337*0c16b537SWarner Losh typedef nodeElt huffNodeTable[2*HUF_SYMBOLVALUE_MAX+1 +1]; 338*0c16b537SWarner Losh size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize) 339*0c16b537SWarner Losh { 340*0c16b537SWarner Losh nodeElt* const huffNode0 = (nodeElt*)workSpace; 341*0c16b537SWarner Losh nodeElt* const huffNode = huffNode0+1; 342*0c16b537SWarner Losh U32 n, nonNullRank; 343*0c16b537SWarner Losh int lowS, lowN; 344*0c16b537SWarner Losh U16 nodeNb = STARTNODE; 345*0c16b537SWarner Losh U32 nodeRoot; 346*0c16b537SWarner Losh 347*0c16b537SWarner Losh /* safety checks */ 348*0c16b537SWarner Losh if (wkspSize < sizeof(huffNodeTable)) return ERROR(GENERIC); /* workSpace is not large enough */ 349*0c16b537SWarner Losh if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; 350*0c16b537SWarner Losh if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(GENERIC); 351*0c16b537SWarner Losh memset(huffNode0, 0, sizeof(huffNodeTable)); 352*0c16b537SWarner Losh 353*0c16b537SWarner Losh /* sort, decreasing order */ 354*0c16b537SWarner Losh HUF_sort(huffNode, count, maxSymbolValue); 355*0c16b537SWarner Losh 356*0c16b537SWarner Losh /* init for parents */ 357*0c16b537SWarner Losh nonNullRank = maxSymbolValue; 358*0c16b537SWarner Losh while(huffNode[nonNullRank].count == 0) nonNullRank--; 359*0c16b537SWarner Losh lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb; 360*0c16b537SWarner Losh huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count; 361*0c16b537SWarner Losh huffNode[lowS].parent = huffNode[lowS-1].parent = nodeNb; 362*0c16b537SWarner Losh nodeNb++; lowS-=2; 363*0c16b537SWarner Losh for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30); 364*0c16b537SWarner Losh huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */ 365*0c16b537SWarner Losh 366*0c16b537SWarner Losh /* create parents */ 367*0c16b537SWarner Losh while (nodeNb <= nodeRoot) { 368*0c16b537SWarner Losh U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; 369*0c16b537SWarner Losh U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++; 370*0c16b537SWarner Losh huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count; 371*0c16b537SWarner Losh huffNode[n1].parent = huffNode[n2].parent = nodeNb; 372*0c16b537SWarner Losh nodeNb++; 373*0c16b537SWarner Losh } 374*0c16b537SWarner Losh 375*0c16b537SWarner Losh /* distribute weights (unlimited tree height) */ 376*0c16b537SWarner Losh huffNode[nodeRoot].nbBits = 0; 377*0c16b537SWarner Losh for (n=nodeRoot-1; n>=STARTNODE; n--) 378*0c16b537SWarner Losh huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1; 379*0c16b537SWarner Losh for (n=0; n<=nonNullRank; n++) 380*0c16b537SWarner Losh huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1; 381*0c16b537SWarner Losh 382*0c16b537SWarner Losh /* enforce maxTableLog */ 383*0c16b537SWarner Losh maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits); 384*0c16b537SWarner Losh 385*0c16b537SWarner Losh /* fill result into tree (val, nbBits) */ 386*0c16b537SWarner Losh { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0}; 387*0c16b537SWarner Losh U16 valPerRank[HUF_TABLELOG_MAX+1] = {0}; 388*0c16b537SWarner Losh if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ 389*0c16b537SWarner Losh for (n=0; n<=nonNullRank; n++) 390*0c16b537SWarner Losh nbPerRank[huffNode[n].nbBits]++; 391*0c16b537SWarner Losh /* determine stating value per rank */ 392*0c16b537SWarner Losh { U16 min = 0; 393*0c16b537SWarner Losh for (n=maxNbBits; n>0; n--) { 394*0c16b537SWarner Losh valPerRank[n] = min; /* get starting value within each rank */ 395*0c16b537SWarner Losh min += nbPerRank[n]; 396*0c16b537SWarner Losh min >>= 1; 397*0c16b537SWarner Losh } } 398*0c16b537SWarner Losh for (n=0; n<=maxSymbolValue; n++) 399*0c16b537SWarner Losh tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */ 400*0c16b537SWarner Losh for (n=0; n<=maxSymbolValue; n++) 401*0c16b537SWarner Losh tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */ 402*0c16b537SWarner Losh } 403*0c16b537SWarner Losh 404*0c16b537SWarner Losh return maxNbBits; 405*0c16b537SWarner Losh } 406*0c16b537SWarner Losh 407*0c16b537SWarner Losh /** HUF_buildCTable() : 408*0c16b537SWarner Losh * Note : count is used before tree is written, so they can safely overlap 409*0c16b537SWarner Losh */ 410*0c16b537SWarner Losh size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits) 411*0c16b537SWarner Losh { 412*0c16b537SWarner Losh huffNodeTable nodeTable; 413*0c16b537SWarner Losh return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, nodeTable, sizeof(nodeTable)); 414*0c16b537SWarner Losh } 415*0c16b537SWarner Losh 416*0c16b537SWarner Losh static size_t HUF_estimateCompressedSize(HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) 417*0c16b537SWarner Losh { 418*0c16b537SWarner Losh size_t nbBits = 0; 419*0c16b537SWarner Losh int s; 420*0c16b537SWarner Losh for (s = 0; s <= (int)maxSymbolValue; ++s) { 421*0c16b537SWarner Losh nbBits += CTable[s].nbBits * count[s]; 422*0c16b537SWarner Losh } 423*0c16b537SWarner Losh return nbBits >> 3; 424*0c16b537SWarner Losh } 425*0c16b537SWarner Losh 426*0c16b537SWarner Losh static int HUF_validateCTable(const HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue) { 427*0c16b537SWarner Losh int bad = 0; 428*0c16b537SWarner Losh int s; 429*0c16b537SWarner Losh for (s = 0; s <= (int)maxSymbolValue; ++s) { 430*0c16b537SWarner Losh bad |= (count[s] != 0) & (CTable[s].nbBits == 0); 431*0c16b537SWarner Losh } 432*0c16b537SWarner Losh return !bad; 433*0c16b537SWarner Losh } 434*0c16b537SWarner Losh 435*0c16b537SWarner Losh static void HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable) 436*0c16b537SWarner Losh { 437*0c16b537SWarner Losh BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits); 438*0c16b537SWarner Losh } 439*0c16b537SWarner Losh 440*0c16b537SWarner Losh size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); } 441*0c16b537SWarner Losh 442*0c16b537SWarner Losh #define HUF_FLUSHBITS(s) BIT_flushBits(s) 443*0c16b537SWarner Losh 444*0c16b537SWarner Losh #define HUF_FLUSHBITS_1(stream) \ 445*0c16b537SWarner Losh if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream) 446*0c16b537SWarner Losh 447*0c16b537SWarner Losh #define HUF_FLUSHBITS_2(stream) \ 448*0c16b537SWarner Losh if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream) 449*0c16b537SWarner Losh 450*0c16b537SWarner Losh size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) 451*0c16b537SWarner Losh { 452*0c16b537SWarner Losh const BYTE* ip = (const BYTE*) src; 453*0c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 454*0c16b537SWarner Losh BYTE* const oend = ostart + dstSize; 455*0c16b537SWarner Losh BYTE* op = ostart; 456*0c16b537SWarner Losh size_t n; 457*0c16b537SWarner Losh BIT_CStream_t bitC; 458*0c16b537SWarner Losh 459*0c16b537SWarner Losh /* init */ 460*0c16b537SWarner Losh if (dstSize < 8) return 0; /* not enough space to compress */ 461*0c16b537SWarner Losh { size_t const initErr = BIT_initCStream(&bitC, op, oend-op); 462*0c16b537SWarner Losh if (HUF_isError(initErr)) return 0; } 463*0c16b537SWarner Losh 464*0c16b537SWarner Losh n = srcSize & ~3; /* join to mod 4 */ 465*0c16b537SWarner Losh switch (srcSize & 3) 466*0c16b537SWarner Losh { 467*0c16b537SWarner Losh case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable); 468*0c16b537SWarner Losh HUF_FLUSHBITS_2(&bitC); 469*0c16b537SWarner Losh /* fall-through */ 470*0c16b537SWarner Losh case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable); 471*0c16b537SWarner Losh HUF_FLUSHBITS_1(&bitC); 472*0c16b537SWarner Losh /* fall-through */ 473*0c16b537SWarner Losh case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable); 474*0c16b537SWarner Losh HUF_FLUSHBITS(&bitC); 475*0c16b537SWarner Losh /* fall-through */ 476*0c16b537SWarner Losh case 0 : /* fall-through */ 477*0c16b537SWarner Losh default: break; 478*0c16b537SWarner Losh } 479*0c16b537SWarner Losh 480*0c16b537SWarner Losh for (; n>0; n-=4) { /* note : n&3==0 at this stage */ 481*0c16b537SWarner Losh HUF_encodeSymbol(&bitC, ip[n- 1], CTable); 482*0c16b537SWarner Losh HUF_FLUSHBITS_1(&bitC); 483*0c16b537SWarner Losh HUF_encodeSymbol(&bitC, ip[n- 2], CTable); 484*0c16b537SWarner Losh HUF_FLUSHBITS_2(&bitC); 485*0c16b537SWarner Losh HUF_encodeSymbol(&bitC, ip[n- 3], CTable); 486*0c16b537SWarner Losh HUF_FLUSHBITS_1(&bitC); 487*0c16b537SWarner Losh HUF_encodeSymbol(&bitC, ip[n- 4], CTable); 488*0c16b537SWarner Losh HUF_FLUSHBITS(&bitC); 489*0c16b537SWarner Losh } 490*0c16b537SWarner Losh 491*0c16b537SWarner Losh return BIT_closeCStream(&bitC); 492*0c16b537SWarner Losh } 493*0c16b537SWarner Losh 494*0c16b537SWarner Losh 495*0c16b537SWarner Losh size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) 496*0c16b537SWarner Losh { 497*0c16b537SWarner Losh size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */ 498*0c16b537SWarner Losh const BYTE* ip = (const BYTE*) src; 499*0c16b537SWarner Losh const BYTE* const iend = ip + srcSize; 500*0c16b537SWarner Losh BYTE* const ostart = (BYTE*) dst; 501*0c16b537SWarner Losh BYTE* const oend = ostart + dstSize; 502*0c16b537SWarner Losh BYTE* op = ostart; 503*0c16b537SWarner Losh 504*0c16b537SWarner Losh if (dstSize < 6 + 1 + 1 + 1 + 8) return 0; /* minimum space to compress successfully */ 505*0c16b537SWarner Losh if (srcSize < 12) return 0; /* no saving possible : too small input */ 506*0c16b537SWarner Losh op += 6; /* jumpTable */ 507*0c16b537SWarner Losh 508*0c16b537SWarner Losh { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) ); 509*0c16b537SWarner Losh if (cSize==0) return 0; 510*0c16b537SWarner Losh MEM_writeLE16(ostart, (U16)cSize); 511*0c16b537SWarner Losh op += cSize; 512*0c16b537SWarner Losh } 513*0c16b537SWarner Losh 514*0c16b537SWarner Losh ip += segmentSize; 515*0c16b537SWarner Losh { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) ); 516*0c16b537SWarner Losh if (cSize==0) return 0; 517*0c16b537SWarner Losh MEM_writeLE16(ostart+2, (U16)cSize); 518*0c16b537SWarner Losh op += cSize; 519*0c16b537SWarner Losh } 520*0c16b537SWarner Losh 521*0c16b537SWarner Losh ip += segmentSize; 522*0c16b537SWarner Losh { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) ); 523*0c16b537SWarner Losh if (cSize==0) return 0; 524*0c16b537SWarner Losh MEM_writeLE16(ostart+4, (U16)cSize); 525*0c16b537SWarner Losh op += cSize; 526*0c16b537SWarner Losh } 527*0c16b537SWarner Losh 528*0c16b537SWarner Losh ip += segmentSize; 529*0c16b537SWarner Losh { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, iend-ip, CTable) ); 530*0c16b537SWarner Losh if (cSize==0) return 0; 531*0c16b537SWarner Losh op += cSize; 532*0c16b537SWarner Losh } 533*0c16b537SWarner Losh 534*0c16b537SWarner Losh return op-ostart; 535*0c16b537SWarner Losh } 536*0c16b537SWarner Losh 537*0c16b537SWarner Losh 538*0c16b537SWarner Losh static size_t HUF_compressCTable_internal( 539*0c16b537SWarner Losh BYTE* const ostart, BYTE* op, BYTE* const oend, 540*0c16b537SWarner Losh const void* src, size_t srcSize, 541*0c16b537SWarner Losh unsigned singleStream, const HUF_CElt* CTable) 542*0c16b537SWarner Losh { 543*0c16b537SWarner Losh size_t const cSize = singleStream ? 544*0c16b537SWarner Losh HUF_compress1X_usingCTable(op, oend - op, src, srcSize, CTable) : 545*0c16b537SWarner Losh HUF_compress4X_usingCTable(op, oend - op, src, srcSize, CTable); 546*0c16b537SWarner Losh if (HUF_isError(cSize)) { return cSize; } 547*0c16b537SWarner Losh if (cSize==0) { return 0; } /* uncompressible */ 548*0c16b537SWarner Losh op += cSize; 549*0c16b537SWarner Losh /* check compressibility */ 550*0c16b537SWarner Losh if ((size_t)(op-ostart) >= srcSize-1) { return 0; } 551*0c16b537SWarner Losh return op-ostart; 552*0c16b537SWarner Losh } 553*0c16b537SWarner Losh 554*0c16b537SWarner Losh 555*0c16b537SWarner Losh /* `workSpace` must a table of at least 1024 unsigned */ 556*0c16b537SWarner Losh static size_t HUF_compress_internal ( 557*0c16b537SWarner Losh void* dst, size_t dstSize, 558*0c16b537SWarner Losh const void* src, size_t srcSize, 559*0c16b537SWarner Losh unsigned maxSymbolValue, unsigned huffLog, 560*0c16b537SWarner Losh unsigned singleStream, 561*0c16b537SWarner Losh void* workSpace, size_t wkspSize, 562*0c16b537SWarner Losh HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat) 563*0c16b537SWarner Losh { 564*0c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 565*0c16b537SWarner Losh BYTE* const oend = ostart + dstSize; 566*0c16b537SWarner Losh BYTE* op = ostart; 567*0c16b537SWarner Losh 568*0c16b537SWarner Losh U32* count; 569*0c16b537SWarner Losh size_t const countSize = sizeof(U32) * (HUF_SYMBOLVALUE_MAX + 1); 570*0c16b537SWarner Losh HUF_CElt* CTable; 571*0c16b537SWarner Losh size_t const CTableSize = sizeof(HUF_CElt) * (HUF_SYMBOLVALUE_MAX + 1); 572*0c16b537SWarner Losh 573*0c16b537SWarner Losh /* checks & inits */ 574*0c16b537SWarner Losh if (wkspSize < sizeof(huffNodeTable) + countSize + CTableSize) return ERROR(GENERIC); 575*0c16b537SWarner Losh if (!srcSize) return 0; /* Uncompressed (note : 1 means rle, so first byte must be correct) */ 576*0c16b537SWarner Losh if (!dstSize) return 0; /* cannot fit within dst budget */ 577*0c16b537SWarner Losh if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */ 578*0c16b537SWarner Losh if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge); 579*0c16b537SWarner Losh if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX; 580*0c16b537SWarner Losh if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT; 581*0c16b537SWarner Losh 582*0c16b537SWarner Losh count = (U32*)workSpace; 583*0c16b537SWarner Losh workSpace = (BYTE*)workSpace + countSize; 584*0c16b537SWarner Losh wkspSize -= countSize; 585*0c16b537SWarner Losh CTable = (HUF_CElt*)workSpace; 586*0c16b537SWarner Losh workSpace = (BYTE*)workSpace + CTableSize; 587*0c16b537SWarner Losh wkspSize -= CTableSize; 588*0c16b537SWarner Losh 589*0c16b537SWarner Losh /* Heuristic : If we don't need to check the validity of the old table use the old table for small inputs */ 590*0c16b537SWarner Losh if (preferRepeat && repeat && *repeat == HUF_repeat_valid) { 591*0c16b537SWarner Losh return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable); 592*0c16b537SWarner Losh } 593*0c16b537SWarner Losh 594*0c16b537SWarner Losh /* Scan input and build symbol stats */ 595*0c16b537SWarner Losh { CHECK_V_F(largest, FSE_count_wksp (count, &maxSymbolValue, (const BYTE*)src, srcSize, (U32*)workSpace) ); 596*0c16b537SWarner Losh if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */ 597*0c16b537SWarner Losh if (largest <= (srcSize >> 7)+1) return 0; /* Fast heuristic : not compressible enough */ 598*0c16b537SWarner Losh } 599*0c16b537SWarner Losh 600*0c16b537SWarner Losh /* Check validity of previous table */ 601*0c16b537SWarner Losh if (repeat && *repeat == HUF_repeat_check && !HUF_validateCTable(oldHufTable, count, maxSymbolValue)) { 602*0c16b537SWarner Losh *repeat = HUF_repeat_none; 603*0c16b537SWarner Losh } 604*0c16b537SWarner Losh /* Heuristic : use existing table for small inputs */ 605*0c16b537SWarner Losh if (preferRepeat && repeat && *repeat != HUF_repeat_none) { 606*0c16b537SWarner Losh return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable); 607*0c16b537SWarner Losh } 608*0c16b537SWarner Losh 609*0c16b537SWarner Losh /* Build Huffman Tree */ 610*0c16b537SWarner Losh huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue); 611*0c16b537SWarner Losh { CHECK_V_F(maxBits, HUF_buildCTable_wksp (CTable, count, maxSymbolValue, huffLog, workSpace, wkspSize) ); 612*0c16b537SWarner Losh huffLog = (U32)maxBits; 613*0c16b537SWarner Losh /* Zero the unused symbols so we can check it for validity */ 614*0c16b537SWarner Losh memset(CTable + maxSymbolValue + 1, 0, CTableSize - (maxSymbolValue + 1) * sizeof(HUF_CElt)); 615*0c16b537SWarner Losh } 616*0c16b537SWarner Losh 617*0c16b537SWarner Losh /* Write table description header */ 618*0c16b537SWarner Losh { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, CTable, maxSymbolValue, huffLog) ); 619*0c16b537SWarner Losh /* Check if using the previous table will be beneficial */ 620*0c16b537SWarner Losh if (repeat && *repeat != HUF_repeat_none) { 621*0c16b537SWarner Losh size_t const oldSize = HUF_estimateCompressedSize(oldHufTable, count, maxSymbolValue); 622*0c16b537SWarner Losh size_t const newSize = HUF_estimateCompressedSize(CTable, count, maxSymbolValue); 623*0c16b537SWarner Losh if (oldSize <= hSize + newSize || hSize + 12 >= srcSize) { 624*0c16b537SWarner Losh return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, oldHufTable); 625*0c16b537SWarner Losh } 626*0c16b537SWarner Losh } 627*0c16b537SWarner Losh /* Use the new table */ 628*0c16b537SWarner Losh if (hSize + 12ul >= srcSize) { return 0; } 629*0c16b537SWarner Losh op += hSize; 630*0c16b537SWarner Losh if (repeat) { *repeat = HUF_repeat_none; } 631*0c16b537SWarner Losh if (oldHufTable) { memcpy(oldHufTable, CTable, CTableSize); } /* Save the new table */ 632*0c16b537SWarner Losh } 633*0c16b537SWarner Losh return HUF_compressCTable_internal(ostart, op, oend, src, srcSize, singleStream, CTable); 634*0c16b537SWarner Losh } 635*0c16b537SWarner Losh 636*0c16b537SWarner Losh 637*0c16b537SWarner Losh size_t HUF_compress1X_wksp (void* dst, size_t dstSize, 638*0c16b537SWarner Losh const void* src, size_t srcSize, 639*0c16b537SWarner Losh unsigned maxSymbolValue, unsigned huffLog, 640*0c16b537SWarner Losh void* workSpace, size_t wkspSize) 641*0c16b537SWarner Losh { 642*0c16b537SWarner Losh return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, NULL, NULL, 0); 643*0c16b537SWarner Losh } 644*0c16b537SWarner Losh 645*0c16b537SWarner Losh size_t HUF_compress1X_repeat (void* dst, size_t dstSize, 646*0c16b537SWarner Losh const void* src, size_t srcSize, 647*0c16b537SWarner Losh unsigned maxSymbolValue, unsigned huffLog, 648*0c16b537SWarner Losh void* workSpace, size_t wkspSize, 649*0c16b537SWarner Losh HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat) 650*0c16b537SWarner Losh { 651*0c16b537SWarner Losh return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize, hufTable, repeat, preferRepeat); 652*0c16b537SWarner Losh } 653*0c16b537SWarner Losh 654*0c16b537SWarner Losh size_t HUF_compress1X (void* dst, size_t dstSize, 655*0c16b537SWarner Losh const void* src, size_t srcSize, 656*0c16b537SWarner Losh unsigned maxSymbolValue, unsigned huffLog) 657*0c16b537SWarner Losh { 658*0c16b537SWarner Losh unsigned workSpace[1024]; 659*0c16b537SWarner Losh return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); 660*0c16b537SWarner Losh } 661*0c16b537SWarner Losh 662*0c16b537SWarner Losh size_t HUF_compress4X_wksp (void* dst, size_t dstSize, 663*0c16b537SWarner Losh const void* src, size_t srcSize, 664*0c16b537SWarner Losh unsigned maxSymbolValue, unsigned huffLog, 665*0c16b537SWarner Losh void* workSpace, size_t wkspSize) 666*0c16b537SWarner Losh { 667*0c16b537SWarner Losh return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, NULL, NULL, 0); 668*0c16b537SWarner Losh } 669*0c16b537SWarner Losh 670*0c16b537SWarner Losh size_t HUF_compress4X_repeat (void* dst, size_t dstSize, 671*0c16b537SWarner Losh const void* src, size_t srcSize, 672*0c16b537SWarner Losh unsigned maxSymbolValue, unsigned huffLog, 673*0c16b537SWarner Losh void* workSpace, size_t wkspSize, 674*0c16b537SWarner Losh HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat) 675*0c16b537SWarner Losh { 676*0c16b537SWarner Losh return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize, hufTable, repeat, preferRepeat); 677*0c16b537SWarner Losh } 678*0c16b537SWarner Losh 679*0c16b537SWarner Losh size_t HUF_compress2 (void* dst, size_t dstSize, 680*0c16b537SWarner Losh const void* src, size_t srcSize, 681*0c16b537SWarner Losh unsigned maxSymbolValue, unsigned huffLog) 682*0c16b537SWarner Losh { 683*0c16b537SWarner Losh unsigned workSpace[1024]; 684*0c16b537SWarner Losh return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace)); 685*0c16b537SWarner Losh } 686*0c16b537SWarner Losh 687*0c16b537SWarner Losh size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize) 688*0c16b537SWarner Losh { 689*0c16b537SWarner Losh return HUF_compress2(dst, maxDstSize, src, (U32)srcSize, 255, HUF_TABLELOG_DEFAULT); 690*0c16b537SWarner Losh } 691