update of javajs package; adds org.apache.harmony, org.xml.sax.helpers
[jalview.git] / src / org / xml / sax / helpers / AttributesImpl.java
1 // AttributesImpl.java - default implementation of Attributes.
2 // http://www.saxproject.org
3 // Written by David Megginson
4 // NO WARRANTY!  This class is in the public domain.
5 // $Id: AttributesImpl.java,v 1.9 2002/01/30 20:52:24 dbrownell Exp $
6
7 package org.xml.sax.helpers;
8
9 import org.xml.sax.Attributes;
10
11
12 /**
13  * Default implementation of the Attributes interface.
14  *
15  * <blockquote>
16  * <em>This module, both source code and documentation, is in the
17  * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
18  * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
19  * for further information.
20  * </blockquote>
21  *
22  * <p>This class provides a default implementation of the SAX2
23  * {@link org.xml.sax.Attributes Attributes} interface, with the 
24  * addition of manipulators so that the list can be modified or 
25  * reused.</p>
26  *
27  * <p>There are two typical uses of this class:</p>
28  *
29  * <ol>
30  * <li>to take a persistent snapshot of an Attributes object
31  *  in a {@link org.xml.sax.ContentHandler#startElement startElement} event; or</li>
32  * <li>to construct or modify an Attributes object in a SAX2 driver or filter.</li>
33  * </ol>
34  *
35  * <p>This class replaces the now-deprecated SAX1 {@link 
36  * org.xml.sax.helpers.AttributeListImpl AttributeListImpl}
37  * class; in addition to supporting the updated Attributes
38  * interface rather than the deprecated {@link org.xml.sax.AttributeList
39  * AttributeList} interface, it also includes a much more efficient 
40  * implementation using a single array rather than a set of Vectors.</p>
41  *
42  * @since SAX 2.0
43  * @author David Megginson
44  * @version 2.0.1 (sax2r2)
45  */
46 public class AttributesImpl implements Attributes
47 {
48
49 \f
50     ////////////////////////////////////////////////////////////////////
51     // Constructors.
52     ////////////////////////////////////////////////////////////////////
53
54
55     /**
56      * Construct a new, empty AttributesImpl object.
57      */
58     public AttributesImpl ()
59     {
60         length = 0;
61         data = null;
62     }
63
64
65     /**
66      * Copy an existing Attributes object.
67      *
68      * <p>This constructor is especially useful inside a
69      * {@link org.xml.sax.ContentHandler#startElement startElement} event.</p>
70      *
71      * @param atts The existing Attributes object.
72      */
73     public AttributesImpl (Attributes atts)
74     {
75         setAttributes(atts);
76     }
77
78
79 \f
80     ////////////////////////////////////////////////////////////////////
81     // Implementation of org.xml.sax.Attributes.
82     ////////////////////////////////////////////////////////////////////
83
84
85     /**
86      * Return the number of attributes in the list.
87      *
88      * @return The number of attributes in the list.
89      * @see org.xml.sax.Attributes#getLength
90      */
91     @Override
92                 public int getLength ()
93     {
94         return length;
95     }
96
97
98     /**
99      * Return an attribute's Namespace URI.
100      *
101      * @param index The attribute's index (zero-based).
102      * @return The Namespace URI, the empty string if none is
103      *         available, or null if the index is out of range.
104      * @see org.xml.sax.Attributes#getURI
105      */
106     @Override
107                 public String getURI (int index)
108     {
109         if (index >= 0 && index < length) {
110             return data[index*5];
111         } else {
112             return null;
113         }
114     }
115
116
117     /**
118      * Return an attribute's local name.
119      *
120      * @param index The attribute's index (zero-based).
121      * @return The attribute's local name, the empty string if 
122      *         none is available, or null if the index if out of range.
123      * @see org.xml.sax.Attributes#getLocalName
124      */
125     @Override
126                 public String getLocalName (int index)
127     {
128         if (index >= 0 && index < length) {
129             return data[index*5+1];
130         } else {
131             return null;
132         }
133     }
134
135
136     /**
137      * Return an attribute's qualified (prefixed) name.
138      *
139      * @param index The attribute's index (zero-based).
140      * @return The attribute's qualified name, the empty string if 
141      *         none is available, or null if the index is out of bounds.
142      * @see org.xml.sax.Attributes#getQName
143      */
144     @Override
145                 public String getQName (int index)
146     {
147         if (index >= 0 && index < length) {
148             return data[index*5+2];
149         } else {
150             return null;
151         }
152     }
153
154
155     /**
156      * Return an attribute's type by index.
157      *
158      * @param index The attribute's index (zero-based).
159      * @return The attribute's type, "CDATA" if the type is unknown, or null
160      *         if the index is out of bounds.
161      * @see org.xml.sax.Attributes#getType(int)
162      */
163     @Override
164                 public String getType (int index)
165     {
166         if (index >= 0 && index < length) {
167             return data[index*5+3];
168         } else {
169             return null;
170         }
171     }
172
173
174     /**
175      * Return an attribute's value by index.
176      *
177      * @param index The attribute's index (zero-based).
178      * @return The attribute's value or null if the index is out of bounds.
179      * @see org.xml.sax.Attributes#getValue(int)
180      */
181     @Override
182                 public String getValue (int index)
183     {
184         if (index >= 0 && index < length) {
185             return data[index*5+4];
186         } else {
187             return null;
188         }
189     }
190
191
192     /**
193      * Look up an attribute's index by Namespace name.
194      *
195      * <p>In many cases, it will be more efficient to look up the name once and
196      * use the index query methods rather than using the name query methods
197      * repeatedly.</p>
198      *
199      * @param uri The attribute's Namespace URI, or the empty
200      *        string if none is available.
201      * @param localName The attribute's local name.
202      * @return The attribute's index, or -1 if none matches.
203      * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
204      */
205     @Override
206                 public int getIndex (String uri, String localName)
207     {
208         int max = length * 5;
209         for (int i = 0; i < max; i += 5) {
210             if (data[i].equals(uri) && data[i+1].equals(localName)) {
211                 return i / 5;
212             }
213         } 
214         return -1;
215     }
216
217
218     /**
219      * Look up an attribute's index by qualified (prefixed) name.
220      *
221      * @param qName The qualified name.
222      * @return The attribute's index, or -1 if none matches.
223      * @see org.xml.sax.Attributes#getIndex(java.lang.String)
224      */
225     @Override
226                 public int getIndex (String qName)
227     {
228         int max = length * 5;
229         for (int i = 0; i < max; i += 5) {
230             if (data[i+2].equals(qName)) {
231                 return i / 5;
232             }
233         } 
234         return -1;
235     }
236
237
238     /**
239      * Look up an attribute's type by Namespace-qualified name.
240      *
241      * @param uri The Namespace URI, or the empty string for a name
242      *        with no explicit Namespace URI.
243      * @param localName The local name.
244      * @return The attribute's type, or null if there is no
245      *         matching attribute.
246      * @see org.xml.sax.Attributes#getType(java.lang.String,java.lang.String)
247      */
248     @Override
249                 public String getType (String uri, String localName)
250     {
251         int max = length * 5;
252         for (int i = 0; i < max; i += 5) {
253             if (data[i].equals(uri) && data[i+1].equals(localName)) {
254                 return data[i+3];
255             }
256         } 
257         return null;
258     }
259
260
261     /**
262      * Look up an attribute's type by qualified (prefixed) name.
263      *
264      * @param qName The qualified name.
265      * @return The attribute's type, or null if there is no
266      *         matching attribute.
267      * @see org.xml.sax.Attributes#getType(java.lang.String)
268      */
269     @Override
270                 public String getType (String qName)
271     {
272         int max = length * 5;
273         for (int i = 0; i < max; i += 5) {
274             if (data[i+2].equals(qName)) {
275                 return data[i+3];
276             }
277         }
278         return null;
279     }
280
281
282     /**
283      * Look up an attribute's value by Namespace-qualified name.
284      *
285      * @param uri The Namespace URI, or the empty string for a name
286      *        with no explicit Namespace URI.
287      * @param localName The local name.
288      * @return The attribute's value, or null if there is no
289      *         matching attribute.
290      * @see org.xml.sax.Attributes#getValue(java.lang.String,java.lang.String)
291      */
292     @Override
293                 public String getValue (String uri, String localName)
294     {
295         int max = length * 5;
296         for (int i = 0; i < max; i += 5) {
297             if (data[i].equals(uri) && data[i+1].equals(localName)) {
298                 return data[i+4];
299             }
300         }
301         return null;
302     }
303
304
305     /**
306      * Look up an attribute's value by qualified (prefixed) name.
307      *
308      * @param qName The qualified name.
309      * @return The attribute's value, or null if there is no
310      *         matching attribute.
311      * @see org.xml.sax.Attributes#getValue(java.lang.String)
312      */
313     @Override
314                 public String getValue (String qName)
315     {
316         int max = length * 5;
317         for (int i = 0; i < max; i += 5) {
318             if (data[i+2].equals(qName)) {
319                 return data[i+4];
320             }
321         }
322         return null;
323     }
324
325
326 \f
327     ////////////////////////////////////////////////////////////////////
328     // Manipulators.
329     ////////////////////////////////////////////////////////////////////
330
331
332     /**
333      * Clear the attribute list for reuse.
334      *
335      * <p>Note that little memory is freed by this call:
336      * the current array is kept so it can be 
337      * reused.</p>
338      */
339     public void clear ()
340     {
341         if (data != null) {
342             for (int i = 0; i < (length * 5); i++)
343                 data [i] = null;
344         }
345         length = 0;
346     }
347
348
349     /**
350      * Copy an entire Attributes object.
351      *
352      * <p>It may be more efficient to reuse an existing object
353      * rather than constantly allocating new ones.</p>
354      * 
355      * @param atts The attributes to copy.
356      */
357     public void setAttributes (Attributes atts)
358     {
359         clear();
360         length = atts.getLength();
361         if (length > 0) {
362             data = new String[length*5];
363             for (int i = 0; i < length; i++) {
364                 data[i*5] = atts.getURI(i);
365                 data[i*5+1] = atts.getLocalName(i);
366                 data[i*5+2] = atts.getQName(i);
367                 data[i*5+3] = atts.getType(i);
368                 data[i*5+4] = atts.getValue(i);
369             }
370         }
371     }
372
373
374     /**
375      * Add an attribute to the end of the list.
376      *
377      * <p>For the sake of speed, this method does no checking
378      * to see if the attribute is already in the list: that is
379      * the responsibility of the application.</p>
380      *
381      * @param uri The Namespace URI, or the empty string if
382      *        none is available or Namespace processing is not
383      *        being performed.
384      * @param localName The local name, or the empty string if
385      *        Namespace processing is not being performed.
386      * @param qName The qualified (prefixed) name, or the empty string
387      *        if qualified names are not available.
388      * @param type The attribute type as a string.
389      * @param value The attribute value.
390      */
391     public void addAttribute (String uri, String localName, String qName,
392                               String type, String value)
393     {
394         ensureCapacity(length+1);
395         data[length*5] = uri;
396         data[length*5+1] = localName;
397         data[length*5+2] = qName;
398         data[length*5+3] = type;
399         data[length*5+4] = value;
400         length++;
401     }
402
403
404     /**
405      * Set an attribute in the list.
406      *
407      * <p>For the sake of speed, this method does no checking
408      * for name conflicts or well-formedness: such checks are the
409      * responsibility of the application.</p>
410      *
411      * @param index The index of the attribute (zero-based).
412      * @param uri The Namespace URI, or the empty string if
413      *        none is available or Namespace processing is not
414      *        being performed.
415      * @param localName The local name, or the empty string if
416      *        Namespace processing is not being performed.
417      * @param qName The qualified name, or the empty string
418      *        if qualified names are not available.
419      * @param type The attribute type as a string.
420      * @param value The attribute value.
421      * @exception java.lang.ArrayIndexOutOfBoundsException When the
422      *            supplied index does not point to an attribute
423      *            in the list.
424      */
425     public void setAttribute (int index, String uri, String localName,
426                               String qName, String type, String value)
427     {
428         if (index >= 0 && index < length) {
429             data[index*5] = uri;
430             data[index*5+1] = localName;
431             data[index*5+2] = qName;
432             data[index*5+3] = type;
433             data[index*5+4] = value;
434         } else {
435             badIndex(index);
436         }
437     }
438
439
440     /**
441      * Remove an attribute from the list.
442      *
443      * @param index The index of the attribute (zero-based).
444      * @exception java.lang.ArrayIndexOutOfBoundsException When the
445      *            supplied index does not point to an attribute
446      *            in the list.
447      */
448     public void removeAttribute (int index)
449     {
450         if (index >= 0 && index < length) {
451             if (index < length - 1) {
452                 System.arraycopy(data, (index+1)*5, data, index*5,
453                                  (length-index-1)*5);
454             }
455             index = (length - 1) * 5;
456             data [index++] = null;
457             data [index++] = null;
458             data [index++] = null;
459             data [index++] = null;
460             data [index] = null;
461             length--;
462         } else {
463             badIndex(index);
464         }
465     }
466
467
468     /**
469      * Set the Namespace URI of a specific attribute.
470      *
471      * @param index The index of the attribute (zero-based).
472      * @param uri The attribute's Namespace URI, or the empty
473      *        string for none.
474      * @exception java.lang.ArrayIndexOutOfBoundsException When the
475      *            supplied index does not point to an attribute
476      *            in the list.
477      */
478     public void setURI (int index, String uri)
479     {
480         if (index >= 0 && index < length) {
481             data[index*5] = uri;
482         } else {
483             badIndex(index);
484         }
485     }
486
487
488     /**
489      * Set the local name of a specific attribute.
490      *
491      * @param index The index of the attribute (zero-based).
492      * @param localName The attribute's local name, or the empty
493      *        string for none.
494      * @exception java.lang.ArrayIndexOutOfBoundsException When the
495      *            supplied index does not point to an attribute
496      *            in the list.
497      */
498     public void setLocalName (int index, String localName)
499     {
500         if (index >= 0 && index < length) {
501             data[index*5+1] = localName;
502         } else {
503             badIndex(index);
504         }
505     }
506
507
508     /**
509      * Set the qualified name of a specific attribute.
510      *
511      * @param index The index of the attribute (zero-based).
512      * @param qName The attribute's qualified name, or the empty
513      *        string for none.
514      * @exception java.lang.ArrayIndexOutOfBoundsException When the
515      *            supplied index does not point to an attribute
516      *            in the list.
517      */
518     public void setQName (int index, String qName)
519     {
520         if (index >= 0 && index < length) {
521             data[index*5+2] = qName;
522         } else {
523             badIndex(index);
524         }
525     }
526
527
528     /**
529      * Set the type of a specific attribute.
530      *
531      * @param index The index of the attribute (zero-based).
532      * @param type The attribute's type.
533      * @exception java.lang.ArrayIndexOutOfBoundsException When the
534      *            supplied index does not point to an attribute
535      *            in the list.
536      */
537     public void setType (int index, String type)
538     {
539         if (index >= 0 && index < length) {
540             data[index*5+3] = type;
541         } else {
542             badIndex(index);
543         }
544     }
545
546
547     /**
548      * Set the value of a specific attribute.
549      *
550      * @param index The index of the attribute (zero-based).
551      * @param value The attribute's value.
552      * @exception java.lang.ArrayIndexOutOfBoundsException When the
553      *            supplied index does not point to an attribute
554      *            in the list.
555      */
556     public void setValue (int index, String value)
557     {
558         if (index >= 0 && index < length) {
559             data[index*5+4] = value;
560         } else {
561             badIndex(index);
562         }
563     }
564
565
566 \f
567     ////////////////////////////////////////////////////////////////////
568     // Internal methods.
569     ////////////////////////////////////////////////////////////////////
570
571
572     /**
573      * Ensure the internal array's capacity.
574      *
575      * @param n The minimum number of attributes that the array must
576      *        be able to hold.
577      */
578     private void ensureCapacity (int n)    {
579         if (n <= 0) {
580             return;
581         }
582         int max;
583         if (data == null || data.length == 0) {
584             max = 25;
585         }
586         else if (data.length >= n * 5) {
587             return;
588         }
589         else {
590             max = data.length;
591         }
592         while (max < n * 5) {
593             max *= 2;
594         }
595
596         String newData[] = new String[max];
597         if (length > 0) {
598             System.arraycopy(data, 0, newData, 0, length*5);
599         }
600         data = newData;
601     }
602
603
604     /**
605      * Report a bad array index in a manipulator.
606      *
607      * @param index The index to report.
608      * @exception java.lang.ArrayIndexOutOfBoundsException Always.
609      */
610     private void badIndex (int index)
611         throws ArrayIndexOutOfBoundsException
612     {
613         String msg =
614             "Attempt to modify attribute at illegal index: " + index;
615         throw new ArrayIndexOutOfBoundsException(msg);
616     }
617
618
619 \f
620     ////////////////////////////////////////////////////////////////////
621     // Internal state.
622     ////////////////////////////////////////////////////////////////////
623
624     int length;
625     String data [];
626
627 }
628
629 // end of AttributesImpl.java
630