/* * 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.org.jvnet.fastinfoset.sax.helpers; import com.sun.xml.internal.fastinfoset.CommonResourceBundle; import com.sun.xml.internal.fastinfoset.EncodingConstants; import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory; import java.io.IOException; import java.util.Map; import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm; import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException; 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.sax.EncodingAlgorithmAttributes; import org.xml.sax.Attributes; /** * Default implementation of the {@link EncodingAlgorithmAttributes} interface. * * <p>This class provides a default implementation of the SAX2 * {@link EncodingAlgorithmAttributes} interface, with the * addition of manipulators so that the list can be modified or * reused.</p> * * <p>There are two typical uses of this class:</p> * * <ol> * <li>to take a persistent snapshot of an EncodingAlgorithmAttributes object * in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li> * <li>to construct or modify an EncodingAlgorithmAttributes object in a SAX2 * driver or filter.</li> * </ol> */ public class EncodingAlgorithmAttributesImpl implements EncodingAlgorithmAttributes { private static final int DEFAULT_CAPACITY = 8; private static final int URI_OFFSET = 0; private static final int LOCALNAME_OFFSET = 1; private static final int QNAME_OFFSET = 2; private static final int TYPE_OFFSET = 3; private static final int VALUE_OFFSET = 4; private static final int ALGORITHMURI_OFFSET = 5; private static final int SIZE = 6; private Map _registeredEncodingAlgorithms; private int _length; private String[] _data; private int[] _algorithmIds; private Object[] _algorithmData; private String[] _alphabets; private boolean[] _toIndex; /** * Construct a new, empty EncodingAlgorithmAttributesImpl object. */ public EncodingAlgorithmAttributesImpl() { this(null, null); } /** * Copy an existing Attributes object. * * <p>This constructor is especially useful inside a * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p> * * @param attributes The existing Attributes object. */ public EncodingAlgorithmAttributesImpl(Attributes attributes) { this(null, attributes); } /** * Use registered encoding algorithms and copy an existing Attributes object. * * <p>This constructor is especially useful inside a * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p> * * @param registeredEncodingAlgorithms * The registeredEncodingAlgorithms encoding algorithms. * @param attributes The existing Attributes object. */ public EncodingAlgorithmAttributesImpl(Map registeredEncodingAlgorithms, Attributes attributes) { _data = new String[DEFAULT_CAPACITY * SIZE]; _algorithmIds = new int[DEFAULT_CAPACITY]; _algorithmData = new Object[DEFAULT_CAPACITY]; _alphabets = new String[DEFAULT_CAPACITY]; _toIndex = new boolean[DEFAULT_CAPACITY]; _registeredEncodingAlgorithms = registeredEncodingAlgorithms; if (attributes != null) { if (attributes instanceof EncodingAlgorithmAttributes) { setAttributes((EncodingAlgorithmAttributes)attributes); } else { setAttributes(attributes); } } } /** * Clear the attribute list for reuse. * */ public final void clear() { for (int i = 0; i < _length; i++) { _data[i * SIZE + VALUE_OFFSET] = null; _algorithmData[i] = null; } _length = 0; } /** * Add an attribute to the end of the list. * * <p>For the sake of speed, this method does no checking * to see if the attribute is already in the list: that is * the responsibility of the application.</p> * * @param URI The Namespace URI, or the empty string if * none is available or Namespace processing is not * being performed. * @param localName The local name, or the empty string if * Namespace processing is not being performed. * @param qName The qualified (prefixed) name, or the empty string * if qualified names are not available. * @param type The attribute type as a string. * @param value The attribute value. */ public void addAttribute(String URI, String localName, String qName, String type, String value) { if (_length >= _algorithmData.length) { resize(); } int i = _length * SIZE; _data[i++] = replaceNull(URI); _data[i++] = replaceNull(localName); _data[i++] = replaceNull(qName); _data[i++] = replaceNull(type); _data[i++] = replaceNull(value); _toIndex[_length] = false; _alphabets[_length] = null; _length++; } /** * Add an attribute to the end of the list. * * <p>For the sake of speed, this method does no checking * to see if the attribute is already in the list: that is * the responsibility of the application.</p> * * @param URI The Namespace URI, or the empty string if * none is available or Namespace processing is not * being performed. * @param localName The local name, or the empty string if * Namespace processing is not being performed. * @param qName The qualified (prefixed) name, or the empty string * if qualified names are not available. * @param type The attribute type as a string. * @param value The attribute value. * @param index True if attribute should be indexed. * @param alphabet The alphabet associated with the attribute value, * may be null if there is no associated alphabet. */ public void addAttribute(String URI, String localName, String qName, String type, String value, boolean index, String alphabet) { if (_length >= _algorithmData.length) { resize(); } int i = _length * SIZE; _data[i++] = replaceNull(URI); _data[i++] = replaceNull(localName); _data[i++] = replaceNull(qName); _data[i++] = replaceNull(type); _data[i++] = replaceNull(value); _toIndex[_length] = index; _alphabets[_length] = alphabet; _length++; } /** * Add an attribute with built in algorithm data to the end of the list. * * <p>For the sake of speed, this method does no checking * to see if the attribute is already in the list: that is * the responsibility of the application.</p> * * @param URI The Namespace URI, or the empty string if * none is available or Namespace processing is not * being performed. * @param localName The local name, or the empty string if * Namespace processing is not being performed. * @param qName The qualified (prefixed) name, or the empty string * if qualified names are not available. * @param builtInAlgorithmID The built in algorithm ID. * @param algorithmData The built in algorithm data. */ public void addAttributeWithBuiltInAlgorithmData(String URI, String localName, String qName, int builtInAlgorithmID, Object algorithmData) { if (_length >= _algorithmData.length) { resize(); } int i = _length * SIZE; _data[i++] = replaceNull(URI); _data[i++] = replaceNull(localName); _data[i++] = replaceNull(qName); _data[i++] = "CDATA"; _data[i++] = ""; _data[i++] = null; _algorithmIds[_length] = builtInAlgorithmID; _algorithmData[_length] = algorithmData; _toIndex[_length] = false; _alphabets[_length] = null; _length++; } /** * Add an attribute with algorithm data to the end of the list. * * <p>For the sake of speed, this method does no checking * to see if the attribute is already in the list: that is * the responsibility of the application.</p> * * @param URI The Namespace URI, or the empty string if * none is available or Namespace processing is not * being performed. * @param localName The local name, or the empty string if * Namespace processing is not being performed. * @param qName The qualified (prefixed) name, or the empty string * if qualified names are not available. * @param algorithmURI The algorithm URI, or null if a built in algorithm * @param algorithmID The algorithm ID. * @param algorithmData The algorithm data. */ public void addAttributeWithAlgorithmData(String URI, String localName, String qName, String algorithmURI, int algorithmID, Object algorithmData) { if (_length >= _algorithmData.length) { resize(); } int i = _length * SIZE; _data[i++] = replaceNull(URI); _data[i++] = replaceNull(localName); _data[i++] = replaceNull(qName); _data[i++] = "CDATA"; _data[i++] = ""; _data[i++] = algorithmURI; _algorithmIds[_length] = algorithmID; _algorithmData[_length] = algorithmData; _toIndex[_length] = false; _alphabets[_length] = null; _length++; } /** * Replace an attribute value with algorithm data. * * <p>For the sake of speed, this method does no checking * to see if the attribute is already in the list: that is * the responsibility of the application.</p> * * @param index The index of the attribute whose value is to be replaced * @param algorithmURI The algorithm URI, or null if a built in algorithm * @param algorithmID The algorithm ID. * @param algorithmData The algorithm data. */ public void replaceWithAttributeAlgorithmData(int index, String algorithmURI, int algorithmID, Object algorithmData) { if (index < 0 || index >= _length) return; int i = index * SIZE; _data[i + VALUE_OFFSET] = null; _data[i + ALGORITHMURI_OFFSET] = algorithmURI; _algorithmIds[index] = algorithmID; _algorithmData[index] = algorithmData; _toIndex[index] = false; _alphabets[index] = null; } /** * Copy an entire Attributes object. * * @param atts The attributes to copy. */ public void setAttributes(Attributes atts) { _length = atts.getLength(); if (_length > 0) { if (_length >= _algorithmData.length) { resizeNoCopy(); } int index = 0; for (int i = 0; i < _length; i++) { _data[index++] = atts.getURI(i); _data[index++] = atts.getLocalName(i); _data[index++] = atts.getQName(i); _data[index++] = atts.getType(i); _data[index++] = atts.getValue(i); index++; _toIndex[i] = false; _alphabets[i] = null; } } } /** * Copy an entire EncodingAlgorithmAttributes object. * * @param atts The attributes to copy. */ public void setAttributes(EncodingAlgorithmAttributes atts) { _length = atts.getLength(); if (_length > 0) { if (_length >= _algorithmData.length) { resizeNoCopy(); } int index = 0; for (int i = 0; i < _length; i++) { _data[index++] = atts.getURI(i); _data[index++] = atts.getLocalName(i); _data[index++] = atts.getQName(i); _data[index++] = atts.getType(i); _data[index++] = atts.getValue(i); _data[index++] = atts.getAlgorithmURI(i); _algorithmIds[i] = atts.getAlgorithmIndex(i); _algorithmData[i] = atts.getAlgorithmData(i); _toIndex[i] = false; _alphabets[i] = null; } } } // org.xml.sax.Attributes public final int getLength() { return _length; } public final String getLocalName(int index) { if (index >= 0 && index < _length) { return _data[index * SIZE + LOCALNAME_OFFSET]; } else { return null; } } public final String getQName(int index) { if (index >= 0 && index < _length) { return _data[index * SIZE + QNAME_OFFSET]; } else { return null; } } public final String getType(int index) { if (index >= 0 && index < _length) { return _data[index * SIZE + TYPE_OFFSET]; } else { return null; } } public final String getURI(int index) { if (index >= 0 && index < _length) { return _data[index * SIZE + URI_OFFSET]; } else { return null; } } public final String getValue(int index) { if (index >= 0 && index < _length) { final String value = _data[index * SIZE + VALUE_OFFSET]; if (value != null) return value; } else { return null; } if (_algorithmData[index] == null || _registeredEncodingAlgorithms == null) { return null; } try { return _data[index * SIZE + VALUE_OFFSET] = convertEncodingAlgorithmDataToString( _algorithmIds[index], _data[index * SIZE + ALGORITHMURI_OFFSET], _algorithmData[index]).toString(); } catch (IOException e) { return null; } catch (FastInfosetException e) { return null; } } public final int getIndex(String qName) { for (int index = 0; index < _length; index++) { if (qName.equals(_data[index * SIZE + QNAME_OFFSET])) { return index; } } return -1; } public final String getType(String qName) { int index = getIndex(qName); if (index >= 0) { return _data[index * SIZE + TYPE_OFFSET]; } else { return null; } } public final String getValue(String qName) { int index = getIndex(qName); if (index >= 0) { return getValue(index); } else { return null; } } public final int getIndex(String uri, String localName) { for (int index = 0; index < _length; index++) { if (localName.equals(_data[index * SIZE + LOCALNAME_OFFSET]) && uri.equals(_data[index * SIZE + URI_OFFSET])) { return index; } } return -1; } public final String getType(String uri, String localName) { int index = getIndex(uri, localName); if (index >= 0) { return _data[index * SIZE + TYPE_OFFSET]; } else { return null; } } public final String getValue(String uri, String localName) { int index = getIndex(uri, localName); if (index >= 0) { return getValue(index); } else { return null; } } // EncodingAlgorithmAttributes public final String getAlgorithmURI(int index) { if (index >= 0 && index < _length) { return _data[index * SIZE + ALGORITHMURI_OFFSET]; } else { return null; } } public final int getAlgorithmIndex(int index) { if (index >= 0 && index < _length) { return _algorithmIds[index]; } else { return -1; } } public final Object getAlgorithmData(int index) { if (index >= 0 && index < _length) { return _algorithmData[index]; } else { return null; } } // ExtendedAttributes public final String getAlpababet(int index) { if (index >= 0 && index < _length) { return _alphabets[index]; } else { return null; } } public final boolean getToIndex(int index) { if (index >= 0 && index < _length) { return _toIndex[index]; } else { return false; } } // ----- private final String replaceNull(String s) { return (s != null) ? s : ""; } private final void resizeNoCopy() { final int newLength = _length * 3 / 2 + 1; _data = new String[newLength * SIZE]; _algorithmIds = new int[newLength]; _algorithmData = new Object[newLength]; } private final void resize() { final int newLength = _length * 3 / 2 + 1; String[] data = new String[newLength * SIZE]; int[] algorithmIds = new int[newLength]; Object[] algorithmData = new Object[newLength]; String[] alphabets = new String[newLength]; boolean[] toIndex = new boolean[newLength]; System.arraycopy(_data, 0, data, 0, _length * SIZE); System.arraycopy(_algorithmIds, 0, algorithmIds, 0, _length); System.arraycopy(_algorithmData, 0, algorithmData, 0, _length); System.arraycopy(_alphabets, 0, alphabets, 0, _length); System.arraycopy(_toIndex, 0, toIndex, 0, _length); _data = data; _algorithmIds = algorithmIds; _algorithmData = algorithmData; _alphabets = alphabets; _toIndex = toIndex; } private final StringBuffer convertEncodingAlgorithmDataToString( int identifier, String URI, Object data) throws FastInfosetException, IOException { EncodingAlgorithm ea = null; if (identifier < EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) { ea = BuiltInEncodingAlgorithmFactory.getAlgorithm(identifier); } else if (identifier == EncodingAlgorithmIndexes.CDATA) { throw new EncodingAlgorithmException( CommonResourceBundle.getInstance().getString("message.CDATAAlgorithmNotSupported")); } else if (identifier >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) { if (URI == null) { throw new EncodingAlgorithmException( CommonResourceBundle.getInstance().getString("message.URINotPresent") + identifier); } ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI); if (ea == null) { throw new EncodingAlgorithmException( CommonResourceBundle.getInstance().getString("message.algorithmNotRegistered") + URI); } } else { // Reserved built-in algorithms for future use // TODO should use sax property to decide if event will be // reported, allows for support through handler if required. throw new EncodingAlgorithmException( CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved")); } final StringBuffer sb = new StringBuffer(); ea.convertToCharacters(data, sb); return sb; } }