1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * The Apache Software License, Version 1.1
   7  *
   8  *
   9  * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
  10  * reserved.
  11  *
  12  * Redistribution and use in source and binary forms, with or without
  13  * modification, are permitted provided that the following conditions
  14  * are met:
  15  *
  16  * 1. Redistributions of source code must retain the above copyright
  17  *    notice, this list of conditions and the following disclaimer.
  18  *
  19  * 2. Redistributions in binary form must reproduce the above copyright
  20  *    notice, this list of conditions and the following disclaimer in
  21  *    the documentation and/or other materials provided with the
  22  *    distribution.
  23  *
  24  * 3. The end-user documentation included with the redistribution,
  25  *    if any, must include the following acknowledgment:
  26  *       "This product includes software developed by the
  27  *        Apache Software Foundation (http://www.apache.org/)."
  28  *    Alternately, this acknowledgment may appear in the software itself,
  29  *    if and wherever such third-party acknowledgments normally appear.
  30  *
  31  * 4. The names "Xerces" and "Apache Software Foundation" must
  32  *    not be used to endorse or promote products derived from this
  33  *    software without prior written permission. For written
  34  *    permission, please contact apache@apache.org.
  35  *
  36  * 5. Products derived from this software may not be called "Apache",
  37  *    nor may "Apache" appear in their name, without prior written
  38  *    permission of the Apache Software Foundation.
  39  *
  40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  43  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  46  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  51  * SUCH DAMAGE.
  52  * ====================================================================
  53  *
  54  * This software consists of voluntary contributions made by many
  55  * individuals on behalf of the Apache Software Foundation and was
  56  * originally based on software copyright (c) 1999, International
  57  * Business Machines, Inc., http://www.apache.org.  For more
  58  * information on the Apache Software Foundation, please see
  59  * <http://www.apache.org/>.
  60  */
  61 
  62 package com.sun.org.apache.xerces.internal.impl.dtd.models;
  63 
  64 import com.sun.org.apache.xerces.internal.xni.QName;
  65 
  66 import com.sun.org.apache.xerces.internal.impl.dtd.XMLContentSpec;
  67 
  68 /**
  69  * SimpleContentModel is a derivative of the abstract content model base
  70  * class that handles a small set of simple content models that are just
  71  * way overkill to give the DFA treatment.
  72  * <p>
  73  * This class handles the following scenarios:
  74  * <ul>
  75  * <li> a
  76  * <li> a?
  77  * <li> a*
  78  * <li> a+
  79  * <li> a,b
  80  * <li> a|b
  81  * </ul>
  82  * <p>
  83  * These all involve a unary operation with one element type, or a binary
  84  * operation with two elements. These are very simple and can be checked
  85  * in a simple way without a DFA and without the overhead of setting up a
  86  * DFA for such a simple check.
  87  *
  88  * @xerces.internal
  89  *
  90  */
  91 public class SimpleContentModel
  92     implements ContentModelValidator {
  93 
  94     //
  95     // Constants
  96     //
  97 
  98     /** CHOICE */
  99     public static final short CHOICE = -1;
 100 
 101     /** SEQUENCE */
 102     public static final short SEQUENCE = -1;
 103 
 104     //
 105     // Data
 106     //
 107 
 108 
 109     /**
 110      * The element decl pool indices of the first (and optional second)
 111      * child node. The operation code tells us whether the second child
 112      * is used or not.
 113      */
 114     private QName fFirstChild = new QName();
 115 
 116     /**
 117      * The element decl pool indices of the first (and optional second)
 118      * child node. The operation code tells us whether the second child
 119      * is used or not.
 120      */
 121     private QName fSecondChild = new QName();
 122 
 123     /**
 124      * The operation that this object represents. Since this class only
 125      * does simple contents, there is only ever a single operation
 126      * involved (i.e. the children of the operation are always one or
 127      * two leafs.) This is one of the XMLDTDParams.CONTENTSPECNODE_XXX values.
 128      */
 129     private int fOperator;
 130 
 131     /* this is the EquivClassComparator object */
 132     //private EquivClassComparator comparator = null;
 133 
 134 
 135     //
 136     // Constructors
 137     //
 138 
 139     /**
 140      * Constructs a simple content model.
 141      *
 142      * @param operator The content model operator.
 143      * @param firstChild qualified name of the first child
 144      * @param secondChild qualified name of the second child
 145      *
 146      */
 147     public SimpleContentModel(short operator, QName firstChild, QName secondChild) {
 148         //
 149         //  Store away the children and operation. This is all we need to
 150         //  do the content model check.
 151         //
 152         //  The operation is one of the ContentSpecNode.NODE_XXX values!
 153         //
 154         fFirstChild.setValues(firstChild);
 155         if (secondChild != null) {
 156             fSecondChild.setValues(secondChild);
 157         }
 158         else {
 159             fSecondChild.clear();
 160         }
 161         fOperator = operator;
 162     }
 163 
 164     //
 165     // ContentModelValidator methods
 166     //
 167 
 168     /**
 169      * Check that the specified content is valid according to this
 170      * content model. This method can also be called to do 'what if'
 171      * testing of content models just to see if they would be valid.
 172      * <p>
 173      * A value of -1 in the children array indicates a PCDATA node. All other
 174      * indexes will be positive and represent child elements. The count can be
 175      * zero, since some elements have the EMPTY content model and that must be
 176      * confirmed.
 177      *
 178      * @param children The children of this element.  Each integer is an index within
 179      *                 the <code>StringPool</code> of the child element name.  An index
 180      *                 of -1 is used to indicate an occurrence of non-whitespace character
 181      *                 data.
 182      * @param offset Offset into the array where the children starts.
 183      * @param length The number of entries in the <code>children</code> array.
 184      *
 185      * @return The value -1 if fully valid, else the 0 based index of the child
 186      *         that first failed. If the value returned is equal to the number
 187      *         of children, then the specified children are valid but additional
 188      *         content is required to reach a valid ending state.
 189      *
 190      */
 191     public int validate(QName[] children, int offset, int length) {
 192 
 193         //
 194         //  According to the type of operation, we do the correct type of
 195         //  content check.
 196         //
 197         switch(fOperator)
 198         {
 199             case XMLContentSpec.CONTENTSPECNODE_LEAF :
 200                 // If there is not a child, then report an error at index 0
 201                 if (length == 0)
 202                     return 0;
 203 
 204                 // If the 0th child is not the right kind, report an error at 0
 205                 if (children[offset].rawname != fFirstChild.rawname) {
 206                     return 0;
 207                 }
 208 
 209                 // If more than one child, report an error at index 1
 210                 if (length > 1)
 211                     return 1;
 212                 break;
 213 
 214             case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE :
 215                 //
 216                 //  If there is one child, make sure its the right type. If not,
 217                 //  then its an error at index 0.
 218                 //
 219                 if (length == 1) {
 220                     if (children[offset].rawname != fFirstChild.rawname) {
 221                         return 0;
 222                     }
 223                 }
 224 
 225                 //
 226                 //  If the child count is greater than one, then obviously
 227                 //  bad, so report an error at index 1.
 228                 //
 229                 if (length > 1)
 230                     return 1;
 231                 break;
 232 
 233             case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE :
 234                 //
 235                 //  If the child count is zero, that's fine. If its more than
 236                 //  zero, then make sure that all children are of the element
 237                 //  type that we stored. If not, report the index of the first
 238                 //  failed one.
 239                 //
 240                 if (length > 0)
 241                 {
 242                     for (int index = 0; index < length; index++) {
 243                         if (children[offset + index].rawname != fFirstChild.rawname) {
 244                             return index;
 245                         }
 246                     }
 247                 }
 248                 break;
 249 
 250             case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE :
 251                 //
 252                 //  If the child count is zero, that's an error so report
 253                 //  an error at index 0.
 254                 //
 255                 if (length == 0)
 256                     return 0;
 257 
 258                 //
 259                 //  Otherwise we have to check them all to make sure that they
 260                 //  are of the correct child type. If not, then report the index
 261                 //  of the first one that is not.
 262                 //
 263                 for (int index = 0; index < length; index++) {
 264                     if (children[offset + index].rawname != fFirstChild.rawname) {
 265                         return index;
 266                     }
 267                 }
 268                 break;
 269 
 270             case XMLContentSpec.CONTENTSPECNODE_CHOICE :
 271                 //
 272                 //  There must be one and only one child, so if the element count
 273                 //  is zero, return an error at index 0.
 274                 //
 275                 if (length == 0)
 276                     return 0;
 277 
 278                 // If the zeroth element isn't one of our choices, error at 0
 279                 if ((children[offset].rawname != fFirstChild.rawname) &&
 280                     (children[offset].rawname != fSecondChild.rawname)) {
 281                     return 0;
 282                 }
 283 
 284                 // If there is more than one element, then an error at 1
 285                 if (length > 1)
 286                     return 1;
 287                 break;
 288 
 289             case XMLContentSpec.CONTENTSPECNODE_SEQ :
 290                 //
 291                 //  There must be two children and they must be the two values
 292                 //  we stored, in the stored order.
 293                 //
 294                 if (length == 2) {
 295                     if (children[offset].rawname != fFirstChild.rawname) {
 296                         return 0;
 297                     }
 298                     if (children[offset + 1].rawname != fSecondChild.rawname) {
 299                         return 1;
 300                     }
 301                 }
 302                 else {
 303                     if (length > 2) {
 304                         return 2;
 305                     }
 306 
 307                     return length;
 308                 }
 309 
 310                 break;
 311 
 312             default :
 313                 throw new RuntimeException("ImplementationMessages.VAL_CST");
 314         }
 315 
 316         // We survived, so return success status
 317         return -1;
 318     } // validate
 319 
 320 } // class SimpleContentModel