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