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  */
  36 final class BalancedDTDGrammar extends DTDGrammar {
  37 
  38     //
  39     // Data
  40     //
  41 
  42     /** Mixed. */
  43     private boolean fMixed;
  44 
  45     /** Stack depth */
  46     private int fDepth = 0;
  47 
  48     /** Children content model operation stack. */
  49     private short [] fOpStack = null;
  50 
  51     /** Holder for choice/sequence/leaf groups at each depth. */
  52     private int [][] fGroupIndexStack;
  53 
  54     /** Sizes of the allocated portions of each int[] in fGroupIndexStack. */
  55     private int [] fGroupIndexStackSizes;
  56 
  57     //
  58     // Constructors
  59     //
  60 
  61     /** Default constructor. */
  62     public BalancedDTDGrammar(SymbolTable symbolTable, XMLDTDDescription desc) {
  63         super(symbolTable, desc);
  64     } // BalancedDTDGrammar(SymbolTable,XMLDTDDescription)
  65 
  66     //
  67     // Public methods
  68     //
  69 
  70     /**
  71      * The start of a content model. Depending on the type of the content
  72      * model, specific methods may be called between the call to the
  73      * startContentModel method and the call to the endContentModel method.
  74      *
  75      * @param elementName The name of the element.
  76      * @param augs Additional information that may include infoset
  77      *                      augmentations.
  78      * @throws XNIException Thrown by handler to signal an error.
  79      */
  80     public final void startContentModel(String elementName, Augmentations augs)
  81         throws XNIException {
  82         fDepth = 0;
  83         initializeContentModelStacks();
  84         super.startContentModel(elementName, augs);
  85     } // startContentModel(String)
  86 
  87     /**
  88      * A start of either a mixed or children content model. A mixed
  89      * content model will immediately be followed by a call to the
  90      * <code>pcdata()</code> method. A children content model will
  91      * contain additional groups and/or elements.
  92      *
  93      * @param augs Additional information that may include infoset
  94      *                      augmentations.
  95      * @throws XNIException Thrown by handler to signal an error.
  96      *
  97      * @see #any
  98      * @see #empty
  99      */
 100     public final void startGroup(Augmentations augs) throws XNIException {
 101         ++fDepth;
 102         initializeContentModelStacks();
 103         fMixed = false;
 104     } // startGroup()
 105 
 106     /**
 107      * The appearance of "#PCDATA" within a group signifying a
 108      * mixed content model. This method will be the first called
 109      * following the content model's <code>startGroup()</code>.
 110      *
 111      *@param augs Additional information that may include infoset
 112      *                      augmentations.
 113      *
 114      * @throws XNIException Thrown by handler to signal an error.
 115      *
 116      * @see #startGroup
 117      */
 118     public final void pcdata(Augmentations augs) throws XNIException {
 119         fMixed = true;
 120     } // pcdata()
 121 
 122     /**
 123      * A referenced element in a mixed or children content model.
 124      *
 125      * @param elementName The name of the referenced element.
 126      * @param augs Additional information that may include infoset
 127      *                      augmentations.
 128      *
 129      * @throws XNIException Thrown by handler to signal an error.
 130      */
 131     public final void element(String elementName, Augmentations augs) throws XNIException {
 132         addToCurrentGroup(addUniqueLeafNode(elementName));
 133     } // element(String)
 134 
 135     /**
 136      * The separator between choices or sequences of a mixed or children
 137      * content model.
 138      *
 139      * @param separator The type of children separator.
 140      * @param augs Additional information that may include infoset
 141      *                      augmentations.
 142      * @throws XNIException Thrown by handler to signal an error.
 143      *
 144      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_CHOICE
 145      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_SEQUENCE
 146      */
 147     public final void separator(short separator, Augmentations augs) throws XNIException {
 148         if (separator == XMLDTDContentModelHandler.SEPARATOR_CHOICE) {
 149             fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_CHOICE;
 150         }
 151         else if (separator == XMLDTDContentModelHandler.SEPARATOR_SEQUENCE) {
 152             fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_SEQ;
 153         }
 154     } // separator(short)
 155 
 156     /**
 157      * The occurrence count for a child in a children content model or
 158      * for the mixed content model group.
 159      *
 160      * @param occurrence The occurrence count for the last element
 161      *                   or group.
 162      * @param augs Additional information that may include infoset
 163      *                      augmentations.
 164      * @throws XNIException Thrown by handler to signal an error.
 165      *
 166      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_ONE
 167      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_MORE
 168      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ONE_OR_MORE
 169      */
 170     public final void occurrence(short occurrence, Augmentations augs) throws XNIException {
 171         if (!fMixed) {
 172             int currentIndex = fGroupIndexStackSizes[fDepth] - 1;
 173             if (occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE) {
 174                 fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, fGroupIndexStack[fDepth][currentIndex], -1);
 175             }
 176             else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE) {
 177                 fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE, fGroupIndexStack[fDepth][currentIndex], -1);
 178             }
 179             else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE) {
 180                 fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE, fGroupIndexStack[fDepth][currentIndex], -1);
 181             }
 182         }
 183     } // occurrence(short)
 184 
 185     /**
 186      * The end of a group for mixed or children content models.
 187      *
 188      * @param augs Additional information that may include infoset
 189      *                      augmentations.
 190      * @throws XNIException Thrown by handler to signal an error.
 191      */
 192     public final void endGroup(Augmentations augs) throws XNIException {
 193         final int length = fGroupIndexStackSizes[fDepth];
 194         final int group = length > 0 ? addContentSpecNodes(0, length - 1) : addUniqueLeafNode(null);
 195         --fDepth;
 196         addToCurrentGroup(group);
 197     } // endGroup()
 198 
 199     /**
 200      * The end of the DTD.
 201      *
 202      * @param augs Additional information that may include infoset
 203      *                      augmentations.
 204      * @throws XNIException Thrown by handler to signal an error.
 205      */
 206     public final void endDTD(Augmentations augs) throws XNIException {
 207         super.endDTD(augs);
 208         fOpStack = null;
 209         fGroupIndexStack = null;
 210         fGroupIndexStackSizes = null;
 211     } // endDTD()
 212 
 213     //
 214     // Protected methods
 215     //
 216 
 217     /**
 218      * Adds the content spec to the given element declaration.
 219      */
 220     protected final void addContentSpecToElement(XMLElementDecl elementDecl) {
 221         int contentSpec = fGroupIndexStackSizes[0] > 0 ? fGroupIndexStack[0][0] : -1;
 222         setContentSpecIndex(fCurrentElementIndex, contentSpec);
 223     }
 224 
 225     //
 226     // Private methods
 227     //
 228 
 229     /**
 230      * Creates a subtree from the leaf nodes at the current depth.
 231      */
 232     private int addContentSpecNodes(int begin, int end) {
 233         if (begin == end) {
 234             return fGroupIndexStack[fDepth][begin];
 235         }
 236         final int middle = (begin + end) >>> 1;
 237         return addContentSpecNode(fOpStack[fDepth],
 238                 addContentSpecNodes(begin, middle),
 239                 addContentSpecNodes(middle + 1, end));
 240     } // addContentSpecNodes(int,int)
 241 
 242     /**
 243      * Initialize the stacks which temporarily hold content models.
 244      */
 245     private void initializeContentModelStacks() {
 246         if (fOpStack == null) {
 247             fOpStack = new short[8];
 248             fGroupIndexStack = new int [8][];
 249             fGroupIndexStackSizes = new int [8];
 250         }
 251         else if (fDepth == fOpStack.length) {
 252             short [] newOpStack = new short[fDepth * 2];
 253             System.arraycopy(fOpStack, 0, newOpStack, 0, fDepth);
 254             fOpStack = newOpStack;
 255             int [][] newGroupIndexStack = new int[fDepth * 2][];
 256             System.arraycopy(fGroupIndexStack, 0, newGroupIndexStack, 0, fDepth);
 257             fGroupIndexStack = newGroupIndexStack;
 258             int [] newGroupIndexStackLengths = new int[fDepth * 2];
 259             System.arraycopy(fGroupIndexStackSizes, 0, newGroupIndexStackLengths, 0, fDepth);
 260             fGroupIndexStackSizes = newGroupIndexStackLengths;
 261         }
 262         fOpStack[fDepth] = -1;
 263         fGroupIndexStackSizes[fDepth] = 0;
 264     } // initializeContentModelStacks()
 265 
 266     /**
 267      * Add XMLContentSpec to the current group.
 268      *
 269      * @param contentSpec handle to the XMLContentSpec to add to the current group
 270      */
 271     private void addToCurrentGroup(int contentSpec) {
 272         int [] currentGroup = fGroupIndexStack[fDepth];
 273         int length = fGroupIndexStackSizes[fDepth]++;
 274         if (currentGroup == null) {
 275             currentGroup = new int[8];
 276             fGroupIndexStack[fDepth] = currentGroup;
 277         }
 278         else if (length == currentGroup.length) {
 279             int [] newGroup = new int[currentGroup.length * 2];
 280             System.arraycopy(currentGroup, 0, newGroup, 0, currentGroup.length);
 281             currentGroup = newGroup;
 282             fGroupIndexStack[fDepth] = currentGroup;
 283         }
 284         currentGroup[length] = contentSpec;
 285     } // addToCurrentGroup(int)
 286 
 287 } // class BalancedDTDGrammar