1 package org.javabb.bbcode; 2 3 import java.io.Serializable ; 4 import java.util.ArrayList ; 5 import java.util.Collections ; 6 import java.util.Comparator ; 7 import java.util.HashSet ; 8 import java.util.LinkedList ; 9 import java.util.List ; 10 import java.util.Set ; 11 import java.util.Stack ; 12 import java.util.regex.Matcher ; 13 import java.util.regex.Pattern ; 14 15 30 31 36 public class ProcessBBCode implements Serializable { 37 private static final String CR_LF = "(?:\r\n|\r|\n)?"; 38 39 40 private boolean acceptHTML = false; 41 42 43 private boolean acceptBBCode = true; 44 45 48 public boolean getAcceptBBCode() { 49 return acceptBBCode; 50 } 51 52 55 public void setAcceptBBCode(boolean acceptBBCode) { 56 this.acceptBBCode = acceptBBCode; 57 } 58 59 62 public boolean getAcceptHTML() { 63 return acceptHTML; 64 } 65 66 69 public void setAcceptHTML(boolean acceptHTML) { 70 this.acceptHTML = acceptHTML; 71 } 72 73 77 public String preparePostText(String texto) { 78 if (!getAcceptHTML()) { 79 texto = escapeHtml(texto); 80 } 81 if (getAcceptBBCode()) { 82 texto = process(texto); 83 } 84 return texto; 85 } 86 87 91 private String process(String string) { 92 StringBuffer buffer = new StringBuffer (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 " </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 " </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 str = buffer.toString(); 118 119 str = str.replaceAll("(\r\n|\n\r|\n|\r)", "<br>"); 120 121 str = str.replaceAll("\\[color=['\"]?(.*?[^'\"])['\"]?\\](.*?)\\[/color\\]", 123 "<span style='color:$1'>$2</span>"); 124 125 str = str.replaceAll("\\[size=['\"]?([0-9]|[1-2][0-9])['\"]?\\](.*?)\\[/size\\]", 127 "<span style='font-size:$1px'>$2</span>"); 128 129 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 str = str.replaceAll("\\[img\\](.*?)\\[/img\\]", "<img SRC='$1' border='0' alt='0'>"); 136 137 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 str = str.replaceAll("\\[email\\](.*?)\\[/email\\]", "<a HREF='mailto:$1'>$1</a>"); 144 145 return str; 146 } 147 148 private static void processCode(StringBuffer 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 content = buffer.substring(start + "[code]".length(), end - "[/code]".length()); 163 content = escapeBBcode(content); 164 165 String replacement = "<!-- [ -code- ] --></span>" + "<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 181 public static String escapeBBcode(String content) { 182 content = replaceAll(content, "[]\t".toCharArray(), new String [] { "[", 184 "]", 185 " " }); 186 187 content = content.replaceAll("\\A\r\n|\\A\r|\\A\n|\r\n\\z|\r\\z|\n\\z", ""); 189 190 content = content.replaceAll(" ", " "); 192 content = content.replaceAll(" ", " "); 193 194 return content; 195 } 196 197 201 private static String escapeHtml(String content) { 202 content = replaceAll(content, "&<>".toCharArray(), new String [] { "&", "<", ">" }); 204 205 content = content.replaceAll("\r\n", "<br>"); 207 content = replaceAll(content, "\n\r".toCharArray(), new String [] { "<br>", "<br>" }); 208 209 return content; 210 } 211 212 private static String replaceAll(String str, char[] chars, String [] replacement) { 213 214 StringBuffer buffer = new StringBuffer (); 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 243 private static void processNestedTags( 244 StringBuffer buffer, 245 String tagName, 246 String openSubstWithParam, 247 String closeSubstWithParam, 248 String openSubstWithoutParam, 249 String closeSubstWithoutParam, 250 String internalSubst, 251 boolean processInternalTags, 252 boolean acceptParam, 253 boolean requiresQuotedParam) { 254 String str = buffer.toString(); 255 256 Stack openStack = new Stack (); 257 Set subsOpen = new HashSet (); 258 Set subsClose = new HashSet (); 259 Set subsInternal = new HashSet (); 260 261 String openTag = CR_LF + "\\[" 262 + tagName 263 + (acceptParam ? (requiresQuotedParam ? "(?:=\"(.*?)\")?" : "(?:=\"?(.*?)\"?)?") : "") 264 + "\\]" 265 + CR_LF; 266 String closeTag = CR_LF + "\\[/" + tagName + "\\]" + CR_LF; 267 String internTag = CR_LF + "\\[\\*\\]" + CR_LF; 268 269 String patternString = "(" + openTag + ")|(" + closeTag + ")"; 270 271 if (processInternalTags) { 272 patternString += "|(" + internTag + ")"; 273 } 274 275 Pattern tagsPattern = Pattern.compile(patternString); 276 Matcher 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; 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 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 } 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 } else if (processInternalTags && (matcher.group(internalTagGroup) != null) 320 && (!openStack.isEmpty())) { 321 subsInternal.add(matchedSeq); 322 } else { 323 } 325 } 326 327 LinkedList subst = new LinkedList (); 328 subst.addAll(subsOpen); 329 subst.addAll(subsClose); 330 subst.addAll(subsInternal); 331 332 Collections.sort(subst, new Comparator () { 333 public int compare(Object o1, Object 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 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( 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 { 377 378 public CharSequence base; 379 380 381 public int start; 382 383 384 public int length; 385 386 387 public String param = null; 388 389 391 public MutableCharSequence() { 392 } 394 395 400 public MutableCharSequence(CharSequence base, int start, int length) { 401 reset(base, start, length); 402 } 403 404 407 public int length() { 408 return this.length; 409 } 410 411 414 public char charAt(int index) { 415 return this.base.charAt(this.start + index); 416 } 417 418 421 public CharSequence subSequence(int pStart, int end) { 422 return new MutableCharSequence(this.base, 423 this.start + pStart, 424 this.start + (end - pStart)); 425 } 426 427 433 public CharSequence reset(CharSequence pBase, int pStart, int pLength) { 434 this.base = pBase; 435 this.start = pStart; 436 this.length = pLength; 437 438 return this; 439 } 440 441 444 public String toString() { 445 StringBuffer sb = new StringBuffer (); 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 |