|
| 1 | +using System; |
| 2 | +using System.Runtime.InteropServices; |
| 3 | +using System.Text; |
| 4 | + |
| 5 | +namespace MLAPI.NetworkingManagerComponents.Binary |
| 6 | +{ |
| 7 | + public class BitReader |
| 8 | + { |
| 9 | + private delegate T Getter<T>(); |
| 10 | + private static readonly float[] holder_f = new float[1]; |
| 11 | + private static readonly double[] holder_d = new double[1]; |
| 12 | + private static readonly ulong[] holder_u = new ulong[1]; |
| 13 | + private static readonly uint[] holder_i = new uint[1]; |
| 14 | + |
| 15 | + private readonly byte[] readFrom; |
| 16 | + private long bitCount = 0; |
| 17 | + public BitReader(byte[] readFrom) => this.readFrom = readFrom; |
| 18 | + |
| 19 | + public bool ReadBool() |
| 20 | + { |
| 21 | + bool result = (readFrom[bitCount / 8] & (byte)(1 << (int)(bitCount % 8))) != 0; |
| 22 | + ++bitCount; |
| 23 | + return result; |
| 24 | + } |
| 25 | + |
| 26 | + public float ReadFloat() => ReadFloating<float>(); |
| 27 | + public double ReadDouble() => ReadFloating<double>(); |
| 28 | + public byte ReadByte() |
| 29 | + { |
| 30 | + int shift = (int)(bitCount % 8); |
| 31 | + int index = (int)(bitCount / 8); |
| 32 | + byte lower_mask = (byte)(0xFF << shift); |
| 33 | + byte upper_mask = (byte)~lower_mask; |
| 34 | + byte result = (byte)(((readFrom[index] & lower_mask) >> shift) | (shift == 0 ? 0 : (readFrom[index + 1] & upper_mask) << (8 - shift))); |
| 35 | + bitCount += 8; |
| 36 | + return result; |
| 37 | + } |
| 38 | + public void SkipPadded() => bitCount += (8 - (bitCount % 8)) % 8; |
| 39 | + public ushort ReadUShort() => (ushort)ReadULong(); |
| 40 | + public uint ReadUInt() => (uint)ReadULong(); |
| 41 | + public sbyte ReadSByte() => (sbyte)ZigZagDecode(ReadByte(), 1); |
| 42 | + public short ReadShort() => (short)ZigZagDecode(ReadUShort(), 2); |
| 43 | + public int ReadInt() => (int)ZigZagDecode(ReadUInt(), 4); |
| 44 | + public long ReadLong() => ZigZagDecode(ReadULong(), 8); |
| 45 | + public float[] ReadFloatArray(int known = -1) => ReadArray(ReadFloat, known); |
| 46 | + public double[] ReadDoubleArray(int known = -1) => ReadArray(ReadDouble, known); |
| 47 | + public byte[] ReadByteArray(int known = -1) => ReadArray(ReadByte, known); |
| 48 | + public ushort[] ReadUShortArray(int known = -1) => ReadArray(ReadUShort, known); |
| 49 | + public uint[] ReadUIntArray(int known = -1) => ReadArray(ReadUInt, known); |
| 50 | + public ulong[] ReadULongArray(int known = -1) => ReadArray(ReadULong, known); |
| 51 | + public sbyte[] ReadSByteArray(int known = -1) => ReadArray(ReadSByte, known); |
| 52 | + public short[] ReadShortArray(int known = -1) => ReadArray(ReadShort, known); |
| 53 | + public int[] ReadIntArray(int known = -1) => ReadArray(ReadInt, known); |
| 54 | + public long[] ReadLongArray(int known = -1) => ReadArray(ReadLong, known); |
| 55 | + public string ReadString() => Encoding.UTF8.GetString(ReadByteArray()); |
| 56 | + |
| 57 | + public ulong ReadULong() |
| 58 | + { |
| 59 | + ulong header = ReadByte(); |
| 60 | + if (header <= 240) return header; |
| 61 | + if (header <= 248) return 240 + 256 * (header - 241) + ReadByte(); |
| 62 | + if (header == 249) return 2288 + 256UL * ReadByte() + ReadByte(); |
| 63 | + ulong res = ReadByte() | ((ulong)ReadByte() << 8) | ((ulong)ReadByte() << 16); |
| 64 | + if(header > 250) |
| 65 | + { |
| 66 | + res |= (ulong) ReadByte() << 24; |
| 67 | + if(header > 251) |
| 68 | + { |
| 69 | + res |= (ulong)ReadByte() << 32; |
| 70 | + if(header > 252) |
| 71 | + { |
| 72 | + res |= (ulong)ReadByte() << 40; |
| 73 | + if (header > 253) |
| 74 | + { |
| 75 | + res |= (ulong)ReadByte() << 48; |
| 76 | + if (header > 254) res |= (ulong)ReadByte() << 56; |
| 77 | + } |
| 78 | + } |
| 79 | + } |
| 80 | + } |
| 81 | + return res; |
| 82 | + } |
| 83 | + private T[] ReadArray<T>(Getter<T> g, int knownSize = -1) |
| 84 | + { |
| 85 | + T[] result = new T[knownSize > 0 ? (uint)knownSize : ReadUInt()]; |
| 86 | + for (ushort s = 0; s < result.Length; ++s) |
| 87 | + result[s] = g(); |
| 88 | + return result; |
| 89 | + } |
| 90 | + |
| 91 | + private T ReadFloating<T>() |
| 92 | + { |
| 93 | + int size = Marshal.SizeOf(typeof(T)); |
| 94 | + Array type_holder = size == 4 ? holder_f as Array : holder_d as Array; |
| 95 | + Array result_holder = size == 4 ? holder_i as Array : holder_u as Array; |
| 96 | + T result; |
| 97 | + lock(result_holder) |
| 98 | + lock (type_holder) |
| 99 | + { |
| 100 | + //for (int i = 0; i < size; ++i) |
| 101 | + // holder.SetValue(ReadByte(), i); |
| 102 | + if (size == 4) result_holder.SetValue(BinaryHelpers.SwapEndian(ReadUInt()), 0); |
| 103 | + else result_holder.SetValue(BinaryHelpers.SwapEndian(ReadULong()), 0); |
| 104 | + Buffer.BlockCopy(result_holder, 0, type_holder, 0, size); |
| 105 | + result = (T)type_holder.GetValue(0); |
| 106 | + } |
| 107 | + return result; |
| 108 | + } |
| 109 | + private static long ZigZagDecode(ulong d, int bytes) => (long)(((d << (bytes * 8 - 1)) & 1) | (d >> 1)); |
| 110 | + } |
| 111 | +} |
0 commit comments