using System; using System.IO; using TrueCraft.API.Networking; using System.Text; namespace TrueCraft.Core.Networking { public class MinecraftStream : Stream, IMinecraftStream { public Stream BaseStream { get; set; } public Encoding StringEncoding { get; set; } public MinecraftStream(Stream baseStream) { BaseStream = baseStream; StringEncoding = Encoding.BigEndianUnicode; } public override bool CanRead { get { return BaseStream.CanRead; } } public override bool CanSeek { get { return BaseStream.CanSeek; } } public override bool CanWrite { get { return BaseStream.CanWrite; } } public override void Flush() { BaseStream.Flush(); } public override long Length { get { return BaseStream.Length; } } public override long Position { get { return BaseStream.Position; } set { BaseStream.Position = value; } } public override int Read(byte[] buffer, int offset, int count) { return BaseStream.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) { return BaseStream.Seek(offset, origin); } public override void SetLength(long value) { BaseStream.SetLength(value); } public override void Write(byte[] buffer, int offset, int count) { BaseStream.Write(buffer, offset, count); } public byte ReadUInt8() { int value = BaseStream.ReadByte(); if (value == -1) throw new EndOfStreamException(); return (byte)value; } public void WriteUInt8(byte value) { WriteByte(value); } public sbyte ReadInt8() { return (sbyte)ReadUInt8(); } public void WriteInt8(sbyte value) { WriteUInt8((byte)value); } public ushort ReadUInt16() { return (ushort)( (ReadUInt8() << 8) | ReadUInt8()); } public void WriteUInt16(ushort value) { Write(new[] { (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFF) }, 0, 2); } public short ReadInt16() { return (short)ReadUInt16(); } public void WriteInt16(short value) { WriteUInt16((ushort)value); } public uint ReadUInt32() { return (uint)( (ReadUInt8() << 24) | (ReadUInt8() << 16) | (ReadUInt8() << 8 ) | ReadUInt8()); } public void WriteUInt32(uint value) { Write(new[] { (byte)((value & 0xFF000000) >> 24), (byte)((value & 0xFF0000) >> 16), (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFF) }, 0, 4); } public int ReadInt32() { return (int)ReadUInt32(); } public void WriteInt32(int value) { WriteUInt32((uint)value); } public ulong ReadUInt64() { return unchecked( ((ulong)ReadUInt8() << 56) | ((ulong)ReadUInt8() << 48) | ((ulong)ReadUInt8() << 40) | ((ulong)ReadUInt8() << 32) | ((ulong)ReadUInt8() << 24) | ((ulong)ReadUInt8() << 16) | ((ulong)ReadUInt8() << 8) | (ulong)ReadUInt8()); } public void WriteUInt64(ulong value) { Write(new[] { (byte)((value & 0xFF00000000000000) >> 56), (byte)((value & 0xFF000000000000) >> 48), (byte)((value & 0xFF0000000000) >> 40), (byte)((value & 0xFF00000000) >> 32), (byte)((value & 0xFF000000) >> 24), (byte)((value & 0xFF0000) >> 16), (byte)((value & 0xFF00) >> 8), (byte)(value & 0xFF) }, 0, 8); } public long ReadInt64() { return (long)ReadUInt64(); } public void WriteInt64(long value) { WriteUInt64((ulong)value); } public byte[] ReadUInt8Array(int length) { var result = new byte[length]; if (length == 0) return result; int n = length; while (true) { n -= Read(result, length - n, n); if (n == 0) break; System.Threading.Thread.Sleep(1); } return result; } public void WriteUInt8Array(byte[] value) { Write(value, 0, value.Length); } public void WriteUInt8Array(byte[] value, int offset, int count) { Write(value, offset, count); } public sbyte[] ReadInt8Array(int length) { return (sbyte[])(Array)ReadUInt8Array(length); } public void WriteInt8Array(sbyte[] value) { Write((byte[])(Array)value, 0, value.Length); } public ushort[] ReadUInt16Array(int length) { var result = new ushort[length]; if (length == 0) return result; for (int i = 0; i < length; i++) result[i] = ReadUInt16(); return result; } public void WriteUInt16Array(ushort[] value) { for (int i = 0; i < value.Length; i++) WriteUInt16(value[i]); } public short[] ReadInt16Array(int length) { return (short[])(Array)ReadUInt16Array(length); } public void WriteInt16Array(short[] value) { WriteUInt16Array((ushort[])(Array)value); } public uint[] ReadUInt32Array(int length) { var result = new uint[length]; if (length == 0) return result; for (int i = 0; i < length; i++) result[i] = ReadUInt32(); return result; } public void WriteUInt32Array(uint[] value) { for (int i = 0; i < value.Length; i++) WriteUInt32(value[i]); } public int[] ReadInt32Array(int length) { return (int[])(Array)ReadUInt32Array(length); } public void WriteInt32Array(int[] value) { WriteUInt32Array((uint[])(Array)value); } public ulong[] ReadUInt64Array(int length) { var result = new ulong[length]; if (length == 0) return result; for (int i = 0; i < length; i++) result[i] = ReadUInt64(); return result; } public void WriteUInt64Array(ulong[] value) { for (int i = 0; i < value.Length; i++) WriteUInt64(value[i]); } public long[] ReadInt64Array(int length) { return (long[])(Array)ReadUInt64Array(length); } public void WriteInt64Array(long[] value) { WriteUInt64Array((ulong[])(Array)value); } public unsafe float ReadSingle() { uint value = ReadUInt32(); return *(float*)&value; } public unsafe void WriteSingle(float value) { WriteUInt32(*(uint*)&value); } public unsafe double ReadDouble() { ulong value = ReadUInt64(); return *(double*)&value; } public unsafe void WriteDouble(double value) { WriteUInt64(*(ulong*)&value); } public bool ReadBoolean() { return ReadUInt8() != 0; } public void WriteBoolean(bool value) { WriteUInt8(value ? (byte)1 : (byte)0); } public string ReadString() { short length = ReadInt16(); if (length == 0) return string.Empty; var data = ReadUInt8Array(length * 2); return StringEncoding.GetString(data); } public void WriteString(string value) { WriteInt16((short)value.Length); if (value.Length > 0) WriteUInt8Array(StringEncoding.GetBytes(value)); } // TODO: string8 is modified UTF-8, which has a special representation of the NULL character public string ReadString8() { short length = ReadInt16(); if (length == 0) return string.Empty; var data = ReadUInt8Array((int)length); return Encoding.UTF8.GetString(data); } public void WriteString8(string value) { WriteInt16((short)value.Length); if (value.Length > 0) WriteUInt8Array(Encoding.UTF8.GetBytes(value)); } } }