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