001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.parsers.bbcode;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.parsers.bbcode.BBCodeTranslator;
020    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.HtmlUtil;
023    import com.liferay.portal.kernel.util.IntegerWrapper;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    
029    import java.util.Collection;
030    import java.util.HashMap;
031    import java.util.List;
032    import java.util.Map;
033    import java.util.Stack;
034    import java.util.regex.Matcher;
035    import java.util.regex.Pattern;
036    
037    /**
038     * @author Iliyan Peychev
039     */
040    @DoPrivileged
041    public class HtmlBBCodeTranslatorImpl implements BBCodeTranslator {
042    
043            public HtmlBBCodeTranslatorImpl() {
044                    _listStyles = new HashMap<String, String>();
045    
046                    _listStyles.put("a", "list-style: lower-alpha outside;");
047                    _listStyles.put("A", "list-style: upper-alpha outside;");
048                    _listStyles.put("1", "list-style: decimal outside;");
049                    _listStyles.put("i", "list-style: lower-roman outside;");
050                    _listStyles.put("I", "list-style: upper-roman outside;");
051    
052                    _excludeNewLineTypes = new HashMap<String, Integer>();
053    
054                    _excludeNewLineTypes.put("*", BBCodeParser.TYPE_TAG_START_END);
055                    _excludeNewLineTypes.put("li", BBCodeParser.TYPE_TAG_START_END);
056                    _excludeNewLineTypes.put("table", BBCodeParser.TYPE_TAG_END);
057                    _excludeNewLineTypes.put("td", BBCodeParser.TYPE_TAG_START_END);
058                    _excludeNewLineTypes.put("th", BBCodeParser.TYPE_TAG_START_END);
059                    _excludeNewLineTypes.put("tr", BBCodeParser.TYPE_TAG_START_END);
060    
061                    _bbCodeCharacters = new HashMap<String, String>();
062    
063                    _bbCodeCharacters.put("&", "&amp;");
064                    _bbCodeCharacters.put("<", "&lt;");
065                    _bbCodeCharacters.put(">", "&gt;");
066                    _bbCodeCharacters.put("\"", "&#034;");
067                    _bbCodeCharacters.put("'", "&#039;");
068                    _bbCodeCharacters.put("/", "&#047;");
069                    _bbCodeCharacters.put("`", "&#096;");
070                    _bbCodeCharacters.put("[", "&#91;");
071                    _bbCodeCharacters.put("]", "&#93;");
072                    _bbCodeCharacters.put("(", "&#40;");
073                    _bbCodeCharacters.put(")", "&#41;");
074    
075                    for (int i = 0; i < _EMOTICONS.length; i++) {
076                            String[] emoticon = _EMOTICONS[i];
077    
078                            _emoticonDescriptions[i] = emoticon[2];
079                            _emoticonFiles[i] = emoticon[0];
080                            _emoticonSymbols[i] = emoticon[1];
081    
082                            String image = emoticon[0];
083    
084                            emoticon[0] =
085                                    "<img alt=\"emoticon\" src=\"@theme_images_path@/emoticons/" +
086                                            image + "\" >";
087                    }
088            }
089    
090            @Override
091            public String[] getEmoticonDescriptions() {
092                    return _emoticonDescriptions;
093            }
094    
095            @Override
096            public String[] getEmoticonFiles() {
097                    return _emoticonFiles;
098            }
099    
100            @Override
101            public String[][] getEmoticons() {
102                    return _EMOTICONS;
103            }
104    
105            @Override
106            public String[] getEmoticonSymbols() {
107                    return _emoticonSymbols;
108            }
109    
110            @Override
111            public String getHTML(String bbcode) {
112                    try {
113                            bbcode = parse(bbcode);
114                    }
115                    catch (Exception e) {
116                            _log.error("Unable to parse: " + bbcode, e);
117    
118                            bbcode = HtmlUtil.escape(bbcode);
119                    }
120    
121                    return bbcode;
122            }
123    
124            @Override
125            public String parse(String text) {
126                    StringBundler sb = new StringBundler();
127    
128                    List<BBCodeItem> bbCodeItems = _bbCodeParser.parse(text);
129                    Stack<String> tags = new Stack<String>();
130                    IntegerWrapper marker = new IntegerWrapper();
131    
132                    for (; marker.getValue() < bbCodeItems.size(); marker.increment()) {
133                            BBCodeItem bbCodeItem = bbCodeItems.get(marker.getValue());
134    
135                            int type = bbCodeItem.getType();
136    
137                            if (type == BBCodeParser.TYPE_DATA) {
138                                    handleData(sb, bbCodeItems, tags, marker, bbCodeItem);
139                            }
140                            else if (type == BBCodeParser.TYPE_TAG_END) {
141                                    handleTagEnd(sb, tags, bbCodeItem);
142                            }
143                            else if (type == BBCodeParser.TYPE_TAG_START) {
144                                    handleTagStart(sb, bbCodeItems, tags, marker, bbCodeItem);
145                            }
146                    }
147    
148                    return sb.toString();
149            }
150    
151            protected String escapeQuote(String quote) {
152                    StringBuilder sb = new StringBuilder();
153    
154                    int index = 0;
155    
156                    Matcher matcher = _bbCodePattern.matcher(quote);
157    
158                    Collection<String> values = _bbCodeCharacters.values();
159    
160                    while (matcher.find()) {
161                            String match = matcher.group();
162    
163                            int matchStartIndex = matcher.start();
164    
165                            int nextSemicolonIndex = quote.indexOf(
166                                    StringPool.SEMICOLON, matchStartIndex);
167    
168                            sb.append(quote.substring(index, matchStartIndex));
169    
170                            boolean entityFound = false;
171    
172                            if (nextSemicolonIndex >= 0) {
173                                    String value = quote.substring(
174                                            matchStartIndex, nextSemicolonIndex + 1);
175    
176                                    if (values.contains(value)) {
177                                            sb.append(value);
178    
179                                            index = matchStartIndex + value.length();
180    
181                                            entityFound = true;
182                                    }
183                            }
184    
185                            if (!entityFound) {
186                                    String escapedValue = _bbCodeCharacters.get(match);
187    
188                                    sb.append(escapedValue);
189    
190                                    index = matchStartIndex + match.length();
191                            }
192                    }
193    
194                    if (index < quote.length()) {
195                            sb.append(quote.substring(index, quote.length()));
196                    }
197    
198                    return sb.toString();
199            }
200    
201            protected String extractData(
202                    List<BBCodeItem> bbCodeItems, IntegerWrapper marker, String tag,
203                    int type, boolean consume) {
204    
205                    StringBundler sb = new StringBundler();
206    
207                    int index = marker.getValue() + 1;
208    
209                    BBCodeItem bbCodeItem = null;
210    
211                    do {
212                            bbCodeItem = bbCodeItems.get(index++);
213    
214                            if ((bbCodeItem.getType() & type) > 0) {
215                                    sb.append(bbCodeItem.getValue());
216                            }
217                    }
218                    while ((bbCodeItem.getType() != BBCodeParser.TYPE_TAG_END) &&
219                               !tag.equals(bbCodeItem.getValue()));
220    
221                    if (consume) {
222                            marker.setValue(index - 1);
223                    }
224    
225                    return sb.toString();
226            }
227    
228            protected void handleBold(StringBundler sb, Stack<String> tags) {
229                    handleSimpleTag(sb, tags, "strong");
230            }
231    
232            protected void handleCode(
233                    StringBundler sb, List<BBCodeItem> bbCodeItems, IntegerWrapper marker) {
234    
235                    sb.append("<div class=\"lfr-code\">");
236                    sb.append("<table>");
237                    sb.append("<tbody>");
238                    sb.append("<tr>");
239                    sb.append("<td class=\"line-numbers\">");
240    
241                    String code = extractData(
242                            bbCodeItems, marker, "code", BBCodeParser.TYPE_DATA, true);
243    
244                    code = HtmlUtil.escape(code);
245                    code = code.replaceAll(StringPool.TAB, StringPool.FOUR_SPACES);
246    
247                    String[] lines = code.split("\r?\n");
248    
249                    for (int i = 0; i < lines.length; i++) {
250                            String index = String.valueOf(i + 1);
251    
252                            sb.append("<span class=\"number\">");
253                            sb.append(index);
254                            sb.append("</span>");
255                    }
256    
257                    sb.append("</td>");
258                    sb.append("<td class=\"lines\">");
259    
260                    for (int i = 0; i < lines.length; i++) {
261                            String line = lines[i];
262    
263                            line = StringUtil.replace(
264                                    line, StringPool.THREE_SPACES, "&nbsp; &nbsp;");
265                            line = StringUtil.replace(line, StringPool.DOUBLE_SPACE, "&nbsp; ");
266    
267                            if (Validator.isNull(line)) {
268                                    line = "<br />";
269                            }
270    
271                            sb.append("<div class=\"line\">");
272                            sb.append(line);
273                            sb.append("</div>");
274                    }
275    
276                    sb.append("</td>");
277                    sb.append("</tr>");
278                    sb.append("</tbody>");
279                    sb.append("</table>");
280                    sb.append("</div>");
281            }
282    
283            protected void handleColor(
284                    StringBundler sb, Stack<String> tags, BBCodeItem bbCodeItem) {
285    
286                    sb.append("<span style=\"color: ");
287    
288                    String color = bbCodeItem.getAttribute();
289    
290                    if (color == null) {
291                            color = "inherit";
292                    }
293                    else {
294                            Matcher matcher = _colorPattern.matcher(color);
295    
296                            if (!matcher.matches()) {
297                                    color = "inherit";
298                            }
299                    }
300    
301                    sb.append(color);
302    
303                    sb.append("\">");
304    
305                    tags.push("</span>");
306            }
307    
308            protected void handleData(
309                    StringBundler sb, List<BBCodeItem> bbCodeItems, Stack<String> tags,
310                    IntegerWrapper marker, BBCodeItem bbCodeItem) {
311    
312                    String value = HtmlUtil.escape(bbCodeItem.getValue());
313    
314                    value = handleNewLine(bbCodeItems, tags, marker, value);
315    
316                    for (int i = 0; i < _EMOTICONS.length; i++) {
317                            String[] emoticon = _EMOTICONS[i];
318    
319                            value = StringUtil.replace(value, emoticon[1], emoticon[0]);
320                    }
321    
322                    sb.append(value);
323            }
324    
325            protected void handleEmail(
326                    StringBundler sb, List<BBCodeItem> bbCodeItems, Stack<String> tags,
327                    IntegerWrapper marker, BBCodeItem bbCodeItem) {
328    
329                    sb.append("<a href=\"");
330    
331                    String href = bbCodeItem.getAttribute();
332    
333                    if (href == null) {
334                            href = extractData(
335                                    bbCodeItems, marker, "email", BBCodeParser.TYPE_DATA, false);
336                    }
337    
338                    if (!href.startsWith("mailto:")) {
339                            href = "mailto:" + href;
340                    }
341    
342                    sb.append(HtmlUtil.escapeHREF(href));
343    
344                    sb.append("\">");
345    
346                    tags.push("</a>");
347            }
348    
349            protected void handleFontFamily(
350                    StringBundler sb, Stack<String> tags, BBCodeItem bbCodeItem) {
351    
352                    sb.append("<span style=\"font-family: ");
353                    sb.append(HtmlUtil.escapeAttribute(bbCodeItem.getAttribute()));
354                    sb.append("\">");
355    
356                    tags.push("</span>");
357            }
358    
359            protected void handleFontSize(
360                    StringBundler sb, Stack<String> tags, BBCodeItem bbCodeItem) {
361    
362                    sb.append("<span style=\"font-size: ");
363    
364                    int size = GetterUtil.getInteger(bbCodeItem.getAttribute());
365    
366                    if ((size >= 1) && (size <= _fontSizes.length)) {
367                            sb.append(_fontSizes[size - 1]);
368                    }
369                    else {
370                            sb.append(_fontSizes[1]);
371                    }
372    
373                    sb.append("px\">");
374    
375                    tags.push("</span>");
376            }
377    
378            protected void handleImage(
379                    StringBundler sb, List<BBCodeItem> bbCodeItems, IntegerWrapper marker) {
380    
381                    sb.append("<img src=\"");
382    
383                    String src = extractData(
384                            bbCodeItems, marker, "img", BBCodeParser.TYPE_DATA, true);
385    
386                    Matcher matcher = _imagePattern.matcher(src);
387    
388                    if (matcher.matches()) {
389                            sb.append(HtmlUtil.escapeAttribute(src));
390                    }
391    
392                    sb.append("\" />");
393            }
394    
395            protected void handleItalic(StringBundler sb, Stack<String> tags) {
396                    handleSimpleTag(sb, tags, "em");
397            }
398    
399            protected void handleList(
400                    StringBundler sb, Stack<String> tags, BBCodeItem bbCodeItem) {
401    
402                    String listStyle = null;
403    
404                    String tag = null;
405    
406                    String listAttribute = bbCodeItem.getAttribute();
407    
408                    if (listAttribute != null) {
409                            listStyle = _listStyles.get(listAttribute);
410    
411                            tag = "ol";
412                    }
413                    else {
414                            tag = "ul style=\"list-style: disc outside;\"";
415                    }
416    
417                    if (listStyle == null) {
418                            sb.append("<");
419                            sb.append(tag);
420                            sb.append(">");
421                    }
422                    else {
423                            sb.append("<");
424                            sb.append(tag);
425                            sb.append(" style=\"");
426                            sb.append(listStyle);
427                            sb.append("\">");
428                    }
429    
430                    tags.push("</" + tag + ">");
431            }
432    
433            protected void handleListItem(StringBundler sb, Stack<String> tags) {
434                    handleSimpleTag(sb, tags, "li");
435            }
436    
437            protected String handleNewLine(
438                    List<BBCodeItem> bbCodeItems, Stack<String> tags, IntegerWrapper marker,
439                    String data) {
440    
441                    BBCodeItem bbCodeItem = null;
442    
443                    if ((marker.getValue() + 1) < bbCodeItems.size()) {
444                            if (data.matches("\\A\r?\n\\z")) {
445                                    bbCodeItem = bbCodeItems.get(marker.getValue() + 1);
446    
447                                    if (bbCodeItem != null) {
448                                            String value = bbCodeItem.getValue();
449    
450                                            if (_excludeNewLineTypes.containsKey(value)) {
451                                                    int type = bbCodeItem.getType();
452    
453                                                    int excludeNewLineType = _excludeNewLineTypes.get(
454                                                            value);
455    
456                                                    if ((type & excludeNewLineType) > 0) {
457                                                            data = StringPool.BLANK;
458                                                    }
459                                            }
460                                    }
461                            }
462                            else if (data.matches("(?s).*\r?\n\\z")) {
463                                    bbCodeItem = bbCodeItems.get(marker.getValue() + 1);
464    
465                                    if ((bbCodeItem != null) &&
466                                            (bbCodeItem.getType() == BBCodeParser.TYPE_TAG_END)) {
467    
468                                            String value = bbCodeItem.getValue();
469    
470                                            if (value.equals("*")) {
471                                                    data = data.substring(0, data.length() - 1);
472                                            }
473                                    }
474                            }
475                    }
476    
477                    if (data.length() > 0) {
478                            data = data.replaceAll("\r?\n", "<br />");
479                    }
480    
481                    return data;
482            }
483    
484            protected void handleQuote(
485                    StringBundler sb, Stack<String> tags, BBCodeItem bbCodeItem) {
486    
487                    String quote = bbCodeItem.getAttribute();
488    
489                    if ((quote != null) && (quote.length() > 0)) {
490                            sb.append("<div class=\"quote-title\">");
491                            sb.append(escapeQuote(quote));
492                            sb.append(":</div>");
493                    }
494    
495                    sb.append("<div class=\"quote\"><div class=\"quote-content\">");
496    
497                    tags.push("</div></div>");
498            }
499    
500            protected void handleSimpleTag(
501                    StringBundler sb, Stack<String> tags, BBCodeItem bbCodeItem) {
502    
503                    handleSimpleTag(sb, tags, bbCodeItem.getValue());
504            }
505    
506            protected void handleSimpleTag(
507                    StringBundler sb, Stack<String> tags, String tag) {
508    
509                    sb.append("<");
510                    sb.append(tag);
511                    sb.append(">");
512    
513                    tags.push("</" + tag + ">");
514            }
515    
516            protected void handleStrikeThrough(StringBundler sb, Stack<String> tags) {
517                    handleSimpleTag(sb, tags, "strike");
518            }
519    
520            protected void handleTable(StringBundler sb, Stack<String> tags) {
521                    handleSimpleTag(sb, tags, "table");
522            }
523    
524            protected void handleTableCell(StringBundler sb, Stack<String> tags) {
525                    handleSimpleTag(sb, tags, "td");
526            }
527    
528            protected void handleTableHeader(StringBundler sb, Stack<String> tags) {
529                    handleSimpleTag(sb, tags, "th");
530            }
531    
532            protected void handleTableRow(StringBundler sb, Stack<String> tags) {
533                    handleSimpleTag(sb, tags, "tr");
534            }
535    
536            protected void handleTagEnd(
537                    StringBundler sb, Stack<String> tags, BBCodeItem bbCodeItem) {
538    
539                    String tag = bbCodeItem.getValue();
540    
541                    if (isValidTag(tag)) {
542                            sb.append(tags.pop());
543                    }
544            }
545    
546            protected void handleTagStart(
547                    StringBundler sb, List<BBCodeItem> bbCodeItems, Stack<String> tags,
548                    IntegerWrapper marker, BBCodeItem bbCodeItem) {
549    
550                    String tag = bbCodeItem.getValue();
551    
552                    if (!isValidTag(tag)) {
553                            return;
554                    }
555    
556                    if (tag.equals("b")) {
557                            handleBold(sb, tags);
558                    }
559                    else if (tag.equals("center") || tag.equals("justify") ||
560                                     tag.equals("left") || tag.equals("right")) {
561    
562                            handleTextAlign(sb, tags, bbCodeItem);
563                    }
564                    else if (tag.equals("code")) {
565                            handleCode(sb, bbCodeItems, marker);
566                    }
567                    else if (tag.equals("color") || tag.equals("colour")) {
568                            handleColor(sb, tags, bbCodeItem);
569                    }
570                    else if (tag.equals("email")) {
571                            handleEmail(sb, bbCodeItems, tags, marker, bbCodeItem);
572                    }
573                    else if (tag.equals("font")) {
574                            handleFontFamily(sb, tags, bbCodeItem);
575                    }
576                    else if (tag.equals("i")) {
577                            handleItalic(sb, tags);
578                    }
579                    else if (tag.equals("img")) {
580                            handleImage(sb, bbCodeItems, marker);
581                    }
582                    else if (tag.equals("li") || tag.equals("*")) {
583                            handleListItem(sb, tags);
584                    }
585                    else if (tag.equals("list")) {
586                            handleList(sb, tags, bbCodeItem);
587                    }
588                    else if (tag.equals("q") || tag.equals("quote")) {
589                            handleQuote(sb, tags, bbCodeItem);
590                    }
591                    else if (tag.equals("s")) {
592                            handleStrikeThrough(sb, tags);
593                    }
594                    else if (tag.equals("size")) {
595                            handleFontSize(sb, tags, bbCodeItem);
596                    }
597                    else if (tag.equals("table")) {
598                            handleTable(sb, tags);
599                    }
600                    else if (tag.equals("td")) {
601                            handleTableCell(sb, tags);
602                    }
603                    else if (tag.equals("th")) {
604                            handleTableHeader(sb, tags);
605                    }
606                    else if (tag.equals("tr")) {
607                            handleTableRow(sb, tags);
608                    }
609                    else if (tag.equals("url")) {
610                            handleURL(sb, bbCodeItems, tags, marker, bbCodeItem);
611                    }
612                    else {
613                            handleSimpleTag(sb, tags, bbCodeItem);
614                    }
615            }
616    
617            protected void handleTextAlign(
618                    StringBundler sb, Stack<String> tags, BBCodeItem bbCodeItem) {
619    
620                    sb.append("<p style=\"text-align: ");
621                    sb.append(bbCodeItem.getValue());
622                    sb.append("\">");
623    
624                    tags.push("</p>");
625            }
626    
627            protected void handleURL(
628                    StringBundler sb, List<BBCodeItem> bbCodeItems, Stack<String> tags,
629                    IntegerWrapper marker, BBCodeItem bbCodeItem) {
630    
631                    sb.append("<a href=\"");
632    
633                    String href = bbCodeItem.getAttribute();
634    
635                    if (href == null) {
636                            href = extractData(
637                                    bbCodeItems, marker, "url", BBCodeParser.TYPE_DATA, false);
638                    }
639    
640                    Matcher matcher = _urlPattern.matcher(href);
641    
642                    if (matcher.matches()) {
643                            sb.append(HtmlUtil.escapeHREF(href));
644                    }
645    
646                    sb.append("\">");
647    
648                    tags.push("</a>");
649            }
650    
651            protected boolean isValidTag(String tag) {
652                    if ((tag != null) && (tag.length() > 0)) {
653                            Matcher matcher = _tagPattern.matcher(tag);
654    
655                            return matcher.matches();
656                    }
657    
658                    return false;
659            }
660    
661            private static final String[][] _EMOTICONS = {
662                    {"happy.gif", ":)", "happy"},
663                    {"smile.gif", ":D", "smile"},
664                    {"cool.gif", "B)", "cool"},
665                    {"sad.gif", ":(", "sad"},
666                    {"tongue.gif", ":P", "tongue"},
667                    {"laugh.gif", ":lol:", "laugh"},
668                    {"kiss.gif", ":#", "kiss"},
669                    {"blush.gif", ":*)", "blush"},
670                    {"bashful.gif", ":bashful:", "bashful"},
671                    {"smug.gif", ":smug:", "smug"},
672                    {"blink.gif", ":blink:", "blink"},
673                    {"huh.gif", ":huh:", "huh"},
674                    {"mellow.gif", ":mellow:", "mellow"},
675                    {"unsure.gif", ":unsure:", "unsure"},
676                    {"mad.gif", ":mad:", "mad"},
677                    {"oh_my.gif", ":O", "oh-my-goodness"},
678                    {"roll_eyes.gif", ":rolleyes:", "roll-eyes"},
679                    {"angry.gif", ":angry:", "angry"},
680                    {"suspicious.gif", "8o", "suspicious"},
681                    {"big_grin.gif", ":grin:", "grin"},
682                    {"in_love.gif", ":love:", "in-love"},
683                    {"bored.gif", ":bored:", "bored"},
684                    {"closed_eyes.gif", "-_-", "closed-eyes"},
685                    {"cold.gif", ":cold:", "cold"},
686                    {"sleep.gif", ":sleep:", "sleep"},
687                    {"glare.gif", ":glare:", "glare"},
688                    {"darth_vader.gif", ":vader:", "darth-vader"},
689                    {"dry.gif", ":dry:", "dry"},
690                    {"exclamation.gif", ":what:", "what"},
691                    {"girl.gif", ":girl:", "girl"},
692                    {"karate_kid.gif", ":kid:", "karate-kid"},
693                    {"ninja.gif", ":ph34r:", "ninja"},
694                    {"pac_man.gif", ":V", "pac-man"},
695                    {"wacko.gif", ":wacko:", "wacko"},
696                    {"wink.gif", ":wink:", "wink"},
697                    {"wub.gif", ":wub:", "wub"}
698            };
699    
700            private static Log _log = LogFactoryUtil.getLog(
701                    HtmlBBCodeTranslatorImpl.class);
702    
703            private Map<String, String> _bbCodeCharacters;
704            private BBCodeParser _bbCodeParser = new BBCodeParser();
705            private Pattern _bbCodePattern = Pattern.compile("[]&<>'\"`\\[()]");
706            private Pattern _colorPattern = Pattern.compile(
707                    "^(:?aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple" +
708                            "|red|silver|teal|white|yellow|#(?:[0-9a-f]{3})?[0-9a-f]{3})$",
709                    Pattern.CASE_INSENSITIVE);
710            private String[] _emoticonDescriptions = new String[_EMOTICONS.length];
711            private String[] _emoticonFiles = new String[_EMOTICONS.length];
712            private String[] _emoticonSymbols = new String[_EMOTICONS.length];
713            private Map<String, Integer> _excludeNewLineTypes;
714            private int[] _fontSizes = {10, 12, 16, 18, 24, 32, 48};
715            private Pattern _imagePattern = Pattern.compile(
716                    "^(?:https?://|/)[-;/?:@&=+$,_.!~*'()%0-9a-z]{1,512}$",
717                    Pattern.CASE_INSENSITIVE);
718            private Map<String, String> _listStyles;
719            private Pattern _tagPattern = Pattern.compile(
720                    "^/?(?:b|center|code|colou?r|email|i|img|justify|left|pre|q|quote|" +
721                            "right|\\*|s|size|table|tr|th|td|li|list|font|u|url)$",
722                    Pattern.CASE_INSENSITIVE);
723            private Pattern _urlPattern = Pattern.compile(
724                    "^[-;/?:@&=+$,_.!~*'()%0-9a-z#]{1,512}$", Pattern.CASE_INSENSITIVE);
725    
726    }