Files
cuetools.net/CUETools.Codecs/BitReader.cs

290 lines
7.5 KiB
C#
Raw Normal View History

using System;
2009-08-30 21:58:54 +00:00
namespace CUETools.Codecs
{
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
};
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
private byte* buffer_m;
private byte* bptr_m;
private int buffer_len_m;
private int have_bits_m;
private ulong cache_m;
2011-10-24 00:13:35 +00:00
public int Position
{
get { return (int)(bptr_m - buffer_m - (have_bits_m >> 3)); }
}
2009-08-17 20:16:56 +00:00
public byte* Buffer
{
get
{
return buffer_m;
}
}
2009-12-24 16:09:20 +00:00
public BitReader()
{
buffer_m = null;
bptr_m = null;
buffer_len_m = 0;
have_bits_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)
{
buffer_m = _buffer;
bptr_m = _buffer + _pos;
buffer_len_m = _len;
have_bits_m = 0;
cache_m = 0;
fill();
}
public void fill()
{
while (have_bits_m < 56)
{
have_bits_m += 8;
cache_m |= (ulong)*(bptr_m++) << (64 - have_bits_m);
}
}
2009-08-17 20:16:56 +00:00
/* skip any number of bits */
public void skipbits(int bits)
{
while (bits > have_bits_m)
{
bits -= have_bits_m;
cache_m = 0;
have_bits_m = 0;
fill();
}
cache_m <<= bits;
have_bits_m -= bits;
}
/* supports reading 1 to 32 bits, in big endian format */
public uint readbits(int bits)
{
fill();
uint result = (uint)(cache_m >> 64 - bits);
skipbits(bits);
return result;
}
/* supports reading 1 to 64 bits, in big endian format */
public ulong readbits64(int bits)
2009-08-17 20:16:56 +00:00
{
if (bits <= 56)
return readbits(bits);
return (readbits(32) << bits - 32) | readbits(bits - 32);
}
/* reads a single bit */
public uint readbit()
{
return readbits(1);
}
public uint read_unary()
{
fill();
uint val = 0;
ulong result = cache_m >> 56;
2009-08-17 20:16:56 +00:00
while (result == 0)
{
2009-08-17 20:16:56 +00:00
val += 8;
cache_m <<= 8;
cache_m |= (ulong)*(bptr_m++) << (64 - have_bits_m);
result = cache_m >> 56;
}
2009-08-17 20:16:56 +00:00
val += byte_to_unary_table[result];
skipbits((int)(val & 7) + 1);
return val;
}
public void flush()
{
if ((have_bits_m & 7) > 0)
{
cache_m <<= have_bits_m & 7;
have_bits_m -= have_bits_m & 7;
}
}
public int readbits_signed(int bits)
{
2009-08-17 20:16:56 +00:00
int val = (int)readbits(bits);
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");
}
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;
}
2009-08-17 20:16:56 +00:00
public void read_rice_block(int n, int k, int* r)
{
fill();
fixed (byte* unary_table = byte_to_unary_table)
{
uint mask = (1U << k) - 1;
byte* bptr = bptr_m;
int have_bits = have_bits_m;
ulong cache = cache_m;
for (int i = n; i > 0; i--)
2011-10-24 00:13:35 +00:00
{
uint bits;
byte* orig_bptr = bptr;
while ((bits = unary_table[cache >> 56]) == 8)
2011-10-24 00:13:35 +00:00
{
cache <<= 8;
cache |= (ulong)*(bptr++) << (64 - have_bits);
2011-10-24 00:13:35 +00: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
{
have_bits += 8;
cache |= (ulong)*(bptr++) << (64 - have_bits);
2011-10-24 00:13:35 +00:00
}
int btsk = k + (int)bits + 1;
uint uval = (msbs << k) | (uint)((cache >> (64 - btsk)) & mask);
cache <<= btsk;
have_bits -= btsk;
*(r++) = (int)(uval >> 1 ^ -(int)(uval & 1));
2011-10-24 00:13:35 +00:00
}
have_bits_m = have_bits;
cache_m = cache;
bptr_m = bptr;
}
}
}
}