1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xerces.internal.impl.dtd;
  23 
  24 import com.sun.org.apache.xerces.internal.impl.dtd.models.CMAny;
  25 import com.sun.org.apache.xerces.internal.impl.dtd.models.CMBinOp;
  26 import com.sun.org.apache.xerces.internal.impl.dtd.models.CMLeaf;
  27 import com.sun.org.apache.xerces.internal.impl.dtd.models.CMNode;
  28 import com.sun.org.apache.xerces.internal.impl.dtd.models.CMUniOp;
  29 import com.sun.org.apache.xerces.internal.impl.dtd.models.ContentModelValidator;
  30 import com.sun.org.apache.xerces.internal.impl.dtd.models.DFAContentModel;
  31 import com.sun.org.apache.xerces.internal.impl.dtd.models.MixedContentModel;
  32 import com.sun.org.apache.xerces.internal.impl.dtd.models.SimpleContentModel;
  33 import com.sun.org.apache.xerces.internal.impl.dv.DatatypeValidator;
  34 import com.sun.org.apache.xerces.internal.impl.validation.EntityState;
  35 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  36 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  37 import com.sun.org.apache.xerces.internal.xni.QName;
  38 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
  39 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
  40 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  41 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  42 import com.sun.org.apache.xerces.internal.xni.XMLString;
  43 import com.sun.org.apache.xerces.internal.xni.XNIException;
  44 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
  45 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  46 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelSource;
  47 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource;
  48 import java.util.ArrayList;
  49 import java.util.HashMap;
  50 import java.util.List;
  51 import java.util.Map;
  52 import java.util.Random;
  53 
  54 /**
  55  * A DTD grammar. This class implements the XNI handler interfaces
  56  * for DTD information so that it can build the appropriate validation
  57  * structures automatically from the callbacks.
  58  *
  59  * @xerces.internal
  60  *
  61  * @author Eric Ye, IBM
  62  * @author Jeffrey Rodriguez, IBM
  63  * @author Andy Clark, IBM
  64  * @author Neil Graham, IBM
  65  *
  66  */
  67 public class DTDGrammar
  68     implements XMLDTDHandler, XMLDTDContentModelHandler, EntityState, Grammar {
  69 
  70     //
  71     // Constants
  72     //
  73 
  74     /** Top level scope (-1). */
  75     public static final int TOP_LEVEL_SCOPE = -1;
  76 
  77     // private
  78 
  79     /** Chunk shift (8). */
  80     private static final int CHUNK_SHIFT = 8; // 2^8 = 256
  81 
  82     /** Chunk size (1 << CHUNK_SHIFT). */
  83     private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
  84 
  85     /** Chunk mask (CHUNK_SIZE - 1). */
  86     private static final int CHUNK_MASK = CHUNK_SIZE - 1;
  87 
  88     /** Initial chunk count (1 << (10 - CHUNK_SHIFT)). */
  89     private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k
  90 
  91     /** List flag (0x80). */
  92     private static final short LIST_FLAG = 0x80;
  93 
  94     /** List mask (~LIST_FLAG). */
  95     private static final short LIST_MASK = ~LIST_FLAG;
  96 
  97     // debugging
  98 
  99     /** Debug DTDGrammar. */
 100     private static final boolean DEBUG = false;
 101 
 102     //
 103     // Data
 104     //
 105 
 106     protected XMLDTDSource fDTDSource = null;
 107     protected XMLDTDContentModelSource fDTDContentModelSource = null;
 108 
 109     /** Current element index. */
 110     protected int fCurrentElementIndex;
 111 
 112     /** Current attribute index. */
 113     protected int fCurrentAttributeIndex;
 114 
 115     /** fReadingExternalDTD */
 116     protected boolean fReadingExternalDTD = false;
 117 
 118     /** Symbol table. */
 119     private SymbolTable fSymbolTable;
 120 
 121     // The XMLDTDDescription with which this Grammar is associated
 122     protected XMLDTDDescription fGrammarDescription = null;
 123 
 124     // element declarations
 125 
 126     /** Number of element declarations. */
 127     private int fElementDeclCount = 0;
 128 
 129     /** Element declaration name. */
 130     private QName fElementDeclName[][] = new QName[INITIAL_CHUNK_COUNT][];
 131 
 132     /**
 133      * Element declaration type.
 134      * @see XMLElementDecl
 135      */
 136     private short fElementDeclType[][] = new short[INITIAL_CHUNK_COUNT][];
 137 
 138     /**
 139      * Element declaration content spec index. This index value is used
 140      * to refer to the content spec information tables.
 141      */
 142     private int fElementDeclContentSpecIndex[][] = new int[INITIAL_CHUNK_COUNT][];
 143 
 144     /**
 145      * Element declaration content model validator. This validator is
 146      * constructed from the content spec nodes.
 147      */
 148     private ContentModelValidator fElementDeclContentModelValidator[][] = new ContentModelValidator[INITIAL_CHUNK_COUNT][];
 149 
 150     /** First attribute declaration of an element declaration. */
 151     private int fElementDeclFirstAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
 152 
 153     /** Last attribute declaration of an element declaration. */
 154     private int fElementDeclLastAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
 155 
 156     // attribute declarations
 157 
 158     /** Number of attribute declarations. */
 159     private int fAttributeDeclCount = 0 ;
 160 
 161     /** Attribute declaration name. */
 162     private QName fAttributeDeclName[][] = new QName[INITIAL_CHUNK_COUNT][];
 163 
 164     // is this grammar immutable?  (fully constructed and not changeable)
 165     private boolean fIsImmutable = false;
 166 
 167     /**
 168      * Attribute declaration type.
 169      * @see XMLAttributeDecl
 170      */
 171     private short fAttributeDeclType[][] = new short[INITIAL_CHUNK_COUNT][];
 172 
 173     /** Attribute declaration enumeration values. */
 174     private String[] fAttributeDeclEnumeration[][] = new String[INITIAL_CHUNK_COUNT][][];
 175     private short fAttributeDeclDefaultType[][] = new short[INITIAL_CHUNK_COUNT][];
 176     private DatatypeValidator fAttributeDeclDatatypeValidator[][] = new DatatypeValidator[INITIAL_CHUNK_COUNT][];
 177     private String fAttributeDeclDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][];
 178     private String fAttributeDeclNonNormalizedDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][];
 179     private int fAttributeDeclNextAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
 180 
 181     // content specs
 182 
 183     // here saves the content spec binary trees for element decls,
 184     // each element with a content model will hold a pointer which is
 185     // the index of the head node of the content spec tree.
 186 
 187     private int fContentSpecCount = 0;
 188     private short fContentSpecType[][] = new short[INITIAL_CHUNK_COUNT][];
 189     private Object fContentSpecValue[][] = new Object[INITIAL_CHUNK_COUNT][];
 190     private Object fContentSpecOtherValue[][] = new Object[INITIAL_CHUNK_COUNT][];
 191 
 192     // entities
 193 
 194     private int fEntityCount = 0;
 195     private String fEntityName[][] = new String[INITIAL_CHUNK_COUNT][];
 196     private String[][] fEntityValue = new String[INITIAL_CHUNK_COUNT][];
 197     private String[][] fEntityPublicId = new String[INITIAL_CHUNK_COUNT][];
 198     private String[][] fEntitySystemId = new String[INITIAL_CHUNK_COUNT][];
 199     private String[][] fEntityBaseSystemId = new String[INITIAL_CHUNK_COUNT][];
 200     private String[][] fEntityNotation = new String[INITIAL_CHUNK_COUNT][];
 201     private byte[][] fEntityIsPE = new byte[INITIAL_CHUNK_COUNT][];
 202     private byte[][] fEntityInExternal = new byte[INITIAL_CHUNK_COUNT][];
 203 
 204     // notations
 205 
 206     private int fNotationCount = 0;
 207     private String fNotationName[][] = new String[INITIAL_CHUNK_COUNT][];
 208     private String[][] fNotationPublicId = new String[INITIAL_CHUNK_COUNT][];
 209     private String[][] fNotationSystemId = new String[INITIAL_CHUNK_COUNT][];
 210     private String[][] fNotationBaseSystemId = new String[INITIAL_CHUNK_COUNT][];
 211 
 212     // other information
 213 
 214     /** Element index mapping table. */
 215     private final Map<String, Integer> fElementIndexMap = new HashMap<>();
 216 
 217     /** Entity index mapping table. */
 218     private final Map<String, Integer> fEntityIndexMap = new HashMap<>();
 219 
 220     /** Notation index mapping table. */
 221     private final Map<String, Integer> fNotationIndexMap = new HashMap<>();
 222 
 223     // temp variables
 224 
 225     /** Mixed. */
 226     private boolean fMixed;
 227 
 228     /** Temporary qualified name. */
 229     private final QName fQName = new QName();
 230 
 231     /** Temporary qualified name. */
 232     private final QName fQName2 = new QName();
 233 
 234     /** Temporary Attribute decl. */
 235     protected final XMLAttributeDecl fAttributeDecl = new XMLAttributeDecl();
 236 
 237     // for buildSyntaxTree method
 238 
 239     private int fLeafCount = 0;
 240     private int fEpsilonIndex = -1;
 241 
 242     /** Element declaration. */
 243     private XMLElementDecl fElementDecl = new XMLElementDecl();
 244 
 245     /** Entity declaration. */
 246     private XMLEntityDecl fEntityDecl = new XMLEntityDecl();
 247 
 248     /** Simple type. */
 249     private XMLSimpleType fSimpleType = new XMLSimpleType();
 250 
 251     /** Content spec node. */
 252     private XMLContentSpec fContentSpec = new XMLContentSpec();
 253 
 254     /** table of XMLElementDecl   */
 255     Map<String, XMLElementDecl> fElementDeclTab = new HashMap<>();
 256 
 257     /** Children content model operation stack. */
 258     private short[] fOpStack = null;
 259 
 260     /** Children content model index stack. */
 261     private int[] fNodeIndexStack = null;
 262 
 263     /** Children content model previous node index stack. */
 264     private int[] fPrevNodeIndexStack = null;
 265 
 266     /** Stack depth   */
 267     private int fDepth = 0;
 268 
 269     /** Entity stack. */
 270     private boolean[] fPEntityStack = new boolean[4];
 271     private int fPEDepth = 0;
 272 
 273     // additional fields(columns) for the element Decl pool in the Grammar
 274 
 275     /** flag if the elementDecl is External. */
 276     private int fElementDeclIsExternal[][] = new int[INITIAL_CHUNK_COUNT][];
 277 
 278 
 279     // additional fields(columns) for the attribute Decl pool in the Grammar
 280 
 281     /** flag if the AttributeDecl is External. */
 282     private int fAttributeDeclIsExternal[][] = new int[INITIAL_CHUNK_COUNT][];
 283 
 284     // for mixedElement method
 285 
 286     int valueIndex            = -1;
 287     int prevNodeIndex         = -1;
 288     int nodeIndex             = -1;
 289 
 290     //
 291     // Constructors
 292     //
 293 
 294     /** Default constructor. */
 295     public DTDGrammar(SymbolTable symbolTable, XMLDTDDescription desc) {
 296         fSymbolTable = symbolTable;
 297         fGrammarDescription = desc;
 298     } // <init>(SymbolTable)
 299 
 300     // Grammar methods
 301 
 302     // return the XMLDTDDescription object with which this is associated
 303     public XMLGrammarDescription getGrammarDescription() {
 304         return fGrammarDescription;
 305     } // getGrammarDescription():  XMLGrammarDescription
 306 
 307     //
 308     // Public methods
 309     //
 310 
 311     /**
 312      * Returns true if the specified element declaration is external.
 313      *
 314      * @param elementDeclIndex The element declaration index.
 315      */
 316     public boolean getElementDeclIsExternal(int elementDeclIndex) {
 317 
 318         if (elementDeclIndex < 0) {
 319             return false;
 320         }
 321 
 322         int chunk = elementDeclIndex >> CHUNK_SHIFT;
 323         int index = elementDeclIndex & CHUNK_MASK;
 324         return (fElementDeclIsExternal[chunk][index] != 0);
 325 
 326     } // getElementDeclIsExternal(int):boolean
 327 
 328     /**
 329      * Returns true if the specified attribute declaration is external.
 330      *
 331      * @param attributeDeclIndex Attribute declaration index.
 332      */
 333     public boolean getAttributeDeclIsExternal(int attributeDeclIndex) {
 334 
 335         if (attributeDeclIndex < 0) {
 336             return false;
 337         }
 338 
 339         int chunk = attributeDeclIndex >> CHUNK_SHIFT;
 340         int index = attributeDeclIndex & CHUNK_MASK;
 341         return (fAttributeDeclIsExternal[chunk][index] != 0);
 342     }
 343 
 344     public int getAttributeDeclIndex(int elementDeclIndex, String attributeDeclName) {
 345         if (elementDeclIndex == -1) {
 346             return -1;
 347         }
 348         int attDefIndex = getFirstAttributeDeclIndex(elementDeclIndex);
 349         while (attDefIndex != -1) {
 350             getAttributeDecl(attDefIndex, fAttributeDecl);
 351 
 352             if (fAttributeDecl.name.rawname == attributeDeclName
 353                 || attributeDeclName.equals(fAttributeDecl.name.rawname) ) {
 354                 return attDefIndex;
 355             }
 356             attDefIndex = getNextAttributeDeclIndex(attDefIndex);
 357         }
 358         return -1;
 359     } // getAttributeDeclIndex (int,QName)
 360 
 361     //
 362     // XMLDTDHandler methods
 363     //
 364 
 365     /**
 366      * The start of the DTD.
 367      *
 368      * @param locator  The document locator, or null if the document
 369      *                 location cannot be reported during the parsing of
 370      *                 the document DTD. However, it is <em>strongly</em>
 371      *                 recommended that a locator be supplied that can
 372      *                 at least report the base system identifier of the
 373      *                 DTD.
 374      *
 375      * @param augs Additional information that may include infoset
 376      *                      augmentations.
 377      * @throws XNIException Thrown by handler to signal an error.
 378      */
 379     public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException {
 380         //Initialize stack
 381         fOpStack = null;
 382         fNodeIndexStack = null;
 383         fPrevNodeIndexStack = null;
 384     } // startDTD(XMLLocator)
 385 
 386     /**
 387      * This method notifies of the start of an entity. The DTD has the
 388      * pseudo-name of "[dtd]" and parameter entity names start with '%'.
 389      * <p>
 390      * <strong>Note:</strong> Since the DTD is an entity, the handler
 391      * will be notified of the start of the DTD entity by calling the
 392      * startParameterEntity method with the entity name "[dtd]" <em>before</em> calling
 393      * the startDTD method.
 394      *
 395      * @param name     The name of the parameter entity.
 396      * @param identifier The resource identifier.
 397      * @param encoding The auto-detected IANA encoding name of the entity
 398      *                 stream. This value will be null in those situations
 399      *                 where the entity encoding is not auto-detected (e.g.
 400      *                 internal parameter entities).
 401      * @param augs Additional information that may include infoset
 402      *                      augmentations.
 403      *
 404      * @throws XNIException Thrown by handler to signal an error.
 405      */
 406     public void startParameterEntity(String name,
 407                                      XMLResourceIdentifier identifier,
 408                                      String encoding,
 409                                      Augmentations augs) throws XNIException {
 410 
 411         // keep track of this entity before fEntityDepth is increased
 412         if (fPEDepth == fPEntityStack.length) {
 413             boolean[] entityarray = new boolean[fPEntityStack.length * 2];
 414             System.arraycopy(fPEntityStack, 0, entityarray, 0, fPEntityStack.length);
 415             fPEntityStack = entityarray;
 416         }
 417         fPEntityStack[fPEDepth] = fReadingExternalDTD;
 418         fPEDepth++;
 419 
 420     } // startParameterEntity(String,XMLResourceIdentifier,String,Augmentations)
 421 
 422     /**
 423      * The start of the DTD external subset.
 424      *
 425      * @param augs Additional information that may include infoset
 426      *                      augmentations.
 427      *
 428      * @throws XNIException Thrown by handler to signal an error.
 429      */
 430     public void startExternalSubset(XMLResourceIdentifier identifier,
 431                                     Augmentations augs) throws XNIException {
 432         fReadingExternalDTD = true;
 433     } // startExternalSubset(Augmentations)
 434 
 435     /**
 436      * This method notifies the end of an entity. The DTD has the pseudo-name
 437      * of "[dtd]" and parameter entity names start with '%'.
 438      * <p>
 439      * <strong>Note:</strong> Since the DTD is an entity, the handler
 440      * will be notified of the end of the DTD entity by calling the
 441      * endEntity method with the entity name "[dtd]" <em>after</em> calling
 442      * the endDTD method.
 443      *
 444      * @param name The name of the entity.
 445      * @param augs Additional information that may include infoset
 446      *                      augmentations.
 447      * @throws XNIException Thrown by handler to signal an error.
 448      */
 449     public void endParameterEntity(String name, Augmentations augs) throws XNIException {
 450 
 451         fPEDepth--;
 452         fReadingExternalDTD = fPEntityStack[fPEDepth];
 453 
 454     } // endParameterEntity(String,Augmentations)
 455 
 456     /**
 457      * The end of the DTD external subset.
 458      *
 459      * @param augs Additional information that may include infoset
 460      *                      augmentations.
 461      *
 462      * @throws XNIException Thrown by handler to signal an error.
 463      */
 464     public void endExternalSubset(Augmentations augs) throws XNIException {
 465         fReadingExternalDTD = false;
 466     } // endExternalSubset(Augmentations)
 467 
 468     /**
 469      * An element declaration.
 470      *
 471      * @param name         The name of the element.
 472      * @param contentModel The element content model.
 473      * @param augs Additional information that may include infoset
 474      *                      augmentations.
 475      * @throws XNIException Thrown by handler to signal an error.
 476      */
 477     public void elementDecl(String name, String contentModel, Augmentations augs)
 478         throws XNIException {
 479 
 480         XMLElementDecl tmpElementDecl = fElementDeclTab.get(name) ;
 481 
 482         // check if it is already defined
 483         if ( tmpElementDecl != null ) {
 484             if (tmpElementDecl.type == -1) {
 485                 fCurrentElementIndex = getElementDeclIndex(name);
 486             }
 487             else {
 488                 // duplicate element, ignored.
 489                 return;
 490             }
 491         }
 492         else {
 493             fCurrentElementIndex = createElementDecl();//create element decl
 494         }
 495 
 496         XMLElementDecl elementDecl       = new XMLElementDecl();
 497 
 498         fQName.setValues(null, name, name, null);
 499 
 500         elementDecl.name.setValues(fQName);
 501 
 502         elementDecl.contentModelValidator = null;
 503         elementDecl.scope= -1;
 504         if (contentModel.equals("EMPTY")) {
 505             elementDecl.type = XMLElementDecl.TYPE_EMPTY;
 506         }
 507         else if (contentModel.equals("ANY")) {
 508             elementDecl.type = XMLElementDecl.TYPE_ANY;
 509         }
 510         else if (contentModel.startsWith("(") ) {
 511             if (contentModel.indexOf("#PCDATA") > 0 ) {
 512                 elementDecl.type = XMLElementDecl.TYPE_MIXED;
 513             }
 514             else {
 515                 elementDecl.type = XMLElementDecl.TYPE_CHILDREN;
 516             }
 517         }
 518 
 519 
 520         //add(or set) this elementDecl to the local cache
 521         this.fElementDeclTab.put(name, elementDecl );
 522 
 523         fElementDecl = elementDecl;
 524         addContentSpecToElement(elementDecl);
 525 
 526         if ( DEBUG ) {
 527             System.out.println(  "name = " + fElementDecl.name.localpart );
 528             System.out.println(  "Type = " + fElementDecl.type );
 529         }
 530 
 531         setElementDecl(fCurrentElementIndex, fElementDecl );//set internal structure
 532 
 533         int chunk = fCurrentElementIndex >> CHUNK_SHIFT;
 534         int index = fCurrentElementIndex & CHUNK_MASK;
 535         ensureElementDeclCapacity(chunk);
 536         fElementDeclIsExternal[chunk][index] = (fReadingExternalDTD || fPEDepth > 0) ? 1 : 0;
 537 
 538     } // elementDecl(String,String)
 539 
 540     /**
 541      * An attribute declaration.
 542      *
 543      * @param elementName   The name of the element that this attribute
 544      *                      is associated with.
 545      * @param attributeName The name of the attribute.
 546      * @param type          The attribute type. This value will be one of
 547      *                      the following: "CDATA", "ENTITY", "ENTITIES",
 548      *                      "ENUMERATION", "ID", "IDREF", "IDREFS",
 549      *                      "NMTOKEN", "NMTOKENS", or "NOTATION".
 550      * @param enumeration   If the type has the value "ENUMERATION", this
 551      *                      array holds the allowed attribute values;
 552      *                      otherwise, this array is null.
 553      * @param defaultType   The attribute default type. This value will be
 554      *                      one of the following: "#FIXED", "#IMPLIED",
 555      *                      "#REQUIRED", or null.
 556      * @param defaultValue  The attribute default value, or null if no
 557      *                      default value is specified.
 558      * @param nonNormalizedDefaultValue  The attribute default value with no normalization
 559      *                      performed, or null if no default value is specified.
 560      *
 561      * @param augs Additional information that may include infoset
 562      *                      augmentations.
 563      * @throws XNIException Thrown by handler to signal an error.
 564      */
 565     public void attributeDecl(String elementName, String attributeName,
 566                               String type, String[] enumeration,
 567                               String defaultType, XMLString defaultValue,
 568                               XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {
 569 
 570         if ( this.fElementDeclTab.containsKey(elementName) ) {
 571             //if ElementDecl has already being created in the Grammar then remove from table,
 572             //this.fElementDeclTab.remove( (String) elementName );
 573         }
 574         // then it is forward reference to a element decl, create the elementDecl first.
 575         else {
 576             fCurrentElementIndex = createElementDecl();//create element decl
 577 
 578             XMLElementDecl elementDecl       = new XMLElementDecl();
 579             elementDecl.name.setValues(null, elementName, elementName, null);
 580 
 581             elementDecl.scope= -1;
 582 
 583             //add(or set) this elementDecl to the local cache
 584             this.fElementDeclTab.put(elementName, elementDecl );
 585 
 586             //set internal structure
 587             setElementDecl(fCurrentElementIndex, elementDecl );
 588         }
 589 
 590         //Get Grammar index to grammar array
 591         int elementIndex       = getElementDeclIndex(elementName);
 592 
 593         //return, when more than one definition is provided for the same attribute of given element type
 594         //only the first declaration is binding and later declarations are ignored
 595         if (getAttributeDeclIndex(elementIndex, attributeName) != -1) {
 596             return;
 597         }
 598 
 599         fCurrentAttributeIndex = createAttributeDecl();// Create current Attribute Decl
 600 
 601         fSimpleType.clear();
 602         if ( defaultType != null ) {
 603             if ( defaultType.equals( "#FIXED") ) {
 604                 fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_FIXED;
 605             } else if ( defaultType.equals( "#IMPLIED") ) {
 606                 fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_IMPLIED;
 607             } else if ( defaultType.equals( "#REQUIRED") ) {
 608                 fSimpleType.defaultType = XMLSimpleType.DEFAULT_TYPE_REQUIRED;
 609             }
 610         }
 611         if ( DEBUG ) {
 612             System.out.println("defaultvalue = " + defaultValue.toString() );
 613         }
 614         fSimpleType.defaultValue      = defaultValue!=null ?  defaultValue.toString() : null;
 615         fSimpleType.nonNormalizedDefaultValue      = nonNormalizedDefaultValue!=null ?  nonNormalizedDefaultValue.toString() : null;
 616         fSimpleType.enumeration       = enumeration;
 617 
 618         if (type.equals("CDATA")) {
 619             fSimpleType.type = XMLSimpleType.TYPE_CDATA;
 620         }
 621         else if ( type.equals("ID") ) {
 622             fSimpleType.type = XMLSimpleType.TYPE_ID;
 623         }
 624         else if ( type.startsWith("IDREF") ) {
 625             fSimpleType.type = XMLSimpleType.TYPE_IDREF;
 626             if (type.indexOf("S") > 0) {
 627                 fSimpleType.list = true;
 628             }
 629         }
 630         else if (type.equals("ENTITIES")) {
 631             fSimpleType.type = XMLSimpleType.TYPE_ENTITY;
 632             fSimpleType.list = true;
 633         }
 634         else if (type.equals("ENTITY")) {
 635             fSimpleType.type = XMLSimpleType.TYPE_ENTITY;
 636         }
 637         else if (type.equals("NMTOKENS")) {
 638             fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN;
 639             fSimpleType.list = true;
 640         }
 641         else if (type.equals("NMTOKEN")) {
 642             fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN;
 643         }
 644         else if (type.startsWith("NOTATION") ) {
 645             fSimpleType.type = XMLSimpleType.TYPE_NOTATION;
 646         }
 647         else if (type.startsWith("ENUMERATION") ) {
 648             fSimpleType.type = XMLSimpleType.TYPE_ENUMERATION;
 649         }
 650         else {
 651             // REVISIT: Report error message. -Ac
 652             System.err.println("!!! unknown attribute type "+type);
 653         }
 654         // REVISIT: The datatype should be stored with the attribute value
 655         //          and not special-cased in the XMLValidator. -Ac
 656         //fSimpleType.datatypeValidator = fDatatypeValidatorFactory.createDatatypeValidator(type, null, facets, fSimpleType.list);
 657 
 658         fQName.setValues(null, attributeName, attributeName, null);
 659         fAttributeDecl.setValues( fQName, fSimpleType, false );
 660 
 661         setAttributeDecl(elementIndex, fCurrentAttributeIndex, fAttributeDecl);
 662 
 663         int chunk = fCurrentAttributeIndex >> CHUNK_SHIFT;
 664         int index = fCurrentAttributeIndex & CHUNK_MASK;
 665         ensureAttributeDeclCapacity(chunk);
 666         fAttributeDeclIsExternal[chunk][index] = (fReadingExternalDTD || fPEDepth > 0) ?  1 : 0;
 667 
 668     } // attributeDecl(String,String,String,String[],String,XMLString,XMLString, Augmentations)
 669 
 670     /**
 671      * An internal entity declaration.
 672      *
 673      * @param name The name of the entity. Parameter entity names start with
 674      *             '%', whereas the name of a general entity is just the
 675      *             entity name.
 676      * @param text The value of the entity.
 677      * @param nonNormalizedText The non-normalized value of the entity. This
 678      *             value contains the same sequence of characters that was in
 679      *             the internal entity declaration, without any entity
 680      *             references expanded.
 681      * @param augs Additional information that may include infoset
 682      *                      augmentations.
 683      * @throws XNIException Thrown by handler to signal an error.
 684      */
 685     public void internalEntityDecl(String name, XMLString text,
 686                                    XMLString nonNormalizedText,
 687                                    Augmentations augs) throws XNIException {
 688 
 689         int entityIndex = getEntityDeclIndex(name);
 690         if( entityIndex == -1){
 691             entityIndex = createEntityDecl();
 692             boolean isPE = name.startsWith("%");
 693             boolean inExternal = (fReadingExternalDTD || fPEDepth > 0);
 694             XMLEntityDecl  entityDecl = new XMLEntityDecl();
 695             entityDecl.setValues(name,null,null, null, null,
 696                                  text.toString(), isPE, inExternal);
 697 
 698             setEntityDecl(entityIndex, entityDecl);
 699         }
 700 
 701     } // internalEntityDecl(String,XMLString,XMLString)
 702 
 703     /**
 704      * An external entity declaration.
 705      *
 706      * @param name     The name of the entity. Parameter entity names start
 707      *                 with '%', whereas the name of a general entity is just
 708      *                 the entity name.
 709      * @param identifier    An object containing all location information
 710      *                      pertinent to this external entity declaration.
 711      * @param augs Additional information that may include infoset
 712      *                      augmentations.
 713      * @throws XNIException Thrown by handler to signal an error.
 714      */
 715     public void externalEntityDecl(String name,
 716                                    XMLResourceIdentifier identifier,
 717                                    Augmentations augs) throws XNIException {
 718 
 719         int entityIndex = getEntityDeclIndex(name);
 720         if( entityIndex == -1){
 721             entityIndex = createEntityDecl();
 722             boolean isPE = name.startsWith("%");
 723             boolean inExternal = (fReadingExternalDTD || fPEDepth > 0);
 724 
 725             XMLEntityDecl  entityDecl = new XMLEntityDecl();
 726             entityDecl.setValues(name, identifier.getPublicId(), identifier.getLiteralSystemId(),
 727                                 identifier.getBaseSystemId(),
 728                                 null, null, isPE, inExternal);
 729 
 730             setEntityDecl(entityIndex, entityDecl);
 731         }
 732     } // externalEntityDecl(String, XMLResourceIdentifier, Augmentations)
 733 
 734     /**
 735      * An unparsed entity declaration.
 736      *
 737      * @param name     The name of the entity.
 738      * @param identifier    An object containing all location information
 739      *                      pertinent to this entity.
 740      * @param notation The name of the notation.
 741      * @param augs Additional information that may include infoset
 742      *                      augmentations.
 743      * @throws XNIException Thrown by handler to signal an error.
 744      */
 745     public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier,
 746                                    String notation,
 747                                    Augmentations augs) throws XNIException {
 748 
 749         XMLEntityDecl  entityDecl = new XMLEntityDecl();
 750         boolean isPE = name.startsWith("%");
 751         boolean inExternal = (fReadingExternalDTD || fPEDepth > 0);
 752 
 753         entityDecl.setValues(name,identifier.getPublicId(),identifier.getLiteralSystemId(),
 754                             identifier.getBaseSystemId(), notation,
 755                             null, isPE, inExternal);
 756         int entityIndex = getEntityDeclIndex(name);
 757         if (entityIndex == -1) {
 758             entityIndex = createEntityDecl();
 759             setEntityDecl(entityIndex, entityDecl);
 760         }
 761 
 762     } // unparsedEntityDecl(String,StringXMLResourceIdentifier,Augmentations)
 763 
 764     /**
 765      * A notation declaration
 766      *
 767      * @param name     The name of the notation.
 768      * @param identifier    An object containing all location information
 769      *                      pertinent to this notation.
 770      * @param augs Additional information that may include infoset
 771      *                      augmentations.
 772      * @throws XNIException Thrown by handler to signal an error.
 773      */
 774     public void notationDecl(String name, XMLResourceIdentifier identifier,
 775                              Augmentations augs) throws XNIException {
 776 
 777         XMLNotationDecl  notationDecl = new XMLNotationDecl();
 778         notationDecl.setValues(name,identifier.getPublicId(),identifier.getLiteralSystemId(),
 779                 identifier.getBaseSystemId());
 780         int notationIndex = getNotationDeclIndex(name);
 781         if (notationIndex == -1) {
 782             notationIndex = createNotationDecl();
 783             setNotationDecl(notationIndex, notationDecl);
 784         }
 785 
 786     } // notationDecl(String,XMLResourceIdentifier,Augmentations)
 787 
 788     /**
 789      * The end of the DTD.
 790      *
 791      * @param augs Additional information that may include infoset
 792      *                      augmentations.
 793      * @throws XNIException Thrown by handler to signal an error.
 794      */
 795     public void endDTD(Augmentations augs) throws XNIException {
 796         fIsImmutable = true;
 797         // make sure our description contains useful stuff...
 798         if (fGrammarDescription.getRootName() == null) {
 799             // we don't know what the root is; so use possibleRoots...
 800             int chunk, index = 0;
 801             String currName = null;
 802             final int size = fElementDeclCount;
 803             List<String> elements = new ArrayList<>(size);
 804             for (int i = 0; i < size; ++i) {
 805                 chunk = i >> CHUNK_SHIFT;
 806                 index = i & CHUNK_MASK;
 807                 currName = fElementDeclName[chunk][index].rawname;
 808                 elements.add(currName);
 809             }
 810             fGrammarDescription.setPossibleRoots(elements);
 811         }
 812     } // endDTD()
 813 
 814     // sets the source of this handler
 815     public void setDTDSource(XMLDTDSource source) {
 816         fDTDSource = source;
 817     } // setDTDSource(XMLDTDSource)
 818 
 819     // returns the source of this handler
 820     public XMLDTDSource getDTDSource() {
 821         return fDTDSource;
 822     } // getDTDSource():  XMLDTDSource
 823 
 824     // no-op methods
 825 
 826     /**
 827      * Notifies of the presence of a TextDecl line in an entity. If present,
 828      * this method will be called immediately following the startEntity call.
 829      * <p>
 830      * <strong>Note:</strong> This method is only called for external
 831      * parameter entities referenced in the DTD.
 832      *
 833      * @param version  The XML version, or null if not specified.
 834      * @param encoding The IANA encoding name of the entity.
 835      *
 836      * @param augs Additional information that may include infoset
 837      *                      augmentations.
 838      * @throws XNIException Thrown by handler to signal an error.
 839      */
 840     public void textDecl(String version, String encoding, Augmentations augs)
 841         throws XNIException {}
 842 
 843     /**
 844      * A comment.
 845      *
 846      * @param text The text in the comment.
 847      * @param augs Additional information that may include infoset
 848      *                      augmentations.
 849      * @throws XNIException Thrown by application to signal an error.
 850      */
 851     public void comment(XMLString text, Augmentations augs) throws XNIException {}
 852 
 853     /**
 854      * A processing instruction. Processing instructions consist of a
 855      * target name and, optionally, text data. The data is only meaningful
 856      * to the application.
 857      * <p>
 858      * Typically, a processing instruction's data will contain a series
 859      * of pseudo-attributes. These pseudo-attributes follow the form of
 860      * element attributes but are <strong>not</strong> parsed or presented
 861      * to the application as anything other than text. The application is
 862      * responsible for parsing the data.
 863      *
 864      * @param target The target.
 865      * @param data   The data or null if none specified.
 866      * @param augs Additional information that may include infoset
 867      *                      augmentations.
 868      * @throws XNIException Thrown by handler to signal an error.
 869      */
 870     public void processingInstruction(String target, XMLString data,
 871                                       Augmentations augs) throws XNIException {}
 872 
 873     /**
 874      * The start of an attribute list.
 875      *
 876      * @param elementName The name of the element that this attribute
 877      *                    list is associated with.
 878      * @param augs Additional information that may include infoset
 879      *                      augmentations.
 880      * @throws XNIException Thrown by handler to signal an error.
 881      */
 882     public void startAttlist(String elementName, Augmentations augs)
 883         throws XNIException {}
 884 
 885     /**
 886      * The end of an attribute list.
 887      * @param augs Additional information that may include infoset
 888      *                      augmentations.
 889      * @throws XNIException Thrown by handler to signal an error.
 890      */
 891     public void endAttlist(Augmentations augs) throws XNIException {}
 892 
 893     /**
 894      * The start of a conditional section.
 895      *
 896      * @param type The type of the conditional section. This value will
 897      *             either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE.
 898      * @param augs Additional information that may include infoset
 899      *                      augmentations.
 900      * @throws XNIException Thrown by handler to signal an error.
 901      *
 902      * @see XMLDTDHandler#CONDITIONAL_INCLUDE
 903      * @see XMLDTDHandler#CONDITIONAL_IGNORE
 904      */
 905     public void startConditional(short type, Augmentations augs)
 906         throws XNIException {}
 907 
 908     /**
 909      * Characters within an IGNORE conditional section.
 910      *
 911      * @param text The ignored text.
 912      * @param augs Additional information that may include infoset
 913      *                      augmentations.
 914      */
 915     public void ignoredCharacters(XMLString text, Augmentations augs)
 916         throws XNIException {}
 917 
 918     /**
 919      * The end of a conditional section.
 920      * @param augs Additional information that may include infoset
 921      *                      augmentations.
 922      * @throws XNIException Thrown by handler to signal an error.
 923      */
 924     public void endConditional(Augmentations augs) throws XNIException {}
 925 
 926     //
 927     // XMLDTDContentModelHandler methods
 928     //
 929 
 930     // set content model source
 931     public void setDTDContentModelSource(XMLDTDContentModelSource source) {
 932         fDTDContentModelSource = source;
 933     }
 934 
 935     // get content model source
 936     public XMLDTDContentModelSource getDTDContentModelSource() {
 937         return fDTDContentModelSource;
 938     }
 939 
 940     /**
 941      * The start of a content model. Depending on the type of the content
 942      * model, specific methods may be called between the call to the
 943      * startContentModel method and the call to the endContentModel method.
 944      *
 945      * @param elementName The name of the element.
 946      * @param augs Additional information that may include infoset
 947      *                      augmentations.
 948      * @throws XNIException Thrown by handler to signal an error.
 949      */
 950     public void startContentModel(String elementName, Augmentations augs)
 951         throws XNIException {
 952 
 953         XMLElementDecl elementDecl = this.fElementDeclTab.get(elementName);
 954         if ( elementDecl != null ) {
 955             fElementDecl = elementDecl;
 956         }
 957         fDepth = 0;
 958         initializeContentModelStack();
 959 
 960     } // startContentModel(String)
 961 
 962     /**
 963      * A start of either a mixed or children content model. A mixed
 964      * content model will immediately be followed by a call to the
 965      * <code>pcdata()</code> method. A children content model will
 966      * contain additional groups and/or elements.
 967      *
 968      * @param augs Additional information that may include infoset
 969      *                      augmentations.
 970      * @throws XNIException Thrown by handler to signal an error.
 971      *
 972      * @see #any
 973      * @see #empty
 974      */
 975     public void startGroup(Augmentations augs) throws XNIException {
 976         fDepth++;
 977         initializeContentModelStack();
 978         fMixed = false;
 979     } // startGroup()
 980 
 981     /**
 982      * The appearance of "#PCDATA" within a group signifying a
 983      * mixed content model. This method will be the first called
 984      * following the content model's <code>startGroup()</code>.
 985      *
 986      *@param augs Additional information that may include infoset
 987      *                      augmentations.
 988      *
 989      * @throws XNIException Thrown by handler to signal an error.
 990      *
 991      * @see #startGroup
 992      */
 993     public void pcdata(Augmentations augs) throws XNIException {
 994         fMixed = true;
 995     } // pcdata()
 996 
 997     /**
 998      * A referenced element in a mixed or children content model.
 999      *
1000      * @param elementName The name of the referenced element.
1001      * @param augs Additional information that may include infoset
1002      *                      augmentations.
1003      *
1004      * @throws XNIException Thrown by handler to signal an error.
1005      */
1006     public void element(String elementName, Augmentations augs) throws XNIException {
1007         if (fMixed) {
1008             if (fNodeIndexStack[fDepth] == -1 ) {
1009                 fNodeIndexStack[fDepth] = addUniqueLeafNode(elementName);
1010             }
1011             else {
1012                 fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_CHOICE,
1013                                                              fNodeIndexStack[fDepth],
1014                                                              addUniqueLeafNode(elementName));
1015             }
1016         }
1017         else {
1018             fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_LEAF, elementName);
1019         }
1020     } // element(String)
1021 
1022     /**
1023      * The separator between choices or sequences of a mixed or children
1024      * content model.
1025      *
1026      * @param separator The type of children separator.
1027      * @param augs Additional information that may include infoset
1028      *                      augmentations.
1029      * @throws XNIException Thrown by handler to signal an error.
1030      *
1031      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_CHOICE
1032      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#SEPARATOR_SEQUENCE
1033      */
1034     public void separator(short separator, Augmentations augs) throws XNIException {
1035 
1036         if (!fMixed) {
1037             if (fOpStack[fDepth] != XMLContentSpec.CONTENTSPECNODE_SEQ && separator == XMLDTDContentModelHandler.SEPARATOR_CHOICE ) {
1038                 if (fPrevNodeIndexStack[fDepth] != -1) {
1039                     fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]);
1040                 }
1041                 fPrevNodeIndexStack[fDepth] = fNodeIndexStack[fDepth];
1042                 fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_CHOICE;
1043             } else if (fOpStack[fDepth] != XMLContentSpec.CONTENTSPECNODE_CHOICE && separator == XMLDTDContentModelHandler.SEPARATOR_SEQUENCE) {
1044                 if (fPrevNodeIndexStack[fDepth] != -1) {
1045                     fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]);
1046                 }
1047                 fPrevNodeIndexStack[fDepth] = fNodeIndexStack[fDepth];
1048                 fOpStack[fDepth] = XMLContentSpec.CONTENTSPECNODE_SEQ;
1049             }
1050         }
1051 
1052     } // separator(short)
1053 
1054     /**
1055      * The occurrence count for a child in a children content model or
1056      * for the mixed content model group.
1057      *
1058      * @param occurrence The occurrence count for the last element
1059      *                   or group.
1060      * @param augs Additional information that may include infoset
1061      *                      augmentations.
1062      * @throws XNIException Thrown by handler to signal an error.
1063      *
1064      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_ONE
1065      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ZERO_OR_MORE
1066      * @see org.apache.xerces.xni.XMLDTDContentModelHandler#OCCURS_ONE_OR_MORE
1067      */
1068     public void occurrence(short occurrence, Augmentations augs) throws XNIException {
1069 
1070         if (!fMixed) {
1071             if (occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE ) {
1072                 fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE, fNodeIndexStack[fDepth], -1);
1073             } else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE ) {
1074                 fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE, fNodeIndexStack[fDepth], -1 );
1075             } else if ( occurrence == XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE) {
1076                 fNodeIndexStack[fDepth] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE, fNodeIndexStack[fDepth], -1 );
1077             }
1078         }
1079 
1080     } // occurrence(short)
1081 
1082     /**
1083      * The end of a group for mixed or children content models.
1084      *
1085      * @param augs Additional information that may include infoset
1086      *                      augmentations.
1087      * @throws XNIException Thrown by handler to signal an error.
1088      */
1089     public void endGroup(Augmentations augs) throws XNIException {
1090 
1091         if (!fMixed) {
1092             if (fPrevNodeIndexStack[fDepth] != -1) {
1093                 fNodeIndexStack[fDepth] = addContentSpecNode(fOpStack[fDepth], fPrevNodeIndexStack[fDepth], fNodeIndexStack[fDepth]);
1094             }
1095             int nodeIndex = fNodeIndexStack[fDepth--];
1096             fNodeIndexStack[fDepth] = nodeIndex;
1097         }
1098 
1099     } // endGroup()
1100 
1101     // no-op methods
1102 
1103     /**
1104      * A content model of ANY.
1105      *
1106      * @param augs Additional information that may include infoset
1107      *                      augmentations.
1108      * @throws XNIException Thrown by handler to signal an error.
1109      *
1110      * @see #empty
1111      * @see #startGroup
1112      */
1113     public void any(Augmentations augs) throws XNIException {}
1114 
1115     /**
1116      * A content model of EMPTY.
1117      *
1118      * @param augs Additional information that may include infoset
1119      *                      augmentations.
1120      * @throws XNIException Thrown by handler to signal an error.
1121      *
1122      * @see #any
1123      * @see #startGroup
1124      */
1125     public void empty(Augmentations augs) throws XNIException {}
1126 
1127     /**
1128      * The end of a content model.
1129      * @param augs Additional information that may include infoset
1130      *                      augmentations.
1131      *
1132      * @throws XNIException Thrown by handler to signal an error.
1133      */
1134     public void endContentModel(Augmentations augs) throws XNIException {}
1135 
1136     //
1137     // Grammar methods
1138     //
1139 
1140     /** Returns true if this grammar is namespace aware. */
1141     public boolean isNamespaceAware() {
1142         return false;
1143     } // isNamespaceAware():boolean
1144 
1145     /** Returns the symbol table. */
1146     public SymbolTable getSymbolTable() {
1147         return fSymbolTable;
1148     } // getSymbolTable():SymbolTable
1149 
1150     /**
1151      * Returns the index of the first element declaration. This index
1152      * is then used to query more information about the element declaration.
1153      *
1154      * @see #getNextElementDeclIndex
1155      * @see #getElementDecl
1156      */
1157     public int getFirstElementDeclIndex() {
1158         return fElementDeclCount >= 0 ? 0 : -1;
1159     } // getFirstElementDeclIndex():int
1160 
1161     /**
1162      * Returns the next index of the element declaration following the
1163      * specified element declaration.
1164      *
1165      * @param elementDeclIndex The element declaration index.
1166      */
1167     public int getNextElementDeclIndex(int elementDeclIndex) {
1168         return elementDeclIndex < fElementDeclCount - 1
1169              ? elementDeclIndex + 1 : -1;
1170     } // getNextElementDeclIndex(int):int
1171 
1172     /**
1173      * getElementDeclIndex
1174      *
1175      * @param elementDeclName
1176      *
1177      * @return index of the elementDeclName in scope
1178      */
1179     public int getElementDeclIndex(String elementDeclName) {
1180         Integer mapping = fElementIndexMap.get(elementDeclName);
1181         if (mapping == null) {
1182             mapping = -1;
1183         }
1184         //System.out.println("getElementDeclIndex("+elementDeclName+") -> "+mapping);
1185         return mapping;
1186     } // getElementDeclIndex(String):int
1187 
1188     /** Returns the element decl index.
1189      * @param elementDeclQName qualilfied name of the element
1190      */
1191     public int getElementDeclIndex(QName elementDeclQName) {
1192         return getElementDeclIndex(elementDeclQName.rawname);
1193     } // getElementDeclIndex(QName):int
1194 
1195                 /** make separate function for getting contentSpecType of element.
1196       * we can avoid setting of the element values.
1197                 */
1198 
1199                 public short getContentSpecType(int elementIndex){
1200         if (elementIndex < 0 || elementIndex >= fElementDeclCount) {
1201             return -1 ;
1202         }
1203 
1204         int chunk = elementIndex >> CHUNK_SHIFT;
1205         int index = elementIndex &  CHUNK_MASK;
1206 
1207         if(fElementDeclType[chunk][index] == -1){
1208             return -1 ;
1209                             }
1210         else{
1211                                        return (short) (fElementDeclType[chunk][index] & LIST_MASK);
1212                             }
1213 
1214                 }//getContentSpecType
1215 
1216     /**
1217      * getElementDecl
1218      *
1219      * @param elementDeclIndex
1220      * @param elementDecl The values of this structure are set by this call.
1221      *
1222      * @return True if find the element, False otherwise.
1223      */
1224     public boolean getElementDecl(int elementDeclIndex,
1225                                   XMLElementDecl elementDecl) {
1226 
1227         if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
1228             return false;
1229         }
1230 
1231         int chunk = elementDeclIndex >> CHUNK_SHIFT;
1232         int index = elementDeclIndex &  CHUNK_MASK;
1233 
1234         elementDecl.name.setValues(fElementDeclName[chunk][index]);
1235 
1236         if (fElementDeclType[chunk][index] == -1) {
1237             elementDecl.type                    = -1;
1238             elementDecl.simpleType.list = false;
1239         } else {
1240             elementDecl.type            = (short) (fElementDeclType[chunk][index] & LIST_MASK);
1241             elementDecl.simpleType.list = (fElementDeclType[chunk][index] & LIST_FLAG) != 0;
1242         }
1243 
1244         /* Validators are null until we add that code */
1245         if (elementDecl.type == XMLElementDecl.TYPE_CHILDREN || elementDecl.type == XMLElementDecl.TYPE_MIXED) {
1246             elementDecl.contentModelValidator = getElementContentModelValidator(elementDeclIndex);
1247         }
1248 
1249         elementDecl.simpleType.datatypeValidator = null;
1250         elementDecl.simpleType.defaultType       = -1;
1251         elementDecl.simpleType.defaultValue      = null;
1252 
1253         return true;
1254 
1255     } // getElementDecl(int,XMLElementDecl):boolean
1256 
1257     QName getElementDeclName(int elementDeclIndex) {
1258         if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
1259             return null;
1260         }
1261         int chunk = elementDeclIndex >> CHUNK_SHIFT;
1262         int index = elementDeclIndex &  CHUNK_MASK;
1263         return fElementDeclName[chunk][index];
1264     }
1265 
1266     // REVISIT: Make this getAttributeDeclCount/getAttributeDeclAt. -Ac
1267 
1268     /**
1269      * getFirstAttributeDeclIndex
1270      *
1271      * @param elementDeclIndex
1272      *
1273      * @return index of the first attribute for element declaration elementDeclIndex
1274      */
1275     public int getFirstAttributeDeclIndex(int elementDeclIndex) {
1276         int chunk = elementDeclIndex >> CHUNK_SHIFT;
1277         int index = elementDeclIndex &  CHUNK_MASK;
1278 
1279         return  fElementDeclFirstAttributeDeclIndex[chunk][index];
1280     } // getFirstAttributeDeclIndex
1281 
1282     /**
1283      * getNextAttributeDeclIndex
1284      *
1285      * @param attributeDeclIndex
1286      *
1287      * @return index of the next attribute of the attribute at attributeDeclIndex
1288      */
1289     public int getNextAttributeDeclIndex(int attributeDeclIndex) {
1290         int chunk = attributeDeclIndex >> CHUNK_SHIFT;
1291         int index = attributeDeclIndex &  CHUNK_MASK;
1292 
1293         return fAttributeDeclNextAttributeDeclIndex[chunk][index];
1294     } // getNextAttributeDeclIndex
1295 
1296     /**
1297      * getAttributeDecl
1298      *
1299      * @param attributeDeclIndex
1300      * @param attributeDecl The values of this structure are set by this call.
1301      *
1302      * @return true if getAttributeDecl was able to fill in the value of attributeDecl
1303      */
1304     public boolean getAttributeDecl(int attributeDeclIndex, XMLAttributeDecl attributeDecl) {
1305         if (attributeDeclIndex < 0 || attributeDeclIndex >= fAttributeDeclCount) {
1306             return false;
1307         }
1308         int chunk = attributeDeclIndex >> CHUNK_SHIFT;
1309         int index = attributeDeclIndex & CHUNK_MASK;
1310 
1311         attributeDecl.name.setValues(fAttributeDeclName[chunk][index]);
1312 
1313         short attributeType;
1314         boolean isList;
1315 
1316         if (fAttributeDeclType[chunk][index] == -1) {
1317 
1318             attributeType = -1;
1319             isList = false;
1320         } else {
1321             attributeType = (short) (fAttributeDeclType[chunk][index] & LIST_MASK);
1322             isList = (fAttributeDeclType[chunk][index] & LIST_FLAG) != 0;
1323         }
1324         attributeDecl.simpleType.setValues(attributeType,fAttributeDeclName[chunk][index].localpart,
1325                                            fAttributeDeclEnumeration[chunk][index],
1326                                            isList, fAttributeDeclDefaultType[chunk][index],
1327                                            fAttributeDeclDefaultValue[chunk][index],
1328                                            fAttributeDeclNonNormalizedDefaultValue[chunk][index],
1329                                            fAttributeDeclDatatypeValidator[chunk][index]);
1330         return true;
1331 
1332     } // getAttributeDecl
1333 
1334 
1335     /**
1336      * Returns whether the given attribute is of type CDATA or not
1337      *
1338      * @param elName The element name.
1339      * @param atName The attribute name.
1340      *
1341      * @return true if the attribute is of type CDATA
1342      */
1343     public boolean isCDATAAttribute(QName elName, QName atName) {
1344         int elDeclIdx = getElementDeclIndex(elName);
1345         if (getAttributeDecl(elDeclIdx, fAttributeDecl)
1346             && fAttributeDecl.simpleType.type != XMLSimpleType.TYPE_CDATA){
1347             return false;
1348         }
1349         return true;
1350     }
1351 
1352     /**
1353      * getEntityDeclIndex
1354      *
1355      * @param entityDeclName
1356      *
1357      * @return the index of the EntityDecl
1358      */
1359     public int getEntityDeclIndex(String entityDeclName) {
1360         if (entityDeclName == null || fEntityIndexMap.get(entityDeclName) == null) {
1361             return -1;
1362         }
1363 
1364         return fEntityIndexMap.get(entityDeclName);
1365     } // getEntityDeclIndex
1366 
1367     /**
1368      * getEntityDecl
1369      *
1370      * @param entityDeclIndex
1371      * @param entityDecl
1372      *
1373      * @return true if getEntityDecl was able to fill entityDecl with the contents of the entity
1374      * with index entityDeclIndex
1375      */
1376     public boolean getEntityDecl(int entityDeclIndex, XMLEntityDecl entityDecl) {
1377         if (entityDeclIndex < 0 || entityDeclIndex >= fEntityCount) {
1378             return false;
1379         }
1380         int chunk = entityDeclIndex >> CHUNK_SHIFT;
1381         int index = entityDeclIndex & CHUNK_MASK;
1382 
1383         entityDecl.setValues(fEntityName[chunk][index],
1384                              fEntityPublicId[chunk][index],
1385                              fEntitySystemId[chunk][index],
1386                              fEntityBaseSystemId[chunk][index],
1387                              fEntityNotation[chunk][index],
1388                              fEntityValue[chunk][index],
1389                              fEntityIsPE[chunk][index] == 0 ? false : true ,
1390                              fEntityInExternal[chunk][index] == 0 ? false : true );
1391 
1392         return true;
1393     } // getEntityDecl
1394 
1395     /**
1396      * getNotationDeclIndex
1397      *
1398      * @param notationDeclName
1399      *
1400      * @return the index if found a notation with the name, otherwise -1.
1401      */
1402     public int getNotationDeclIndex(String notationDeclName) {
1403         if (notationDeclName == null || fNotationIndexMap.get(notationDeclName) == null) {
1404             return -1;
1405         }
1406 
1407         return fNotationIndexMap.get(notationDeclName);
1408     } // getNotationDeclIndex
1409 
1410     /**
1411      * getNotationDecl
1412      *
1413      * @param notationDeclIndex
1414      * @param notationDecl
1415      *
1416      * @return return true of getNotationDecl can fill notationDecl with information about
1417      * the notation at notationDeclIndex.
1418      */
1419     public boolean getNotationDecl(int notationDeclIndex, XMLNotationDecl notationDecl) {
1420         if (notationDeclIndex < 0 || notationDeclIndex >= fNotationCount) {
1421             return false;
1422         }
1423         int chunk = notationDeclIndex >> CHUNK_SHIFT;
1424         int index = notationDeclIndex & CHUNK_MASK;
1425 
1426         notationDecl.setValues(fNotationName[chunk][index],
1427                                fNotationPublicId[chunk][index],
1428                                fNotationSystemId[chunk][index],
1429                                fNotationBaseSystemId[chunk][index]);
1430 
1431         return true;
1432 
1433     } // getNotationDecl
1434 
1435     /**
1436      * getContentSpec
1437      *
1438      * @param contentSpecIndex
1439      * @param contentSpec
1440      *
1441      * @return true if find the requested contentSpec node, false otherwise
1442      */
1443     public boolean getContentSpec(int contentSpecIndex, XMLContentSpec contentSpec) {
1444         if (contentSpecIndex < 0 || contentSpecIndex >= fContentSpecCount )
1445             return false;
1446 
1447         int chunk = contentSpecIndex >> CHUNK_SHIFT;
1448         int index = contentSpecIndex & CHUNK_MASK;
1449 
1450         contentSpec.type       = fContentSpecType[chunk][index];
1451         contentSpec.value      = fContentSpecValue[chunk][index];
1452         contentSpec.otherValue = fContentSpecOtherValue[chunk][index];
1453         return true;
1454     }
1455 
1456     /**
1457      * Returns the index to the content spec for the given element
1458      * declaration, or <code>-1</code> if the element declaration
1459      * index was invalid.
1460      */
1461     public int getContentSpecIndex(int elementDeclIndex) {
1462         if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
1463             return -1;
1464         }
1465         final int chunk = elementDeclIndex >> CHUNK_SHIFT;
1466         final int index = elementDeclIndex & CHUNK_MASK;
1467         return fElementDeclContentSpecIndex[chunk][index];
1468     }
1469 
1470     /**
1471      * getContentSpecAsString
1472      *
1473      * @param elementDeclIndex
1474      *
1475      * @return String
1476      */
1477     public String getContentSpecAsString(int elementDeclIndex){
1478 
1479         if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
1480             return null;
1481         }
1482 
1483         int chunk = elementDeclIndex >> CHUNK_SHIFT;
1484         int index = elementDeclIndex &  CHUNK_MASK;
1485 
1486         int contentSpecIndex = fElementDeclContentSpecIndex[chunk][index];
1487 
1488         // lookup content spec node
1489         XMLContentSpec contentSpec = new XMLContentSpec();
1490 
1491         if (getContentSpec(contentSpecIndex, contentSpec)) {
1492 
1493             // build string
1494             StringBuffer str = new StringBuffer();
1495             int    parentContentSpecType = contentSpec.type & 0x0f;
1496             int    nextContentSpec;
1497             switch (parentContentSpecType) {
1498                 case XMLContentSpec.CONTENTSPECNODE_LEAF: {
1499                     str.append('(');
1500                     if (contentSpec.value == null && contentSpec.otherValue == null) {
1501                         str.append("#PCDATA");
1502                     }
1503                     else {
1504                         str.append(contentSpec.value);
1505                     }
1506                     str.append(')');
1507                     break;
1508                 }
1509                 case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: {
1510                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
1511                     nextContentSpec = contentSpec.type;
1512 
1513                     if (nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) {
1514                         str.append('(');
1515                         str.append(contentSpec.value);
1516                         str.append(')');
1517                     } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE  ||
1518                         nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE  ||
1519                         nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
1520                         str.append('(' );
1521                         appendContentSpec(contentSpec, str,
1522                                           true, parentContentSpecType );
1523                         str.append(')');
1524                     } else {
1525                         appendContentSpec(contentSpec, str,
1526                                           true, parentContentSpecType );
1527                     }
1528                     str.append('?');
1529                     break;
1530                 }
1531                 case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: {
1532                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
1533                     nextContentSpec = contentSpec.type;
1534 
1535                     if ( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) {
1536                         str.append('(');
1537                         if (contentSpec.value == null && contentSpec.otherValue == null) {
1538                             str.append("#PCDATA");
1539                         }
1540                         else if (contentSpec.otherValue != null) {
1541                             str.append("##any:uri=").append(contentSpec.otherValue);
1542                         }
1543                         else if (contentSpec.value == null) {
1544                             str.append("##any");
1545                         }
1546                         else {
1547                             appendContentSpec(contentSpec, str,
1548                                               true, parentContentSpecType );
1549                         }
1550                         str.append(')');
1551                     } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE  ||
1552                         nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE  ||
1553                         nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
1554                         str.append('(' );
1555                         appendContentSpec(contentSpec, str,
1556                                           true, parentContentSpecType );
1557                         str.append(')');
1558                     } else {
1559                         appendContentSpec(contentSpec, str,
1560                                           true, parentContentSpecType );
1561                     }
1562                     str.append('*');
1563                     break;
1564                 }
1565                 case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: {
1566                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
1567                     nextContentSpec = contentSpec.type;
1568 
1569                     if ( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_LEAF) {
1570                         str.append('(');
1571                         if (contentSpec.value == null && contentSpec.otherValue == null) {
1572                             str.append("#PCDATA");
1573                         }
1574                         else if (contentSpec.otherValue != null) {
1575                             str.append("##any:uri=").append(contentSpec.otherValue);
1576                         }
1577                         else if (contentSpec.value == null) {
1578                             str.append("##any");
1579                         }
1580                         else {
1581                             str.append(contentSpec.value);
1582                         }
1583                         str.append(')');
1584                     } else if( nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE  ||
1585                         nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE  ||
1586                         nextContentSpec == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
1587                         str.append('(' );
1588                         appendContentSpec(contentSpec, str,
1589                                           true, parentContentSpecType );
1590                         str.append(')');
1591                     } else {
1592                         appendContentSpec(contentSpec, str,
1593                                           true, parentContentSpecType);
1594                     }
1595                     str.append('+');
1596                     break;
1597                 }
1598                 case XMLContentSpec.CONTENTSPECNODE_CHOICE:
1599                 case XMLContentSpec.CONTENTSPECNODE_SEQ: {
1600                     appendContentSpec(contentSpec, str,
1601                                       true, parentContentSpecType );
1602                     break;
1603                 }
1604                 case XMLContentSpec.CONTENTSPECNODE_ANY: {
1605                     str.append("##any");
1606                     if (contentSpec.otherValue != null) {
1607                         str.append(":uri=");
1608                         str.append(contentSpec.otherValue);
1609                     }
1610                     break;
1611                 }
1612                 case XMLContentSpec.CONTENTSPECNODE_ANY_OTHER: {
1613                     str.append("##other:uri=");
1614                     str.append(contentSpec.otherValue);
1615                     break;
1616                 }
1617                 case XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL: {
1618                     str.append("##local");
1619                     break;
1620                 }
1621                 default: {
1622                     str.append("???");
1623                 }
1624 
1625             } // switch type
1626 
1627             // return string
1628             return str.toString();
1629         }
1630 
1631         // not found
1632         return null;
1633 
1634     } // getContentSpecAsString(int):String
1635 
1636     // debugging
1637 
1638     public void printElements(  ) {
1639         int elementDeclIndex = 0;
1640         XMLElementDecl elementDecl = new XMLElementDecl();
1641         while (getElementDecl(elementDeclIndex++, elementDecl)) {
1642 
1643             System.out.println("element decl: "+elementDecl.name+
1644                                ", "+ elementDecl.name.rawname  );
1645 
1646             //                   ", "+ elementDecl.contentModelValidator.toString());
1647         }
1648     }
1649 
1650     public void printAttributes(int elementDeclIndex) {
1651         int attributeDeclIndex = getFirstAttributeDeclIndex(elementDeclIndex);
1652         System.out.print(elementDeclIndex);
1653         System.out.print(" [");
1654         while (attributeDeclIndex != -1) {
1655             System.out.print(' ');
1656             System.out.print(attributeDeclIndex);
1657             printAttribute(attributeDeclIndex);
1658             attributeDeclIndex = getNextAttributeDeclIndex(attributeDeclIndex);
1659             if (attributeDeclIndex != -1) {
1660                 System.out.print(",");
1661             }
1662         }
1663         System.out.println(" ]");
1664     }
1665 
1666     //
1667     // Protected methods
1668     //
1669 
1670     /**
1671      * Adds the content spec to the given element declaration.
1672      */
1673     protected void addContentSpecToElement(XMLElementDecl elementDecl) {
1674         if ((fDepth == 0 || (fDepth == 1 && elementDecl.type == XMLElementDecl.TYPE_MIXED)) &&
1675                 fNodeIndexStack != null) {
1676             if (elementDecl.type == XMLElementDecl.TYPE_MIXED) {
1677                 int pcdata = addUniqueLeafNode(null);
1678                 if (fNodeIndexStack[0] == -1) {
1679                     fNodeIndexStack[0] = pcdata;
1680                 }
1681                 else {
1682                     fNodeIndexStack[0] = addContentSpecNode(XMLContentSpec.CONTENTSPECNODE_CHOICE,
1683                             pcdata, fNodeIndexStack[0]);
1684                 }
1685             }
1686             setContentSpecIndex(fCurrentElementIndex, fNodeIndexStack[fDepth]);
1687         }
1688     }
1689 
1690     /**
1691      * getElementContentModelValidator
1692      *
1693      * @param elementDeclIndex
1694      *
1695      * @return its ContentModelValidator if any.
1696      */
1697     protected ContentModelValidator getElementContentModelValidator(int elementDeclIndex) {
1698 
1699         int chunk = elementDeclIndex >> CHUNK_SHIFT;
1700         int index = elementDeclIndex & CHUNK_MASK;
1701 
1702         ContentModelValidator contentModel    =  fElementDeclContentModelValidator[chunk][index];
1703 
1704         // If we have one, just return that. Otherwise, gotta create one
1705         if (contentModel != null) {
1706             return contentModel;
1707         }
1708 
1709         int contentType = fElementDeclType[chunk][index];
1710         if (contentType == XMLElementDecl.TYPE_SIMPLE) {
1711             return null;
1712         }
1713 
1714         // Get the type of content this element has
1715         int contentSpecIndex = fElementDeclContentSpecIndex[chunk][index];
1716 
1717         /***
1718         if ( contentSpecIndex == -1 )
1719             return null;
1720         /***/
1721 
1722         XMLContentSpec  contentSpec = new XMLContentSpec();
1723         getContentSpec( contentSpecIndex, contentSpec );
1724 
1725         // And create the content model according to the spec type
1726         if ( contentType == XMLElementDecl.TYPE_MIXED ) {
1727             //
1728             //  Just create a mixel content model object. This type of
1729             //  content model is optimized for mixed content validation.
1730             //
1731             ChildrenList children = new ChildrenList();
1732             contentSpecTree(contentSpecIndex, contentSpec, children);
1733             contentModel = new MixedContentModel(children.qname,
1734                                                  children.type,
1735                                                  0, children.length,
1736                                                  false);
1737         } else if (contentType == XMLElementDecl.TYPE_CHILDREN) {
1738             //  This method will create an optimal model for the complexity
1739             //  of the element's defined model. If its simple, it will create
1740             //  a SimpleContentModel object. If its a simple list, it will
1741             //  create a SimpleListContentModel object. If its complex, it
1742             //  will create a DFAContentModel object.
1743             //
1744             contentModel = createChildModel(contentSpecIndex);
1745         } else {
1746             throw new RuntimeException("Unknown content type for a element decl "
1747                                      + "in getElementContentModelValidator() in AbstractDTDGrammar class");
1748         }
1749 
1750         // Add the new model to the content model for this element
1751         fElementDeclContentModelValidator[chunk][index] = contentModel;
1752 
1753         return contentModel;
1754 
1755     } // getElementContentModelValidator(int):ContentModelValidator
1756 
1757    protected int createElementDecl() {
1758       int chunk = fElementDeclCount >> CHUNK_SHIFT;
1759       int index = fElementDeclCount & CHUNK_MASK;
1760       ensureElementDeclCapacity(chunk);
1761       fElementDeclName[chunk][index]                    = new QName();
1762       fElementDeclType[chunk][index]                    = -1;
1763       fElementDeclContentModelValidator[chunk][index]   = null;
1764       fElementDeclFirstAttributeDeclIndex[chunk][index] = -1;
1765       fElementDeclLastAttributeDeclIndex[chunk][index]  = -1;
1766       return fElementDeclCount++;
1767    }
1768 
1769    protected void setElementDecl(int elementDeclIndex, XMLElementDecl elementDecl) {
1770       if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
1771          return;
1772       }
1773       int     chunk       = elementDeclIndex >> CHUNK_SHIFT;
1774       int     index       = elementDeclIndex &  CHUNK_MASK;
1775 
1776       fElementDeclName[chunk][index].setValues(elementDecl.name);
1777       fElementDeclType[chunk][index]                  = elementDecl.type;
1778 
1779       fElementDeclContentModelValidator[chunk][index] = elementDecl.contentModelValidator;
1780 
1781       if (elementDecl.simpleType.list  == true ) {
1782          fElementDeclType[chunk][index] |= LIST_FLAG;
1783       }
1784 
1785       fElementIndexMap.put(elementDecl.name.rawname, elementDeclIndex);
1786    }
1787 
1788 
1789 
1790 
1791    protected void putElementNameMapping(QName name, int scope,
1792                                         int elementDeclIndex) {
1793    }
1794 
1795    protected void setFirstAttributeDeclIndex(int elementDeclIndex, int newFirstAttrIndex){
1796 
1797       if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
1798          return;
1799       }
1800 
1801       int chunk = elementDeclIndex >> CHUNK_SHIFT;
1802       int index = elementDeclIndex &  CHUNK_MASK;
1803 
1804       fElementDeclFirstAttributeDeclIndex[chunk][index] = newFirstAttrIndex;
1805    }
1806 
1807    protected void setContentSpecIndex(int elementDeclIndex, int contentSpecIndex){
1808 
1809       if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
1810          return;
1811       }
1812 
1813       int chunk = elementDeclIndex >> CHUNK_SHIFT;
1814       int index = elementDeclIndex &  CHUNK_MASK;
1815 
1816       fElementDeclContentSpecIndex[chunk][index] = contentSpecIndex;
1817    }
1818 
1819 
1820    protected int createAttributeDecl() {
1821       int chunk = fAttributeDeclCount >> CHUNK_SHIFT;
1822       int index = fAttributeDeclCount & CHUNK_MASK;
1823 
1824       ensureAttributeDeclCapacity(chunk);
1825       fAttributeDeclName[chunk][index]                    = new QName();
1826       fAttributeDeclType[chunk][index]                    = -1;
1827       fAttributeDeclDatatypeValidator[chunk][index]       = null;
1828       fAttributeDeclEnumeration[chunk][index]             = null;
1829       fAttributeDeclDefaultType[chunk][index]             = XMLSimpleType.DEFAULT_TYPE_IMPLIED;
1830       fAttributeDeclDefaultValue[chunk][index]            = null;
1831       fAttributeDeclNonNormalizedDefaultValue[chunk][index]            = null;
1832       fAttributeDeclNextAttributeDeclIndex[chunk][index]  = -1;
1833       return fAttributeDeclCount++;
1834    }
1835 
1836 
1837    protected void setAttributeDecl(int elementDeclIndex, int attributeDeclIndex,
1838                                    XMLAttributeDecl attributeDecl) {
1839       int attrChunk = attributeDeclIndex >> CHUNK_SHIFT;
1840       int attrIndex = attributeDeclIndex &  CHUNK_MASK;
1841       fAttributeDeclName[attrChunk][attrIndex].setValues(attributeDecl.name);
1842       fAttributeDeclType[attrChunk][attrIndex]  =  attributeDecl.simpleType.type;
1843 
1844       if (attributeDecl.simpleType.list) {
1845          fAttributeDeclType[attrChunk][attrIndex] |= LIST_FLAG;
1846       }
1847       fAttributeDeclEnumeration[attrChunk][attrIndex]  =  attributeDecl.simpleType.enumeration;
1848       fAttributeDeclDefaultType[attrChunk][attrIndex]  =  attributeDecl.simpleType.defaultType;
1849       fAttributeDeclDatatypeValidator[attrChunk][attrIndex] =  attributeDecl.simpleType.datatypeValidator;
1850 
1851       fAttributeDeclDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.defaultValue;
1852       fAttributeDeclNonNormalizedDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.nonNormalizedDefaultValue;
1853 
1854       int elemChunk     = elementDeclIndex >> CHUNK_SHIFT;
1855       int elemIndex     = elementDeclIndex &  CHUNK_MASK;
1856       int index         = fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex];
1857       while (index != -1) {
1858          if (index == attributeDeclIndex) {
1859             break;
1860          }
1861          attrChunk = index >> CHUNK_SHIFT;
1862          attrIndex = index & CHUNK_MASK;
1863          index = fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex];
1864       }
1865       if (index == -1) {
1866          if (fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] == -1) {
1867             fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex;
1868          } else {
1869             index = fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex];
1870             attrChunk = index >> CHUNK_SHIFT;
1871             attrIndex = index & CHUNK_MASK;
1872             fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex] = attributeDeclIndex;
1873          }
1874          fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex;
1875       }
1876    }
1877 
1878    protected int createContentSpec() {
1879       int chunk = fContentSpecCount >> CHUNK_SHIFT;
1880       int index = fContentSpecCount & CHUNK_MASK;
1881 
1882       ensureContentSpecCapacity(chunk);
1883       fContentSpecType[chunk][index]       = -1;
1884       fContentSpecValue[chunk][index]      = null;
1885       fContentSpecOtherValue[chunk][index] = null;
1886 
1887       return fContentSpecCount++;
1888    }
1889 
1890    protected void setContentSpec(int contentSpecIndex, XMLContentSpec contentSpec) {
1891       int   chunk = contentSpecIndex >> CHUNK_SHIFT;
1892       int   index = contentSpecIndex & CHUNK_MASK;
1893 
1894       fContentSpecType[chunk][index]       = contentSpec.type;
1895       fContentSpecValue[chunk][index]      = contentSpec.value;
1896       fContentSpecOtherValue[chunk][index] = contentSpec.otherValue;
1897    }
1898 
1899 
1900    protected int createEntityDecl() {
1901        int chunk = fEntityCount >> CHUNK_SHIFT;
1902        int index = fEntityCount & CHUNK_MASK;
1903 
1904       ensureEntityDeclCapacity(chunk);
1905       fEntityIsPE[chunk][index] = 0;
1906       fEntityInExternal[chunk][index] = 0;
1907 
1908       return fEntityCount++;
1909    }
1910 
1911    protected void setEntityDecl(int entityDeclIndex, XMLEntityDecl entityDecl) {
1912        int chunk = entityDeclIndex >> CHUNK_SHIFT;
1913        int index = entityDeclIndex & CHUNK_MASK;
1914 
1915        fEntityName[chunk][index] = entityDecl.name;
1916        fEntityValue[chunk][index] = entityDecl.value;
1917        fEntityPublicId[chunk][index] = entityDecl.publicId;
1918        fEntitySystemId[chunk][index] = entityDecl.systemId;
1919        fEntityBaseSystemId[chunk][index] = entityDecl.baseSystemId;
1920        fEntityNotation[chunk][index] = entityDecl.notation;
1921        fEntityIsPE[chunk][index] = entityDecl.isPE ? (byte)1 : (byte)0;
1922        fEntityInExternal[chunk][index] = entityDecl.inExternal ? (byte)1 : (byte)0;
1923 
1924        fEntityIndexMap.put(entityDecl.name, entityDeclIndex);
1925    }
1926 
1927    protected int createNotationDecl() {
1928        int chunk = fNotationCount >> CHUNK_SHIFT;
1929        ensureNotationDeclCapacity(chunk);
1930        return fNotationCount++;
1931    }
1932 
1933    protected void setNotationDecl(int notationDeclIndex, XMLNotationDecl notationDecl) {
1934        int chunk = notationDeclIndex >> CHUNK_SHIFT;
1935        int index = notationDeclIndex & CHUNK_MASK;
1936 
1937        fNotationName[chunk][index] = notationDecl.name;
1938        fNotationPublicId[chunk][index] = notationDecl.publicId;
1939        fNotationSystemId[chunk][index] = notationDecl.systemId;
1940        fNotationBaseSystemId[chunk][index] = notationDecl.baseSystemId;
1941 
1942        fNotationIndexMap.put(notationDecl.name, notationDeclIndex);
1943    }
1944 
1945     /**
1946      * Create an XMLContentSpec for a single non-leaf
1947      *
1948      * @param nodeType the type of XMLContentSpec to create - from XMLContentSpec.CONTENTSPECNODE_*
1949      * @param nodeValue handle to an XMLContentSpec
1950      * @return handle to the newly create XMLContentSpec
1951      */
1952     protected int addContentSpecNode(short nodeType, String nodeValue) {
1953 
1954         // create content spec node
1955         int contentSpecIndex = createContentSpec();
1956 
1957         // set content spec node values
1958         fContentSpec.setValues(nodeType, nodeValue, null);
1959         setContentSpec(contentSpecIndex, fContentSpec);
1960 
1961         // return index
1962         return contentSpecIndex;
1963 
1964     } // addContentSpecNode(short,String):int
1965 
1966     /**
1967      * create an XMLContentSpec for a leaf
1968      *
1969      * @param   elementName  the name (Element) for the node
1970      * @return handle to the newly create XMLContentSpec
1971      */
1972     protected int addUniqueLeafNode(String elementName) {
1973 
1974         // create content spec node
1975         int contentSpecIndex = createContentSpec();
1976 
1977         // set content spec node values
1978         fContentSpec.setValues( XMLContentSpec.CONTENTSPECNODE_LEAF,
1979                                 elementName, null);
1980         setContentSpec(contentSpecIndex, fContentSpec);
1981 
1982         // return index
1983         return contentSpecIndex;
1984 
1985     } // addUniqueLeafNode(String):int
1986 
1987     /**
1988      * Create an XMLContentSpec for a two child leaf
1989      *
1990      * @param nodeType the type of XMLContentSpec to create - from XMLContentSpec.CONTENTSPECNODE_*
1991      * @param leftNodeIndex handle to an XMLContentSpec
1992      * @param rightNodeIndex handle to an XMLContentSpec
1993      * @return handle to the newly create XMLContentSpec
1994      */
1995     protected int addContentSpecNode(short nodeType,
1996                                      int leftNodeIndex, int rightNodeIndex) {
1997 
1998         // create content spec node
1999         int contentSpecIndex = createContentSpec();
2000 
2001         // set content spec node values
2002         int[] leftIntArray  = new int[1];
2003         int[] rightIntArray = new int[1];
2004 
2005         leftIntArray[0]      = leftNodeIndex;
2006         rightIntArray[0]    = rightNodeIndex;
2007         fContentSpec.setValues(nodeType, leftIntArray, rightIntArray);
2008         setContentSpec(contentSpecIndex, fContentSpec);
2009 
2010         // return index
2011         return contentSpecIndex;
2012 
2013     } // addContentSpecNode(short,int,int):int
2014 
2015     /** Initialize content model stack. */
2016     protected void initializeContentModelStack() {
2017 
2018         if (fOpStack == null) {
2019             fOpStack = new short[8];
2020             fNodeIndexStack = new int[8];
2021             fPrevNodeIndexStack = new int[8];
2022         } else if (fDepth == fOpStack.length) {
2023             short[] newStack = new short[fDepth * 2];
2024             System.arraycopy(fOpStack, 0, newStack, 0, fDepth);
2025             fOpStack = newStack;
2026             int[]   newIntStack = new int[fDepth * 2];
2027             System.arraycopy(fNodeIndexStack, 0, newIntStack, 0, fDepth);
2028             fNodeIndexStack = newIntStack;
2029             newIntStack = new int[fDepth * 2];
2030             System.arraycopy(fPrevNodeIndexStack, 0, newIntStack, 0, fDepth);
2031             fPrevNodeIndexStack = newIntStack;
2032         }
2033         fOpStack[fDepth] = -1;
2034         fNodeIndexStack[fDepth] = -1;
2035         fPrevNodeIndexStack[fDepth] = -1;
2036 
2037     } // initializeContentModelStack()
2038 
2039     boolean isImmutable() {
2040         return fIsImmutable;
2041     }
2042 
2043     //
2044     // Private methods
2045     //
2046 
2047     private void appendContentSpec(XMLContentSpec contentSpec,
2048                                    StringBuffer str, boolean parens,
2049                                    int parentContentSpecType ) {
2050 
2051         int thisContentSpec = contentSpec.type & 0x0f;
2052         switch (thisContentSpec) {
2053             case XMLContentSpec.CONTENTSPECNODE_LEAF: {
2054                 if (contentSpec.value == null && contentSpec.otherValue == null) {
2055                     str.append("#PCDATA");
2056                 }
2057                 else if (contentSpec.value == null && contentSpec.otherValue != null) {
2058                     str.append("##any:uri=").append(contentSpec.otherValue);
2059                 }
2060                 else if (contentSpec.value == null) {
2061                     str.append("##any");
2062                 }
2063                 else {
2064                     str.append(contentSpec.value);
2065                 }
2066                 break;
2067             }
2068             case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE: {
2069                 if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE  ||
2070                     parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE ||
2071                     parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
2072                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
2073                     str.append('(');
2074                     appendContentSpec(contentSpec, str, true, thisContentSpec );
2075                     str.append(')');
2076                 }
2077                 else {
2078                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
2079                     appendContentSpec( contentSpec, str, true, thisContentSpec );
2080                 }
2081                 str.append('?');
2082                 break;
2083             }
2084             case XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE: {
2085                 if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE ||
2086                     parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE ||
2087                     parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
2088                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
2089                     str.append('(');
2090                     appendContentSpec(contentSpec, str, true, thisContentSpec);
2091                     str.append(')' );
2092                 }
2093                 else {
2094                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
2095                     appendContentSpec(contentSpec, str, true, thisContentSpec);
2096                 }
2097                 str.append('*');
2098                 break;
2099             }
2100             case XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE: {
2101                 if (parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE   ||
2102                     parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE  ||
2103                     parentContentSpecType == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ) {
2104 
2105                     str.append('(');
2106                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
2107                     appendContentSpec(contentSpec, str, true, thisContentSpec);
2108                     str.append(')' );
2109                 }
2110                 else {
2111                     getContentSpec(((int[])contentSpec.value)[0], contentSpec);
2112                     appendContentSpec(contentSpec, str, true, thisContentSpec);
2113                 }
2114                 str.append('+');
2115                 break;
2116             }
2117             case XMLContentSpec.CONTENTSPECNODE_CHOICE:
2118             case XMLContentSpec.CONTENTSPECNODE_SEQ: {
2119                 if (parens) {
2120                     str.append('(');
2121                 }
2122                 int type = contentSpec.type;
2123                 int otherValue = ((int[])contentSpec.otherValue)[0];
2124                 getContentSpec(((int[])contentSpec.value)[0], contentSpec);
2125                 appendContentSpec(contentSpec, str, contentSpec.type != type, thisContentSpec);
2126                 if (type == XMLContentSpec.CONTENTSPECNODE_CHOICE) {
2127                     str.append('|');
2128                 }
2129                 else {
2130                     str.append(',');
2131                 }
2132                 getContentSpec(otherValue, contentSpec);
2133                 appendContentSpec(contentSpec, str, true, thisContentSpec);
2134                 if (parens) {
2135                     str.append(')');
2136                 }
2137                 break;
2138             }
2139             case XMLContentSpec.CONTENTSPECNODE_ANY: {
2140                 str.append("##any");
2141                 if (contentSpec.otherValue != null) {
2142                     str.append(":uri=");
2143                     str.append(contentSpec.otherValue);
2144                 }
2145                 break;
2146             }
2147             case XMLContentSpec.CONTENTSPECNODE_ANY_OTHER: {
2148                 str.append("##other:uri=");
2149                 str.append(contentSpec.otherValue);
2150                 break;
2151             }
2152             case XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL: {
2153                 str.append("##local");
2154                 break;
2155             }
2156             default: {
2157                 str.append("???");
2158                 break;
2159             }
2160 
2161         } // switch type
2162 
2163     } // appendContentSpec(XMLContentSpec.Provider,StringPool,XMLContentSpec,StringBuffer,boolean)
2164 
2165     // debugging
2166 
2167     private void printAttribute(int attributeDeclIndex) {
2168 
2169         XMLAttributeDecl attributeDecl = new XMLAttributeDecl();
2170         if (getAttributeDecl(attributeDeclIndex, attributeDecl)) {
2171             System.out.print(" { ");
2172             System.out.print(attributeDecl.name.localpart);
2173             System.out.print(" }");
2174         }
2175 
2176     } // printAttribute(int)
2177 
2178     // content models
2179 
2180     /**
2181      * When the element has a 'CHILDREN' model, this method is called to
2182      * create the content model object. It looks for some special case simple
2183      * models and creates SimpleContentModel objects for those. For the rest
2184      * it creates the standard DFA style model.
2185      */
2186     private synchronized ContentModelValidator createChildModel(int contentSpecIndex) {
2187 
2188         //
2189         //  Get the content spec node for the element we are working on.
2190         //  This will tell us what kind of node it is, which tells us what
2191         //  kind of model we will try to create.
2192         //
2193         XMLContentSpec contentSpec = new XMLContentSpec();
2194         getContentSpec(contentSpecIndex, contentSpec);
2195 
2196         if ((contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY ||
2197             (contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER ||
2198             (contentSpec.type & 0x0f ) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) {
2199             // let fall through to build a DFAContentModel
2200         }
2201 
2202         else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
2203             //
2204             //  Check that the left value is not -1, since any content model
2205             //  with PCDATA should be MIXED, so we should not have gotten here.
2206             //
2207             if (contentSpec.value == null && contentSpec.otherValue == null)
2208                 throw new RuntimeException("ImplementationMessages.VAL_NPCD");
2209 
2210             //
2211             //  Its a single leaf, so its an 'a' type of content model, i.e.
2212             //  just one instance of one element. That one is definitely a
2213             //  simple content model.
2214             //
2215 
2216             fQName.setValues(null, (String)contentSpec.value,
2217                               (String)contentSpec.value, (String)contentSpec.otherValue);
2218             return new SimpleContentModel(contentSpec.type, fQName, null);
2219         } else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE)
2220                     ||  (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) {
2221             //
2222             //  Lets see if both of the children are leafs. If so, then it
2223             //  it has to be a simple content model
2224             //
2225             XMLContentSpec contentSpecLeft  = new XMLContentSpec();
2226             XMLContentSpec contentSpecRight = new XMLContentSpec();
2227 
2228             getContentSpec( ((int[])contentSpec.value)[0], contentSpecLeft);
2229             getContentSpec( ((int[])contentSpec.otherValue)[0], contentSpecRight);
2230 
2231             if ((contentSpecLeft.type == XMLContentSpec.CONTENTSPECNODE_LEAF)
2232                  &&  (contentSpecRight.type == XMLContentSpec.CONTENTSPECNODE_LEAF)) {
2233                 //
2234                 //  Its a simple choice or sequence, so we can do a simple
2235                 //  content model for it.
2236                 //
2237                 fQName.setValues(null, (String)contentSpecLeft.value,
2238                                   (String)contentSpecLeft.value, (String)contentSpecLeft.otherValue);
2239                 fQName2.setValues(null, (String)contentSpecRight.value,
2240                                   (String)contentSpecRight.value, (String)contentSpecRight.otherValue);
2241                 return new SimpleContentModel(contentSpec.type, fQName, fQName2);
2242             }
2243         } else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE)
2244                     ||  (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE)
2245                     ||  (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE)) {
2246             //
2247             //  Its a repetition, so see if its one child is a leaf. If so
2248             //  its a repetition of a single element, so we can do a simple
2249             //  content model for that.
2250             //
2251             XMLContentSpec contentSpecLeft = new XMLContentSpec();
2252             getContentSpec(((int[])contentSpec.value)[0], contentSpecLeft);
2253 
2254             if (contentSpecLeft.type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
2255                 //
2256                 //  It is, so we can create a simple content model here that
2257                 //  will check for this repetition. We pass -1 for the unused
2258                 //  right node.
2259                 //
2260                 fQName.setValues(null, (String)contentSpecLeft.value,
2261                                   (String)contentSpecLeft.value, (String)contentSpecLeft.otherValue);
2262                 return new SimpleContentModel(contentSpec.type, fQName, null);
2263             }
2264         } else {
2265             throw new RuntimeException("ImplementationMessages.VAL_CST");
2266         }
2267 
2268         //
2269         //  Its not a simple content model, so here we have to create a DFA
2270         //  for this element. So we create a DFAContentModel object. He
2271         //  encapsulates all of the work to create the DFA.
2272         //
2273 
2274         fLeafCount = 0;
2275         //int leafCount = countLeaves(contentSpecIndex);
2276         fLeafCount = 0;
2277         CMNode cmn    = buildSyntaxTree(contentSpecIndex, contentSpec);
2278 
2279         // REVISIT: has to be fLeafCount because we convert x+ to x,x*, one more leaf
2280         return new DFAContentModel(  cmn, fLeafCount, false);
2281 
2282     } // createChildModel(int):ContentModelValidator
2283 
2284     private final CMNode buildSyntaxTree(int startNode,
2285                                          XMLContentSpec contentSpec) {
2286 
2287         // We will build a node at this level for the new tree
2288         CMNode nodeRet = null;
2289         getContentSpec(startNode, contentSpec);
2290         if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY) {
2291             //nodeRet = new CMAny(contentSpec.type, -1, fLeafCount++);
2292             nodeRet = new CMAny(contentSpec.type, (String)contentSpec.otherValue, fLeafCount++);
2293         }
2294         else if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) {
2295             nodeRet = new CMAny(contentSpec.type, (String)contentSpec.otherValue, fLeafCount++);
2296         }
2297         else if ((contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL) {
2298             nodeRet = new CMAny(contentSpec.type, null, fLeafCount++);
2299         }
2300         //
2301         //  If this node is a leaf, then its an easy one. We just add it
2302         //  to the tree.
2303         //
2304         else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) {
2305             //
2306             //  Create a new leaf node, and pass it the current leaf count,
2307             //  which is its DFA state position. Bump the leaf count after
2308             //  storing it. This makes the positions zero based since we
2309             //  store first and then increment.
2310             //
2311             fQName.setValues(null, (String)contentSpec.value,
2312                               (String)contentSpec.value, (String)contentSpec.otherValue);
2313             nodeRet = new CMLeaf(fQName, fLeafCount++);
2314         }
2315         else {
2316             //
2317             //  Its not a leaf, so we have to recurse its left and maybe right
2318             //  nodes. Save both values before we recurse and trash the node.
2319             final int leftNode = ((int[])contentSpec.value)[0];
2320             final int rightNode = ((int[])contentSpec.otherValue)[0];
2321 
2322             if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE)
2323                 ||  (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) {
2324                 //
2325                 //  Recurse on both children, and return a binary op node
2326                 //  with the two created sub nodes as its children. The node
2327                 //  type is the same type as the source.
2328                 //
2329 
2330                 nodeRet = new CMBinOp( contentSpec.type, buildSyntaxTree(leftNode, contentSpec)
2331                                        , buildSyntaxTree(rightNode, contentSpec));
2332             }
2333             else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE) {
2334                 nodeRet = new CMUniOp( contentSpec.type, buildSyntaxTree(leftNode, contentSpec));
2335             }
2336             else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE
2337                   || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE
2338                   || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) {
2339                 nodeRet = new CMUniOp(contentSpec.type, buildSyntaxTree(leftNode, contentSpec));
2340             }
2341             else {
2342                 throw new RuntimeException("ImplementationMessages.VAL_CST");
2343             }
2344         }
2345         // And return our new node for this level
2346         return nodeRet;
2347     }
2348 
2349     /**
2350      * Build a vector of valid QNames from Content Spec
2351      * table.
2352      *
2353      * @param contentSpecIndex
2354      *               Content Spec index
2355      * @param vectorQName
2356      *               Array of QName
2357      * @exception RuntimeException
2358      */
2359     private void contentSpecTree(int contentSpecIndex,
2360                                  XMLContentSpec contentSpec,
2361                                  ChildrenList children) {
2362 
2363         // Handle any and leaf nodes
2364         getContentSpec( contentSpecIndex, contentSpec);
2365         if ( contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF ||
2366             (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY ||
2367             (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_LOCAL ||
2368             (contentSpec.type & 0x0f) == XMLContentSpec.CONTENTSPECNODE_ANY_OTHER) {
2369 
2370             // resize arrays, if needed
2371             if (children.length == children.qname.length) {
2372                 QName[] newQName = new QName[children.length * 2];
2373                 System.arraycopy(children.qname, 0, newQName, 0, children.length);
2374                 children.qname = newQName;
2375                 int[] newType = new int[children.length * 2];
2376                 System.arraycopy(children.type, 0, newType, 0, children.length);
2377                 children.type = newType;
2378             }
2379 
2380             // save values and return length
2381             children.qname[children.length] = new QName(null, (String)contentSpec.value,
2382                                                      (String) contentSpec.value,
2383                                                      (String) contentSpec.otherValue);
2384             children.type[children.length] = contentSpec.type;
2385             children.length++;
2386             return;
2387         }
2388 
2389         //
2390         //  Its not a leaf, so we have to recurse its left and maybe right
2391         //  nodes. Save both values before we recurse and trash the node.
2392         //
2393         final int leftNode = contentSpec.value != null
2394                            ? ((int[])(contentSpec.value))[0] : -1;
2395         int rightNode = -1 ;
2396         if (contentSpec.otherValue != null )
2397             rightNode = ((int[])(contentSpec.otherValue))[0];
2398         else
2399             return;
2400 
2401         if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE ||
2402             contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ) {
2403             contentSpecTree(leftNode, contentSpec, children);
2404             contentSpecTree(rightNode, contentSpec, children);
2405             return;
2406         }
2407 
2408         if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE ||
2409             contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE ||
2410             contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) {
2411             contentSpecTree(leftNode, contentSpec, children);
2412             return;
2413         }
2414 
2415         // error
2416         throw new RuntimeException("Invalid content spec type seen in contentSpecTree() method of AbstractDTDGrammar class : "+contentSpec.type);
2417 
2418     } // contentSpecTree(int,XMLContentSpec,ChildrenList)
2419 
2420     // ensure capacity
2421 
2422     private void ensureElementDeclCapacity(int chunk) {
2423         if (chunk >= fElementDeclName.length) {
2424             fElementDeclIsExternal = resize(fElementDeclIsExternal,
2425                                      fElementDeclIsExternal.length * 2);
2426 
2427             fElementDeclName = resize(fElementDeclName, fElementDeclName.length * 2);
2428             fElementDeclType = resize(fElementDeclType, fElementDeclType.length * 2);
2429             fElementDeclContentModelValidator = resize(fElementDeclContentModelValidator, fElementDeclContentModelValidator.length * 2);
2430             fElementDeclContentSpecIndex = resize(fElementDeclContentSpecIndex,fElementDeclContentSpecIndex.length * 2);
2431             fElementDeclFirstAttributeDeclIndex = resize(fElementDeclFirstAttributeDeclIndex, fElementDeclFirstAttributeDeclIndex.length * 2);
2432             fElementDeclLastAttributeDeclIndex = resize(fElementDeclLastAttributeDeclIndex, fElementDeclLastAttributeDeclIndex.length * 2);
2433         }
2434         else if (fElementDeclName[chunk] != null) {
2435             return;
2436         }
2437 
2438         fElementDeclIsExternal[chunk] = new int[CHUNK_SIZE];
2439         fElementDeclName[chunk] = new QName[CHUNK_SIZE];
2440         fElementDeclType[chunk] = new short[CHUNK_SIZE];
2441         fElementDeclContentModelValidator[chunk] = new ContentModelValidator[CHUNK_SIZE];
2442         fElementDeclContentSpecIndex[chunk] = new int[CHUNK_SIZE];
2443         fElementDeclFirstAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
2444         fElementDeclLastAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
2445         return;
2446     }
2447 
2448     private void ensureAttributeDeclCapacity(int chunk) {
2449 
2450         if (chunk >= fAttributeDeclName.length) {
2451             fAttributeDeclIsExternal = resize(fAttributeDeclIsExternal,
2452                                        fAttributeDeclIsExternal.length * 2);
2453             fAttributeDeclName = resize(fAttributeDeclName, fAttributeDeclName.length * 2);
2454             fAttributeDeclType = resize(fAttributeDeclType, fAttributeDeclType.length * 2);
2455             fAttributeDeclEnumeration = resize(fAttributeDeclEnumeration, fAttributeDeclEnumeration.length * 2);
2456             fAttributeDeclDefaultType = resize(fAttributeDeclDefaultType, fAttributeDeclDefaultType.length * 2);
2457             fAttributeDeclDatatypeValidator = resize(fAttributeDeclDatatypeValidator, fAttributeDeclDatatypeValidator.length * 2);
2458             fAttributeDeclDefaultValue = resize(fAttributeDeclDefaultValue, fAttributeDeclDefaultValue.length * 2);
2459             fAttributeDeclNonNormalizedDefaultValue = resize(fAttributeDeclNonNormalizedDefaultValue, fAttributeDeclNonNormalizedDefaultValue.length * 2);
2460             fAttributeDeclNextAttributeDeclIndex = resize(fAttributeDeclNextAttributeDeclIndex, fAttributeDeclNextAttributeDeclIndex.length * 2);
2461         }
2462         else if (fAttributeDeclName[chunk] != null) {
2463             return;
2464         }
2465 
2466         fAttributeDeclIsExternal[chunk] = new int[CHUNK_SIZE];
2467         fAttributeDeclName[chunk] = new QName[CHUNK_SIZE];
2468         fAttributeDeclType[chunk] = new short[CHUNK_SIZE];
2469         fAttributeDeclEnumeration[chunk] = new String[CHUNK_SIZE][];
2470         fAttributeDeclDefaultType[chunk] = new short[CHUNK_SIZE];
2471         fAttributeDeclDatatypeValidator[chunk] = new DatatypeValidator[CHUNK_SIZE];
2472         fAttributeDeclDefaultValue[chunk] = new String[CHUNK_SIZE];
2473         fAttributeDeclNonNormalizedDefaultValue[chunk] = new String[CHUNK_SIZE];
2474         fAttributeDeclNextAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
2475         return;
2476     }
2477 
2478     private void ensureEntityDeclCapacity(int chunk) {
2479         if (chunk >= fEntityName.length) {
2480             fEntityName = resize(fEntityName, fEntityName.length * 2);
2481             fEntityValue = resize(fEntityValue, fEntityValue.length * 2);
2482             fEntityPublicId = resize(fEntityPublicId, fEntityPublicId.length * 2);
2483             fEntitySystemId = resize(fEntitySystemId, fEntitySystemId.length * 2);
2484             fEntityBaseSystemId = resize(fEntityBaseSystemId, fEntityBaseSystemId.length * 2);
2485             fEntityNotation = resize(fEntityNotation, fEntityNotation.length * 2);
2486             fEntityIsPE = resize(fEntityIsPE, fEntityIsPE.length * 2);
2487             fEntityInExternal = resize(fEntityInExternal, fEntityInExternal.length * 2);
2488         }
2489         else if (fEntityName[chunk] != null) {
2490             return;
2491         }
2492 
2493         fEntityName[chunk] = new String[CHUNK_SIZE];
2494         fEntityValue[chunk] = new String[CHUNK_SIZE];
2495         fEntityPublicId[chunk] = new String[CHUNK_SIZE];
2496         fEntitySystemId[chunk] = new String[CHUNK_SIZE];
2497         fEntityBaseSystemId[chunk] = new String[CHUNK_SIZE];
2498         fEntityNotation[chunk] = new String[CHUNK_SIZE];
2499         fEntityIsPE[chunk] = new byte[CHUNK_SIZE];
2500         fEntityInExternal[chunk] = new byte[CHUNK_SIZE];
2501         return;
2502     }
2503 
2504     private void ensureNotationDeclCapacity(int chunk) {
2505         if (chunk >= fNotationName.length) {
2506             fNotationName = resize(fNotationName, fNotationName.length * 2);
2507             fNotationPublicId = resize(fNotationPublicId, fNotationPublicId.length * 2);
2508             fNotationSystemId = resize(fNotationSystemId, fNotationSystemId.length * 2);
2509             fNotationBaseSystemId = resize(fNotationBaseSystemId, fNotationBaseSystemId.length * 2);
2510         }
2511         else if (fNotationName[chunk] != null) {
2512             return;
2513         }
2514 
2515         fNotationName[chunk] = new String[CHUNK_SIZE];
2516         fNotationPublicId[chunk] = new String[CHUNK_SIZE];
2517         fNotationSystemId[chunk] = new String[CHUNK_SIZE];
2518         fNotationBaseSystemId[chunk] = new String[CHUNK_SIZE];
2519         return;
2520     }
2521 
2522     private void ensureContentSpecCapacity(int chunk) {
2523         if (chunk >= fContentSpecType.length) {
2524             fContentSpecType = resize(fContentSpecType, fContentSpecType.length * 2);
2525             fContentSpecValue = resize(fContentSpecValue, fContentSpecValue.length * 2);
2526             fContentSpecOtherValue = resize(fContentSpecOtherValue, fContentSpecOtherValue.length * 2);
2527         }
2528         else if (fContentSpecType[chunk] != null) {
2529             return;
2530         }
2531 
2532         fContentSpecType[chunk] = new short[CHUNK_SIZE];
2533         fContentSpecValue[chunk] = new Object[CHUNK_SIZE];
2534         fContentSpecOtherValue[chunk] = new Object[CHUNK_SIZE];
2535         return;
2536     }
2537 
2538     //
2539     // Private static methods
2540     //
2541 
2542     // resize chunks
2543 
2544     private static byte[][] resize(byte array[][], int newsize) {
2545         byte newarray[][] = new byte[newsize][];
2546         System.arraycopy(array, 0, newarray, 0, array.length);
2547         return newarray;
2548     }
2549 
2550     private static short[][] resize(short array[][], int newsize) {
2551         short newarray[][] = new short[newsize][];
2552         System.arraycopy(array, 0, newarray, 0, array.length);
2553         return newarray;
2554     }
2555 
2556     private static int[][] resize(int array[][], int newsize) {
2557         int newarray[][] = new int[newsize][];
2558         System.arraycopy(array, 0, newarray, 0, array.length);
2559         return newarray;
2560     }
2561 
2562     private static DatatypeValidator[][] resize(DatatypeValidator array[][], int newsize) {
2563         DatatypeValidator newarray[][] = new DatatypeValidator[newsize][];
2564         System.arraycopy(array, 0, newarray, 0, array.length);
2565         return newarray;
2566     }
2567 
2568     private static ContentModelValidator[][] resize(ContentModelValidator array[][], int newsize) {
2569         ContentModelValidator newarray[][] = new ContentModelValidator[newsize][];
2570         System.arraycopy(array, 0, newarray, 0, array.length);
2571         return newarray;
2572     }
2573 
2574     private static Object[][] resize(Object array[][], int newsize) {
2575         Object newarray[][] = new Object[newsize][];
2576         System.arraycopy(array, 0, newarray, 0, array.length);
2577         return newarray;
2578     }
2579 
2580     private static QName[][] resize(QName array[][], int newsize) {
2581         QName newarray[][] = new QName[newsize][];
2582         System.arraycopy(array, 0, newarray, 0, array.length);
2583         return newarray;
2584     }
2585 
2586     private static String[][] resize(String array[][], int newsize) {
2587         String newarray[][] = new String[newsize][];
2588         System.arraycopy(array, 0, newarray, 0, array.length);
2589         return newarray;
2590     }
2591 
2592     private static String[][][] resize(String array[][][], int newsize) {
2593         String newarray[][][] = new String[newsize] [][];
2594         System.arraycopy(array, 0, newarray, 0, array.length);
2595         return newarray;
2596     }
2597 
2598     //
2599     // Classes
2600     //
2601 
2602     /**
2603      * Children list for <code>contentSpecTree</code> method.
2604      *
2605      * @xerces.internal
2606      *
2607      * @author Eric Ye, IBM
2608      */
2609     private static class ChildrenList {
2610 
2611         //
2612         // Data
2613         //
2614 
2615         /** Length. */
2616         public int length = 0;
2617 
2618         // NOTE: The following set of data is mutually exclusive. It is
2619         //       written this way because Java doesn't have a native
2620         //       union data structure. -Ac
2621 
2622         /** Left and right children names. */
2623         public QName[] qname = new QName[2];
2624 
2625         /** Left and right children types. */
2626         public int[] type = new int[2];
2627 
2628         //
2629         // Constructors
2630         //
2631 
2632         public ChildrenList () {}
2633 
2634     } // class ChildrenList
2635 
2636     //
2637     // EntityState methods
2638     //
2639     public boolean isEntityDeclared (String name){
2640         return (getEntityDeclIndex(name)!=-1)?true:false;
2641     }
2642 
2643     public boolean isEntityUnparsed (String name){
2644         int entityIndex = getEntityDeclIndex(name);
2645         if (entityIndex >-1) {
2646             int chunk = entityIndex >> CHUNK_SHIFT;
2647             int index = entityIndex & CHUNK_MASK;
2648             //for unparsed entity notation!=null
2649             return (fEntityNotation[chunk][index]!=null)?true:false;
2650         }
2651         return false;
2652     }
2653 } // class DTDGrammar