1 54 55 68 package org.wings.template.parser; 69 70 import java.io.IOException ; 71 import java.io.Reader ; 72 import java.io.StringReader ; 73 import java.util.HashMap ; 74 import java.util.Iterator ; 75 import java.util.LinkedHashMap ; 76 import java.util.LinkedList ; 77 78 113 114 118 119 public class SGMLTag { 120 public final static char singleQuote = '\''; 121 public final static char doubleQuote = '\"'; 122 123 127 private String name = null; 128 129 133 private String closeTag = null; 134 135 138 private int offset = 0; 139 140 143 private int start = 0; 144 private int end = 0; 145 146 private LinkedList attrs = null; private LinkedHashMap values = null; private boolean wellFormed = true; private boolean attr_ready = false; 151 152 static final String COMMENT_START = "!--", COMMENT_END = "-->"; 154 static final String SSI_START = COMMENT_START + "#", SSI_END = COMMENT_END; 155 156 160 private SGMLTag(String textContent, int begin) { 161 PositionReader r = new PositionReader(new StringReader (textContent)); 162 try { 163 r.skip(begin); 164 offset = begin; 165 searchStart(r); 166 start = offset; 167 parse(r); 171 } catch (IOException reading_from_string_should_never_fail) { 172 offset = -1; 173 } 174 end = (int) r.getPosition(); 175 } 176 177 194 public SGMLTag(Reader input, boolean parseIt) 195 throws IOException { 196 searchStart(input); 197 if (parseIt) readAttributes(input); 198 } 199 200 210 public SGMLTag(Reader input) 211 throws IOException { 212 this(input, true); 213 } 214 215 public void parse(Reader input) 216 throws IOException { 217 readAttributes(input); 218 } 219 220 226 protected void searchStart(Reader input) 227 throws IOException { 228 int c = 0, num; 229 char buff[] = new char[8]; String cmpStr; 231 232 while (true) { 234 while (c >= 0 && c != '<') { 236 c = input.read(); 237 offset++; 238 } 239 if (c == -1) { 240 offset = -1; 241 return; 242 } offset--; 244 245 250 input.mark(SSI_START.length()); 251 int pos; 252 num = 0; 253 for (pos = 0; pos >= 0 && num < SSI_START.length(); num += pos) 254 pos = input.read(buff, pos, SSI_START.length() - pos); 255 if (pos == -1) { 256 offset = -1; 257 return; 258 } 260 cmpStr = new String (buff, 0, num); 261 if (SSI_START.equals(cmpStr) || 262 !(cmpStr.startsWith(COMMENT_START))) { 263 input.reset(); 264 break; } 266 267 272 input.reset(); 273 num = 0; 274 for (pos = 0; pos >= 0 && num < COMMENT_START.length(); num += pos) 275 pos = input.read(buff, pos, COMMENT_START.length() - pos); 276 279 offset += COMMENT_START.length() + 1; boolean endOfComment = false; 282 int len = 0, ringHead = 0; 283 int checkpos, p; 284 while (!endOfComment) { 285 c = input.read(); 286 if (c == -1) { 287 offset = -1; 288 return; 289 } len++; 291 offset++; 292 buff[ringHead] = (char) c; if (len >= COMMENT_END.length()) { 295 for (checkpos = ringHead + buff.length, p = COMMENT_END.length() - 1; 297 p >= 0; --checkpos, --p) { 298 if (COMMENT_END.charAt(p) != buff[checkpos % buff.length]) 299 break; 300 } 301 endOfComment = (p == -1); 302 } 303 ringHead = (++ringHead) % buff.length; 304 } 305 306 } 307 308 name = nextToken(input, false); 312 if (name != null) 313 name = name.toUpperCase(); 314 315 if (name != null && name.startsWith(SSI_START)) { 317 closeTag = SSI_END; } else { 319 closeTag = ">"; } 321 } 322 323 324 330 public boolean finished() { 331 return offset == -1 && name == null; 332 } 333 334 340 public boolean isNamed(String name) { 341 return this.name != null && this.name.equals(name.toUpperCase()); 342 } 343 344 350 public boolean isWellFormed() { 351 if (name == null) return false; 352 if (!attr_ready || values == null) return false; 353 return wellFormed; 354 } 355 356 360 public int getOffset() { 361 return offset; 362 } 363 364 370 public String getName() { 371 return name; 372 } 373 374 383 public Iterator attributes(boolean upperCase) { 384 if (!isWellFormed()) 386 return null; 387 388 if (upperCase) { 390 return values.keySet().iterator(); 391 } else { 392 return attrs.iterator(); 393 } 394 } 395 396 407 public String value(String attributeName, String defaultValue) { 408 if (!isWellFormed()) 409 return null; 410 String value = (String ) values.get(attributeName.toUpperCase()); 411 return value == null ? defaultValue : value; 412 } 413 414 419 private boolean readAttributes(Reader input) 420 throws IOException { 421 423 if (attr_ready) 424 return wellFormed && values != null; 425 attr_ready = true; 426 427 if (values == null && wellFormed) { 428 String key = null, token; 429 wellFormed = false; 430 attrs = new LinkedList (); 431 values = new LinkedHashMap (); 432 433 while (true) { 434 if (key == null) 436 key = nextToken(input); 437 438 if (key != null && key.equals(closeTag)) { 440 wellFormed = true; 441 break; 442 } 443 444 if (key != null && key.equals("/>")) { 446 wellFormed = true; 447 break; 448 } 449 450 if (key == null 452 || isDelimiter(key.charAt(0)) 453 || key.charAt(0) == doubleQuote 454 || key.charAt(0) == singleQuote) 455 break; 456 457 token = nextToken(input); 459 if (token == null || token.charAt(0) != '=') { 460 attrs.add(key); 461 if (token == null) 462 break; 463 key = token; continue; 465 } 466 467 token = nextToken(input); 469 if (token == null || isDelimiter(token.charAt(0))) 470 break; 471 472 if (token.charAt(0) == doubleQuote || token.charAt(0) == singleQuote) 474 token = token.substring(1, token.length() - 1); 475 476 String upperCase = key.toUpperCase(); 478 if (!values.containsKey(upperCase)) 479 attrs.add(key); 480 481 values.put(upperCase, token); 483 key = null; } 485 } 486 return wellFormed && values != null; 487 } 488 489 499 public String nextToken(Reader input) 500 throws IOException { 501 return nextToken(input, true); 502 } 503 504 514 public String nextToken(Reader input, boolean skipWhitespaces) 515 throws IOException { 516 StringBuffer token = new StringBuffer (); 517 518 if (skipWhitespaces) 519 skipWhiteSpace(input); 520 521 input.mark(1); 522 int c = input.read(); 523 524 if (c == -1) { 525 offset = -1; 526 return null; 527 } 528 529 if (c == doubleQuote || c == singleQuote) { 531 boolean inSingle = false; 532 boolean inDouble = false; 533 if (c == singleQuote) inSingle = true; else inDouble = true; 534 token.append((char) c); 535 do { 536 c = input.read(); 537 if (c == -1) { 538 offset = -1; 539 String reportString = token.toString(); 540 if (reportString.length() > 30) { 541 reportString = reportString.substring(0, 30) + 542 " (truncated, length is " + reportString.length() + ")"; 543 } 544 throw new IOException ("EOF in String: " + reportString); 545 } 546 if (c == '\\') { 547 int quoted = input.read(); 548 if (quoted >= 0) token.append((char) quoted); 549 } else 550 token.append((char) c); 551 } while ((inDouble && c != doubleQuote) || (inSingle && c != singleQuote)); 552 } 553 554 else if (isDelimiter((char) c)) { 556 token.append((char) c); 557 } 558 559 else if (c == '-') { 562 do { 563 token.append((char) c); 564 input.mark(1); 565 c = input.read(); 566 } while (c >= 0 && 567 !Character.isWhitespace((char) c) && 568 !isDelimiter((char) c)); 569 input.reset(); 570 token.append((char) input.read()); 571 } 572 573 else if (!skipWhitespaces && 576 Character.isWhitespace((char) c)) { 577 input.reset(); 578 return null; 579 } 580 581 else { 583 do { 584 token.append((char) c); 585 input.mark(1); 586 c = input.read(); 587 } while (c >= 0 && 588 !Character.isWhitespace((char) c) && 589 !isDelimiter((char) c)); 590 if (token.length() == 1 && token.charAt(0) == '/') 591 token.append((char) c); 592 else 593 input.reset(); 594 } 595 return token.toString(); 596 } 597 598 601 public static int skipWhiteSpace(Reader r) 602 throws IOException { 603 int c, len = 0; 604 do { 605 r.mark(1); 606 c = r.read(); 607 len++; 608 } while (c >= 0 && Character.isWhitespace((char) c)); 609 r.reset(); 610 return len - 1; 611 } 612 613 622 public String getAttribute(String key, String defaultValue) { 623 return value(key, defaultValue); 624 } 625 626 633 public HashMap getAttributes() { 634 return isWellFormed() ? values : null; 635 } 636 637 643 private static boolean isDelimiter(char c) { 644 return c == '<' || c == '=' || c == '>'; 645 } 646 647 652 public String toString() { 653 StringBuffer str = new StringBuffer (); 654 str.append("[SGMLTag ").append(name).append(": (").append(getOffset()).append(",---)"); 655 if (attrs != null && wellFormed) { 656 Iterator iter = attributes(true); 657 while (iter.hasNext()) { 658 String key = (String ) iter.next(); 659 str.append(" ").append(key).append("=\"").append(value(key, null)).append("\""); 660 } 661 } else { 662 str.append(" *MALFORMED TAG*"); 663 } 664 str.append(" ]"); 665 return str.toString(); 666 } 667 } 668 669 670 671 | Popular Tags |