|
|
|
|
|
*/ |
|
|
|
/* |
|
* 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 com.sun.xml.internal.stream.dtd; |
|
import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar; |
|
import com.sun.xml.internal.stream.dtd.nonvalidating.XMLAttributeDecl; |
|
import com.sun.xml.internal.stream.dtd.nonvalidating.XMLElementDecl; |
|
import com.sun.xml.internal.stream.dtd.nonvalidating.XMLSimpleType; |
|
import com.sun.org.apache.xerces.internal.impl.Constants; |
|
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.util.XMLSymbols; |
|
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.NamespaceContext; |
|
import com.sun.org.apache.xerces.internal.xni.XMLAttributes; |
|
import com.sun.org.apache.xerces.internal.xni.XMLString; |
|
import com.sun.org.apache.xerces.internal.xni.XNIException; |
|
import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; |
|
import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; |
|
import javax.xml.XMLConstants; |
|
|
|
/* |
|
* @author Eric Ye, IBM |
|
* @author Andy Clark, IBM |
|
* @author Jeffrey Rodriguez IBM |
|
* @author Neil Graham, IBM |
|
* @author Sunitha Reddy, Sun Microsystems |
|
*/ |
|
|
|
public class DTDGrammarUtil { |
|
|
|
|
|
|
|
protected static final String SYMBOL_TABLE = |
|
Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; |
|
|
|
protected static final String NAMESPACES = |
|
Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; |
|
|
|
|
|
|
|
private static final boolean DEBUG_ATTRIBUTES = false; |
|
|
|
|
|
private static final boolean DEBUG_ELEMENT_CHILDREN = false; |
|
|
|
protected DTDGrammar fDTDGrammar = null; |
|
|
|
protected boolean fNamespaces; |
|
|
|
|
|
protected SymbolTable fSymbolTable = null; |
|
|
|
|
|
private int fCurrentElementIndex = -1; |
|
|
|
|
|
private int fCurrentContentSpecType = -1; |
|
|
|
|
|
private boolean[] fElementContentState = new boolean[8]; |
|
|
|
|
|
private int fElementDepth = -1; |
|
|
|
|
|
private boolean fInElementContent = false; |
|
|
|
|
|
private XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl(); |
|
|
|
|
|
private QName fTempQName = new QName(); |
|
|
|
|
|
private StringBuilder fBuffer = new StringBuilder(); |
|
|
|
private NamespaceContext fNamespaceContext = null; |
|
|
|
|
|
public DTDGrammarUtil(SymbolTable symbolTable) { |
|
fSymbolTable = symbolTable; |
|
} |
|
|
|
public DTDGrammarUtil(DTDGrammar grammar, SymbolTable symbolTable) { |
|
fDTDGrammar = grammar; |
|
fSymbolTable = symbolTable; |
|
} |
|
|
|
public DTDGrammarUtil(DTDGrammar grammar, SymbolTable symbolTable, |
|
NamespaceContext namespaceContext) { |
|
fDTDGrammar = grammar; |
|
fSymbolTable = symbolTable; |
|
fNamespaceContext = namespaceContext; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void reset(XMLComponentManager componentManager) |
|
throws XMLConfigurationException { |
|
|
|
fDTDGrammar = null; |
|
fInElementContent = false; |
|
fCurrentElementIndex = -1; |
|
fCurrentContentSpecType = -1; |
|
fNamespaces = componentManager.getFeature(NAMESPACES, true); |
|
fSymbolTable = (SymbolTable) componentManager.getProperty( |
|
Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY); |
|
fElementDepth = -1; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void startElement(QName element, XMLAttributes attributes) throws XNIException { |
|
handleStartElement(element, attributes); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void endElement(QName element) throws XNIException { |
|
handleEndElement(element); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void startCDATA(Augmentations augs) throws XNIException { |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void endCDATA(Augmentations augs) throws XNIException { |
|
} |
|
|
|
|
|
|
|
|
|
public void addDTDDefaultAttrs(QName elementName, XMLAttributes attributes) |
|
throws XNIException { |
|
|
|
int elementIndex; |
|
elementIndex = fDTDGrammar.getElementDeclIndex(elementName); |
|
|
|
if (elementIndex == -1 || fDTDGrammar == null) { |
|
return; |
|
} |
|
|
|
// |
|
// Check after all specified attrs are scanned |
|
// (1) report error for REQUIRED attrs that are missing (V_TAGc) |
|
// (2) add default attrs (FIXED and NOT_FIXED) |
|
|
|
int attlistIndex = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); |
|
|
|
while (attlistIndex != -1) { |
|
|
|
fDTDGrammar.getAttributeDecl(attlistIndex, fTempAttDecl); |
|
|
|
if (DEBUG_ATTRIBUTES) { |
|
if (fTempAttDecl != null) { |
|
XMLElementDecl elementDecl = new XMLElementDecl(); |
|
fDTDGrammar.getElementDecl(elementIndex, elementDecl); |
|
System.out.println("element: " + (elementDecl.name.localpart)); |
|
System.out.println("attlistIndex " + attlistIndex + "\n" + |
|
"attName : '" + (fTempAttDecl.name.localpart) + "'\n" |
|
+ "attType : " + fTempAttDecl.simpleType.type + "\n" |
|
+ "attDefaultType : " + fTempAttDecl.simpleType.defaultType + "\n" |
|
+ "attDefaultValue : '" + fTempAttDecl.simpleType.defaultValue + "'\n" |
|
+ attributes.getLength() + "\n" |
|
); |
|
} |
|
} |
|
String attPrefix = fTempAttDecl.name.prefix; |
|
String attLocalpart = fTempAttDecl.name.localpart; |
|
String attRawName = fTempAttDecl.name.rawname; |
|
String attType = getAttributeTypeName(fTempAttDecl); |
|
int attDefaultType = fTempAttDecl.simpleType.defaultType; |
|
String attValue = null; |
|
|
|
if (fTempAttDecl.simpleType.defaultValue != null) { |
|
attValue = fTempAttDecl.simpleType.defaultValue; |
|
} |
|
boolean specified = false; |
|
boolean required = attDefaultType == XMLSimpleType.DEFAULT_TYPE_REQUIRED; |
|
boolean cdata = attType == XMLSymbols.fCDATASymbol; |
|
|
|
if (!cdata || required || attValue != null) { |
|
|
|
|
|
if (fNamespaceContext != null && attRawName.startsWith(XMLConstants.XMLNS_ATTRIBUTE)) { |
|
String prefix = ""; |
|
int pos = attRawName.indexOf(':'); |
|
if (pos != -1) { |
|
prefix = attRawName.substring(0, pos); |
|
} else { |
|
prefix = attRawName; |
|
} |
|
prefix = fSymbolTable.addSymbol(prefix); |
|
if (!((com.sun.org.apache.xerces.internal.util. |
|
NamespaceSupport) fNamespaceContext). |
|
containsPrefixInCurrentContext(prefix)) { |
|
fNamespaceContext.declarePrefix(prefix, attValue); |
|
} |
|
specified = true; |
|
} else { |
|
|
|
int attrCount = attributes.getLength(); |
|
for (int i = 0; i < attrCount; i++) { |
|
if (attributes.getQName(i) == attRawName) { |
|
specified = true; |
|
break; |
|
} |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (!specified) { |
|
if (attValue != null) { |
|
if (fNamespaces) { |
|
int index = attRawName.indexOf(':'); |
|
if (index != -1) { |
|
attPrefix = attRawName.substring(0, index); |
|
attPrefix = fSymbolTable.addSymbol(attPrefix); |
|
attLocalpart = attRawName.substring(index + 1); |
|
attLocalpart = fSymbolTable.addSymbol(attLocalpart); |
|
} |
|
} |
|
fTempQName.setValues(attPrefix, attLocalpart, attRawName, |
|
fTempAttDecl.name.uri); |
|
int newAttr = attributes.addAttribute(fTempQName, attType, |
|
attValue); |
|
} |
|
} |
|
attlistIndex = fDTDGrammar.getNextAttributeDeclIndex(attlistIndex); |
|
} |
|
|
|
// now iterate through the expanded attributes for |
|
// 1. if every attribute seen is declared in the DTD |
|
// 2. check if the VC: default_fixed holds |
|
|
|
int attrCount = attributes.getLength(); |
|
for (int i = 0; i < attrCount; i++) { |
|
String attrRawName = attributes.getQName(i); |
|
boolean declared = false; |
|
int position = |
|
fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); |
|
while (position != -1) { |
|
fDTDGrammar.getAttributeDecl(position, fTempAttDecl); |
|
if (fTempAttDecl.name.rawname == attrRawName) { |
|
|
|
declared = true; |
|
break; |
|
} |
|
position = fDTDGrammar.getNextAttributeDeclIndex(position); |
|
} |
|
if (!declared) { |
|
continue; |
|
} |
|
|
|
String type = getAttributeTypeName(fTempAttDecl); |
|
attributes.setType(i, type); |
|
|
|
boolean changedByNormalization = false; |
|
if (attributes.isSpecified(i) && type != XMLSymbols.fCDATASymbol) { |
|
changedByNormalization = normalizeAttrValue(attributes, i); |
|
} |
|
} // for all attributes |
|
|
|
} // addDTDDefaultAttrsAndValidate(int,XMLAttrList) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private boolean normalizeAttrValue(XMLAttributes attributes, int index) { |
|
|
|
boolean leadingSpace = true; |
|
boolean spaceStart = false; |
|
boolean readingNonSpace = false; |
|
int count = 0; |
|
int eaten = 0; |
|
String attrValue = attributes.getValue(index); |
|
char[] attValue = new char[attrValue.length()]; |
|
|
|
fBuffer.setLength(0); |
|
attrValue.getChars(0, attrValue.length(), attValue, 0); |
|
for (int i = 0; i < attValue.length; i++) { |
|
|
|
if (attValue[i] == ' ') { |
|
|
|
|
|
if (readingNonSpace) { |
|
spaceStart = true; |
|
readingNonSpace = false; |
|
} |
|
|
|
if (spaceStart && !leadingSpace) { |
|
spaceStart = false; |
|
fBuffer.append(attValue[i]); |
|
count++; |
|
} else { |
|
if (leadingSpace || !spaceStart) { |
|
eaten++; |
|
} |
|
} |
|
|
|
} else { |
|
readingNonSpace = true; |
|
spaceStart = false; |
|
leadingSpace = false; |
|
fBuffer.append(attValue[i]); |
|
count++; |
|
} |
|
} |
|
|
|
|
|
if (count > 0 && fBuffer.charAt(count - 1) == ' ') { |
|
fBuffer.setLength(count - 1); |
|
|
|
} |
|
String newValue = fBuffer.toString(); |
|
attributes.setValue(index, newValue); |
|
return !attrValue.equals(newValue); |
|
} |
|
|
|
|
|
|
|
|
|
private String getAttributeTypeName(XMLAttributeDecl attrDecl) { |
|
|
|
switch (attrDecl.simpleType.type) { |
|
case XMLSimpleType.TYPE_ENTITY: { |
|
return attrDecl.simpleType.list ? XMLSymbols.fENTITIESSymbol : |
|
XMLSymbols.fENTITYSymbol; |
|
} |
|
case XMLSimpleType.TYPE_ENUMERATION: { |
|
StringBuilder buffer = new StringBuilder(); |
|
buffer.append('('); |
|
for (int i = 0; i < attrDecl.simpleType.enumeration.length; i++) { |
|
if (i > 0) { |
|
buffer.append("|"); |
|
} |
|
buffer.append(attrDecl.simpleType.enumeration[i]); |
|
} |
|
buffer.append(')'); |
|
return fSymbolTable.addSymbol(buffer.toString()); |
|
} |
|
case XMLSimpleType.TYPE_ID: { |
|
return XMLSymbols.fIDSymbol; |
|
} |
|
case XMLSimpleType.TYPE_IDREF: { |
|
return attrDecl.simpleType.list ? XMLSymbols.fIDREFSSymbol : |
|
XMLSymbols.fIDREFSymbol; |
|
} |
|
case XMLSimpleType.TYPE_NMTOKEN: { |
|
return attrDecl.simpleType.list ? XMLSymbols.fNMTOKENSSymbol : |
|
XMLSymbols.fNMTOKENSymbol; |
|
} |
|
case XMLSimpleType.TYPE_NOTATION: { |
|
return XMLSymbols.fNOTATIONSymbol; |
|
} |
|
} |
|
return XMLSymbols.fCDATASymbol; |
|
|
|
} |
|
|
|
|
|
|
|
private void ensureStackCapacity(int newElementDepth) { |
|
if (newElementDepth == fElementContentState.length) { |
|
boolean[] newStack = new boolean[newElementDepth * 2]; |
|
System.arraycopy(this.fElementContentState, 0, newStack, 0, |
|
newElementDepth); |
|
fElementContentState = newStack; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void handleStartElement(QName element, XMLAttributes attributes) throws XNIException { |
|
|
|
if (fDTDGrammar == null) { |
|
fCurrentElementIndex = -1; |
|
fCurrentContentSpecType = -1; |
|
fInElementContent = false; |
|
return; |
|
} else { |
|
fCurrentElementIndex = fDTDGrammar.getElementDeclIndex(element); |
|
fCurrentContentSpecType = fDTDGrammar.getContentSpecType( |
|
fCurrentElementIndex); |
|
|
|
addDTDDefaultAttrs(element, attributes); |
|
} |
|
|
|
fInElementContent = fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN; |
|
fElementDepth++; |
|
ensureStackCapacity(fElementDepth); |
|
fElementContentState[fElementDepth] = fInElementContent; |
|
} |
|
|
|
|
|
|
|
protected void handleEndElement(QName element) throws XNIException { |
|
if (fDTDGrammar == null) return; |
|
fElementDepth--; |
|
if (fElementDepth < -1) { |
|
throw new RuntimeException("FWK008 Element stack underflow"); |
|
} |
|
if (fElementDepth < 0) { |
|
fCurrentElementIndex = -1; |
|
fCurrentContentSpecType = -1; |
|
fInElementContent = false; |
|
return; |
|
} |
|
fInElementContent = fElementContentState[fElementDepth]; |
|
} |
|
|
|
public boolean isInElementContent() { |
|
return fInElementContent; |
|
} |
|
|
|
public boolean isIgnorableWhiteSpace(XMLString text) { |
|
if (isInElementContent()) { |
|
for (int i = text.offset; i < text.offset + text.length; i++) { |
|
if (!XMLChar.isSpace(text.ch[i])) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
return false; |
|
} |
|
} |