using System; using System.Runtime.InteropServices; using System.Text; namespace Tofvesson.Common { public class BitReader { private delegate T Getter(); private static readonly float[] holder_f = new float[1]; private static readonly double[] holder_d = new double[1]; private static readonly ulong[] holder_u = new ulong[1]; private static readonly uint[] holder_i = new uint[1]; private readonly byte[] readFrom; private long bitCount = 0; public BitReader(byte[] readFrom) => this.readFrom = readFrom; public bool ReadBool() { bool result = (readFrom[bitCount / 8] & (byte)(1 << (int)(bitCount % 8))) != 0; ++bitCount; return result; } public float ReadFloat() => ReadFloating(); public double ReadDouble() => ReadFloating(); public byte ReadByte() { int shift = (int)(bitCount % 8); int index = (int)(bitCount / 8); byte lower_mask = (byte)(0xFF << shift); byte upper_mask = (byte)~lower_mask; byte result = (byte)(((readFrom[index] & lower_mask) >> shift) | (shift == 0 ? 0 : (readFrom[index + 1] & upper_mask) << (8 - shift))); bitCount += 8; return result; } public void SkipPadded() => bitCount += (8 - (bitCount % 8)) % 8; public ushort ReadUShort() => (ushort)ReadULong(); public uint ReadUInt() => (uint)ReadULong(); public sbyte ReadSByte() => (sbyte)ZigZagDecode(ReadByte(), 1); public short ReadShort() => (short)ZigZagDecode(ReadUShort(), 2); public int ReadInt() => (int)ZigZagDecode(ReadUInt(), 4); public long ReadLong() => ZigZagDecode(ReadULong(), 8); public float[] ReadFloatArray(int known = -1) => ReadArray(ReadFloat, known); public double[] ReadDoubleArray(int known = -1) => ReadArray(ReadDouble, known); public byte[] ReadByteArray(int known = -1) => ReadArray(ReadByte, known); public ushort[] ReadUShortArray(int known = -1) => ReadArray(ReadUShort, known); public uint[] ReadUIntArray(int known = -1) => ReadArray(ReadUInt, known); public ulong[] ReadULongArray(int known = -1) => ReadArray(ReadULong, known); public sbyte[] ReadSByteArray(int known = -1) => ReadArray(ReadSByte, known); public short[] ReadShortArray(int known = -1) => ReadArray(ReadShort, known); public int[] ReadIntArray(int known = -1) => ReadArray(ReadInt, known); public long[] ReadLongArray(int known = -1) => ReadArray(ReadLong, known); public string ReadString() => Encoding.UTF8.GetString(ReadByteArray()); public ulong ReadULong() { ulong header = ReadByte(); if (header <= 240) return header; if (header <= 248) return 240 + 256 * (header - 241) + ReadByte(); if (header == 249) return 2288 + 256UL * ReadByte() + ReadByte(); ulong res = ReadByte() | ((ulong)ReadByte() << 8) | ((ulong)ReadByte() << 16); if(header > 250) { res |= (ulong) ReadByte() << 24; if(header > 251) { res |= (ulong)ReadByte() << 32; if(header > 252) { res |= (ulong)ReadByte() << 40; if (header > 253) { res |= (ulong)ReadByte() << 48; if (header > 254) res |= (ulong)ReadByte() << 56; } } } } return res; } private T[] ReadArray(Getter g, int knownSize = -1) { T[] result = new T[knownSize > 0 ? (uint)knownSize : ReadUInt()]; for (ushort s = 0; s < result.Length; ++s) result[s] = g(); return result; } private T ReadFloating() { int size = Marshal.SizeOf(typeof(T)); Array type_holder = size == 4 ? holder_f as Array : holder_d as Array; Array result_holder = size == 4 ? holder_i as Array : holder_u as Array; T result; lock(result_holder) lock (type_holder) { //for (int i = 0; i < size; ++i) // holder.SetValue(ReadByte(), i); if (size == 4) result_holder.SetValue(BinaryHelpers.SwapEndian(ReadUInt()), 0); else result_holder.SetValue(BinaryHelpers.SwapEndian(ReadULong()), 0); Buffer.BlockCopy(result_holder, 0, type_holder, 0, size); result = (T)type_holder.GetValue(0); } return result; } private static long ZigZagDecode(ulong d, int bytes) => (long)(((d << (bytes * 8 - 1)) & 1) | (d >> 1)); } }