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 if (!fTokenNames.containsValue(tokenStr)) { 563 Integer tokenInt = new Integer(fTokenNames.size()); 564 fTokenNames.put(tokenInt, tokenStr); 565 addToken(tokenInt.intValue()); 566 } 567 } 568 569 /** 570 * Add the specified int token 571 * 572 * @param token The int specifying the token 573 */ 574 private void addToken(int token) { 575 try { 576 fTokens[fTokenCount] = token; 577 } catch (ArrayIndexOutOfBoundsException ex) { 578 int[] oldList = fTokens; 579 fTokens = new int[fTokenCount << 1]; 580 System.arraycopy(oldList, 0, fTokens, 0, fTokenCount); 581 fTokens[fTokenCount] = token; 582 } 583 fTokenCount++; 584 } 585 586 /** 587 * Resets the current position to the head of the token list. 588 */ 589 private void rewind() { 590 fCurrentTokenIndex = 0; 591 } 592 593 /** 594 * Returns true if the {@link #getNextToken()} method 595 * returns a valid token. 596 */ 597 private boolean hasMore() { 598 return fCurrentTokenIndex < fTokenCount; 599 } 600 601 /** 602 * Obtains the token at the current position, then advance 603 * the current position by one. 604 * 605 * If there's no such next token, this method throws 606 * <tt>new XNIException("InvalidXPointerExpression");</tt>. 607 */ 608 private int nextToken() throws XNIException { 609 if (fCurrentTokenIndex == fTokenCount) 610 reportError("XPointerElementSchemeProcessingError", null); 611 return fTokens[fCurrentTokenIndex++]; 612 } 613 614 /** 615 * Obtains the token at the current position, without advancing 616 * the current position. 617 * 618 * If there's no such next token, this method throws 619 * <tt>new XNIException("InvalidXPointerExpression");</tt>. 620 */ 621 private int peekToken() throws XNIException { 622 if (fCurrentTokenIndex == fTokenCount) 623 reportError("XPointerElementSchemeProcessingError", null); 624 return fTokens[fCurrentTokenIndex]; 625 } 626 627 /** 628 * Obtains the token at the current position as a String. 629 * 630 * If there's no current token or if the current token 631 * is not a string token, this method throws 632 * If there's no such next token, this method throws 633 * <tt>new XNIException("InvalidXPointerExpression");</tt>. 634 */ 635 private String nextTokenAsString() throws XNIException { 636 String s = getTokenString(nextToken()); 637 if (s == null) 638 reportError("XPointerElementSchemeProcessingError", null); 639 return s; 640 } 641 642 /** 643 * Returns the number of tokens. 644 * 645 */ 646 private int getTokenCount() { 647 return fTokenCount; 648 } 649 } 650 651 /** 652 * 653 * The XPointer expression scanner. Scans the XPointer framework expression. 654 * 655 * @xerces.internal 656 * 657 * @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $ 658 */ 659 private class Scanner { 660 661 /** 662 * 7-bit ASCII subset 663 * 664 * 0 1 2 3 4 5 6 7 8 9 A B C D E F 665 * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0 666 * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 667 * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2 668 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3 669 * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4 670 * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5 671 * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6 672 * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7 673 */ 674 private static final byte CHARTYPE_INVALID = 0, // invalid XML characters, control characters and 7F 675 CHARTYPE_OTHER = 1, // A valid XML character (possibly invalid NCNameChar) that does not fall in one of the other categories 676 CHARTYPE_MINUS = 2, // '-' (0x2D) 677 CHARTYPE_PERIOD = 3, // '.' (0x2E) 678 CHARTYPE_SLASH = 4, // '/' (0x2F) 679 CHARTYPE_DIGIT = 5, // '0'-'9' (0x30 to 0x39) 680 CHARTYPE_LETTER = 6, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A) 681 CHARTYPE_UNDERSCORE = 7, // '_' (0x5F) 682 CHARTYPE_NONASCII = 8; // Non-ASCII Unicode codepoint (>= 0x80) 683 684 private final byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 685 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 686 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 5, 5, 5, 5, 5, 687 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 688 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 689 7, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 690 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1 }; 691 692 /** 693 * Symbol literals 694 */ 695 696 // 697 // Data 698 // 699 /** Symbol table. */ 700 private SymbolTable fSymbolTable; 701 702 // 703 // Constructors 704 // 705 706 /** 707 * Constructs an XPath expression scanner. 708 * 709 * @param symbolTable SymbolTable 710 */ 711 private Scanner(SymbolTable symbolTable) { 712 // save pool and tokens 713 fSymbolTable = symbolTable; 714 715 } // <init>(SymbolTable) 716 717 /** 718 * Scans the XPointer Expression 719 * 720 */ 721 private boolean scanExpr(SymbolTable symbolTable, Tokens tokens, 722 String data, int currentOffset, int endOffset) 723 throws XNIException { 724 725 int ch; 726 int nameOffset; 727 String nameHandle = null; 728 729 while (true) { 730 if (currentOffset == endOffset) { 731 break; 732 } 733 734 ch = data.charAt(currentOffset); 735 byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII 736 : fASCIICharMap[ch]; 737 738 // 739 // [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence 740 // [2] ChildSequence ::= ('/' [1-9] [0-9]*)+ 741 // 742 743 switch (chartype) { 744 745 case CHARTYPE_SLASH: 746 // if last character is '/', break and report an error 747 if (++currentOffset == endOffset) { 748 return false; 749 } 750 751 addToken(tokens, Tokens.XPTRTOKEN_ELEM_CHILD); 752 ch = data.charAt(currentOffset); 753 754 // ChildSequence ::= ('/' [1-9] [0-9]*)+ 755 int child = 0; 756 while (ch >= '0' && ch <= '9') { 757 child = (child * 10) + (ch - '0'); 758 if (++currentOffset == endOffset) { 759 break; 760 } 761 ch = data.charAt(currentOffset); 762 } 763 764 // An invalid child sequence character 765 if (child == 0) { 766 reportError("InvalidChildSequenceCharacter", 767 new Object[] { new Character((char) ch) }); 768 return false; 769 } 770 771 tokens.addToken(child); 772 773 break; 774 775 case CHARTYPE_DIGIT: 776 case CHARTYPE_LETTER: 777 case CHARTYPE_MINUS: 778 case CHARTYPE_NONASCII: 779 case CHARTYPE_OTHER: 780 case CHARTYPE_PERIOD: 781 case CHARTYPE_UNDERSCORE: 782 // Scan the ShortHand Pointer NCName 783 nameOffset = currentOffset; 784 currentOffset = scanNCName(data, endOffset, currentOffset); 785 786 if (currentOffset == nameOffset) { 787 //return false; 788 reportError("InvalidNCNameInElementSchemeData", 789 new Object[] { data }); 790 return false; 791 } 792 793 if (currentOffset < endOffset) { 794 ch = data.charAt(currentOffset); 795 } else { 796 ch = -1; 797 } 798 799 nameHandle = symbolTable.addSymbol(data.substring( 800 nameOffset, currentOffset)); 801 addToken(tokens, Tokens.XPTRTOKEN_ELEM_NCNAME); 802 tokens.addToken(nameHandle); 803 804 break; 805 } 806 } 807 return true; 808 } 809 810 /** 811 * Scans a NCName. 812 * From Namespaces in XML 813 * [5] NCName ::= (Letter | '_') (NCNameChar)* 814 * [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender 815 * 816 * @param data A String containing the XPointer expression 817 * @param endOffset The int XPointer expression length 818 * @param currentOffset An int representing the current position of the XPointer expression pointer 819 */ 820 private int scanNCName(String data, int endOffset, int currentOffset) { 821 int ch = data.charAt(currentOffset); 822 if (ch >= 0x80) { 823 if (!XMLChar.isNameStart(ch)) { 824 return currentOffset; 825 } 826 } else { 827 byte chartype = fASCIICharMap[ch]; 828 if (chartype != CHARTYPE_LETTER 829 && chartype != CHARTYPE_UNDERSCORE) { 830 return currentOffset; 831 } 832 } 833 while (++currentOffset < endOffset) { 834 ch = data.charAt(currentOffset); 835 if (ch >= 0x80) { 836 if (!XMLChar.isName(ch)) { 837 break; 838 } 839 } else { 840 byte chartype = fASCIICharMap[ch]; 841 if (chartype != CHARTYPE_LETTER 842 && chartype != CHARTYPE_DIGIT 843 && chartype != CHARTYPE_PERIOD 844 && chartype != CHARTYPE_MINUS 845 && chartype != CHARTYPE_UNDERSCORE) { 846 break; 847 } 848 } 849 } 850 return currentOffset; 851 } 852 853 // 854 // Protected methods 855 // 856 857 /** 858 * This method adds the specified token to the token list. By 859 * default, this method allows all tokens. However, subclasses 860 * of the XPathExprScanner can override this method in order 861 * to disallow certain tokens from being used in the scanned 862 * XPath expression. This is a convenient way of allowing only 863 * a subset of XPath. 864 */ 865 protected void addToken(Tokens tokens, int token) throws XNIException { 866 tokens.addToken(token); 867 } // addToken(int) 868 869 } // class Scanner 870 871 }