You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
2.5 KiB
119 lines
2.5 KiB
/** |
|
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; |
|
}
|
|
|