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