예제 #1
0
        public static Richtext Parse(BinaryReader reader)
        {
            var result = new Richtext();

            // TODO: 解析富文本
            try
            {
                var messageType = reader.ReadByte();
                var dataLength  = reader.BeReadUInt16();
                var pos         = reader.BaseStream.Position;
                while (pos + dataLength < reader.BaseStream.Length)
                {
                    reader.ReadByte();

                    switch (messageType)
                    {
                    case 0x01:     // 纯文本消息、@
                    {
                        var messageStr = reader.BeReadString();
                        if (messageStr.StartsWith("@") && pos + dataLength - reader.BaseStream.Position == 16)
                        {
                            reader.ReadBytes(10);
                            result.Snippets.Add(new TextSnippet(messageStr, MessageType.At,
                                                                ("Target", reader.BeReadLong32())));
                        }
                        else
                        {
                            result.Snippets.Add(messageStr);
                        }

                        break;
                    }

                    case 0x02:                 // Emoji(系统表情)
                    {
                        reader.BeReadUInt16(); // 这里的数字貌似总是1:系统表情只有208个。
                        result.Snippets.Add(new TextSnippet("", MessageType.Emoji, ("Type", reader.ReadByte())));
                        break;
                    }

                    case 0x03:     // 图片
                    {
                        result.Snippets.Add(new TextSnippet(reader.BeReadString(), MessageType.Picture));
                        break;
                    }

                    case 0x0A:     // 音频
                    {
                        result.Snippets.Add(new TextSnippet(reader.BeReadString(), MessageType.Audio));
                        break;
                    }

                    case 0x0E:     // 未知
                    {
                        break;
                    }

                    case 0x12:     // 群名片
                    {
                        break;
                    }

                    case 0x14:     // XML
                    {
                        reader.ReadByte();
                        result.Snippets.Add(new TextSnippet(
                                                GZipByteArray.DecompressString(reader.ReadBytes((int)(reader.BaseStream.Length - 1))),
                                                MessageType.Xml));
                        break;
                    }

                    case 0x18:     // 群文件
                    {
                        reader.ReadBytes(5);
                        var fileName = reader.BeReadString();    // 文件名称... 长度总是一个byte
                        reader.ReadByte();
                        reader.ReadBytes(reader.ReadByte());     // 文件大小
                        result.Snippets.Add(new TextSnippet(fileName, MessageType.OfflineFile));
                        break;
                    }

                    case 0x19:     // 红包秘钥段
                    {
                        if (reader.ReadByte() != 0xC2)
                        {
                            break;
                        }

                        reader.ReadBytes(19);
                        reader.ReadBytes(reader.ReadByte());                       // 恭喜发财
                        reader.ReadByte();
                        reader.ReadBytes(reader.ReadByte());                       // 赶紧点击拆开吧
                        reader.ReadByte();
                        reader.ReadBytes(reader.ReadByte());                       // QQ红包
                        reader.ReadBytes(5);
                        reader.ReadBytes(reader.ReadByte());                       // [QQ红包]恭喜发财
                        reader.ReadBytes(22);
                        var redId = Encoding.UTF8.GetString(reader.ReadBytes(32)); //redid
                        reader.ReadBytes(12);
                        reader.ReadBytes(reader.BeReadUInt16());
                        reader.ReadBytes(0x10);
                        var key1 = Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadByte()));     //Key1
                        reader.BeReadUInt16();
                        var key2 = Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadByte()));     //Key2
                        result.Snippets.Add(new TextSnippet("", MessageType.RedBag, ("RedId", redId),
                                                            ("Key1", key1), ("Key2", key2)));
                        break;
                    }
                    }

                    reader.ReadBytes((int)(pos + dataLength - reader.BaseStream.Position));
                    messageType = reader.ReadByte();
                    dataLength  = reader.BeReadUInt16();
                    pos         = reader.BaseStream.Position;
                }
            }
            catch (Exception ex)
            {
            }

            // 移除所有空白的片段
            result.Snippets.RemoveAll(s => s.Type == MessageType.Normal && string.IsNullOrEmpty(s.Content));

            // 若长度大于1,那么应该只含有普通文本、At、表情、图片。
            // 虽然我看着别人好像视频也能通过转发什么的弄进来,但是反正我们现在不支持接收音视频,所以不管了
            return(result.Snippets.Count > 1 && result.Snippets.Any(s =>
                                                                    s.Type != MessageType.Normal && s.Type != MessageType.At &&
                                                                    s.Type != MessageType.Emoji && s.Type != MessageType.Picture)
                ? throw new NotSupportedException("富文本中包含多个非聊天代码")
                : result);
        }
