content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package mf.org.apache.xerces.xpointer;
  
  import java.util.HashMap;
  
  import mf.org.apache.xerces.impl.XMLErrorReporter;
  import mf.org.apache.xerces.util.SymbolTable;
  import mf.org.apache.xerces.util.XMLChar;
  import mf.org.apache.xerces.xni.Augmentations;
  import mf.org.apache.xerces.xni.QName;
  import mf.org.apache.xerces.xni.XMLAttributes;
  import mf.org.apache.xerces.xni.XNIException;
  import mf.org.apache.xerces.xni.parser.XMLErrorHandler;
  
  
  /**
   * <p>
   * Implements the XPointerPart interface for element() scheme specific processing.
   * </p>
   *
   * @version $Id: ElementSchemePointer.java 603808 2007-12-13 03:44:48Z mrglavas $
   * @xerces.internal
   */
  final class ElementSchemePointer implements XPointerPart {
  
      // Fields
  
      // The XPointer Error reporter
      protected XMLErrorReporter fErrorReporter;
      // The XPointer Error Handler
      protected XMLErrorHandler fErrorHandler;
      // If a shorthand pointer is present and resolved
      boolean fIsShortHand = false;
      // The depth at which the element was found
      int fFoundDepth = 0;
      // The Scheme Name i.e element
      private String fSchemeName;
      // The scheme Data
      private String fSchemeData;
      // The scheme Data & child sequence
      private String fShortHandPointerName;
      // Should we attempt to resolve the ChildSequence from the
      // current element position. If a ShortHand Pointer is present
      // attempt to resolve relative to the short hand pointer.
      private boolean fIsResolveElement = false;
      // Has the element been found
      private boolean fIsElementFound = false;
      // Was only an empty element found
      private boolean fWasOnlyEmptyElementFound = false;
      // The XPointer element child sequence
      private int fChildSequence[];
      // The current child position
      private int fCurrentChildPosition = 1;
      // The current child depth
      private int fCurrentChildDepth = 0;
      // The current element's child sequence
      private int fCurrentChildSequence[];
      // Stores if the Fragment was resolved by the pointer
      private boolean fIsFragmentResolved = false;
      // Stores if the Fragment was resolved by the pointer
      private ShortHandPointer fShortHandPointer;
      //
      private SymbolTable fSymbolTable;
  
      // ************************************************************************
      // Constructors
      // ************************************************************************
      public ElementSchemePointer() {
      }
  
      public ElementSchemePointer(SymbolTable symbolTable) {
          fSymbolTable = symbolTable;
      }
  
      public ElementSchemePointer(SymbolTable symbolTable,
                                  XMLErrorReporter errorReporter) {
          fSymbolTable = symbolTable;
          fErrorReporter = errorReporter;
      }
  
      // ************************************************************************
      // XPointerPart implementation
      // ************************************************************************
  
      /**
       * Parses the XPointer expression and tokenizes it into Strings
       * delimited by whitespace.
       *
       * @see mf.org.apache.xerces.xpointer.XPointerProcessor#parseXPointer(java.lang.String)
       */
      @Override
      public void parseXPointer(String xpointer) throws XNIException {
  
          //
          init();
  
          // tokens
          final Tokens tokens = new Tokens(fSymbolTable);
  
          // scanner
          Scanner scanner = new Scanner(fSymbolTable) {
              @Override
              protected void addToken(Tokens tokens, int token)
                      throws XNIException {
                  if (token == Tokens.XPTRTOKEN_ELEM_CHILD
                          || token == Tokens.XPTRTOKEN_ELEM_NCNAME) {
                      super.addToken(tokens, token);
                      return;
                  }
                  reportError("InvalidElementSchemeToken", new Object[]{tokens
                          .getTokenString(token)});
              }
          };
  
          // scan the element() XPointer expression
          int length = xpointer.length();
          boolean success = scanner.scanExpr(fSymbolTable, tokens, xpointer, 0,
                  length);
  
          if (!success) {
              reportError("InvalidElementSchemeXPointer",
                      new Object[]{xpointer});
          }
  
          // Initialize a temp arrays to the size of token count which should 
          // be atleast twice the size of child sequence, to hold the ChildSequence.
          int tmpChildSequence[] = new int[tokens.getTokenCount() / 2 + 1];
  
          // the element depth          
          int i = 0;
  
          // Traverse the scanned tokens
          while (tokens.hasMore()) {
              int token = tokens.nextToken();
  
              switch (token) {
                  case Tokens.XPTRTOKEN_ELEM_NCNAME: {
                      // Note:  Only a single ShortHand pointer can be present
  
                      // The shortHand name
                      token = tokens.nextToken();
                      fShortHandPointerName = tokens.getTokenString(token);
  
                      // Create a new ShortHandPointer
                      fShortHandPointer = new ShortHandPointer(fSymbolTable);
                      fShortHandPointer.setSchemeName(fShortHandPointerName);
  
                      break;
                  }
                  case Tokens.XPTRTOKEN_ELEM_CHILD: {
                      tmpChildSequence[i] = tokens.nextToken();
                      i++;
  
                      break;
                  }
                  default:
                      reportError("InvalidElementSchemeXPointer",
                              new Object[]{xpointer});
              }
          }
  
          // Initialize the arrays to the number of elements in the ChildSequence.
          fChildSequence = new int[i];
          fCurrentChildSequence = new int[i];
          System.arraycopy(tmpChildSequence, 0, fChildSequence, 0, i);
  
      }
  
      /**
       * Returns the scheme name i.e element
       *
       * @see mf.org.apache.xerces.xpointer.XPointerPart#getSchemeName()
       */
      @Override
      public String getSchemeName() {
          return fSchemeName;
      }
  
      /**
       * Sets the scheme name
       *
       * @see mf.org.apache.xerces.xpointer.XPointerPart#setSchemeName(java.lang.String)
       */
      @Override
      public void setSchemeName(String schemeName) {
          fSchemeName = schemeName;
  
      }
  
      /**
       * Returns the scheme data
       *
       * @see mf.org.apache.xerces.xpointer.XPointerPart#getSchemeData()
       */
      @Override
      public String getSchemeData() {
          return fSchemeData;
      }
  
      /**
       * Sets the scheme data
       *
       * @see mf.org.apache.xerces.xpointer.XPointerPart#setSchemeData(java.lang.String)
       */
      @Override
      public void setSchemeData(String schemeData) {
          fSchemeData = schemeData;
      }
  
      /**
       * Responsible for resolving the element() scheme XPointer.  If a ShortHand
       * Pointer is present and it is successfully resolved and if a child
       * sequence is present, the child sequence is resolved relative to it.
       *
       * @see org.apache.xerces.xpointer.XPointerProcessor#resolveXPointer(org.apache.xerces.xni.QName, org.apache.xerces.xni.XMLAttributes, org.apache.xerces.xni.Augmentations, int event)
       */
      @Override
      public boolean resolveXPointer(QName element, XMLAttributes attributes,
                                     Augmentations augs, int event) throws XNIException {
  
          boolean isShortHandPointerResolved = false;
  
          // if a ChildSequence exisits, resolve child elements
  
          // if an element name exists
          if (fShortHandPointerName != null) {
              // resolve ShortHand Pointer
              isShortHandPointerResolved = fShortHandPointer.resolveXPointer(
                      element, attributes, augs, event);
              if (isShortHandPointerResolved) {
                  fIsResolveElement = true;
                  fIsShortHand = true;
              } else {
                  fIsResolveElement = false;
              }
          } else {
              fIsResolveElement = true;
          }
  
          // Added here to skip the ShortHand pointer corresponding to
          // an element if one exisits and start searching from its child
          if (fChildSequence.length > 0) {
              fIsFragmentResolved = matchChildSequence(element, event);
          } else if (isShortHandPointerResolved && fChildSequence.length <= 0) {
              // if only a resolved shorthand pointer exists
              fIsFragmentResolved = isShortHandPointerResolved;
          } else {
              fIsFragmentResolved = false;
          }
  
          return fIsFragmentResolved;
      }
  
      /**
       * Matches the current element position in the document tree with the
       * element position specified in the element XPointer scheme.
       *
       * @param event
       * @return boolean - true if the current element position in the document
       * tree matches theelement position specified in the element XPointer
       * scheme.
       */
      protected boolean matchChildSequence(QName element, int event)
              throws XNIException {
  
          // need to resize fCurrentChildSequence
          if (fCurrentChildDepth >= fCurrentChildSequence.length) {
              int tmpCurrentChildSequence[] = new int[fCurrentChildSequence.length];
              System.arraycopy(fCurrentChildSequence, 0, tmpCurrentChildSequence,
                      0, fCurrentChildSequence.length);
  
              // Increase the size by a factor of 2 (?)
              fCurrentChildSequence = new int[fCurrentChildDepth * 2];
              System.arraycopy(tmpCurrentChildSequence, 0, fCurrentChildSequence,
                      0, tmpCurrentChildSequence.length);
          }
  
          //     
          if (fIsResolveElement) {
              // start
              if (event == XPointerPart.EVENT_ELEMENT_START) {
                  fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition;
                  fCurrentChildDepth++;
  
                  // reset the current child position 
                  fCurrentChildPosition = 1;
  
                  //if (!fSchemeNameFound) {
                  if ((fCurrentChildDepth <= fFoundDepth) || (fFoundDepth == 0)) {
                      if (checkMatch()) {
                          fIsElementFound = true;
                          fFoundDepth = fCurrentChildDepth;
                      } else {
                          fIsElementFound = false;
                          fFoundDepth = 0;
                      }
                  }
  
              } else if (event == XPointerPart.EVENT_ELEMENT_END) {
                  if (fCurrentChildDepth == fFoundDepth) {
                      fIsElementFound = true;
                  } else if (((fCurrentChildDepth < fFoundDepth) && (fFoundDepth != 0))
                          || ((fCurrentChildDepth > fFoundDepth) // or empty element found
                          && (fFoundDepth == 0))) {
                      fIsElementFound = false;
                  }
  
                  // reset array position of last child
                  fCurrentChildSequence[fCurrentChildDepth] = 0;
  
                  fCurrentChildDepth--;
                  fCurrentChildPosition = fCurrentChildSequence[fCurrentChildDepth] + 1;
  
              } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) {
  
                  fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition;
                  fCurrentChildPosition++;
  
                  // Donot check for empty elements if the empty element is 
                  // a child of a found parent element 
                  if (checkMatch()) {
                      fWasOnlyEmptyElementFound = !fIsElementFound;
                      fIsElementFound = true;
                  } else {
                      fIsElementFound = false;
                      fWasOnlyEmptyElementFound = false;
                  }
              }
          }
  
          return fIsElementFound;
      }
  
      /**
       * Matches the current position of the element being visited by checking
       * its position and previous elements against the element XPointer expression.
       * If a match is found it return true else false.
       *
       * @return boolean
       */
      protected boolean checkMatch() {
          // If the number of elements in the ChildSequence is greater than the
          // current child depth, there is not point in checking further
          if (!fIsShortHand) {
              // If a shorthand pointer is not present traverse the children
              // and compare
              if (fChildSequence.length <= fCurrentChildDepth + 1) {
  
                  for (int i = 0; i < fChildSequence.length; i++) {
                      if (fChildSequence[i] != fCurrentChildSequence[i]) {
                          return false;
                      }
                  }
              } else {
                  return false;
              }
          } else {
              // If a shorthand pointer is present traverse the children
              // ignoring the first element of the CurrenChildSequence which
              // contains the ShortHand pointer element and compare            
              if (fChildSequence.length <= fCurrentChildDepth + 1) {
  
                  for (int i = 0; i < fChildSequence.length; i++) {
                      // ensure fCurrentChildSequence is large enough
                      if (fCurrentChildSequence.length < i + 2) {
                          return false;
                      }
  
                      // ignore the first element of fCurrentChildSequence
                      if (fChildSequence[i] != fCurrentChildSequence[i + 1]) {
                          return false;
                      }
                  }
              } else {
                  return false;
              }
  
          }
  
          return true;
      }
  
      /**
       * Returns true if the node matches or is a child of a matching element()
       * scheme XPointer.
       *
       * @see mf.org.apache.xerces.xpointer.XPointerProcessor#isFragmentResolved()
       */
      @Override
      public boolean isFragmentResolved() throws XNIException {
          // Return true if the Fragment was resolved and the current Node depth
          // is greater than or equal to the depth at which the element was found
          return fIsFragmentResolved;
      }
  
      /**
       * Returns true if the XPointer expression resolves to a non-element child
       * of the current resource fragment.
       *
       * @see mf.org.apache.xerces.xpointer.XPointerPart#isChildFragmentResolved()
       */
      @Override
      public boolean isChildFragmentResolved() {
          // if only a shorthand pointer was present
          if (fIsShortHand && fShortHandPointer != null && fChildSequence.length <= 0) {
              return fShortHandPointer.isChildFragmentResolved();
          } else {
              return fWasOnlyEmptyElementFound ? !fWasOnlyEmptyElementFound
                      : (fIsFragmentResolved && (fCurrentChildDepth >= fFoundDepth));
          }
      }
  
      /**
       * Reports an XPointer error
       */
      protected void reportError(String key, Object[] arguments)
              throws XNIException {
          /*fErrorReporter.reportError(XPointerMessageFormatter.XPOINTER_DOMAIN,
           key, arguments, XMLErrorReporter.SEVERITY_ERROR);
      	 */
          throw new XNIException((fErrorReporter
                  .getMessageFormatter(XPointerMessageFormatter.XPOINTER_DOMAIN))
                  .formatMessage(fErrorReporter.getLocale(), key, arguments));
      }
  
      /**
       * Initializes error handling objects
       */
      protected void initErrorReporter() {
          if (fErrorReporter == null) {
              fErrorReporter = new XMLErrorReporter();
          }
          if (fErrorHandler == null) {
              fErrorHandler = new XPointerErrorHandler();
          }
          fErrorReporter.putMessageFormatter(
                  XPointerMessageFormatter.XPOINTER_DOMAIN,
                  new XPointerMessageFormatter());
      }
  
      /**
       * Initializes the element scheme processor
       */
      protected void init() {
          fSchemeName = null;
          fSchemeData = null;
          fShortHandPointerName = null;
          fIsResolveElement = false;
          fIsElementFound = false;
          fWasOnlyEmptyElementFound = false;
          fFoundDepth = 0;
          fCurrentChildPosition = 1;
          fCurrentChildDepth = 0;
          fIsFragmentResolved = false;
          fShortHandPointer = null;
  
          initErrorReporter();
      }
  
      // ************************************************************************
      // element() Scheme expression scanner
      // ************************************************************************
  
      /**
       * List of XPointer Framework tokens.
       *
       * @author Neil Delima, IBM
       * @version $Id: ElementSchemePointer.java 603808 2007-12-13 03:44:48Z mrglavas $
       * @xerces.internal
       */
      private final class Tokens {
  
          /**
           * XPointer element() scheme
           * [1]    ElementSchemeData    ::=    (NCName ChildSequence?) | ChildSequence
           * [2]    ChildSequence    ::=    ('/' [1-9] [0-9]*)+
           */
          private static final int XPTRTOKEN_ELEM_NCNAME = 0;
  
          private static final int XPTRTOKEN_ELEM_CHILD = 1;
          // Token count
          private static final int INITIAL_TOKEN_COUNT = 1 << 8;
          // Token names
          private final String[] fgTokenNames = {"XPTRTOKEN_ELEM_NCNAME",
                  "XPTRTOKEN_ELEM_CHILD"};
          private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
  
          private int fTokenCount = 0;
  
          // Current token position
          private int fCurrentTokenIndex;
  
          private SymbolTable fSymbolTable;
  
          private HashMap fTokenNames = new HashMap();
  
          /**
           * Constructor
           *
           * @param symbolTable SymbolTable
           */
          private Tokens(SymbolTable symbolTable) {
              fSymbolTable = symbolTable;
  
              fTokenNames.put(new Integer(XPTRTOKEN_ELEM_NCNAME),
                      "XPTRTOKEN_ELEM_NCNAME");
              fTokenNames.put(new Integer(XPTRTOKEN_ELEM_CHILD),
                      "XPTRTOKEN_ELEM_CHILD");
          }
  
          /*
           * Returns the token String 
           * @param token The index of the token
           * @return String The token string
           */
          private String getTokenString(int token) {
              return (String) fTokenNames.get(new Integer(token));
          }
  
          /**
           * Returns the token String
           *
           * @param token The index of the token
           * @return String The token string
           */
          private Integer getToken(int token) {
              return (Integer) fTokenNames.get(new Integer(token));
          }
  
          /**
           * Add the specified string as a token
           *
           * @param token The token string
           */
          private void addToken(String tokenStr) {
              Integer tokenInt = (Integer) fTokenNames.get(tokenStr);
              if (tokenInt == null) {
                  tokenInt = new Integer(fTokenNames.size());
                  fTokenNames.put(tokenInt, tokenStr);
              }
              addToken(tokenInt.intValue());
          }
  
          /**
           * Add the specified int token
           *
           * @param token The int specifying the token
           */
          private void addToken(int token) {
              try {
                  fTokens[fTokenCount] = token;
              } catch (ArrayIndexOutOfBoundsException ex) {
                  int[] oldList = fTokens;
                  fTokens = new int[fTokenCount << 1];
                  System.arraycopy(oldList, 0, fTokens, 0, fTokenCount);
                  fTokens[fTokenCount] = token;
              }
              fTokenCount++;
          }
  
          /**
           * Resets the current position to the head of the token list.
           */
          private void rewind() {
              fCurrentTokenIndex = 0;
          }
  
          /**
           * Returns true if the {@link #getNextToken()} method
           * returns a valid token.
           */
          private boolean hasMore() {
              return fCurrentTokenIndex < fTokenCount;
          }
  
          /**
           * Obtains the token at the current position, then advance
           * the current position by one.
           * <p/>
           * If there's no such next token, this method throws
           * <tt>new XNIException("InvalidXPointerExpression");</tt>.
           */
          private int nextToken() throws XNIException {
              if (fCurrentTokenIndex == fTokenCount)
                  reportError("XPointerElementSchemeProcessingError", null);
              return fTokens[fCurrentTokenIndex++];
          }
  
          /**
           * Obtains the token at the current position, without advancing
           * the current position.
           * <p/>
           * If there's no such next token, this method throws
           * <tt>new XNIException("InvalidXPointerExpression");</tt>.
           */
          private int peekToken() throws XNIException {
              if (fCurrentTokenIndex == fTokenCount)
                  reportError("XPointerElementSchemeProcessingError", null);
              return fTokens[fCurrentTokenIndex];
          }
  
          /**
           * Obtains the token at the current position as a String.
           * <p/>
           * If there's no current token or if the current token
           * is not a string token, this method throws
           * If there's no such next token, this method throws
           * <tt>new XNIException("InvalidXPointerExpression");</tt>.
           */
          private String nextTokenAsString() throws XNIException {
              String s = getTokenString(nextToken());
              if (s == null)
                  reportError("XPointerElementSchemeProcessingError", null);
              return s;
          }
  
          /**
           * Returns the number of tokens.
           */
          private int getTokenCount() {
              return fTokenCount;
          }
      }
  
      /**
       * The XPointer expression scanner.  Scans the XPointer framework expression.
       *
       * @version $Id: ElementSchemePointer.java 603808 2007-12-13 03:44:48Z mrglavas $
       * @xerces.internal
       */
      private class Scanner {
  
          /**
           * 7-bit ASCII subset
           * <p/>
           * 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
           * 0,  0,  0,  0,  0,  0,  0,  0,  0, HT, LF,  0,  0, CR,  0,  0,  // 0
           * 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 1
           * SP,  !,  ",  #,  $,  %,  &,  ',  (,  ),  *,  +,  ,,  -,  .,  /,  // 2
           * 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  :,  ;,  <,  =,  >,  ?,  // 3
           *
           * @, A,  B,  C,  D,  E,  F,  G,  H,  I,  J,  K,  L,  M,  N,  O,  // 4
           * P,  Q,  R,  S,  T,  U,  V,  W,  X,  Y,  Z,  [,  \,  ],  ^,  _,  // 5
           * `,  a,  b,  c,  d,  e,  f,  g,  h,  i,  j,  k,  l,  m,  n,  o,  // 6
           * p,  q,  r,  s,  t,  u,  v,  w,  x,  y,  z,  {,  |,  },  ~, DEL  // 7
           */
          private static final byte CHARTYPE_INVALID = 0, // invalid XML characters, control characters and 7F
                  CHARTYPE_OTHER = 1, // A valid XML character (possibly invalid NCNameChar) that does not fall in one of the other categories
                  CHARTYPE_MINUS = 2, // '-' (0x2D)
                  CHARTYPE_PERIOD = 3, // '.' (0x2E)
                  CHARTYPE_SLASH = 4, // '/' (0x2F)
                  CHARTYPE_DIGIT = 5, // '0'-'9' (0x30 to 0x39)
                  CHARTYPE_LETTER = 6, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A)
                  CHARTYPE_UNDERSCORE = 7, // '_' (0x5F)
                  CHARTYPE_NONASCII = 8; // Non-ASCII Unicode codepoint (>= 0x80)
  
          private final byte[] fASCIICharMap = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
                  0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 5, 5, 5, 5, 5,
                  5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6,
                  6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1,
                  7, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
                  6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1};
  
          /**
           * Symbol literals
           */
  
          //
          // Data
          //
          /**
           * Symbol table.
           */
          private SymbolTable fSymbolTable;
  
          //
          // Constructors
          //
  
          /**
           * Constructs an XPath expression scanner.
           *
           * @param symbolTable SymbolTable
           */
          private Scanner(SymbolTable symbolTable) {
              // save pool and tokens
              fSymbolTable = symbolTable;
  
          } // <init>(SymbolTable)
  
          /**
           * Scans the XPointer Expression
           */
          private boolean scanExpr(SymbolTable symbolTable, Tokens tokens,
                                   String data, int currentOffset, int endOffset)
                  throws XNIException {
  
              int ch;
              int nameOffset;
              String nameHandle = null;
  
              while (true) {
                  if (currentOffset == endOffset) {
                      break;
                  }
  
                  ch = data.charAt(currentOffset);
                  byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII
                          : fASCIICharMap[ch];
  
                  // 
                  // [1]    ElementSchemeData    ::=    (NCName ChildSequence?) | ChildSequence  
                  // [2]    ChildSequence    ::=    ('/' [1-9] [0-9]*)+ 
                  //  
  
                  switch (chartype) {
  
                      case CHARTYPE_SLASH:
                          // if last character is '/', break and report an error
                          if (++currentOffset == endOffset) {
                              return false;
                          }
  
                          addToken(tokens, Tokens.XPTRTOKEN_ELEM_CHILD);
                          ch = data.charAt(currentOffset);
  
                          // ChildSequence    ::=    ('/' [1-9] [0-9]*)+
                          int child = 0;
                          while (ch >= '0' && ch <= '9') {
                              child = (child * 10) + (ch - '0');
                              if (++currentOffset == endOffset) {
                                  break;
                              }
                              ch = data.charAt(currentOffset);
                          }
  
                          // An invalid child sequence character
                          if (child == 0) {
                              reportError("InvalidChildSequenceCharacter",
                                      new Object[]{new Character((char) ch)});
                              return false;
                          }
  
                          tokens.addToken(child);
  
                          break;
  
                      case CHARTYPE_DIGIT:
                      case CHARTYPE_LETTER:
                      case CHARTYPE_MINUS:
                      case CHARTYPE_NONASCII:
                      case CHARTYPE_OTHER:
                      case CHARTYPE_PERIOD:
                      case CHARTYPE_UNDERSCORE:
                          // Scan the ShortHand Pointer NCName
                          nameOffset = currentOffset;
                          currentOffset = scanNCName(data, endOffset, currentOffset);
  
                          if (currentOffset == nameOffset) {
                              //return false;
                              reportError("InvalidNCNameInElementSchemeData",
                                      new Object[]{data});
                              return false;
                          }
  
                          if (currentOffset < endOffset) {
                              ch = data.charAt(currentOffset);
                          } else {
                              ch = -1;
                          }
  
                          nameHandle = symbolTable.addSymbol(data.substring(
                                  nameOffset, currentOffset));
                          addToken(tokens, Tokens.XPTRTOKEN_ELEM_NCNAME);
                          tokens.addToken(nameHandle);
  
                          break;
                  }
              }
              return true;
          }
  
          /**
           * Scans a NCName.
           * From Namespaces in XML
           * [5] NCName ::= (Letter | '_') (NCNameChar)*
           * [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
           *
           * @param data          A String containing the XPointer expression
           * @param endOffset     The int XPointer expression length
           * @param currentOffset An int representing the current position of the XPointer expression pointer
           */
          private int scanNCName(String data, int endOffset, int currentOffset) {
              int ch = data.charAt(currentOffset);
              if (ch >= 0x80) {
                  if (!XMLChar.isNameStart(ch)) {
                      return currentOffset;
                  }
              } else {
                  byte chartype = fASCIICharMap[ch];
                  if (chartype != CHARTYPE_LETTER
                          && chartype != CHARTYPE_UNDERSCORE) {
                      return currentOffset;
                  }
              }
              while (++currentOffset < endOffset) {
                  ch = data.charAt(currentOffset);
                  if (ch >= 0x80) {
                      if (!XMLChar.isName(ch)) {
                          break;
                      }
                  } else {
                      byte chartype = fASCIICharMap[ch];
                      if (chartype != CHARTYPE_LETTER
                              && chartype != CHARTYPE_DIGIT
                              && chartype != CHARTYPE_PERIOD
                              && chartype != CHARTYPE_MINUS
                              && chartype != CHARTYPE_UNDERSCORE) {
                          break;
                      }
                  }
              }
              return currentOffset;
          }
  
          //
          // Protected methods
          //
  
          /**
           * This method adds the specified token to the token list. By
           * default, this method allows all tokens. However, subclasses
           * of the XPathExprScanner can override this method in order
           * to disallow certain tokens from being used in the scanned
           * XPath expression. This is a convenient way of allowing only
           * a subset of XPath.
           */
          protected void addToken(Tokens tokens, int token) throws XNIException {
              tokens.addToken(token);
          } // addToken(int)
  
      } // class Scanner
  
  }