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