001
014
015 package com.liferay.portal.parsers.bbcode;
016
017 import com.liferay.portal.kernel.util.GetterUtil;
018 import com.liferay.portal.kernel.util.IntegerWrapper;
019 import com.liferay.portal.kernel.util.SetUtil;
020
021 import java.util.ArrayList;
022 import java.util.List;
023 import java.util.Set;
024 import java.util.Stack;
025
026
029 public class BBCodeParser {
030
031 public static final int TYPE_DATA = 0x04;
032
033 public static final int TYPE_TAG_END = 0x02;
034
035 public static final int TYPE_TAG_START = 0x01;
036
037 public static final int TYPE_TAG_START_END = TYPE_TAG_START | TYPE_TAG_END;
038
039 public BBCodeParser() {
040 _blockElements = SetUtil.fromArray(
041 new String[] {
042 "*", "center", "code", "justify", "left", "li", "list", "q",
043 "quote", "right", "table", "td", "th", "tr"
044 });
045
046 _inlineElements = SetUtil.fromArray(
047 new String[] {
048 "b", "color", "font", "i", "img", "s", "size", "u", "url"
049 });
050
051 _selfCloseElements = SetUtil.fromArray(new String[] {"*"});
052 }
053
054 public List<BBCodeItem> parse(String text) {
055 List<BBCodeItem> bbCodeItems = new ArrayList<BBCodeItem>();
056
057 BBCodeLexer bbCodeLexer = new BBCodeLexer(text);
058 Stack<String> tags = new Stack<String>();
059 IntegerWrapper marker = new IntegerWrapper();
060
061 BBCodeToken bbCodeToken = null;
062
063 while ((bbCodeToken = bbCodeLexer.getNextBBCodeToken()) != null) {
064 handleData(bbCodeItems, bbCodeLexer, marker, bbCodeToken, text);
065
066 if (bbCodeToken.getStartTag() == null) {
067 handleTagEnd(bbCodeItems, tags, bbCodeToken);
068
069 continue;
070 }
071
072 handleTagStart(bbCodeItems, tags, bbCodeToken);
073
074 String startTag = bbCodeToken.getStartTag();
075
076 if (!startTag.equals("code")) {
077 continue;
078 }
079
080 while (true) {
081 bbCodeToken = bbCodeLexer.getNextBBCodeToken();
082
083 if (bbCodeToken == null) {
084 break;
085 }
086
087 String endTag = GetterUtil.getString(bbCodeToken.getEndTag());
088
089 if (endTag.equals("code")) {
090 break;
091 }
092 }
093
094 handleData(bbCodeItems, bbCodeLexer, marker, bbCodeToken, text);
095
096 if (bbCodeToken != null) {
097 handleTagEnd(bbCodeItems, tags, bbCodeToken);
098 }
099 else {
100 break;
101 }
102 }
103
104 handleData(bbCodeItems, bbCodeLexer, marker, null, text);
105 handleTagEnd(bbCodeItems, tags, null);
106
107 return bbCodeItems;
108 }
109
110 protected void handleData(
111 List<BBCodeItem> bbCodeItems, BBCodeLexer bbCodeLexer,
112 IntegerWrapper marker, BBCodeToken bbCodeToken, String data) {
113
114 int length = data.length();
115
116 int lastIndex = length;
117
118 if (bbCodeToken != null) {
119 length = bbCodeToken.getStart();
120
121 lastIndex = bbCodeLexer.getLastIndex();
122 }
123
124 if (length > marker.getValue()) {
125 BBCodeItem bbCodeItem = new BBCodeItem(
126 TYPE_DATA, null, data.substring(marker.getValue(), length));
127
128 bbCodeItems.add(bbCodeItem);
129 }
130
131 marker.setValue(lastIndex);
132 }
133
134 protected void handleTagEnd(
135 List<BBCodeItem> bbCodeItems, Stack<String> tags,
136 BBCodeToken bbCodeToken) {
137
138 int size = 0;
139
140 if (bbCodeToken != null) {
141 String endTag = bbCodeToken.getEndTag();
142
143 for (size = tags.size() - 1; size >= 0; size--) {
144 if (endTag.equals(tags.elementAt(size))) {
145 break;
146 }
147 }
148 }
149
150 if (size >= 0) {
151 for (int i = tags.size() - 1; i >= size; i--) {
152 BBCodeItem bbCodeItem = new BBCodeItem(
153 TYPE_TAG_END, null, tags.elementAt(i));
154
155 bbCodeItems.add(bbCodeItem);
156 }
157
158 tags.setSize(size);
159 }
160 }
161
162 protected void handleTagStart(
163 List<BBCodeItem> bbCodeItems, Stack<String> tags,
164 BBCodeToken bbCodeToken) {
165
166 String startTag = bbCodeToken.getStartTag();
167
168 if (_blockElements.contains(startTag)) {
169 String currentTag = null;
170
171 while (!tags.isEmpty() &&
172 ((currentTag = tags.lastElement()) != null) &&
173 _inlineElements.contains(currentTag)) {
174
175 BBCodeToken currentTagBBCodeToken = new BBCodeToken(currentTag);
176
177 handleTagEnd(bbCodeItems, tags, currentTagBBCodeToken);
178 }
179 }
180
181 if (_selfCloseElements.contains(startTag) &&
182 startTag.equals(tags.lastElement())) {
183
184 BBCodeToken tagBBCodeToken = new BBCodeToken(startTag);
185
186 handleTagEnd(bbCodeItems, tags, tagBBCodeToken);
187 }
188
189 tags.push(startTag);
190
191 BBCodeItem bbCodeItem = new BBCodeItem(
192 TYPE_TAG_START, bbCodeToken.getAttribute(), startTag);
193
194 bbCodeItems.add(bbCodeItem);
195 }
196
197 private Set<String> _blockElements;
198 private Set<String> _inlineElements;
199 private Set<String> _selfCloseElements;
200
201 }