2009-08-17 03:39:53 +00:00
|
|
|
using System;
|
|
|
|
|
|
2009-08-30 21:58:54 +00:00
|
|
|
namespace CUETools.Codecs
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2009-08-30 21:58:54 +00:00
|
|
|
unsafe public class BitReader
|
2011-10-24 00:13:35 +00:00
|
|
|
{
|
|
|
|
|
#region Static Methods
|
2009-08-17 20:16:56 +00:00
|
|
|
|
2011-10-24 00:13:35 +00:00
|
|
|
public static int log2i(int v)
|
|
|
|
|
{
|
|
|
|
|
return log2i((uint)v);
|
|
|
|
|
}
|
2009-08-30 21:58:54 +00:00
|
|
|
|
2011-10-24 00:13:35 +00:00
|
|
|
public static int log2i(ulong v)
|
|
|
|
|
{
|
|
|
|
|
int n = 0;
|
|
|
|
|
if (0 != (v & 0xffffffff00000000)) { v >>= 32; n += 32; }
|
|
|
|
|
if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; }
|
|
|
|
|
if (0 != (v & 0xff00)) { v >>= 8; n += 8; }
|
|
|
|
|
return n + byte_to_log2_table[v];
|
|
|
|
|
}
|
2010-12-07 22:52:34 +00:00
|
|
|
|
2011-10-24 00:13:35 +00:00
|
|
|
public static int log2i(uint v)
|
|
|
|
|
{
|
|
|
|
|
int n = 0;
|
|
|
|
|
if (0 != (v & 0xffff0000)) { v >>= 16; n += 16; }
|
|
|
|
|
if (0 != (v & 0xff00)) { v >>= 8; n += 8; }
|
|
|
|
|
return n + byte_to_log2_table[v];
|
|
|
|
|
}
|
2009-08-30 21:58:54 +00:00
|
|
|
|
2011-10-24 00:13:35 +00:00
|
|
|
public static readonly byte[] byte_to_unary_table = new byte[]
|
2009-08-17 20:16:56 +00:00
|
|
|
{
|
|
|
|
|
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
|
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|
|
|
|
};
|
2009-08-17 03:39:53 +00:00
|
|
|
|
2011-10-24 00:13:35 +00:00
|
|
|
public static readonly byte[] byte_to_log2_table = new byte[]
|
2009-08-30 21:58:54 +00:00
|
|
|
{
|
|
|
|
|
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
|
|
|
|
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
|
|
|
|
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
|
|
|
|
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
|
|
|
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
|
|
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
|
|
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
|
|
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
|
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
|
|
|
|
};
|
|
|
|
|
|
2011-10-24 00:13:35 +00:00
|
|
|
#endregion
|
|
|
|
|
|
2013-03-18 03:18:59 -04:00
|
|
|
private byte* buffer_m;
|
|
|
|
|
private int buffer_offset_m, buffer_len_m;
|
|
|
|
|
private int bitaccumulator_m;
|
|
|
|
|
private uint cache_m;
|
2011-10-24 00:13:35 +00:00
|
|
|
|
2009-08-17 03:39:53 +00:00
|
|
|
public int Position
|
|
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
get { return buffer_offset_m; }
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
public byte* Buffer
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
return buffer_m;
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-24 16:09:20 +00:00
|
|
|
public BitReader()
|
|
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
buffer_m = null;
|
|
|
|
|
buffer_offset_m = 0;
|
|
|
|
|
buffer_len_m = 0;
|
|
|
|
|
bitaccumulator_m = 0;
|
|
|
|
|
cache_m = 0;
|
2009-12-24 16:09:20 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
public BitReader(byte* _buffer, int _pos, int _len)
|
2009-12-24 16:09:20 +00:00
|
|
|
{
|
|
|
|
|
Reset(_buffer, _pos, _len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Reset(byte* _buffer, int _pos, int _len)
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
buffer_m = _buffer;
|
|
|
|
|
buffer_offset_m = _pos;
|
|
|
|
|
buffer_len_m = _len;
|
|
|
|
|
bitaccumulator_m = 0;
|
|
|
|
|
cache_m = peek4();
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
public uint peek4()
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
//uint result = ((((uint)buffer[pos]) << 24) | (((uint)buffer[pos + 1]) << 16) | (((uint)buffer[pos + 2]) << 8) | ((uint)buffer[pos + 3])) << bitaccumulator_m;
|
|
|
|
|
byte* b = buffer_m + buffer_offset_m;
|
2009-08-17 20:16:56 +00:00
|
|
|
uint result = *(b++);
|
|
|
|
|
result = (result << 8) + *(b++);
|
|
|
|
|
result = (result << 8) + *(b++);
|
|
|
|
|
result = (result << 8) + *(b++);
|
2013-03-18 03:18:59 -04:00
|
|
|
result <<= bitaccumulator_m;
|
2009-08-17 20:16:56 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
2009-08-17 03:39:53 +00:00
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
/* skip any number of bits */
|
|
|
|
|
public void skipbits(int bits)
|
|
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
int new_accumulator = (bitaccumulator_m + bits);
|
|
|
|
|
buffer_offset_m += (new_accumulator >> 3);
|
|
|
|
|
bitaccumulator_m = (new_accumulator & 7);
|
|
|
|
|
cache_m = peek4();
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
2009-12-24 16:09:20 +00:00
|
|
|
/* skip up to 16 bits */
|
|
|
|
|
public void skipbits16(int bits)
|
|
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
cache_m <<= bits;
|
|
|
|
|
int new_accumulator = (bitaccumulator_m + bits);
|
|
|
|
|
buffer_offset_m += (new_accumulator >> 3);
|
|
|
|
|
bitaccumulator_m = (new_accumulator & 7);
|
|
|
|
|
cache_m |= ((((uint)buffer_m[buffer_offset_m + 2] << 8) + (uint)buffer_m[buffer_offset_m + 3]) << bitaccumulator_m);
|
2009-12-24 16:09:20 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
/* skip up to 8 bits */
|
|
|
|
|
public void skipbits8(int bits)
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
cache_m <<= bits;
|
|
|
|
|
int new_accumulator = (bitaccumulator_m + bits);
|
|
|
|
|
buffer_offset_m += (new_accumulator >> 3);
|
|
|
|
|
bitaccumulator_m = (new_accumulator & 7);
|
|
|
|
|
cache_m |= ((uint)buffer_m[buffer_offset_m + 3] << bitaccumulator_m);
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
/* supports reading 1 to 24 bits, in big endian format */
|
|
|
|
|
public uint readbits24(int bits)
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2009-08-17 20:16:56 +00:00
|
|
|
//uint result = peek4() >> (32 - bits);
|
2013-03-18 03:18:59 -04:00
|
|
|
uint result = cache_m >> (32 - bits);
|
2009-08-17 20:16:56 +00:00
|
|
|
skipbits(bits);
|
2009-08-17 03:39:53 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
public uint peekbits24(int bits)
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
return cache_m >> 32 - bits;
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* supports reading 1 to 32 bits, in big endian format */
|
|
|
|
|
public uint readbits(int bits)
|
|
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
uint result = cache_m >> 32 - bits;
|
2009-08-17 03:39:53 +00:00
|
|
|
if (bits <= 24)
|
2009-08-17 20:16:56 +00:00
|
|
|
{
|
|
|
|
|
skipbits(bits);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
skipbits(24);
|
2013-03-18 03:18:59 -04:00
|
|
|
result |= cache_m >> 56 - bits;
|
2009-08-17 20:16:56 +00:00
|
|
|
skipbits(bits - 24);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2009-08-17 03:39:53 +00:00
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
public ulong readbits64(int bits)
|
|
|
|
|
{
|
|
|
|
|
if (bits <= 24)
|
|
|
|
|
return readbits24(bits);
|
|
|
|
|
ulong result = readbits24(24);
|
|
|
|
|
bits -= 24;
|
|
|
|
|
if (bits <= 24)
|
|
|
|
|
return (result << bits) | readbits24(bits);
|
|
|
|
|
result = (result << 24) | readbits24(24);
|
|
|
|
|
bits -= 24;
|
|
|
|
|
return (result << bits) | readbits24(bits);
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* reads a single bit */
|
|
|
|
|
public uint readbit()
|
|
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
uint result = cache_m >> 31;
|
2009-08-17 20:16:56 +00:00
|
|
|
skipbits8(1);
|
2009-08-17 03:39:53 +00:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint read_unary()
|
|
|
|
|
{
|
|
|
|
|
uint val = 0;
|
|
|
|
|
|
2013-03-18 03:18:59 -04:00
|
|
|
uint result = cache_m >> 24;
|
2009-08-17 20:16:56 +00:00
|
|
|
while (result == 0)
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2009-08-17 20:16:56 +00:00
|
|
|
val += 8;
|
|
|
|
|
skipbits8(8);
|
2013-03-18 03:18:59 -04:00
|
|
|
result = cache_m >> 24;
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
val += byte_to_unary_table[result];
|
|
|
|
|
skipbits8((int)(val & 7) + 1);
|
2009-08-17 03:39:53 +00:00
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void flush()
|
|
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
if (bitaccumulator_m > 0)
|
|
|
|
|
skipbits8(8 - bitaccumulator_m);
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int readbits_signed(int bits)
|
|
|
|
|
{
|
2009-08-17 20:16:56 +00:00
|
|
|
int val = (int)readbits(bits);
|
2009-08-17 03:39:53 +00:00
|
|
|
val <<= (32 - bits);
|
|
|
|
|
val >>= (32 - bits);
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint read_utf8()
|
|
|
|
|
{
|
|
|
|
|
uint x = readbits(8);
|
|
|
|
|
uint v;
|
|
|
|
|
int i;
|
|
|
|
|
if (0 == (x & 0x80))
|
|
|
|
|
{
|
|
|
|
|
v = x;
|
|
|
|
|
i = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (0xC0 == (x & 0xE0)) /* 110xxxxx */
|
|
|
|
|
{
|
|
|
|
|
v = x & 0x1F;
|
|
|
|
|
i = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (0xE0 == (x & 0xF0)) /* 1110xxxx */
|
|
|
|
|
{
|
|
|
|
|
v = x & 0x0F;
|
|
|
|
|
i = 2;
|
|
|
|
|
}
|
|
|
|
|
else if (0xF0 == (x & 0xF8)) /* 11110xxx */
|
|
|
|
|
{
|
|
|
|
|
v = x & 0x07;
|
|
|
|
|
i = 3;
|
|
|
|
|
}
|
|
|
|
|
else if (0xF8 == (x & 0xFC)) /* 111110xx */
|
|
|
|
|
{
|
|
|
|
|
v = x & 0x03;
|
|
|
|
|
i = 4;
|
|
|
|
|
}
|
|
|
|
|
else if (0xFC == (x & 0xFE)) /* 1111110x */
|
|
|
|
|
{
|
|
|
|
|
v = x & 0x01;
|
|
|
|
|
i = 5;
|
|
|
|
|
}
|
2011-10-24 00:13:35 +00:00
|
|
|
else if (0xFE == x) /* 11111110 */
|
|
|
|
|
{
|
|
|
|
|
v = 0;
|
|
|
|
|
i = 6;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("invalid utf8 encoding");
|
|
|
|
|
}
|
2009-08-17 03:39:53 +00:00
|
|
|
for (; i > 0; i--)
|
|
|
|
|
{
|
|
|
|
|
x = readbits(8);
|
|
|
|
|
if (0x80 != (x & 0xC0)) /* 10xxxxxx */
|
|
|
|
|
throw new Exception("invalid utf8 encoding");
|
|
|
|
|
v <<= 6;
|
|
|
|
|
v |= (x & 0x3F);
|
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int read_rice_signed(int k)
|
|
|
|
|
{
|
|
|
|
|
uint msbs = read_unary();
|
2009-08-17 20:16:56 +00:00
|
|
|
uint lsbs = readbits24(k);
|
2009-08-17 03:39:53 +00:00
|
|
|
uint uval = (msbs << k) | lsbs;
|
|
|
|
|
return (int)(uval >> 1 ^ -(int)(uval & 1));
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
public int read_unary_signed()
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2009-08-17 20:16:56 +00:00
|
|
|
uint uval = read_unary();
|
2009-08-17 03:39:53 +00:00
|
|
|
return (int)(uval >> 1 ^ -(int)(uval & 1));
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-17 20:16:56 +00:00
|
|
|
public void read_rice_block(int n, int k, int* r)
|
2009-08-17 03:39:53 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
fixed (byte* unary_table = byte_to_unary_table)
|
|
|
|
|
{
|
|
|
|
|
uint mask = (1U << k) - 1;
|
|
|
|
|
byte* bptr = &buffer_m[buffer_offset_m];
|
|
|
|
|
int have_bits = 24 - bitaccumulator_m;
|
|
|
|
|
ulong _lcache = ((ulong)cache_m) << 32;
|
|
|
|
|
bptr += 3;
|
|
|
|
|
for (int i = n; i > 0; i--)
|
2011-10-24 00:13:35 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
uint bits;
|
|
|
|
|
byte* orig_bptr = bptr;
|
|
|
|
|
while ((bits = unary_table[_lcache >> 56]) == 8)
|
2011-10-24 00:13:35 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
_lcache <<= 8;
|
|
|
|
|
_lcache |= (ulong)*(bptr++) << (64 - have_bits);
|
2011-10-24 00:13:35 +00:00
|
|
|
}
|
2013-03-18 03:18:59 -04:00
|
|
|
uint msbs = bits + ((uint)(bptr - orig_bptr) << 3);
|
|
|
|
|
// assumes k <= 41 (have_bits < 41 + 7 + 1 + 8 == 57, so we don't loose bits here)
|
|
|
|
|
while (have_bits < 56)
|
2011-10-24 00:13:35 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
have_bits += 8;
|
|
|
|
|
_lcache |= (ulong)*(bptr++) << (64 - have_bits);
|
2011-10-24 00:13:35 +00:00
|
|
|
}
|
2013-03-18 03:18:59 -04:00
|
|
|
|
|
|
|
|
int btsk = k + (int)bits + 1;
|
|
|
|
|
uint uval = (msbs << k) | (uint)((_lcache >> (64 - btsk)) & mask);
|
|
|
|
|
_lcache <<= btsk;
|
|
|
|
|
have_bits -= btsk;
|
|
|
|
|
*(r++) = (int)(uval >> 1 ^ -(int)(uval & 1));
|
2011-10-24 00:13:35 +00:00
|
|
|
}
|
2013-03-18 03:18:59 -04:00
|
|
|
while (have_bits <= 24)
|
2011-10-24 00:13:35 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
_lcache |= ((ulong)bptr[0] << 56) >> have_bits;
|
|
|
|
|
have_bits += 8;
|
|
|
|
|
bptr++;
|
2011-10-24 00:13:35 +00:00
|
|
|
}
|
2013-03-18 03:18:59 -04:00
|
|
|
while (have_bits > 32)
|
2011-10-24 00:13:35 +00:00
|
|
|
{
|
2013-03-18 03:18:59 -04:00
|
|
|
have_bits -= 8;
|
|
|
|
|
bptr--;
|
2011-10-24 00:13:35 +00:00
|
|
|
}
|
2013-03-18 03:18:59 -04:00
|
|
|
bitaccumulator_m = 32 - have_bits;
|
|
|
|
|
cache_m = (uint)(_lcache >> 32);
|
|
|
|
|
bptr -= 4;
|
|
|
|
|
buffer_offset_m = (int)(bptr - buffer_m);
|
|
|
|
|
}
|
2009-08-17 03:39:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|