1/*
2 * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 *
25 * THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
26 */
27
28package com.sun.xml.internal.fastinfoset.sax;
29
30import com.sun.xml.internal.fastinfoset.EncodingConstants;
31import com.sun.xml.internal.fastinfoset.QualifiedName;
32import com.sun.xml.internal.fastinfoset.algorithm.BuiltInEncodingAlgorithmFactory;
33import java.io.IOException;
34import java.util.Map;
35import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithm;
36import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmException;
37import com.sun.xml.internal.org.jvnet.fastinfoset.EncodingAlgorithmIndexes;
38import com.sun.xml.internal.org.jvnet.fastinfoset.FastInfosetException;
39
40import com.sun.xml.internal.org.jvnet.fastinfoset.sax.EncodingAlgorithmAttributes;
41import com.sun.xml.internal.fastinfoset.CommonResourceBundle;
42
43public class AttributesHolder implements EncodingAlgorithmAttributes {
44    private static final int DEFAULT_CAPACITY = 8;
45
46    private Map _registeredEncodingAlgorithms;
47
48    private int _attributeCount;
49
50    private QualifiedName[] _names;
51    private String[] _values;
52
53    private String[] _algorithmURIs;
54    private int[] _algorithmIds;
55    private Object[] _algorithmData;
56
57    public AttributesHolder() {
58        _names = new QualifiedName[DEFAULT_CAPACITY];
59        _values = new String[DEFAULT_CAPACITY];
60
61        _algorithmURIs = new String[DEFAULT_CAPACITY];
62        _algorithmIds = new int[DEFAULT_CAPACITY];
63        _algorithmData = new Object[DEFAULT_CAPACITY];
64    }
65
66    public AttributesHolder(Map registeredEncodingAlgorithms) {
67        this();
68        _registeredEncodingAlgorithms = registeredEncodingAlgorithms;
69    }
70
71    // org.xml.sax.Attributes
72
73    public final int getLength() {
74        return _attributeCount;
75    }
76
77    public final String getLocalName(int index) {
78        return _names[index].localName;
79    }
80
81    public final String getQName(int index) {
82        return _names[index].getQNameString();
83    }
84
85    public final String getType(int index) {
86        return "CDATA";
87    }
88
89    public final String getURI(int index) {
90        return _names[index].namespaceName;
91    }
92
93    public final String getValue(int index) {
94        final String value = _values[index];
95        if (value != null) {
96            return value;
97        }
98
99        if (_algorithmData[index] == null ||
100                (_algorithmIds[index] >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START &&
101                _registeredEncodingAlgorithms == null)) {
102            return null;
103        }
104
105        try {
106            return _values[index] = convertEncodingAlgorithmDataToString(
107                    _algorithmIds[index],
108                    _algorithmURIs[index],
109                    _algorithmData[index]).toString();
110        } catch (IOException e) {
111            return null;
112        } catch (FastInfosetException e) {
113            return null;
114        }
115    }
116
117    public final int getIndex(String qName) {
118        int i = qName.indexOf(':');
119        String prefix = "";
120        String localName = qName;
121        if (i >= 0) {
122            prefix = qName.substring(0, i);
123            localName = qName.substring(i + 1);
124        }
125
126        for (i = 0; i < _attributeCount; i++) {
127            QualifiedName name = _names[i];
128            if (localName.equals(name.localName) &&
129                prefix.equals(name.prefix)) {
130                return i;
131            }
132        }
133        return -1;
134    }
135
136    public final String getType(String qName) {
137        int index = getIndex(qName);
138        if (index >= 0) {
139            return "CDATA";
140        } else {
141            return null;
142        }
143    }
144
145    public final String getValue(String qName) {
146        int index = getIndex(qName);
147        if (index >= 0) {
148            return _values[index];
149        } else {
150            return null;
151        }
152    }
153
154    public final int getIndex(String uri, String localName) {
155        for (int i = 0; i < _attributeCount; i++) {
156            QualifiedName name = _names[i];
157            if (localName.equals(name.localName) &&
158                uri.equals(name.namespaceName)) {
159                return i;
160            }
161        }
162        return -1;
163    }
164
165    public final String getType(String uri, String localName) {
166        int index = getIndex(uri, localName);
167        if (index >= 0) {
168            return "CDATA";
169        } else {
170            return null;
171        }
172    }
173
174    public final String getValue(String uri, String localName) {
175        int index = getIndex(uri, localName);
176        if (index >= 0) {
177            return _values[index];
178        } else {
179            return null;
180        }
181    }
182
183    public final void clear() {
184        for (int i = 0; i < _attributeCount; i++) {
185            _values[i] = null;
186            _algorithmData[i] = null;
187        }
188        _attributeCount = 0;
189    }
190
191    // EncodingAlgorithmAttributes
192
193    public final String getAlgorithmURI(int index) {
194        return _algorithmURIs[index];
195    }
196
197    public final int getAlgorithmIndex(int index) {
198        return _algorithmIds[index];
199    }
200
201    public final Object getAlgorithmData(int index) {
202        return _algorithmData[index];
203    }
204
205    public String getAlpababet(int index) {
206        return null;
207    }
208
209    public boolean getToIndex(int index) {
210        return false;
211    }
212
213    // -----
214
215    public final void addAttribute(QualifiedName name, String value) {
216        if (_attributeCount == _names.length) {
217            resize();
218        }
219        _names[_attributeCount] = name;
220        _values[_attributeCount++] = value;
221    }
222
223    public final void addAttributeWithAlgorithmData(QualifiedName name, String URI, int id, Object data) {
224        if (_attributeCount == _names.length) {
225            resize();
226        }
227        _names[_attributeCount] = name;
228        _values[_attributeCount] = null;
229
230        _algorithmURIs[_attributeCount] = URI;
231        _algorithmIds[_attributeCount] = id;
232        _algorithmData[_attributeCount++] = data;
233    }
234
235    public final QualifiedName getQualifiedName(int index) {
236        return _names[index];
237    }
238
239    public final String getPrefix(int index) {
240        return _names[index].prefix;
241    }
242
243    private final void resize() {
244        final int newLength = _attributeCount * 3 / 2 + 1;
245
246        QualifiedName[] names = new QualifiedName[newLength];
247        String[] values = new String[newLength];
248
249        String[] algorithmURIs = new String[newLength];
250        int[] algorithmIds = new int[newLength];
251        Object[] algorithmData = new Object[newLength];
252
253        System.arraycopy(_names, 0, names, 0, _attributeCount);
254        System.arraycopy(_values, 0, values, 0, _attributeCount);
255
256        System.arraycopy(_algorithmURIs, 0, algorithmURIs, 0, _attributeCount);
257        System.arraycopy(_algorithmIds, 0, algorithmIds, 0, _attributeCount);
258        System.arraycopy(_algorithmData, 0, algorithmData, 0, _attributeCount);
259
260        _names = names;
261        _values = values;
262
263        _algorithmURIs = algorithmURIs;
264        _algorithmIds = algorithmIds;
265        _algorithmData = algorithmData;
266    }
267
268    private final StringBuffer convertEncodingAlgorithmDataToString(int identifier, String URI, Object data) throws FastInfosetException, IOException {
269        EncodingAlgorithm ea = null;
270        if (identifier < EncodingConstants.ENCODING_ALGORITHM_BUILTIN_END) {
271            ea = BuiltInEncodingAlgorithmFactory.getAlgorithm(identifier);
272        } else if (identifier == EncodingAlgorithmIndexes.CDATA) {
273            throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.CDATAAlgorithmNotSupported"));
274        } else if (identifier >= EncodingConstants.ENCODING_ALGORITHM_APPLICATION_START) {
275            if (URI == null) {
276                throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.URINotPresent") + identifier);
277            }
278
279            ea = (EncodingAlgorithm)_registeredEncodingAlgorithms.get(URI);
280            if (ea == null) {
281                throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.algorithmNotRegistered") + URI);
282            }
283        } else {
284            // Reserved built-in algorithms for future use
285            // TODO should use sax property to decide if event will be
286            // reported, allows for support through handler if required.
287            throw new EncodingAlgorithmException(CommonResourceBundle.getInstance().getString("message.identifiers10to31Reserved"));
288        }
289
290        final StringBuffer sb = new StringBuffer();
291        ea.convertToCharacters(data, sb);
292        return sb;
293    }
294
295}
296