KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > javabb > bbcode > ProcessBBCode


1 package org.javabb.bbcode;
2
3 import java.io.Serializable JavaDoc;
4 import java.util.ArrayList JavaDoc;
5 import java.util.Collections JavaDoc;
6 import java.util.Comparator JavaDoc;
7 import java.util.HashSet JavaDoc;
8 import java.util.LinkedList JavaDoc;
9 import java.util.List JavaDoc;
10 import java.util.Set JavaDoc;
11 import java.util.Stack JavaDoc;
12 import java.util.regex.Matcher JavaDoc;
13 import java.util.regex.Pattern JavaDoc;
14
15 /*
16  * Copyright 2004 JavaFree.org
17  *
18  * Licensed under the Apache License, Version 2.0 (the "License");
19  * you may not use this file except in compliance with the License.
20  * You may obtain a copy of the License at
21  *
22  * http://www.apache.org/licenses/LICENSE-2.0
23  *
24  * Unless required by applicable law or agreed to in writing, software
25  * distributed under the License is distributed on an "AS IS" BASIS,
26  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27  * See the License for the specific language governing permissions and
28  * limitations under the License.
29  */

30
31 /**
32  * $Id: ProcessBBCode.java,v 1.18.2.2.4.2 2006/04/17 17:47:04 daltoncamargo Exp $
33  * @author Dalton Camargo - <a HREF="mailto:dalton@javabb.org">dalton@javabb.org </a> <br>
34  * @author Ronald Tetsuo Miura
35  */

