1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 package com.sun.org.apache.xerces.internal.xpointer; 22 23 import java.util.HashMap; 24 25 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 26 import com.sun.org.apache.xerces.internal.util.SymbolTable; 27 import com.sun.org.apache.xerces.internal.util.XMLChar; 28 import com.sun.org.apache.xerces.internal.xni.Augmentations; 29 import com.sun.org.apache.xerces.internal.xni.QName; 30 import com.sun.org.apache.xerces.internal.xni.XMLAttributes; 31 import com.sun.org.apache.xerces.internal.xni.XNIException; 32 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler; 33 34 /** 35 * <p> 36 * Implements the XPointerPart interface for element() scheme specific processing. 37 * </p> 38 * 39 * @xerces.internal 40 * 41 * @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $ 42 */ 43 final class ElementSchemePointer implements XPointerPart { 44 45 // Fields 46 47 // The Scheme Name i.e element 48 private String fSchemeName; 49 50 // The scheme Data 51 private String fSchemeData; 52 53 // The scheme Data & child sequence 54 private String fShortHandPointerName; 55 56 // Should we attempt to resolve the ChildSequence from the 57 // current element position. If a ShortHand Pointer is present 58 // attempt to resolve relative to the short hand pointer. 59 private boolean fIsResolveElement = false; 60 61 // Has the element been found 62 private boolean fIsElementFound = false; 63 64 // Was only an empty element found 65 private boolean fWasOnlyEmptyElementFound = false; 66 67 // If a shorthand pointer is present and resolved 68 boolean fIsShortHand = false; 69 70 // The depth at which the element was found 71 int fFoundDepth = 0; 72 73 // The XPointer element child sequence 74 private int fChildSequence[]; 75 76 // The current child position 77 private int fCurrentChildPosition = 1; 78 79 // The current child depth 80 private int fCurrentChildDepth = 0; 81 82 // The current element's child sequence 83 private int fCurrentChildSequence[];; 84 85 // Stores if the Fragment was resolved by the pointer 86 private boolean fIsFragmentResolved = false; 87 88 // Stores if the Fragment was resolved by the pointer 89 private ShortHandPointer fShortHandPointer; 90 91 // The XPointer Error reporter 92 protected XMLErrorReporter fErrorReporter; 93 94 // The XPointer Error Handler 95 protected XMLErrorHandler fErrorHandler; 96 97 // 98 private SymbolTable fSymbolTable; 99 100 // ************************************************************************ 101 // Constructors 102 // ************************************************************************ 103 public ElementSchemePointer() { 104 } 105 106 public ElementSchemePointer(SymbolTable symbolTable) { 107 fSymbolTable = symbolTable; 108 } 109 110 public ElementSchemePointer(SymbolTable symbolTable, 111 XMLErrorReporter errorReporter) { 112 fSymbolTable = symbolTable; 113 fErrorReporter = errorReporter; 114 } 115 116 // ************************************************************************ 117 // XPointerPart implementation 118 // ************************************************************************ 119 120 /** 121 * Parses the XPointer expression and tokenizes it into Strings 122 * delimited by whitespace. 123 * 124 * @see com.sun.org.apache.xerces.internal.xpointer.XPointerProcessor#parseXPointer(java.lang.String) 125 */ 126 public void parseXPointer(String xpointer) throws XNIException { 127 128 // 129 init(); 130 131 // tokens 132 final Tokens tokens = new Tokens(fSymbolTable); 133 134 // scanner 135 Scanner scanner = new Scanner(fSymbolTable) { 136 protected void addToken(Tokens tokens, int token) 137 throws XNIException { 138 if (token == Tokens.XPTRTOKEN_ELEM_CHILD 139 || token == Tokens.XPTRTOKEN_ELEM_NCNAME) { 140 super.addToken(tokens, token); 141 return; 142 } 143 reportError("InvalidElementSchemeToken", new Object[] { tokens 144 .getTokenString(token) }); 145 } 146 }; 147 148 // scan the element() XPointer expression 149 int length = xpointer.length(); 150 boolean success = scanner.scanExpr(fSymbolTable, tokens, xpointer, 0, 151 length); 152 153 if (!success) { 154 reportError("InvalidElementSchemeXPointer", 155 new Object[] { xpointer }); 156 } 157 158 // Initialize a temp arrays to the size of token count which should 159 // be atleast twice the size of child sequence, to hold the ChildSequence. 160 int tmpChildSequence[] = new int[tokens.getTokenCount() / 2 + 1]; 161 162 // the element depth 163 int i = 0; 164 165 // Traverse the scanned tokens 166 while (tokens.hasMore()) { 167 int token = tokens.nextToken(); 168 169 switch (token) { 170 case Tokens.XPTRTOKEN_ELEM_NCNAME: { 171 // Note: Only a single ShortHand pointer can be present 172 173 // The shortHand name 174 token = tokens.nextToken(); 175 fShortHandPointerName = tokens.getTokenString(token); 176 177 // Create a new ShortHandPointer 178 fShortHandPointer = new ShortHandPointer(fSymbolTable); 179 fShortHandPointer.setSchemeName(fShortHandPointerName); 180 181 break; 182 } 183 case Tokens.XPTRTOKEN_ELEM_CHILD: { 184 tmpChildSequence[i] = tokens.nextToken(); 185 i++; 186 187 break; 188 } 189 default: 190 reportError("InvalidElementSchemeXPointer", 191 new Object[] { xpointer }); 192 } 193 } 194 195 // Initialize the arrays to the number of elements in the ChildSequence. 196 fChildSequence = new int[i]; 197 fCurrentChildSequence = new int[i]; 198 System.arraycopy(tmpChildSequence, 0, fChildSequence, 0, i); 199 200 } 201 202 /** 203 * Returns the scheme name i.e element 204 * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeName() 205 */ 206 public String getSchemeName() { 207 return fSchemeName; 208 } 209 210 /** 211 * Returns the scheme data 212 * 213 * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeData() 214 */ 215 public String getSchemeData() { 216 return fSchemeData; 217 } 218 219 /** 220 * Sets the scheme name 221 * 222 * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeName(java.lang.String) 223 */ 224 public void setSchemeName(String schemeName) { 225 fSchemeName = schemeName; 226 227 } 228 229 /** 230 * Sets the scheme data 231 * 232 * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeData(java.lang.String) 233 */ 234 public void setSchemeData(String schemeData) { 235 fSchemeData = schemeData; 236 } 237 238 /** 239 * Responsible for resolving the element() scheme XPointer. If a ShortHand 240 * Pointer is present and it is successfully resolved and if a child 241 * sequence is present, the child sequence is resolved relative to it. 242 * 243 * @see com.sun.org.apache.xerces.internal.xpointer.XPointerProcessor#resolveXPointer(com.sun.org.apache.xerces.internal.xni.QName, com.sun.org.apache.xerces.internal.xni.XMLAttributes, com.sun.org.apache.xerces.internal.xni.Augmentations, int event) 244 */ 245 public boolean resolveXPointer(QName element, XMLAttributes attributes, 246 Augmentations augs, int event) throws XNIException { 247 248 boolean isShortHandPointerResolved = false; 249 250 // if a ChildSequence exisits, resolve child elements 251 252 // if an element name exists 253 if (fShortHandPointerName != null) { 254 // resolve ShortHand Pointer 255 isShortHandPointerResolved = fShortHandPointer.resolveXPointer( 256 element, attributes, augs, event); 257 if (isShortHandPointerResolved) { 258 fIsResolveElement = true; 259 fIsShortHand = true; 260 } else { 261 fIsResolveElement = false; 262 } 263 } else { 264 fIsResolveElement = true; 265 } 266 267 // Added here to skip the ShortHand pointer corresponding to 268 // an element if one exisits and start searching from its child 269 if (fChildSequence.length > 0) { 270 fIsFragmentResolved = matchChildSequence(element, event); 271 } else if (isShortHandPointerResolved && fChildSequence.length <= 0) { 272 // if only a resolved shorthand pointer exists 273 fIsFragmentResolved = isShortHandPointerResolved; 274 } else { 275 fIsFragmentResolved = false; 276 } 277 278 return fIsFragmentResolved; 279 } 280 281 /** 282 * Matches the current element position in the document tree with the 283 * element position specified in the element XPointer scheme. 284 * 285 * @param event 286 * @return boolean - true if the current element position in the document 287 * tree matches theelement position specified in the element XPointer 288 * scheme. 289 */ 290 protected boolean matchChildSequence(QName element, int event) 291 throws XNIException { 292 293 // need to resize fCurrentChildSequence 294 if (fCurrentChildDepth >= fCurrentChildSequence.length) { 295 int tmpCurrentChildSequence[] = new int[fCurrentChildSequence.length]; 296 System.arraycopy(fCurrentChildSequence, 0, tmpCurrentChildSequence, 297 0, fCurrentChildSequence.length); 298 299 // Increase the size by a factor of 2 (?) 300 fCurrentChildSequence = new int[fCurrentChildDepth * 2]; 301 System.arraycopy(tmpCurrentChildSequence, 0, fCurrentChildSequence, 302 0, tmpCurrentChildSequence.length); 303 } 304 305 // 306 if (fIsResolveElement) { 307 // start 308 fWasOnlyEmptyElementFound = false; 309 if (event == XPointerPart.EVENT_ELEMENT_START) { 310 fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition; 311 fCurrentChildDepth++; 312 313 // reset the current child position 314 fCurrentChildPosition = 1; 315 316 //if (!fSchemeNameFound) { 317 if ((fCurrentChildDepth <= fFoundDepth) || (fFoundDepth == 0)) { 318 if (checkMatch()) { 319 fIsElementFound = true; 320 fFoundDepth = fCurrentChildDepth; 321 } else { 322 fIsElementFound = false; 323 fFoundDepth = 0; 324 } 325 } 326 327 } else if (event == XPointerPart.EVENT_ELEMENT_END) { 328 if (fCurrentChildDepth == fFoundDepth) { 329 fIsElementFound = true; 330 } else if (((fCurrentChildDepth < fFoundDepth) && (fFoundDepth != 0)) 331 || ((fCurrentChildDepth > fFoundDepth) // or empty element found 332 && (fFoundDepth == 0))) { 333 fIsElementFound = false; 334 } 335 336 // reset array position of last child 337 fCurrentChildSequence[fCurrentChildDepth] = 0; 338 339 fCurrentChildDepth--; 340 fCurrentChildPosition = fCurrentChildSequence[fCurrentChildDepth] + 1; 341 342 } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) { 343 344 fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition; 345 fCurrentChildPosition++; 346 347 // Donot check for empty elements if the empty element is 348 // a child of a found parent element 349 if (checkMatch()) { 350 if (!fIsElementFound) { 351 fWasOnlyEmptyElementFound = true; 352 } else { 353 fWasOnlyEmptyElementFound = false; 354 } 355 fIsElementFound = true; 356 } else { 357 fIsElementFound = false; 358 fWasOnlyEmptyElementFound = false; 359 } 360 } 361 } 362 363 return fIsElementFound; 364 } 365 366 /** 367 * Matches the current position of the element being visited by checking 368 * its position and previous elements against the element XPointer expression. 369 * If a match is found it return true else false. 370 * 371 * @return boolean 372 */ 373 protected boolean checkMatch() { 374 // If the number of elements in the ChildSequence is greater than the 375 // current child depth, there is not point in checking further 376 if (!fIsShortHand) { 377 // If a shorthand pointer is not present traverse the children 378 // and compare 379 if (fChildSequence.length <= fCurrentChildDepth + 1) { 380 381 for (int i = 0; i < fChildSequence.length; i++) { 382 if (fChildSequence[i] != fCurrentChildSequence[i]) { 383 return false; 384 } 385 } 386 } else { 387 return false; 388 } 389 } else { 390 // If a shorthand pointer is present traverse the children 391 // ignoring the first element of the CurrenChildSequence which 392 // contains the ShortHand pointer element and compare 393 if (fChildSequence.length <= fCurrentChildDepth + 1) { 394 395 for (int i = 0; i < fChildSequence.length; i++) { 396 // ensure fCurrentChildSequence is large enough 397 if (fCurrentChildSequence.length < i + 2) { 398 return false; 399 } 400 401 // ignore the first element of fCurrentChildSequence 402 if (fChildSequence[i] != fCurrentChildSequence[i + 1]) { 403 return false; 404 } 405 } 406 } else { 407 return false; 408 } 409 410 } 411 412 return true; 413 } 414 415 /** 416 * Returns true if the node matches or is a child of a matching element() 417 * scheme XPointer. 418 * 419 * @see com.sun.org.apache.xerces.internal.xpointer.XPointerProcessor#isFragmentResolved() 420 */ 421 public boolean isFragmentResolved() throws XNIException { 422 // Return true if the Fragment was resolved and the current Node depth 423 // is greater than or equal to the depth at which the element was found 424 return fIsFragmentResolved ; 425 } 426 427 /** 428 * Returns true if the XPointer expression resolves to a non-element child 429 * of the current resource fragment. 430 * 431 * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#isChildFragmentResolved() 432 * 433 */ 434 public boolean isChildFragmentResolved() { 435 // if only a shorthand pointer was present 436 if (fIsShortHand && fShortHandPointer != null && fChildSequence.length <= 0) { 437 return fShortHandPointer.isChildFragmentResolved(); 438 } else { 439 return fWasOnlyEmptyElementFound ? !fWasOnlyEmptyElementFound 440 : (fIsFragmentResolved && (fCurrentChildDepth >= fFoundDepth)); 441 } 442 } 443 444 /** 445 * Reports an XPointer error 446 */ 447 protected void reportError(String key, Object[] arguments) 448 throws XNIException { 449 /*fErrorReporter.reportError(XPointerMessageFormatter.XPOINTER_DOMAIN, 450 key, arguments, XMLErrorReporter.SEVERITY_ERROR); 451 */ 452 throw new XNIException((fErrorReporter 453 .getMessageFormatter(XPointerMessageFormatter.XPOINTER_DOMAIN)) 454 .formatMessage(fErrorReporter.getLocale(), key, arguments)); 455 } 456 457 /** 458 * Initializes error handling objects 459 */ 460 protected void initErrorReporter() { 461 if (fErrorReporter == null) { 462 fErrorReporter = new XMLErrorReporter(); 463 } 464 if (fErrorHandler == null) { 465 fErrorHandler = new XPointerErrorHandler(); 466 } 467 fErrorReporter.putMessageFormatter( 468 XPointerMessageFormatter.XPOINTER_DOMAIN, 469 new XPointerMessageFormatter()); 470 } 471 472 /** 473 * Initializes the element scheme processor 474 */ 475 protected void init() { 476 fSchemeName = null; 477 fSchemeData = null; 478 fShortHandPointerName = null; 479 fIsResolveElement = false; 480 fIsElementFound = false; 481 fWasOnlyEmptyElementFound = false; 482 fFoundDepth = 0; 483 fCurrentChildPosition = 1; 484 fCurrentChildDepth = 0; 485 fIsFragmentResolved = false; 486 fShortHandPointer = null; 487 488 initErrorReporter(); 489 } 490 491 // ************************************************************************ 492 // element() Scheme expression scanner 493 // ************************************************************************ 494 495 /** 496 * List of XPointer Framework tokens. 497 * 498 * @xerces.internal 499 * 500 * @author Neil Delima, IBM 501 * @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $ 502 * 503 */ 504 private final class Tokens { 505 506 /** 507 * XPointer element() scheme 508 * [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence 509 * [2] ChildSequence ::= ('/' [1-9] [0-9]*)+ 510 */ 511 private static final int XPTRTOKEN_ELEM_NCNAME = 0; 512 513 private static final int XPTRTOKEN_ELEM_CHILD = 1; 514 515 // Token names 516 private final String[] fgTokenNames = { "XPTRTOKEN_ELEM_NCNAME", 517 "XPTRTOKEN_ELEM_CHILD" }; 518 519 // Token count 520 private static final int INITIAL_TOKEN_COUNT = 1 << 8; 521 522 private int[] fTokens = new int[INITIAL_TOKEN_COUNT]; 523 524 private int fTokenCount = 0; 525 526 // Current token position 527 private int fCurrentTokenIndex; 528 529 private SymbolTable fSymbolTable; 530 531 private HashMap<Integer, String> fTokenNames = new HashMap<>(); 532 533 /** 534 * Constructor 535 * 536 * @param symbolTable SymbolTable 537 */ 538 private Tokens(SymbolTable symbolTable) { 539 fSymbolTable = symbolTable; 540 541 fTokenNames.put(new Integer(XPTRTOKEN_ELEM_NCNAME), 542 "XPTRTOKEN_ELEM_NCNAME"); 543 fTokenNames.put(new Integer(XPTRTOKEN_ELEM_CHILD), 544 "XPTRTOKEN_ELEM_CHILD"); 545 } 546 547 /* 548 * Returns the token String 549 * @param token The index of the token 550 * @return String The token string 551 */ 552 private String getTokenString(int token) { 553 return fTokenNames.get(new Integer(token)); 554 } 555 556 /** 557 * Add the specified string as a token 558 * 559 * @param token The token string 560 */ 561 private void addToken(String tokenStr) { 562 String str = fTokenNames.get(tokenStr); 563 Integer tokenInt = str == null ? null : Integer.parseInt(str); 564 if (tokenInt == null) { 565 tokenInt = new Integer(fTokenNames.size()); 566 fTokenNames.put(tokenInt, tokenStr); 567 } 568 addToken(tokenInt.intValue()); 569 } 570 571 /** 572 * Add the specified int token 573 * 574 * @param token The int specifying the token 575 */ 576 private void addToken(int token) { 577 try { 578 fTokens[fTokenCount] = token; 579 } catch (ArrayIndexOutOfBoundsException ex) { 580 int[] oldList = fTokens; 581 fTokens = new int[fTokenCount << 1]; 582 System.arraycopy(oldList, 0, fTokens, 0, fTokenCount); 583 fTokens[fTokenCount] = token; 584 } 585 fTokenCount++; 586 } 587 588 /** 589 * Resets the current position to the head of the token list. 590 */ 591 private void rewind() { 592 fCurrentTokenIndex = 0; 593 } 594 595 /** 596 * Returns true if the {@link #getNextToken()} method 597 * returns a valid token. 598 */ 599 private boolean hasMore() { 600 return fCurrentTokenIndex < fTokenCount; 601 } 602 603 /** 604 * Obtains the token at the current position, then advance 605 * the current position by one. 606 * 607 * If there's no such next token, this method throws 608 * <tt>new XNIException("InvalidXPointerExpression");</tt>. 609 */ 610 private int nextToken() throws XNIException { 611 if (fCurrentTokenIndex == fTokenCount) 612 reportError("XPointerElementSchemeProcessingError", null); 613 return fTokens[fCurrentTokenIndex++]; 614 } 615 616 /** 617 * Obtains the token at the current position, without advancing 618 * the current position. 619 * 620 * If there's no such next token, this method throws 621 * <tt>new XNIException("InvalidXPointerExpression");</tt>. 622 */ 623 private int peekToken() throws XNIException { 624 if (fCurrentTokenIndex == fTokenCount) 625 reportError("XPointerElementSchemeProcessingError", null); 626 return fTokens[fCurrentTokenIndex]; 627 } 628 629 /** 630 * Obtains the token at the current position as a String. 631 * 632 * If there's no current token or if the current token 633 * is not a string token, this method throws 634 * If there's no such next token, this method throws 635 * <tt>new XNIException("InvalidXPointerExpression");</tt>. 636 */ 637 private String nextTokenAsString() throws XNIException { 638 String s = getTokenString(nextToken()); 639 if (s == null) 640 reportError("XPointerElementSchemeProcessingError", null); 641 return s; 642 } 643 644 /** 645 * Returns the number of tokens. 646 * 647 */ 648 private int getTokenCount() { 649 return fTokenCount; 650 } 651 } 652 653 /** 654 * 655 * The XPointer expression scanner. Scans the XPointer framework expression. 656 * 657 * @xerces.internal 658 * 659 * @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $ 660 */ 661 private class Scanner { 662 663 /** 664 * 7-bit ASCII subset 665 * 666 * 0 1 2 3 4 5 6 7 8 9 A B C D E F 667 * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0 668 * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 669 * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2 670 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3 671 * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4 672 * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5 673 * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6 674 * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7 675 */ 676 private static final byte CHARTYPE_INVALID = 0, // invalid XML characters, control characters and 7F 677 CHARTYPE_OTHER = 1, // A valid XML character (possibly invalid NCNameChar) that does not fall in one of the other categories 678 CHARTYPE_MINUS = 2, // '-' (0x2D) 679 CHARTYPE_PERIOD = 3, // '.' (0x2E) 680 CHARTYPE_SLASH = 4, // '/' (0x2F) 681 CHARTYPE_DIGIT = 5, // '0'-'9' (0x30 to 0x39) 682 CHARTYPE_LETTER = 6, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A) 683 CHARTYPE_UNDERSCORE = 7, // '_' (0x5F) 684 CHARTYPE_NONASCII = 8; // Non-ASCII Unicode codepoint (>= 0x80) 685 686 private final byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 687 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 688 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 5, 5, 5, 5, 5, 689 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 690 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 691 7, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 692 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1 }; 693 694 /** 695 * Symbol literals 696 */ 697 698 // 699 // Data 700 // 701 /** Symbol table. */ 702 private SymbolTable fSymbolTable; 703 704 // 705 // Constructors 706 // 707 708 /** 709 * Constructs an XPath expression scanner. 710 * 711 * @param symbolTable SymbolTable 712 */ 713 private Scanner(SymbolTable symbolTable) { 714 // save pool and tokens 715 fSymbolTable = symbolTable; 716 717 } // <init>(SymbolTable) 718 719 /** 720 * Scans the XPointer Expression 721 * 722 */ 723 private boolean scanExpr(SymbolTable symbolTable, Tokens tokens, 724 String data, int currentOffset, int endOffset) 725 throws XNIException { 726 727 int ch; 728 int nameOffset; 729 String nameHandle = null; 730 731 while (true) { 732 if (currentOffset == endOffset) { 733 break; 734 } 735 736 ch = data.charAt(currentOffset); 737 byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII 738 : fASCIICharMap[ch]; 739 740 // 741 // [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence 742 // [2] ChildSequence ::= ('/' [1-9] [0-9]*)+ 743 // 744 745 switch (chartype) { 746 747 case CHARTYPE_SLASH: 748 // if last character is '/', break and report an error 749 if (++currentOffset == endOffset) { 750 return false; 751 } 752 753 addToken(tokens, Tokens.XPTRTOKEN_ELEM_CHILD); 754 ch = data.charAt(currentOffset); 755 756 // ChildSequence ::= ('/' [1-9] [0-9]*)+ 757 int child = 0; 758 while (ch >= '0' && ch <= '9') { 759 child = (child * 10) + (ch - '0'); 760 if (++currentOffset == endOffset) { 761 break; 762 } 763 ch = data.charAt(currentOffset); 764 } 765 766 // An invalid child sequence character 767 if (child == 0) { 768 reportError("InvalidChildSequenceCharacter", 769 new Object[] { new Character((char) ch) }); 770 return false; 771 } 772 773 tokens.addToken(child); 774 775 break; 776 777 case CHARTYPE_DIGIT: 778 case CHARTYPE_LETTER: 779 case CHARTYPE_MINUS: 780 case CHARTYPE_NONASCII: 781 case CHARTYPE_OTHER: 782 case CHARTYPE_PERIOD: 783 case CHARTYPE_UNDERSCORE: 784 // Scan the ShortHand Pointer NCName 785 nameOffset = currentOffset; 786 currentOffset = scanNCName(data, endOffset, currentOffset); 787 788 if (currentOffset == nameOffset) { 789 //return false; 790 reportError("InvalidNCNameInElementSchemeData", 791 new Object[] { data }); 792 return false; 793 } 794 795 if (currentOffset < endOffset) { 796 ch = data.charAt(currentOffset); 797 } else { 798 ch = -1; 799 } 800 801 nameHandle = symbolTable.addSymbol(data.substring( 802 nameOffset, currentOffset)); 803 addToken(tokens, Tokens.XPTRTOKEN_ELEM_NCNAME); 804 tokens.addToken(nameHandle); 805 806 break; 807 } 808 } 809 return true; 810 } 811 812 /** 813 * Scans a NCName. 814 * From Namespaces in XML 815 * [5] NCName ::= (Letter | '_') (NCNameChar)* 816 * [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender 817 * 818 * @param data A String containing the XPointer expression 819 * @param endOffset The int XPointer expression length 820 * @param currentOffset An int representing the current position of the XPointer expression pointer 821 */ 822 private int scanNCName(String data, int endOffset, int currentOffset) { 823 int ch = data.charAt(currentOffset); 824 if (ch >= 0x80) { 825 if (!XMLChar.isNameStart(ch)) { 826 return currentOffset; 827 } 828 } else { 829 byte chartype = fASCIICharMap[ch]; 830 if (chartype != CHARTYPE_LETTER 831 && chartype != CHARTYPE_UNDERSCORE) { 832 return currentOffset; 833 } 834 } 835 while (++currentOffset < endOffset) { 836 ch = data.charAt(currentOffset); 837 if (ch >= 0x80) { 838 if (!XMLChar.isName(ch)) { 839 break; 840 } 841 } else { 842 byte chartype = fASCIICharMap[ch]; 843 if (chartype != CHARTYPE_LETTER 844 && chartype != CHARTYPE_DIGIT 845 && chartype != CHARTYPE_PERIOD 846 && chartype != CHARTYPE_MINUS 847 && chartype != CHARTYPE_UNDERSCORE) { 848 break; 849 } 850 } 851 } 852 return currentOffset; 853 } 854 855 // 856 // Protected methods 857 // 858 859 /** 860 * This method adds the specified token to the token list. By 861 * default, this method allows all tokens. However, subclasses 862 * of the XPathExprScanner can override this method in order 863 * to disallow certain tokens from being used in the scanned 864 * XPath expression. This is a convenient way of allowing only 865 * a subset of XPath. 866 */ 867 protected void addToken(Tokens tokens, int token) throws XNIException { 868 tokens.addToken(token); 869 } // addToken(int) 870 871 } // class Scanner 872 873 }