aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2011, 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.bind.v2.runtime.unmarshaller; aoqi@0: aoqi@0: import javax.xml.stream.Location; aoqi@0: import javax.xml.stream.XMLStreamConstants; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: aoqi@0: import com.sun.xml.internal.bind.WhiteSpaceProcessor; aoqi@0: import com.sun.xml.internal.fastinfoset.stax.StAXDocumentParser; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes; aoqi@0: import org.xml.sax.SAXException; aoqi@0: aoqi@0: /** aoqi@0: * Reads from FastInfoset StAX parser and feeds into JAXB Unmarshaller. aoqi@0: *

aoqi@0: * This class will peek at future events to ascertain if characters need to be aoqi@0: * buffered or not. aoqi@0: * aoqi@0: * @author Paul Sandoz. aoqi@0: */ aoqi@0: final class FastInfosetConnector extends StAXConnector { aoqi@0: aoqi@0: // event source aoqi@0: private final StAXDocumentParser fastInfosetStreamReader; aoqi@0: aoqi@0: // Flag set to true if text has been reported aoqi@0: private boolean textReported; aoqi@0: aoqi@0: // Buffer for octets aoqi@0: private final Base64Data base64Data = new Base64Data(); aoqi@0: aoqi@0: // Buffer for characters aoqi@0: private final StringBuilder buffer = new StringBuilder(); aoqi@0: aoqi@0: public FastInfosetConnector(StAXDocumentParser fastInfosetStreamReader, aoqi@0: XmlVisitor visitor) { aoqi@0: super(visitor); aoqi@0: fastInfosetStreamReader.setStringInterning(true); aoqi@0: this.fastInfosetStreamReader = fastInfosetStreamReader; aoqi@0: } aoqi@0: aoqi@0: public void bridge() throws XMLStreamException { aoqi@0: try { aoqi@0: // remembers the nest level of elements to know when we are done. aoqi@0: int depth=0; aoqi@0: aoqi@0: // if the parser is at the start tag, proceed to the first element aoqi@0: int event = fastInfosetStreamReader.getEventType(); aoqi@0: if(event == XMLStreamConstants.START_DOCUMENT) { aoqi@0: // nextTag doesn't correctly handle DTDs aoqi@0: while( !fastInfosetStreamReader.isStartElement() ) aoqi@0: event = fastInfosetStreamReader.next(); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: if( event!=XMLStreamConstants.START_ELEMENT) aoqi@0: throw new IllegalStateException("The current event is not START_ELEMENT\n but " + event); aoqi@0: aoqi@0: // TODO: we don't have to rely on this hack --- we can just emulate aoqi@0: // start/end prefix mappings. But for now, I'll rely on this hack. aoqi@0: handleStartDocument(fastInfosetStreamReader.getNamespaceContext()); aoqi@0: aoqi@0: OUTER: aoqi@0: while(true) { aoqi@0: // These are all of the events listed in the javadoc for aoqi@0: // XMLEvent. aoqi@0: // The spec only really describes 11 of them. aoqi@0: switch (event) { aoqi@0: case XMLStreamConstants.START_ELEMENT : aoqi@0: handleStartElement(); aoqi@0: depth++; aoqi@0: break; aoqi@0: case XMLStreamConstants.END_ELEMENT : aoqi@0: depth--; aoqi@0: handleEndElement(); aoqi@0: if(depth==0) break OUTER; aoqi@0: break; aoqi@0: case XMLStreamConstants.CHARACTERS : aoqi@0: case XMLStreamConstants.CDATA : aoqi@0: case XMLStreamConstants.SPACE : aoqi@0: if (predictor.expectText()) { aoqi@0: // Peek at the next event to see if there are aoqi@0: // fragmented characters aoqi@0: event = fastInfosetStreamReader.peekNext(); aoqi@0: if (event == XMLStreamConstants.END_ELEMENT) aoqi@0: processNonIgnorableText(); aoqi@0: else if (event == XMLStreamConstants.START_ELEMENT) aoqi@0: processIgnorableText(); aoqi@0: else aoqi@0: handleFragmentedCharacters(); aoqi@0: } aoqi@0: break; aoqi@0: // otherwise simply ignore aoqi@0: } aoqi@0: aoqi@0: event=fastInfosetStreamReader.next(); aoqi@0: } aoqi@0: aoqi@0: fastInfosetStreamReader.next(); // move beyond the end tag. aoqi@0: aoqi@0: handleEndDocument(); aoqi@0: } catch (SAXException e) { aoqi@0: throw new XMLStreamException(e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected Location getCurrentLocation() { aoqi@0: return fastInfosetStreamReader.getLocation(); aoqi@0: } aoqi@0: aoqi@0: protected String getCurrentQName() { aoqi@0: return fastInfosetStreamReader.getNameString(); aoqi@0: } aoqi@0: aoqi@0: private void handleStartElement() throws SAXException { aoqi@0: processUnreportedText(); aoqi@0: aoqi@0: for (int i = 0; i < fastInfosetStreamReader.accessNamespaceCount(); i++) { aoqi@0: visitor.startPrefixMapping(fastInfosetStreamReader.getNamespacePrefix(i), aoqi@0: fastInfosetStreamReader.getNamespaceURI(i)); aoqi@0: } aoqi@0: aoqi@0: tagName.uri = fastInfosetStreamReader.accessNamespaceURI(); aoqi@0: tagName.local = fastInfosetStreamReader.accessLocalName(); aoqi@0: tagName.atts = fastInfosetStreamReader.getAttributesHolder(); aoqi@0: aoqi@0: visitor.startElement(tagName); aoqi@0: } aoqi@0: aoqi@0: private void handleFragmentedCharacters() throws XMLStreamException, SAXException { aoqi@0: buffer.setLength(0); aoqi@0: aoqi@0: // Append characters of first character event aoqi@0: buffer.append(fastInfosetStreamReader.getTextCharacters(), aoqi@0: fastInfosetStreamReader.getTextStart(), aoqi@0: fastInfosetStreamReader.getTextLength()); aoqi@0: aoqi@0: // Consume all character aoqi@0: while(true) { aoqi@0: switch(fastInfosetStreamReader.peekNext()) { aoqi@0: case XMLStreamConstants.START_ELEMENT : aoqi@0: processBufferedText(true); aoqi@0: return; aoqi@0: case XMLStreamConstants.END_ELEMENT : aoqi@0: processBufferedText(false); aoqi@0: return; aoqi@0: case XMLStreamConstants.CHARACTERS : aoqi@0: case XMLStreamConstants.CDATA : aoqi@0: case XMLStreamConstants.SPACE : aoqi@0: // Append characters of second and subsequent character events aoqi@0: fastInfosetStreamReader.next(); aoqi@0: buffer.append(fastInfosetStreamReader.getTextCharacters(), aoqi@0: fastInfosetStreamReader.getTextStart(), aoqi@0: fastInfosetStreamReader.getTextLength()); aoqi@0: break; aoqi@0: default: aoqi@0: fastInfosetStreamReader.next(); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void handleEndElement() throws SAXException { aoqi@0: processUnreportedText(); aoqi@0: aoqi@0: tagName.uri = fastInfosetStreamReader.accessNamespaceURI(); aoqi@0: tagName.local = fastInfosetStreamReader.accessLocalName(); aoqi@0: aoqi@0: visitor.endElement(tagName); aoqi@0: aoqi@0: for (int i = fastInfosetStreamReader.accessNamespaceCount() - 1; i >= 0; i--) { aoqi@0: visitor.endPrefixMapping(fastInfosetStreamReader.getNamespacePrefix(i)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: final private class CharSequenceImpl implements CharSequence { aoqi@0: char[] ch; aoqi@0: int start; aoqi@0: int length; aoqi@0: aoqi@0: CharSequenceImpl() { aoqi@0: } aoqi@0: aoqi@0: CharSequenceImpl(final char[] ch, final int start, final int length) { aoqi@0: this.ch = ch; aoqi@0: this.start = start; aoqi@0: this.length = length; aoqi@0: } aoqi@0: aoqi@0: public void set() { aoqi@0: ch = fastInfosetStreamReader.getTextCharacters(); aoqi@0: start = fastInfosetStreamReader.getTextStart(); aoqi@0: length = fastInfosetStreamReader.getTextLength(); aoqi@0: } aoqi@0: aoqi@0: // CharSequence interface aoqi@0: aoqi@0: public final int length() { aoqi@0: return length; aoqi@0: } aoqi@0: aoqi@0: public final char charAt(final int index) { aoqi@0: return ch[start + index]; aoqi@0: } aoqi@0: aoqi@0: public final CharSequence subSequence(final int start, final int end) { aoqi@0: return new CharSequenceImpl(ch, this.start + start, end - start); aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return new String(ch, start, length); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: final private CharSequenceImpl charArray = new CharSequenceImpl(); aoqi@0: aoqi@0: private void processNonIgnorableText() throws SAXException { aoqi@0: textReported = true; aoqi@0: boolean isTextAlgorithmAplied = aoqi@0: (fastInfosetStreamReader.getTextAlgorithmBytes() != null); aoqi@0: aoqi@0: if (isTextAlgorithmAplied && aoqi@0: fastInfosetStreamReader.getTextAlgorithmIndex() == EncodingAlgorithmIndexes.BASE64) { aoqi@0: base64Data.set(fastInfosetStreamReader.getTextAlgorithmBytesClone(),null); aoqi@0: visitor.text(base64Data); aoqi@0: } else { aoqi@0: if (isTextAlgorithmAplied) { aoqi@0: fastInfosetStreamReader.getText(); aoqi@0: } aoqi@0: aoqi@0: charArray.set(); aoqi@0: visitor.text(charArray); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void processIgnorableText() throws SAXException { aoqi@0: boolean isTextAlgorithmAplied = aoqi@0: (fastInfosetStreamReader.getTextAlgorithmBytes() != null); aoqi@0: aoqi@0: if (isTextAlgorithmAplied && aoqi@0: fastInfosetStreamReader.getTextAlgorithmIndex() == EncodingAlgorithmIndexes.BASE64) { aoqi@0: base64Data.set(fastInfosetStreamReader.getTextAlgorithmBytesClone(),null); aoqi@0: visitor.text(base64Data); aoqi@0: textReported = true; aoqi@0: } else { aoqi@0: if (isTextAlgorithmAplied) { aoqi@0: fastInfosetStreamReader.getText(); aoqi@0: } aoqi@0: aoqi@0: charArray.set(); aoqi@0: if (!WhiteSpaceProcessor.isWhiteSpace(charArray)) { aoqi@0: visitor.text(charArray); aoqi@0: textReported = true; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void processBufferedText(boolean ignorable) throws SAXException { aoqi@0: if (!ignorable || !WhiteSpaceProcessor.isWhiteSpace(buffer)) { aoqi@0: visitor.text(buffer); aoqi@0: textReported = true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void processUnreportedText() throws SAXException { aoqi@0: if(!textReported && predictor.expectText()) { aoqi@0: visitor.text(""); aoqi@0: } aoqi@0: textReported = false; aoqi@0: } aoqi@0: }