using System; using System.Text; namespace KaduhServer { public class Packet { private const int DEFAULT_SIZE = 256; public readonly ushort Opcode; private byte[] mData = null; private int mWriteCursor = 0; private int mReadCursor = 0; public Packet(ushort pOpcode) { Opcode = pOpcode; mData = new byte[DEFAULT_SIZE]; WriteUShort(pOpcode); } public Packet(byte[] pData, int pStart, int pLength) { Decrypt(ref pData, pStart, pLength); mData = new byte[pLength]; Opcode = BitConverter.ToUInt16(pData, pStart); WriteBytes(pData, pStart, pLength); } protected byte[] Data { get { return mData; } } public int Length { get { return mWriteCursor; } } public int Cursor { get { return mReadCursor; } } public int Remaining { get { return mWriteCursor - mReadCursor; } } private void Prepare(int pLength) { if (mData.Length - mWriteCursor >= pLength) return; int newSize = mData.Length * 2; while (newSize < mWriteCursor + pLength) newSize *= 2; Array.Resize(ref mData, newSize); } public void Rewind(int pPosition) { if (pPosition < 0) pPosition = 0; else if (pPosition > mWriteCursor) pPosition = mWriteCursor; mReadCursor = pPosition; } public void WriteSkip(int pLength) { Prepare(pLength); mWriteCursor += pLength; } public void WriteBool(bool pValue) { Prepare(1); mData[mWriteCursor++] = (byte)(pValue ? 1 : 0); } public void WriteByte(byte pValue) { Prepare(1); mData[mWriteCursor++] = pValue; } public void WriteSByte(sbyte pValue) { Prepare(1); mData[mWriteCursor++] = (byte)pValue; } public void WriteBytes(byte[] pBytes) { WriteBytes(pBytes, 0, pBytes.Length); } public void WriteBytes(byte[] pBytes, int pStart, int pLength) { if (pLength <= 0) return; Prepare(pLength); Buffer.BlockCopy(pBytes, pStart, mData, mWriteCursor, pLength); mWriteCursor += pLength; } public void WriteUShort(ushort pValue) { Prepare(2); mData[mWriteCursor++] = (byte)(pValue & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 8) & 0xFF); } public void WriteShort(short pValue) { Prepare(2); mData[mWriteCursor++] = (byte)(pValue & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 8) & 0xFF); } public void WriteUInt(uint pValue) { Prepare(4); mData[mWriteCursor++] = (byte)(pValue & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 8) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 16) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 24) & 0xFF); } public void WriteInt(int pValue) { Prepare(4); mData[mWriteCursor++] = (byte)(pValue & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 8) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 16) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 24) & 0xFF); } public void WriteFloat(float pValue) { byte[] buffer = BitConverter.GetBytes(pValue); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); WriteBytes(buffer); } public void WriteULong(ulong pValue) { Prepare(8); mData[mWriteCursor++] = (byte)(pValue & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 8) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 16) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 24) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 32) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 40) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 48) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 56) & 0xFF); } public void WriteLong(long pValue) { Prepare(8); mData[mWriteCursor++] = (byte)(pValue & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 8) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 16) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 24) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 32) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 40) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 48) & 0xFF); mData[mWriteCursor++] = (byte)((pValue >> 56) & 0xFF); } public void WriteDouble(double pValue) { byte[] buffer = BitConverter.GetBytes(pValue); if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); WriteBytes(buffer); } public void WriteString(string pValue) { WriteUShort((ushort)pValue.Length); WriteBytes(Encoding.ASCII.GetBytes(pValue)); } public void WritePaddedString(string pValue, int pLength) { byte[] buffer = Encoding.ASCII.GetBytes(pValue); Array.Resize(ref buffer, pLength); WriteBytes(buffer); } public bool ReadSkip(int pLength) { if (mReadCursor + pLength > mWriteCursor) return false; mReadCursor += pLength; return true; } public bool ReadBool(out bool pValue) { pValue = false; if (mReadCursor + 1 > mWriteCursor) return false; pValue = mData[mReadCursor++] != 0; return true; } public bool ReadByte(out byte pValue) { pValue = 0; if (mReadCursor + 1 > mWriteCursor) return false; pValue = mData[mReadCursor++]; return true; } public bool ReadSByte(out sbyte pValue) { pValue = 0; if (mReadCursor + 1 > mWriteCursor) return false; pValue = (sbyte)mData[mReadCursor++]; return true; } public bool ReadBytes(byte[] pBytes) { return ReadBytes(pBytes, 0, pBytes.Length); } public bool ReadBytes(byte[] pBytes, int pStart, int pLength) { if (mReadCursor + pLength > mWriteCursor) return false; Buffer.BlockCopy(mData, mReadCursor, pBytes, pStart, pLength); mReadCursor += pLength; return true; } public bool ReadUShort(out ushort pValue) { pValue = 0; if (mReadCursor + 2 > mWriteCursor) return false; pValue = mData[mReadCursor++]; pValue |= (ushort)(mData[mReadCursor++] << 8); return true; } public bool ReadShort(out short pValue) { pValue = 0; if (mReadCursor + 2 > mWriteCursor) return false; pValue = mData[mReadCursor++]; pValue |= (short)(mData[mReadCursor++] << 8); return true; } public bool ReadFloat(out float pValue) { pValue = 0; byte[] buffer = new byte[4]; if (!ReadBytes(buffer)) return false; if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); pValue = BitConverter.ToSingle(buffer, 0); return true; } public bool ReadUInt(out uint pValue) { pValue = 0; if (mReadCursor + 4 > mWriteCursor) return false; pValue = mData[mReadCursor++]; pValue |= (uint)(mData[mReadCursor++] << 8); pValue |= (uint)(mData[mReadCursor++] << 16); pValue |= (uint)(mData[mReadCursor++] << 24); return true; } public bool ReadInt(out int pValue) { pValue = 0; if (mReadCursor + 4 > mWriteCursor) return false; pValue = mData[mReadCursor++]; pValue |= (mData[mReadCursor++] << 8); pValue |= (mData[mReadCursor++] << 16); pValue |= (mData[mReadCursor++] << 24); return true; } public bool ReadULong(out ulong pValue) { pValue = 0; if (mReadCursor + 8 > mWriteCursor) return false; pValue = mData[mReadCursor++]; pValue |= ((ulong)mData[mReadCursor++] << 8); pValue |= ((ulong)mData[mReadCursor++] << 16); pValue |= ((ulong)mData[mReadCursor++] << 24); pValue |= ((ulong)mData[mReadCursor++] << 32); pValue |= ((ulong)mData[mReadCursor++] << 40); pValue |= ((ulong)mData[mReadCursor++] << 48); pValue |= ((ulong)mData[mReadCursor++] << 56); return true; } public bool ReadLong(out long pValue) { pValue = 0; if (mReadCursor + 8 > mWriteCursor) return false; pValue = mData[mReadCursor++]; pValue |= ((long)mData[mReadCursor++] << 8); pValue |= ((long)mData[mReadCursor++] << 16); pValue |= ((long)mData[mReadCursor++] << 24); pValue |= ((long)mData[mReadCursor++] << 32); pValue |= ((long)mData[mReadCursor++] << 40); pValue |= ((long)mData[mReadCursor++] << 48); pValue |= ((long)mData[mReadCursor++] << 56); return true; } public bool ReadDouble(out double pValue) { pValue = 0; byte[] buffer = new byte[8]; if (!ReadBytes(buffer)) return false; if (!BitConverter.IsLittleEndian) Array.Reverse(buffer); pValue = BitConverter.ToDouble(buffer, 0); return true; } public bool ReadString(out string pValue, ushort pLength) { pValue = ""; if (mReadCursor + pLength > mWriteCursor) return false; pValue = Encoding.ASCII.GetString(mData, mReadCursor, pLength); mReadCursor += pLength; return true; } public bool ReadString(out string pValue) { pValue = ""; if (mReadCursor + 2 > mWriteCursor) return false; ushort len; ReadUShort(out len); return ReadString(out pValue, len); } public bool ReadPaddedString(out string pValue, int pLength) { pValue = ""; if (mReadCursor + pLength > mWriteCursor) return false; int length = 0; while (mData[mReadCursor + length] != 0x00 && length < pLength) ++length; if (length > 0) pValue = Encoding.ASCII.GetString(mData, mReadCursor, length); mReadCursor += pLength; return true; } public byte[] ToArray() { byte[] toRet = new byte[mWriteCursor]; Buffer.BlockCopy(mData, 0, toRet, 0, mWriteCursor); Decrypt(ref toRet, 0, toRet.Length); return toRet; } public static void Decrypt(ref byte[] data, int index, int length) { if (((index < 0) | (length < 1)) | ((index + length) > data.Length)) { throw new IndexOutOfRangeException(); } byte num = (byte)length; for (int i = length - 1; i >= 0; --i) { data[i] = (byte)(data[i] ^ num); byte num3 = (byte)i; num3 = (byte)(num3 & 15); num3 = (byte)(num3 + 0x55); num3 = (byte)(num3 ^ ((byte)(((byte)i) * 11))); num3 = (byte)(num3 ^ num); num3 = (byte)(num3 ^ 170); num = num3; } } } }