You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
880 lines
30 KiB
880 lines
30 KiB
/*
|
|
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*/
|
|
/*
|
|
* Copyright 2005 The Apache Software Foundation.
|
|
*
|
|
* Licensed 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 com.sun.org.apache.xerces.internal.xpointer;
|
|
|
|
import java.util.Hashtable;
|
|
|
|
import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
|
|
import com.sun.org.apache.xerces.internal.util.SymbolTable;
|
|
import com.sun.org.apache.xerces.internal.util.XMLChar;
|
|
import com.sun.org.apache.xerces.internal.xni.Augmentations;
|
|
import com.sun.org.apache.xerces.internal.xni.QName;
|
|
import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
|
|
import com.sun.org.apache.xerces.internal.xni.XNIException;
|
|
import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
|
|
|
|
/**
|
|
* <p>
|
|
* Implements the XPointerPart interface for element() scheme specific processing.
|
|
* </p>
|
|
*
|
|
* @xerces.internal
|
|
*
|
|
* @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $
|
|
*
|
|
*/
|
|
class ElementSchemePointer implements XPointerPart {
|
|
|
|
// Fields
|
|
|
|
// 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;
|
|
|
|
// If a shorthand pointer is present and resolved
|
|
boolean fIsShortHand = false;
|
|
|
|
// The depth at which the element was found
|
|
int fFoundDepth = 0;
|
|
|
|
// 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;
|
|
|
|
// The XPointer Error reporter
|
|
protected XMLErrorReporter fErrorReporter;
|
|
|
|
// The XPointer Error Handler
|
|
protected XMLErrorHandler fErrorHandler;
|
|
|
|
//
|
|
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 com.sun.org.apache.xerces.internal.xpointer.XPointerProcessor#parseXPointer(java.lang.String)
|
|
*/
|
|
public void parseXPointer(String xpointer) throws XNIException {
|
|
|
|
//
|
|
init();
|
|
|
|
// tokens
|
|
final Tokens tokens = new Tokens(fSymbolTable);
|
|
|
|
// scanner
|
|
Scanner scanner = new Scanner(fSymbolTable) {
|
|
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 com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeName()
|
|
*/
|
|
public String getSchemeName() {
|
|
return fSchemeName;
|
|
}
|
|
|
|
/**
|
|
* Returns the scheme data
|
|
*
|
|
* @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeData()
|
|
*/
|
|
public String getSchemeData() {
|
|
return fSchemeData;
|
|
}
|
|
|
|
/**
|
|
* Sets the scheme name
|
|
*
|
|
* @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeName(java.lang.String)
|
|
*/
|
|
public void setSchemeName(String schemeName) {
|
|
fSchemeName = schemeName;
|
|
|
|
}
|
|
|
|
/**
|
|
* Sets the scheme data
|
|
*
|
|
* @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeData(java.lang.String)
|
|
*/
|
|
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 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)
|
|
*/
|
|
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
|
|
fWasOnlyEmptyElementFound = false;
|
|
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 (!fIsElementFound) {
|
|
if (checkMatch()) {
|
|
fIsElementFound = true;
|
|
fWasOnlyEmptyElementFound = true;
|
|
} else {
|
|
fIsElementFound = 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 com.sun.org.apache.xerces.internal.xpointer.XPointerProcessor#isFragmentResolved()
|
|
*/
|
|
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 com.sun.org.apache.xerces.internal.xpointer.XPointerPart#isChildFragmentResolved()
|
|
*
|
|
*/
|
|
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.
|
|
*
|
|
* @xerces.internal
|
|
*
|
|
* @author Neil Delima, IBM
|
|
* @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $
|
|
*
|
|
*/
|
|
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 names
|
|
private final String[] fgTokenNames = { "XPTRTOKEN_ELEM_NCNAME",
|
|
"XPTRTOKEN_ELEM_CHILD" };
|
|
|
|
// Token count
|
|
private static final int INITIAL_TOKEN_COUNT = 1 << 8;
|
|
|
|
private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
|
|
|
|
private int fTokenCount = 0;
|
|
|
|
// Current token position
|
|
private int fCurrentTokenIndex;
|
|
|
|
private SymbolTable fSymbolTable;
|
|
|
|
private Hashtable fTokenNames = new Hashtable();
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* @xerces.internal
|
|
*
|
|
* @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $
|
|
*/
|
|
private class Scanner {
|
|
|
|
/**
|
|
* 7-bit ASCII subset
|
|
*
|
|
* 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
|
|
|
|
}
|