Beispiel #1
0
        public static string[] HtmlTagSplit(string str)
        {
            List <string> strList = new List <string>();
            StringStream  st      = new StringStream(str);
            int           found   = -1;

            while (!st.EOS)
            {
                found = st.Find('<');
                if (found < 0)
                {
                    strList.Add(st.Substring());
                    break;
                }
                else if (found > 0)
                {
                    strList.Add(st.Substring(st.CurrentPosition, found));
                    st.CurrentPosition += found;
                }
                found = st.Find('>');
                if (found < 0)
                {
                    return(null);
                }
                found++;
                strList.Add(st.Substring(st.CurrentPosition, found));
                st.CurrentPosition += found;
            }
            string[] ret = new string[strList.Count];
            strList.CopyTo(ret);
            return(ret);
        }
Beispiel #2
0
        private static AConsoleDisplayPart tagAnalyze(HtmlAnalzeState state, StringStream st)
        {
            bool   endTag = (st.Current == '/');
            string tag;

            if (endTag)
            {
                st.ShiftNext();
                int found = st.Find('>');
                if (found < 0)
                {
                    st.CurrentPosition = st.RowString.Length;
                    return(null);                   //戻り先でエラーを出す
                }
                tag = st.Substring(st.CurrentPosition, found).Trim();
                st.CurrentPosition += found;
                FontStyle endStyle = FontStyle.Strikeout;
                switch (tag.ToLower())
                {
                case "b": endStyle = FontStyle.Bold; goto case "s";

                case "i": endStyle = FontStyle.Italic; goto case "s";

                case "u": endStyle = FontStyle.Underline; goto case "s";

                case "s":
                    if ((state.FontStyle & endStyle) == FontStyle.Regular)
                    {
                        throw new CodeEE("</" + tag + ">の前に<" + tag + ">がありません");
                    }
                    state.FontStyle ^= endStyle;
                    return(null);

                case "p":
                    if ((!state.FlagP) || (state.FlagPClosed))
                    {
                        throw new CodeEE("</p>の前に<p>がありません");
                    }
                    state.FlagPClosed = true;
                    return(null);

                case "nobr":
                    if ((!state.FlagNobr) || (state.FlagNobrClosed))
                    {
                        throw new CodeEE("</nobr>の前に<nobr>がありません");
                    }
                    state.FlagNobrClosed = true;
                    return(null);

                case "font":
                    if (state.FonttagList.Count == 0)
                    {
                        throw new CodeEE("</font>の前に<font>がありません");
                    }
                    state.FonttagList.RemoveAt(state.FonttagList.Count - 1);
                    return(null);

                case "button":
                    if (state.CurrentButtonTag == null || !state.CurrentButtonTag.IsButtonTag)
                    {
                        throw new CodeEE("</button>の前に<button>がありません");
                    }
                    state.CurrentButtonTag = null;
                    state.FlagButton       = true;
                    return(null);

                case "nonbutton":
                    if (state.CurrentButtonTag == null || state.CurrentButtonTag.IsButtonTag)
                    {
                        throw new CodeEE("</nonbutton>の前に<nonbutton>がありません");
                    }
                    state.CurrentButtonTag = null;
                    state.FlagButton       = true;
                    return(null);

                default:
                    throw new CodeEE("終了タグ</" + tag + ">は解釈できません");
                }
                //goto error;
            }
            //以降は開始タグ

            bool           tempUseMacro = LexicalAnalyzer.UseMacro;
            WordCollection wc           = null;

            try
            {
                LexicalAnalyzer.UseMacro = false;                //一時的にマクロ展開をやめる
                tag = LexicalAnalyzer.ReadSingleIdentifier(st);
                LexicalAnalyzer.SkipWhiteSpace(st);
                if (st.Current != '>')
                {
                    wc = LexicalAnalyzer.Analyse(st, LexEndWith.GreaterThan, LexAnalyzeFlag.AllowAssignment | LexAnalyzeFlag.AllowSingleQuotationStr);
                }
            }
            finally
            {
                LexicalAnalyzer.UseMacro = tempUseMacro;
            }
            if (string.IsNullOrEmpty(tag))
            {
                goto error;
            }
            IdentifierWord word;
            FontStyle      newStyle = FontStyle.Strikeout;

            switch (tag.ToLower())
            {
            case "b": newStyle = FontStyle.Bold; goto case "s";

            case "i": newStyle = FontStyle.Italic; goto case "s";

            case "u": newStyle = FontStyle.Underline; goto case "s";

            case "s":
                if (wc != null)
                {
                    throw new CodeEE("<" + tag + ">タグにに属性が設定されています");
                }
                if ((state.FontStyle & newStyle) != FontStyle.Regular)
                {
                    throw new CodeEE("<" + tag + ">が二重に使われています");
                }
                state.FontStyle |= newStyle;
                return(null);

            case "br":
                if (wc != null)
                {
                    throw new CodeEE("<" + tag + ">タグにに属性が設定されています");
                }
                state.FlagBr = true;
                return(null);

            case "nobr":
                if (wc != null)
                {
                    throw new CodeEE("<" + tag + ">タグに属性が設定されています");
                }
                if (!state.LineHead)
                {
                    throw new CodeEE("<nobr>が行頭以外で使われています");
                }
                if (state.FlagNobr)
                {
                    throw new CodeEE("<nobr>が2度以上使われています");
                }
                state.FlagNobr = true;
                return(null);

            case "p":
            {
                if (wc == null)
                {
                    throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
                }
                if (!state.LineHead)
                {
                    throw new CodeEE("<p>が行頭以外で使われています");
                }
                if (state.FlagNobr)
                {
                    throw new CodeEE("<p>が2度以上使われています");
                }
                word = wc.Current as IdentifierWord;
                wc.ShiftNext();
                OperatorWord op = wc.Current as OperatorWord;
                wc.ShiftNext();
                LiteralStringWord attr = wc.Current as LiteralStringWord;
                wc.ShiftNext();
                if (!wc.EOL || word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
                {
                    goto error;
                }
                if (!word.Code.Equals("align", StringComparison.OrdinalIgnoreCase))
                {
                    throw new CodeEE("<p>タグの属性名" + word.Code + "は解釈できません");
                }
                string attrValue = Unescape(attr.Str);
                switch (attrValue.ToLower())
                {
                case "left":
                    state.Alignment = DisplayLineAlignment.LEFT;
                    break;

                case "center":
                    state.Alignment = DisplayLineAlignment.CENTER;
                    break;

                case "right":
                    state.Alignment = DisplayLineAlignment.RIGHT;
                    break;

                default:
                    throw new CodeEE("属性値" + attr.Str + "は解釈できません");
                }
                state.FlagP = true;
                return(null);
            }

            case "img":
            {
                if (wc == null)
                {
                    throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
                }
                string attrValue = null;
                string src       = null;
                string srcb      = null;
                int    height    = 0;
                int    width     = 0;
                int    ypos      = 0;
                while (wc != null && !wc.EOL)
                {
                    word = wc.Current as IdentifierWord;
                    wc.ShiftNext();
                    OperatorWord op = wc.Current as OperatorWord;
                    wc.ShiftNext();
                    LiteralStringWord attr = wc.Current as LiteralStringWord;
                    wc.ShiftNext();
                    if (word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
                    {
                        goto error;
                    }
                    attrValue = Unescape(attr.Str);
                    if (word.Code.Equals("src", StringComparison.OrdinalIgnoreCase))
                    {
                        if (src != null)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        src = attrValue;
                    }
                    else if (word.Code.Equals("srcb", StringComparison.OrdinalIgnoreCase))
                    {
                        if (srcb != null)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        srcb = attrValue;
                    }
                    else if (word.Code.Equals("height", StringComparison.OrdinalIgnoreCase))
                    {
                        if (height != 0)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        if (!int.TryParse(attrValue, out height))
                        {
                            throw new CodeEE("<" + tag + ">タグのheight属性の属性値が数値として解釈できません");
                        }
                    }
                    else if (word.Code.Equals("width", StringComparison.OrdinalIgnoreCase))
                    {
                        if (width != 0)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        if (!int.TryParse(attrValue, out width))
                        {
                            throw new CodeEE("<" + tag + ">タグのwidth属性の属性値が数値として解釈できません");
                        }
                    }
                    else if (word.Code.Equals("ypos", StringComparison.OrdinalIgnoreCase))
                    {
                        if (ypos != 0)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        if (!int.TryParse(attrValue, out ypos))
                        {
                            throw new CodeEE("<" + tag + ">タグのypos属性の属性値が数値として解釈できません");
                        }
                    }
                    else
                    {
                        throw new CodeEE("<" + tag + ">タグの属性名" + word.Code + "は解釈できません");
                    }
                }
                if (src == null)
                {
                    throw new CodeEE("<" + tag + ">タグにsrc属性が設定されていません");
                }
                return(new ConsoleImagePart(src, srcb, height, width, ypos));
            }

            case "shape":
            {
                if (wc == null)
                {
                    throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
                }
                int[]  param  = null;
                string type   = null;
                int    color  = -1;
                int    bcolor = -1;
                while (!wc.EOL)
                {
                    word = wc.Current as IdentifierWord;
                    wc.ShiftNext();
                    OperatorWord op = wc.Current as OperatorWord;
                    wc.ShiftNext();
                    LiteralStringWord attr = wc.Current as LiteralStringWord;
                    wc.ShiftNext();
                    if (word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
                    {
                        goto error;
                    }
                    string attrValue = Unescape(attr.Str);
                    switch (word.Code.ToLower())
                    {
                    case "color":
                        if (color >= 0)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        color = stringToColorInt32(attrValue);
                        break;

                    case "bcolor":
                        if (bcolor >= 0)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        bcolor = stringToColorInt32(attrValue);
                        break;

                    case "type":
                        if (type != null)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        type = attrValue;
                        break;

                    case "param":
                        if (param != null)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        {
                            string[] tokens = attrValue.Split(',');
                            param = new int[tokens.Length];
                            for (int i = 0; i < tokens.Length; i++)
                            {
                                if (!int.TryParse(tokens[i], out param[i]))
                                {
                                    throw new CodeEE("<" + tag + ">タグの" + word.Code + "属性の属性値が数値として解釈できません");
                                }
                            }
                            break;
                        }

                    default:
                        throw new CodeEE("<" + tag + ">タグの属性名" + word.Code + "は解釈できません");
                    }
                }
                if (param == null)
                {
                    throw new CodeEE("<" + tag + ">タグにparam属性が設定されていません");
                }
                if (type == null)
                {
                    throw new CodeEE("<" + tag + ">タグにtype属性が設定されていません");
                }
                Color c = Config.ForeColor;
                Color b = Config.FocusColor;
                if (color >= 0)
                {
                    c = Color.FromArgb(color >> 16, (color >> 8) & 0xFF, color & 0xFF);
                }
                if (bcolor >= 0)
                {
                    b = Color.FromArgb(bcolor >> 16, (bcolor >> 8) & 0xFF, bcolor & 0xFF);
                }
                return(ConsoleShapePart.CreateShape(type, param, c, b, color >= 0));
            }

            case "button":
            case "nonbutton":
            {
                if (state.CurrentButtonTag != null)
                {
                    throw new CodeEE("<button>又は<nonbutton>が入れ子にされています");
                }
                HtmlAnalzeStateButtonTag buttonTag = new HtmlAnalzeStateButtonTag();
                bool   isButton  = tag.ToLower() == "button";
                string attrValue = null;
                string value     = null;
                //if (wc == null)
                //	throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
                while (wc != null && !wc.EOL)
                {
                    word = wc.Current as IdentifierWord;
                    wc.ShiftNext();
                    OperatorWord op = wc.Current as OperatorWord;
                    wc.ShiftNext();
                    LiteralStringWord attr = wc.Current as LiteralStringWord;
                    wc.ShiftNext();
                    if (word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
                    {
                        goto error;
                    }
                    attrValue = Unescape(attr.Str);
                    if (word.Code.Equals("value", StringComparison.OrdinalIgnoreCase))
                    {
                        if (!isButton)
                        {
                            throw new CodeEE("<" + tag + ">タグにvalue属性が設定されています");
                        }
                        if (value != null)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        value = attrValue;
                    }
                    else if (word.Code.Equals("title", StringComparison.OrdinalIgnoreCase))
                    {
                        if (buttonTag.ButtonTitle != null)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        buttonTag.ButtonTitle = attrValue;
                    }
                    else if (word.Code.Equals("pos", StringComparison.OrdinalIgnoreCase))
                    {
                        //throw new NotImplCodeEE();
                        int pos = 0;
                        if (buttonTag.PointXisLocked)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        if (!int.TryParse(attrValue, out pos))
                        {
                            throw new CodeEE("<" + tag + ">タグのpos属性の属性値が数値として解釈できません");
                        }
                        buttonTag.PointX         = pos;
                        buttonTag.PointXisLocked = true;
                    }
                    else
                    {
                        throw new CodeEE("<" + tag + ">タグの属性名" + word.Code + "は解釈できません");
                    }
                }
                if (isButton)
                {
                    //if (value == null)
                    //	throw new CodeEE("<" + tag + ">タグにvalue属性が設定されていません");
                    int intValue = 0;
                    buttonTag.ButtonIsInteger = (int.TryParse(value, out intValue));
                    buttonTag.ButtonValueInt  = intValue;
                    buttonTag.ButtonValueStr  = value;
                }
                buttonTag.IsButton     = value != null;
                buttonTag.IsButtonTag  = isButton;
                state.CurrentButtonTag = buttonTag;
                state.FlagButton       = true;
                return(null);
            }

            case "font":
            {
                if (wc == null)
                {
                    throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
                }
                HtmlAnalzeStateFontTag font = new HtmlAnalzeStateFontTag();
                while (!wc.EOL)
                {
                    word = wc.Current as IdentifierWord;
                    wc.ShiftNext();
                    OperatorWord op = wc.Current as OperatorWord;
                    wc.ShiftNext();
                    LiteralStringWord attr = wc.Current as LiteralStringWord;
                    wc.ShiftNext();
                    if (word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
                    {
                        goto error;
                    }
                    string attrValue = Unescape(attr.Str);
                    switch (word.Code.ToLower())
                    {
                    case "color":
                        if (font.Color >= 0)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        font.Color = stringToColorInt32(attrValue);
                        break;

                    case "bcolor":
                        if (font.BColor >= 0)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        font.BColor = stringToColorInt32(attrValue);
                        break;

                    case "face":
                        if (font.FontName != null)
                        {
                            throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                        }
                        font.FontName = attrValue;
                        break;

                    //case "pos":
                    //	{
                    //		//throw new NotImplCodeEE();
                    //		if (font.PointXisLocked)
                    //			throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
                    //		int pos = 0;
                    //		if (!int.TryParse(attrValue, out pos))
                    //			throw new CodeEE("<font>タグのpos属性の属性値が数値として解釈できません");
                    //		font.PointX = pos;
                    //		font.PointXisLocked = true;
                    //		break;
                    //	}
                    default:
                        throw new CodeEE("<" + tag + ">タグの属性名" + word.Code + "は解釈できません");
                    }
                }
                //他のfontタグの内側であるなら未設定項目については外側のfontタグの設定を受け継ぐ(posは除く)
                if (state.FonttagList.Count > 0)
                {
                    HtmlAnalzeStateFontTag oldFont = state.FonttagList[state.FonttagList.Count - 1];
                    if (font.Color < 0)
                    {
                        font.Color = oldFont.Color;
                    }
                    if (font.BColor < 0)
                    {
                        font.BColor = oldFont.BColor;
                    }
                    if (font.FontName == null)
                    {
                        font.FontName = oldFont.FontName;
                    }
                }
                state.FonttagList.Add(font);
                return(null);
            }

            default:
                goto error;
            }


error:
            throw new CodeEE("html文字列\"" + st.RowString + "\"のタグ解析中にエラーが発生しました");
        }
Beispiel #3
0
        /// <summary>
        /// htmlから表示行の作成
        /// </summary>
        /// <param name="str">htmlテキスト</param>
        /// <param name="sm"></param>
        /// <param name="console">実際の表示に使わないならnullにする</param>
        /// <returns></returns>
        public static ConsoleDisplayLine[] Html2DisplayLine(string str, StringMeasure sm, EmueraConsole console)
        {
            List <AConsoleDisplayPart> cssList    = new List <AConsoleDisplayPart>();
            List <ConsoleButtonString> buttonList = new List <ConsoleButtonString>();
            StringStream    st = new StringStream(str);
            int             found;
            bool            hasComment = str.IndexOf("<!--") >= 0;
            bool            hasReturn  = str.IndexOf('\n') >= 0;
            HtmlAnalzeState state      = new HtmlAnalzeState();

            while (!st.EOS)
            {
                found = st.Find('<');
                if (hasReturn)
                {
                    int rFound = st.Find('\n');
                    if (rFound >= 0 && (found > rFound || found < 0))
                    {
                        found = rFound;
                    }
                }
                if (found < 0)
                {
                    string txt = Unescape(st.Substring());
                    cssList.Add(new ConsoleStyledString(txt, state.GetSS()));
                    if (state.FlagPClosed)
                    {
                        throw new CodeEE("</p>の後にテキストがあります");
                    }
                    if (state.FlagNobrClosed)
                    {
                        throw new CodeEE("</nobr>の後にテキストがあります");
                    }
                    break;
                }
                else if (found > 0)
                {
                    string txt = Unescape(st.Substring(st.CurrentPosition, found));
                    cssList.Add(new ConsoleStyledString(txt, state.GetSS()));
                    state.LineHead      = false;
                    st.CurrentPosition += found;
                }
                //コメントタグのみ特別扱い
                if (hasComment && st.CurrentEqualTo("<!--"))
                {
                    st.CurrentPosition += 4;
                    found = st.Find("-->");
                    if (found < 0)
                    {
                        throw new CodeEE("コメンdト終了タグ\"-->\"がみつかりません");
                    }
                    st.CurrentPosition += found + 3;
                    continue;
                }
                if (hasReturn && st.Current == '\n')                //テキスト中の\nは<br>として扱う
                {
                    state.FlagBr = true;
                    st.ShiftNext();
                }
                else                //タグ解析
                {
                    st.ShiftNext();
                    AConsoleDisplayPart part = tagAnalyze(state, st);
                    if (st.Current != '>')
                    {
                        throw new CodeEE("タグ終端'>'が見つかりません");
                    }
                    if (part != null)
                    {
                        cssList.Add(part);
                    }
                    st.ShiftNext();
                }

                if (state.FlagBr)
                {
                    state.LastButtonTag = state.CurrentButtonTag;
                    if (cssList.Count > 0)
                    {
                        buttonList.Add(cssToButton(cssList, state, console));
                    }
                    buttonList.Add(null);
                }
                if (state.FlagButton && cssList.Count > 0)
                {
                    buttonList.Add(cssToButton(cssList, state, console));
                }
                state.FlagBr        = false;
                state.FlagButton    = false;
                state.LastButtonTag = state.CurrentButtonTag;
            }
            //</nobr></p>は省略許可
            if (state.CurrentButtonTag != null || state.FontStyle != FontStyle.Regular || state.FonttagList.Count > 0)
            {
                throw new CodeEE("閉じられていないタグがあります");
            }
            if (cssList.Count > 0)
            {
                buttonList.Add(cssToButton(cssList, state, console));
            }

            foreach (ConsoleButtonString button in buttonList)
            {
                if (button != null && button.PointXisLocked)
                {
                    if (!state.FlagNobr)
                    {
                        throw new CodeEE("<nobr>が設定されていない行ではpos属性は使用できません");
                    }
                    if (state.Alignment != DisplayLineAlignment.LEFT)
                    {
                        throw new CodeEE("alignがleftでない行ではpos属性は使用できません");
                    }
                    break;
                }
            }
            ConsoleDisplayLine[] ret = PrintStringBuffer.ButtonsToDisplayLines(buttonList, sm, state.FlagNobr, false);

            foreach (ConsoleDisplayLine dl in ret)
            {
                dl.SetAlignment(state.Alignment);
            }
            return(ret);
        }