alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (DTDGrammar.java)

This example Java source code file (DTDGrammar.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

augmentations, chunk_mask, chunk_shift, contentmodelvalidator, datatypevalidator, object, qname, qnamehashtable, string, util, xmlattributedecl, xmlcontentspec, xmlelementdecl, xmlentitydecl, xniexception

The DTDGrammar.java Java example source code

/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

package com.sun.org.apache.xerces.internal.impl.dtd;

import java.util.ArrayList;
import java.util.Hashtable;

import com.sun.org.apache.xerces.internal.impl.dtd.models.CMAny;
import com.sun.org.apache.xerces.internal.impl.dtd.models.CMBinOp;
import com.sun.org.apache.xerces.internal.impl.dtd.models.CMLeaf;
import com.sun.org.apache.xerces.internal.impl.dtd.models.CMNode;
import com.sun.org.apache.xerces.internal.impl.dtd.models.CMUniOp;
import com.sun.org.apache.xerces.internal.impl.dtd.models.ContentModelValidator;
import com.sun.org.apache.xerces.internal.impl.dtd.models.DFAContentModel;
import com.sun.org.apache.xerces.internal.impl.dtd.models.MixedContentModel;
import com.sun.org.apache.xerces.internal.impl.dtd.models.SimpleContentModel;
import com.sun.org.apache.xerces.internal.impl.dv.DatatypeValidator;
import com.sun.org.apache.xerces.internal.impl.validation.EntityState;
import com.sun.org.apache.xerces.internal.util.SymbolTable;
import com.sun.org.apache.xerces.internal.xni.Augmentations;
import com.sun.org.apache.xerces.internal.xni.QName;
import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
import com.sun.org.apache.xerces.internal.xni.XMLLocator;
import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
import com.sun.org.apache.xerces.internal.xni.XMLString;
import com.sun.org.apache.xerces.internal.xni.XNIException;
import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelSource;
import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource;

/**
 * A DTD grammar. This class implements the XNI handler interfaces
 * for DTD information so that it can build the approprate validation
 * structures automatically from the callbacks.
 *
 * @xerces.internal
 *
 * @author Eric Ye, IBM
 * @author Jeffrey Rodriguez, IBM
 * @author Andy Clark, IBM
 * @author Neil Graham, IBM
 *
 * @version $Id: DTDGrammar.java,v 1.4 2010/08/11 07:18:37 joehw Exp $
 */
public class DTDGrammar
    implements XMLDTDHandler, XMLDTDContentModelHandler, EntityState, Grammar {

    //
    // Constants
    //

    /** Top level scope (-1). */
    public static final int TOP_LEVEL_SCOPE = -1;

    // private

    /** Chunk shift (8). */
    private static final int CHUNK_SHIFT = 8; // 2^8 = 256

    /** Chunk size (1 << CHUNK_SHIFT). */
    private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);

    /** Chunk mask (CHUNK_SIZE - 1). */
    private static final int CHUNK_MASK = CHUNK_SIZE - 1;

    /** Initial chunk count (1 << (10 - CHUNK_SHIFT)). */
    private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k

    /** List flag (0x80). */
    private static final short LIST_FLAG = 0x80;

    /** List mask (~LIST_FLAG). */
    private static final short LIST_MASK = ~LIST_FLAG;

    // debugging

    /** Debug DTDGrammar. */
    private static final boolean DEBUG = false;

    //
    // Data
    //

    protected XMLDTDSource fDTDSource = null;
    protected XMLDTDContentModelSource fDTDContentModelSource = null;

    /** Current element index. */
    protected int fCurrentElementIndex;

    /** Current attribute index. */
    protected int fCurrentAttributeIndex;

    /** fReadingExternalDTD */
    protected boolean fReadingExternalDTD = false;

    /** Symbol table. */
    private SymbolTable fSymbolTable;

    // The XMLDTDDescription with which this Grammar is associated
    protected XMLDTDDescription fGrammarDescription = null;

    // element declarations

    /** Number of element declarations. */
    private int fElementDeclCount = 0;

    /** Element declaration name. */
    private QName fElementDeclName[][] = new QName[INITIAL_CHUNK_COUNT][];

    /**
     * Element declaration type.
     * @see XMLElementDecl
     */
    private short fElementDeclType[][] = new short[INITIAL_CHUNK_COUNT][];

    /**
     * Element declaration content spec index. This index value is used
     * to refer to the content spec information tables.
     */
    private int fElementDeclContentSpecIndex[][] = new int[INITIAL_CHUNK_COUNT][];

    /**
     * Element declaration content model validator. This validator is
     * constructed from the content spec nodes.
     */
    private ContentModelValidator fElementDeclContentModelValidator[][] = new ContentModelValidator[INITIAL_CHUNK_COUNT][];

    /** First attribute declaration of an element declaration. */
    private int fElementDeclFirstAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];

    /** Last attribute declaration of an element declaration. */
    private int fElementDeclLastAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];

    // attribute declarations

    /** Number of attribute declarations. */
    private int fAttributeDeclCount = 0 ;

    /** Attribute declaration name. */
    private QName fAttributeDeclName[][] = new QName[INITIAL_CHUNK_COUNT][];

    // is this grammar immutable?  (fully constructed and not changeable)
    private boolean fIsImmutable = false;

    /**
     * Attribute declaration type.
     * @see XMLAttributeDecl
     */
    private short fAttributeDeclType[][] = new short[INITIAL_CHUNK_COUNT][];

    /** Attribute declaration enumeration values. */
    private String[] fAttributeDeclEnumeration[][] = new String[INITIAL_CHUNK_COUNT][][];
    private short fAttributeDeclDefaultType[][] = new short[INITIAL_CHUNK_COUNT][];
    private DatatypeValidator fAttributeDeclDatatypeValidator[][] = new DatatypeValidator[INITIAL_CHUNK_COUNT][];
    private String fAttributeDeclDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][];
    private String fAttributeDeclNonNormalizedDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][];
    private int fAttributeDeclNextAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];

    // content specs

    // here saves the content spec binary trees for element decls,
    // each element with a content model will hold a pointer which is
    // the index of the head node of the content spec tree.

    private int fContentSpecCount = 0;
    private short fContentSpecType[][] = new short[INITIAL_CHUNK_COUNT][];
    private Object fContentSpecValue[][] = new Object[INITIAL_CHUNK_COUNT][];
    private Object fContentSpecOtherValue[][] = new Object[INITIAL_CHUNK_COUNT][];

    // entities

    private int fEntityCount = 0;
    private String fEntityName[][] = new String[INITIAL_CHUNK_COUNT][];
    private String[][] fEntityValue = new String[INITIAL_CHUNK_COUNT][];
    private String[][] fEntityPublicId = new String[INITIAL_CHUNK_COUNT][];
    private String[][] fEntitySystemId = new String[INITIAL_CHUNK_COUNT][];
    private String[][] fEntityBaseSystemId = new String[INITIAL_CHUNK_COUNT][];
    private String[][] fEntityNotation = new String[INITIAL_CHUNK_COUNT][];
    private byte[][] fEntityIsPE = new byte[INITIAL_CHUNK_COUNT][];
    private byte[][] fEntityInExternal = new byte[INITIAL_CHUNK_COUNT][];

    // notations

    private int fNotationCount = 0;
    private String fNotationName[][] = new String[INITIAL_CHUNK_COUNT][];
    private String[][] fNotationPublicId = new String[INITIAL_CHUNK_COUNT][];
    private String[][] fNotationSystemId = new String[INITIAL_CHUNK_COUNT][];
    private String[][] fNotationBaseSystemId = new String[INITIAL_CHUNK_COUNT][];

    // other information

    /** Element index mapping table. */
    private QNameHashtable fElementIndexMap = new QNameHashtable();

    /** Entity index mapping table. */
    private QNameHashtable fEntityIndexMap = new QNameHashtable();

    /** Notation index mapping table. */
    private QNameHashtable fNotationIndexMap = new QNameHashtable();

    // temp variables

    /** Mixed. */
    private boolean fMixed;

    /** Temporary qualified name. */
    private final QName fQName = new QName();

    /** Temporary qualified name. */
    private final QName fQName2 = new QName();

    /** Temporary Attribute decl. */
    protected final XMLAttributeDecl fAttributeDecl = new XMLAttributeDecl();

    // for buildSyntaxTree method

    private int fLeafCount = 0;
    private int fEpsilonIndex = -1;

    /** Element declaration. */
    private XMLElementDecl fElementDecl = new XMLElementDecl();

    /** Entity declaration. */
    private XMLEntityDecl fEntityDecl = new XMLEntityDecl();

    /** Simple type. */
    private XMLSimpleType fSimpleType = new XMLSimpleType();

    /** Content spec node. */
    private XMLContentSpec fContentSpec = new XMLContentSpec();

    /** table of XMLElementDecl   */
    Hashtable   fElementDeclTab     = new Hashtable();

    /** Children content model operation stack. */
    private short[] fOpStack = null;

    /** Children content model index stack. */
    private int[] fNodeIndexStack = null;

    /** Children content model previous node index stack. */
    private int[] fPrevNodeIndexStack = null;

    /** Stack depth   */
    private int fDepth = 0;

    /** Entity stack. */
    private boolean[] fPEntityStack = new boolean[4];
    private int fPEDepth = 0;

    // additional fields(columns) for the element Decl pool in the Grammar

    /** flag if the elementDecl is External. */
    private int fElementDeclIsExternal[][] = new int[INITIAL_CHUNK_COUNT][];


    // additional fields(columns) for the attribute Decl pool in the Grammar

    /** flag if the AttributeDecl is External. */
    private int fAttributeDeclIsExternal[][] = new int[INITIAL_CHUNK_COUNT][];

    // for mixedElement method

    int valueIndex            = -1;
    int prevNodeIndex         = -1;
    int nodeIndex             = -1;

    //
    // Constructors
    //

    /** Default constructor. */
    public DTDGrammar(SymbolTable symbolTable, XMLDTDDescription desc) {
        fSymbolTable = symbolTable;
        fGrammarDescription = desc;
    } // <init>(SymbolTable)

    // Grammar methods

    // return the XMLDTDDescription object with which this is associated
    public XMLGrammarDescription getGrammarDescription() {
        return fGrammarDescription;
    } // getGrammarDescription():  XMLGrammarDescription

    //
    // Public methods
    //

    /**
     * Returns true if the specified element declaration is external.
     *
     * @param elementDeclIndex The element declaration index.
     */
    public boolean getElementDeclIsExternal(int elementDeclIndex) {

        if (elementDeclIndex < 0) {
            return false;
        }

        int chunk = elementDeclIndex >> CHUNK_SHIFT;
        int index = elementDeclIndex & CHUNK_MASK;
        return (fElementDeclIsExternal[chunk][index] != 0);

    } // getElementDeclIsExternal(int):boolean

    /**
     * Returns true if the specified attribute declaration is external.
     *
     * @param attributeDeclIndex Attribute declaration index.
     */
    public boolean getAttributeDeclIsExternal(int attributeDeclIndex) {

        if (attributeDeclIndex < 0) {
            return false;
        }

        int chunk = attributeDeclIndex >> CHUNK_SHIFT;
        int index = attributeDeclIndex & CHUNK_MASK;
        return (fAttributeDeclIsExternal[chunk][index] != 0);
    }

    public int getAttributeDeclIndex(int elementDeclIndex, String attributeDeclName) {
        if (elementDeclIndex == -1) {
            return -1;
        }
        int attDefIndex = getFirstAttributeDeclIndex(elementDeclIndex);
        while (attDefIndex != -1) {
            getAttributeDecl(attDefIndex, fAttributeDecl);

            if (fAttributeDecl.name.rawname == attributeDeclName
                || attributeDeclName.equals(fAttributeDecl.name.rawname) ) {
                return attDefIndex;
            }
            attDefIndex = getNextAttributeDeclIndex(attDefIndex);
        }
        return -1;
    } // getAttributeDeclIndex (int,QName)

    //
    // XMLDTDHandler methods
    //

    /**
     * The start of the DTD.
     *
     * @param locator  The document locator, or null if the document
     *                 location cannot be reported during the parsing of
     *                 the document DTD. However, it is <em>strongly
     *                 recommended that a locator be supplied that can
     *                 at least report the base system identifier of the
     *                 DTD.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException {
        //Initialize stack
        fOpStack = null;
        fNodeIndexStack = null;
        fPrevNodeIndexStack = null;
    } // startDTD(XMLLocator)

    /**
     * This method notifies of the start of an entity. The DTD has the
     * pseudo-name of "[dtd]" and parameter entity names start with '%'.
     * <p>
     * <strong>Note: Since the DTD is an entity, the handler
     * will be notified of the start of the DTD entity by calling the
     * startParameterEntity method with the entity name "[dtd]" <em>before calling
     * the startDTD method.
     *
     * @param name     The name of the parameter entity.
     * @param identifier The resource identifier.
     * @param encoding The auto-detected IANA encoding name of the entity
     *                 stream. This value will be null in those situations
     *                 where the entity encoding is not auto-detected (e.g.
     *                 internal parameter entities).
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startParameterEntity(String name,
                                     XMLResourceIdentifier identifier,
                                     String encoding,
                                     Augmentations augs) throws XNIException {

        // keep track of this entity before fEntityDepth is increased
        if (fPEDepth == fPEntityStack.length) {
            boolean[] entityarray = new boolean[fPEntityStack.length * 2];
            System.arraycopy(fPEntityStack, 0, entityarray, 0, fPEntityStack.length);
            fPEntityStack = entityarray;
        }
        fPEntityStack[fPEDepth] = fReadingExternalDTD;
        fPEDepth++;

    } // startParameterEntity(String,XMLResourceIdentifier,String,Augmentations)

    /**
     * The start of the DTD external subset.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startExternalSubset(XMLResourceIdentifier identifier,
                                    Augmentations augs) throws XNIException {
        fReadingExternalDTD = true;
    } // startExternalSubset(Augmentations)

    /**
     * This method notifies the end of an entity. The DTD has the pseudo-name
     * of "[dtd]" and parameter entity names start with '%'.
     * <p>
     * <strong>Note: Since the DTD is an entity, the handler
     * will be notified of the end of the DTD entity by calling the
     * endEntity method with the entity name "[dtd]" <em>after calling
     * the endDTD method.
     *
     * @param name The name of the entity.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endParameterEntity(String name, Augmentations augs) throws XNIException {

        fPEDepth--;
        fReadingExternalDTD = fPEntityStack[fPEDepth];

    } // endParameterEntity(String,Augmentations)

    /**
     * The end of the DTD external subset.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endExternalSubset(Augmentations augs) throws XNIException {
        fReadingExternalDTD = false;
    } // endExternalSubset(Augmentations)

    /**
     * An element declaration.
     *
     * @param name         The name of the element.
     * @param contentModel The element content model.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void elementDecl(String name, String contentModel, Augmentations augs)
        throws XNIException {

        XMLElementDecl tmpElementDecl = (XMLElementDecl) fElementDeclTab.get(name) ;

        // check if it is already defined
        if ( tmpElementDecl != null ) {
            if (tmpElementDecl.type == -1) {
                fCurrentElementIndex = getElementDeclIndex(name);
            }
            else {
                // duplicate element, ignored.
                return;
            }
        }
        else {
            fCurrentElementIndex = createElementDecl();//create element decl
        }

        XMLElementDecl elementDecl       = new XMLElementDecl();

        fQName.setValues(null, name, name, null);

        elementDecl.name.setValues(fQName);

        elementDecl.contentModelValidator = null;
        elementDecl.scope= -1;
        if (contentModel.equals("EMPTY")) {
            elementDecl.type = XMLElementDecl.TYPE_EMPTY;
        }
        else if (contentModel.equals("ANY")) {
            elementDecl.type = XMLElementDecl.TYPE_ANY;
        }
        else if (contentModel.startsWith("(") ) {
            if (contentModel.indexOf("#PCDATA") > 0 ) {
                elementDecl.type = XMLElementDecl.TYPE_MIXED;
            }
            else {
                elementDecl.type = XMLElementDecl.TYPE_CHILDREN;
            }
        }


        //add(or set) this elementDecl to the local cache
        this.fElementDeclTab.put(name, elementDecl );

        fElementDecl = elementDecl;
        addContentSpecToElement(elementDecl);

        if ( DEBUG ) {
            System.out.println(  "name = " + fElementDecl.name.localpart );
            System.out.println(  "Type = " + fElementDecl.type );
        }

        setElementDecl(fCurrentElementIndex, fElementDecl );//set internal structure

        int chunk = fCurrentElementIndex >> CHUNK_SHIFT;
        int index = fCurrentElementIndex & CHUNK_MASK;
        ensureElementDeclCapacity(chunk);
        fElementDeclIsExternal[chunk][index] = (fReadingExternalDTD || fPEDepth > 0) ? 1 : 0;

    } // elementDecl(String,String)

    /**
     * An attribute declaration.
     *
     * @param elementName   The name of the element that this attribute
     *                      is associated with.
     * @param attributeName The name of the attribute.
     * @param type          The attribute type. This value will be one of
     *                      the following: "CDATA", "ENTITY", "ENTITIES",
     *                      "ENUMERATION", "ID", "IDREF", "IDREFS",
     *                      "NMTOKEN", "NMTOKENS", or "NOTATION".
     * @param enumeration   If the type has the value "ENUMERATION", this
     *                      array holds the allowed attribute values;
     *                      otherwise, this array is null.
     * @param defaultType   The attribute default type. This value will be
     *                      one of the following: "#FIXED", "#IMPLIED",
     *                      "#REQUIRED", or null.
     * @param defaultValue  The attribute default value, or null if no
     *                      default value is specified.
     * @param nonNormalizedDefaultValue  The attribute default value with no normalization
     *                      performed, or null if no default value is specified.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void attributeDecl(String elementName, String attributeName,
                              String type, String[] enumeration,
                              String defaultType, XMLString defaultValue,
                              XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {

        if ( this.fElementDeclTab.containsKey( (String) elementName) ) {
            //if ElementDecl has already being created in the Grammar then remove from table,
            //this.fElementDeclTab.remove( (String) elementName );
        }
        // then it is forward reference to a element decl, create the elementDecl first.
        else {
            fCurrentElementIndex = createElementDecl();//create element decl

            XMLElementDecl elementDecl       = new XMLElementDecl();
            elementDecl.name.setValues(null, elementName, elementName, null);

            elementDecl.scope= -1;

            //add(or set) this elementDecl to the local cache
            this.fElementDeclTab.put(elementName, elementDecl );

            //set internal structure
            setElementDecl(fCurrentElementIndex, elementDecl );
        }

        //Get Grammar index to grammar array
        int elementIndex       = getElementDeclIndex(elementName);

        //return, when more than one definition is provided for the same attribute of given element type
        //only the first declaration is binding and later declarations are ignored
        if (getAttributeDeclIndex(elementIndex, attributeName) != -1) {
            return;
        }

        fCurrentAttributeIndex = createAttributeDecl();// Create current Attribute Decl

        fSimpleType.clear();
        if ( defaultType != null ) {
            if ( defaultType.equals( "#FIXED") ) {
                fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_FIXED;
            } else if ( defaultType.equals( "#IMPLIED") ) {
                fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_IMPLIED;
            } else if ( defaultType.equals( "#REQUIRED") ) {
                fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_REQUIRED;
            }
        }
        if ( DEBUG ) {
            System.out.println("defaultvalue = " + defaultValue.toString() );
        }
        fSimpleType.defaultValue      = defaultValue!=null ?  defaultValue.toString() : null;
        fSimpleType.nonNormalizedDefaultValue      = nonNormalizedDefaultValue!=null ?  nonNormalizedDefaultValue.toString() : null;
        fSimpleType.enumeration       = enumeration;

        if (type.equals("CDATA")) {
            fSimpleType.type = XMLSimpleType.TYPE_CDATA;
        }
        else if ( type.equals("ID") ) {
            fSimpleType.type = XMLSimpleType.TYPE_ID;
        }
        else if ( type.startsWith("IDREF") ) {
            fSimpleType.type = XMLSimpleType.TYPE_IDREF;
            if (type.indexOf("S") > 0) {
                fSimpleType.list = true;
            }
        }
        else if (type.equals("ENTITIES")) {
            fSimpleType.type = XMLSimpleType.TYPE_ENTITY;
            fSimpleType.list = true;
        }
        else if (type.equals("ENTITY")) {
            fSimpleType.type = XMLSimpleType.TYPE_ENTITY;
        }
        else if (type.equals("NMTOKENS")) {
            fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN;
            fSimpleType.list = true;
        }
        else if (type.equals("NMTOKEN")) {
            fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN;
        }
        else if (type.startsWith("NOTATION") ) {
            fSimpleType.type = XMLSimpleType.TYPE_NOTATION;
        }
        else if (type.startsWith("ENUMERATION") ) {
            fSimpleType.type = XMLSimpleType.TYPE_ENUMERATION;
        }
        else {
            // REVISIT: Report error message. -Ac
            System.err.println("!!! unknown attribute type "+type);
        }
        // REVISIT: The datatype should be stored with the attribute value
        //          and not special-cased in the XMLValidator. -Ac
        //fSimpleType.datatypeValidator = fDatatypeValidatorFactory.createDatatypeValidator(type, null, facets, fSimpleType.list);

        fQName.setValues(null, attributeName, attributeName, null);
        fAttributeDecl.setValues( fQName, fSimpleType, false );

        setAttributeDecl(elementIndex, fCurrentAttributeIndex, fAttributeDecl);

        int chunk = fCurrentAttributeIndex >> CHUNK_SHIFT;
        int index = fCurrentAttributeIndex & CHUNK_MASK;
        ensureAttributeDeclCapacity(chunk);
        fAttributeDeclIsExternal[chunk][index] = (fReadingExternalDTD || fPEDepth > 0) ?  1 : 0;

    } // attributeDecl(String,String,String,String[],String,XMLString,XMLString, Augmentations)

    /**
     * An internal entity declaration.
     *
     * @param name The name of the entity. Parameter entity names start with
     *             '%', whereas the name of a general entity is just the
     *             entity name.
     * @param text The value of the entity.
     * @param nonNormalizedText The non-normalized value of the entity. This
     *             value contains the same sequence of characters that was in
     *             the internal entity declaration, without any entity
     *             references expanded.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void internalEntityDecl(String name, XMLString text,
                                   XMLString nonNormalizedText,
                                   Augmentations augs) throws XNIException {

        int entityIndex = getEntityDeclIndex(name);
        if( entityIndex == -1){
            entityIndex = createEntityDecl();
            boolean isPE = name.startsWith("%");
            boolean inExternal = (fReadingExternalDTD || fPEDepth > 0);
            XMLEntityDecl  entityDecl = new XMLEntityDecl();
            entityDecl.setValues(name,null,null, null, null,
                                 text.toString(), isPE, inExternal);

            setEntityDecl(entityIndex, entityDecl);
        }

    } // internalEntityDecl(String,XMLString,XMLString)

    /**
     * An external entity declaration.
     *
     * @param name     The name of the entity. Parameter entity names start
     *                 with '%', whereas the name of a general entity is just
     *                 the entity name.
     * @param identifier    An object containing all location information
     *                      pertinent to this external entity declaration.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void externalEntityDecl(String name,
                                   XMLResourceIdentifier identifier,
                                   Augmentations augs) throws XNIException {

        int entityIndex = getEntityDeclIndex(name);
        if( entityIndex == -1){
            entityIndex = createEntityDecl();
            boolean isPE = name.startsWith("%");
            boolean inExternal = (fReadingExternalDTD || fPEDepth > 0);

            XMLEntityDecl  entityDecl = new XMLEntityDecl();
            entityDecl.setValues(name, identifier.getPublicId(), identifier.getLiteralSystemId(),
                                identifier.getBaseSystemId(),
                                null, null, isPE, inExternal);

            setEntityDecl(entityIndex, entityDecl);
        }
    } // externalEntityDecl(String, XMLResourceIdentifier, Augmentations)

    /**
     * An unparsed entity declaration.
     *
     * @param name     The name of the entity.
     * @param identifier    An object containing all location information
     *                      pertinent to this entity.
     * @param notation The name of the notation.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier,
                                   String notation,
                                   Augmentations augs) throws XNIException {

        XMLEntityDecl  entityDecl = new XMLEntityDecl();
        boolean isPE = name.startsWith("%");
        boolean inExternal = (fReadingExternalDTD || fPEDepth > 0);

        entityDecl.setValues(name,identifier.getPublicId(),identifier.getLiteralSystemId(),
                            identifier.getBaseSystemId(), notation,
                            null, isPE, inExternal);
        int entityIndex = getEntityDeclIndex(name);
        if (entityIndex == -1) {
            entityIndex = createEntityDecl();
            setEntityDecl(entityIndex, entityDecl);
        }

    } // unparsedEntityDecl(String,StringXMLResourceIdentifier,Augmentations)

    /**
     * A notation declaration
     *
     * @param name     The name of the notation.
     * @param identifier    An object containing all location information
     *                      pertinent to this notation.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void notationDecl(String name, XMLResourceIdentifier identifier,
                             Augmentations augs) throws XNIException {

        XMLNotationDecl  notationDecl = new XMLNotationDecl();
        notationDecl.setValues(name,identifier.getPublicId(),identifier.getLiteralSystemId(),
                identifier.getBaseSystemId());
        int notationIndex = getNotationDeclIndex(name);
        if (notationIndex == -1) {
            notationIndex = createNotationDecl();
            setNotationDecl(notationIndex, notationDecl);
        }

    } // notationDecl(String,XMLResourceIdentifier,Augmentations)

    /**
     * The end of the DTD.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endDTD(Augmentations augs) throws XNIException {
        fIsImmutable = true;
        // make sure our description contains useful stuff...
        if (fGrammarDescription.getRootName() == null) {
            // we don't know what the root is; so use possibleRoots...
            int chunk, index = 0;
            String currName = null;
            final int size = fElementDeclCount;
            ArrayList elements = new ArrayList(size);
            for (int i = 0; i < size; ++i) {
                chunk = i >> CHUNK_SHIFT;
                index = i & CHUNK_MASK;
                currName = fElementDeclName[chunk][index].rawname;
                elements.add(currName);
            }
            fGrammarDescription.setPossibleRoots(elements);
        }
    } // endDTD()

    // sets the source of this handler
    public void setDTDSource(XMLDTDSource source) {
        fDTDSource = source;
    } // setDTDSource(XMLDTDSource)

    // returns the source of this handler
    public XMLDTDSource getDTDSource() {
        return fDTDSource;
    } // getDTDSource():  XMLDTDSource

    // no-op methods

    /**
     * Notifies of the presence of a TextDecl line in an entity. If present,
     * this method will be called immediately following the startEntity call.
     * <p>
     * <strong>Note: This method is only called for external
     * parameter entities referenced in the DTD.
     *
     * @param version  The XML version, or null if not specified.
     * @param encoding The IANA encoding name of the entity.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void textDecl(String version, String encoding, Augmentations augs)
        throws XNIException {}

    /**
     * A comment.
     *
     * @param text The text in the comment.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by application to signal an error.
     */
    public void comment(XMLString text, Augmentations augs) throws XNIException {}

    /**
     * A processing instruction. Processing instructions consist of a
     * target name and, optionally, text data. The data is only meaningful
     * to the application.
     * <p>
     * Typically, a processing instruction's data will contain a series
     * of pseudo-attributes. These pseudo-attributes follow the form of
     * element attributes but are <strong>not parsed or presented
     * to the application as anything other than text. The application is
     * responsible for parsing the data.
     *
     * @param target The target.
     * @param data   The data or null if none specified.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void processingInstruction(String target, XMLString data,
                                      Augmentations augs) throws XNIException {}

    /**
     * The start of an attribute list.
     *
     * @param elementName The name of the element that this attribute
     *                    list is associated with.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startAttlist(String elementName, Augmentations augs)
        throws XNIException {}

    /**
     * The end of an attribute list.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endAttlist(Augmentations augs) throws XNIException {}

    /**
     * The start of a conditional section.
     *
     * @param type The type of the conditional section. This value will
     *             either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     *
     * @see XMLDTDHandler#CONDITIONAL_INCLUDE
     * @see XMLDTDHandler#CONDITIONAL_IGNORE
     */
    public void startConditional(short type, Augmentations augs)
        throws XNIException {}

    /**
     * Characters within an IGNORE conditional section.
     *
     * @param text The ignored text.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     */
    public void ignoredCharacters(XMLString text, Augmentations augs)
        throws XNIException {}

    /**
     * The end of a conditional section.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endConditional(Augmentations augs) throws XNIException {}

    //
    // XMLDTDContentModelHandler methods
    //

    // set content model source
    public void setDTDContentModelSource(XMLDTDContentModelSource source) {
        fDTDContentModelSource = source;
    }

    // get content model source
    public XMLDTDContentModelSource getDTDContentModelSource() {
        return fDTDContentModelSource;
    }

    /**
     * The start of a content model. Depending on the type of the content
     * model, specific methods may be called between the call to the
     * startContentModel method and the call to the endContentModel method.
     *
     * @param elementName The name of the element.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void startContentModel(String elementName, Augmentations augs)
        throws XNIException {

        XMLElementDecl elementDecl = (XMLElementDecl) this.fElementDeclTab.get( elementName);
        if ( elementDecl != null ) {
            fElementDecl = elementDecl;
        }
        fDepth = 0;
        initializeContentModelStack();

    } // startContentModel(String)

    /**
     * A start of either a mixed or children content model. A mixed
     * content model will immediately be followed by a call to the
     * <code>pcdata() method. A children content model will
     * contain additional groups and/or elements.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     *
     * @see #any
     * @see #empty
     */
    public void startGroup(Augmentations augs) throws XNIException {
        fDepth++;
        initializeContentModelStack();
        fMixed = false;
    } // startGroup()

    /**
     * The appearance of "#PCDATA" within a group signifying a
     * mixed content model. This method will be the first called
     * following the content model's <code>startGroup().
     *
     *@param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     *
     * @see #startGroup
     */
    public void pcdata(Augmentations augs) throws XNIException {
        fMixed = true;
    } // pcdata()

    /**
     * A referenced element in a mixed or children content model.
     *
     * @param elementName The name of the referenced element.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void element(String elementName, Augmentations augs) throws XNIException {
        if (fMixed) {
            if (fNodeIndexStack[fDepth] == -1 ) {
                fNodeIndexStack[fDepth] = addUniqueLeafNode(elementName);
            }
            else {
                fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_CHOICE,
                                                             fNodeIndexStack[fDepth],
                                                             addUniqueLeafNode(elementName));
            }
        }
        else {
            fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF, elementName);
        }
    } // element(String)

    /**
     * The separator between choices or sequences of a mixed or children
     * content model.
     *
     * @param separator The type of children separator.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     *
     * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_CHOICE
     * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_SEQUENCE
     */
    public void separator(short separator, Augmentations augs) throws XNIException {

        if (!fMixed) {
            if (fOpStack[fDepth] != XMLContentSpec.CONTENTSPECNODE_SEQ && separator == XMLDTDContentModelHandler.SEPARATOR_CHOICE ) {
                if (fPrevNodeIndexStack[fDepth] != -1) {
                    fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]);
                }
                fPrevNodeIndexStack[fDepth] = fNodeIndexStack[fDepth];
                fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_CHOICE;
            } else if (fOpStack[fDepth] != XMLContentSpec.CONTENTSPECNODE_CHOICE && separator == XMLDTDContentModelHandler.SEPARATOR_SEQUENCE) {
                if (fPrevNodeIndexStack[fDepth] != -1) {
                    fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]);
                }
                fPrevNodeIndexStack[fDepth] = fNodeIndexStack[fDepth];
                fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_SEQ;
            }
        }

    } // separator(short)

    /**
     * The occurrence count for a child in a children content model or
     * for the mixed content model group.
     *
     * @param occurrence The occurrence count for the last element
     *                   or group.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     *
     * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_ONE
     * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_MORE
     * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ONE_OR_MORE
     */
    public void occurrence(short occurrence, Augmentations augs) throws XNIException {

        if (!fMixed) {
            if (occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE ) {
                fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, fNodeIndexStack[fDepth], -1);
            } else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE ) {
                fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE, fNodeIndexStack[fDepth], -1 );
            } else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE) {
                fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE, fNodeIndexStack[fDepth], -1 );
            }
        }

    } // occurrence(short)

    /**
     * The end of a group for mixed or children content models.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endGroup(Augmentations augs) throws XNIException {

        if (!fMixed) {
            if (fPrevNodeIndexStack[fDepth] != -1) {
                fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]);
            }
            int nodeIndex = fNodeIndexStack[fDepth--];
            fNodeIndexStack[fDepth] = nodeIndex;
        }

    } // endGroup()

    // no-op methods

    /**
     * A content model of ANY.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     *
     * @see #empty
     * @see #startGroup
     */
    public void any(Augmentations augs) throws XNIException {}

    /**
     * A content model of EMPTY.
     *
     * @param augs Additional information that may include infoset
     *                      augmentations.
     * @throws XNIException Thrown by handler to signal an error.
     *
     * @see #any
     * @see #startGroup
     */
    public void empty(Augmentations augs) throws XNIException {}

    /**
     * The end of a content model.
     * @param augs Additional information that may include infoset
     *                      augmentations.
     *
     * @throws XNIException Thrown by handler to signal an error.
     */
    public void endContentModel(Augmentations augs) throws XNIException {}

    //
    // Grammar methods
    //

    /** Returns true if this grammar is namespace aware. */
    public boolean isNamespaceAware() {
        return false;
    } // isNamespaceAware():boolean

    /** Returns the symbol table. */
    public SymbolTable getSymbolTable() {
        return fSymbolTable;
    } // getSymbolTable():SymbolTable

    /**
     * Returns the index of the first element declaration. This index
     * is then used to query more information about the element declaration.
     *
     * @see #getNextElementDeclIndex
     * @see #getElementDecl
     */
    public int getFirstElementDeclIndex() {
        return fElementDeclCount >= 0 ? 0 : -1;
    } // getFirstElementDeclIndex():int

    /**
     * Returns the next index of the element declaration following the
     * specified element declaration.
     *
     * @param elementDeclIndex The element declaration index.
     */
    public int getNextElementDeclIndex(int elementDeclIndex) {
        return elementDeclIndex < fElementDeclCount - 1
             ? elementDeclIndex + 1 : -1;
    } // getNextElementDeclIndex(int):int

    /**
     * getElementDeclIndex
     *
     * @param elementDeclName
     *
     * @return index of the elementDeclName in scope
     */
    public int getElementDeclIndex(String elementDeclName) {
        int mapping = fElementIndexMap.get(elementDeclName);
        //System.out.println("getElementDeclIndex("+elementDeclName+") -> "+mapping);
        return mapping;
    } // getElementDeclIndex(String):int

    /** Returns the element decl index.
     * @param elementDeclQName qualilfied name of the element
     */
    public int getElementDeclIndex(QName elementDeclQName) {
        return getElementDeclIndex(elementDeclQName.rawname);
    } // getElementDeclIndex(QName):int

                /** make separate function for getting contentSpecType of element.
      * we can avoid setting of the element values.
                */

                public short getContentSpecType(int elementIndex){
        if (elementIndex < 0 || elementIndex >= fElementDeclCount) {
            return -1 ;
        }

        int chunk = elementIndex >> CHUNK_SHIFT;
        int index = elementIndex &  CHUNK_MASK;

        if(fElementDeclType[chunk][index] == -1){
            return -1 ;
                            }
        else{
                                       return (short) (fElementDeclType[chunk][index] & LIST_MASK);
                            }

                }//getContentSpecType

    /**
     * getElementDecl
     *
     * @param elementDeclIndex
     * @param elementDecl The values of this structure are set by this call.
     *
     * @return True if find the element, False otherwise.
     */
    public boolean getElementDecl(int elementDeclIndex,
                                  XMLElementDecl elementDecl) {

        if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
            return false;
        }

        int chunk = elementDeclIndex >> CHUNK_SHIFT;
        int index = elementDeclIndex &  CHUNK_MASK;

        elementDecl.name.setValues(fElementDeclName[chunk][index]);

        if (fElementDeclType[chunk][index] == -1) {
            elementDecl.type                    = -1;
            elementDecl.simpleType.list = false;
        } else {
            elementDecl.type            = (short) (fElementDeclType[chunk][index] & LIST_MASK);
            elementDecl.simpleType.list = (fElementDeclType[chunk][index] & LIST_FLAG) != 0;
        }

        /* Validators are null until we add that code */
        if (elementDecl.type == XMLElementDecl.TYPE_CHILDREN || elementDecl.type == XMLElementDecl.TYPE_MIXED) {
            elementDecl.contentModelValidator = getElementContentModelValidator(elementDeclIndex);
        }

        elementDecl.simpleType.datatypeValidator = null;
        elementDecl.simpleType.defaultType       = -1;
        elementDecl.simpleType.defaultValue      = null;

        return true;

    } // getElementDecl(int,XMLElementDecl):boolean

    QName getElementDeclName(int elementDeclIndex) {
        if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
            return null;
        }
        int chunk = elementDeclIndex >> CHUNK_SHIFT;
        int index = elementDeclIndex &  CHUNK_MASK;
        return fElementDeclName[chunk][index];
    }

    // REVISIT: Make this getAttributeDeclCount/getAttributeDeclAt. -Ac

    /**
     * getFirstAttributeDeclIndex
     *
     * @param elementDeclIndex
     *
     * @return index of the first attribute for element declaration elementDeclIndex
     */
    public int getFirstAttributeDeclIndex(int elementDeclIndex) {
        int chunk = elementDeclIndex >> CHUNK_SHIFT;
        int index = elementDeclIndex &  CHUNK_MASK;

        return  fElementDeclFirstAttributeDeclIndex[chunk][index];
    } // getFirstAttributeDeclIndex

    /**
     * getNextAttributeDeclIndex
     *
     * @param attributeDeclIndex
     *
     * @return index of the next attribute of the attribute at attributeDeclIndex
     */
    public int getNextAttributeDeclIndex(int attributeDeclIndex) {
        int chunk = attributeDeclIndex >> CHUNK_SHIFT;
        int index = attributeDeclIndex &  CHUNK_MASK;

        return fAttributeDeclNextAttributeDeclIndex[chunk][index];
    } // getNextAttributeDeclIndex

    /**
     * getAttributeDecl
     *
     * @param attributeDeclIndex
     * @param attributeDecl The values of this structure are set by this call.
     *
     * @return true if getAttributeDecl was able to fill in the value of attributeDecl
     */
    public boolean getAttributeDecl(int attributeDeclIndex, XMLAttributeDecl attributeDecl) {
        if (attributeDeclIndex < 0 || attributeDeclIndex >= fAttributeDeclCount) {
            return false;
        }
        int chunk = attributeDeclIndex >> CHUNK_SHIFT;
        int index = attributeDeclIndex & CHUNK_MASK;

        attributeDecl.name.setValues(fAttributeDeclName[chunk][index]);

        short attributeType;
        boolean isList;

        if (fAttributeDeclType[chunk][index] == -1) {

            attributeType = -1;
            isList = false;
        } else {
            attributeType = (short) (fAttributeDeclType[chunk][index] & LIST_MASK);
            isList = (fAttributeDeclType[chunk][index] & LIST_FLAG) != 0;
        }
        attributeDecl.simpleType.setValues(attributeType,fAttributeDeclName[chunk][index].localpart,
                                           fAttributeDeclEnumeration[chunk][index],
                                           isList, fAttributeDeclDefaultType[chunk][index],
                                           fAttributeDeclDefaultValue[chunk][index],
                                           fAttributeDeclNonNormalizedDefaultValue[chunk][index],
                                           fAttributeDeclDatatypeValidator[chunk][index]);
        return true;

    } // getAttributeDecl


    /**
     * Returns whether the given attribute is of type CDATA or not
     *
     * @param elName The element name.
     * @param atName The attribute name.
     *
     * @return true if the attribute is of type CDATA
     */
    public boolean isCDATAAttribute(QName elName, QName atName) {
        int elDeclIdx = getElementDeclIndex(elName);
        if (getAttributeDecl(elDeclIdx, fAttributeDecl)
            && fAttributeDecl.simpleType.type != XMLSimpleType.TYPE_CDATA){
            return false;
        }
        return true;
    }

    /**
     * getEntityDeclIndex
     *
     * @param entityDeclName
     *
     * @return the index of the EntityDecl
     */
    public int getEntityDeclIndex(String entityDeclName) {
        if (entityDeclName == null) {
            return -1;
        }

        return fEntityIndexMap.get(entityDeclName);
    } // getEntityDeclIndex

    /**
     * getEntityDecl
     *
     * @param entityDeclIndex
     * @param entityDecl
     *
     * @return true if getEntityDecl was able to fill entityDecl with the contents of the entity
     * with index entityDeclIndex
     */
    public boolean getEntityDecl(int entityDeclIndex, XMLEntityDecl entityDecl) {
        if (entityDeclIndex < 0 || entityDeclIndex >= fEntityCount) {
            return false;
        }
        int chunk = entityDeclIndex >> CHUNK_SHIFT;
        int index = entityDeclIndex & CHUNK_MASK;

        entityDecl.setValues(fEntityName[chunk][index],
                             fEntityPublicId[chunk][index],
                             fEntitySystemId[chunk][index],
                             fEntityBaseSystemId[chunk][index],
                             fEntityNotation[chunk][index],
                             fEntityValue[chunk][index],
                             fEntityIsPE[chunk][index] == 0 ? false : true ,
                             fEntityInExternal[chunk][index] == 0 ? false : true );

        return true;
    } // getEntityDecl

    /**
     * getNotationDeclIndex
     *
     * @param notationDeclName
     *
     * @return the index if found a notation with the name, otherwise -1.
     */
    public int getNotationDeclIndex(String notationDeclName) {
        if (notationDeclName == null) {
            return -1;
        }

        return fNotationIndexMap.get(notationDeclName);
    } // getNotationDeclIndex

    /**
     * getNotationDecl
     *
     * @param notationDeclIndex
     * @param notationDecl
     *
     * @return return true of getNotationDecl can fill notationDecl with information about
     * the notation at notationDeclIndex.
     */
    public boolean getNotationDecl(int notationDeclIndex, XMLNotationDecl notationDecl) {
        if (notationDeclIndex < 0 || notationDeclIndex >= fNotationCount) {
            return false;
        }
        int chunk = notationDeclIndex >> CHUNK_SHIFT;
        int index = notationDeclIndex & CHUNK_MASK;

        notationDecl.setValues(fNotationName[chunk][index],
                               fNotationPublicId[chunk][index],
                               fNotationSystemId[chunk][index],
                               fNotationBaseSystemId[chunk][index]);

        return true;

    } // getNotationDecl

    /**
     * getContentSpec
     *
     * @param contentSpecIndex
     * @param contentSpec
     *
     * @return true if find the requested contentSpec node, false otherwise
     */
    public boolean getContentSpec(int contentSpecIndex, XMLContentSpec contentSpec) {
        if (contentSpecIndex < 0 || contentSpecIndex >= fContentSpecCount )
            return false;

        int chunk = contentSpecIndex >> CHUNK_SHIFT;
        int index = contentSpecIndex & CHUNK_MASK;

        contentSpec.type       = fContentSpecType[chunk][index];
        contentSpec.value      = fContentSpecValue[chunk][index];
        contentSpec.otherValue = fContentSpecOtherValue[chunk][index];
        return true;
    }

    /**
     * Returns the index to the content spec for the given element
     * declaration, or <code>-1 if the element declaration
     * index was invalid.
     */
    public int getContentSpecIndex(int elementDeclIndex) {
        if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
            return -1;
        }
        final int chunk = elementDeclIndex >> CHUNK_SHIFT;
        final int index = elementDeclIndex & CHUNK_MASK;
        return fElementDeclContentSpecIndex[chunk][index];
    }

    /**
     * getContentSpecAsString
     *
     * @param elementDeclIndex
     *
     * @return String
     */
    public String getContentSpecAsString(int elementDeclIndex){

        if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
            return null;
        }

        int chunk = elementDeclIndex >> CHUNK_SHIFT;
        int index = elementDeclIndex &  CHUNK_MASK;

        int contentSpecIndex = fElementDeclContentSpecIndex[chunk][index];

        // lookup content spec node
        XMLContentSpec contentSpec = new XMLContentSpec();

        if (getContentSpec(contentSpecIndex, contentSpec)) {

            // build string
            StringBuffer str = new StringBuffer();
            int    parentContentSpecType = contentSpec.type & 0x0f;
            int    nextContentSpec;
            switch (parentContentSpecType) {
                case XMLContentSpec.CONTENTSPECNODE_LEAF: {
                    str.append('(');
                    if (contentSpec.value == null && contentSpec.otherValue == null) {
                        str.append("#PCDATA");
                    }
                    else {
                        str.append(contentSpec.value);
                    }
                    str.append(')');
                    break;
                }
                case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: {
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    nextContentSpec = contentSpec.type;

                    if (nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) {
                        str.append('(');
                        str.append(contentSpec.value);
                        str.append(')');
                    } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE  ||
                        nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE  ||
                        nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
                        str.append('(' );
                        appendContentSpec(contentSpec, str,
                                          true, parentContentSpecType );
                        str.append(')');
                    } else {
                        appendContentSpec(contentSpec, str,
                                          true, parentContentSpecType );
                    }
                    str.append('?');
                    break;
                }
                case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: {
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    nextContentSpec = contentSpec.type;

                    if ( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) {
                        str.append('(');
                        if (contentSpec.value == null && contentSpec.otherValue == null) {
                            str.append("#PCDATA");
                        }
                        else if (contentSpec.otherValue != null) {
                            str.append("##any:uri=").append(contentSpec.otherValue);
                        }
                        else if (contentSpec.value == null) {
                            str.append("##any");
                        }
                        else {
                            appendContentSpec(contentSpec, str,
                                              true, parentContentSpecType );
                        }
                        str.append(')');
                    } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE  ||
                        nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE  ||
                        nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
                        str.append('(' );
                        appendContentSpec(contentSpec, str,
                                          true, parentContentSpecType );
                        str.append(')');
                    } else {
                        appendContentSpec(contentSpec, str,
                                          true, parentContentSpecType );
                    }
                    str.append('*');
                    break;
                }
                case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: {
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    nextContentSpec = contentSpec.type;

                    if ( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) {
                        str.append('(');
                        if (contentSpec.value == null && contentSpec.otherValue == null) {
                            str.append("#PCDATA");
                        }
                        else if (contentSpec.otherValue != null) {
                            str.append("##any:uri=").append(contentSpec.otherValue);
                        }
                        else if (contentSpec.value == null) {
                            str.append("##any");
                        }
                        else {
                            str.append(contentSpec.value);
                        }
                        str.append(')');
                    } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE  ||
                        nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE  ||
                        nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
                        str.append('(' );
                        appendContentSpec(contentSpec, str,
                                          true, parentContentSpecType );
                        str.append(')');
                    } else {
                        appendContentSpec(contentSpec, str,
                                          true, parentContentSpecType);
                    }
                    str.append('+');
                    break;
                }
                case XMLContentSpec.CONTENTSPECNODE_CHOICE:
                case XMLContentSpec.CONTENTSPECNODE_SEQ: {
                    appendContentSpec(contentSpec, str,
                                      true, parentContentSpecType );
                    break;
                }
                case XMLContentSpec.CONTENTSPECNODE_ANY: {
                    str.append("##any");
                    if (contentSpec.otherValue != null) {
                        str.append(":uri=");
                        str.append(contentSpec.otherValue);
                    }
                    break;
                }
                case XMLContentSpec.CONTENTSPECNODE_ANY_OTHER: {
                    str.append("##other:uri=");
                    str.append(contentSpec.otherValue);
                    break;
                }
                case XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL: {
                    str.append("##local");
                    break;
                }
                default: {
                    str.append("???");
                }

            } // switch type

            // return string
            return str.toString();
        }

        // not found
        return null;

    } // getContentSpecAsString(int):String

    // debugging

    public void printElements(  ) {
        int elementDeclIndex = 0;
        XMLElementDecl elementDecl = new XMLElementDecl();
        while (getElementDecl(elementDeclIndex++, elementDecl)) {

            System.out.println("element decl: "+elementDecl.name+
                               ", "+ elementDecl.name.rawname  );

            //                   ", "+ elementDecl.contentModelValidator.toString());
        }
    }

    public void printAttributes(int elementDeclIndex) {
        int attributeDeclIndex = getFirstAttributeDeclIndex(elementDeclIndex);
        System.out.print(elementDeclIndex);
        System.out.print(" [");
        while (attributeDeclIndex != -1) {
            System.out.print(' ');
            System.out.print(attributeDeclIndex);
            printAttribute(attributeDeclIndex);
            attributeDeclIndex = getNextAttributeDeclIndex(attributeDeclIndex);
            if (attributeDeclIndex != -1) {
                System.out.print(",");
            }
        }
        System.out.println(" ]");
    }

    //
    // Protected methods
    //

    /**
     * Adds the content spec to the given element declaration.
     */
    protected void addContentSpecToElement(XMLElementDecl elementDecl) {
        if ((fDepth == 0 || (fDepth == 1 && elementDecl.type == XMLElementDecl.TYPE_MIXED)) &&
                fNodeIndexStack != null) {
            if (elementDecl.type == XMLElementDecl.TYPE_MIXED) {
                int pcdata = addUniqueLeafNode(null);
                if (fNodeIndexStack[0] == -1) {
                    fNodeIndexStack[0] = pcdata;
                }
                else {
                    fNodeIndexStack[0] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_CHOICE,
                            pcdata, fNodeIndexStack[0]);
                }
            }
            setContentSpecIndex(fCurrentElementIndex, fNodeIndexStack[fDepth]);
        }
    }

    /**
     * getElementContentModelValidator
     *
     * @param elementDeclIndex
     *
     * @return its ContentModelValidator if any.
     */
    protected ContentModelValidator getElementContentModelValidator(int elementDeclIndex) {

        int chunk = elementDeclIndex >> CHUNK_SHIFT;
        int index = elementDeclIndex & CHUNK_MASK;

        ContentModelValidator contentModel    =  fElementDeclContentModelValidator[chunk][index];

        // If we have one, just return that. Otherwise, gotta create one
        if (contentModel != null) {
            return contentModel;
        }

        int contentType = fElementDeclType[chunk][index];
        if (contentType == XMLElementDecl.TYPE_SIMPLE) {
            return null;
        }

        // Get the type of content this element has
        int contentSpecIndex = fElementDeclContentSpecIndex[chunk][index];

        /***
        if ( contentSpecIndex == -1 )
            return null;
        /***/

        XMLContentSpec  contentSpec = new XMLContentSpec();
        getContentSpec( contentSpecIndex, contentSpec );

        // And create the content model according to the spec type
        if ( contentType == XMLElementDecl.TYPE_MIXED ) {
            //
            //  Just create a mixel content model object. This type of
            //  content model is optimized for mixed content validation.
            //
            ChildrenList children = new ChildrenList();
            contentSpecTree(contentSpecIndex, contentSpec, children);
            contentModel = new MixedContentModel(children.qname,
                                                 children.type,
                                                 0, children.length,
                                                 false);
        } else if (contentType == XMLElementDecl.TYPE_CHILDREN) {
            //  This method will create an optimal model for the complexity
            //  of the element's defined model. If its simple, it will create
            //  a SimpleContentModel object. If its a simple list, it will
            //  create a SimpleListContentModel object. If its complex, it
            //  will create a DFAContentModel object.
            //
            contentModel = createChildModel(contentSpecIndex);
        } else {
            throw new RuntimeException("Unknown content type for a element decl "
                                     + "in getElementContentModelValidator() in AbstractDTDGrammar class");
        }

        // Add the new model to the content model for this element
        fElementDeclContentModelValidator[chunk][index] = contentModel;

        return contentModel;

    } // getElementContentModelValidator(int):ContentModelValidator

   protected int createElementDecl() {
      int chunk = fElementDeclCount >> CHUNK_SHIFT;
      int index = fElementDeclCount & CHUNK_MASK;
      ensureElementDeclCapacity(chunk);
      fElementDeclName[chunk][index]                    = new QName();
      fElementDeclType[chunk][index]                    = -1;
      fElementDeclContentModelValidator[chunk][index]   = null;
      fElementDeclFirstAttributeDeclIndex[chunk][index] = -1;
      fElementDeclLastAttributeDeclIndex[chunk][index]  = -1;
      return fElementDeclCount++;
   }

   protected void setElementDecl(int elementDeclIndex, XMLElementDecl elementDecl) {
      if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
         return;
      }
      int     chunk       = elementDeclIndex >> CHUNK_SHIFT;
      int     index       = elementDeclIndex &  CHUNK_MASK;

      fElementDeclName[chunk][index].setValues(elementDecl.name);
      fElementDeclType[chunk][index]                  = elementDecl.type;

      fElementDeclContentModelValidator[chunk][index] = elementDecl.contentModelValidator;

      if (elementDecl.simpleType.list  == true ) {
         fElementDeclType[chunk][index] |= LIST_FLAG;
      }

      fElementIndexMap.put(elementDecl.name.rawname, elementDeclIndex);
   }




   protected void putElementNameMapping(QName name, int scope,
                                        int elementDeclIndex) {
   }

   protected void setFirstAttributeDeclIndex(int elementDeclIndex, int newFirstAttrIndex){

      if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
         return;
      }

      int chunk = elementDeclIndex >> CHUNK_SHIFT;
      int index = elementDeclIndex &  CHUNK_MASK;

      fElementDeclFirstAttributeDeclIndex[chunk][index] = newFirstAttrIndex;
   }

   protected void setContentSpecIndex(int elementDeclIndex, int contentSpecIndex){

      if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
         return;
      }

      int chunk = elementDeclIndex >> CHUNK_SHIFT;
      int index = elementDeclIndex &  CHUNK_MASK;

      fElementDeclContentSpecIndex[chunk][index] = contentSpecIndex;
   }


   protected int createAttributeDecl() {
      int chunk = fAttributeDeclCount >> CHUNK_SHIFT;
      int index = fAttributeDeclCount & CHUNK_MASK;

      ensureAttributeDeclCapacity(chunk);
      fAttributeDeclName[chunk][index]                    = new QName();
      fAttributeDeclType[chunk][index]                    = -1;
      fAttributeDeclDatatypeValidator[chunk][index]       = null;
      fAttributeDeclEnumeration[chunk][index]             = null;
      fAttributeDeclDefaultType[chunk][index]             = XMLSimpleType.DEFAULT_TYPE_IMPLIED;
      fAttributeDeclDefaultValue[chunk][index]            = null;
      fAttributeDeclNonNormalizedDefaultValue[chunk][index]            = null;
      fAttributeDeclNextAttributeDeclIndex[chunk][index]  = -1;
      return fAttributeDeclCount++;
   }


   protected void setAttributeDecl(int elementDeclIndex, int attributeDeclIndex,
                                   XMLAttributeDecl attributeDecl) {
      int attrChunk = attributeDeclIndex >> CHUNK_SHIFT;
      int attrIndex = attributeDeclIndex &  CHUNK_MASK;
      fAttributeDeclName[attrChunk][attrIndex].setValues(attributeDecl.name);
      fAttributeDeclType[attrChunk][attrIndex]  =  attributeDecl.simpleType.type;

      if (attributeDecl.simpleType.list) {
         fAttributeDeclType[attrChunk][attrIndex] |= LIST_FLAG;
      }
      fAttributeDeclEnumeration[attrChunk][attrIndex]  =  attributeDecl.simpleType.enumeration;
      fAttributeDeclDefaultType[attrChunk][attrIndex]  =  attributeDecl.simpleType.defaultType;
      fAttributeDeclDatatypeValidator[attrChunk][attrIndex] =  attributeDecl.simpleType.datatypeValidator;

      fAttributeDeclDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.defaultValue;
      fAttributeDeclNonNormalizedDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.nonNormalizedDefaultValue;

      int elemChunk     = elementDeclIndex >> CHUNK_SHIFT;
      int elemIndex     = elementDeclIndex &  CHUNK_MASK;
      int index         = fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex];
      while (index != -1) {
         if (index == attributeDeclIndex) {
            break;
         }
         attrChunk = index >> CHUNK_SHIFT;
         attrIndex = index & CHUNK_MASK;
         index = fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex];
      }
      if (index == -1) {
         if (fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] == -1) {
            fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex;
         } else {
            index = fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex];
            attrChunk = index >> CHUNK_SHIFT;
            attrIndex = index & CHUNK_MASK;
            fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex] = attributeDeclIndex;
         }
         fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex;
      }
   }

   protected int createContentSpec() {
      int chunk = fContentSpecCount >> CHUNK_SHIFT;
      int index = fContentSpecCount & CHUNK_MASK;

      ensureContentSpecCapacity(chunk);
      fContentSpecType[chunk][index]       = -1;
      fContentSpecValue[chunk][index]      = null;
      fContentSpecOtherValue[chunk][index] = null;

      return fContentSpecCount++;
   }

   protected void setContentSpec(int contentSpecIndex, XMLContentSpec contentSpec) {
      int   chunk = contentSpecIndex >> CHUNK_SHIFT;
      int   index = contentSpecIndex & CHUNK_MASK;

      fContentSpecType[chunk][index]       = contentSpec.type;
      fContentSpecValue[chunk][index]      = contentSpec.value;
      fContentSpecOtherValue[chunk][index] = contentSpec.otherValue;
   }


   protected int createEntityDecl() {
       int chunk = fEntityCount >> CHUNK_SHIFT;
       int index = fEntityCount & CHUNK_MASK;

      ensureEntityDeclCapacity(chunk);
      fEntityIsPE[chunk][index] = 0;
      fEntityInExternal[chunk][index] = 0;

      return fEntityCount++;
   }

   protected void setEntityDecl(int entityDeclIndex, XMLEntityDecl entityDecl) {
       int chunk = entityDeclIndex >> CHUNK_SHIFT;
       int index = entityDeclIndex & CHUNK_MASK;

       fEntityName[chunk][index] = entityDecl.name;
       fEntityValue[chunk][index] = entityDecl.value;
       fEntityPublicId[chunk][index] = entityDecl.publicId;
       fEntitySystemId[chunk][index] = entityDecl.systemId;
       fEntityBaseSystemId[chunk][index] = entityDecl.baseSystemId;
       fEntityNotation[chunk][index] = entityDecl.notation;
       fEntityIsPE[chunk][index] = entityDecl.isPE ? (byte)1 : (byte)0;
       fEntityInExternal[chunk][index] = entityDecl.inExternal ? (byte)1 : (byte)0;

       fEntityIndexMap.put(entityDecl.name, entityDeclIndex);
   }

   protected int createNotationDecl() {
       int chunk = fNotationCount >> CHUNK_SHIFT;
       ensureNotationDeclCapacity(chunk);
       return fNotationCount++;
   }

   protected void setNotationDecl(int notationDeclIndex, XMLNotationDecl notationDecl) {
       int chunk = notationDeclIndex >> CHUNK_SHIFT;
       int index = notationDeclIndex & CHUNK_MASK;

       fNotationName[chunk][index] = notationDecl.name;
       fNotationPublicId[chunk][index] = notationDecl.publicId;
       fNotationSystemId[chunk][index] = notationDecl.systemId;
       fNotationBaseSystemId[chunk][index] = notationDecl.baseSystemId;

       fNotationIndexMap.put(notationDecl.name, notationDeclIndex);
   }

    /**
     * Create an XMLContentSpec for a single non-leaf
     *
     * @param nodeType the type of XMLContentSpec to create - from XMLContentSpec.CONTENTSPECNODE_*
     * @param nodeValue handle to an XMLContentSpec
     * @return handle to the newly create XMLContentSpec
     */
    protected int addContentSpecNode(short nodeType, String nodeValue) {

        // create content spec node
        int contentSpecIndex = createContentSpec();

        // set content spec node values
        fContentSpec.setValues(nodeType, nodeValue, null);
        setContentSpec(contentSpecIndex, fContentSpec);

        // return index
        return contentSpecIndex;

    } // addContentSpecNode(short,String):int

    /**
     * create an XMLContentSpec for a leaf
     *
     * @param   elementName  the name (Element) for the node
     * @return handle to the newly create XMLContentSpec
     */
    protected int addUniqueLeafNode(String elementName) {

        // create content spec node
        int contentSpecIndex = createContentSpec();

        // set content spec node values
        fContentSpec.setValues( XMLContentSpec.CONTENTSPECNODE_LEAF,
                                elementName, null);
        setContentSpec(contentSpecIndex, fContentSpec);

        // return index
        return contentSpecIndex;

    } // addUniqueLeafNode(String):int

    /**
     * Create an XMLContentSpec for a two child leaf
     *
     * @param nodeType the type of XMLContentSpec to create - from XMLContentSpec.CONTENTSPECNODE_*
     * @param leftNodeIndex handle to an XMLContentSpec
     * @param rightNodeIndex handle to an XMLContentSpec
     * @return handle to the newly create XMLContentSpec
     */
    protected int addContentSpecNode(short nodeType,
                                     int leftNodeIndex, int rightNodeIndex) {

        // create content spec node
        int contentSpecIndex = createContentSpec();

        // set content spec node values
        int[] leftIntArray  = new int[1];
        int[] rightIntArray = new int[1];

        leftIntArray[0]      = leftNodeIndex;
        rightIntArray[0]    = rightNodeIndex;
        fContentSpec.setValues(nodeType, leftIntArray, rightIntArray);
        setContentSpec(contentSpecIndex, fContentSpec);

        // return index
        return contentSpecIndex;

    } // addContentSpecNode(short,int,int):int

    /** Initialize content model stack. */
    protected void initializeContentModelStack() {

        if (fOpStack == null) {
            fOpStack = new short[8];
            fNodeIndexStack = new int[8];
            fPrevNodeIndexStack = new int[8];
        } else if (fDepth == fOpStack.length) {
            short[] newStack = new short[fDepth * 2];
            System.arraycopy(fOpStack, 0, newStack, 0, fDepth);
            fOpStack = newStack;
            int[]   newIntStack = new int[fDepth * 2];
            System.arraycopy(fNodeIndexStack, 0, newIntStack, 0, fDepth);
            fNodeIndexStack = newIntStack;
            newIntStack = new int[fDepth * 2];
            System.arraycopy(fPrevNodeIndexStack, 0, newIntStack, 0, fDepth);
            fPrevNodeIndexStack = newIntStack;
        }
        fOpStack[fDepth] = -1;
        fNodeIndexStack[fDepth] = -1;
        fPrevNodeIndexStack[fDepth] = -1;

    } // initializeContentModelStack()

    boolean isImmutable() {
        return fIsImmutable;
    }

    //
    // Private methods
    //

    private void appendContentSpec(XMLContentSpec contentSpec,
                                   StringBuffer str, boolean parens,
                                   int parentContentSpecType ) {

        int thisContentSpec = contentSpec.type & 0x0f;
        switch (thisContentSpec) {
            case XMLContentSpec.CONTENTSPECNODE_LEAF: {
                if (contentSpec.value == null && contentSpec.otherValue == null) {
                    str.append("#PCDATA");
                }
                else if (contentSpec.value == null && contentSpec.otherValue != null) {
                    str.append("##any:uri=").append(contentSpec.otherValue);
                }
                else if (contentSpec.value == null) {
                    str.append("##any");
                }
                else {
                    str.append(contentSpec.value);
                }
                break;
            }
            case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: {
                if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE  ||
                    parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE ||
                    parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    str.append('(');
                    appendContentSpec(contentSpec, str, true, thisContentSpec );
                    str.append(')');
                }
                else {
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    appendContentSpec( contentSpec, str, true, thisContentSpec );
                }
                str.append('?');
                break;
            }
            case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: {
                if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE ||
                    parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE ||
                    parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    str.append('(');
                    appendContentSpec(contentSpec, str, true, thisContentSpec);
                    str.append(')' );
                }
                else {
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    appendContentSpec(contentSpec, str, true, thisContentSpec);
                }
                str.append('*');
                break;
            }
            case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: {
                if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE   ||
                    parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE  ||
                    parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {

                    str.append('(');
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    appendContentSpec(contentSpec, str, true, thisContentSpec);
                    str.append(')' );
                }
                else {
                    getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                    appendContentSpec(contentSpec, str, true, thisContentSpec);
                }
                str.append('+');
                break;
            }
            case XMLContentSpec.CONTENTSPECNODE_CHOICE:
            case XMLContentSpec.CONTENTSPECNODE_SEQ: {
                if (parens) {
                    str.append('(');
                }
                int type = contentSpec.type;
                int otherValue = ((int[])contentSpec.otherValue)[0];
                getContentSpec(((int[])contentSpec.value)[0], contentSpec);
                appendContentSpec(contentSpec, str, contentSpec.type != type, thisContentSpec);
                if (type == XMLContentSpec.CONTENTSPECNODE_CHOICE) {
                    str.append('|');
                }
                else {
                    str.append(',');
                }
                getContentSpec(otherValue, contentSpec);
                appendContentSpec(contentSpec, str, true, thisContentSpec);
                if (parens) {
                    str.append(')');
                }
                break;
            }
            case XMLContentSpec.CONTENTSPECNODE_ANY: {
                str.append("##any");
                if (contentSpec.otherValue != null) {
                    str.append(":uri=");
                    str.append(contentSpec.otherValue);
                }
                break;
            }
            case XMLContentSpec.CONTENTSPECNODE_ANY_OTHER: {
                str.append("##other:uri=");
                str.append(contentSpec.otherValue);
                break;
            }
            case XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL: {
                str.append("##local");
                break;
            }
            default: {
                str.append("???");
                break;
            }

        } // switch type

    } // appendContentSpec(XMLContentSpec.Provider,StringPool,XMLContentSpec,StringBuffer,boolean)

    // debugging

    private void printAttribute(int attributeDeclIndex) {

        XMLAttributeDecl attributeDecl = new XMLAttributeDecl();
        if (getAttributeDecl(attributeDeclIndex, attributeDecl)) {
            System.out.print(" { ");
            System.out.print(attributeDecl.name.localpart);
            System.out.print(" }");
        }

    } // printAttribute(int)

    // content models

    /**
     * When the element has a 'CHILDREN' model, this method is called to
     * create the content model object. It looks for some special case simple
     * models and creates SimpleContentModel objects for those. For the rest
     * it creates the standard DFA style model.
     */
    private synchronized ContentModelValidator createChildModel(int contentSpecIndex) {

        //
        //  Get the content spec node for the element we are working on.
        //  This will tell us what kind of node it is, which tells us what
        //  kind of model we will try to create.
        //
        XMLContentSpec contentSpec = new XMLContentSpec();
        getContentSpec(contentSpecIndex, contentSpec);

        if ((contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY ||
            (contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER ||
            (contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) {
            // let fall through to build a DFAContentModel
        }

        else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
            //
            //  Check that the left value is not -1, since any content model
            //  with PCDATA should be MIXED, so we should not have gotten here.
            //
            if (contentSpec.value == null && contentSpec.otherValue == null)
                throw new RuntimeException("ImplementationMessages.VAL_NPCD");

            //
            //  Its a single leaf, so its an 'a' type of content model, i.e.
            //  just one instance of one element. That one is definitely a
            //  simple content model.
            //

            fQName.setValues(null, (String)contentSpec.value,
                              (String)contentSpec.value, (String)contentSpec.otherValue);
            return new SimpleContentModel(contentSpec.type, fQName, null);
        } else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE)
                    ||  (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) {
            //
            //  Lets see if both of the children are leafs. If so, then it
            //  it has to be a simple content model
            //
            XMLContentSpec contentSpecLeft  = new XMLContentSpec();
            XMLContentSpec contentSpecRight = new XMLContentSpec();

            getContentSpec( ((int[])contentSpec.value)[0], contentSpecLeft);
            getContentSpec( ((int[])contentSpec.otherValue)[0], contentSpecRight);

            if ((contentSpecLeft.type == XMLContentSpec.CONTENTSPECNODE_LEAF)
                 &&  (contentSpecRight.type == XMLContentSpec.CONTENTSPECNODE_LEAF)) {
                //
                //  Its a simple choice or sequence, so we can do a simple
                //  content model for it.
                //
                fQName.setValues(null, (String)contentSpecLeft.value,
                                  (String)contentSpecLeft.value, (String)contentSpecLeft.otherValue);
                fQName2.setValues(null, (String)contentSpecRight.value,
                                  (String)contentSpecRight.value, (String)contentSpecRight.otherValue);
                return new SimpleContentModel(contentSpec.type, fQName, fQName2);
            }
        } else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE)
                    ||  (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE)
                    ||  (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE)) {
            //
            //  Its a repetition, so see if its one child is a leaf. If so
            //  its a repetition of a single element, so we can do a simple
            //  content model for that.
            //
            XMLContentSpec contentSpecLeft = new XMLContentSpec();
            getContentSpec(((int[])contentSpec.value)[0], contentSpecLeft);

            if (contentSpecLeft.type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
                //
                //  It is, so we can create a simple content model here that
                //  will check for this repetition. We pass -1 for the unused
                //  right node.
                //
                fQName.setValues(null, (String)contentSpecLeft.value,
                                  (String)contentSpecLeft.value, (String)contentSpecLeft.otherValue);
                return new SimpleContentModel(contentSpec.type, fQName, null);
            }
        } else {
            throw new RuntimeException("ImplementationMessages.VAL_CST");
        }

        //
        //  Its not a simple content model, so here we have to create a DFA
        //  for this element. So we create a DFAContentModel object. He
        //  encapsulates all of the work to create the DFA.
        //

        fLeafCount = 0;
        //int leafCount = countLeaves(contentSpecIndex);
        fLeafCount = 0;
        CMNode cmn    = buildSyntaxTree(contentSpecIndex, contentSpec);

        // REVISIT: has to be fLeafCount because we convert x+ to x,x*, one more leaf
        return new DFAContentModel(  cmn, fLeafCount, false);

    } // createChildModel(int):ContentModelValidator

    private final CMNode buildSyntaxTree(int startNode,
                                         XMLContentSpec contentSpec) {

        // We will build a node at this level for the new tree
        CMNode nodeRet = null;
        getContentSpec(startNode, contentSpec);
        if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY) {
            //nodeRet = new CMAny(contentSpec.type, -1, fLeafCount++);
            nodeRet = new CMAny(contentSpec.type, (String)contentSpec.otherValue, fLeafCount++);
        }
        else if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) {
            nodeRet = new CMAny(contentSpec.type, (String)contentSpec.otherValue, fLeafCount++);
        }
        else if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) {
            nodeRet = new CMAny(contentSpec.type, null, fLeafCount++);
        }
        //
        //  If this node is a leaf, then its an easy one. We just add it
        //  to the tree.
        //
        else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
            //
            //  Create a new leaf node, and pass it the current leaf count,
            //  which is its DFA state position. Bump the leaf count after
            //  storing it. This makes the positions zero based since we
            //  store first and then increment.
            //
            fQName.setValues(null, (String)contentSpec.value,
                              (String)contentSpec.value, (String)contentSpec.otherValue);
            nodeRet = new CMLeaf(fQName, fLeafCount++);
        }
        else {
            //
            //  Its not a leaf, so we have to recurse its left and maybe right
            //  nodes. Save both values before we recurse and trash the node.
            final int leftNode = ((int[])contentSpec.value)[0];
            final int rightNode = ((int[])contentSpec.otherValue)[0];

            if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE)
                ||  (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) {
                //
                //  Recurse on both children, and return a binary op node
                //  with the two created sub nodes as its children. The node
                //  type is the same type as the source.
                //

                nodeRet = new CMBinOp( contentSpec.type, buildSyntaxTree(leftNode, contentSpec)
                                       , buildSyntaxTree(rightNode, contentSpec));
            }
            else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE) {
                nodeRet = new CMUniOp( contentSpec.type, buildSyntaxTree(leftNode, contentSpec));
            }
            else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE
                  || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE
                  || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) {
                nodeRet = new CMUniOp(contentSpec.type, buildSyntaxTree(leftNode, contentSpec));
            }
            else {
                throw new RuntimeException("ImplementationMessages.VAL_CST");
            }
        }
        // And return our new node for this level
        return nodeRet;
    }

    /**
     * Build a vector of valid QNames from Content Spec
     * table.
     *
     * @param contentSpecIndex
     *               Content Spec index
     * @param vectorQName
     *               Array of QName
     * @exception RuntimeException
     */
    private void contentSpecTree(int contentSpecIndex,
                                 XMLContentSpec contentSpec,
                                 ChildrenList children) {

        // Handle any and leaf nodes
        getContentSpec( contentSpecIndex, contentSpec);
        if ( contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF ||
            (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY ||
            (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL ||
            (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) {

            // resize arrays, if needed
            if (children.length == children.qname.length) {
                QName[] newQName = new QName[children.length * 2];
                System.arraycopy(children.qname, 0, newQName, 0, children.length);
                children.qname = newQName;
                int[] newType = new int[children.length * 2];
                System.arraycopy(children.type, 0, newType, 0, children.length);
                children.type = newType;
            }

            // save values and return length
            children.qname[children.length] = new QName(null, (String)contentSpec.value,
                                                     (String) contentSpec.value,
                                                     (String) contentSpec.otherValue);
            children.type[children.length] = contentSpec.type;
            children.length++;
            return;
        }

        //
        //  Its not a leaf, so we have to recurse its left and maybe right
        //  nodes. Save both values before we recurse and trash the node.
        //
        final int leftNode = contentSpec.value != null
                           ? ((int[])(contentSpec.value))[0] : -1;
        int rightNode = -1 ;
        if (contentSpec.otherValue != null )
            rightNode = ((int[])(contentSpec.otherValue))[0];
        else
            return;

        if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE ||
            contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ) {
            contentSpecTree(leftNode, contentSpec, children);
            contentSpecTree(rightNode, contentSpec, children);
            return;
        }

        if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ||
            contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE ||
            contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) {
            contentSpecTree(leftNode, contentSpec, children);
            return;
        }

        // error
        throw new RuntimeException("Invalid content spec type seen in contentSpecTree() method of AbstractDTDGrammar class : "+contentSpec.type);

    } // contentSpecTree(int,XMLContentSpec,ChildrenList)

    // ensure capacity

    private void ensureElementDeclCapacity(int chunk) {
        if (chunk >= fElementDeclName.length) {
            fElementDeclIsExternal = resize(fElementDeclIsExternal,
                                     fElementDeclIsExternal.length * 2);

            fElementDeclName = resize(fElementDeclName, fElementDeclName.length * 2);
            fElementDeclType = resize(fElementDeclType, fElementDeclType.length * 2);
            fElementDeclContentModelValidator = resize(fElementDeclContentModelValidator, fElementDeclContentModelValidator.length * 2);
            fElementDeclContentSpecIndex = resize(fElementDeclContentSpecIndex,fElementDeclContentSpecIndex.length * 2);
            fElementDeclFirstAttributeDeclIndex = resize(fElementDeclFirstAttributeDeclIndex, fElementDeclFirstAttributeDeclIndex.length * 2);
            fElementDeclLastAttributeDeclIndex = resize(fElementDeclLastAttributeDeclIndex, fElementDeclLastAttributeDeclIndex.length * 2);
        }
        else if (fElementDeclName[chunk] != null) {
            return;
        }

        fElementDeclIsExternal[chunk] = new int[CHUNK_SIZE];
        fElementDeclName[chunk] = new QName[CHUNK_SIZE];
        fElementDeclType[chunk] = new short[CHUNK_SIZE];
        fElementDeclContentModelValidator[chunk] = new ContentModelValidator[CHUNK_SIZE];
        fElementDeclContentSpecIndex[chunk] = new int[CHUNK_SIZE];
        fElementDeclFirstAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
        fElementDeclLastAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
        return;
    }

    private void ensureAttributeDeclCapacity(int chunk) {

        if (chunk >= fAttributeDeclName.length) {
            fAttributeDeclIsExternal = resize(fAttributeDeclIsExternal,
                                       fAttributeDeclIsExternal.length * 2);
            fAttributeDeclName = resize(fAttributeDeclName, fAttributeDeclName.length * 2);
            fAttributeDeclType = resize(fAttributeDeclType, fAttributeDeclType.length * 2);
            fAttributeDeclEnumeration = resize(fAttributeDeclEnumeration, fAttributeDeclEnumeration.length * 2);
            fAttributeDeclDefaultType = resize(fAttributeDeclDefaultType, fAttributeDeclDefaultType.length * 2);
            fAttributeDeclDatatypeValidator = resize(fAttributeDeclDatatypeValidator, fAttributeDeclDatatypeValidator.length * 2);
            fAttributeDeclDefaultValue = resize(fAttributeDeclDefaultValue, fAttributeDeclDefaultValue.length * 2);
            fAttributeDeclNonNormalizedDefaultValue = resize(fAttributeDeclNonNormalizedDefaultValue, fAttributeDeclNonNormalizedDefaultValue.length * 2);
            fAttributeDeclNextAttributeDeclIndex = resize(fAttributeDeclNextAttributeDeclIndex, fAttributeDeclNextAttributeDeclIndex.length * 2);
        }
        else if (fAttributeDeclName[chunk] != null) {
            return;
        }

        fAttributeDeclIsExternal[chunk] = new int[CHUNK_SIZE];
        fAttributeDeclName[chunk] = new QName[CHUNK_SIZE];
        fAttributeDeclType[chunk] = new short[CHUNK_SIZE];
        fAttributeDeclEnumeration[chunk] = new String[CHUNK_SIZE][];
        fAttributeDeclDefaultType[chunk] = new short[CHUNK_SIZE];
        fAttributeDeclDatatypeValidator[chunk] = new DatatypeValidator[CHUNK_SIZE];
        fAttributeDeclDefaultValue[chunk] = new String[CHUNK_SIZE];
        fAttributeDeclNonNormalizedDefaultValue[chunk] = new String[CHUNK_SIZE];
        fAttributeDeclNextAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
        return;
    }

    private void ensureEntityDeclCapacity(int chunk) {
        if (chunk >= fEntityName.length) {
            fEntityName = resize(fEntityName, fEntityName.length * 2);
            fEntityValue = resize(fEntityValue, fEntityValue.length * 2);
            fEntityPublicId = resize(fEntityPublicId, fEntityPublicId.length * 2);
            fEntitySystemId = resize(fEntitySystemId, fEntitySystemId.length * 2);
            fEntityBaseSystemId = resize(fEntityBaseSystemId, fEntityBaseSystemId.length * 2);
            fEntityNotation = resize(fEntityNotation, fEntityNotation.length * 2);
            fEntityIsPE = resize(fEntityIsPE, fEntityIsPE.length * 2);
            fEntityInExternal = resize(fEntityInExternal, fEntityInExternal.length * 2);
        }
        else if (fEntityName[chunk] != null) {
            return;
        }

        fEntityName[chunk] = new String[CHUNK_SIZE];
        fEntityValue[chunk] = new String[CHUNK_SIZE];
        fEntityPublicId[chunk] = new String[CHUNK_SIZE];
        fEntitySystemId[chunk] = new String[CHUNK_SIZE];
        fEntityBaseSystemId[chunk] = new String[CHUNK_SIZE];
        fEntityNotation[chunk] = new String[CHUNK_SIZE];
        fEntityIsPE[chunk] = new byte[CHUNK_SIZE];
        fEntityInExternal[chunk] = new byte[CHUNK_SIZE];
        return;
    }

    private void ensureNotationDeclCapacity(int chunk) {
        if (chunk >= fNotationName.length) {
            fNotationName = resize(fNotationName, fNotationName.length * 2);
            fNotationPublicId = resize(fNotationPublicId, fNotationPublicId.length * 2);
            fNotationSystemId = resize(fNotationSystemId, fNotationSystemId.length * 2);
            fNotationBaseSystemId = resize(fNotationBaseSystemId, fNotationBaseSystemId.length * 2);
        }
        else if (fNotationName[chunk] != null) {
            return;
        }

        fNotationName[chunk] = new String[CHUNK_SIZE];
        fNotationPublicId[chunk] = new String[CHUNK_SIZE];
        fNotationSystemId[chunk] = new String[CHUNK_SIZE];
        fNotationBaseSystemId[chunk] = new String[CHUNK_SIZE];
        return;
    }

    private void ensureContentSpecCapacity(int chunk) {
        if (chunk >= fContentSpecType.length) {
            fContentSpecType = resize(fContentSpecType, fContentSpecType.length * 2);
            fContentSpecValue = resize(fContentSpecValue, fContentSpecValue.length * 2);
            fContentSpecOtherValue = resize(fContentSpecOtherValue, fContentSpecOtherValue.length * 2);
        }
        else if (fContentSpecType[chunk] != null) {
            return;
        }

        fContentSpecType[chunk] = new short[CHUNK_SIZE];
        fContentSpecValue[chunk] = new Object[CHUNK_SIZE];
        fContentSpecOtherValue[chunk] = new Object[CHUNK_SIZE];
        return;
    }

    //
    // Private static methods
    //

    // resize chunks

    private static byte[][] resize(byte array[][], int newsize) {
        byte newarray[][] = new byte[newsize][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    private static short[][] resize(short array[][], int newsize) {
        short newarray[][] = new short[newsize][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    private static int[][] resize(int array[][], int newsize) {
        int newarray[][] = new int[newsize][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    private static DatatypeValidator[][] resize(DatatypeValidator array[][], int newsize) {
        DatatypeValidator newarray[][] = new DatatypeValidator[newsize][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    private static ContentModelValidator[][] resize(ContentModelValidator array[][], int newsize) {
        ContentModelValidator newarray[][] = new ContentModelValidator[newsize][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    private static Object[][] resize(Object array[][], int newsize) {
        Object newarray[][] = new Object[newsize][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    private static QName[][] resize(QName array[][], int newsize) {
        QName newarray[][] = new QName[newsize][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    private static String[][] resize(String array[][], int newsize) {
        String newarray[][] = new String[newsize][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    private static String[][][] resize(String array[][][], int newsize) {
        String newarray[][][] = new String[newsize] [][];
        System.arraycopy(array, 0, newarray, 0, array.length);
        return newarray;
    }

    //
    // Classes
    //

    /**
     * Children list for <code>contentSpecTree method.
     *
     * @xerces.internal
     *
     * @author Eric Ye, IBM
     */
    private static class ChildrenList {

        //
        // Data
        //

        /** Length. */
        public int length = 0;

        // NOTE: The following set of data is mutually exclusive. It is
        //       written this way because Java doesn't have a native
        //       union data structure. -Ac

        /** Left and right children names. */
        public QName[] qname = new QName[2];

        /** Left and right children types. */
        public int[] type = new int[2];

        //
        // Constructors
        //

        public ChildrenList () {}

    } // class ChildrenList

    //
    // Classes
    //

    /**
     * A simple Hashtable implementation that takes a tuple (String, String)
     * as the key and a int as value.
     *
     * @xerces.internal
     *
     * @author Eric Ye, IBM
     * @author Andy Clark, IBM
     */
    protected static final class QNameHashtable {

        //
        // Constants
        //

        /** Initial bucket size (4). */
        private static final int INITIAL_BUCKET_SIZE = 4;

        // NOTE: Changed previous hashtable size from 512 to 101 so
        //       that we get a better distribution for hashing. -Ac
        /** Hashtable size (101). */
        private static final int HASHTABLE_SIZE = 101;

        //
        // Data
        //
        private Object[][] fHashTable = new Object[HASHTABLE_SIZE][];

        //
        // Public methods
        //
        /** Associates the given value with the specified key tuple. */
        public void put(String key, int value) {

            int hash = (key.hashCode() & 0x7FFFFFFF) % HASHTABLE_SIZE;
            Object[] bucket = fHashTable[hash];

            if (bucket == null) {
                bucket = new Object[1 + 2*INITIAL_BUCKET_SIZE];
                bucket[0] = new int[]{1};
                bucket[1] = key;
                bucket[2] = new int[]{value};
                fHashTable[hash] = bucket;
            } else {
                int count = ((int[])bucket[0])[0];
                int offset = 1 + 2*count;
                if (offset == bucket.length) {
                    int newSize = count + INITIAL_BUCKET_SIZE;
                    Object[] newBucket = new Object[1 + 2*newSize];
                    System.arraycopy(bucket, 0, newBucket, 0, offset);
                    bucket = newBucket;
                    fHashTable[hash] = bucket;
                }
                boolean found = false;
                int j=1;
                for (int i=0; i<count; i++){
                    if ((String)bucket[j] == key) {
                        ((int[])bucket[j+1])[0] = value;
                        found = true;
                        break;
                    }
                    j += 2;
                }
                if (! found) {
                    bucket[offset++] = key;
                    bucket[offset]= new int[]{value};
                    ((int[])bucket[0])[0] = ++count;
                }

            }
            //System.out.println("put("+key+" -> "+value+')');
            //System.out.println("get("+key+") -> "+get(key));

        } // put(int,String,String,int)

        /** Returns the value associated with the specified key tuple. */
        public int get(String key) {
            int hash = (key.hashCode() & 0x7FFFFFFF) % HASHTABLE_SIZE;
            Object[] bucket = fHashTable[hash];

            if (bucket == null) {
                return -1;
            }
            int count = ((int[])bucket[0])[0];

            int j=1;
            for (int i=0; i<count; i++){
                if ((String)bucket[j] == key) {
                    return ((int[])bucket[j+1])[0];
                }
                j += 2;
            }
            return -1;

        } // get(int,String,String)

    }  // class QNameHashtable

    //
    // EntityState methods
    //
    public boolean isEntityDeclared (String name){
        return (getEntityDeclIndex(name)!=-1)?true:false;
    }

    public boolean isEntityUnparsed (String name){
        int entityIndex = getEntityDeclIndex(name);
        if (entityIndex >-1) {
            int chunk = entityIndex >> CHUNK_SHIFT;
            int index = entityIndex & CHUNK_MASK;
            //for unparsed entity notation!=null
            return (fEntityNotation[chunk][index]!=null)?true:false;
        }
        return false;
    }
} // class DTDGrammar

Other Java examples (source code examples)

Here is a short list of links related to this Java DTDGrammar.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.