001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.impl.dtd;
019:
020: import org.apache.xerces.util.SymbolTable;
021: import org.apache.xerces.xni.Augmentations;
022: import org.apache.xerces.xni.XMLDTDContentModelHandler;
023: import org.apache.xerces.xni.XNIException;
024:
025: /**
026: * <p>A DTD grammar that produces balanced syntax trees.</p>
027: *
028: * @xerces.internal
029: *
030: * @author Michael Glavassevich, IBM
031: * @version $Id: BalancedDTDGrammar.java 446755 2006-09-15 21:56:27Z mrglavas $
032: */
033: final class BalancedDTDGrammar extends DTDGrammar {
034:
035: //
036: // Data
037: //
038:
039: /** Mixed. */
040: private boolean fMixed;
041:
042: /** Stack depth */
043: private int fDepth = 0;
044:
045: /** Children content model operation stack. */
046: private short[] fOpStack = null;
047:
048: /** Holder for choice/sequence/leaf groups at each depth. */
049: private int[][] fGroupIndexStack;
050:
051: /** Sizes of the allocated portions of each int[] in fGroupIndexStack. */
052: private int[] fGroupIndexStackSizes;
053:
054: //
055: // Constructors
056: //
057:
058: /** Default constructor. */
059: public BalancedDTDGrammar(SymbolTable symbolTable,
060: XMLDTDDescription desc) {
061: super (symbolTable, desc);
062: } // BalancedDTDGrammar(SymbolTable,XMLDTDDescription)
063:
064: //
065: // Public methods
066: //
067:
068: /**
069: * The start of a content model. Depending on the type of the content
070: * model, specific methods may be called between the call to the
071: * startContentModel method and the call to the endContentModel method.
072: *
073: * @param elementName The name of the element.
074: * @param augs Additional information that may include infoset
075: * augmentations.
076: * @throws XNIException Thrown by handler to signal an error.
077: */
078: public final void startContentModel(String elementName,
079: Augmentations augs) throws XNIException {
080: fDepth = 0;
081: initializeContentModelStacks();
082: super .startContentModel(elementName, augs);
083: } // startContentModel(String)
084:
085: /**
086: * A start of either a mixed or children content model. A mixed
087: * content model will immediately be followed by a call to the
088: * <code>pcdata()</code> method. A children content model will
089: * contain additional groups and/or elements.
090: *
091: * @param augs Additional information that may include infoset
092: * augmentations.
093: * @throws XNIException Thrown by handler to signal an error.
094: *
095: * @see #any
096: * @see #empty
097: */
098: public final void startGroup(Augmentations augs)
099: throws XNIException {
100: ++fDepth;
101: initializeContentModelStacks();
102: fMixed = false;
103: } // startGroup()
104:
105: /**
106: * The appearance of "#PCDATA" within a group signifying a
107: * mixed content model. This method will be the first called
108: * following the content model's <code>startGroup()</code>.
109: *
110: *@param augs Additional information that may include infoset
111: * augmentations.
112: *
113: * @throws XNIException Thrown by handler to signal an error.
114: *
115: * @see #startGroup
116: */
117: public final void pcdata(Augmentations augs) throws XNIException {
118: fMixed = true;
119: } // pcdata()
120:
121: /**
122: * A referenced element in a mixed or children content model.
123: *
124: * @param elementName The name of the referenced element.
125: * @param augs Additional information that may include infoset
126: * augmentations.
127: *
128: * @throws XNIException Thrown by handler to signal an error.
129: */
130: public final void element(String elementName, Augmentations augs)
131: 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)
148: throws XNIException {
149: if (separator == XMLDTDContentModelHandler.SEPARATOR_CHOICE) {
150: fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_CHOICE;
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)
171: throws XNIException {
172: if (!fMixed) {
173: int currentIndex = fGroupIndexStackSizes[fDepth] - 1;
174: if (occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE) {
175: fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(
176: XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE,
177: fGroupIndexStack[fDepth][currentIndex], -1);
178: } else if (occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE) {
179: fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(
180: XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE,
181: fGroupIndexStack[fDepth][currentIndex], -1);
182: } else if (occurrence == XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE) {
183: fGroupIndexStack[fDepth][currentIndex] = addContentSpecNode(
184: XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE,
185: fGroupIndexStack[fDepth][currentIndex], -1);
186: }
187: }
188: } // occurrence(short)
189:
190: /**
191: * The end of a group for mixed or children content models.
192: *
193: * @param augs Additional information that may include infoset
194: * augmentations.
195: * @throws XNIException Thrown by handler to signal an error.
196: */
197: public final void endGroup(Augmentations augs) throws XNIException {
198: final int length = fGroupIndexStackSizes[fDepth];
199: final int group = length > 0 ? addContentSpecNodes(0,
200: length - 1) : addUniqueLeafNode(null);
201: --fDepth;
202: addToCurrentGroup(group);
203: } // endGroup()
204:
205: /**
206: * The end of the DTD.
207: *
208: * @param augs Additional information that may include infoset
209: * augmentations.
210: * @throws XNIException Thrown by handler to signal an error.
211: */
212: public final void endDTD(Augmentations augs) throws XNIException {
213: super .endDTD(augs);
214: fOpStack = null;
215: fGroupIndexStack = null;
216: fGroupIndexStackSizes = null;
217: } // endDTD()
218:
219: //
220: // Protected methods
221: //
222:
223: /**
224: * Adds the content spec to the given element declaration.
225: */
226: protected final void addContentSpecToElement(
227: XMLElementDecl elementDecl) {
228: int contentSpec = fGroupIndexStackSizes[0] > 0 ? fGroupIndexStack[0][0]
229: : -1;
230: setContentSpecIndex(fCurrentElementIndex, contentSpec);
231: }
232:
233: //
234: // Private methods
235: //
236:
237: /**
238: * Creates a subtree from the leaf nodes at the current depth.
239: */
240: private int addContentSpecNodes(int begin, int end) {
241: if (begin == end) {
242: return fGroupIndexStack[fDepth][begin];
243: }
244: int middle = (begin + end) / 2;
245: return addContentSpecNode(fOpStack[fDepth],
246: addContentSpecNodes(begin, middle),
247: addContentSpecNodes(middle + 1, end));
248: } // addContentSpecNodes(int,int)
249:
250: /**
251: * Initialize the stacks which temporarily hold content models.
252: */
253: private void initializeContentModelStacks() {
254: if (fOpStack == null) {
255: fOpStack = new short[8];
256: fGroupIndexStack = new int[8][];
257: fGroupIndexStackSizes = new int[8];
258: } else if (fDepth == fOpStack.length) {
259: short[] newOpStack = new short[fDepth * 2];
260: System.arraycopy(fOpStack, 0, newOpStack, 0, fDepth);
261: fOpStack = newOpStack;
262: int[][] newGroupIndexStack = new int[fDepth * 2][];
263: System.arraycopy(fGroupIndexStack, 0, newGroupIndexStack,
264: 0, fDepth);
265: fGroupIndexStack = newGroupIndexStack;
266: int[] newGroupIndexStackLengths = new int[fDepth * 2];
267: System.arraycopy(fGroupIndexStackSizes, 0,
268: newGroupIndexStackLengths, 0, fDepth);
269: fGroupIndexStackSizes = newGroupIndexStackLengths;
270: }
271: fOpStack[fDepth] = -1;
272: fGroupIndexStackSizes[fDepth] = 0;
273: } // initializeContentModelStacks()
274:
275: /**
276: * Add XMLContentSpec to the current group.
277: *
278: * @param contentSpec handle to the XMLContentSpec to add to the current group
279: */
280: private void addToCurrentGroup(int contentSpec) {
281: int[] currentGroup = fGroupIndexStack[fDepth];
282: int length = fGroupIndexStackSizes[fDepth]++;
283: if (currentGroup == null) {
284: currentGroup = new int[8];
285: fGroupIndexStack[fDepth] = currentGroup;
286: } else if (length == currentGroup.length) {
287: int[] newGroup = new int[currentGroup.length * 2];
288: System.arraycopy(currentGroup, 0, newGroup, 0,
289: currentGroup.length);
290: currentGroup = newGroup;
291: fGroupIndexStack[fDepth] = currentGroup;
292: }
293: currentGroup[length] = contentSpec;
294: } // addToCurrentGroup(int)
295:
296: } // class BalancedDTDGrammar
|