/**
 
        libsmacker - A C library for decoding .smk Smacker Video files
 
        Copyright (C) 2012-2017 Greg Kennedy
 
 
 
        See smacker.h for more information.
 
 
 
        smk_bitstream.c
 
                Implements a bitstream structure, which can extract and
 
                return a bit at a time from a raw block of bytes.
 
*/
 
 
 
#include "smk_bitstream.h"
 
 
 
/* malloc and friends */
 
#include "smk_malloc.h"
 
 
 
/*
 
        Bitstream structure
 
        Pointer to raw block of data and a size limit.
 
        Maintains internal pointers to byte_num and bit_number.
 
*/
 
struct smk_bit_t
 
{
 
        const unsigned char* buffer;
 
        unsigned long size;
 
 
 
        unsigned long byte_num;
 
        char bit_num;
 
};
 
 
 
/* BITSTREAM Functions */
 
struct smk_bit_t* smk_bs_init(const unsigned char* b, const unsigned long size)
 
{
 
        struct smk_bit_t* ret = NULL;
 
 
 
        /* sanity check */
 
        smk_assert(b);
 
 
 
        /* allocate a bitstream struct */
 
        smk_malloc(ret, sizeof(struct smk_bit_t));
 
 
 
        /* set up the pointer to bitstream, and the size counter */
 
        ret->buffer = b;
 
        ret->size = size;
 
 
 
        /* point to initial byte: note, smk_malloc already sets these to 0 */
 
        /* ret->byte_num = 0;
 
        ret->bit_num = 0; */
 
 
 
        /* return ret or NULL if error : ) */
 
error:
 
        return ret;
 
}
 
 
 
/* Reads a bit
 
        Returns -1 if error encountered */
 
char _smk_bs_read_1(struct smk_bit_t* bs)
 
{
 
        unsigned char ret = -1;
 
 
 
        /* sanity check */
 
        smk_assert(bs);
 
 
 
        /* don't die when running out of bits, but signal */
 
        if (bs->byte_num >= bs->size)
 
        {
 
                fprintf(stderr
, "libsmacker::_smk_bs_read_1(bs): ERROR: bitstream (length=%lu) exhausted.\n", bs
->size
);  
                goto error;
 
        }
 
 
 
        /* get next bit and return */
 
        ret = (((bs->buffer[bs->byte_num]) & (1 << bs->bit_num)) != 0);
 
 
 
        /* advance to next bit */
 
        bs->bit_num ++;
 
 
 
        /* Out of bits in this byte: next! */
 
        if (bs->bit_num > 7)
 
        {
 
                bs->byte_num ++;
 
                bs->bit_num = 0;
 
        }
 
 
 
        /* return ret, or (default) -1 if error */
 
error:
 
        return ret;
 
}
 
 
 
/* Reads a byte
 
        Returns -1 if error. */
 
short _smk_bs_read_8(struct smk_bit_t* bs)
 
{
 
        unsigned char ret = -1;
 
 
 
        /* sanity check */
 
        smk_assert(bs);
 
 
 
        /* don't die when running out of bits, but signal */
 
        if (bs->byte_num + (bs->bit_num > 0) >= bs->size)
 
        {
 
                fprintf(stderr
, "libsmacker::_smk_bs_read_8(bs): ERROR: bitstream (length=%lu) exhausted.\n", bs
->size
);  
                goto error;
 
        }
 
 
 
        if (bs->bit_num)
 
        {
 
                /* unaligned read */
 
                ret = bs->buffer[bs->byte_num] >> bs->bit_num;
 
                bs->byte_num ++;
 
                ret |= (bs->buffer[bs->byte_num] << (8 - bs->bit_num));
 
        } else {
 
                /* aligned read */
 
                ret = bs->buffer[bs->byte_num ++];
 
        }
 
 
 
        /* return ret, or (default) -1 if error */
 
error:
 
        return ret;
 
}