cog/Frameworks/vgmstream/vgmstream/src/util/bitstream_lsb.h

105 lines
3.8 KiB
C

#ifndef _BITSTREAM_LSB_H
#define _BITSTREAM_LSB_H
#include "../streamtypes.h"
/* Simple bitreader for Vorbis' bit style, in 'least significant byte' (LSB) format.
* Example: 0x12345678 is read as 12,34,56,78 (continuous).
* Kept in .h since it's slightly faster (compiler can optimize statics better using default compile flags). */
typedef struct {
uint8_t* buf; /* buffer to read/write */
size_t bufsize; /* max size of the buffer */
uint32_t b_off; /* current offset in bits inside the buffer */
} bitstream_t;
/* convenience util */
static inline void bl_setup(bitstream_t* b, uint8_t* buf, size_t bufsize) {
b->buf = buf;
b->bufsize = bufsize;
b->b_off = 0;
}
/* same as (1 << bits) - 1, but that seems to trigger some nasty UB when bits = 32
* (though in theory (1 << 32) = 0, 0 - 1 = UINT_MAX, but gives 0 compiling in some cases, but not always) */
static const uint32_t MASK_TABLE[33] = {
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff,
0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff,
0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
};
/* Read bits (max 32) from buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
* (ex. from 2 bytes 00100111 00000001 we can could read 4b=0111 and 6b=010010, 6b=remainder (second value is split into the 2nd byte) */
static inline int bl_get(bitstream_t* ib, uint32_t bits, uint32_t* value) {
uint32_t shift, mask, pos, val;
if (bits > 32 || ib->b_off + bits > ib->bufsize * 8)
goto fail;
pos = ib->b_off / 8; /* byte offset */
shift = ib->b_off % 8; /* bit sub-offset */
mask = MASK_TABLE[bits]; /* to remove upper in highest byte */
val = ib->buf[pos+0] >> shift;
if (bits + shift > 8) {
val |= ib->buf[pos+1] << (8u - shift);
if (bits + shift > 16) {
val |= ib->buf[pos+2] << (16u - shift);
if (bits + shift > 24) {
val |= ib->buf[pos+3] << (24u - shift);
if (bits + shift > 32) {
val |= ib->buf[pos+4] << (32u - shift); /* upper bits are lost (shifting over 32) */
}
}
}
}
*value = (val & mask);
ib->b_off += bits;
return 1;
fail:
//VGM_LOG_ONCE("BITREADER: read fail\n");
*value = 0;
return 0;
}
/* Write bits (max 32) to buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
* (ex. writing 1101011010 from b_off 2 we get 01101011 00001101 (value split, and 11 in the first byte skipped)*/
static inline int bl_put(bitstream_t* ob, uint32_t bits, uint32_t value) {
uint32_t shift, mask, pos;
if (bits > 32 || ob->b_off + bits > ob->bufsize*8)
goto fail;
pos = ob->b_off / 8; /* byte offset */
shift = ob->b_off % 8; /* bit sub-offset */
mask = (1 << shift) - 1; /* to keep lower bits in lowest byte */
ob->buf[pos+0] = (value << shift) | (ob->buf[pos+0] & mask);
if (bits + shift > 8) {
ob->buf[pos+1] = value >> (8 - shift);
if (bits + shift > 16) {
ob->buf[pos+2] = value >> (16 - shift);
if (bits + shift > 24) {
ob->buf[pos+3] = value >> (24 - shift);
if (bits + shift > 32) {
/* upper bits are set to 0 (shifting unsigned) but shouldn't matter */
ob->buf[pos+4] = value >> (32 - shift);
}
}
}
}
ob->b_off += bits;
return 1;
fail:
//VGM_LOG_ONCE("BITREADER: write fail\n");
return 0;
}
#endif