aoqi@0: /* aoqi@0: * Copyright (c) 2004, 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: * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.fastinfoset.sax; aoqi@0: aoqi@0: import com.sun.xml.internal.fastinfoset.EncodingConstants; aoqi@0: import com.sun.xml.internal.fastinfoset.QualifiedName; aoqi@0: import com.sun.xml.internal.fastinfoset.util.KeyIntMap; aoqi@0: import com.sun.xml.internal.fastinfoset.util.LocalNameQualifiedNamesMap; aoqi@0: import com.sun.xml.internal.fastinfoset.util.StringIntMap; aoqi@0: import java.io.IOException; aoqi@0: import java.util.HashMap; aoqi@0: import org.xml.sax.SAXException; aoqi@0: import java.util.Map; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.RestrictedAlphabet; aoqi@0: import com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmAttributes; aoqi@0: import org.xml.sax.Attributes; aoqi@0: aoqi@0: /** aoqi@0: * The Fast Infoset SAX serializer that maps prefixes to user specified prefixes aoqi@0: * that are specified in a namespace URI to prefix map. aoqi@0: *

aoqi@0: * This serializer will not preserve the original prefixes and this serializer aoqi@0: * should not be used when prefixes need to be preserved, such as the case aoqi@0: * when there are qualified names in content. aoqi@0: *

aoqi@0: * A namespace URI to prefix map is utilized such that the prefixes aoqi@0: * in the map are utilized rather than the prefixes specified in aoqi@0: * the qualified name for elements and attributes. aoqi@0: *

aoqi@0: * Any namespace declarations with a namespace URI that is not present in aoqi@0: * the map are added. aoqi@0: *

aoqi@0: */ aoqi@0: public class SAXDocumentSerializerWithPrefixMapping extends SAXDocumentSerializer { aoqi@0: protected Map _namespaceToPrefixMapping; aoqi@0: protected Map _prefixToPrefixMapping; aoqi@0: protected String _lastCheckedNamespace; aoqi@0: protected String _lastCheckedPrefix; aoqi@0: aoqi@0: protected StringIntMap _declaredNamespaces; aoqi@0: aoqi@0: public SAXDocumentSerializerWithPrefixMapping(Map namespaceToPrefixMapping) { aoqi@0: // Use the local name to look up elements/attributes aoqi@0: super(true); aoqi@0: _namespaceToPrefixMapping = new HashMap(namespaceToPrefixMapping); aoqi@0: _prefixToPrefixMapping = new HashMap(); aoqi@0: aoqi@0: // Empty prefix aoqi@0: _namespaceToPrefixMapping.put("", ""); aoqi@0: // 'xml' prefix aoqi@0: _namespaceToPrefixMapping.put(EncodingConstants.XML_NAMESPACE_NAME, EncodingConstants.XML_NAMESPACE_PREFIX); aoqi@0: aoqi@0: _declaredNamespaces = new StringIntMap(4); aoqi@0: } aoqi@0: aoqi@0: public final void startPrefixMapping(String prefix, String uri) throws SAXException { aoqi@0: try { aoqi@0: if (_elementHasNamespaces == false) { aoqi@0: encodeTermination(); aoqi@0: aoqi@0: // Mark the current buffer position to flag attributes if necessary aoqi@0: mark(); aoqi@0: _elementHasNamespaces = true; aoqi@0: aoqi@0: // Write out Element byte with namespaces aoqi@0: write(EncodingConstants.ELEMENT | EncodingConstants.ELEMENT_NAMESPACES_FLAG); aoqi@0: aoqi@0: _declaredNamespaces.clear(); aoqi@0: _declaredNamespaces.obtainIndex(uri); aoqi@0: } else { aoqi@0: if (_declaredNamespaces.obtainIndex(uri) != KeyIntMap.NOT_PRESENT) { aoqi@0: final String p = getPrefix(uri); aoqi@0: if (p != null) { aoqi@0: _prefixToPrefixMapping.put(prefix, p); aoqi@0: } aoqi@0: return; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: final String p = getPrefix(uri); aoqi@0: if (p != null) { aoqi@0: encodeNamespaceAttribute(p, uri); aoqi@0: _prefixToPrefixMapping.put(prefix, p); aoqi@0: } else { aoqi@0: putPrefix(uri, prefix); aoqi@0: encodeNamespaceAttribute(prefix, uri); aoqi@0: } aoqi@0: aoqi@0: } catch (IOException e) { aoqi@0: throw new SAXException("startElement", e); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final void encodeElement(String namespaceURI, String qName, String localName) throws IOException { aoqi@0: LocalNameQualifiedNamesMap.Entry entry = _v.elementName.obtainEntry(localName); aoqi@0: if (entry._valueIndex > 0) { aoqi@0: if (encodeElementMapEntry(entry, namespaceURI)) return; aoqi@0: // Check the entry is a member of the read only map aoqi@0: if (_v.elementName.isQNameFromReadOnlyMap(entry._value[0])) { aoqi@0: entry = _v.elementName.obtainDynamicEntry(localName); aoqi@0: if (entry._valueIndex > 0) { aoqi@0: if (encodeElementMapEntry(entry, namespaceURI)) return; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: encodeLiteralElementQualifiedNameOnThirdBit(namespaceURI, getPrefix(namespaceURI), aoqi@0: localName, entry); aoqi@0: } aoqi@0: aoqi@0: protected boolean encodeElementMapEntry(LocalNameQualifiedNamesMap.Entry entry, String namespaceURI) throws IOException { aoqi@0: QualifiedName[] names = entry._value; aoqi@0: for (int i = 0; i < entry._valueIndex; i++) { aoqi@0: if ((namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) { aoqi@0: encodeNonZeroIntegerOnThirdBit(names[i].index); aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: protected final void encodeAttributes(Attributes atts) throws IOException, FastInfosetException { aoqi@0: boolean addToTable; aoqi@0: boolean mustToBeAddedToTable; aoqi@0: String value; aoqi@0: if (atts instanceof EncodingAlgorithmAttributes) { aoqi@0: final EncodingAlgorithmAttributes eAtts = (EncodingAlgorithmAttributes)atts; aoqi@0: Object data; aoqi@0: String alphabet; aoqi@0: for (int i = 0; i < eAtts.getLength(); i++) { aoqi@0: final String uri = atts.getURI(i); aoqi@0: if (encodeAttribute(uri, atts.getQName(i), atts.getLocalName(i))) { aoqi@0: data = eAtts.getAlgorithmData(i); aoqi@0: // If data is null then there is no algorithm data aoqi@0: if (data == null) { aoqi@0: value = eAtts.getValue(i); aoqi@0: addToTable = isAttributeValueLengthMatchesLimit(value.length()); aoqi@0: mustToBeAddedToTable = eAtts.getToIndex(i); aoqi@0: alphabet = eAtts.getAlpababet(i); aoqi@0: if (alphabet == null) { aoqi@0: if (uri == "http://www.w3.org/2001/XMLSchema-instance" || aoqi@0: uri.equals("http://www.w3.org/2001/XMLSchema-instance")) { aoqi@0: value = convertQName(value); aoqi@0: } aoqi@0: encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue, addToTable, mustToBeAddedToTable); aoqi@0: } else if (alphabet == RestrictedAlphabet.DATE_TIME_CHARACTERS) { aoqi@0: encodeDateTimeNonIdentifyingStringOnFirstBit( aoqi@0: value, addToTable, mustToBeAddedToTable); aoqi@0: } else if (alphabet == RestrictedAlphabet.NUMERIC_CHARACTERS) { aoqi@0: encodeNumericNonIdentifyingStringOnFirstBit( aoqi@0: value, addToTable, mustToBeAddedToTable); aoqi@0: } else { aoqi@0: encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue, addToTable, mustToBeAddedToTable); aoqi@0: } aoqi@0: } else { aoqi@0: encodeNonIdentifyingStringOnFirstBit(eAtts.getAlgorithmURI(i), aoqi@0: eAtts.getAlgorithmIndex(i), data); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } else { aoqi@0: for (int i = 0; i < atts.getLength(); i++) { aoqi@0: final String uri = atts.getURI(i); aoqi@0: if (encodeAttribute(atts.getURI(i), atts.getQName(i), atts.getLocalName(i))) { aoqi@0: value = atts.getValue(i); aoqi@0: addToTable = isAttributeValueLengthMatchesLimit(value.length()); aoqi@0: aoqi@0: if (uri == "http://www.w3.org/2001/XMLSchema-instance" || aoqi@0: uri.equals("http://www.w3.org/2001/XMLSchema-instance")) { aoqi@0: value = convertQName(value); aoqi@0: } aoqi@0: encodeNonIdentifyingStringOnFirstBit(value, _v.attributeValue, addToTable, false); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: _b = EncodingConstants.TERMINATOR; aoqi@0: _terminate = true; aoqi@0: } aoqi@0: aoqi@0: private String convertQName(String qName) { aoqi@0: int i = qName.indexOf(':'); aoqi@0: String prefix = ""; aoqi@0: String localName = qName; aoqi@0: if (i != -1) { aoqi@0: prefix = qName.substring(0, i); aoqi@0: localName = qName.substring(i + 1); aoqi@0: } aoqi@0: aoqi@0: String p = (String)_prefixToPrefixMapping.get(prefix); aoqi@0: if (p != null) { aoqi@0: if (p.length() == 0) aoqi@0: return localName; aoqi@0: else aoqi@0: return p + ":" + localName; aoqi@0: } else { aoqi@0: return qName; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: protected final boolean encodeAttribute(String namespaceURI, String qName, String localName) throws IOException { aoqi@0: LocalNameQualifiedNamesMap.Entry entry = _v.attributeName.obtainEntry(localName); aoqi@0: if (entry._valueIndex > 0) { aoqi@0: if (encodeAttributeMapEntry(entry, namespaceURI)) return true; aoqi@0: // Check the entry is a member of the read only map aoqi@0: if (_v.attributeName.isQNameFromReadOnlyMap(entry._value[0])) { aoqi@0: entry = _v.attributeName.obtainDynamicEntry(localName); aoqi@0: if (entry._valueIndex > 0) { aoqi@0: if (encodeAttributeMapEntry(entry, namespaceURI)) return true; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return encodeLiteralAttributeQualifiedNameOnSecondBit(namespaceURI, getPrefix(namespaceURI), aoqi@0: localName, entry); aoqi@0: } aoqi@0: aoqi@0: protected boolean encodeAttributeMapEntry(LocalNameQualifiedNamesMap.Entry entry, String namespaceURI) throws IOException { aoqi@0: QualifiedName[] names = entry._value; aoqi@0: for (int i = 0; i < entry._valueIndex; i++) { aoqi@0: if ((namespaceURI == names[i].namespaceName || namespaceURI.equals(names[i].namespaceName))) { aoqi@0: encodeNonZeroIntegerOnSecondBitFirstBitZero(names[i].index); aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: protected final String getPrefix(String namespaceURI) { aoqi@0: if (_lastCheckedNamespace == namespaceURI) return _lastCheckedPrefix; aoqi@0: aoqi@0: _lastCheckedNamespace = namespaceURI; aoqi@0: return _lastCheckedPrefix = (String)_namespaceToPrefixMapping.get(namespaceURI); aoqi@0: } aoqi@0: aoqi@0: protected final void putPrefix(String namespaceURI, String prefix) { aoqi@0: _namespaceToPrefixMapping.put(namespaceURI, prefix); aoqi@0: aoqi@0: _lastCheckedNamespace = namespaceURI; aoqi@0: _lastCheckedPrefix = prefix; aoqi@0: } aoqi@0: }