#include "bitstream.h"
#include <limits.h>
#include "simplicity_assert.h"
simplicity_err rustsimplicity_0_6_closeBitstream(bitstream* stream) {
if (1 < stream->len) return SIMPLICITY_ERR_BITSTREAM_TRAILING_BYTES;
if (1 == stream->len) {
if (0 == stream->offset) return SIMPLICITY_ERR_BITSTREAM_TRAILING_BYTES;
if (0 != (*stream->arr & (UCHAR_MAX >> stream->offset))) {
return SIMPLICITY_ERR_BITSTREAM_ILLEGAL_PADDING;
}
}
*stream = (bitstream){0};
return SIMPLICITY_NO_ERROR;
}
int32_t rustsimplicity_0_6_readNBits(int n, bitstream* stream) {
rustsimplicity_0_6_assert(0 <= n && n < 32);
uint32_t result = 0;
while (CHAR_BIT <= stream->offset + n) {
if (!stream->len) return SIMPLICITY_ERR_BITSTREAM_EOF;
n -= CHAR_BIT - stream->offset;
result |= (uint32_t)(*stream->arr & (UCHAR_MAX >> stream->offset)) << n;
stream->arr++; stream->len--; stream->offset = 0;
}
if (n) {
if (!stream->len) return SIMPLICITY_ERR_BITSTREAM_EOF;
stream->offset += (unsigned char)n;
result |= (*stream->arr >> (CHAR_BIT - stream->offset)) & ((UCHAR_MAX >> (CHAR_BIT - n)));
}
return (int32_t)result;
}
static int32_t decodeUpto1Bit(int32_t* result, bitstream* stream) {
*result = read1Bit(stream);
if (*result <= 0) return *result;
*result = read1Bit(stream);
if (*result < 0) return *result;
if (0 != *result) return SIMPLICITY_ERR_DATA_OUT_OF_RANGE;
*result = read1Bit(stream);
if (*result < 0) return *result;
return 1;
}
static int32_t decodeUpto3(bitstream* stream) {
int32_t result;
int32_t len = decodeUpto1Bit(&result, stream);
if (len < 0) return len;
result |= 1 << len;
return result;
}
static int32_t decodeUpto3Bits(int32_t* result, bitstream* stream) {
int32_t bit = read1Bit(stream);
if (bit < 0) return bit;
*result = 0;
if (0 == bit) {
return 0;
} else {
int32_t n = decodeUpto3(stream);
if (0 <= n) {
*result = rustsimplicity_0_6_readNBits(n, stream);
if (*result < 0) return *result;
}
return n;
}
}
static int32_t decodeUpto15(bitstream* stream) {
int32_t result;
int32_t len = decodeUpto3Bits(&result, stream);
if (len < 0) return len;
result |= 1 << len;
return result;
}
static int32_t decodeUpto15Bits(int32_t* result, bitstream* stream) {
int32_t bit = read1Bit(stream);
if (bit < 0) return bit;
*result = 0;
if (0 == bit) {
return 0;
} else {
int32_t n = decodeUpto15(stream);
if (0 <= n) {
*result = rustsimplicity_0_6_readNBits(n, stream);
if (*result < 0) return *result;
}
return n;
}
}
static int32_t decodeUpto65535(bitstream* stream) {
int32_t result;
int32_t len = decodeUpto15Bits(&result, stream);
if (len < 0) return len;
result |= 1 << len;
return result;
}
int32_t rustsimplicity_0_6_decodeUptoMaxInt(bitstream* stream) {
int32_t bit = read1Bit(stream);
if (bit < 0) return bit;
if (0 == bit) {
return 1;
} else {
int32_t n = decodeUpto65535(stream);
if (n < 0) return n;
if (30 < n) return SIMPLICITY_ERR_DATA_OUT_OF_RANGE;
{
int32_t result = rustsimplicity_0_6_readNBits(n, stream);
if (result < 0) return result;
return ((1 << n) | result);
}
}
}
simplicity_err rustsimplicity_0_6_readBitstring(bitstring* result, size_t n, bitstream* stream) {
static_assert(0x80000000u + 2*(CHAR_BIT - 1) <= SIZE_MAX, "size_t needs to be at least 32-bits");
rustsimplicity_0_6_assert(n <= 0x80000000u);
size_t total_offset = n + stream->offset;
if (stream->len < (total_offset + (CHAR_BIT - 1)) / CHAR_BIT) return SIMPLICITY_ERR_BITSTREAM_EOF;
*result = (bitstring)
{ .arr = stream->arr
, .offset = stream->offset
, .len = n
};
{
size_t delta = total_offset / CHAR_BIT;
stream->arr += delta; stream->len -= delta;
stream->offset = total_offset % CHAR_BIT;
}
return SIMPLICITY_NO_ERROR;
}