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

162 lines
4.3 KiB
C

#ifndef _BITSTREAM_MSB_H
#define _BITSTREAM_MSB_H
#include "../streamtypes.h"
/* Simple bitreader for MPEG/standard bit style, in 'most significant byte' (MSB) format.
* Example: 0x12345678 is read as 78,56,34,12 then each byte's bits.
* 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 */
size_t b_max; /* max size in bits */
uint32_t b_off; /* current offset in bits inside buffer */
} bitstream_t;
static inline void bm_setup(bitstream_t* bs, uint8_t* buf, size_t bufsize) {
bs->buf = buf;
bs->bufsize = bufsize;
bs->b_max = bufsize * 8;
bs->b_off = 0;
}
static inline int bm_set(bitstream_t* bs, uint32_t b_off) {
if (bs->b_off > bs->b_max)
goto fail;
bs->b_off = b_off;
return 1;
fail:
return 0;
}
static inline int bm_fill(bitstream_t* bs, uint32_t bytes) {
if (bs->b_off > bs->b_max)
goto fail;
bs->bufsize += bytes;
bs->b_max += bytes * 8;
return 1;
fail:
return 0;
}
static inline int bm_skip(bitstream_t* bs, uint32_t bits) {
if (bs->b_off + bits > bs->b_max)
goto fail;
bs->b_off += bits;
return 1;
fail:
return 0;
}
static inline int bm_pos(bitstream_t* bs) {
return bs->b_off;
}
/* Read bits (max 32) from buf and update the bit offset. Order is BE (MSB). */
static inline int bm_get(bitstream_t* ib, uint32_t bits, uint32_t* value) {
uint32_t shift, pos, val;
int i, bit_buf, bit_val;
if (bits > 32 || ib->b_off + bits > ib->b_max)
goto fail;
pos = ib->b_off / 8; /* byte offset */
shift = ib->b_off % 8; /* bit sub-offset */
#if 1 //naive approach
val = 0;
for (i = 0; i < bits; i++) {
bit_buf = (1U << (8-1-shift)) & 0xFF; /* bit check for buf */
bit_val = (1U << (bits-1-i)); /* bit to set in value */
if (ib->buf[pos] & bit_buf) /* is bit in buf set? */
val |= bit_val; /* set bit */
shift++;
if (shift % 8 == 0) { /* new byte starts */
shift = 0;
pos++;
}
}
#else //has bugs
pos = ib->b_off / 8; /* byte offset */
shift = ib->b_off % 8; /* bit sub-offset */
uint32_t mask = MASK_TABLE[bits]; /* to remove upper in highest byte */
int left = 0;
if (bits == 0)
val = 0;
else
val = ib->buf[pos+0];
left = 8 - (bits + shift);
if (bits + shift > 8) {
val = (val << 8u) | ib->buf[pos+1];
left = 16 - (bits + shift);
if (bits + shift > 16) {
val = (val << 8u) | ib->buf[pos+2];
left = 32 - (bits + shift);
if (bits + shift > 24) {
val = (val << 8u) | ib->buf[pos+3];
left = 32 - (bits + shift);
if (bits + shift > 32) {
val = (val << 8u) | ib->buf[pos+4]; /* upper bits are lost (shifting over 32) */ TO-DO
left = 40 - (bits + shift);
}
}
}
}
val = ((val >> left) & mask);
#endif
*value = val;
ib->b_off += bits;
return 1;
fail:
//VGM_LOG("BITREADER: read fail\n");
*value = 0;
return 0;
}
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSB). */
static inline int bm_put(bitstream_t* ob, uint32_t bits, uint32_t value) {
uint32_t shift, pos;
int i, bit_val, bit_buf;
if (bits > 32 || ob->b_off + bits > ob->b_max)
goto fail;
pos = ob->b_off / 8; /* byte offset */
shift = ob->b_off % 8; /* bit sub-offset */
for (i = 0; i < bits; i++) {
bit_val = (1U << (bits-1-i)); /* bit check for value */
bit_buf = (1U << (8-1-shift)) & 0xFF; /* bit to set in buf */
if (value & bit_val) /* is bit in val set? */
ob->buf[pos] |= bit_buf; /* set bit */
else
ob->buf[pos] &= ~bit_buf; /* unset bit */
shift++;
if (shift % 8 == 0) { /* new byte starts */
shift = 0;
pos++;
}
}
ob->b_off += bits;
return 1;
fail:
return 0;
}
#endif