1 9 10 package org.jboss.portal.format.parser.bbcode; 11 12 import java.io.IOException ; 13 import java.io.Reader ; 14 import java.util.Iterator ; 15 16 import org.jboss.portal.format.parser.AbstractParser; 17 import org.jboss.portal.format.parser.ParseEvent; 18 import org.jboss.portal.format.parser.TextEvent; 19 import org.jboss.portal.format.parser.Token; 20 import org.jboss.portal.format.parser.chars.MutableChars; 21 import org.jboss.portal.format.util.Stack; 22 23 29 public class BBCodeParser 30 extends AbstractParser 31 { 32 33 35 public static final int EVENT_NORMAL = 0; 36 public static final int EVENT_BOLD = 1; 37 public static final int EVENT_ITALIC = 2; 38 public static final int EVENT_UNDERLINE = 3; 39 public static final int EVENT_COLOR = 4; 40 public static final int EVENT_SIZE = 5; 41 public static final int EVENT_QUOTE = 6; 42 public static final int EVENT_CODE = 7; 43 public static final int EVENT_ITEM = 8; 44 public static final int EVENT_LINK = 9; 45 public static final int EVENT_UNORDERED_LIST = 10; 46 public static final int EVENT_ALPHABETICALLY_ORDERED_LIST = 11; 47 public static final int EVENT_NUMERICALLY_ORDERED_LIST = 12; 48 49 51 public static final Reader NULL_READER = new Reader () 52 { 53 public int read(char cbuf[], int off, int len) throws IOException 54 { 55 return 0; 56 } 57 public void close() throws IOException 58 { 59 } 60 }; 61 62 private Analyzer analyzer = new Analyzer(BBCodeParser.NULL_READER); 63 private CodeKey myKey = new CodeKey(); 64 private MutableChars buffer = new MutableChars(); 65 private TextEvent textEvent = new TextEvent(); 66 private OpenEvent openEvent = new OpenEvent(); 67 68 private Stack stack = new Stack(10) 69 { 70 protected Stack.Key createKey() 71 { 72 return new CloseEvent(); 73 } 74 protected boolean equals(Stack.Key key1, Stack.Key key2) 75 { 76 return ((CodeKey)key1).getType() == ((CodeKey)key2).getType(); 77 } 78 }; 79 80 public BBCodeParser() 81 { 82 } 83 84 public void parse(char[] chars, int offset, int length) 85 { 86 stack.reset(); 88 analyzer.reset(chars, offset, length); 89 buffer.reset(); 90 91 _start(EVENT_NORMAL, null); 93 94 while (true) 96 { 97 Token t = analyzer.next(); 99 100 if (t == null) 101 { 102 break; 104 } 105 106 switch (t.type) 108 { 109 case Analyzer.OPEN_B: 110 _start(EVENT_BOLD, null); 111 break; 112 case Analyzer.CLOSE_B: 113 _end(EVENT_BOLD); 114 break; 115 116 case Analyzer.OPEN_I: 117 _start(EVENT_ITALIC, null); 118 break; 119 case Analyzer.CLOSE_I: 120 _end(EVENT_ITALIC); 121 break; 122 123 case Analyzer.OPEN_U: 124 _start(EVENT_UNDERLINE, null); 125 break; 126 case Analyzer.CLOSE_U: 127 _end(EVENT_UNDERLINE); 128 break; 129 130 case Analyzer.OPEN_COLOR: 131 _start(EVENT_COLOR, t.value); 132 break; 133 case Analyzer.CLOSE_COLOR: 134 _end(EVENT_COLOR); 135 break; 136 137 case Analyzer.OPEN_SIZE: 138 _start(EVENT_SIZE, t.value); 139 break; 140 case Analyzer.CLOSE_SIZE: 141 _end(EVENT_SIZE); 142 break; 143 144 case Analyzer.OPEN_QUOTE_ANONYMOUS: 145 _start(EVENT_QUOTE, null); 146 break; 147 case Analyzer.OPEN_QUOTE: 148 _start(EVENT_QUOTE, t.value); 149 break; 150 case Analyzer.CLOSE_QUOTE: 151 _end(EVENT_QUOTE); 152 break; 153 154 case Analyzer.OPEN_CODE: 155 _start(EVENT_CODE, null); 156 break; 157 case Analyzer.CLOSE_CODE: 158 _end(EVENT_CODE); 159 break; 160 161 case Analyzer.OPEN_LIST_UNORDERED: 162 _start(EVENT_UNORDERED_LIST, null); 163 break; 164 case Analyzer.OPEN_LIST_ORDERED_NUMERICAL: 165 _start(EVENT_NUMERICALLY_ORDERED_LIST, null); 166 break; 167 case Analyzer.OPEN_LIST_ORDERED_ALPHABETICAL: 168 _start(EVENT_ALPHABETICALLY_ORDERED_LIST, null); 169 break; 170 171 case Analyzer.CLOSE_LIST: 172 CodeKey tmp = (CodeKey)stack.peek(2); 176 if (tmp != null) 177 { 178 int type = tmp.type; 179 if (type == EVENT_UNORDERED_LIST || 180 type == EVENT_NUMERICALLY_ORDERED_LIST || 181 type == EVENT_ALPHABETICALLY_ORDERED_LIST) 182 { 183 _end(type); 184 } 185 } 186 break; 187 188 case Analyzer.LIST_ITEM: 189 CodeKey tmp2 = (CodeKey)stack.peek(1); 191 if (tmp2 != null && tmp2.type == EVENT_ITEM) 192 { 193 _end(EVENT_ITEM); 194 } 195 _start(EVENT_ITEM, null); 196 break; 197 198 case Analyzer.LINK: 199 int bracket = t.value.indexOf(']'); 200 if (bracket > 0) 201 { 202 boolean hasEquals = t.value.charAt(0) == '='; 203 if (hasEquals) 204 { 205 String url = t.value.substring(1, bracket); 207 String link = t.value.substring(bracket + 1); 208 _start(EVENT_LINK, url); 209 _end(EVENT_LINK); 210 } 211 } 212 else 213 { 214 _start(EVENT_LINK, t.value.substring(1)); 215 _end(EVENT_LINK); 216 } 217 218 break; 219 220 case Analyzer.TEXT: 221 buffer.append(t.value.charAt(0)); 222 break; 223 224 default: 225 throw new IllegalStateException ("This should not be possible"); 226 } 227 } 228 229 _end(EVENT_NORMAL); 231 } 232 233 private void _text() 234 { 235 if (buffer.length() > 0) 236 { 237 textEvent.setText(buffer.chars(), 0, buffer.length()); 238 buffer.reset(); 239 handler.handle(textEvent); 240 } 241 } 242 243 private void _start(int type, String string) 244 { 245 _text(); 246 CloseEvent closeEvent = (CloseEvent)stack.push(); 247 openEvent.type = closeEvent.type = type; 248 openEvent.string = string; 249 handler.handle(openEvent); 250 } 251 252 private void _end(int type) 253 { 254 myKey.type = type; 255 Iterator i = stack.pop(myKey); 256 if (i.hasNext()) 257 { 258 _text(); 259 do 260 { 261 handler.handle((CloseEvent)i.next()); 262 } 263 while (i.hasNext()); 264 } 265 } 266 267 private static class CodeKey implements Stack.Key 268 { 269 protected int type; 270 protected String string; 271 public CodeKey() 272 { 273 type = -1; 274 string = null; 275 } 276 public int getType() 277 { 278 return type; 279 } 280 public String getString() 281 { 282 return string; 283 } 284 } 285 286 public static class OpenEvent extends CodeKey implements ParseEvent 287 { 288 public String toString() 289 { 290 return "open: " + type + " " + string; 291 } 292 } 293 294 public static class CloseEvent extends CodeKey implements ParseEvent 295 { 296 public String toString() 297 { 298 return "close: " + type + " " + string; 299 } 300 } 301 } 302 | Popular Tags |