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