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 libcore.util.EmptyArray;
9import org.xml.sax.Attributes;
10import org.xml.sax.helpers.AttributesImpl;
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        declared = EmptyArray.BOOLEAN;
49        specified = EmptyArray.BOOLEAN;
50    }
51
52
53    /**
54     * Copy an existing Attributes or Attributes2 object.
55     * If the object implements Attributes2, values of the
56     * <em>specified</em> and <em>declared</em> flags for each
57     * attribute are copied.
58     * Otherwise the flag values are defaulted to assume no DTD was used,
59     * unless there is evidence to the contrary (such as attributes with
60     * type other than CDATA, which must have been <em>declared</em>).
61     *
62     * <p>This constructor is especially useful inside a
63     * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
64     *
65     * @param atts The existing Attributes object.
66     */
67    public Attributes2Impl (Attributes atts)
68    {
69    super (atts);
70    }
71
72
73    ////////////////////////////////////////////////////////////////////
74    // Implementation of Attributes2
75    ////////////////////////////////////////////////////////////////////
76
77
78    /*
79     * Returns the current value of the attribute's "declared" flag.
80     */
81    // javadoc mostly from interface
82    public boolean isDeclared (int index)
83    {
84    if (index < 0 || index >= getLength ())
85        throw new ArrayIndexOutOfBoundsException (
86        "No attribute at index: " + index);
87    return declared [index];
88    }
89
90
91    /*
92     * Returns the current value of the attribute's "declared" flag.
93     */
94    // javadoc mostly from interface
95    public boolean isDeclared (String uri, String localName)
96    {
97    int index = getIndex (uri, localName);
98
99    if (index < 0)
100        throw new IllegalArgumentException (
101        "No such attribute: local=" + localName
102        + ", namespace=" + uri);
103    return declared [index];
104    }
105
106
107    /*
108     * Returns the current value of the attribute's "declared" flag.
109     */
110    // javadoc mostly from interface
111    public boolean isDeclared (String qName)
112    {
113    int index = getIndex (qName);
114
115    if (index < 0)
116        throw new IllegalArgumentException (
117        "No such attribute: " + qName);
118    return declared [index];
119    }
120
121
122    /**
123     * Returns the current value of an attribute's "specified" flag.
124     *
125     * @param index The attribute index (zero-based).
126     * @return current flag value
127     * @exception java.lang.ArrayIndexOutOfBoundsException When the
128     *            supplied index does not identify an attribute.
129     */
130    public boolean isSpecified (int index)
131    {
132    if (index < 0 || index >= getLength ())
133        throw new ArrayIndexOutOfBoundsException (
134        "No attribute at index: " + index);
135    return specified [index];
136    }
137
138
139    /**
140     * Returns the current value of an attribute's "specified" flag.
141     *
142     * @param uri The Namespace URI, or the empty string if
143     *        the name has no Namespace URI.
144     * @param localName The attribute's local name.
145     * @return current flag value
146     * @exception java.lang.IllegalArgumentException When the
147     *            supplied names do not identify an attribute.
148     */
149    public boolean isSpecified (String uri, String localName)
150    {
151    int index = getIndex (uri, localName);
152
153    if (index < 0)
154        throw new IllegalArgumentException (
155        "No such attribute: local=" + localName
156        + ", namespace=" + uri);
157    return specified [index];
158    }
159
160
161    /**
162     * Returns the current value of an attribute's "specified" flag.
163     *
164     * @param qName The XML qualified (prefixed) name.
165     * @return current flag value
166     * @exception java.lang.IllegalArgumentException When the
167     *            supplied name does not identify an attribute.
168     */
169    public boolean isSpecified (String qName)
170    {
171    int index = getIndex (qName);
172
173    if (index < 0)
174        throw new IllegalArgumentException (
175        "No such attribute: " + qName);
176    return specified [index];
177    }
178
179
180    ////////////////////////////////////////////////////////////////////
181    // Manipulators
182    ////////////////////////////////////////////////////////////////////
183
184
185    /**
186     * Copy an entire Attributes object.  The "specified" flags are
187     * assigned as true, and "declared" flags as false (except when
188     * an attribute's type is not CDATA),
189     * unless the object is an Attributes2 object.
190     * In that case those flag values are all copied.
191     *
192     * @param atts The attributes to copy.
193     *
194     * @see AttributesImpl#setAttributes
195     */
196    public void setAttributes (Attributes atts)
197    {
198    int length = atts.getLength ();
199
200    super.setAttributes (atts);
201    declared = new boolean [length];
202    specified = new boolean [length];
203
204    if (atts instanceof Attributes2) {
205        Attributes2    a2 = (Attributes2) atts;
206        for (int i = 0; i < length; i++) {
207        declared [i] = a2.isDeclared (i);
208        specified [i] = a2.isSpecified (i);
209        }
210    } else {
211        for (int i = 0; i < length; i++) {
212        declared [i] = !"CDATA".equals (atts.getType (i));
213        specified [i] = true;
214        }
215    }
216    }
217
218
219    /**
220     * Add an attribute to the end of the list, setting its
221     * "specified" flag to true.  To set that flag's value
222     * to false, use {@link #setSpecified}.
223     *
224     * <p>Unless the attribute <em>type</em> is CDATA, this attribute
225     * is marked as being declared in the DTD.  To set that flag's value
226     * to true for CDATA attributes, use {@link #setDeclared}.
227     *
228     * @param uri The Namespace URI, or the empty string if
229     *        none is available or Namespace processing is not
230     *        being performed.
231     * @param localName The local name, or the empty string if
232     *        Namespace processing is not being performed.
233     * @param qName The qualified (prefixed) name, or the empty string
234     *        if qualified names are not available.
235     * @param type The attribute type as a string.
236     * @param value The attribute value.
237     *
238     * @see AttributesImpl#addAttribute
239     */
240    public void addAttribute (String uri, String localName, String qName,
241                  String type, String value)
242    {
243    super.addAttribute (uri, localName, qName, type, value);
244
245    int length = getLength ();
246
247    if (length > specified.length) {
248        boolean[] newFlags = new boolean [length];
249        System.arraycopy (declared, 0, newFlags, 0, declared.length);
250        declared = newFlags;
251
252        newFlags = new boolean [length];
253        System.arraycopy (specified, 0, newFlags, 0, specified.length);
254        specified = newFlags;
255    }
256
257    specified [length - 1] = true;
258    declared [length - 1] = !"CDATA".equals (type);
259    }
260
261
262    // javadoc entirely from superclass
263    public void removeAttribute (int index)
264    {
265    int origMax = getLength () - 1;
266
267    super.removeAttribute (index);
268    if (index != origMax) {
269        System.arraycopy (declared, index + 1, declared, index,
270            origMax - index);
271        System.arraycopy (specified, index + 1, specified, index,
272            origMax - index);
273    }
274    }
275
276
277    /**
278     * Assign a value to the "declared" flag of a specific attribute.
279     * This is normally needed only for attributes of type CDATA,
280     * including attributes whose type is changed to or from CDATA.
281     *
282     * @param index The index of the attribute (zero-based).
283     * @param value The desired flag value.
284     * @exception java.lang.ArrayIndexOutOfBoundsException When the
285     *            supplied index does not identify an attribute.
286     * @see #setType
287     */
288    public void setDeclared (int index, boolean value)
289    {
290    if (index < 0 || index >= getLength ())
291        throw new ArrayIndexOutOfBoundsException (
292        "No attribute at index: " + index);
293    declared [index] = value;
294    }
295
296
297    /**
298     * Assign a value to the "specified" flag of a specific attribute.
299     * This is the only way this flag can be cleared, except clearing
300     * by initialization with the copy constructor.
301     *
302     * @param index The index of the attribute (zero-based).
303     * @param value The desired flag value.
304     * @exception java.lang.ArrayIndexOutOfBoundsException When the
305     *            supplied index does not identify an attribute.
306     */
307    public void setSpecified (int index, boolean value)
308    {
309    if (index < 0 || index >= getLength ())
310        throw new ArrayIndexOutOfBoundsException (
311        "No attribute at index: " + index);
312    specified [index] = value;
313    }
314}
315