using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ChatRoomServer.Main.Entities { using System.IO; using System.Threading; class EntityUtility { static readonly string EncryptKey = "iFishMessagePack"; static readonly byte[] EncryptKeyBuffer = Encoding.ASCII.GetBytes(EncryptKey); static readonly int EncStart = 1; static readonly Random Random = new Random(); public static MessageItem FromBuffer(byte[] buffer) { if (buffer.Length < 1 + EncryptKeyBuffer.Length || buffer[0] >= EncryptKeyBuffer.Length) return null; //decrypt key var key = EncryptKeyBuffer[buffer[0]]; for (int i = EncStart; i < buffer.Length; i++) { var tkey = key; key = buffer[i]; buffer[i] ^= tkey; } //read prefix var index = 1; if (Encoding.ASCII.GetString(buffer, index, EncryptKeyBuffer.Length) != EncryptKey) return null; index += EncryptKeyBuffer.Length; var item = new MessageItem(); item.Action = ReadString(buffer, ref index); item.Success = buffer[index++] == 1; item.Time = System.FishDateTimeExtension.JsTicksStartBase.AddTicks(BitConverter.ToInt64(buffer, index) * 10000); index += 8; item.SystemMessage = buffer[index++] == 1; item.SysMsgType = (SystemMessageType)BitConverter.ToInt32(buffer, index); index += 4; item.UserMsgType = (UserMessageType)BitConverter.ToInt32(buffer, index); index += 4; item.Content = ReadString(buffer, ref index); item.Color = ReadString(buffer, ref index); //images var imgCount = BitConverter.ToInt32(buffer, index); index += 4; if (imgCount > 0) { item.Images = new string[imgCount]; for (int i = 0; i < imgCount; i++) { item.Images[i] = ReadString(buffer, ref index); } } //from item.From = ReadString(buffer, ref index); //to var tousersCount = BitConverter.ToInt32(buffer, index); index += 4; if (tousersCount > 0) { item.ToUsers = new string[tousersCount]; for (int i = 0; i < tousersCount; i++) { item.ToUsers[i] = ReadString(buffer, ref index); } } return item; } static string ReadString(byte[] data, ref int index) { var unicode = data[index++] == 1; var length = BitConverter.ToInt32(data, index); index += 4; var result = (unicode ? Encoding.Unicode : Encoding.ASCII).GetString(data, index, length); index += length; return result; } public static byte[] ToBuffer(MessageItem item) { var length = (item.Content?.Length ?? 0) * 3 + 100; var randomKeyIndex = Random.Next(EncryptKey.Length); var randomKey = (byte)EncryptKey[randomKeyIndex]; using (var ms = new MemoryStream(length)) { //1. write encrypt key ms.Write(new byte[] { (byte)randomKeyIndex }); //1. write package header ms.Write(EncryptKeyBuffer); //3. write action Write(ms, item.Action, false); //4. write success ms.Write(new[] { (byte)(item.Success ? 1 : 0) }); //5. write time ms.Write(item.Time.ToJsTicks()); //6. system message ms.Write(new[] { (byte)(item.SystemMessage ? 1 : 0) }); //7. ms.Write((int)item.SysMsgType); //8. ms.Write((int)item.UserMsgType); //9. content Write(ms, item.Content, true); //10. color Write(ms, item.Color, false); //11. images ms.Write(item.Images?.Length ?? 0); if (item.Images != null) { foreach (var image in item.Images) { Write(ms, image, false); } } //12. from user Write(ms, item.From, false); //13. to user ms.Write(item.ToUsers?.Length ?? 0); if (item.ToUsers != null) { foreach (var user in item.ToUsers) { Write(ms, user, false); } } var data = ms.ToArray(); for (int i = EncStart; i < data.Length; i++) { randomKey = data[i] ^= randomKey; } return data; } } static void Write(Stream stream, string text, bool unicode = true) { text = text ?? ""; var buffer = unicode ? Encoding.Unicode.GetBytes(text) : Encoding.ASCII.GetBytes(text); stream.Write(new[] { (byte)(unicode ? 1 : 0) }); stream.Write(buffer.Length); stream.Write(buffer); } } }