1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xerces.internal.impl.dtd;
  23 
  24 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  25 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  26 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
  27 import com.sun.org.apache.xerces.internal.xni.XNIException;
  28 
  29 /**
  30  * <p>A DTD grammar that produces balanced syntax trees.</p>
  31  *
  32  * @xerces.internal
  33  *
  34  * @author Michael Glavassevich, IBM
  35  * @version $Id: BalancedDTDGrammar.java,v 1.1 2010/08/11 07:18:38 joehw Exp $
  36  */
  37 final class BalancedDTDGrammar extends DTDGrammar {
  38 
  39     //
  40     // Data
  41     //
  42 
  43     /** Mixed. */
  44     private boolean fMixed;
  45 
  46     /** Stack depth */
  47     private int fDepth = 0;
  48 
  49     /** Children content model operation stack. */
  50     private short [] fOpStack = null;
  51 
  52     /** Holder for choice/sequence/leaf groups at each depth. */
  53     private int [][] fGroupIndexStack;
  54 
  55     /** Sizes of the allocated portions of each int[] in fGroupIndexStack. */
  56     private int [] fGroupIndexStackSizes;
  57 
  58     //
  59     // Constructors
  60     //
  61 
  62     /** Default constructor. */
  63     public BalancedDTDGrammar(SymbolTable symbolTable, XMLDTDDescription desc) {
  64         super(symbolTable, desc);
  65     } // BalancedDTDGrammar(SymbolTable,XMLDTDDescription)
  66 
  67     //
  68     // Public methods
  69     //
  70 
  71     /**
  72      * The start of a content model. Depending on the type of the content
  73      * model, specific methods may be called between the call to the
  74      * startContentModel method and the call to the endContentModel method.
  75      *
  76      * @param elementName The name of the element.
  77      * @param augs Additional information that may include infoset
  78      *                      augmentations.
  79      * @throws XNIException Thrown by handler to signal an error.
  80      */
  81     public final void startContentModel(String elementName, Augmentations augs)
  82         throws XNIException {
  83         fDepth = 0;
  84         initializeContentModelStacks();
  85         super.startContentModel(elementName, augs);
  86     } // startContentModel(String)
  87 
  88     /**
  89      * A start of either a mixed or children content model. A mixed
  90      * content model will immediately be followed by a call to the
  91      * <code>pcdata()</code> method. A children content model will
  92      * contain additional groups and/or elements.
  93      *
  94      * @param augs Additional information that may include infoset
  95      *                      augmentations.
  96      * @throws XNIException Thrown by handler to signal an error.
  97      *
  98      * @see #any
  99      * @see #empty
 100      */
 101     public final void startGroup(Augmentations augs) throws XNIException {
 102         ++fDepth;
 103         initializeContentModelStacks();
 104         fMixed = false;
 105     } // startGroup()
 106 
 107     /**
 108      * The appearance of "#PCDATA" within a group signifying a
 109      * mixed content model. This method will be the first called
 110      * following the content model's <code>startGroup()</code>.
 111      *
 112      *@param augs Additional information that may include infoset
 113      *                      augmentations.
 114      *
 115      * @throws XNIException Thrown by handler to signal an error.
 116      *
 117      * @see #startGroup
 118      */
 119     public final void pcdata(Augmentations augs) throws XNIException {
 120         fMixed = true;
 121     } // pcdata()
 122 
 123     /**
 124      * A referenced element in a mixed or children content model.
 125      *
 126      * @param elementName The name of the referenced element.
 127      * @param augs Additional information that may include infoset
 128      *                      augmentations.
 129      *
 130      * @throws XNIException Thrown by handler to signal an error.
 131      */
 132     public final void element(String elementName, Augmentations augs) throws XNIException {
 133         addToCurrentGroup(addUniqueLeafNode(elementName));
 134     } // element(String)
 135 
 136     /**
 137      * The separator between choices or sequences of a mixed or children
 138      * content model.
 139      *
 140      * @param separator The type of children separator.
 141      * @param augs Additional information that may include infoset
 142      *                      augmentations.
 143      * @throws XNIException Thrown by handler to signal an error.
 144      *
 145      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_CHOICE
 146      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_SEQUENCE
 147      */
 148     public final void separator(short separator, Augmentations augs) throws XNIException {
 149         if (separator == XMLDTDContentModelHandler.SEPARATOR_CHOICE) {
 150             fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_CHOICE;
 151         }
 152         else if (separator == XMLDTDContentModelHandler.SEPARATOR_SEQUENCE) {
 153             fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_SEQ;
 154         }
 155     } // separator(short)
 156 
 157     /**
 158      * The occurrence count for a child in a children content model or
 159      * for the mixed content model group.
 160      *
 161      * @param occurrence The occurrence count for the last element
 162      *                   or group.
 163      * @param augs Additional information that may include infoset
 164      *                      augmentations.
 165      * @throws XNIException Thrown by handler to signal an error.
 166      *
 167      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_ONE
 168      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_MORE
 169      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ONE_OR_MORE
 170      */
 171     public final void occurrence(short occurrence, Augmentations augs) throws XNIException {
 172         if (!fMixed) {
 173             int currentIndex = fGroupIndexStackSizes[fDepth] - 1;
 174             if (occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE) {
 175                 fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, fGroupIndexStack[fDepth][currentIndex], -1);
 176             }
 177             else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE) {
 178                 fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE, fGroupIndexStack[fDepth][currentIndex], -1);
 179             }
 180             else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE) {
 181                 fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE, fGroupIndexStack[fDepth][currentIndex], -1);
 182             }
 183         }
 184     } // occurrence(short)
 185 
 186     /**
 187      * The end of a group for mixed or children content models.
 188      *
 189      * @param augs Additional information that may include infoset
 190      *                      augmentations.
 191      * @throws XNIException Thrown by handler to signal an error.
 192      */
 193     public final void endGroup(Augmentations augs) throws XNIException {
 194         final int length = fGroupIndexStackSizes[fDepth];
 195         final int group = length > 0 ? addContentSpecNodes(0, length - 1) : addUniqueLeafNode(null);
 196         --fDepth;
 197         addToCurrentGroup(group);
 198     } // endGroup()
 199 
 200     /**
 201      * The end of the DTD.
 202      *
 203      * @param augs Additional information that may include infoset
 204      *                      augmentations.
 205      * @throws XNIException Thrown by handler to signal an error.
 206      */
 207     public final void endDTD(Augmentations augs) throws XNIException {
 208         super.endDTD(augs);
 209         fOpStack = null;
 210         fGroupIndexStack = null;
 211         fGroupIndexStackSizes = null;
 212     } // endDTD()
 213 
 214     //
 215     // Protected methods
 216     //
 217 
 218     /**
 219      * Adds the content spec to the given element declaration.
 220      */
 221     protected final void addContentSpecToElement(XMLElementDecl elementDecl) {
 222         int contentSpec = fGroupIndexStackSizes[0] > 0 ? fGroupIndexStack[0][0] : -1;
 223         setContentSpecIndex(fCurrentElementIndex, contentSpec);
 224     }
 225 
 226     //
 227     // Private methods
 228     //
 229 
 230     /**
 231      * Creates a subtree from the leaf nodes at the current depth.
 232      */
 233     private int addContentSpecNodes(int begin, int end) {
 234         if (begin == end) {
 235             return fGroupIndexStack[fDepth][begin];
 236         }
 237         final int middle = (begin + end) >>> 1;
 238         return addContentSpecNode(fOpStack[fDepth],
 239                 addContentSpecNodes(begin, middle),
 240                 addContentSpecNodes(middle + 1, end));
 241     } // addContentSpecNodes(int,int)
 242 
 243     /**
 244      * Initialize the stacks which temporarily hold content models.
 245      */
 246     private void initializeContentModelStacks() {
 247         if (fOpStack == null) {
 248             fOpStack = new short[8];
 249             fGroupIndexStack = new int [8][];
 250             fGroupIndexStackSizes = new int [8];
 251         }
 252         else if (fDepth == fOpStack.length) {
 253             short [] newOpStack = new short[fDepth * 2];
 254             System.arraycopy(fOpStack, 0, newOpStack, 0, fDepth);
 255             fOpStack = newOpStack;
 256             int [][] newGroupIndexStack = new int[fDepth * 2][];
 257             System.arraycopy(fGroupIndexStack, 0, newGroupIndexStack, 0, fDepth);
 258             fGroupIndexStack = newGroupIndexStack;
 259             int [] newGroupIndexStackLengths = new int[fDepth * 2];
 260             System.arraycopy(fGroupIndexStackSizes, 0, newGroupIndexStackLengths, 0, fDepth);
 261             fGroupIndexStackSizes = newGroupIndexStackLengths;
 262         }
 263         fOpStack[fDepth] = -1;
 264         fGroupIndexStackSizes[fDepth] = 0;
 265     } // initializeContentModelStacks()
 266 
 267     /**
 268      * Add XMLContentSpec to the current group.
 269      *
 270      * @param contentSpec handle to the XMLContentSpec to add to the current group
 271      */
 272     private void addToCurrentGroup(int contentSpec) {
 273         int [] currentGroup = fGroupIndexStack[fDepth];
 274         int length = fGroupIndexStackSizes[fDepth]++;
 275         if (currentGroup == null) {
 276             currentGroup = new int[8];
 277             fGroupIndexStack[fDepth] = currentGroup;
 278         }
 279         else if (length == currentGroup.length) {
 280             int [] newGroup = new int[currentGroup.length * 2];
 281             System.arraycopy(currentGroup, 0, newGroup, 0, currentGroup.length);
 282             currentGroup = newGroup;
 283             fGroupIndexStack[fDepth] = currentGroup;
 284         }
 285         currentGroup[length] = contentSpec;
 286     } // addToCurrentGroup(int)
 287 
 288 } // class BalancedDTDGrammar