using System.Collections.Generic; using System; using System.Text; namespace NeonTea.Quakeball.TeaNet.Packets { /// Contains a stream of bytes for sending or receiving over the internet. public class ByteBuffer { public int Size => Bytes.Count; private List Bytes; private int pos = 0; /// Creates a new empty ByteBuffer public ByteBuffer() { Bytes = new List(); } /// Creates a new ByteBuffer from the given byte[] public ByteBuffer(byte[] bytes) { Bytes = new List(bytes); } /// Packs the byte buffer in to a byte[] array. public byte[] Pack() { return Bytes.ToArray(); } /// is there a byte to read next? public bool CanRead() { return pos < Bytes.Count; } /// Reads a given object with Serializable implemented. Assumes there is one next. public void ReadSerializable(Serializable s) { s.Read(this); } /// Read a char on the buffer. Assumes there is one next. public char ReadChar() { return BitConverter.ToChar(Read(2), 0); } /// Read a boolean on the buffer. Assumes there is one next. public bool ReadBool() { return Read() == 1; } /// Read a double on the buffer. Assumes there is one next. public double ReadDouble() { return BitConverter.ToDouble(Read(8), 0); } /// Read a float on the buffer. Assumes there is one next. public float ReadFloat() { return BitConverter.ToSingle(Read(4), 0); } /// Read an unsigned long on the buffer. Assumes there is one next. public ulong ReadULong() { return BitConverter.ToUInt64(Read(8), 0); } /// Read an unsigned integer on the buffer. Assumes there is one next. public uint ReadUInt() { return BitConverter.ToUInt32(Read(4), 0); } /// Read an unsigned short on the buffer. Assumes there is one next. public ushort ReadUShort() { return BitConverter.ToUInt16(Read(2), 0); } /// Read a long on the buffer. Assumes there is one next. public long ReadLong() { return BitConverter.ToInt64(Read(8), 0); } /// Read an integer on the buffer. Assumes there is one next. public int ReadInt() { return BitConverter.ToInt32(Read(4), 0); } /// Read a short on the buffer. Assumes there is one next. public short ReadShort() { return BitConverter.ToInt16(Read(2), 0); } /// Read a string on the buffer. Assumes there is one next. public string ReadString() { int length = ReadInt(); string s = Encoding.UTF8.GetString(Read(length)); return s; } /// Read an integer on the buffer. Assumes there is one next. public byte[] Read(int amount) { byte[] bytes = Bytes.GetRange(pos, amount).ToArray(); pos += amount; return bytes; } /// Read the next byte on the buffer. Assumes there is one next. public byte Read() { return Bytes[pos++]; } /// Write something that implements Serializable. public void Write(Serializable s) { s.Write(this); } /// Write a char to the buffer. public void Write(char c) { Bytes.AddRange(BitConverter.GetBytes(c)); } /// Write a boolean to the buffer. public void Write(bool b) { Write(b ? (byte)0b1 : (byte)0b0); } /// Write a double to the buffer. public void Write(double d) { Bytes.AddRange(BitConverter.GetBytes(d)); } /// Write a float to the buffer. public void Write(float f) { Bytes.AddRange(BitConverter.GetBytes(f)); } /// Write an unsigned long to the buffer. public void Write(ulong l) { Bytes.AddRange(BitConverter.GetBytes(l)); } /// Write an unsigned integer to the buffer. public void Write(uint i) { Bytes.AddRange(BitConverter.GetBytes(i)); } /// Write an unsigned short to the buffer. public void Write(ushort s) { Bytes.AddRange(BitConverter.GetBytes(s)); } /// Write a long to the buffer. public void Write(long l) { Bytes.AddRange(BitConverter.GetBytes(l)); } /// Write an integer to the buffer. public void Write(int i) { Bytes.AddRange(BitConverter.GetBytes(i)); } /// Write a short to the buffer. public void Write(short s) { Bytes.AddRange(BitConverter.GetBytes(s)); } /// Write a string to the buffer. public void Write(string s) { byte[] bytes = Encoding.UTF8.GetBytes(s); Write(bytes.Length); Bytes.AddRange(bytes); } /// Write a byte to the buffer. public void Write(byte b) { Bytes.Add(b); } /// Read weather the given fingerprint is next on the buffer. public bool ReadFingerprint(byte[] fingerprint) { foreach (byte b in fingerprint) { if (!(CanRead() && Read() == b)) { return false; } } return true; } public PacketStage ReadStage() { PacketStage stage = PacketStage.Closed; switch (Read()) { case 0: stage = PacketStage.Establishing; break; case 1: stage = PacketStage.Rejected; break; case 2: stage = PacketStage.Closed; break; case 3: stage = PacketStage.Ready; break; } return stage; } public ClosingReason ReadClosingReason() { ClosingReason reason = ClosingReason.Unknown; switch (Read()) { case 0: reason = ClosingReason.Unknown; break; case 1: reason = ClosingReason.IncorrectVersion; break; } return reason; } /// Write an entire packet using the protocol to the buffer. public void WritePacket(Protocol protocol, Packet p) { int old = Bytes.Count; Write(protocol.GetPacketTypeID(p)); p.Write(this); p.Size = Bytes.Count - old; } /// Read an entire packet using the given protocol from the buffer. public Packet ReadPacket(Protocol protocol) { int old = pos; int packetType = ReadInt(); Type t = protocol.GetPacketType(packetType); Packet p = (Packet)Activator.CreateInstance(t); p.Read(this); p.Size = pos - old; return p; } } }