using System; 
 | 
using System.Collections.Generic; 
 | 
using System.IO; 
 | 
using System.Text; 
 | 
  
 | 
namespace Taobao.Top.Link.Endpoints 
 | 
{ 
 | 
    //simple protocol impl, match protocolVersion=2 
 | 
    public class MessageIO 
 | 
    { 
 | 
        public static Message ReadMessage(Stream input) 
 | 
        { 
 | 
            var buffer = new BinaryReader(input); 
 | 
            Message msg = new Message(); 
 | 
            msg.ProtocolVersion = buffer.ReadByte(); 
 | 
            msg.MessageType = buffer.ReadByte(); 
 | 
            // read kv 
 | 
            IDictionary<string, object> dict = new Dictionary<string, object>(); 
 | 
            short headerType = buffer.ReadInt16(); 
 | 
            while (headerType != MessageType.HeaderType.EndOfHeaders) 
 | 
            { 
 | 
                if (headerType == MessageType.HeaderType.Custom) 
 | 
                    dict.Add(ReadCountedString(buffer), ReadCustomValue(buffer)); 
 | 
                else if (headerType == MessageType.HeaderType.StatusCode) 
 | 
                    msg.StatusCode = buffer.ReadInt32(); 
 | 
                else if (headerType == MessageType.HeaderType.StatusPhrase) 
 | 
                    msg.StatusPhase = ReadCountedString(buffer); 
 | 
                else if (headerType == MessageType.HeaderType.Flag) 
 | 
                    msg.Flag = buffer.ReadInt32(); 
 | 
                else if (headerType == MessageType.HeaderType.Token) 
 | 
                    msg.Token = ReadCountedString(buffer); 
 | 
                headerType = buffer.ReadInt16(); 
 | 
            } 
 | 
            msg.Content = dict; 
 | 
            return msg; 
 | 
        } 
 | 
        public static void WriteMessage(Stream input, Message message) 
 | 
        { 
 | 
            var buffer = new BinaryWriter(input); 
 | 
            buffer.Write((byte)message.ProtocolVersion); 
 | 
            buffer.Write((byte)message.MessageType); 
 | 
  
 | 
            if (message.StatusCode > 0) 
 | 
            { 
 | 
                buffer.Write(MessageType.HeaderType.StatusCode); 
 | 
                buffer.Write(message.StatusCode); 
 | 
            } 
 | 
            if (message.StatusPhase != null && message.StatusPhase != "") 
 | 
            { 
 | 
                buffer.Write(MessageType.HeaderType.StatusPhrase); 
 | 
                WriteCountedString(buffer, message.StatusPhase); 
 | 
            } 
 | 
            if (message.Flag > 0) 
 | 
            { 
 | 
                buffer.Write(MessageType.HeaderType.Flag); 
 | 
                buffer.Write(message.Flag); 
 | 
            } 
 | 
            if (message.Token != null && message.Token != "") 
 | 
            { 
 | 
                buffer.Write(MessageType.HeaderType.Token); 
 | 
                WriteCountedString(buffer, message.Token); 
 | 
            } 
 | 
            if (message.Content != null) 
 | 
            { 
 | 
                foreach (var i in message.Content) 
 | 
                    WriteCustomHeader(buffer, i.Key, i.Value); 
 | 
            } 
 | 
            buffer.Write(MessageType.HeaderType.EndOfHeaders); 
 | 
        } 
 | 
        // UTF-8 only 
 | 
        private static string ReadCountedString(BinaryReader buffer) 
 | 
        { 
 | 
            int size = buffer.ReadInt32(); 
 | 
            return size > 0 ? Encoding.UTF8.GetString(buffer.ReadBytes(size)) : null; 
 | 
        } 
 | 
        private static void WriteCountedString(BinaryWriter buffer, string value) 
 | 
        { 
 | 
            int strLength = 0; 
 | 
            if (value != null) 
 | 
                strLength = value.Length; 
 | 
  
 | 
            if (strLength > 0) 
 | 
            { 
 | 
                byte[] strBytes = Encoding.UTF8.GetBytes(value); 
 | 
                buffer.Write(strBytes.Length); 
 | 
                buffer.Write(strBytes); 
 | 
            } 
 | 
            else 
 | 
                buffer.Write(0); 
 | 
        } 
 | 
        private static void WriteCustomHeader(BinaryWriter buffer, string name, object value) 
 | 
        { 
 | 
            buffer.Write(MessageType.HeaderType.Custom); 
 | 
            WriteCountedString(buffer, name); 
 | 
            WriteCustomValue(buffer, value); 
 | 
        } 
 | 
        private static object ReadCustomValue(BinaryReader buffer) 
 | 
        { 
 | 
            byte format = buffer.ReadByte(); 
 | 
            switch (format) 
 | 
            { 
 | 
                case MessageType.ValueFormat.Void: 
 | 
                    return null; 
 | 
                case MessageType.ValueFormat.Byte: 
 | 
                    return buffer.ReadByte(); 
 | 
                case MessageType.ValueFormat.Int16: 
 | 
                    return buffer.ReadInt16(); 
 | 
                case MessageType.ValueFormat.Int32: 
 | 
                    return buffer.ReadInt32(); 
 | 
                case MessageType.ValueFormat.Int64: 
 | 
                    return buffer.ReadInt64(); 
 | 
                case MessageType.ValueFormat.Date: 
 | 
                    return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1).AddMilliseconds(buffer.ReadInt64())); 
 | 
                case MessageType.ValueFormat.ByteArray: 
 | 
                    return buffer.ReadBytes(buffer.ReadInt32()); 
 | 
                default: 
 | 
                    return ReadCountedString(buffer); 
 | 
            } 
 | 
        } 
 | 
        private static void WriteCustomValue(BinaryWriter buffer, object value) 
 | 
        { 
 | 
            if (value == null) 
 | 
            { 
 | 
                buffer.Write(MessageType.ValueFormat.Void); 
 | 
                return; 
 | 
            } 
 | 
            Type type = value.GetType(); 
 | 
            if (typeof(byte).Equals(type) || typeof(Byte).Equals(type)) 
 | 
            { 
 | 
                buffer.Write(MessageType.ValueFormat.Byte); 
 | 
                buffer.Write((byte)value); 
 | 
            } 
 | 
            else if (typeof(short).Equals(type)) 
 | 
            { 
 | 
                buffer.Write(MessageType.ValueFormat.Int16); 
 | 
                buffer.Write((short)value); 
 | 
            } 
 | 
            else if (typeof(int).Equals(type) || typeof(Int32).Equals(type)) 
 | 
            { 
 | 
                buffer.Write(MessageType.ValueFormat.Int32); 
 | 
                buffer.Write((int)value); 
 | 
            } 
 | 
            else if (typeof(long).Equals(type) || typeof(Int64).Equals(type)) 
 | 
            { 
 | 
                buffer.Write(MessageType.ValueFormat.Int64); 
 | 
                buffer.Write((long)value); 
 | 
            } 
 | 
            else if (typeof(DateTime).Equals(type)) 
 | 
            { 
 | 
                buffer.Write(MessageType.ValueFormat.Date); 
 | 
                buffer.Write(((DateTime)value).Ticks); 
 | 
            } 
 | 
            else if (typeof(byte[]).Equals(type)) 
 | 
            { 
 | 
                buffer.Write(MessageType.ValueFormat.ByteArray); 
 | 
                var data = value as byte[]; 
 | 
                buffer.Write(data.Length); 
 | 
                buffer.Write(data); 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                buffer.Write(MessageType.ValueFormat.CountedString); 
 | 
                WriteCountedString(buffer, (string)value); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
} 
 |