1// Attributes2Impl.java - extended AttributesImpl
2// http://www.saxproject.org
3// Public Domain: no warranty.
4// $Id: Attributes2Impl.java,v 1.5 2004/03/08 13:01:01 dmegginson Exp $
5
6package org.xml.sax.ext;
7
8import org.xml.sax.Attributes;
9import org.xml.sax.helpers.AttributesImpl;
10
11
12/**
13 * SAX2 extension helper for additional Attributes information,
14 * implementing the {@link Attributes2} interface.
15 *
16 * <blockquote>
17 * <em>This module, both source code and documentation, is in the
18 * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
19 * </blockquote>
20 *
21 * <p>This is not part of core-only SAX2 distributions.</p>
22 *
23 * <p>The <em>specified</em> flag for each attribute will always
24 * be true, unless it has been set to false in the copy constructor
25 * or using {@link #setSpecified}.
26 * Similarly, the <em>declared</em> flag for each attribute will
27 * always be false, except for defaulted attributes (<em>specified</em>
28 * is false), non-CDATA attributes, or when it is set to true using
29 * {@link #setDeclared}.
30 * If you change an attribute's type by hand, you may need to modify
31 * its <em>declared</em> flag to match.
32 * </p>
33 *
34 * @since SAX 2.0 (extensions 1.1 alpha)
35 * @author David Brownell
36 * @version TBS
37 */
38public class Attributes2Impl extends AttributesImpl implements Attributes2
39{
40    private boolean    declared [];
41    private boolean    specified [];
42
43
44    /**
45     * Construct a new, empty Attributes2Impl object.
46     */
47    public Attributes2Impl () {
48        // BEGIN android-added
49        declared = new boolean[0];
50        specified = new boolean[0];
51        // END android-added
52    }
53
54
55    /**
56     * Copy an existing Attributes or Attributes2 object.
57     * If the object implements Attributes2, values of the
58     * <em>specified</em> and <em>declared</em> flags for each
59     * attribute are copied.
60     * Otherwise the flag values are defaulted to assume no DTD was used,
61     * unless there is evidence to the contrary (such as attributes with
62     * type other than CDATA, which must have been <em>declared</em>).
63     *
64     * <p>This constructor is especially useful inside a
65     * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
66     *
67     * @param atts The existing Attributes object.
68     */
69    public Attributes2Impl (Attributes atts)
70    {
71    super (atts);
72    }
73
74
75    ////////////////////////////////////////////////////////////////////
76    // Implementation of Attributes2
77    ////////////////////////////////////////////////////////////////////
78
79
80    /*
81     * Returns the current value of the attribute's "declared" flag.
82     */
83    // javadoc mostly from interface
84    public boolean isDeclared (int index)
85    {
86    if (index < 0 || index >= getLength ())
87        throw new ArrayIndexOutOfBoundsException (
88        "No attribute at index: " + index);
89    return declared [index];
90    }
91
92
93    /*
94     * Returns the current value of the attribute's "declared" flag.
95     */
96    // javadoc mostly from interface
97    public boolean isDeclared (String uri, String localName)
98    {
99    int index = getIndex (uri, localName);
100
101    if (index < 0)
102        throw new IllegalArgumentException (
103        "No such attribute: local=" + localName
104        + ", namespace=" + uri);
105    return declared [index];
106    }
107
108
109    /*
110     * Returns the current value of the attribute's "declared" flag.
111     */
112    // javadoc mostly from interface
113    public boolean isDeclared (String qName)
114    {
115    int index = getIndex (qName);
116
117    if (index < 0)
118        throw new IllegalArgumentException (
119        "No such attribute: " + qName);
120    return declared [index];
121    }
122
123
124    /**
125     * Returns the current value of an attribute's "specified" flag.
126     *
127     * @param index The attribute index (zero-based).
128     * @return current flag value
129     * @exception java.lang.ArrayIndexOutOfBoundsException When the
130     *            supplied index does not identify an attribute.
131     */
132    public boolean isSpecified (int index)
133    {
134    if (index < 0 || index >= getLength ())
135        throw new ArrayIndexOutOfBoundsException (
136        "No attribute at index: " + index);
137    return specified [index];
138    }
139
140
141    /**
142     * Returns the current value of an attribute's "specified" flag.
143     *
144     * @param uri The Namespace URI, or the empty string if
145     *        the name has no Namespace URI.
146     * @param localName The attribute's local name.
147     * @return current flag value
148     * @exception java.lang.IllegalArgumentException When the
149     *            supplied names do not identify an attribute.
150     */
151    public boolean isSpecified (String uri, String localName)
152    {
153    int index = getIndex (uri, localName);
154
155    if (index < 0)
156        throw new IllegalArgumentException (
157        "No such attribute: local=" + localName
158        + ", namespace=" + uri);
159    return specified [index];
160    }
161
162
163    /**
164     * Returns the current value of an attribute's "specified" flag.
165     *
166     * @param qName The XML qualified (prefixed) name.
167     * @return current flag value
168     * @exception java.lang.IllegalArgumentException When the
169     *            supplied name does not identify an attribute.
170     */
171    public boolean isSpecified (String qName)
172    {
173    int index = getIndex (qName);
174
175    if (index < 0)
176        throw new IllegalArgumentException (
177        "No such attribute: " + qName);
178    return specified [index];
179    }
180
181
182    ////////////////////////////////////////////////////////////////////
183    // Manipulators
184    ////////////////////////////////////////////////////////////////////
185
186
187    /**
188     * Copy an entire Attributes object.  The "specified" flags are
189     * assigned as true, and "declared" flags as false (except when
190     * an attribute's type is not CDATA),
191     * unless the object is an Attributes2 object.
192     * In that case those flag values are all copied.
193     *
194     * @param atts The attributes to copy.
195     *
196     * @see AttributesImpl#setAttributes
197     */
198    public void setAttributes (Attributes atts)
199    {
200    int length = atts.getLength ();
201
202    super.setAttributes (atts);
203    declared = new boolean [length];
204    specified = new boolean [length];
205
206    if (atts instanceof Attributes2) {
207        Attributes2    a2 = (Attributes2) atts;
208        for (int i = 0; i < length; i++) {
209        declared [i] = a2.isDeclared (i);
210        specified [i] = a2.isSpecified (i);
211        }
212    } else {
213        for (int i = 0; i < length; i++) {
214        declared [i] = !"CDATA".equals (atts.getType (i));
215        specified [i] = true;
216        }
217    }
218    }
219
220
221    /**
222     * Add an attribute to the end of the list, setting its
223     * "specified" flag to true.  To set that flag's value
224     * to false, use {@link #setSpecified}.
225     *
226     * <p>Unless the attribute <em>type</em> is CDATA, this attribute
227     * is marked as being declared in the DTD.  To set that flag's value
228     * to true for CDATA attributes, use {@link #setDeclared}.
229     *
230     * @param uri The Namespace URI, or the empty string if
231     *        none is available or Namespace processing is not
232     *        being performed.
233     * @param localName The local name, or the empty string if
234     *        Namespace processing is not being performed.
235     * @param qName The qualified (prefixed) name, or the empty string
236     *        if qualified names are not available.
237     * @param type The attribute type as a string.
238     * @param value The attribute value.
239     *
240     * @see AttributesImpl#addAttribute
241     */
242    public void addAttribute (String uri, String localName, String qName,
243                  String type, String value)
244    {
245    super.addAttribute (uri, localName, qName, type, value);
246
247    int length = getLength ();
248
249    // BEGIN android-changed
250    if (length > specified.length) {
251    // END android-changed
252        boolean    newFlags [];
253
254        newFlags = new boolean [length];
255        System.arraycopy (declared, 0, newFlags, 0, declared.length);
256        declared = newFlags;
257
258        newFlags = new boolean [length];
259        System.arraycopy (specified, 0, newFlags, 0, specified.length);
260        specified = newFlags;
261    }
262
263    specified [length - 1] = true;
264    declared [length - 1] = !"CDATA".equals (type);
265    }
266
267
268    // javadoc entirely from superclass
269    public void removeAttribute (int index)
270    {
271    int origMax = getLength () - 1;
272
273    super.removeAttribute (index);
274    if (index != origMax) {
275        System.arraycopy (declared, index + 1, declared, index,
276            origMax - index);
277        System.arraycopy (specified, index + 1, specified, index,
278            origMax - index);
279    }
280    }
281
282
283    /**
284     * Assign a value to the "declared" flag of a specific attribute.
285     * This is normally needed only for attributes of type CDATA,
286     * including attributes whose type is changed to or from CDATA.
287     *
288     * @param index The index of the attribute (zero-based).
289     * @param value The desired flag value.
290     * @exception java.lang.ArrayIndexOutOfBoundsException When the
291     *            supplied index does not identify an attribute.
292     * @see #setType
293     */
294    public void setDeclared (int index, boolean value)
295    {
296    if (index < 0 || index >= getLength ())
297        throw new ArrayIndexOutOfBoundsException (
298        "No attribute at index: " + index);
299    declared [index] = value;
300    }
301
302
303    /**
304     * Assign a value to the "specified" flag of a specific attribute.
305     * This is the only way this flag can be cleared, except clearing
306     * by initialization with the copy constructor.
307     *
308     * @param index The index of the attribute (zero-based).
309     * @param value The desired flag value.
310     * @exception java.lang.ArrayIndexOutOfBoundsException When the
311     *            supplied index does not identify an attribute.
312     */
313    public void setSpecified (int index, boolean value)
314    {
315    if (index < 0 || index >= getLength ())
316        throw new ArrayIndexOutOfBoundsException (
317        "No attribute at index: " + index);
318    specified [index] = value;
319    }
320}
321