using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Tofvesson.Common; using Tofvesson.Crypto; namespace Common { // Helper methods. WithHeader() should really just be in Support.cs public static class NetSupport { public enum Compression { int16, int32, int64 } public static byte[] WithHeader(string message) => WithHeader(Encoding.UTF8.GetBytes(message)); public static byte[] WithHeader(byte[] message) { int i = BinaryHelpers.VarIntSize(message.Length); byte[] nmsg = new byte[message.Length + i]; //Support.WriteToArray(nmsg, message.Length, 0); BinaryHelpers.WriteVarInt(nmsg, 0, message.Length); Array.Copy(message, 0, nmsg, i, message.Length); Debug.WriteLine($"Compression: {nmsg.Length}/{Compress(nmsg, Compression.int16).Length}/{Compress(nmsg, Compression.int32).Length}/{Compress(nmsg, Compression.int64).Length}"); Debug.WriteLine($"Matches: {Support.ArraysEqual(nmsg, Decompress(Compress(nmsg)))}"); return nmsg; } public static byte[] Decompress(byte[] cmpMessage, Compression method = Compression.int32) { BitReader reader = new BitReader(cmpMessage); byte[] decomp = new byte[reader.ReadUInt()]; int size = method == Compression.int16 ? 2 : method == Compression.int32 ? 4 : 8; int count = (decomp.Length / size) + (decomp.Length % size == 0 ? 0 : 1); for(int i = 0; i= 0; --j) decomp[(i * size) + j] = (byte)((int)(value >> (8 * j)) & 0xFF); } return decomp; } public static byte[] FromHeaded(byte[] msg, int offset) => msg.SubArray(offset + 4, offset + 4 + Support.ReadInt(msg, offset)); internal static void DoStateCheck(bool state, bool target) { if (state != target) throw new InvalidOperationException("Bad state!"); } private delegate void WriteFunc(BitWriter writer, byte[] data, int index); private static WriteFunc func16 = (w, d, i) => w.WriteUShort(ReadUShort(d, i * 2)), func32 = (w, d, i) => w.WriteUInt(ReadUInt(d, i * 4)), func64 = (w, d, i) => w.WriteULong(ReadULong(d, i * 8)); private static byte[] Compress(byte[] data, Compression method = Compression.int32) { int size = method == Compression.int16 ? 2 : method == Compression.int32 ? 4 : 8; int count = (data.Length / size) + (data.Length % size == 0 ? 0 : 1); WriteFunc func = size == 2 ? func16 : size == 4 ? func32 : func64; using (BitWriter writer = new BitWriter()) { writer.WriteUInt((uint)data.Length); for (int i = 0; i < count; ++i) func(writer, data, i); return writer.Finalize(); } } private static ushort ReadUShort(byte[] b, int offset) => (ushort)((ushort)TryReadByte(b, offset) | (ushort)((ushort)TryReadByte(b, offset + 1) << 8)); private static uint ReadUInt(byte[] b, int offset) => (uint)TryReadByte(b, offset) | ((uint)TryReadByte(b, offset + 1) << 8) | ((uint)TryReadByte(b, offset + 2) << 16) | ((uint)TryReadByte(b, offset + 3) << 24); private static ulong ReadULong(byte[] b, int offset) => (ulong)TryReadByte(b, offset) | ((ulong)TryReadByte(b, offset + 1) << 8) | ((ulong)TryReadByte(b, offset + 2) << 16) | ((ulong)TryReadByte(b, offset + 3) << 24) | ((ulong)TryReadByte(b, offset + 4) << 32) | ((ulong)TryReadByte(b, offset + 5) << 40) | ((ulong)TryReadByte(b, offset + 6) << 48) | ((ulong)TryReadByte(b, offset + 7) << 56); private static byte TryReadByte(byte[] b, int idx) => idx >= b.Length ? (byte) 0 : b[idx]; } }