using Mina.Core.Buffer; using System; using System.Collections.Generic; using System.Text; namespace FSO.Common.Serialization { public static class IoBufferUtils { public static void PutSerializable(this IoBuffer buffer, object obj, ISerializationContext context) { buffer.PutSerializable(context, obj, false); } public static byte[] GetBytes(this IoBuffer buffer) { var result = new byte[buffer.Limit]; buffer.Get(result, 0, buffer.Limit); return result; } public static T Deserialize(byte[] bytes, ISerializationContext context) where T : IoBufferDeserializable { var buffer = IoBuffer.Wrap(bytes); return Deserialize(buffer, context); } public static T Deserialize(IoBuffer buffer, ISerializationContext context) where T : IoBufferDeserializable { var model = Activator.CreateInstance(); model.Deserialize(buffer, context); return (T)model; } public static IoBuffer SerializableToIoBuffer(object obj, ISerializationContext context) { if (obj is IoBuffer) { var ioBuffer = (IoBuffer)obj; return (IoBuffer)ioBuffer; } else if (obj is byte[]) { var byteArray = (byte[])obj; return IoBuffer.Wrap(byteArray); } else if (obj is IoBufferSerializable) { var ioBuffer = IoBuffer.Allocate(0); ioBuffer.AutoExpand = true; ioBuffer.Order = ByteOrder.BigEndian; var serializable = (IoBufferSerializable)obj; serializable.Serialize(ioBuffer, context); ioBuffer.Flip(); return ioBuffer; } throw new Exception("Unknown serializable type: " + obj); } public static void PutSerializable(this IoBuffer buffer, ISerializationContext context, object obj, bool writeLength) { if(obj is IoBuffer) { var ioBuffer = (IoBuffer)obj; if (writeLength){ buffer.PutUInt32((uint)ioBuffer.Remaining); } buffer.Put(ioBuffer); }else if(obj is byte[]) { var byteArray = (byte[])obj; if (writeLength) { buffer.PutUInt32((uint)byteArray.Length); } buffer.Put(byteArray); }else if(obj is IoBufferSerializable) { var ioBuffer = IoBuffer.Allocate(0); ioBuffer.AutoExpand = true; ioBuffer.Order = ByteOrder.BigEndian; var serializable = (IoBufferSerializable)obj; serializable.Serialize(ioBuffer, context); ioBuffer.Flip(); if (writeLength) { buffer.PutUInt32((uint)ioBuffer.Remaining); } buffer.Put(ioBuffer); } } public static void PutBool(this IoBuffer buffer, bool value) { buffer.Put(value ? (byte)0x01 : (byte)0x00); } public static bool GetBool(this IoBuffer buffer) { return buffer.Get() == 1 ? true : false; } public static void PutUInt32(this IoBuffer buffer, uint value) { int converted = unchecked((int)value); buffer.PutInt32(converted); } public static uint GetUInt32(this IoBuffer buffer) { return (uint)buffer.GetInt32(); } public static void PutUInt16(this IoBuffer buffer, ushort value) { buffer.PutInt16((short)value); } public static void PutUInt64(this IoBuffer buffer, ulong value) { buffer.PutInt64((long)value); } public static void PutEnum(this IoBuffer buffer, T enumValue) { ushort value = Convert.ToUInt16((object)enumValue); buffer.PutUInt16(value); } public static void PutUTF8(this IoBuffer buffer, string value) { if (value == null) { buffer.PutInt16(-1); } else { buffer.PutInt16((short)value.Length); buffer.PutString(value, Encoding.UTF8); } } public static string GetUTF8(this IoBuffer buffer) { short len = buffer.GetInt16(); if (len == -1) { return null; } return buffer.GetString(len, Encoding.UTF8); } public static ushort GetUInt16(this IoBuffer buffer) { return (ushort)buffer.GetInt16(); } public static ulong GetUInt64(this IoBuffer buffer) { return (ulong)buffer.GetInt64(); } public static T GetEnum(this IoBuffer buffer) { return (T)System.Enum.Parse(typeof(T), buffer.GetUInt16().ToString()); } public static String GetPascalVLCString(this IoBuffer buffer) { byte lengthByte = 0; uint length = 0; int shift = 0; do { lengthByte = buffer.Get(); length |= (uint)((lengthByte & (uint)0x7F) << shift); shift += 7; } while ( (lengthByte >> 7) == 1 ); if (length > 0) { var data = new List(); for (int i = 0; i < length; i++) { data.Add(buffer.Get()); } return Encoding.UTF8.GetString(data.ToArray()); } else { return ""; } } public static byte[] GetPascalVLCString(String value) { if(value == null) { return new byte[] { 0x00 }; } //TODO: Support strings bigger than 128 chars var buffer = new byte[1 + value.Length]; buffer[0] = (byte)value.Length; var chars = value.ToCharArray(); for(int i=0; i < chars.Length; i++){ buffer[i + 1] = (byte)chars[i]; } return buffer; } public static void PutPascalVLCString(this IoBuffer buffer, String value) { byte[] encode = null; long strlen = 0; if (value != null) { encode = Encoding.UTF8.GetBytes(value); strlen = encode.Length; } bool write = strlen > 0; bool first = true; while (strlen > 0 || first) { buffer.Put((byte)(((strlen > 127) ? (uint)128 : 0) | (strlen & 127))); strlen >>= 7; first = false; } if (write) { buffer.Put(encode); } } public static String GetPascalString(this IoBuffer buffer) { byte len1 = buffer.Get(); byte len2 = buffer.Get(); byte len3 = buffer.Get(); byte len4 = buffer.Get(); len1 &= 0x7F; long len = len1 << 24 | len2 << 16 | len3 << 8 | len4; if (len > 0) { StringBuilder str = new StringBuilder(); for (int i = 0; i < len; i++) { str.Append((char)buffer.Get()); } return str.ToString(); } else { return ""; } } public static void PutPascalString(this IoBuffer buffer, String value) { long strlen = 0; if (value != null) { strlen = value.Length; } byte len1 = (byte)((strlen >> 24) | 0x80); byte len2 = (byte)((strlen >> 16) & 0xFF); byte len3 = (byte)((strlen >> 8) & 0xFF); byte len4 = (byte)(strlen & 0xFF); buffer.Put(len1); buffer.Put(len2); buffer.Put(len3); buffer.Put(len4); if (strlen > 0) { foreach (char ch in value.ToCharArray()) { buffer.Put((byte)ch); } } } } }