/*
 * Copyright (c) 2004, 2012, Oracle and/or its affiliates. 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
 */

package com.sun.xml.internal.fastinfoset.sax;

import com.sun.xml.internal.fastinfoset.Encoder;
import com.sun.xml.internal.fastinfoset.EncodingConstants;
import com.sun.xml.internal.fastinfoset.QualifiedName;
import com.sun.xml.internal.org.jvnet.fastinfoset.sax.FastInfosetWriter;
import com.sun.xml.internal.fastinfoset.util.LocalNameQualifiedNamesMap;
import java.io.IOException;
import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException;
import com.sun.xml.internal.org.jvnet.fastinfoset.RestrictedAlphabet;
import com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmAttributes;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.sun.xml.internal.fastinfoset.CommonResourceBundle;

The Fast Infoset SAX serializer.

Instantiate this serializer to serialize a fast infoset document in accordance with the SAX API.

This utilizes the SAX API in a reverse manner to that of parsing. It is the responsibility of the client to call the appropriate event methods on the SAX handlers, and to ensure that such a sequence of methods calls results in the production well-formed fast infoset documents. The SAXDocumentSerializer performs no well-formed checks.

More than one fast infoset document may be encoded to the OutputStream.

/** * The Fast Infoset SAX serializer. * <p> * Instantiate this serializer to serialize a fast infoset document in accordance * with the SAX API. * <p> * This utilizes the SAX API in a reverse manner to that of parsing. It is the * responsibility of the client to call the appropriate event methods on the * SAX handlers, and to ensure that such a sequence of methods calls results * in the production well-formed fast infoset documents. The * SAXDocumentSerializer performs no well-formed checks. * * <p> * More than one fast infoset document may be encoded to the * {@link java.io.OutputStream}. */
public class SAXDocumentSerializer extends Encoder implements FastInfosetWriter { protected boolean _elementHasNamespaces = false; protected boolean _charactersAsCDATA = false; protected SAXDocumentSerializer(boolean v) { super(v); } public SAXDocumentSerializer() { } public void reset() { super.reset(); _elementHasNamespaces = false; _charactersAsCDATA = false; } // ContentHandler public final void startDocument() throws SAXException { try { reset(); encodeHeader(false); encodeInitialVocabulary(); } catch (IOException e) { throw new SAXException("startDocument", e); } } public final void endDocument() throws SAXException { try { encodeDocumentTermination(); } catch (IOException e) { throw new SAXException("endDocument", e); } } public void startPrefixMapping(String prefix, String uri) throws SAXException { try { if (_elementHasNamespaces == false) { encodeTermination(); // Mark the current buffer position to flag attributes if necessary mark(); _elementHasNamespaces = true; // Write out Element byte with namespaces write(EncodingConstants.ELEMENT | EncodingConstants.ELEMENT_NAMESPACES_FLAG); } encodeNamespaceAttribute(prefix, uri); } catch (IOException e) { throw new SAXException("startElement", e); } } public final void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { // TODO consider using buffer for encoding of attributes, then pre-counting is not necessary final int attributeCount = (atts != null && atts.getLength() > 0) ? countAttributes(atts) : 0; try { if (_elementHasNamespaces) { _elementHasNamespaces = false; if (attributeCount > 0) { // Flag the marked byte with attributes _octetBuffer[_markIndex] |= EncodingConstants.ELEMENT_ATTRIBUTE_FLAG; } resetMark(); write(EncodingConstants.TERMINATOR); _b = 0; } else { encodeTermination(); _b = EncodingConstants.ELEMENT; if (attributeCount > 0) { _b |= EncodingConstants.ELEMENT_ATTRIBUTE_FLAG; } } encodeElement(namespaceURI, qName, localName); if (attributeCount > 0) { encodeAttributes(atts); } } catch (IOException e) { throw new SAXException("startElement", e); } catch (FastInfosetException e) { throw new SAXException("startElement", e); } } public final void endElement(String namespaceURI, String localName, String qName) throws SAXException { try { encodeElementTermination(); } catch (IOException e) { throw new SAXException("endElement", e); } } public final void characters(char[] ch, int start, int length) throws SAXException { if (length <= 0) { return; } if (getIgnoreWhiteSpaceTextContent() && isWhiteSpace(ch, start, length)) return; try { encodeTermination(); if (!_charactersAsCDATA) { encodeCharacters(ch, start, length); } else { encodeCIIBuiltInAlgorithmDataAsCDATA(ch, start, length); } } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public final void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { if (getIgnoreWhiteSpaceTextContent()) return; characters(ch, start, length); } public final void processingInstruction(String target, String data) throws SAXException { try { if (getIgnoreProcesingInstructions()) return; if (target.length() == 0) { throw new SAXException(CommonResourceBundle.getInstance(). getString("message.processingInstructionTargetIsEmpty")); } encodeTermination(); encodeProcessingInstruction(target, data); } catch (IOException e) { throw new SAXException("processingInstruction", e); } } public final void setDocumentLocator(org.xml.sax.Locator locator) { } public final void skippedEntity(String name) throws SAXException { } // LexicalHandler public final void comment(char[] ch, int start, int length) throws SAXException { try { if (getIgnoreComments()) return; encodeTermination(); encodeComment(ch, start, length); } catch (IOException e) { throw new SAXException("startElement", e); } } public final void startCDATA() throws SAXException { _charactersAsCDATA = true; } public final void endCDATA() throws SAXException { _charactersAsCDATA = false; } public final void startDTD(String name, String publicId, String systemId) throws SAXException { if (getIgnoreDTD()) return; try { encodeTermination(); encodeDocumentTypeDeclaration(publicId, systemId); encodeElementTermination(); } catch (IOException e) { throw new SAXException("startDTD", e); } } public final void endDTD() throws SAXException { } public final void startEntity(String name) throws SAXException { } public final void endEntity(String name) throws SAXException { } // EncodingAlgorithmContentHandler public final void octets(String URI, int id, byte[] b, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeNonIdentifyingStringOnThirdBit(URI, id, b, start, length); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public final void object(String URI, int id, Object data) throws SAXException { try { encodeTermination(); encodeNonIdentifyingStringOnThirdBit(URI, id, data); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } // PrimitiveTypeContentHandler public final void bytes(byte[] b, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeCIIOctetAlgorithmData(EncodingAlgorithmIndexes.BASE64, b, start, length); } catch (IOException e) { throw new SAXException(e); } } public final void shorts(short[] s, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.SHORT, s, start, length); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public final void ints(int[] i, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.INT, i, start, length); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public final void longs(long[] l, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.LONG, l, start, length); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public final void booleans(boolean[] b, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.BOOLEAN, b, start, length); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public final void floats(float[] f, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.FLOAT, f, start, length); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public final void doubles(double[] d, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.DOUBLE, d, start, length); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public void uuids(long[] msblsb, int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); encodeCIIBuiltInAlgorithmData(EncodingAlgorithmIndexes.UUID, msblsb, start, length); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } // RestrictedAlphabetContentHandler public void numericCharacters(char ch[], int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); encodeNumericFourBitCharacters(ch, start, length, addToTable); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public void dateTimeCharacters(char ch[], int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); encodeDateTimeFourBitCharacters(ch, start, length, addToTable); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } public void alphabetCharacters(String alphabet, char ch[], int start, int length) throws SAXException { if (length <= 0) { return; } try { encodeTermination(); final boolean addToTable = isCharacterContentChunkLengthMatchesLimit(length); encodeAlphabetCharacters(alphabet, ch, start, length, addToTable); } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } // ExtendedContentHandler public void characters(char[] ch, int start, int length, boolean index) throws SAXException { if (length <= 0) { return; } if (getIgnoreWhiteSpaceTextContent() && isWhiteSpace(ch, start, length)) return; try { encodeTermination(); if (!_charactersAsCDATA) { encodeNonIdentifyingStringOnThirdBit(ch, start, length, _v.characterContentChunk, index, true); } else { encodeCIIBuiltInAlgorithmDataAsCDATA(ch, start, length); } } catch (IOException e) { throw new SAXException(e); } catch (FastInfosetException e) { throw new SAXException(e); } } protected final int countAttributes(Attributes atts) { // Count attributes ignoring any in the XMLNS namespace // Note, such attributes may be produced when transforming from a DOM node int count = 0; for (int i = 0; i < atts.getLength(); i++) { final String uri = atts.getURI(i); if (uri == "http://www.w3.org/2000/xmlns/" || uri.equals("http://www.w3.org/2000/xmlns/")) { continue; } count++; } return count; } protected void encodeAttributes(Attributes atts) throws IOException, FastInfosetException { boolean addToTable; boolean mustBeAddedToTable; String value; if (atts instanceof EncodingAlgorithmAttributes) { final EncodingAlgorithmAttributes eAtts = (EncodingAlgorithmAttributes)atts; Object data; String alphabet; for (int i = 0; i < eAtts.getLength(); i++) { if (encodeAttribute(atts.getURI(i), atts.getQName(i), atts.getLocalName(i))) { data = eAtts.getAlgorithmData(i); // If data is null then there is no algorithm data if (data == null) { value = eAtts.getValue(i); addToTable = isAttributeValueLengthMatchesLimit(value.length()); mustBeAddedToTable = eAtts.getToIndex(i); alphabet = eAtts.getAlpababet(i); if (alphabet == null) { encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue, addToTable, mustBeAddedToTable); } else if (alphabet == RestrictedAlphabet.DATE_TIME_CHARACTERS) { encodeDateTimeNonIdentifyingStringOnFirstBit( value, addToTable, mustBeAddedToTable); } else if (alphabet == RestrictedAlphabet.NUMERIC_CHARACTERS) { encodeNumericNonIdentifyingStringOnFirstBit( value, addToTable, mustBeAddedToTable); } else { encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue, addToTable, mustBeAddedToTable); } } else { encodeNonIdentifyingStringOnFirstBit(eAtts.getAlgorithmURI(i), eAtts.getAlgorithmIndex(i), data); } } } } else { for (int i = 0; i < atts.getLength(); i++) { if (encodeAttribute(atts.getURI(i), atts.getQName(i), atts.getLocalName(i))) { value = atts.getValue(i); addToTable = isAttributeValueLengthMatchesLimit(value.length()); encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue, addToTable, false); } } } _b = EncodingConstants.TERMINATOR; _terminate = true; } protected void encodeElement(String namespaceURI, String qName, String localName) throws IOException { LocalNameQualifiedNamesMap.Entry entry = _v.elementName.obtainEntry(qName); if (entry._valueIndex > 0) { QualifiedName[] names = entry._value; for (int i = 0; i < entry._valueIndex; i++) { final QualifiedName n = names[i]; if ((namespaceURI == n.namespaceName || namespaceURI.equals(n.namespaceName))) { encodeNonZeroIntegerOnThirdBit(names[i].index); return; } } } encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI, getPrefixFromQualifiedName(qName), localName, entry); } protected boolean encodeAttribute(String namespaceURI, String qName, String localName) throws IOException { LocalNameQualifiedNamesMap.Entry entry = _v.attributeName.obtainEntry(qName); if (entry._valueIndex > 0) { QualifiedName[] names = entry._value; for (int i = 0; i < entry._valueIndex; i++) { if ((namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) { encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index); return true; } } } return encodeLiteralAttributeQualifiedNameOnSecondBit(namespaceURI, getPrefixFromQualifiedName(qName), localName, entry); } }