36 public class ProcessBBCode implements Serializable JavaDoc {
37     private static final String JavaDoc CR_LF = "(?:\r\n|\r|\n)?";
38
39     /** */
40     private boolean acceptHTML = false;
41
42     /** */
43     private boolean acceptBBCode = true;
44
45     /**
46      * @return acceptBBCode
47      */

48     public boolean getAcceptBBCode() {
49         return acceptBBCode;
50     }
51
52     /**
53      * @param acceptBBCode the new acceptBBCode value
54      */

55     public void setAcceptBBCode(boolean acceptBBCode) {
56         this.acceptBBCode = acceptBBCode;
57     }
58
59     /**
60      * @return htmlAccepted
61      */

62     public boolean getAcceptHTML() {
63         return acceptHTML;
64     }
65
66     /**
67      * @param acceptHTML the new acceptHTML value
68      */

69     public void setAcceptHTML(boolean acceptHTML) {
70         this.acceptHTML = acceptHTML;
71     }
72
73     /**
74      * @param texto
75      * @return TODO unuseful parameters.
76      */

77     public String JavaDoc preparePostText(String JavaDoc texto) {
78         if (!getAcceptHTML()) {
79             texto = escapeHtml(texto);
80         }
81         if (getAcceptBBCode()) {
82             texto = process(texto);
83         }
84         return texto;
85     }
86
87     /**
88      * @param string
89      * @return HTML-formated message
90      */

91     private String JavaDoc process(String JavaDoc string) {
92         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(string);
93         processCode(buffer);
94
95         processNestedTags(buffer,
96             "quote",
97             "<table width='90%' cellspacing='1' cellpadding='1' border='0' " + "align='center'><tr><td><span class='genmed'><b>{BBCODE_PARAM} escreveu:</b></span></td></tr></table><table width='90%' cellspacing='1' cellpadding='1' border='0' align='center'><tr><td class='quote' bgcolor='#F3F5FF'>",
98             " &nbsp;</td></tr></table>",
99             "<table width='90%' cellspacing='1' cellpadding='3' border='0' " + "align='center'><tr><td><span class='genmed'><b>Quote:</b></span></td></tr><tr><td class='quote'>",
100             " &nbsp;</td></tr></table>",
101             "[*]",
102             false,
103             true,
104             true);
105
106         processNestedTags(buffer,
107             "list",
108             "<ol type=\"{BBCODE_PARAM}\">",
109             "</ol>",
110             "<ul>",
111             "</ul>",
112             "<li>",
113             true,
114             true,
115             true);
116
117         String JavaDoc str = buffer.toString();
118
119         str = str.replaceAll("(\r\n|\n\r|\n|\r)", "<br>");
120
121         // [color]
122
str = str.replaceAll("\\[color=['\"]?(.*?[^'\"])['\"]?\\](.*?)\\[/color\\]",
123             "<span style='color:$1'>$2</span>");
124
125         // [size]
126
str = str.replaceAll("\\[size=['\"]?([0-9]|[1-2][0-9])['\"]?\\](.*?)\\[/size\\]",
127             "<span style='font-size:$1px'>$2</span>");
128
129         // [b][u][i]
130
str = str.replaceAll("\\[b\\](.*?)\\[/b\\]", "<b>$1</b>");
131         str = str.replaceAll("\\[u\\](.*?)\\[/u\\]", "<u>$1</u>");
132         str = str.replaceAll("\\[i\\](.*?)\\[/i\\]", "<i>$1</i>");
133
134         // [img]
135
str = str.replaceAll("\\[img\\](.*?)\\[/img\\]", "<img SRC='$1' border='0' alt='0'>");
136
137         // [url]
138
str = str.replaceAll("\\[url\\](.*?)\\[/url\\]", "<a HREF='$1' target='_blank'>$1</a>");
139         str = str.replaceAll("\\[url=['\"]?(.*?[^'\"])['\"]?\\](.*?)\\[/url\\]",
140             "<a HREF=\"$1\" target=\"_new\">$2</a>");
141
142         // [email]
143
str = str.replaceAll("\\[email\\](.*?)\\[/email\\]", "<a HREF='mailto:$1'>$1</a>");
144
145         return str;
146     }
147
148     private static void processCode(StringBuffer JavaDoc buffer) {
149         int start = buffer.indexOf("[code]");
150         int end;
151
152         for (; (start >= 0) && (start < buffer.length()); start = buffer.indexOf("[code]", end)) {
153
154             end = buffer.indexOf("[/code]", start);
155
156             if (end < 0) {
157                 break;
158             }
159
160             end += "[/code]".length();
161
162             String JavaDoc content = buffer.substring(start + "[code]".length(), end - "[/code]".length());
163             content = escapeBBcode(content);
164
165             String JavaDoc replacement = "<!-- [ -code- ] --></span>" //
166
+ "<table width='90%' cellspacing='1' cellpadding='3' border='0' align='center'>"
167                 + "<tr><td><span class='genmed'><b>Code:</b></span></td></tr>"
168                 + "<tr><td class='code'>"
169                 + content
170                 + "</td></tr></table><span class='postbody'><!-- [/ -code- ] -->";
171             buffer.replace(start, end, replacement);
172
173             end = start + replacement.length();
174         }
175     }
176
177     /**
178      * @param content
179      * @return -
180      */

181     public static String JavaDoc escapeBBcode(String JavaDoc content) {
182         // escaping single characters
183
content = replaceAll(content, "[]\t".toCharArray(), new String JavaDoc[] { "&#91;",
184             "&#93;",
185             "&nbsp; &nbsp;" });
186
187         // taking off start and end line breaks
188
content = content.replaceAll("\\A\r\n|\\A\r|\\A\n|\r\n\\z|\r\\z|\n\\z", "");
189
190         // replacing spaces for &nbsp; to keep indentation
191
content = content.replaceAll(" ", "&nbsp; ");
192         content = content.replaceAll(" ", " &nbsp;");
193
194         return content;
195     }
196
197     /**
198      * @param content
199      * @return -
200      */

201     private static String JavaDoc escapeHtml(String JavaDoc content) {
202         // escaping single characters
203
content = replaceAll(content, "&<>".toCharArray(), new String JavaDoc[] { "&amp;", "&lt;", "&gt;" });
204
205         // replacing line breaks for <br>
206
content = content.replaceAll("\r\n", "<br>");
207         content = replaceAll(content, "\n\r".toCharArray(), new String JavaDoc[] { "<br>", "<br>" });
208
209         return content;
210     }
211
212     private static String JavaDoc replaceAll(String JavaDoc str, char[] chars, String JavaDoc[] replacement) {
213
214         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
215         for (int i = 0; i < str.length(); i++) {
216             char c = str.charAt(i);
217             boolean matched = false;
218             for (int j = 0; j < chars.length; j++) {
219                 if (c == chars[j]) {
220                     buffer.append(replacement[j]);
221                     matched = true;
222                 }
223             }
224             if (!matched) {
225                 buffer.append(c);
226             }
227         }
228         return buffer.toString();
229     }
230
231     /**
232      * @param buffer
233      * @param tagName
234      * @param openSubstWithParam
235      * @param closeSubstWithParam
236      * @param openSubstWithoutParam
237      * @param closeSubstWithoutParam
238      * @param internalSubst
239      * @param processInternalTags
240      * @param acceptParam
241      * @param requiresQuotedParam
242      */

243     private static void processNestedTags(
244         StringBuffer JavaDoc buffer,
245         String JavaDoc tagName,
246         String JavaDoc openSubstWithParam,
247         String JavaDoc closeSubstWithParam,
248         String JavaDoc openSubstWithoutParam,
249         String JavaDoc closeSubstWithoutParam,
250         String JavaDoc internalSubst,
251         boolean processInternalTags,
252         boolean acceptParam,
253         boolean requiresQuotedParam) {
254         String JavaDoc str = buffer.toString();
255
256         Stack JavaDoc openStack = new Stack JavaDoc();
257         Set JavaDoc subsOpen = new HashSet JavaDoc();
258         Set JavaDoc subsClose = new HashSet JavaDoc();
259         Set JavaDoc subsInternal = new HashSet JavaDoc();
260
261         String JavaDoc openTag = CR_LF + "\\["
262             + tagName
263             + (acceptParam ? (requiresQuotedParam ? "(?:=\"(.*?)\")?" : "(?:=\"?(.*?)\"?)?") : "")
264             + "\\]"
265             + CR_LF;
266         String JavaDoc closeTag = CR_LF + "\\[/" + tagName + "\\]" + CR_LF;
267         String JavaDoc internTag = CR_LF + "\\[\\*\\]" + CR_LF;
268
269         String JavaDoc patternString = "(" + openTag + ")|(" + closeTag + ")";
270
271         if (processInternalTags) {
272             patternString += "|(" + internTag + ")";
273         }
274
275         Pattern JavaDoc tagsPattern = Pattern.compile(patternString);
276         Matcher JavaDoc matcher = tagsPattern.matcher(str);
277
278         int openTagGroup;
279         int paramGroup;
280         int closeTagGroup;
281         int internalTagGroup;
282
283         if (acceptParam) {
284             openTagGroup = 1;
285             paramGroup = 2;
286             closeTagGroup = 3;
287             internalTagGroup = 4;
288         } else {
289             openTagGroup = 1;
290             paramGroup = -1; // INFO
291
closeTagGroup = 2;
292             internalTagGroup = 3;
293         }
294
295         while (matcher.find()) {
296             int length = matcher.end() - matcher.start();
297             MutableCharSequence matchedSeq = new MutableCharSequence(str, matcher.start(), length);
298
299             // test opening tags
300
if (matcher.group(openTagGroup) != null) {
301                 if (acceptParam && (matcher.group(paramGroup) != null)) {
302                     matchedSeq.param = matcher.group(paramGroup);
303                 }
304
305                 openStack.push(matchedSeq);
306
307                 // test closing tags
308
} else if ((matcher.group(closeTagGroup) != null) && !openStack.isEmpty()) {
309                 MutableCharSequence openSeq = (MutableCharSequence) openStack.pop();
310
311                 if (acceptParam) {
312                     matchedSeq.param = openSeq.param;
313                 }
314
315                 subsOpen.add(openSeq);
316                 subsClose.add(matchedSeq);
317
318                 // test internal tags
319
} else if (processInternalTags && (matcher.group(internalTagGroup) != null)
320                 && (!openStack.isEmpty())) {
321                 subsInternal.add(matchedSeq);
322             } else {
323                 // assert (false);
324
}
325         }
326
327         LinkedList JavaDoc subst = new LinkedList JavaDoc();
328         subst.addAll(subsOpen);
329         subst.addAll(subsClose);
330         subst.addAll(subsInternal);
331
332         Collections.sort(subst, new Comparator JavaDoc() {
333             public int compare(Object JavaDoc o1, Object JavaDoc o2) {
334                 MutableCharSequence s1 = (MutableCharSequence) o1;
335                 MutableCharSequence s2 = (MutableCharSequence) o2;
336                 return -(s1.start - s2.start);
337             }
338         });
339
340         buffer.delete(0, buffer.length());
341
342         int start = 0;
343
344         while (!subst.isEmpty()) {
345             MutableCharSequence seq = (MutableCharSequence) subst.removeLast();
346             buffer.append(str.substring(start, seq.start));
347
348             if (subsClose.contains(seq)) {
349                 if (seq.param != null) {
350                     buffer.append(closeSubstWithParam);
351                 } else {
352                     buffer.append(closeSubstWithoutParam);
353                 }
354             } else if (subsInternal.contains(seq)) {
355                 buffer.append(internalSubst);
356             } else if (subsOpen.contains(seq)) {
357                 Matcher JavaDoc m = Pattern.compile(openTag).matcher(str.substring(seq.start,
358                     seq.start + seq.length));
359
360                 if (m.matches()) {
361                     if (acceptParam && (seq.param != null)) {
362                         buffer.append( //
363
openSubstWithParam.replaceAll("\\{BBCODE_PARAM\\}", seq.param));
364                     } else {
365                         buffer.append(openSubstWithoutParam);
366                     }
367                 }
368             }
369
370             start = seq.start + seq.length;
371         }
372
373         buffer.append(str.substring(start));
374     }
375
376     static class MutableCharSequence implements CharSequence JavaDoc {
377         /** */
378         public CharSequence JavaDoc base;
379
380         /** */
381         public int start;
382
383         /** */
384         public int length;
385
386         /** */
387         public String JavaDoc param = null;
388
389         /**
390          */

391         public MutableCharSequence() {
392             //
393
}
394
395         /**
396          * @param base
397          * @param start
398          * @param length
399          */

400         public MutableCharSequence(CharSequence JavaDoc base, int start, int length) {
401             reset(base, start, length);
402         }
403
404         /**
405          * @see java.lang.CharSequence#length()
406          */

407         public int length() {
408             return this.length;
409         }
410
411         /**
412          * @see java.lang.CharSequence#charAt(int)
413          */

414         public char charAt(int index) {
415             return this.base.charAt(this.start + index);
416         }
417
418         /**
419          * @see java.lang.CharSequence#subSequence(int, int)
420          */

421         public CharSequence JavaDoc subSequence(int pStart, int end) {
422             return new MutableCharSequence(this.base,
423                 this.start + pStart,
424                 this.start + (end - pStart));
425         }
426
427         /**
428          * @param pBase
429          * @param pStart
430          * @param pLength
431          * @return -
432          */

433         public CharSequence JavaDoc reset(CharSequence JavaDoc pBase, int pStart, int pLength) {
434             this.base = pBase;
435             this.start = pStart;
436             this.length = pLength;
437
438             return this;
439         }
440
441         /**
442          * @see java.lang.Object#toString()
443          */

444         public String JavaDoc toString() {
445             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
446
447             for (int i = this.start; i < (this.start + this.length); i++) {
448                 sb.append(this.base.charAt(i));
449             }
450
451             return sb.toString();
452         }
453
454     }
455     
456 }
457
Popular Tags