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