/* * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package com.sun.xml.internal.stream.buffer.stax; import com.sun.xml.internal.stream.buffer.AbstractProcessor; import com.sun.xml.internal.stream.buffer.XMLStreamBuffer; import com.sun.xml.internal.org.jvnet.staxex.XMLStreamWriterEx; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; /** * A processor of a {@link XMLStreamBuffer} that writes the XML infoset to a * {@link XMLStreamWriter}. * * @author Paul.Sandoz@Sun.Com * @author K.Venugopal@sun.com */ public class StreamWriterBufferProcessor extends AbstractProcessor { public StreamWriterBufferProcessor() { } /** * @deprecated * Use {@link #StreamWriterBufferProcessor(XMLStreamBuffer, boolean)} */ public StreamWriterBufferProcessor(XMLStreamBuffer buffer) { setXMLStreamBuffer(buffer,buffer.isFragment()); } /** * @param produceFragmentEvent * True to generate fragment SAX events without start/endDocument. * False to generate a full document SAX events. */ public StreamWriterBufferProcessor(XMLStreamBuffer buffer,boolean produceFragmentEvent) { setXMLStreamBuffer(buffer,produceFragmentEvent); } public final void process(XMLStreamBuffer buffer, XMLStreamWriter writer) throws XMLStreamException { setXMLStreamBuffer(buffer,buffer.isFragment()); process(writer); } public void process(XMLStreamWriter writer) throws XMLStreamException { if(_fragmentMode){ writeFragment(writer); }else{ write(writer); } } /** * @deprecated * Use {@link #setXMLStreamBuffer(XMLStreamBuffer, boolean)} */ public void setXMLStreamBuffer(XMLStreamBuffer buffer) { setBuffer(buffer); } /** * @param produceFragmentEvent * True to generate fragment SAX events without start/endDocument. * False to generate a full document SAX events. */ public void setXMLStreamBuffer(XMLStreamBuffer buffer, boolean produceFragmentEvent) { setBuffer(buffer,produceFragmentEvent); } /** * Writes a full XML infoset event to the given writer, * including start/end document. */ public void write(XMLStreamWriter writer) throws XMLStreamException{ if(!_fragmentMode) { if(_treeCount>1) throw new IllegalStateException("forest cannot be written as a full infoset"); writer.writeStartDocument(); } // TODO: if we are writing a fragment XMLStreamBuffer as a full document, // we need to put in-scope namespaces as top-level ns decls. while(true) { int item = _eiiStateTable[peekStructure()]; writer.flush(); switch(item) { case STATE_DOCUMENT: readStructure(); //skip break; case STATE_ELEMENT_U_LN_QN: case STATE_ELEMENT_P_U_LN: case STATE_ELEMENT_U_LN: case STATE_ELEMENT_LN: writeFragment(writer); break; case STATE_COMMENT_AS_CHAR_ARRAY_SMALL: { readStructure(); final int length = readStructure(); final int start = readContentCharactersBuffer(length); final String comment = new String(_contentCharactersBuffer, start, length); writer.writeComment(comment); break; } case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM: { readStructure(); final int length = readStructure16(); final int start = readContentCharactersBuffer(length); final String comment = new String(_contentCharactersBuffer, start, length); writer.writeComment(comment); break; } case STATE_COMMENT_AS_CHAR_ARRAY_COPY: { readStructure(); final char[] ch = readContentCharactersCopy(); writer.writeComment(new String(ch)); break; } case STATE_PROCESSING_INSTRUCTION: readStructure(); writer.writeProcessingInstruction(readStructureString(), readStructureString()); break; case STATE_END: // done readStructure(); writer.writeEndDocument(); return; default: throw new XMLStreamException("Invalid State "+item); } } } /** * Writes the buffer as a fragment, meaning * the writer will not receive start/endDocument events. * * <p> * If {@link XMLStreamBuffer} has a forest, this method will write all the forests. */ public void writeFragment(XMLStreamWriter writer) throws XMLStreamException { if (writer instanceof XMLStreamWriterEx) { writeFragmentEx((XMLStreamWriterEx)writer); } else { writeFragmentNoEx(writer); } } public void writeFragmentEx(XMLStreamWriterEx writer) throws XMLStreamException { int depth = 0; // used to determine when we are done with a tree. int item = _eiiStateTable[peekStructure()]; if(item==STATE_DOCUMENT) readStructure(); // skip STATE_DOCUMENT do { item = readEiiState(); switch(item) { case STATE_DOCUMENT: throw new AssertionError(); case STATE_ELEMENT_U_LN_QN: { depth ++; final String uri = readStructureString(); final String localName = readStructureString(); final String prefix = getPrefixFromQName(readStructureString()); writer.writeStartElement(prefix,localName,uri); writeAttributes(writer); break; } case STATE_ELEMENT_P_U_LN: { depth ++; final String prefix = readStructureString(); final String uri = readStructureString(); final String localName = readStructureString(); writer.writeStartElement(prefix,localName,uri); writeAttributes(writer); break; } case STATE_ELEMENT_U_LN: { depth ++; final String uri = readStructureString(); final String localName = readStructureString(); writer.writeStartElement("",localName,uri); writeAttributes(writer); break; } case STATE_ELEMENT_LN: { depth ++; final String localName = readStructureString(); writer.writeStartElement(localName); writeAttributes(writer); break; } case STATE_TEXT_AS_CHAR_ARRAY_SMALL: { final int length = readStructure(); final int start = readContentCharactersBuffer(length); writer.writeCharacters(_contentCharactersBuffer,start,length); break; } case STATE_TEXT_AS_CHAR_ARRAY_MEDIUM: { final int length = readStructure16(); final int start = readContentCharactersBuffer(length); writer.writeCharacters(_contentCharactersBuffer,start,length); break; } case STATE_TEXT_AS_CHAR_ARRAY_COPY: { char[] c = readContentCharactersCopy(); writer.writeCharacters(c,0,c.length); break; } case STATE_TEXT_AS_STRING: { final String s = readContentString(); writer.writeCharacters(s); break; } case STATE_TEXT_AS_OBJECT: { final CharSequence c = (CharSequence)readContentObject(); writer.writePCDATA(c); break; } case STATE_COMMENT_AS_CHAR_ARRAY_SMALL: { final int length = readStructure(); final int start = readContentCharactersBuffer(length); final String comment = new String(_contentCharactersBuffer, start, length); writer.writeComment(comment); break; } case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM: { final int length = readStructure16(); final int start = readContentCharactersBuffer(length); final String comment = new String(_contentCharactersBuffer, start, length); writer.writeComment(comment); break; } case STATE_COMMENT_AS_CHAR_ARRAY_COPY: { final char[] ch = readContentCharactersCopy(); writer.writeComment(new String(ch)); break; } case STATE_PROCESSING_INSTRUCTION: writer.writeProcessingInstruction(readStructureString(), readStructureString()); break; case STATE_END: writer.writeEndElement(); depth --; if(depth==0) _treeCount--; break; default: throw new XMLStreamException("Invalid State "+item); } } while(depth>0 || _treeCount>0); } public void writeFragmentNoEx(XMLStreamWriter writer) throws XMLStreamException { int depth = 0; int item = _eiiStateTable[peekStructure()]; if(item==STATE_DOCUMENT) readStructure(); // skip STATE_DOCUMENT do { item = readEiiState(); switch(item) { case STATE_DOCUMENT: throw new AssertionError(); case STATE_ELEMENT_U_LN_QN: { depth ++; final String uri = readStructureString(); final String localName = readStructureString(); final String prefix = getPrefixFromQName(readStructureString()); writer.writeStartElement(prefix,localName,uri); writeAttributes(writer); break; } case STATE_ELEMENT_P_U_LN: { depth ++; final String prefix = readStructureString(); final String uri = readStructureString(); final String localName = readStructureString(); writer.writeStartElement(prefix,localName,uri); writeAttributes(writer); break; } case STATE_ELEMENT_U_LN: { depth ++; final String uri = readStructureString(); final String localName = readStructureString(); writer.writeStartElement("",localName,uri); writeAttributes(writer); break; } case STATE_ELEMENT_LN: { depth ++; final String localName = readStructureString(); writer.writeStartElement(localName); writeAttributes(writer); break; } case STATE_TEXT_AS_CHAR_ARRAY_SMALL: { final int length = readStructure(); final int start = readContentCharactersBuffer(length); writer.writeCharacters(_contentCharactersBuffer,start,length); break; } case STATE_TEXT_AS_CHAR_ARRAY_MEDIUM: { final int length = readStructure16(); final int start = readContentCharactersBuffer(length); writer.writeCharacters(_contentCharactersBuffer,start,length); break; } case STATE_TEXT_AS_CHAR_ARRAY_COPY: { char[] c = readContentCharactersCopy(); writer.writeCharacters(c,0,c.length); break; } case STATE_TEXT_AS_STRING: { final String s = readContentString(); writer.writeCharacters(s); break; } case STATE_TEXT_AS_OBJECT: { final CharSequence c = (CharSequence)readContentObject(); writer.writeCharacters(c.toString()); break; } case STATE_COMMENT_AS_CHAR_ARRAY_SMALL: { final int length = readStructure(); final int start = readContentCharactersBuffer(length); final String comment = new String(_contentCharactersBuffer, start, length); writer.writeComment(comment); break; } case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM: { final int length = readStructure16(); final int start = readContentCharactersBuffer(length); final String comment = new String(_contentCharactersBuffer, start, length); writer.writeComment(comment); break; } case STATE_COMMENT_AS_CHAR_ARRAY_COPY: { final char[] ch = readContentCharactersCopy(); writer.writeComment(new String(ch)); break; } case STATE_PROCESSING_INSTRUCTION: writer.writeProcessingInstruction(readStructureString(), readStructureString()); break; case STATE_END: writer.writeEndElement(); depth --; if(depth==0) _treeCount--; break; default: throw new XMLStreamException("Invalid State "+item); } } while(depth > 0 && _treeCount>0); } private void writeAttributes(XMLStreamWriter writer) throws XMLStreamException { int item = peekStructure(); if ((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE) { // Skip the namespace declarations on the element // they will have been added already item = writeNamespaceAttributes(item, writer); } if ((item & TYPE_MASK) == T_ATTRIBUTE) { writeAttributes(item, writer); } } private int writeNamespaceAttributes(int item, XMLStreamWriter writer) throws XMLStreamException { do { switch(_niiStateTable[item]){ case STATE_NAMESPACE_ATTRIBUTE: // Undeclaration of default namespace writer.writeDefaultNamespace(""); break; case STATE_NAMESPACE_ATTRIBUTE_P: // Undeclaration of namespace // Declaration with prefix writer.writeNamespace(readStructureString(), ""); break; case STATE_NAMESPACE_ATTRIBUTE_P_U: // Declaration with prefix writer.writeNamespace(readStructureString(), readStructureString()); break; case STATE_NAMESPACE_ATTRIBUTE_U: // Default declaration writer.writeDefaultNamespace(readStructureString()); break; } readStructure(); item = peekStructure(); } while((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE); return item; } private void writeAttributes(int item, XMLStreamWriter writer) throws XMLStreamException { do { switch(_aiiStateTable[item]) { case STATE_ATTRIBUTE_U_LN_QN: { final String uri = readStructureString(); final String localName = readStructureString(); final String prefix = getPrefixFromQName(readStructureString()); writer.writeAttribute(prefix,uri,localName,readContentString()); break; } case STATE_ATTRIBUTE_P_U_LN: writer.writeAttribute(readStructureString(), readStructureString(), readStructureString(), readContentString()); break; case STATE_ATTRIBUTE_U_LN: writer.writeAttribute(readStructureString(), readStructureString(), readContentString()); break; case STATE_ATTRIBUTE_LN: writer.writeAttribute(readStructureString(), readContentString()); break; } // Ignore the attribute type readStructureString(); readStructure(); item = peekStructure(); } while((item & TYPE_MASK) == T_ATTRIBUTE); } }