package com.sun.xml.internal.stream.buffer.sax;
import com.sun.xml.internal.stream.buffer.AbstractProcessor;
import com.sun.xml.internal.stream.buffer.AttributesHolder;
import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.LocatorImpl;
import javax.xml.XMLConstants;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class SAXBufferProcessor extends AbstractProcessor implements XMLReader {
protected EntityResolver _entityResolver = DEFAULT_LEXICAL_HANDLER;
protected DTDHandler _dtdHandler = DEFAULT_LEXICAL_HANDLER;
protected ContentHandler _contentHandler = DEFAULT_LEXICAL_HANDLER;
protected ErrorHandler _errorHandler = DEFAULT_LEXICAL_HANDLER;
protected LexicalHandler _lexicalHandler = DEFAULT_LEXICAL_HANDLER;
protected boolean _namespacePrefixesFeature = false;
protected AttributesHolder _attributes = new AttributesHolder();
protected String[] _namespacePrefixes = new String[16];
protected int _namespacePrefixesIndex;
protected int[] _namespaceAttributesStartingStack = new int[16];
protected int[] _namespaceAttributesStack = new int[16];
protected int _namespaceAttributesStackIndex;
public SAXBufferProcessor() {
}
public SAXBufferProcessor(XMLStreamBuffer buffer) {
setXMLStreamBuffer(buffer);
}
public SAXBufferProcessor(XMLStreamBuffer buffer, boolean produceFragmentEvent) {
setXMLStreamBuffer(buffer,produceFragmentEvent);
}
public boolean getFeature(String name)
throws SAXNotRecognizedException, SAXNotSupportedException {
if (name.equals(Features.NAMESPACES_FEATURE)) {
return true;
} else if (name.equals(Features.NAMESPACE_PREFIXES_FEATURE)) {
return _namespacePrefixesFeature;
} else if (name.equals(Features.EXTERNAL_GENERAL_ENTITIES)) {
return true;
} else if (name.equals(Features.EXTERNAL_PARAMETER_ENTITIES)) {
return true;
} else if (name.equals(Features.STRING_INTERNING_FEATURE)) {
return _stringInterningFeature;
} else {
throw new SAXNotRecognizedException(
"Feature not supported: " + name);
}
}
public void setFeature(String name, boolean value)
throws SAXNotRecognizedException, SAXNotSupportedException {
if (name.equals(Features.NAMESPACES_FEATURE)) {
if (!value) {
throw new SAXNotSupportedException(name + ":" + value);
}
} else if (name.equals(Features.NAMESPACE_PREFIXES_FEATURE)) {
_namespacePrefixesFeature = value;
} else if (name.equals(Features.EXTERNAL_GENERAL_ENTITIES)) {
} else if (name.equals(Features.EXTERNAL_PARAMETER_ENTITIES)) {
} else if (name.equals(Features.STRING_INTERNING_FEATURE)) {
if (value != _stringInterningFeature) {
throw new SAXNotSupportedException(name + ":" + value);
}
} else {
throw new SAXNotRecognizedException(
"Feature not supported: " + name);
}
}
public Object getProperty(String name)
throws SAXNotRecognizedException, SAXNotSupportedException {
if (name.equals(Properties.LEXICAL_HANDLER_PROPERTY)) {
return getLexicalHandler();
} else {
throw new SAXNotRecognizedException("Property not recognized: " + name);
}
}
public void setProperty(String name, Object value)
throws SAXNotRecognizedException, SAXNotSupportedException {
if (name.equals(Properties.LEXICAL_HANDLER_PROPERTY)) {
if (value instanceof LexicalHandler) {
setLexicalHandler((LexicalHandler)value);
} else {
throw new SAXNotSupportedException(Properties.LEXICAL_HANDLER_PROPERTY);
}
} else {
throw new SAXNotRecognizedException("Property not recognized: " + name);
}
}
public void setEntityResolver(EntityResolver resolver) {
_entityResolver = resolver;
}
public EntityResolver getEntityResolver() {
return _entityResolver;
}
public void setDTDHandler(DTDHandler handler) {
_dtdHandler = handler;
}
public DTDHandler getDTDHandler() {
return _dtdHandler;
}
public void setContentHandler(ContentHandler handler) {
_contentHandler = handler;
}
public ContentHandler getContentHandler() {
return _contentHandler;
}
public void setErrorHandler(ErrorHandler handler) {
_errorHandler = handler;
}
public ErrorHandler getErrorHandler() {
return _errorHandler;
}
public void setLexicalHandler(LexicalHandler handler) {
_lexicalHandler = handler;
}
public LexicalHandler getLexicalHandler() {
return _lexicalHandler;
}
public void parse(InputSource input) throws IOException, SAXException {
process();
}
public void parse(String systemId) throws IOException, SAXException {
process();
}
public final void process(XMLStreamBuffer buffer) throws SAXException {
setXMLStreamBuffer(buffer);
process();
}
public final void process(XMLStreamBuffer buffer, boolean produceFragmentEvent) throws SAXException {
setXMLStreamBuffer(buffer);
process();
}
public void setXMLStreamBuffer(XMLStreamBuffer buffer) {
setBuffer(buffer);
}
public void setXMLStreamBuffer(XMLStreamBuffer buffer, boolean produceFragmentEvent) {
if(!produceFragmentEvent && _treeCount>1)
throw new IllegalStateException("Can't write a forest to a full XML infoset");
setBuffer(buffer,produceFragmentEvent);
}
public final void process() throws SAXException {
if(!_fragmentMode) {
LocatorImpl nullLocator = new LocatorImpl();
nullLocator.setSystemId(_buffer.getSystemId());
nullLocator.setLineNumber(-1);
nullLocator.setColumnNumber(-1);
_contentHandler.setDocumentLocator(nullLocator);
_contentHandler.startDocument();
}
while (_treeCount>0) {
final int item = readEiiState();
switch(item) {
case STATE_DOCUMENT:
processDocument();
_treeCount--;
break;
case STATE_END:
return;
case STATE_ELEMENT_U_LN_QN:
processElement(readStructureString(), readStructureString(), readStructureString(), isInscope());
_treeCount--;
break;
case STATE_ELEMENT_P_U_LN:
{
final String prefix = readStructureString();
final String uri = readStructureString();
final String localName = readStructureString();
processElement(uri, localName, getQName(prefix, localName),isInscope());
_treeCount--;
break;
}
case STATE_ELEMENT_U_LN: {
final String uri = readStructureString();
final String localName = readStructureString();
processElement(uri, localName, localName,isInscope());
_treeCount--;
break;
}
case STATE_ELEMENT_LN:
{
final String localName = readStructureString();
processElement("", localName, localName,isInscope());
_treeCount--;
break;
}
case STATE_COMMENT_AS_CHAR_ARRAY_SMALL:
processCommentAsCharArraySmall();
break;
case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM:
processCommentAsCharArrayMedium();
break;
case STATE_COMMENT_AS_CHAR_ARRAY_COPY:
processCommentAsCharArrayCopy();
break;
case STATE_COMMENT_AS_STRING:
processComment(readContentString());
break;
case STATE_PROCESSING_INSTRUCTION:
processProcessingInstruction(readStructureString(), readStructureString());
break;
default:
throw reportFatalError("Illegal state for DIIs: "+item);
}
}
if(!_fragmentMode)
_contentHandler.endDocument();
}
private void () throws SAXException {
final int length = readStructure();
final int start = readContentCharactersBuffer(length);
processComment(_contentCharactersBuffer, start, length);
}
private SAXParseException reportFatalError(String msg) throws SAXException {
SAXParseException spe = new SAXParseException(msg, null);
if(_errorHandler!=null)
_errorHandler.fatalError(spe);
return spe;
}
private boolean isInscope() {
return _buffer.getInscopeNamespaces().size() > 0;
}
private void processDocument() throws SAXException {
while(true) {
int item = readEiiState();
switch(item) {
case STATE_ELEMENT_U_LN_QN:
processElement(readStructureString(), readStructureString(), readStructureString(),isInscope());
break;
case STATE_ELEMENT_P_U_LN:
{
final String prefix = readStructureString();
final String uri = readStructureString();
final String localName = readStructureString();
processElement(uri, localName, getQName(prefix, localName),isInscope());
break;
}
case STATE_ELEMENT_U_LN: {
final String uri = readStructureString();
final String localName = readStructureString();
processElement(uri, localName, localName,isInscope());
break;
}
case STATE_ELEMENT_LN:
{
final String localName = readStructureString();
processElement("", localName, localName,isInscope());
break;
}
case STATE_COMMENT_AS_CHAR_ARRAY_SMALL:
processCommentAsCharArraySmall();
break;
case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM:
processCommentAsCharArrayMedium();
break;
case STATE_COMMENT_AS_CHAR_ARRAY_COPY:
processCommentAsCharArrayCopy();
break;
case STATE_COMMENT_AS_STRING:
processComment(readContentString());
break;
case STATE_PROCESSING_INSTRUCTION:
processProcessingInstruction(readStructureString(), readStructureString());
break;
case STATE_END:
return;
default:
throw reportFatalError("Illegal state for child of DII: "+item);
}
}
}
protected void processElement(String uri, String localName, String qName, boolean inscope) throws SAXException {
boolean hasAttributes = false;
boolean hasNamespaceAttributes = false;
int item = peekStructure();
Set<String> prefixSet = inscope ? new HashSet<String>() : Collections.<String>emptySet();
if ((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE) {
cacheNamespacePrefixStartingIndex();
hasNamespaceAttributes = true;
item = processNamespaceAttributes(item, inscope, prefixSet);
}
if (inscope) {
readInscopeNamespaces(prefixSet);
}
if ((item & TYPE_MASK) == T_ATTRIBUTE) {
hasAttributes = true;
processAttributes(item);
}
_contentHandler.startElement(uri, localName, qName, _attributes);
if (hasAttributes) {
_attributes.clear();
}
do {
item = readEiiState();
switch(item) {
case STATE_ELEMENT_U_LN_QN:
processElement(readStructureString(), readStructureString(), readStructureString(), false);
break;
case STATE_ELEMENT_P_U_LN:
{
final String p = readStructureString();
final String u = readStructureString();
final String ln = readStructureString();
processElement(u, ln, getQName(p, ln),false);
break;
}
case STATE_ELEMENT_U_LN: {
final String u = readStructureString();
final String ln = readStructureString();
processElement(u, ln, ln,false);
break;
}
case STATE_ELEMENT_LN: {
final String ln = readStructureString();
processElement("", ln, ln,false);
break;
}
case STATE_TEXT_AS_CHAR_ARRAY_SMALL:
{
final int length = readStructure();
int start = readContentCharactersBuffer(length);
_contentHandler.characters(_contentCharactersBuffer, start, length);
break;
}
case STATE_TEXT_AS_CHAR_ARRAY_MEDIUM:
{
final int length = readStructure16();
int start = readContentCharactersBuffer(length);
_contentHandler.characters(_contentCharactersBuffer, start, length);
break;
}
case STATE_TEXT_AS_CHAR_ARRAY_COPY:
{
final char[] ch = readContentCharactersCopy();
_contentHandler.characters(ch, 0, ch.length);
break;
}
case STATE_TEXT_AS_STRING:
{
final String s = readContentString();
_contentHandler.characters(s.toCharArray(), 0, s.length());
break;
}
case STATE_TEXT_AS_OBJECT:
{
final CharSequence c = (CharSequence)readContentObject();
final String s = c.toString();
_contentHandler.characters(s.toCharArray(), 0, s.length());
break;
}
case STATE_COMMENT_AS_CHAR_ARRAY_SMALL:
processCommentAsCharArraySmall();
break;
case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM:
processCommentAsCharArrayMedium();
break;
case STATE_COMMENT_AS_CHAR_ARRAY_COPY:
processCommentAsCharArrayCopy();
break;
case T_COMMENT_AS_STRING:
processComment(readContentString());
break;
case STATE_PROCESSING_INSTRUCTION:
processProcessingInstruction(readStructureString(), readStructureString());
break;
case STATE_END:
break;
default:
throw reportFatalError("Illegal state for child of EII: "+item);
}
} while(item != STATE_END);
_contentHandler.endElement(uri, localName, qName);
if (hasNamespaceAttributes) {
processEndPrefixMapping();
}
}
private void readInscopeNamespaces(Set<String> prefixSet) throws SAXException {
for (Map.Entry<String, String> e : _buffer.getInscopeNamespaces().entrySet()) {
String key = fixNull(e.getKey());
if (!prefixSet.contains(key)) {
processNamespaceAttribute(key,e.getValue());
}
}
}
private static String fixNull(String s) {
if (s == null) return "";
else return s;
}
private void () throws SAXException {
final char[] ch = readContentCharactersCopy();
processComment(ch, 0, ch.length);
}
private void () throws SAXException {
final int length = readStructure16();
final int start = readContentCharactersBuffer(length);
processComment(_contentCharactersBuffer, start, length);
}
private void processEndPrefixMapping() throws SAXException {
final int end = _namespaceAttributesStack[--_namespaceAttributesStackIndex];
final int start = (_namespaceAttributesStackIndex >= 0) ? _namespaceAttributesStartingStack[_namespaceAttributesStackIndex] : 0;
for (int i = end - 1; i >= start; i--) {
_contentHandler.endPrefixMapping(_namespacePrefixes[i]);
}
_namespacePrefixesIndex = start;
}
private int processNamespaceAttributes(int item,boolean collectPrefixes, Set<String> prefixSet) throws SAXException {
do {
String prefix;
switch(getNIIState(item)) {
case STATE_NAMESPACE_ATTRIBUTE:
processNamespaceAttribute("", "");
if(collectPrefixes) {
prefixSet.add("");
}
break;
case STATE_NAMESPACE_ATTRIBUTE_P:
prefix = readStructureString();
processNamespaceAttribute(prefix, "");
if(collectPrefixes) {
prefixSet.add(prefix);
}
break;
case STATE_NAMESPACE_ATTRIBUTE_P_U:
prefix = readStructureString();
processNamespaceAttribute(prefix, readStructureString());
if(collectPrefixes) {
prefixSet.add(prefix);
}
break;
case STATE_NAMESPACE_ATTRIBUTE_U:
processNamespaceAttribute("", readStructureString());
if(collectPrefixes) {
prefixSet.add("");
}
break;
default:
throw reportFatalError("Illegal state: "+item);
}
readStructure();
item = peekStructure();
} while((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE);
cacheNamespacePrefixIndex();
return item;
}
private void processAttributes(int item) throws SAXException {
do {
switch(getAIIState(item)) {
case STATE_ATTRIBUTE_U_LN_QN:
_attributes.addAttributeWithQName(readStructureString(), readStructureString(), readStructureString(), readStructureString(), readContentString());
break;
case STATE_ATTRIBUTE_P_U_LN:
{
final String p = readStructureString();
final String u = readStructureString();
final String ln = readStructureString();
_attributes.addAttributeWithQName(u, ln, getQName(p, ln), readStructureString(), readContentString());
break;
}
case STATE_ATTRIBUTE_U_LN: {
final String u = readStructureString();
final String ln = readStructureString();
_attributes.addAttributeWithQName(u, ln, ln, readStructureString(), readContentString());
break;
}
case STATE_ATTRIBUTE_LN: {
final String ln = readStructureString();
_attributes.addAttributeWithQName("", ln, ln, readStructureString(), readContentString());
break;
}
default:
throw reportFatalError("Illegal state: "+item);
}
readStructure();
item = peekStructure();
} while((item & TYPE_MASK) == T_ATTRIBUTE);
}
private void processNamespaceAttribute(String prefix, String uri) throws SAXException {
_contentHandler.startPrefixMapping(prefix, uri);
if (_namespacePrefixesFeature) {
if (prefix != "") {
_attributes.addAttributeWithQName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, prefix,
getQName(XMLConstants.XMLNS_ATTRIBUTE, prefix),
"CDATA", uri);
} else {
_attributes.addAttributeWithQName(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE,
XMLConstants.XMLNS_ATTRIBUTE,
"CDATA", uri);
}
}
cacheNamespacePrefix(prefix);
}
private void cacheNamespacePrefix(String prefix) {
if (_namespacePrefixesIndex == _namespacePrefixes.length) {
final String[] namespaceAttributes = new String[_namespacePrefixesIndex * 3 / 2 + 1];
System.arraycopy(_namespacePrefixes, 0, namespaceAttributes, 0, _namespacePrefixesIndex);
_namespacePrefixes = namespaceAttributes;
}
_namespacePrefixes[_namespacePrefixesIndex++] = prefix;
}
private void cacheNamespacePrefixIndex() {
if (_namespaceAttributesStackIndex == _namespaceAttributesStack.length) {
final int[] namespaceAttributesStack = new int[_namespaceAttributesStackIndex * 3 /2 + 1];
System.arraycopy(_namespaceAttributesStack, 0, namespaceAttributesStack, 0, _namespaceAttributesStackIndex);
_namespaceAttributesStack = namespaceAttributesStack;
}
_namespaceAttributesStack[_namespaceAttributesStackIndex++] = _namespacePrefixesIndex;
}
private void cacheNamespacePrefixStartingIndex() {
if (_namespaceAttributesStackIndex == _namespaceAttributesStartingStack.length) {
final int[] namespaceAttributesStart = new int[_namespaceAttributesStackIndex * 3 /2 + 1];
System.arraycopy(_namespaceAttributesStartingStack, 0, namespaceAttributesStart, 0, _namespaceAttributesStackIndex);
_namespaceAttributesStartingStack = namespaceAttributesStart;
}
_namespaceAttributesStartingStack[_namespaceAttributesStackIndex] = _namespacePrefixesIndex;
}
private void (String s) throws SAXException {
processComment(s.toCharArray(), 0, s.length());
}
private void (char[] ch, int start, int length) throws SAXException {
_lexicalHandler.comment(ch, start, length);
}
private void processProcessingInstruction(String target, String data) throws SAXException {
_contentHandler.processingInstruction(target, data);
}
private static final DefaultWithLexicalHandler DEFAULT_LEXICAL_HANDLER = new DefaultWithLexicalHandler();
}