예제 #2
0
        public static List <byte[]> WriteSnippet(TextSnippet snippet, int length)
        {
            // TODO: 富文本支持
            var ret = new List <byte[]>();
            var bw  = new BinaryWriter(new MemoryStream());

            switch (snippet.Type)
            {
            case MessageType.Normal:
            {
                if (length + 6 >= 699)     // 数字应该稍大点,但是我不清楚具体是多少
                {
                    length = 0;
                    ret.Add(new byte[0]);
                }

                bw.BaseStream.Position = 6;
                foreach (var chr in snippet.Content)
                {
                    var bytes = Encoding.UTF8.GetBytes(chr.ToString());
                    // 705 = 699 + 6个byte: (byte + short + byte + short)
                    if (length + bw.BaseStream.Length + bytes.Length > 705)
                    {
                        var pos = bw.BaseStream.Position;
                        bw.BaseStream.Position = 0;
                        bw.Write(new byte[] { 0x01 });
                        bw.BeWrite((ushort)(pos - 3));      // 本来是+3和0的,但是提前预留了6个byte给它们,所以变成了-3和-6。下同理。
                        bw.Write(new byte[] { 0x01 });
                        bw.BeWrite((ushort)(pos - 6));
                        bw.BaseStream.Position = pos;
                        ret.Add(bw.BaseStream.ToBytesArray());
                        bw = new BinaryWriter(new MemoryStream());
                        bw.BaseStream.Position = 6;
                        length = 0;
                    }

                    bw.Write(bytes);
                }

                // 在最后一段的开头补充结构
                {
                    var pos = bw.BaseStream.Position;
                    bw.BaseStream.Position = 0;
                    bw.Write(new byte[] { 0x01 });
                    bw.BeWrite((ushort)(pos - 3));
                    bw.Write(new byte[] { 0x01 });
                    bw.BeWrite((ushort)(pos - 6));
                    bw.BaseStream.Position = pos;
                }
                break;
            }

            case MessageType.At:
                break;

            case MessageType.Emoji:
            {
                if (length + 12 > 699)
                {
                    ret.Add(new byte[0]);
                }

                var faceIndex = Convert.ToByte(snippet.Content);
                if (faceIndex > 199)
                {
                    faceIndex = 0;
                }

                bw.Write(new byte[] { 0x02, 0x00, 0x14, 0x01, 0x00, 0x01 });
                bw.Write(faceIndex);
                bw.Write(new byte[] { 0xFF, 0x00, 0x02, 0x14 });
                bw.Write((byte)(faceIndex + 65));
                bw.Write(new byte[] { 0x0B, 0x00, 0x08, 0x00, 0x01, 0x00, 0x04, 0x52, 0xCC, 0x85, 0x50 });
                break;
            }

            case MessageType.Picture:
                break;

            case MessageType.Xml:
                break;

            case MessageType.Json:
                break;

            case MessageType.Shake:
                break;

            case MessageType.Audio:
                break;

            case MessageType.Video:
                break;

            case MessageType.ExitGroup:
                break;

            case MessageType.GetGroupImformation:
                break;

            case MessageType.AddGroup:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (bw.BaseStream.Position != 0)
            {
                ret.Add(bw.BaseStream.ToBytesArray());
            }

            return(ret);
        }
예제 #3
0
        public static Richtext Parse(BinaryReader reader)
        {
            var result = new Richtext();

            // TODO: 解析富文本
            try
            {
                var messageType = reader.ReadByte();
                var dataLength  = reader.BeReadChar();
                var pos         = reader.BaseStream.Position;
                while (pos + dataLength < reader.BaseStream.Length)
                {
                    reader.ReadByte();
                    switch (messageType)
                    {
                    case 0x01:     //文本消息
                    {
                        var messageStr = Encoding.UTF8.GetString(reader.ReadBytes(reader.BeReadChar()));
                        if (messageStr.Contains("@"))
                        {
                            //Reader.ReadBytes(10);
                            //var AtQQ = Util.GetQQNumRetUint(Util.ToHex(Reader.ReadBytes(4)));//被At人的QQ号
                            result.Snippets.Add(new TextSnippet(messageStr, MessageType.At));
                        }
                        else
                        {
                            result.Snippets.Add(messageStr);
                        }

                        break;
                    }

                    case 0x02:     //小黄豆表情
                    {
                        result.Snippets.Add(new TextSnippet(
                                                Util.GetQQNumRetUint(Util.ToHex(reader.ReadBytes(reader.BeReadChar()))).ToString(),
                                                MessageType.Emoji));
                        break;
                    }

                    case 0x03:     //图片
                    {
                        result.Snippets.Add(new TextSnippet(
                                                Encoding.UTF8.GetString(reader.ReadBytes(reader.BeReadChar())), MessageType.Picture));
                        break;
                    }

                    case 0x0A:     //音频
                    {
                        result.Snippets.Add(new TextSnippet(Encoding.UTF8.GetString(reader.ReadBytes(reader.BeReadChar())), MessageType.Audio));
                        break;
                    }

                    case 0x0E:     //未知
                    {
                        break;
                    }

                    case 0x12:    //群名片
                    {
                        break;
                    }

                    case 0x14:     //XML
                    {
                        reader.ReadByte();
                        result.Snippets.Add(new TextSnippet(GZipByteArray.DecompressString(reader.ReadBytes((int)(reader.BaseStream.Length - 1))), MessageType.Xml));
                        break;
                    }

                    case 0x18:     //群文件
                    {
                        reader.ReadBytes(3);
                        var fileName = reader.ReadBytes(reader.ReadByte()); //文件名称
                        reader.ReadByte();
                        reader.ReadBytes(reader.ReadByte());                //文件大小
                        result.Snippets.Add(new TextSnippet(Encoding.UTF8.GetString(fileName),
                                                            MessageType.OfflineFile));
                        break;
                    }

                    case 0x19:     //红包秘钥段
                    {
                        if (reader.ReadByte() != 0xC2)
                        {
                            break;
                        }
                        reader.ReadBytes(19);
                        reader.ReadBytes(reader.ReadByte());                       //恭喜发财
                        reader.ReadByte();
                        reader.ReadBytes(reader.ReadByte());                       //赶紧点击拆开吧
                        reader.ReadByte();
                        reader.ReadBytes(reader.ReadByte());                       //QQ红包
                        reader.ReadBytes(5);
                        reader.ReadBytes(reader.ReadByte());                       //[QQ红包]恭喜发财
                        reader.ReadBytes(22);
                        var redId = Encoding.UTF8.GetString(reader.ReadBytes(32)); //redid
                        reader.ReadBytes(12);
                        reader.ReadBytes(reader.BeReadChar());
                        reader.ReadBytes(0x10);
                        var key1 = Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadByte()));     //Key1
                        reader.BeReadChar();
                        var key2 = Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadByte()));     //Key2
                        result.Snippets.Add(new TextSnippet("", MessageType.RedBag, ("RedId", redId),
                                                            ("Key1", key1), ("Key2", key2)));
                        break;
                    }
                    }

                    reader.ReadBytes((int)(pos + dataLength - reader.BaseStream.Position));
                    messageType = reader.ReadByte();
                    dataLength  = reader.BeReadChar();
                    pos         = reader.BaseStream.Position;
                }
            }
            catch (Exception ex)
            {
            }

            return(result);
        }