aoqi@0: /* aoqi@0: * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.stream.buffer.stax; aoqi@0: aoqi@0: import com.sun.xml.internal.stream.buffer.AbstractProcessor; aoqi@0: import com.sun.xml.internal.stream.buffer.XMLStreamBuffer; aoqi@0: aoqi@0: import java.io.IOException; aoqi@0: import java.util.Collections; aoqi@0: import java.util.HashSet; aoqi@0: import java.util.Map; aoqi@0: import java.util.Set; aoqi@0: aoqi@0: import com.sun.xml.internal.org.jvnet.staxex.Base64Data; aoqi@0: import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; aoqi@0: aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.stream.XMLStreamWriter; aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * A processor of a {@link XMLStreamBuffer} that writes the XML infoset to a aoqi@0: * {@link XMLStreamWriter}. aoqi@0: * aoqi@0: * @author Paul.Sandoz@Sun.Com aoqi@0: * @author K.Venugopal@sun.com aoqi@0: */ aoqi@0: public class StreamWriterBufferProcessor extends AbstractProcessor { aoqi@0: aoqi@0: aoqi@0: public StreamWriterBufferProcessor() { aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @deprecated aoqi@0: * Use {@link #StreamWriterBufferProcessor(XMLStreamBuffer, boolean)} aoqi@0: */ aoqi@0: public StreamWriterBufferProcessor(XMLStreamBuffer buffer) { aoqi@0: setXMLStreamBuffer(buffer,buffer.isFragment()); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @param produceFragmentEvent aoqi@0: * True to generate fragment SAX events without start/endDocument. aoqi@0: * False to generate a full document SAX events. aoqi@0: */ aoqi@0: public StreamWriterBufferProcessor(XMLStreamBuffer buffer,boolean produceFragmentEvent) { aoqi@0: setXMLStreamBuffer(buffer,produceFragmentEvent); aoqi@0: } aoqi@0: aoqi@0: public final void process(XMLStreamBuffer buffer, XMLStreamWriter writer) throws XMLStreamException { aoqi@0: setXMLStreamBuffer(buffer,buffer.isFragment()); aoqi@0: process(writer); aoqi@0: } aoqi@0: aoqi@0: public void process(XMLStreamWriter writer) throws XMLStreamException { aoqi@0: if(_fragmentMode){ aoqi@0: writeFragment(writer); aoqi@0: }else{ aoqi@0: write(writer); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @deprecated aoqi@0: * Use {@link #setXMLStreamBuffer(XMLStreamBuffer, boolean)} aoqi@0: */ aoqi@0: public void setXMLStreamBuffer(XMLStreamBuffer buffer) { aoqi@0: setBuffer(buffer); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @param produceFragmentEvent aoqi@0: * True to generate fragment SAX events without start/endDocument. aoqi@0: * False to generate a full document SAX events. aoqi@0: */ aoqi@0: public void setXMLStreamBuffer(XMLStreamBuffer buffer, boolean produceFragmentEvent) { aoqi@0: setBuffer(buffer,produceFragmentEvent); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Writes a full XML infoset event to the given writer, aoqi@0: * including start/end document. aoqi@0: * Any inscope namespaces present will be written as namespace aoqi@0: * delcarations on each top-level element. aoqi@0: */ aoqi@0: public void write(XMLStreamWriter writer) throws XMLStreamException{ aoqi@0: aoqi@0: if(!_fragmentMode) { aoqi@0: if(_treeCount>1) aoqi@0: throw new IllegalStateException("forest cannot be written as a full infoset"); aoqi@0: writer.writeStartDocument(); aoqi@0: } aoqi@0: aoqi@0: while(true) { aoqi@0: int item = getEIIState(peekStructure()); aoqi@0: writer.flush(); aoqi@0: aoqi@0: switch(item) { aoqi@0: case STATE_DOCUMENT: aoqi@0: readStructure(); //skip aoqi@0: break; aoqi@0: case STATE_ELEMENT_U_LN_QN: aoqi@0: case STATE_ELEMENT_P_U_LN: aoqi@0: case STATE_ELEMENT_U_LN: aoqi@0: case STATE_ELEMENT_LN: aoqi@0: writeFragment(writer); aoqi@0: break; aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_SMALL: { aoqi@0: readStructure(); aoqi@0: final int length = readStructure(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: final String comment = new String(_contentCharactersBuffer, start, length); aoqi@0: writer.writeComment(comment); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM: { aoqi@0: readStructure(); aoqi@0: final int length = readStructure16(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: final String comment = new String(_contentCharactersBuffer, start, length); aoqi@0: writer.writeComment(comment); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_COPY: { aoqi@0: readStructure(); aoqi@0: final char[] ch = readContentCharactersCopy(); aoqi@0: writer.writeComment(new String(ch)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_PROCESSING_INSTRUCTION: aoqi@0: readStructure(); aoqi@0: writer.writeProcessingInstruction(readStructureString(), readStructureString()); aoqi@0: break; aoqi@0: case STATE_END: // done aoqi@0: readStructure(); aoqi@0: writer.writeEndDocument(); aoqi@0: return; aoqi@0: default: aoqi@0: throw new XMLStreamException("Invalid State "+item); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Writes the buffer as a fragment, meaning aoqi@0: * the writer will not receive start/endDocument events. aoqi@0: * Any inscope namespaces present will be written as namespace aoqi@0: * delcarations on each top-level element. aoqi@0: *

aoqi@0: * If {@link XMLStreamBuffer} has a forest, this method will write all the forests. aoqi@0: */ aoqi@0: public void writeFragment(XMLStreamWriter writer) throws XMLStreamException { aoqi@0: if (writer instanceof XMLStreamWriterEx) { aoqi@0: writeFragmentEx((XMLStreamWriterEx)writer); aoqi@0: } else { aoqi@0: writeFragmentNoEx(writer); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void writeFragmentEx(XMLStreamWriterEx writer) throws XMLStreamException { aoqi@0: int depth = 0; // used to determine when we are done with a tree. aoqi@0: aoqi@0: int item = getEIIState(peekStructure()); aoqi@0: if(item==STATE_DOCUMENT) aoqi@0: readStructure(); // skip STATE_DOCUMENT aoqi@0: aoqi@0: do { aoqi@0: aoqi@0: item = readEiiState(); aoqi@0: aoqi@0: switch(item) { aoqi@0: case STATE_DOCUMENT: aoqi@0: throw new AssertionError(); aoqi@0: case STATE_ELEMENT_U_LN_QN: { aoqi@0: depth ++; aoqi@0: final String uri = readStructureString(); aoqi@0: final String localName = readStructureString(); aoqi@0: final String prefix = getPrefixFromQName(readStructureString()); aoqi@0: writer.writeStartElement(prefix,localName,uri); aoqi@0: writeAttributes(writer, isInscope(depth)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_ELEMENT_P_U_LN: { aoqi@0: depth ++; aoqi@0: final String prefix = readStructureString(); aoqi@0: final String uri = readStructureString(); aoqi@0: final String localName = readStructureString(); aoqi@0: writer.writeStartElement(prefix,localName,uri); aoqi@0: writeAttributes(writer, isInscope(depth)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_ELEMENT_U_LN: { aoqi@0: depth ++; aoqi@0: final String uri = readStructureString(); aoqi@0: final String localName = readStructureString(); aoqi@0: writer.writeStartElement("",localName,uri); aoqi@0: writeAttributes(writer, isInscope(depth)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_ELEMENT_LN: { aoqi@0: depth ++; aoqi@0: final String localName = readStructureString(); aoqi@0: writer.writeStartElement(localName); aoqi@0: writeAttributes(writer, isInscope(depth)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_CHAR_ARRAY_SMALL: { aoqi@0: final int length = readStructure(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: writer.writeCharacters(_contentCharactersBuffer,start,length); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_CHAR_ARRAY_MEDIUM: { aoqi@0: final int length = readStructure16(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: writer.writeCharacters(_contentCharactersBuffer,start,length); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_CHAR_ARRAY_COPY: { aoqi@0: char[] c = readContentCharactersCopy(); aoqi@0: writer.writeCharacters(c,0,c.length); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_STRING: { aoqi@0: final String s = readContentString(); aoqi@0: writer.writeCharacters(s); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_OBJECT: { aoqi@0: final CharSequence c = (CharSequence)readContentObject(); aoqi@0: writer.writePCDATA(c); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_SMALL: { aoqi@0: final int length = readStructure(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: final String comment = new String(_contentCharactersBuffer, start, length); aoqi@0: writer.writeComment(comment); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM: { aoqi@0: final int length = readStructure16(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: final String comment = new String(_contentCharactersBuffer, start, length); aoqi@0: writer.writeComment(comment); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_COPY: { aoqi@0: final char[] ch = readContentCharactersCopy(); aoqi@0: writer.writeComment(new String(ch)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_PROCESSING_INSTRUCTION: aoqi@0: writer.writeProcessingInstruction(readStructureString(), readStructureString()); aoqi@0: break; aoqi@0: case STATE_END: aoqi@0: writer.writeEndElement(); aoqi@0: depth --; aoqi@0: if(depth==0) aoqi@0: _treeCount--; aoqi@0: break; aoqi@0: default: aoqi@0: throw new XMLStreamException("Invalid State "+item); aoqi@0: } aoqi@0: } while(depth>0 || _treeCount>0); aoqi@0: aoqi@0: } aoqi@0: aoqi@0: public void writeFragmentNoEx(XMLStreamWriter writer) throws XMLStreamException { aoqi@0: int depth = 0; aoqi@0: aoqi@0: int item = getEIIState(peekStructure()); aoqi@0: if(item==STATE_DOCUMENT) aoqi@0: readStructure(); // skip STATE_DOCUMENT aoqi@0: aoqi@0: do { aoqi@0: item = readEiiState(); aoqi@0: aoqi@0: switch(item) { aoqi@0: case STATE_DOCUMENT: aoqi@0: throw new AssertionError(); aoqi@0: case STATE_ELEMENT_U_LN_QN: { aoqi@0: depth ++; aoqi@0: final String uri = readStructureString(); aoqi@0: final String localName = readStructureString(); aoqi@0: final String prefix = getPrefixFromQName(readStructureString()); aoqi@0: writer.writeStartElement(prefix,localName,uri); aoqi@0: writeAttributes(writer, isInscope(depth)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_ELEMENT_P_U_LN: { aoqi@0: depth ++; aoqi@0: final String prefix = readStructureString(); aoqi@0: final String uri = readStructureString(); aoqi@0: final String localName = readStructureString(); aoqi@0: writer.writeStartElement(prefix,localName,uri); aoqi@0: writeAttributes(writer, isInscope(depth)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_ELEMENT_U_LN: { aoqi@0: depth ++; aoqi@0: final String uri = readStructureString(); aoqi@0: final String localName = readStructureString(); aoqi@0: writer.writeStartElement("",localName,uri); aoqi@0: writeAttributes(writer, isInscope(depth)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_ELEMENT_LN: { aoqi@0: depth ++; aoqi@0: final String localName = readStructureString(); aoqi@0: writer.writeStartElement(localName); aoqi@0: writeAttributes(writer, isInscope(depth)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_CHAR_ARRAY_SMALL: { aoqi@0: final int length = readStructure(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: writer.writeCharacters(_contentCharactersBuffer,start,length); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_CHAR_ARRAY_MEDIUM: { aoqi@0: final int length = readStructure16(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: writer.writeCharacters(_contentCharactersBuffer,start,length); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_CHAR_ARRAY_COPY: { aoqi@0: char[] c = readContentCharactersCopy(); aoqi@0: writer.writeCharacters(c,0,c.length); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_STRING: { aoqi@0: final String s = readContentString(); aoqi@0: writer.writeCharacters(s); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_TEXT_AS_OBJECT: { aoqi@0: final CharSequence c = (CharSequence)readContentObject(); aoqi@0: if (c instanceof Base64Data) { aoqi@0: try { aoqi@0: Base64Data bd = (Base64Data)c; aoqi@0: bd.writeTo(writer); aoqi@0: } catch (IOException e) { aoqi@0: throw new XMLStreamException(e); aoqi@0: } aoqi@0: } else { aoqi@0: writer.writeCharacters(c.toString()); aoqi@0: } aoqi@0: break; aoqi@0: } aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_SMALL: { aoqi@0: final int length = readStructure(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: final String comment = new String(_contentCharactersBuffer, start, length); aoqi@0: writer.writeComment(comment); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM: { aoqi@0: final int length = readStructure16(); aoqi@0: final int start = readContentCharactersBuffer(length); aoqi@0: final String comment = new String(_contentCharactersBuffer, start, length); aoqi@0: writer.writeComment(comment); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_COMMENT_AS_CHAR_ARRAY_COPY: { aoqi@0: final char[] ch = readContentCharactersCopy(); aoqi@0: writer.writeComment(new String(ch)); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_PROCESSING_INSTRUCTION: aoqi@0: writer.writeProcessingInstruction(readStructureString(), readStructureString()); aoqi@0: break; aoqi@0: case STATE_END: aoqi@0: writer.writeEndElement(); aoqi@0: depth --; aoqi@0: if(depth==0) aoqi@0: _treeCount--; aoqi@0: break; aoqi@0: default: aoqi@0: throw new XMLStreamException("Invalid State "+item); aoqi@0: } aoqi@0: } while(depth > 0 || _treeCount>0); aoqi@0: aoqi@0: } aoqi@0: aoqi@0: private boolean isInscope(int depth) { aoqi@0: return _buffer.getInscopeNamespaces().size() > 0 && depth ==1; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * @param inscope: true means write inscope namespaces aoqi@0: */ aoqi@0: private void writeAttributes(XMLStreamWriter writer, boolean inscope) throws XMLStreamException { aoqi@0: // prefixSet to collect prefixes that are written before writing inscope namespaces aoqi@0: Set prefixSet = inscope ? new HashSet() : Collections.emptySet(); aoqi@0: int item = peekStructure(); aoqi@0: if ((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE) { aoqi@0: // Skip the namespace declarations on the element aoqi@0: // they will have been added already aoqi@0: item = writeNamespaceAttributes(item, writer, inscope, prefixSet); aoqi@0: } aoqi@0: if (inscope) { aoqi@0: writeInscopeNamespaces(writer, prefixSet); aoqi@0: } aoqi@0: if ((item & TYPE_MASK) == T_ATTRIBUTE) { aoqi@0: writeAttributes(item, writer); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static String fixNull(String s) { aoqi@0: if (s == null) return ""; aoqi@0: else return s; aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * @param prefixSet: already written prefixes aoqi@0: */ aoqi@0: private void writeInscopeNamespaces(XMLStreamWriter writer, Set prefixSet) throws XMLStreamException { aoqi@0: for (Map.Entry e : _buffer.getInscopeNamespaces().entrySet()) { aoqi@0: String key = fixNull(e.getKey()); aoqi@0: // If the prefix is already written, do not write the prefix aoqi@0: if (!prefixSet.contains(key)) { aoqi@0: writer.writeNamespace(key, e.getValue()); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private int writeNamespaceAttributes(int item, XMLStreamWriter writer, boolean collectPrefixes, Set prefixSet) throws XMLStreamException { aoqi@0: do { aoqi@0: switch(getNIIState(item)){ aoqi@0: case STATE_NAMESPACE_ATTRIBUTE: aoqi@0: // Undeclaration of default namespace aoqi@0: writer.writeDefaultNamespace(""); aoqi@0: if (collectPrefixes) { aoqi@0: prefixSet.add(""); aoqi@0: } aoqi@0: break; aoqi@0: case STATE_NAMESPACE_ATTRIBUTE_P: aoqi@0: // Undeclaration of namespace aoqi@0: // Declaration with prefix aoqi@0: String prefix = readStructureString(); aoqi@0: writer.writeNamespace(prefix, ""); aoqi@0: if (collectPrefixes) { aoqi@0: prefixSet.add(prefix); aoqi@0: } aoqi@0: break; aoqi@0: case STATE_NAMESPACE_ATTRIBUTE_P_U: aoqi@0: // Declaration with prefix aoqi@0: prefix = readStructureString(); aoqi@0: writer.writeNamespace(prefix, readStructureString()); aoqi@0: if (collectPrefixes) { aoqi@0: prefixSet.add(prefix); aoqi@0: } aoqi@0: break; aoqi@0: case STATE_NAMESPACE_ATTRIBUTE_U: aoqi@0: // Default declaration aoqi@0: writer.writeDefaultNamespace(readStructureString()); aoqi@0: if (collectPrefixes) { aoqi@0: prefixSet.add(""); aoqi@0: } aoqi@0: break; aoqi@0: } aoqi@0: readStructure(); aoqi@0: aoqi@0: item = peekStructure(); aoqi@0: } while((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE); aoqi@0: aoqi@0: return item; aoqi@0: } aoqi@0: aoqi@0: private void writeAttributes(int item, XMLStreamWriter writer) throws XMLStreamException { aoqi@0: do { aoqi@0: switch(getAIIState(item)) { aoqi@0: case STATE_ATTRIBUTE_U_LN_QN: { aoqi@0: final String uri = readStructureString(); aoqi@0: final String localName = readStructureString(); aoqi@0: final String prefix = getPrefixFromQName(readStructureString()); aoqi@0: writer.writeAttribute(prefix,uri,localName,readContentString()); aoqi@0: break; aoqi@0: } aoqi@0: case STATE_ATTRIBUTE_P_U_LN: aoqi@0: writer.writeAttribute(readStructureString(), readStructureString(), aoqi@0: readStructureString(), readContentString()); aoqi@0: break; aoqi@0: case STATE_ATTRIBUTE_U_LN: aoqi@0: writer.writeAttribute(readStructureString(), readStructureString(), readContentString()); aoqi@0: break; aoqi@0: case STATE_ATTRIBUTE_LN: aoqi@0: writer.writeAttribute(readStructureString(), readContentString()); aoqi@0: break; aoqi@0: } aoqi@0: // Ignore the attribute type aoqi@0: readStructureString(); aoqi@0: aoqi@0: readStructure(); aoqi@0: aoqi@0: item = peekStructure(); aoqi@0: } while((item & TYPE_MASK) == T_ATTRIBUTE); aoqi@0: } aoqi@0: }