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