private static void SetStyle(Attr attr, SmiStatus status)
 {
     attr.b      = status.b > 0;
     attr.i      = status.i > 0;
     attr.u      = status.u > 0;
     attr.fs     = (status.fs.Count > 0) ? status.fs[status.fs.Count - 1] : 0;
     attr.fn     = (status.fn.Count > 0) ? status.fn[status.fn.Count - 1] : "";
     attr.fc     = (status.fc.Count > 0) ? status.fc[status.fc.Count - 1] : "";
     attr.fade   = (status.fade.Count > 0) ? status.fade[status.fade.Count - 1] : 0;
     attr.typing = (status.typing.Count > 0) ? status.typing[status.typing.Count - 1] : null;
 }
        public static List <Attr> ToAttr(string text)
        {
            List <Attr> result = new List <Attr>();

            int       index  = 0;
            int       pos    = 0;
            SmiStatus status = new SmiStatus();
            Attr      last   = new Attr();

            result.Add(last);

            while ((pos = text.IndexOf('<', index)) >= 0)
            {
                #region 태그명
                int tagNameLength = 0;
                while (pos + 1 + tagNameLength < text.Length &&
                       text[pos + 1 + tagNameLength] != ' ' &&
                       text[pos + 1 + tagNameLength] != '>' &&
                       text[pos + 1 + tagNameLength] != '\r' &&
                       text[pos + 1 + tagNameLength] != '\n' &&
                       text[pos + 1 + tagNameLength] != '\t'
                       )
                {
                    tagNameLength++;
                }

                string tagName = text.Substring(pos + 1, tagNameLength).ToUpper();
                int    attrPos = pos + 1 + tagNameLength;
                #endregion

                #region 태그 속성
                List <string[]> attrs = new List <string[]>();
                if (text[attrPos] == '>')
                {
                    attrPos++;
                }
                else
                {
                    if (tagName[0].Equals('/')) // 종료 태그
                    {
                        attrPos = text.IndexOf('>', attrPos) + 1;
                    }
                    else
                    {
                        int    mode = 0;
                        int    attrNameStart = attrPos, attrValueStart = 0;
                        string name = "";

                        while (mode >= 0)
                        {
                            switch (mode)
                            {
                            case 0:     // 속성 이름
                            {
                                for (; mode == 0 && attrPos < text.Length; attrPos++)
                                {
                                    switch (text[attrPos])
                                    {
                                    case '>':
                                        if (attrPos - attrNameStart > 0)
                                        {
                                            // 이름만 있는 속성
                                            attrs.Add(new string[] {
                                                    text.Substring(attrNameStart, attrPos - attrNameStart).ToLower(),
                                                    null
                                                });
                                        }
                                        mode = -1;
                                        break;

                                    case ' ':
                                    case '\t':
                                    case '\r':
                                    case '\n':
                                        if (attrPos - attrNameStart > 0)
                                        {
                                            // 이름만 있는 속성
                                            attrs.Add(new string[] {
                                                    text.Substring(attrNameStart, attrPos - attrNameStart).ToLower(),
                                                    null
                                                });
                                        }
                                        attrNameStart = attrPos + 1;
                                        break;

                                    case '=':
                                        // 이름 끝, 값 시작
                                        name           = text.Substring(attrNameStart, attrPos - attrNameStart).ToLower();
                                        mode           = 1;
                                        attrValueStart = attrPos + 1;
                                        break;
                                    }
                                }
                                break;
                            }

                            case 1:     // 속성 값
                            {
                                for (; mode == 1 && attrPos < text.Length; attrPos++)
                                {
                                    switch (text[attrPos])
                                    {
                                    case '>':
                                        // 값 끝
                                        attrs.Add(new string[] {
                                                name,
                                                text.Substring(attrNameStart, attrPos - attrNameStart).ToLower()
                                            });
                                        mode = -1;
                                        attrPos++;
                                        break;

                                    case ' ':
                                    case '\t':
                                    case '\r':
                                    case '\n':
                                        // 값 끝
                                        attrs.Add(new string[] {
                                                name,
                                                text.Substring(attrValueStart, attrPos - attrValueStart).ToLower()
                                            });
                                        mode          = 0;
                                        attrNameStart = attrPos + 1;
                                        break;

                                    case '\'':
                                        if (attrPos == attrValueStart)
                                        {
                                            mode = 2;
                                            attrValueStart++;
                                        }
                                        break;

                                    case '"':
                                        if (attrPos == attrValueStart)
                                        {
                                            mode = 3;
                                            attrValueStart++;
                                        }
                                        break;
                                    }
                                }
                                break;
                            }

                            case 2:     // 속성 값 (작은 따옴표)
                            {
                                for (; mode == 2 && attrPos < text.Length; attrPos++)
                                {
                                    switch (text[attrPos])
                                    {
                                    case '\\':
                                        attrPos++;
                                        break;

                                    case '\'':
                                        // 값 끝
                                        attrs.Add(new string[] {
                                                name,
                                                text.Substring(attrValueStart, attrPos - attrValueStart).ToLower()
                                            });
                                        mode          = 0;
                                        attrNameStart = attrPos + 1;
                                        break;
                                    }
                                }
                                break;
                            }

                            case 3:     // 속성 값 (큰 따옴표)
                            {
                                for (; mode == 3 && attrPos < text.Length; attrPos++)
                                {
                                    switch (text[attrPos])
                                    {
                                    case '\\':
                                        attrPos++;
                                        break;

                                    case '"':
                                        // 값 끝
                                        attrs.Add(new string[] {
                                                name,
                                                text.Substring(attrValueStart, attrPos - attrValueStart).ToLower()
                                            });
                                        mode          = 0;
                                        attrNameStart = attrPos + 1;
                                        break;
                                    }
                                }
                                break;
                            }
                            }
                        }
                    }
                }
                #endregion

                if (tagName[0].Equals('/')) // 종료 태그
                {
                    tagName = tagName.Substring(1);
                    switch (tagName)
                    {
                    case "B":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", ""));
                        if (last.text.Length > 0)
                        {
                            result.Add((last = new Attr()));
                        }
                        SetStyle(last, status.SetB(false));
                        break;

                    case "I":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", ""));
                        if (last.text.Length > 0)
                        {
                            result.Add((last = new Attr()));
                        }
                        SetStyle(last, status.SetI(false));
                        break;

                    case "U":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", ""));
                        if (last.text.Length > 0)
                        {
                            result.Add((last = new Attr()));
                        }
                        SetStyle(last, status.SetU(false));
                        break;

                    case "FONT":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", ""));
                        if (last.text.Length > 0)
                        {
                            result.Add((last = new Attr()));
                        }
                        SetStyle(last, status.SetFont(null));
                        break;

                    default:
                        break;
                    }
                }
                else
                {
                    switch (tagName)
                    {
                    case "B":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", ""));
                        if (last.text.Length > 0)
                        {
                            result.Add((last = new Attr()));
                        }
                        SetStyle(last, status.SetB(true));
                        break;

                    case "I":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", ""));
                        if (last.text.Length > 0)
                        {
                            result.Add((last = new Attr()));
                        }
                        SetStyle(last, status.SetI(true));
                        break;

                    case "U":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", ""));
                        if (last.text.Length > 0)
                        {
                            result.Add((last = new Attr()));
                        }
                        SetStyle(last, status.SetU(true));
                        break;

                    case "FONT":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", ""));
                        if (last.text.Length > 0)
                        {
                            result.Add((last = new Attr()));
                        }
                        SetStyle(last, status.SetFont(attrs));
                        break;

                    case "BR":
                        last.text += WebUtility.HtmlDecode(text.Substring(index, pos - index).Replace("\n", "")) + "\n";
                        break;

                    default:
                        last.text += WebUtility.HtmlDecode(text.Substring(index, attrPos - index).Replace("\n", ""));
                        break;
                    }
                }

                index = attrPos;
            }
            last.text += WebUtility.HtmlDecode(text.Substring(index));

            return(result);
        }