1 /* 2 * Copyright (c) 2012, 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 package jdk.internal.util.xml.impl; 27 28 import jdk.internal.org.xml.sax.Attributes; 29 30 public class Attrs implements Attributes { 31 32 /** 33 * Attributes string array. Each individual attribute is represented by four 34 * strings: namespace URL(+0), qname(+1), local name(+2), value(+3), 35 * type(+4), declared["d"] and default["D"](+5). In order to find attribute 36 * by the attrubute index, the attribute index MUST be multiplied by 8. The 37 * result will point to the attribute namespace URL. 38 */ 39 /* pkg */ String[] mItems; 40 /** 41 * Number of attributes in the attributes string array. 42 */ 43 private char mLength; 44 /** 45 * current index 46 */ 47 private char mAttrIdx = 0; 48 49 /** 50 * Constructor. 51 */ 52 public Attrs() { 53 // The default number of attributies capacity is 8. 54 mItems = new String[(8 << 3)]; 55 } 56 57 /** 58 * Sets up the number of attributes and ensure the capacity of the attribute 59 * string array. 60 * 61 * @param length The number of attributes in the object. 62 */ 63 public void setLength(char length) { 64 if (length > ((char) (mItems.length >> 3))) { 65 mItems = new String[length << 3]; 66 } 67 mLength = length; 68 } 69 70 /** 71 * Return the number of attributes in the list. 72 * 73 * <p>Once you know the number of attributes, you can iterate through the 74 * list.</p> 75 * 76 * @return The number of attributes in the list. 77 * @see #getURI(int) 78 * @see #getLocalName(int) 79 * @see #getQName(int) 80 * @see #getType(int) 81 * @see #getValue(int) 82 */ 83 public int getLength() { 84 return mLength; 85 } 86 87 /** 88 * Look up an attribute's Namespace URI by index. 89 * 90 * @param index The attribute index (zero-based). 91 * @return The Namespace URI, or the empty string if none is available, or 92 * null if the index is out of range. 93 * @see #getLength 94 */ 95 public String getURI(int index) { 96 return ((index >= 0) && (index < mLength)) 97 ? (mItems[index << 3]) 98 : null; 99 } 100 101 /** 102 * Look up an attribute's local name by index. 103 * 104 * @param index The attribute index (zero-based). 105 * @return The local name, or the empty string if Namespace processing is 106 * not being performed, or null if the index is out of range. 107 * @see #getLength 108 */ 109 public String getLocalName(int index) { 110 return ((index >= 0) && (index < mLength)) 111 ? (mItems[(index << 3) + 2]) 112 : null; 113 } 114 115 /** 116 * Look up an attribute's XML 1.0 qualified name by index. 117 * 118 * @param index The attribute index (zero-based). 119 * @return The XML 1.0 qualified name, or the empty string if none is 120 * available, or null if the index is out of range. 121 * @see #getLength 122 */ 123 public String getQName(int index) { 124 if ((index < 0) || (index >= mLength)) { 125 return null; 126 } 127 return mItems[(index << 3) + 1]; 128 } 129 130 /** 131 * Look up an attribute's type by index. 132 * 133 * <p>The attribute type is one of the strings "CDATA", "ID", "IDREF", 134 * "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", or "NOTATION" 135 * (always in upper case).</p> 136 * 137 * <p>If the parser has not read a declaration for the attribute, or if the 138 * parser does not report attribute types, then it must return the value 139 * "CDATA" as stated in the XML 1.0 Recommentation (clause 3.3.3, 140 * "Attribute-Value Normalization").</p> 141 * 142 * <p>For an enumerated attribute that is not a notation, the parser will 143 * report the type as "NMTOKEN".</p> 144 * 145 * @param index The attribute index (zero-based). 146 * @return The attribute's type as a string, or null if the index is out of 147 * range. 148 * @see #getLength 149 */ 150 public String getType(int index) { 151 return ((index >= 0) && (index < (mItems.length >> 3))) 152 ? (mItems[(index << 3) + 4]) 153 : null; 154 } 155 156 /** 157 * Look up an attribute's value by index. 158 * 159 * <p>If the attribute value is a list of tokens (IDREFS, ENTITIES, or 160 * NMTOKENS), the tokens will be concatenated into a single string with each 161 * token separated by a single space.</p> 162 * 163 * @param index The attribute index (zero-based). 164 * @return The attribute's value as a string, or null if the index is out of 165 * range. 166 * @see #getLength 167 */ 168 public String getValue(int index) { 169 return ((index >= 0) && (index < mLength)) 170 ? (mItems[(index << 3) + 3]) 171 : null; 172 } 173 174 /** 175 * Look up the index of an attribute by Namespace name. 176 * 177 * @param uri The Namespace URI, or the empty string if the name has no 178 * Namespace URI. 179 * @param localName The attribute's local name. 180 * @return The index of the attribute, or -1 if it does not appear in the 181 * list. 182 */ 183 public int getIndex(String uri, String localName) { 184 char len = mLength; 185 for (char idx = 0; idx < len; idx++) { 186 if ((mItems[idx << 3]).equals(uri) 187 && mItems[(idx << 3) + 2].equals(localName)) { 188 return idx; 189 } 190 } 191 return -1; 192 } 193 194 /** 195 * Look up the index of an attribute by Namespace name. 196 * 197 * @param uri The Namespace URI, or the empty string if the name has no 198 * Namespace URI. <code>null</code> value enforce the search by the local 199 * name only. 200 * @param localName The attribute's local name. 201 * @return The index of the attribute, or -1 if it does not appear in the 202 * list. 203 */ 204 /* pkg */ int getIndexNullNS(String uri, String localName) { 205 char len = mLength; 206 if (uri != null) { 207 for (char idx = 0; idx < len; idx++) { 208 if ((mItems[idx << 3]).equals(uri) 209 && mItems[(idx << 3) + 2].equals(localName)) { 210 return idx; 211 } 212 } 213 } else { 214 for (char idx = 0; idx < len; idx++) { 215 if (mItems[(idx << 3) + 2].equals(localName)) { 216 return idx; 217 } 218 } 219 } 220 return -1; 221 } 222 223 /** 224 * Look up the index of an attribute by XML 1.0 qualified name. 225 * 226 * @param qName The qualified (prefixed) name. 227 * @return The index of the attribute, or -1 if it does not appear in the 228 * list. 229 */ 230 public int getIndex(String qName) { 231 char len = mLength; 232 for (char idx = 0; idx < len; idx++) { 233 if (mItems[(idx << 3) + 1].equals(qName)) { 234 return idx; 235 } 236 } 237 return -1; 238 } 239 240 /** 241 * Look up an attribute's type by Namespace name. 242 * 243 * <p>See {@link #getType(int) getType(int)} for a description of the 244 * possible types.</p> 245 * 246 * @param uri The Namespace URI, or the empty String if the name has no 247 * Namespace URI. 248 * @param localName The local name of the attribute. 249 * @return The attribute type as a string, or null if the attribute is not 250 * in the list or if Namespace processing is not being performed. 251 */ 252 public String getType(String uri, String localName) { 253 int idx = getIndex(uri, localName); 254 return (idx >= 0) ? (mItems[(idx << 3) + 4]) : null; 255 } 256 257 /** 258 * Look up an attribute's type by XML 1.0 qualified name. 259 * 260 * <p>See {@link #getType(int) getType(int)} for a description of the 261 * possible types.</p> 262 * 263 * @param qName The XML 1.0 qualified name. 264 * @return The attribute type as a string, or null if the attribute is not 265 * in the list or if qualified names are not available. 266 */ 267 public String getType(String qName) { 268 int idx = getIndex(qName); 269 return (idx >= 0) ? (mItems[(idx << 3) + 4]) : null; 270 } 271 272 /** 273 * Look up an attribute's value by Namespace name. 274 * 275 * <p>See {@link #getValue(int) getValue(int)} for a description of the 276 * possible values.</p> 277 * 278 * @param uri The Namespace URI, or the empty String if the name has no 279 * Namespace URI. 280 * @param localName The local name of the attribute. 281 * @return The attribute value as a string, or null if the attribute is not 282 * in the list. 283 */ 284 public String getValue(String uri, String localName) { 285 int idx = getIndex(uri, localName); 286 return (idx >= 0) ? (mItems[(idx << 3) + 3]) : null; 287 } 288 289 /** 290 * Look up an attribute's value by XML 1.0 qualified name. 291 * 292 * <p>See {@link #getValue(int) getValue(int)} for a description of the 293 * possible values.</p> 294 * 295 * @param qName The XML 1.0 qualified name. 296 * @return The attribute value as a string, or null if the attribute is not 297 * in the list or if qualified names are not available. 298 */ 299 public String getValue(String qName) { 300 int idx = getIndex(qName); 301 return (idx >= 0) ? (mItems[(idx << 3) + 3]) : null; 302 } 303 304 /** 305 * Returns false unless the attribute was declared in the DTD. This helps 306 * distinguish two kinds of attributes that SAX reports as CDATA: ones that 307 * were declared (and hence are usually valid), and those that were not (and 308 * which are never valid). 309 * 310 * @param index The attribute index (zero-based). 311 * @return true if the attribute was declared in the DTD, false otherwise. 312 * @exception java.lang.ArrayIndexOutOfBoundsException When the supplied 313 * index does not identify an attribute. 314 */ 315 public boolean isDeclared(int index) { 316 if ((index < 0) || (index >= mLength)) { 317 throw new ArrayIndexOutOfBoundsException(""); 318 } 319 320 return ((mItems[(index << 3) + 5]) != null); 321 } 322 323 /** 324 * Returns false unless the attribute was declared in the DTD. This helps 325 * distinguish two kinds of attributes that SAX reports as CDATA: ones that 326 * were declared (and hence are usually valid), and those that were not (and 327 * which are never valid). 328 * 329 * @param qName The XML qualified (prefixed) name. 330 * @return true if the attribute was declared in the DTD, false otherwise. 331 * @exception java.lang.IllegalArgumentException When the supplied name does 332 * not identify an attribute. 333 */ 334 public boolean isDeclared(String qName) { 335 int idx = getIndex(qName); 336 if (idx < 0) { 337 throw new IllegalArgumentException(""); 338 } 339 340 return ((mItems[(idx << 3) + 5]) != null); 341 } 342 343 /** 344 * Returns false unless the attribute was declared in the DTD. This helps 345 * distinguish two kinds of attributes that SAX reports as CDATA: ones that 346 * were declared (and hence are usually valid), and those that were not (and 347 * which are never valid). 348 * 349 * <p>Remember that since DTDs do not "understand" namespaces, the namespace 350 * URI associated with an attribute may not have come from the DTD. The 351 * declaration will have applied to the attribute's <em>qName</em>. 352 * 353 * @param uri The Namespace URI, or the empty string if the name has no 354 * Namespace URI. 355 * @param localName The attribute's local name. 356 * @return true if the attribute was declared in the DTD, false otherwise. 357 * @exception java.lang.IllegalArgumentException When the supplied names do 358 * not identify an attribute. 359 */ 360 public boolean isDeclared(String uri, String localName) { 361 int idx = getIndex(uri, localName); 362 if (idx < 0) { 363 throw new IllegalArgumentException(""); 364 } 365 366 return ((mItems[(idx << 3) + 5]) != null); 367 } 368 369 /** 370 * Returns true unless the attribute value was provided by DTD defaulting. 371 * 372 * @param index The attribute index (zero-based). 373 * @return true if the value was found in the XML text, false if the value 374 * was provided by DTD defaulting. 375 * @exception java.lang.ArrayIndexOutOfBoundsException When the supplied 376 * index does not identify an attribute. 377 */ 378 public boolean isSpecified(int index) { 379 if ((index < 0) || (index >= mLength)) { 380 throw new ArrayIndexOutOfBoundsException(""); 381 } 382 383 String str = mItems[(index << 3) + 5]; 384 return ((str != null) ? (str.charAt(0) == 'd') : true); 385 } 386 387 /** 388 * Returns true unless the attribute value was provided by DTD defaulting. 389 * 390 * <p>Remember that since DTDs do not "understand" namespaces, the namespace 391 * URI associated with an attribute may not have come from the DTD. The 392 * declaration will have applied to the attribute's <em>qName</em>. 393 * 394 * @param uri The Namespace URI, or the empty string if the name has no 395 * Namespace URI. 396 * @param localName The attribute's local name. 397 * @return true if the value was found in the XML text, false if the value 398 * was provided by DTD defaulting. 399 * @exception java.lang.IllegalArgumentException When the supplied names do 400 * not identify an attribute. 401 */ 402 public boolean isSpecified(String uri, String localName) { 403 int idx = getIndex(uri, localName); 404 if (idx < 0) { 405 throw new IllegalArgumentException(""); 406 } 407 408 String str = mItems[(idx << 3) + 5]; 409 return ((str != null) ? (str.charAt(0) == 'd') : true); 410 } 411 412 /** 413 * Returns true unless the attribute value was provided by DTD defaulting. 414 * 415 * @param qName The XML qualified (prefixed) name. 416 * @return true if the value was found in the XML text, false if the value 417 * was provided by DTD defaulting. 418 * @exception java.lang.IllegalArgumentException When the supplied name does 419 * not identify an attribute. 420 */ 421 public boolean isSpecified(String qName) { 422 int idx = getIndex(qName); 423 if (idx < 0) { 424 throw new IllegalArgumentException(""); 425 } 426 427 String str = mItems[(idx << 3) + 5]; 428 return ((str != null) ? (str.charAt(0) == 'd') : true); 429 } 430 }