001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999,2000 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058: package org.apache.xerces.framework;
059:
060: import org.apache.xerces.utils.QName;
061: import org.apache.xerces.utils.StringPool;
062:
063: import org.xml.sax.AttributeList;
064: import org.xml.sax.Locator;
065: import org.xml.sax.SAXParseException;
066:
067: /**
068: * An instance of this class is used to represent the set of attributes
069: * for an element that are either directly specified or provided through
070: * a default value in the grammar for the document. XMLAttrList carries
071: * the attributes associated with an element from the scanner up to the
072: * application level (via the SAX AtributeList). Because all the attributes
073: * are bundled up together before being presented to the application, we don't
074: * have a way to build up an attribute value from pieces, most notably entity
075: * references.
076: * <p>
077: * There is typically one instance of this class for each instance of a
078: * parser. The parser may either use this object to hold the attributes
079: * of a single element, calling releaseAttrList() before each new element,
080: * or it may use this object to hold the attributes of all of the elements
081: * in the document.
082: * <p>
083: * To start saving a new set of attributes, the startAttrList() method is
084: * called, returning a handle for the attribute list. All addAttr() calls
085: * will be added to the set until a call is made to endAttrList(). A handle
086: * of -1 is used to indicate that there are no attributes in the set.
087: * <p>
088: * When an attribute is added to the set, the type of the attribute and an
089: * indicator of whether it was specified explicitly or through a default is
090: * provided.
091: * <p>
092: * The attributes in the set may be accessed either through the getFirstAttr()
093: * and getNextAttr() iteration interface, or the getAttributeList() method
094: * may be used to access the attribute list through the SAX <code>AttributeList</code>
095: * interface.
096: *
097: * @version $Id: XMLAttrList.java,v 1.10 2001/07/20 17:26:10 lmartin Exp $
098: */
099: public final class XMLAttrList implements AttributeList {
100:
101: //
102: // Constants
103: //
104:
105: // Chunk size constants
106:
107: private static final int CHUNK_SHIFT = 5; // 2^5 = 32
108: private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
109: private static final int CHUNK_MASK = CHUNK_SIZE - 1;
110: private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k
111:
112: // Flags (bits)
113:
114: private static final int ATTFLAG_SPECIFIED = 1;
115: private static final int ATTFLAG_LASTATTR = 2;
116: private static final int ATTFLAG_NEEDSEARCH = 4;
117:
118: //
119: // Data
120: //
121:
122: // Instance variables
123:
124: private StringPool fStringPool = null;
125: private int fCurrentHandle = -1;
126: private int fAttributeListHandle = -1;
127: private int fAttributeListLength = 0;
128: private int fAttrCount = 0;
129: private int[][] fAttPrefix = new int[INITIAL_CHUNK_COUNT][];
130: private int[][] fAttLocalpart = new int[INITIAL_CHUNK_COUNT][];
131: private int[][] fAttName = new int[INITIAL_CHUNK_COUNT][];
132: private int[][] fAttURI = new int[INITIAL_CHUNK_COUNT][];
133: private int[][] fAttValue = new int[INITIAL_CHUNK_COUNT][];
134: private int[][] fAttType = new int[INITIAL_CHUNK_COUNT][];
135: private byte[][] fAttFlags = new byte[INITIAL_CHUNK_COUNT][];
136:
137: // utility
138:
139: private QName fAttributeQName = new QName();
140:
141: /**
142: * Constructor
143: *
144: * @param stringPool The string pool instance to use.
145: */
146: public XMLAttrList(StringPool stringPool) {
147: fStringPool = stringPool;
148: }
149:
150: /**
151: * Reset this instance to an "empty" state.
152: *
153: * @param stringPool The string pool instance to use.
154: */
155: public void reset(StringPool stringPool) {
156: fStringPool = stringPool;
157: fCurrentHandle = -1;
158: fAttributeListHandle = -1;
159: fAttributeListLength = 0;
160: fAttrCount = 0;
161: }
162:
163: public int addAttr(int attrName, int attValue, int attType,
164: boolean specified, boolean search) throws Exception {
165: fAttributeQName.setValues(-1, attrName, attrName);
166: return addAttr(fAttributeQName, attValue, attType, specified,
167: search);
168: }
169:
170: /**
171: * Add an attribute to the current set.
172: *
173: * @param attrName The name of the attribute, an index in the string pool.
174: * @param attValue The value of the attribute, an index in the string pool.
175: * @param attType The type of the attribute, an index in the string pool.
176: * @param specified <code>true</code> if the attribute is specified directly; otherwise
177: * <code>false</code> is the attribute is provided through a default.
178: * @param search <code>true</code> if the list should be searched for a duplicate.
179: * @return The index of this attribute; or -1 is <code>search</code> was <code>true</code>
180: * and <code>attrName</code> was already present.
181: */
182: public int addAttr(QName attribute, int attValue, int attType,
183: boolean specified, boolean search) throws Exception {
184:
185: int chunk;
186: int index;
187: if (search) {
188: chunk = fCurrentHandle >> CHUNK_SHIFT;
189: index = fCurrentHandle & CHUNK_MASK;
190: for (int attrIndex = fCurrentHandle; attrIndex < fAttrCount; attrIndex++) {
191: // check on rawname, as required by XML1.0
192: // we check qname later in endAttrList
193: if (fStringPool.equalNames(fAttName[chunk][index],
194: attribute.rawname)) {
195: return -1;
196: }
197: if (++index == CHUNK_SIZE) {
198: chunk++;
199: index = 0;
200: }
201: }
202: } else {
203: chunk = fAttrCount >> CHUNK_SHIFT;
204: index = fAttrCount & CHUNK_MASK;
205: }
206:
207: ensureCapacity(chunk, index);
208: fAttPrefix[chunk][index] = attribute.prefix;
209: fAttLocalpart[chunk][index] = attribute.localpart;
210: fAttName[chunk][index] = attribute.rawname;
211: fAttURI[chunk][index] = attribute.uri;
212: fAttValue[chunk][index] = attValue;
213: fAttType[chunk][index] = attType;
214: fAttFlags[chunk][index] = (byte) ((specified ? ATTFLAG_SPECIFIED
215: : 0) | (search ? ATTFLAG_NEEDSEARCH : 0));
216: return fAttrCount++;
217:
218: } // addAttr(QName,int,int,boolean,boolean):int
219:
220: /**
221: * Start a new set of attributes.
222: *
223: * @return The handle for the new set of attributes.
224: */
225: public int startAttrList() {
226: fCurrentHandle = fAttrCount;
227: return fCurrentHandle;
228: }
229:
230: /**
231: * Terminate the current set of attributes.
232: */
233: public int[] endAttrList() {
234: if (fCurrentHandle == -1)
235: return null;
236: int oldHandle = fCurrentHandle;
237:
238: int attrIndex = fAttrCount - 1;
239: int chunk = attrIndex >> CHUNK_SHIFT;
240: int index = attrIndex & CHUNK_MASK;
241: fAttFlags[chunk][index] |= ATTFLAG_LASTATTR;
242: fCurrentHandle = -1;
243:
244: int dupCount = 0;
245: int dupNames[] = null;
246:
247: int attrIndex1 = oldHandle + 1, attrIndex2;
248: int chunk1 = attrIndex1 >> CHUNK_SHIFT;
249: int index1 = attrIndex1 & CHUNK_MASK;
250: int chunk2, index2;
251: for (; attrIndex1 < fAttrCount; attrIndex1++) {
252: if ((fAttFlags[chunk1][index1] & ATTFLAG_NEEDSEARCH) == 0)
253: continue;
254: chunk2 = chunk1;
255: index2 = index1;
256: for (attrIndex2 = oldHandle; attrIndex2 < attrIndex1; attrIndex2++) {
257: if (--index2 == -1) {
258: chunk2--;
259: index2 = CHUNK_SIZE - 1;
260: }
261: if (fStringPool.equalNames(fAttURI[chunk1][index1],
262: fAttURI[chunk2][index2])
263: && fStringPool.equalNames(
264: fAttLocalpart[chunk1][index1],
265: fAttLocalpart[chunk2][index2])) {
266: if (dupCount == 0)
267: dupNames = new int[fAttrCount - oldHandle];
268: dupNames[dupCount++] = fAttName[chunk1][index1];
269: }
270: }
271: if (++index1 == CHUNK_SIZE) {
272: chunk1++;
273: index1 = 0;
274: }
275: }
276:
277: if (dupCount > 0) {
278: int[] names = new int[dupCount];
279: System.arraycopy(dupNames, 0, names, 0, dupCount);
280: dupNames = names;
281: }
282:
283: return dupNames;
284: }
285:
286: /**
287: * Get the prefix of the attribute.
288: */
289: public int getAttrPrefix(int attrIndex) {
290: if (attrIndex < 0 || attrIndex >= fAttrCount)
291: return -1;
292: int chunk = attrIndex >> CHUNK_SHIFT;
293: int index = attrIndex & CHUNK_MASK;
294: return fAttPrefix[chunk][index];
295: }
296:
297: /**
298: * Return the localpart of the attribute.
299: */
300: public int getAttrLocalpart(int attrIndex) {
301: if (attrIndex < 0 || attrIndex >= fAttrCount)
302: return -1;
303: int chunk = attrIndex >> CHUNK_SHIFT;
304: int index = attrIndex & CHUNK_MASK;
305: return fAttLocalpart[chunk][index];
306: }
307:
308: // REVISIT: Should this be renamed "getAttrRawname" to match?
309: /**
310: * Get the name of the attribute
311: *
312: * @param attrIndex The index of the attribute.
313: * @return The name of the attribute, an index in the string pool.
314: */
315: public int getAttrName(int attrIndex) {
316: if (attrIndex < 0 || attrIndex >= fAttrCount)
317: return -1;
318: int chunk = attrIndex >> CHUNK_SHIFT;
319: int index = attrIndex & CHUNK_MASK;
320: return fAttName[chunk][index];
321: }
322:
323: /** Sets the uri of the attribute. */
324: public void setAttrURI(int attrIndex, int uri) {
325: if (attrIndex < 0 || attrIndex >= fAttrCount)
326: return;
327: int chunk = attrIndex >> CHUNK_SHIFT;
328: int index = attrIndex & CHUNK_MASK;
329: fAttURI[chunk][index] = uri;
330: }
331:
332: /** Return the uri of the attribute. */
333: public int getAttrURI(int attrIndex) {
334: if (attrIndex < 0 || attrIndex >= fAttrCount)
335: return -1;
336: int chunk = attrIndex >> CHUNK_SHIFT;
337: int index = attrIndex & CHUNK_MASK;
338: return fAttURI[chunk][index];
339: }
340:
341: /**
342: * Get the value of the attribute
343: *
344: * @param attrIndex The index of the attribute.
345: * @return The value of the attribute, an index in the string pool.
346: */
347: public int getAttValue(int attrIndex) {
348: if (attrIndex < 0 || attrIndex >= fAttrCount)
349: return -1;
350: int chunk = attrIndex >> CHUNK_SHIFT;
351: int index = attrIndex & CHUNK_MASK;
352: return fAttValue[chunk][index];
353: }
354:
355: /**
356: * Sets the value of the attribute.
357: */
358: public void setAttValue(int attrIndex, int attrValue) {
359: if (attrIndex < 0 || attrIndex >= fAttrCount)
360: return;
361: int chunk = attrIndex >> CHUNK_SHIFT;
362: int index = attrIndex & CHUNK_MASK;
363: fAttValue[chunk][index] = attrValue;
364: }
365:
366: /** Sets the type of the attribute. */
367: public void setAttType(int attrIndex, int attTypeIndex) {
368: if (attrIndex < 0 || attrIndex >= fAttrCount)
369: return;
370: int chunk = attrIndex >> CHUNK_SHIFT;
371: int index = attrIndex & CHUNK_MASK;
372: fAttType[chunk][index] = attTypeIndex;
373: }
374:
375: /**
376: * Get the type of the attribute
377: *
378: * @param attrIndex The index of the attribute.
379: * @return The type of the attribute, an index in the string pool.
380: */
381: public int getAttType(int attrIndex) {
382: if (attrIndex < 0 || attrIndex >= fAttrCount)
383: return -1;
384: int chunk = attrIndex >> CHUNK_SHIFT;
385: int index = attrIndex & CHUNK_MASK;
386: return fAttType[chunk][index];
387: }
388:
389: /**
390: * Was the attribute explicitly supplied or was it provided through a default?
391: *
392: * @param attrIndex The index of the attribute.
393: * @return <code>true</code> if the attribute was specified directly; otherwise
394: * <code>false</code> is the attribute was provided through a default.
395: */
396: public boolean isSpecified(int attrIndex) {
397: if (attrIndex < 0 || attrIndex >= fAttrCount)
398: return true;
399: int chunk = attrIndex >> CHUNK_SHIFT;
400: int index = attrIndex & CHUNK_MASK;
401: return (fAttFlags[chunk][index] & ATTFLAG_SPECIFIED) != 0;
402: }
403:
404: /**
405: * Make the resources of the current attribute list available for reuse.
406: *
407: * @param The attribute list handle.
408: */
409: public void releaseAttrList(int attrListHandle) {
410: if (attrListHandle == -1)
411: return;
412: int chunk = attrListHandle >> CHUNK_SHIFT;
413: int index = attrListHandle & CHUNK_MASK;
414: while (true) {
415: boolean last = (fAttFlags[chunk][index] & ATTFLAG_LASTATTR) != 0;
416: fAttPrefix[chunk][index] = -1;
417: fAttLocalpart[chunk][index] = -1;
418: fAttName[chunk][index] = -1;
419: fAttURI[chunk][index] = StringPool.EMPTY_STRING;
420: if ((fAttFlags[chunk][index] & ATTFLAG_SPECIFIED) != 0)
421: fStringPool.releaseString(fAttValue[chunk][index]);
422: fAttValue[chunk][index] = -1;
423: if (++index == CHUNK_SIZE) {
424: chunk++;
425: index = 0;
426: }
427: if (last)
428: break;
429: }
430: int lastIndex = (chunk << CHUNK_SHIFT) + index;
431: if (fAttrCount == lastIndex)
432: fAttrCount = attrListHandle;
433: }
434:
435: /**
436: * Get the first attribute in the attribute list.
437: *
438: * @param attrListHandle The attribute list handle.
439: * @return The index of the first attribute in the specified
440: * attribute list or -1 if the handle is invalid.
441: */
442: public int getFirstAttr(int attrListHandle) {
443: if (attrListHandle < 0 || attrListHandle >= fAttrCount) {
444: return -1;
445: }
446: // the first attribute in a list is implemented as
447: // the same index of the attribute list handle
448: return attrListHandle;
449: }
450:
451: /**
452: * Get the next attribute in the attribute list.
453: *
454: * @param attrIndex The attribute index.
455: * @return The index of the next attribute after <code>attrIndex</code> in
456: * the same attribute list or -1 if there is no next index.
457: */
458: public int getNextAttr(int attrIndex) {
459: if (attrIndex < 0 || attrIndex + 1 >= fAttrCount) {
460: return -1;
461: }
462: int chunk = attrIndex >> CHUNK_SHIFT;
463: int index = attrIndex & CHUNK_MASK;
464: if ((fAttFlags[chunk][index] & ATTFLAG_LASTATTR) != 0) {
465: return -1;
466: }
467: // attribute lists are implemented in the
468: // chunks one after another with the last
469: // attribute having a "last" flag set
470: return attrIndex + 1;
471: }
472:
473: /* AttributeList support */
474:
475: /**
476: * Setup this instance to respond as an <code>AttributeList</code> implementation.
477: *
478: * @return This instance as an <code>AttributeList</code>.
479: */
480: public AttributeList getAttributeList(int attrListHandle) {
481: fAttributeListHandle = attrListHandle;
482: if (fAttributeListHandle == -1)
483: fAttributeListLength = 0;
484: else {
485: int chunk = fAttributeListHandle >> CHUNK_SHIFT;
486: int index = fAttributeListHandle & CHUNK_MASK;
487: fAttributeListLength = 1;
488: while ((fAttFlags[chunk][index] & ATTFLAG_LASTATTR) == 0) {
489: if (++index == CHUNK_SIZE) {
490: chunk++;
491: index = 0;
492: }
493: fAttributeListLength++;
494: }
495: }
496: return this ;
497: }
498:
499: /**
500: * Return the number of attributes in this list.
501: *
502: * <p>The SAX parser may provide attributes in any
503: * arbitrary order, regardless of the order in which they were
504: * declared or specified. The number of attributes may be
505: * zero.</p>
506: *
507: * @return The number of attributes in the list.
508: */
509: public int getLength() {
510: return fAttributeListLength;
511: }
512:
513: /**
514: * Return the prefix of an attribute in this list (by position).
515: */
516: public String getPrefix(int i) {
517: if (i < 0 || i >= fAttributeListLength) {
518: return null;
519: }
520: int chunk = (fAttributeListHandle + i) >> CHUNK_SHIFT;
521: int index = (fAttributeListHandle + i) & CHUNK_MASK;
522: return fStringPool.toString(fAttPrefix[chunk][index]);
523: }
524:
525: /**
526: * Return the local part of an attribute in this list (by position).
527: */
528: public String getLocalpart(int i) {
529: if (i < 0 || i >= fAttributeListLength) {
530: return null;
531: }
532: int chunk = (fAttributeListHandle + i) >> CHUNK_SHIFT;
533: int index = (fAttributeListHandle + i) & CHUNK_MASK;
534: return fStringPool.toString(fAttLocalpart[chunk][index]);
535: }
536:
537: /**
538: * Return the name of an attribute in this list (by position).
539: *
540: * <p>The names must be unique: the SAX parser shall not include the
541: * same attribute twice. Attributes without values (those declared
542: * #IMPLIED without a value specified in the start tag) will be
543: * omitted from the list.</p>
544: *
545: * <p>If the attribute name has a namespace prefix, the prefix
546: * will still be attached.</p>
547: *
548: * @param i The index of the attribute in the list (starting at 0).
549: * @return The name of the indexed attribute, or null
550: * if the index is out of range.
551: * @see #getLength
552: */
553: public String getName(int i) {
554: if (i < 0 || i >= fAttributeListLength)
555: return null;
556: int chunk = (fAttributeListHandle + i) >> CHUNK_SHIFT;
557: int index = (fAttributeListHandle + i) & CHUNK_MASK;
558: return fStringPool.toString(fAttName[chunk][index]);
559: }
560:
561: /** Returns the URI of an attribute in this list (by position). */
562: public String getURI(int i) {
563: if (i < 0 || i >= fAttributeListLength)
564: return null;
565: int chunk = (fAttributeListHandle + i) >> CHUNK_SHIFT;
566: int index = (fAttributeListHandle + i) & CHUNK_MASK;
567: return fStringPool.toString(fAttURI[chunk][index]);
568: }
569:
570: /**
571: * Return the type of an attribute in the list (by position).
572: *
573: * <p>The attribute type is one of the strings "CDATA", "ID",
574: * "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES",
575: * or "NOTATION" (always in upper case).</p>
576: *
577: * <p>If the parser has not read a declaration for the attribute,
578: * or if the parser does not report attribute types, then it must
579: * return the value "CDATA" as stated in the XML 1.0 Recommentation
580: * (clause 3.3.3, "Attribute-Value Normalization").</p>
581: *
582: * <p>For an enumerated attribute that is not a notation, the
583: * parser will report the type as "NMTOKEN".</p>
584: *
585: * @param i The index of the attribute in the list (starting at 0).
586: * @return The attribute type as a string, or
587: * null if the index is out of range.
588: * @see #getLength
589: * @see #getType(java.lang.String)
590: */
591: public String getType(int i) {
592: if (i < 0 || i >= fAttributeListLength)
593: return null;
594: int chunk = (fAttributeListHandle + i) >> CHUNK_SHIFT;
595: int index = (fAttributeListHandle + i) & CHUNK_MASK;
596: int attType = fAttType[chunk][index];
597: if (attType == fStringPool.addSymbol("ENUMERATION"))
598: attType = fStringPool.addSymbol("NMTOKEN");
599: return fStringPool.toString(attType);
600: }
601:
602: /**
603: * Return the value of an attribute in the list (by position).
604: *
605: * <p>If the attribute value is a list of tokens (IDREFS,
606: * ENTITIES, or NMTOKENS), the tokens will be concatenated
607: * into a single string separated by whitespace.</p>
608: *
609: * @param i The index of the attribute in the list (starting at 0).
610: * @return The attribute value as a string, or
611: * null if the index is out of range.
612: * @see #getLength
613: * @see #getValue(java.lang.String)
614: */
615: public String getValue(int i) {
616: if (i < 0 || i >= fAttributeListLength)
617: return null;
618: int chunk = (fAttributeListHandle + i) >> CHUNK_SHIFT;
619: int index = (fAttributeListHandle + i) & CHUNK_MASK;
620: return fStringPool.toString(fAttValue[chunk][index]);
621: }
622:
623: /**
624: * Return the type of an attribute in the list (by name).
625: *
626: * <p>The return value is the same as the return value for
627: * getType(int).</p>
628: *
629: * <p>If the attribute name has a namespace prefix in the document,
630: * the application must include the prefix here.</p>
631: *
632: * @param name The name of the attribute.
633: * @return The attribute type as a string, or null if no
634: * such attribute exists.
635: * @see #getType(int)
636: */
637: public String getType(String name) {
638: int nameIndex = fStringPool.addSymbol(name);
639: if (nameIndex == -1)
640: return null;
641: int chunk = fAttributeListHandle >> CHUNK_SHIFT;
642: int index = fAttributeListHandle & CHUNK_MASK;
643: for (int i = 0; i < fAttributeListLength; i++) {
644: if (fStringPool.equalNames(fAttName[chunk][index],
645: nameIndex)) {
646: int attType = fAttType[chunk][index];
647: if (attType == fStringPool.addSymbol("ENUMERATION"))
648: attType = fStringPool.addSymbol("NMTOKEN");
649: return fStringPool.toString(attType);
650: }
651: if (++index == CHUNK_SIZE) {
652: chunk++;
653: index = 0;
654: }
655: }
656: return null;
657: }
658:
659: /**
660: * Return the value of an attribute in the list (by name).
661: *
662: * <p>The return value is the same as the return value for
663: * getValue(int).</p>
664: *
665: * <p>If the attribute name has a namespace prefix in the document,
666: * the application must include the prefix here.</p>
667: *
668: * @param i The index of the attribute in the list.
669: * @return The attribute value as a string, or null if
670: * no such attribute exists.
671: * @see #getValue(int)
672: */
673: public String getValue(String name) {
674: int nameIndex = fStringPool.addSymbol(name);
675: if (nameIndex == -1)
676: return null;
677: int chunk = fAttributeListHandle >> CHUNK_SHIFT;
678: int index = fAttributeListHandle & CHUNK_MASK;
679: for (int i = 0; i < fAttributeListLength; i++) {
680: if (fStringPool.equalNames(fAttName[chunk][index],
681: nameIndex))
682: return fStringPool.toString(fAttValue[chunk][index]);
683: if (++index == CHUNK_SIZE) {
684: chunk++;
685: index = 0;
686: }
687: }
688: return null;
689: }
690:
691: //
692: // Private methods
693: //
694:
695: /* Expand our internal data structures as needed. */
696: private void ensureCapacity(int chunk, int index) {
697: if (chunk >= fAttPrefix.length) {
698: int[][] newIntArray = new int[chunk * 2][];
699: System.arraycopy(fAttPrefix, 0, newIntArray, 0, chunk);
700: fAttPrefix = newIntArray;
701: newIntArray = new int[chunk * 2][];
702: System.arraycopy(fAttLocalpart, 0, newIntArray, 0, chunk);
703: fAttLocalpart = newIntArray;
704: newIntArray = new int[chunk * 2][];
705: System.arraycopy(fAttName, 0, newIntArray, 0, chunk);
706: fAttName = newIntArray;
707: newIntArray = new int[chunk * 2][];
708: System.arraycopy(fAttURI, 0, newIntArray, 0, chunk);
709: fAttURI = newIntArray;
710: newIntArray = new int[chunk * 2][];
711: System.arraycopy(fAttValue, 0, newIntArray, 0, chunk);
712: fAttValue = newIntArray;
713: newIntArray = new int[chunk * 2][];
714: System.arraycopy(fAttType, 0, newIntArray, 0, chunk);
715: fAttType = newIntArray;
716: byte[][] newByteArray = new byte[chunk * 2][];
717: System.arraycopy(fAttFlags, 0, newByteArray, 0, chunk);
718: fAttFlags = newByteArray;
719: } else if (fAttPrefix[chunk] != null) {
720: return;
721: }
722: fAttPrefix[chunk] = new int[CHUNK_SIZE];
723: fAttLocalpart[chunk] = new int[CHUNK_SIZE];
724: fAttName[chunk] = new int[CHUNK_SIZE];
725: fAttURI[chunk] = new int[CHUNK_SIZE];
726: fAttValue[chunk] = new int[CHUNK_SIZE];
727: fAttType[chunk] = new int[CHUNK_SIZE];
728: fAttFlags[chunk] = new byte[CHUNK_SIZE];
729: return;
730:
731: } // ensureCapacity(int,int):void
732:
733: } // class XMLAttrList
|