2020-07-30 20:17:14 +02:00
|
|
|
#ifndef _VORBIS_BITREADER_H
|
|
|
|
#define _VORBIS_BITREADER_H
|
|
|
|
|
|
|
|
/* Simple bitreader for Vorbis' bit format.
|
|
|
|
* Kept in .h since it's slightly faster (compiler can optimize statics better) */
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-07-30 23:49:52 +02:00
|
|
|
/* convenience util */
|
|
|
|
static void init_bitstream(bitstream_t* b, uint8_t* buf, size_t bufsize) {
|
|
|
|
b->buf = buf;
|
|
|
|
b->bufsize = bufsize;
|
|
|
|
b->b_off = 0;
|
|
|
|
}
|
|
|
|
|
2020-07-30 20:17:14 +02:00
|
|
|
/* 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 int rv_bits(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 */
|
|
|
|
|
2020-07-31 16:44:31 +02:00
|
|
|
val = ib->buf[pos+0] >> shift;
|
2020-07-30 20:17:14 +02:00
|
|
|
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) {
|
2020-07-31 16:44:31 +02:00
|
|
|
val |= ib->buf[pos+4] << (32u - shift); /* upper bits are lost (shifting over 32) */
|
2020-07-30 20:17:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = (val & mask);
|
|
|
|
|
|
|
|
ib->b_off += bits;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
fail:
|
2020-08-22 13:40:49 +02:00
|
|
|
VGM_LOG_ONCE("BITREADER: read fail\n");
|
2020-07-30 20:17:14 +02:00
|
|
|
*value = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-31 16:44:31 +02:00
|
|
|
#ifndef BITSTREAM_READ_ONLY
|
2020-07-30 20:17:14 +02:00
|
|
|
/* 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 int wv_bits(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:
|
2020-08-22 13:40:49 +02:00
|
|
|
VGM_LOG_ONCE("BITREADER: write fail\n");
|
2020-07-30 20:17:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|