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