10c16b537SWarner Losh /* ****************************************************************** 20c16b537SWarner Losh bitstream 30c16b537SWarner Losh Part of FSE library 40f743729SConrad Meyer Copyright (C) 2013-present, Yann Collet. 50c16b537SWarner Losh 60c16b537SWarner Losh BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 70c16b537SWarner Losh 80c16b537SWarner Losh Redistribution and use in source and binary forms, with or without 90c16b537SWarner Losh modification, are permitted provided that the following conditions are 100c16b537SWarner Losh met: 110c16b537SWarner Losh 120c16b537SWarner Losh * Redistributions of source code must retain the above copyright 130c16b537SWarner Losh notice, this list of conditions and the following disclaimer. 140c16b537SWarner Losh * Redistributions in binary form must reproduce the above 150c16b537SWarner Losh copyright notice, this list of conditions and the following disclaimer 160c16b537SWarner Losh in the documentation and/or other materials provided with the 170c16b537SWarner Losh distribution. 180c16b537SWarner Losh 190c16b537SWarner Losh THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 200c16b537SWarner Losh "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 210c16b537SWarner Losh LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 220c16b537SWarner Losh A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 230c16b537SWarner Losh OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 240c16b537SWarner Losh SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 250c16b537SWarner Losh LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 260c16b537SWarner Losh DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 270c16b537SWarner Losh THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 280c16b537SWarner Losh (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 290c16b537SWarner Losh OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 300c16b537SWarner Losh 310c16b537SWarner Losh You can contact the author at : 320c16b537SWarner Losh - Source repository : https://github.com/Cyan4973/FiniteStateEntropy 330c16b537SWarner Losh ****************************************************************** */ 340c16b537SWarner Losh #ifndef BITSTREAM_H_MODULE 350c16b537SWarner Losh #define BITSTREAM_H_MODULE 360c16b537SWarner Losh 370c16b537SWarner Losh #if defined (__cplusplus) 380c16b537SWarner Losh extern "C" { 390c16b537SWarner Losh #endif 400c16b537SWarner Losh 410c16b537SWarner Losh /* 420c16b537SWarner Losh * This API consists of small unitary functions, which must be inlined for best performance. 430c16b537SWarner Losh * Since link-time-optimization is not available for all compilers, 440c16b537SWarner Losh * these functions are defined into a .h to be included. 450c16b537SWarner Losh */ 460c16b537SWarner Losh 470c16b537SWarner Losh /*-**************************************** 480c16b537SWarner Losh * Dependencies 490c16b537SWarner Losh ******************************************/ 500c16b537SWarner Losh #include "mem.h" /* unaligned access routines */ 510f743729SConrad Meyer #include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */ 520c16b537SWarner Losh #include "error_private.h" /* error codes and messages */ 530c16b537SWarner Losh 540c16b537SWarner Losh 550c16b537SWarner Losh /*========================================= 560c16b537SWarner Losh * Target specific 570c16b537SWarner Losh =========================================*/ 580c16b537SWarner Losh #if defined(__BMI__) && defined(__GNUC__) 590c16b537SWarner Losh # include <immintrin.h> /* support for bextr (experimental) */ 600c16b537SWarner Losh #endif 610c16b537SWarner Losh 620c16b537SWarner Losh #define STREAM_ACCUMULATOR_MIN_32 25 630c16b537SWarner Losh #define STREAM_ACCUMULATOR_MIN_64 57 640c16b537SWarner Losh #define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 : STREAM_ACCUMULATOR_MIN_64)) 650c16b537SWarner Losh 660c16b537SWarner Losh 670c16b537SWarner Losh /*-****************************************** 680c16b537SWarner Losh * bitStream encoding API (write forward) 690c16b537SWarner Losh ********************************************/ 700c16b537SWarner Losh /* bitStream can mix input from multiple sources. 710c16b537SWarner Losh * A critical property of these streams is that they encode and decode in **reverse** direction. 720c16b537SWarner Losh * So the first bit sequence you add will be the last to be read, like a LIFO stack. 730c16b537SWarner Losh */ 740f743729SConrad Meyer typedef struct { 750c16b537SWarner Losh size_t bitContainer; 760c16b537SWarner Losh unsigned bitPos; 770c16b537SWarner Losh char* startPtr; 780c16b537SWarner Losh char* ptr; 790c16b537SWarner Losh char* endPtr; 800c16b537SWarner Losh } BIT_CStream_t; 810c16b537SWarner Losh 820c16b537SWarner Losh MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity); 830c16b537SWarner Losh MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits); 840c16b537SWarner Losh MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC); 850c16b537SWarner Losh MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); 860c16b537SWarner Losh 870c16b537SWarner Losh /* Start with initCStream, providing the size of buffer to write into. 880c16b537SWarner Losh * bitStream will never write outside of this buffer. 890c16b537SWarner Losh * `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code. 900c16b537SWarner Losh * 910c16b537SWarner Losh * bits are first added to a local register. 920c16b537SWarner Losh * Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems. 930c16b537SWarner Losh * Writing data into memory is an explicit operation, performed by the flushBits function. 940c16b537SWarner Losh * Hence keep track how many bits are potentially stored into local register to avoid register overflow. 950c16b537SWarner Losh * After a flushBits, a maximum of 7 bits might still be stored into local register. 960c16b537SWarner Losh * 970c16b537SWarner Losh * Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers. 980c16b537SWarner Losh * 990c16b537SWarner Losh * Last operation is to close the bitStream. 1000c16b537SWarner Losh * The function returns the final size of CStream in bytes. 1010c16b537SWarner Losh * If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable) 1020c16b537SWarner Losh */ 1030c16b537SWarner Losh 1040c16b537SWarner Losh 1050c16b537SWarner Losh /*-******************************************** 1060c16b537SWarner Losh * bitStream decoding API (read backward) 1070c16b537SWarner Losh **********************************************/ 1080f743729SConrad Meyer typedef struct { 1090c16b537SWarner Losh size_t bitContainer; 1100c16b537SWarner Losh unsigned bitsConsumed; 1110c16b537SWarner Losh const char* ptr; 1120c16b537SWarner Losh const char* start; 1130c16b537SWarner Losh const char* limitPtr; 1140c16b537SWarner Losh } BIT_DStream_t; 1150c16b537SWarner Losh 1160c16b537SWarner Losh typedef enum { BIT_DStream_unfinished = 0, 1170c16b537SWarner Losh BIT_DStream_endOfBuffer = 1, 1180c16b537SWarner Losh BIT_DStream_completed = 2, 1190c16b537SWarner Losh BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */ 1200c16b537SWarner Losh /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */ 1210c16b537SWarner Losh 1220c16b537SWarner Losh MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize); 1230c16b537SWarner Losh MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits); 1240c16b537SWarner Losh MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); 1250c16b537SWarner Losh MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); 1260c16b537SWarner Losh 1270c16b537SWarner Losh 1280c16b537SWarner Losh /* Start by invoking BIT_initDStream(). 1290c16b537SWarner Losh * A chunk of the bitStream is then stored into a local register. 1300c16b537SWarner Losh * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). 1310c16b537SWarner Losh * You can then retrieve bitFields stored into the local register, **in reverse order**. 1320c16b537SWarner Losh * Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. 1330c16b537SWarner Losh * A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished. 1340c16b537SWarner Losh * Otherwise, it can be less than that, so proceed accordingly. 1350c16b537SWarner Losh * Checking if DStream has reached its end can be performed with BIT_endOfDStream(). 1360c16b537SWarner Losh */ 1370c16b537SWarner Losh 1380c16b537SWarner Losh 1390c16b537SWarner Losh /*-**************************************** 1400c16b537SWarner Losh * unsafe API 1410c16b537SWarner Losh ******************************************/ 1420c16b537SWarner Losh MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits); 1430c16b537SWarner Losh /* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */ 1440c16b537SWarner Losh 1450c16b537SWarner Losh MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC); 1460c16b537SWarner Losh /* unsafe version; does not check buffer overflow */ 1470c16b537SWarner Losh 1480c16b537SWarner Losh MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits); 1490c16b537SWarner Losh /* faster, but works only if nbBits >= 1 */ 1500c16b537SWarner Losh 1510c16b537SWarner Losh 1520c16b537SWarner Losh 1530c16b537SWarner Losh /*-************************************************************** 1540c16b537SWarner Losh * Internal functions 1550c16b537SWarner Losh ****************************************************************/ 156052d3c12SConrad Meyer MEM_STATIC unsigned BIT_highbit32 (U32 val) 1570c16b537SWarner Losh { 1580c16b537SWarner Losh assert(val != 0); 1590c16b537SWarner Losh { 1600c16b537SWarner Losh # if defined(_MSC_VER) /* Visual */ 1610c16b537SWarner Losh unsigned long r=0; 1620c16b537SWarner Losh _BitScanReverse ( &r, val ); 1630c16b537SWarner Losh return (unsigned) r; 1640f743729SConrad Meyer # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */ 1650c16b537SWarner Losh return 31 - __builtin_clz (val); 1660c16b537SWarner Losh # else /* Software version */ 1670c16b537SWarner Losh static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 1680c16b537SWarner Losh 11, 14, 16, 18, 22, 25, 3, 30, 1690c16b537SWarner Losh 8, 12, 20, 28, 15, 17, 24, 7, 1700c16b537SWarner Losh 19, 27, 23, 6, 26, 5, 4, 31 }; 1710c16b537SWarner Losh U32 v = val; 1720c16b537SWarner Losh v |= v >> 1; 1730c16b537SWarner Losh v |= v >> 2; 1740c16b537SWarner Losh v |= v >> 4; 1750c16b537SWarner Losh v |= v >> 8; 1760c16b537SWarner Losh v |= v >> 16; 1770c16b537SWarner Losh return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27]; 1780c16b537SWarner Losh # endif 1790c16b537SWarner Losh } 1800c16b537SWarner Losh } 1810c16b537SWarner Losh 1820c16b537SWarner Losh /*===== Local Constants =====*/ 1830c16b537SWarner Losh static const unsigned BIT_mask[] = { 1840c16b537SWarner Losh 0, 1, 3, 7, 0xF, 0x1F, 1850c16b537SWarner Losh 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 1860c16b537SWarner Losh 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 1870c16b537SWarner Losh 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 1880c16b537SWarner Losh 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, 1890c16b537SWarner Losh 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */ 1900c16b537SWarner Losh #define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0])) 1910c16b537SWarner Losh 1920c16b537SWarner Losh /*-************************************************************** 1930c16b537SWarner Losh * bitStream encoding 1940c16b537SWarner Losh ****************************************************************/ 1950c16b537SWarner Losh /*! BIT_initCStream() : 1960c16b537SWarner Losh * `dstCapacity` must be > sizeof(size_t) 1970c16b537SWarner Losh * @return : 0 if success, 1980c16b537SWarner Losh * otherwise an error code (can be tested using ERR_isError()) */ 1990c16b537SWarner Losh MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, 2000c16b537SWarner Losh void* startPtr, size_t dstCapacity) 2010c16b537SWarner Losh { 2020c16b537SWarner Losh bitC->bitContainer = 0; 2030c16b537SWarner Losh bitC->bitPos = 0; 2040c16b537SWarner Losh bitC->startPtr = (char*)startPtr; 2050c16b537SWarner Losh bitC->ptr = bitC->startPtr; 2060c16b537SWarner Losh bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer); 2070c16b537SWarner Losh if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall); 2080c16b537SWarner Losh return 0; 2090c16b537SWarner Losh } 2100c16b537SWarner Losh 2110c16b537SWarner Losh /*! BIT_addBits() : 2120c16b537SWarner Losh * can add up to 31 bits into `bitC`. 2130c16b537SWarner Losh * Note : does not check for register overflow ! */ 2140c16b537SWarner Losh MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, 2150c16b537SWarner Losh size_t value, unsigned nbBits) 2160c16b537SWarner Losh { 2170c16b537SWarner Losh MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32); 2180c16b537SWarner Losh assert(nbBits < BIT_MASK_SIZE); 2190c16b537SWarner Losh assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); 2200c16b537SWarner Losh bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos; 2210c16b537SWarner Losh bitC->bitPos += nbBits; 2220c16b537SWarner Losh } 2230c16b537SWarner Losh 2240c16b537SWarner Losh /*! BIT_addBitsFast() : 2250f743729SConrad Meyer * works only if `value` is _clean_, 2260f743729SConrad Meyer * meaning all high bits above nbBits are 0 */ 2270c16b537SWarner Losh MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, 2280c16b537SWarner Losh size_t value, unsigned nbBits) 2290c16b537SWarner Losh { 2300c16b537SWarner Losh assert((value>>nbBits) == 0); 2310c16b537SWarner Losh assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8); 2320c16b537SWarner Losh bitC->bitContainer |= value << bitC->bitPos; 2330c16b537SWarner Losh bitC->bitPos += nbBits; 2340c16b537SWarner Losh } 2350c16b537SWarner Losh 2360c16b537SWarner Losh /*! BIT_flushBitsFast() : 2370c16b537SWarner Losh * assumption : bitContainer has not overflowed 2380c16b537SWarner Losh * unsafe version; does not check buffer overflow */ 2390c16b537SWarner Losh MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) 2400c16b537SWarner Losh { 2410c16b537SWarner Losh size_t const nbBytes = bitC->bitPos >> 3; 2420c16b537SWarner Losh assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); 2430c16b537SWarner Losh MEM_writeLEST(bitC->ptr, bitC->bitContainer); 2440c16b537SWarner Losh bitC->ptr += nbBytes; 2450c16b537SWarner Losh assert(bitC->ptr <= bitC->endPtr); 2460c16b537SWarner Losh bitC->bitPos &= 7; 2470c16b537SWarner Losh bitC->bitContainer >>= nbBytes*8; 2480c16b537SWarner Losh } 2490c16b537SWarner Losh 2500c16b537SWarner Losh /*! BIT_flushBits() : 2510c16b537SWarner Losh * assumption : bitContainer has not overflowed 2520c16b537SWarner Losh * safe version; check for buffer overflow, and prevents it. 2530c16b537SWarner Losh * note : does not signal buffer overflow. 2540c16b537SWarner Losh * overflow will be revealed later on using BIT_closeCStream() */ 2550c16b537SWarner Losh MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) 2560c16b537SWarner Losh { 2570c16b537SWarner Losh size_t const nbBytes = bitC->bitPos >> 3; 2580c16b537SWarner Losh assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8); 2590c16b537SWarner Losh MEM_writeLEST(bitC->ptr, bitC->bitContainer); 2600c16b537SWarner Losh bitC->ptr += nbBytes; 2610c16b537SWarner Losh if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr; 2620c16b537SWarner Losh bitC->bitPos &= 7; 2630c16b537SWarner Losh bitC->bitContainer >>= nbBytes*8; 2640c16b537SWarner Losh } 2650c16b537SWarner Losh 2660c16b537SWarner Losh /*! BIT_closeCStream() : 2670c16b537SWarner Losh * @return : size of CStream, in bytes, 2680c16b537SWarner Losh * or 0 if it could not fit into dstBuffer */ 2690c16b537SWarner Losh MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) 2700c16b537SWarner Losh { 2710c16b537SWarner Losh BIT_addBitsFast(bitC, 1, 1); /* endMark */ 2720c16b537SWarner Losh BIT_flushBits(bitC); 2730c16b537SWarner Losh if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ 2740c16b537SWarner Losh return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0); 2750c16b537SWarner Losh } 2760c16b537SWarner Losh 2770c16b537SWarner Losh 2780c16b537SWarner Losh /*-******************************************************** 2790c16b537SWarner Losh * bitStream decoding 2800c16b537SWarner Losh **********************************************************/ 2810c16b537SWarner Losh /*! BIT_initDStream() : 2820c16b537SWarner Losh * Initialize a BIT_DStream_t. 2830c16b537SWarner Losh * `bitD` : a pointer to an already allocated BIT_DStream_t structure. 2840c16b537SWarner Losh * `srcSize` must be the *exact* size of the bitStream, in bytes. 2850c16b537SWarner Losh * @return : size of stream (== srcSize), or an errorCode if a problem is detected 2860c16b537SWarner Losh */ 2870c16b537SWarner Losh MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) 2880c16b537SWarner Losh { 2890c16b537SWarner Losh if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); } 2900c16b537SWarner Losh 2910c16b537SWarner Losh bitD->start = (const char*)srcBuffer; 2920c16b537SWarner Losh bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer); 2930c16b537SWarner Losh 2940c16b537SWarner Losh if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */ 2950c16b537SWarner Losh bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer); 2960c16b537SWarner Losh bitD->bitContainer = MEM_readLEST(bitD->ptr); 2970c16b537SWarner Losh { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; 2980c16b537SWarner Losh bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */ 2990c16b537SWarner Losh if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ } 3000c16b537SWarner Losh } else { 3010c16b537SWarner Losh bitD->ptr = bitD->start; 3020c16b537SWarner Losh bitD->bitContainer = *(const BYTE*)(bitD->start); 3030c16b537SWarner Losh switch(srcSize) 3040c16b537SWarner Losh { 3050c16b537SWarner Losh case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16); 3060c16b537SWarner Losh /* fall-through */ 3070c16b537SWarner Losh 3080c16b537SWarner Losh case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24); 3090c16b537SWarner Losh /* fall-through */ 3100c16b537SWarner Losh 3110c16b537SWarner Losh case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32); 3120c16b537SWarner Losh /* fall-through */ 3130c16b537SWarner Losh 3140c16b537SWarner Losh case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24; 3150c16b537SWarner Losh /* fall-through */ 3160c16b537SWarner Losh 3170c16b537SWarner Losh case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16; 3180c16b537SWarner Losh /* fall-through */ 3190c16b537SWarner Losh 3200c16b537SWarner Losh case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8; 3210c16b537SWarner Losh /* fall-through */ 3220c16b537SWarner Losh 3230c16b537SWarner Losh default: break; 3240c16b537SWarner Losh } 3250c16b537SWarner Losh { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1]; 3260c16b537SWarner Losh bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; 3270c16b537SWarner Losh if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present */ 3280c16b537SWarner Losh } 3290c16b537SWarner Losh bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8; 3300c16b537SWarner Losh } 3310c16b537SWarner Losh 3320c16b537SWarner Losh return srcSize; 3330c16b537SWarner Losh } 3340c16b537SWarner Losh 3350c16b537SWarner Losh MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start) 3360c16b537SWarner Losh { 3370c16b537SWarner Losh return bitContainer >> start; 3380c16b537SWarner Losh } 3390c16b537SWarner Losh 3400c16b537SWarner Losh MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits) 3410c16b537SWarner Losh { 3420f743729SConrad Meyer U32 const regMask = sizeof(bitContainer)*8 - 1; 3430f743729SConrad Meyer /* if start > regMask, bitstream is corrupted, and result is undefined */ 3440c16b537SWarner Losh assert(nbBits < BIT_MASK_SIZE); 3450f743729SConrad Meyer return (bitContainer >> (start & regMask)) & BIT_mask[nbBits]; 3460c16b537SWarner Losh } 3470c16b537SWarner Losh 3480c16b537SWarner Losh MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits) 3490c16b537SWarner Losh { 3500c16b537SWarner Losh assert(nbBits < BIT_MASK_SIZE); 3510c16b537SWarner Losh return bitContainer & BIT_mask[nbBits]; 3520c16b537SWarner Losh } 3530c16b537SWarner Losh 3540c16b537SWarner Losh /*! BIT_lookBits() : 3550c16b537SWarner Losh * Provides next n bits from local register. 3560c16b537SWarner Losh * local register is not modified. 3570c16b537SWarner Losh * On 32-bits, maxNbBits==24. 3580c16b537SWarner Losh * On 64-bits, maxNbBits==56. 3590c16b537SWarner Losh * @return : value extracted */ 3600c16b537SWarner Losh MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits) 3610c16b537SWarner Losh { 3620f743729SConrad Meyer /* arbitrate between double-shift and shift+mask */ 3630f743729SConrad Meyer #if 1 3640f743729SConrad Meyer /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8, 3650f743729SConrad Meyer * bitstream is likely corrupted, and result is undefined */ 3660c16b537SWarner Losh return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits); 3670c16b537SWarner Losh #else 3680f743729SConrad Meyer /* this code path is slower on my os-x laptop */ 3690c16b537SWarner Losh U32 const regMask = sizeof(bitD->bitContainer)*8 - 1; 3700c16b537SWarner Losh return ((bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> 1) >> ((regMask-nbBits) & regMask); 3710c16b537SWarner Losh #endif 3720c16b537SWarner Losh } 3730c16b537SWarner Losh 3740c16b537SWarner Losh /*! BIT_lookBitsFast() : 3750c16b537SWarner Losh * unsafe version; only works if nbBits >= 1 */ 3760c16b537SWarner Losh MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits) 3770c16b537SWarner Losh { 3780c16b537SWarner Losh U32 const regMask = sizeof(bitD->bitContainer)*8 - 1; 3790c16b537SWarner Losh assert(nbBits >= 1); 3800c16b537SWarner Losh return (bitD->bitContainer << (bitD->bitsConsumed & regMask)) >> (((regMask+1)-nbBits) & regMask); 3810c16b537SWarner Losh } 3820c16b537SWarner Losh 3830c16b537SWarner Losh MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) 3840c16b537SWarner Losh { 3850c16b537SWarner Losh bitD->bitsConsumed += nbBits; 3860c16b537SWarner Losh } 3870c16b537SWarner Losh 3880c16b537SWarner Losh /*! BIT_readBits() : 3890c16b537SWarner Losh * Read (consume) next n bits from local register and update. 3900c16b537SWarner Losh * Pay attention to not read more than nbBits contained into local register. 3910c16b537SWarner Losh * @return : extracted value. */ 392*a0483764SConrad Meyer MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits) 3930c16b537SWarner Losh { 3940c16b537SWarner Losh size_t const value = BIT_lookBits(bitD, nbBits); 3950c16b537SWarner Losh BIT_skipBits(bitD, nbBits); 3960c16b537SWarner Losh return value; 3970c16b537SWarner Losh } 3980c16b537SWarner Losh 3990c16b537SWarner Losh /*! BIT_readBitsFast() : 4000c16b537SWarner Losh * unsafe version; only works only if nbBits >= 1 */ 401*a0483764SConrad Meyer MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits) 4020c16b537SWarner Losh { 4030c16b537SWarner Losh size_t const value = BIT_lookBitsFast(bitD, nbBits); 4040c16b537SWarner Losh assert(nbBits >= 1); 4050c16b537SWarner Losh BIT_skipBits(bitD, nbBits); 4060c16b537SWarner Losh return value; 4070c16b537SWarner Losh } 4080c16b537SWarner Losh 4090c16b537SWarner Losh /*! BIT_reloadDStream() : 4100c16b537SWarner Losh * Refill `bitD` from buffer previously set in BIT_initDStream() . 4110c16b537SWarner Losh * This function is safe, it guarantees it will not read beyond src buffer. 4120c16b537SWarner Losh * @return : status of `BIT_DStream_t` internal register. 41319fcbaf1SConrad Meyer * when status == BIT_DStream_unfinished, internal register is filled with at least 25 or 57 bits */ 4140c16b537SWarner Losh MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) 4150c16b537SWarner Losh { 4160c16b537SWarner Losh if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* overflow detected, like end of stream */ 4170c16b537SWarner Losh return BIT_DStream_overflow; 4180c16b537SWarner Losh 4190c16b537SWarner Losh if (bitD->ptr >= bitD->limitPtr) { 4200c16b537SWarner Losh bitD->ptr -= bitD->bitsConsumed >> 3; 4210c16b537SWarner Losh bitD->bitsConsumed &= 7; 4220c16b537SWarner Losh bitD->bitContainer = MEM_readLEST(bitD->ptr); 4230c16b537SWarner Losh return BIT_DStream_unfinished; 4240c16b537SWarner Losh } 4250c16b537SWarner Losh if (bitD->ptr == bitD->start) { 4260c16b537SWarner Losh if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; 4270c16b537SWarner Losh return BIT_DStream_completed; 4280c16b537SWarner Losh } 4290c16b537SWarner Losh /* start < ptr < limitPtr */ 4300c16b537SWarner Losh { U32 nbBytes = bitD->bitsConsumed >> 3; 4310c16b537SWarner Losh BIT_DStream_status result = BIT_DStream_unfinished; 4320c16b537SWarner Losh if (bitD->ptr - nbBytes < bitD->start) { 4330c16b537SWarner Losh nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ 4340c16b537SWarner Losh result = BIT_DStream_endOfBuffer; 4350c16b537SWarner Losh } 4360c16b537SWarner Losh bitD->ptr -= nbBytes; 4370c16b537SWarner Losh bitD->bitsConsumed -= nbBytes*8; 4380c16b537SWarner Losh bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD->bitContainer), otherwise bitD->ptr == bitD->start */ 4390c16b537SWarner Losh return result; 4400c16b537SWarner Losh } 4410c16b537SWarner Losh } 4420c16b537SWarner Losh 4430c16b537SWarner Losh /*! BIT_endOfDStream() : 4440c16b537SWarner Losh * @return : 1 if DStream has _exactly_ reached its end (all bits consumed). 4450c16b537SWarner Losh */ 4460c16b537SWarner Losh MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) 4470c16b537SWarner Losh { 4480c16b537SWarner Losh return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8)); 4490c16b537SWarner Losh } 4500c16b537SWarner Losh 4510c16b537SWarner Losh #if defined (__cplusplus) 4520c16b537SWarner Losh } 4530c16b537SWarner Losh #endif 4540c16b537SWarner Losh 4550c16b537SWarner Losh #endif /* BITSTREAM_H_MODULE */ 456