View Javadoc
1   /*
2    * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3    */
4   
5   /*
6    * Copyright 2005 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package com.sun.xml.internal.stream.dtd.nonvalidating;
22  
23  import java.util.Hashtable;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import com.sun.org.apache.xerces.internal.util.SymbolTable;
28  import com.sun.org.apache.xerces.internal.xni.Augmentations;
29  import com.sun.org.apache.xerces.internal.xni.QName;
30  import com.sun.org.apache.xerces.internal.util.XMLSymbols;
31  import com.sun.org.apache.xerces.internal.xni.XMLLocator;
32  import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
33  import com.sun.org.apache.xerces.internal.xni.XMLString;
34  import com.sun.org.apache.xerces.internal.xni.XNIException;
35  import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelSource;
36  import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource;
37  
38  /**
39   * A DTD grammar. This class implements the XNI handler interfaces
40   * for DTD information so that it can build the approprate validation
41   * structures automatically from the callbacks.
42   *
43   * @author Eric Ye, IBM
44   * @author Jeffrey Rodriguez, IBM
45   * @author Andy Clark, IBM
46   * @author Neil Graham, IBM
47   *
48   */
49  public class DTDGrammar {
50  
51  
52      /** Top level scope (-1). */
53      public static final int TOP_LEVEL_SCOPE = -1;
54  
55      // private
56  
57      /** Chunk shift (8). */
58      private static final int CHUNK_SHIFT = 8; // 2^8 = 256
59  
60      /** Chunk size (1 << CHUNK_SHIFT). */
61      private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
62  
63      /** Chunk mask (CHUNK_SIZE - 1). */
64      private static final int CHUNK_MASK = CHUNK_SIZE - 1;
65  
66      /** Initial chunk count (1 << (10 - CHUNK_SHIFT)). */
67      private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k
68  
69      /** List flag (0x80). */
70      private static final short LIST_FLAG = 0x80;
71  
72      /** List mask (~LIST_FLAG). */
73      private static final short LIST_MASK = ~LIST_FLAG;
74  
75      // debugging
76  
77      /** Debug DTDGrammar. */
78      private static final boolean DEBUG = false;
79  
80      //
81      // Data
82      //
83  
84      protected XMLDTDSource fDTDSource = null;
85      protected XMLDTDContentModelSource fDTDContentModelSource = null;
86  
87      /** Current element index. */
88      protected int fCurrentElementIndex;
89  
90      /** Current attribute index. */
91      protected int fCurrentAttributeIndex;
92  
93      /** fReadingExternalDTD */
94      protected boolean fReadingExternalDTD = false;
95  
96      /** Symbol table. */
97      private SymbolTable fSymbolTable;
98      private ArrayList notationDecls = new ArrayList();
99  
100     // element declarations
101 
102     /** Number of element declarations. */
103     private int fElementDeclCount = 0;
104 
105     /** Element declaration name. */
106     private QName fElementDeclName[][] = new QName[INITIAL_CHUNK_COUNT][];
107 
108     /**
109      * Element declaration type.
110      * @see XMLElementDecl
111      */
112     private short fElementDeclType[][] = new short[INITIAL_CHUNK_COUNT][];
113 
114 
115     /** First attribute declaration of an element declaration. */
116     private int fElementDeclFirstAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
117 
118     /** Last attribute declaration of an element declaration. */
119     private int fElementDeclLastAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
120 
121     // attribute declarations
122 
123     /** Number of attribute declarations. */
124     private int fAttributeDeclCount = 0 ;
125 
126     /** Attribute declaration name. */
127     private QName fAttributeDeclName[][] = new QName[INITIAL_CHUNK_COUNT][];
128 
129     /**
130      * Attribute declaration type.
131      * @see XMLAttributeDecl
132      */
133     private short fAttributeDeclType[][] = new short[INITIAL_CHUNK_COUNT][];
134 
135     /** Attribute declaration enumeration values. */
136     private String[] fAttributeDeclEnumeration[][] = new String[INITIAL_CHUNK_COUNT][][];
137     private short fAttributeDeclDefaultType[][] = new short[INITIAL_CHUNK_COUNT][];
138     private String fAttributeDeclDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][];
139     private String fAttributeDeclNonNormalizedDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][];
140     private int fAttributeDeclNextAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
141 
142     /** Element index mapping table. */
143     private QNameHashtable fElementIndexMap = new QNameHashtable();
144 
145     /** Temporary qualified name. */
146     private QName fQName = new QName();
147 
148     /** Temporary Attribute decl. */
149     protected XMLAttributeDecl fAttributeDecl = new XMLAttributeDecl();
150 
151     /** Element declaration. */
152     private XMLElementDecl fElementDecl = new XMLElementDecl();
153 
154     /** Simple type. */
155     private XMLSimpleType fSimpleType = new XMLSimpleType();
156 
157 
158     /** table of XMLElementDecl   */
159     Hashtable   fElementDeclTab     = new Hashtable();
160 
161     /** Default constructor. */
162     public DTDGrammar(SymbolTable symbolTable) {
163         fSymbolTable = symbolTable;
164     }
165 
166     public int getAttributeDeclIndex(int elementDeclIndex, String attributeDeclName) {
167         if (elementDeclIndex == -1) {
168             return -1;
169         }
170         int attDefIndex = getFirstAttributeDeclIndex(elementDeclIndex);
171         while (attDefIndex != -1) {
172             getAttributeDecl(attDefIndex, fAttributeDecl);
173 
174             if (fAttributeDecl.name.rawname == attributeDeclName
175             || attributeDeclName.equals(fAttributeDecl.name.rawname) ) {
176                 return attDefIndex;
177             }
178             attDefIndex = getNextAttributeDeclIndex(attDefIndex);
179         }
180         return -1;
181     }
182 
183     /**
184      * The start of the DTD.
185      *
186      * @param locator  The document locator, or null if the document
187      *                 location cannot be reported during the parsing of
188      *                 the document DTD. However, it is <em>strongly</em>
189      *                 recommended that a locator be supplied that can
190      *                 at least report the base system identifier of the
191      *                 DTD.
192      *
193      * @param augs Additional information that may include infoset
194      *                      augmentations.
195      * @throws XNIException Thrown by handler to signal an error.
196      */
197     public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException {
198     } // startDTD(XMLLocator)
199 
200     // startExternalSubset(Augmentations)
201 
202     // endExternalSubset(Augmentations)
203 
204     /**
205      * An element declaration.
206      *
207      * @param name         The name of the element.
208      * @param contentModel The element content model.
209      * @param augs Additional information that may include infoset
210      *                      augmentations.
211      * @throws XNIException Thrown by handler to signal an error.
212      */
213     public void elementDecl(String name, String contentModel, Augmentations augs)
214     throws XNIException {
215 
216         XMLElementDecl tmpElementDecl = (XMLElementDecl) fElementDeclTab.get(name) ;
217         if ( tmpElementDecl != null ) {
218             if (tmpElementDecl.type == -1) {
219                 fCurrentElementIndex = getElementDeclIndex(name);
220             }
221             else {
222                 // duplicate element, ignored.
223                 return;
224             }
225         }
226         else {
227             fCurrentElementIndex = createElementDecl();//create element decl
228         }
229 
230         XMLElementDecl elementDecl       = new XMLElementDecl();
231         QName          elementName       = new QName(null, name, name, null);
232 
233         elementDecl.name.setValues(elementName);
234         elementDecl.scope= -1;
235         if (contentModel.equals("EMPTY")) {
236             elementDecl.type = XMLElementDecl.TYPE_EMPTY;
237         }
238         else if (contentModel.equals("ANY")) {
239             elementDecl.type = XMLElementDecl.TYPE_ANY;
240         }
241         else if (contentModel.startsWith("(") ) {
242             if (contentModel.indexOf("#PCDATA") > 0 ) {
243                 elementDecl.type = XMLElementDecl.TYPE_MIXED;
244             }
245             else {
246                 elementDecl.type = XMLElementDecl.TYPE_CHILDREN;
247             }
248         }
249 
250 
251         //add(or set) this elementDecl to the local cache
252         this.fElementDeclTab.put(name, elementDecl );
253 
254         fElementDecl = elementDecl;
255 
256 
257         if ( DEBUG ) {
258             System.out.println(  "name = " + fElementDecl.name.localpart );
259             System.out.println(  "Type = " + fElementDecl.type );
260         }
261 
262         setElementDecl(fCurrentElementIndex, fElementDecl );//set internal structure
263 
264         int chunk = fCurrentElementIndex >> CHUNK_SHIFT;
265         ensureElementDeclCapacity(chunk);
266     }
267 
268     /**
269      * An attribute declaration.
270      *
271      * @param elementName   The name of the element that this attribute
272      *                      is associated with.
273      * @param attributeName The name of the attribute.
274      * @param type          The attribute type. This value will be one of
275      *                      the following: "CDATA", "ENTITY", "ENTITIES",
276      *                      "ENUMERATION", "ID", "IDREF", "IDREFS",
277      *                      "NMTOKEN", "NMTOKENS", or "NOTATION".
278      * @param enumeration   If the type has the value "ENUMERATION", this
279      *                      array holds the allowed attribute values;
280      *                      otherwise, this array is null.
281      * @param defaultType   The attribute default type. This value will be
282      *                      one of the following: "#FIXED", "#IMPLIED",
283      *                      "#REQUIRED", or null.
284      * @param defaultValue  The attribute default value, or null if no
285      *                      default value is specified.
286      * @param nonNormalizedDefaultValue  The attribute default value with no normalization
287      *                      performed, or null if no default value is specified.
288      *
289      * @param augs Additional information that may include infoset
290      *                      augmentations.
291      * @throws XNIException Thrown by handler to signal an error.
292      */
293     public void attributeDecl(String elementName, String attributeName,
294     String type, String[] enumeration,
295     String defaultType, XMLString defaultValue,
296     XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {
297 
298         if (type != XMLSymbols.fCDATASymbol && defaultValue != null) {
299             normalizeDefaultAttrValue(defaultValue);
300         }
301 
302         if ( this.fElementDeclTab.containsKey( (String) elementName) ) {
303             //if ElementDecl has already being created in the Grammar then remove from table,
304             //this.fElementDeclTab.remove( (String) elementName );
305         }
306         // then it is forward reference to a element decl, create the elementDecl first.
307         else {
308             fCurrentElementIndex = createElementDecl();//create element decl
309 
310             XMLElementDecl elementDecl       = new XMLElementDecl();
311             elementDecl.name.setValues(null, elementName, elementName, null);
312 
313             elementDecl.scope= -1;
314 
315             //add(or set) this elementDecl to the local cache
316             this.fElementDeclTab.put(elementName, elementDecl );
317 
318             //set internal structure
319             setElementDecl(fCurrentElementIndex, elementDecl );
320         }
321 
322         //Get Grammar index to grammar array
323         int elementIndex       = getElementDeclIndex(elementName);
324 
325         //return, when more than one definition is provided for the same attribute of given element type
326         //only the first declaration is binding and later declarations are ignored
327         if (getAttributeDeclIndex(elementIndex, attributeName) != -1) {
328             return;
329         }
330 
331         fCurrentAttributeIndex = createAttributeDecl();// Create current Attribute Decl
332 
333         fSimpleType.clear();
334         if ( defaultType != null ) {
335             if ( defaultType.equals( "#FIXED") ) {
336                 fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_FIXED;
337             } else if ( defaultType.equals( "#IMPLIED") ) {
338                 fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_IMPLIED;
339             } else if ( defaultType.equals( "#REQUIRED") ) {
340                 fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_REQUIRED;
341             }
342         }
343         if ( DEBUG ) {
344             System.out.println("defaultvalue = " + defaultValue.toString() );
345         }
346         fSimpleType.defaultValue      = defaultValue!=null ?  defaultValue.toString() : null;
347         fSimpleType.nonNormalizedDefaultValue      = nonNormalizedDefaultValue!=null ?  nonNormalizedDefaultValue.toString() : null;
348         fSimpleType.enumeration       = enumeration;
349 
350         if (type.equals("CDATA")) {
351             fSimpleType.type = XMLSimpleType.TYPE_CDATA;
352         }
353         else if ( type.equals("ID") ) {
354             fSimpleType.type = XMLSimpleType.TYPE_ID;
355         }
356         else if ( type.startsWith("IDREF") ) {
357             fSimpleType.type = XMLSimpleType.TYPE_IDREF;
358             if (type.indexOf("S") > 0) {
359                 fSimpleType.list = true;
360             }
361         }
362         else if (type.equals("ENTITIES")) {
363             fSimpleType.type = XMLSimpleType.TYPE_ENTITY;
364             fSimpleType.list = true;
365         }
366         else if (type.equals("ENTITY")) {
367             fSimpleType.type = XMLSimpleType.TYPE_ENTITY;
368         }
369         else if (type.equals("NMTOKENS")) {
370             fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN;
371             fSimpleType.list = true;
372         }
373         else if (type.equals("NMTOKEN")) {
374             fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN;
375         }
376         else if (type.startsWith("NOTATION") ) {
377             fSimpleType.type = XMLSimpleType.TYPE_NOTATION;
378         }
379         else if (type.startsWith("ENUMERATION") ) {
380             fSimpleType.type = XMLSimpleType.TYPE_ENUMERATION;
381         }
382         else {
383             // REVISIT: Report error message. -Ac
384             System.err.println("!!! unknown attribute type "+type);
385         }
386         // REVISIT: The datatype should be stored with the attribute value
387         //          and not special-cased in the XMLValidator. -Ac
388         //fSimpleType.datatypeValidator = fDatatypeValidatorFactory.createDatatypeValidator(type, null, facets, fSimpleType.list);
389 
390         fQName.setValues(null, attributeName, attributeName, null);
391         fAttributeDecl.setValues( fQName, fSimpleType, false );
392 
393         setAttributeDecl(elementIndex, fCurrentAttributeIndex, fAttributeDecl);
394 
395         int chunk = fCurrentAttributeIndex >> CHUNK_SHIFT;
396         ensureAttributeDeclCapacity(chunk);
397     } // attributeDecl(String,String,String,String[],String,XMLString,XMLString, Augmentations)
398 
399     /** Returns the symbol table. */
400     public SymbolTable getSymbolTable() {
401         return fSymbolTable;
402     } // getSymbolTable():SymbolTable
403 
404     /**
405      * Returns the index of the first element declaration. This index
406      * is then used to query more information about the element declaration.
407      *
408      * @see #getNextElementDeclIndex
409      * @see #getElementDecl
410      */
411     public int getFirstElementDeclIndex() {
412         return fElementDeclCount >= 0 ? 0 : -1;
413     } // getFirstElementDeclIndex():int
414 
415     /**
416      * Returns the next index of the element declaration following the
417      * specified element declaration.
418      *
419      * @param elementDeclIndex The element declaration index.
420      */
421     public int getNextElementDeclIndex(int elementDeclIndex) {
422         return elementDeclIndex < fElementDeclCount - 1
423         ? elementDeclIndex + 1 : -1;
424     } // getNextElementDeclIndex(int):int
425 
426     /**
427      * getElementDeclIndex
428      *
429      * @param elementDeclName
430      *
431      * @return index of the elementDeclName in scope
432      */
433     public int getElementDeclIndex(String elementDeclName) {
434         int mapping = fElementIndexMap.get(elementDeclName);
435         //System.out.println("getElementDeclIndex("+elementDeclName+") -> "+mapping);
436         return mapping;
437     } // getElementDeclIndex(String):int
438 
439     /** Returns the element decl index.
440      * @param elementDeclQName qualilfied name of the element
441      */
442     public int getElementDeclIndex(QName elementDeclQName) {
443         return getElementDeclIndex(elementDeclQName.rawname);
444     } // getElementDeclIndex(QName):int
445 
446     /** make separate function for getting contentSpecType of element.
447      * we can avoid setting of the element values.
448      */
449 
450     public short getContentSpecType(int elementIndex){
451         if (elementIndex < 0 || elementIndex >= fElementDeclCount) {
452             return -1 ;
453         }
454 
455         int chunk = elementIndex >> CHUNK_SHIFT;
456         int index = elementIndex &  CHUNK_MASK;
457 
458         if(fElementDeclType[chunk][index] == -1){
459             return -1 ;
460         }
461         else{
462             return (short) (fElementDeclType[chunk][index] & LIST_MASK);
463         }
464     }
465 
466     /**
467      * getElementDecl
468      *
469      * @param elementDeclIndex
470      * @param elementDecl The values of this structure are set by this call.
471      *
472      * @return True if find the element, False otherwise.
473      */
474     public boolean getElementDecl(int elementDeclIndex,
475     XMLElementDecl elementDecl) {
476 
477         if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
478             return false;
479         }
480 
481         int chunk = elementDeclIndex >> CHUNK_SHIFT;
482         int index = elementDeclIndex &  CHUNK_MASK;
483 
484         elementDecl.name.setValues(fElementDeclName[chunk][index]);
485 
486         if (fElementDeclType[chunk][index] == -1) {
487             elementDecl.type                    = -1;
488             elementDecl.simpleType.list = false;
489         } else {
490             elementDecl.type            = (short) (fElementDeclType[chunk][index] & LIST_MASK);
491             elementDecl.simpleType.list = (fElementDeclType[chunk][index] & LIST_FLAG) != 0;
492         }
493 
494         elementDecl.simpleType.defaultType       = -1;
495         elementDecl.simpleType.defaultValue      = null;
496         return true;
497 
498     }
499 
500     // REVISIT: Make this getAttributeDeclCount/getAttributeDeclAt. -Ac
501 
502     /**
503      * getFirstAttributeDeclIndex
504      *
505      * @param elementDeclIndex
506      *
507      * @return index of the first attribute for element declaration elementDeclIndex
508      */
509     public int getFirstAttributeDeclIndex(int elementDeclIndex) {
510         int chunk = elementDeclIndex >> CHUNK_SHIFT;
511         int index = elementDeclIndex &  CHUNK_MASK;
512 
513         return  fElementDeclFirstAttributeDeclIndex[chunk][index];
514     } // getFirstAttributeDeclIndex
515 
516     /**
517      * getNextAttributeDeclIndex
518      *
519      * @param attributeDeclIndex
520      *
521      * @return index of the next attribute of the attribute at attributeDeclIndex
522      */
523     public int getNextAttributeDeclIndex(int attributeDeclIndex) {
524         int chunk = attributeDeclIndex >> CHUNK_SHIFT;
525         int index = attributeDeclIndex &  CHUNK_MASK;
526 
527         return fAttributeDeclNextAttributeDeclIndex[chunk][index];
528     }
529 
530     /**
531      * getAttributeDecl
532      *
533      * @param attributeDeclIndex
534      * @param attributeDecl The values of this structure are set by this call.
535      *
536      * @return true if getAttributeDecl was able to fill in the value of attributeDecl
537      */
538     public boolean getAttributeDecl(int attributeDeclIndex, XMLAttributeDecl attributeDecl) {
539         if (attributeDeclIndex < 0 || attributeDeclIndex >= fAttributeDeclCount) {
540             return false;
541         }
542         int chunk = attributeDeclIndex >> CHUNK_SHIFT;
543         int index = attributeDeclIndex & CHUNK_MASK;
544 
545         attributeDecl.name.setValues(fAttributeDeclName[chunk][index]);
546 
547         short attributeType;
548         boolean isList;
549 
550         if (fAttributeDeclType[chunk][index] == -1) {
551 
552             attributeType = -1;
553             isList = false;
554         } else {
555             attributeType = (short) (fAttributeDeclType[chunk][index] & LIST_MASK);
556             isList = (fAttributeDeclType[chunk][index] & LIST_FLAG) != 0;
557         }
558         attributeDecl.simpleType.setValues(attributeType,fAttributeDeclName[chunk][index].localpart,
559         fAttributeDeclEnumeration[chunk][index],
560         isList, fAttributeDeclDefaultType[chunk][index],
561         fAttributeDeclDefaultValue[chunk][index],
562         fAttributeDeclNonNormalizedDefaultValue[chunk][index]);
563         return true;
564 
565     } // getAttributeDecl
566 
567 
568     /**
569      * Returns whether the given attribute is of type CDATA or not
570      *
571      * @param elName The element name.
572      * @param atName The attribute name.
573      *
574      * @return true if the attribute is of type CDATA
575      */
576     public boolean isCDATAAttribute(QName elName, QName atName) {
577         int elDeclIdx = getElementDeclIndex(elName);
578         if (getAttributeDecl(elDeclIdx, fAttributeDecl)
579         && fAttributeDecl.simpleType.type != XMLSimpleType.TYPE_CDATA){
580             return false;
581         }
582         return true;
583     }
584 
585 
586 
587     public void printElements(  ) {
588         int elementDeclIndex = 0;
589         XMLElementDecl elementDecl = new XMLElementDecl();
590         while (getElementDecl(elementDeclIndex++, elementDecl)) {
591 
592             System.out.println("element decl: "+elementDecl.name+
593             ", "+ elementDecl.name.rawname  );
594 
595         }
596     }
597 
598     public void printAttributes(int elementDeclIndex) {
599         int attributeDeclIndex = getFirstAttributeDeclIndex(elementDeclIndex);
600         System.out.print(elementDeclIndex);
601         System.out.print(" [");
602         while (attributeDeclIndex != -1) {
603             System.out.print(' ');
604             System.out.print(attributeDeclIndex);
605             printAttribute(attributeDeclIndex);
606             attributeDeclIndex = getNextAttributeDeclIndex(attributeDeclIndex);
607             if (attributeDeclIndex != -1) {
608                 System.out.print(",");
609             }
610         }
611         System.out.println(" ]");
612     }
613 
614 
615     protected int createElementDecl() {
616         int chunk = fElementDeclCount >> CHUNK_SHIFT;
617         int index = fElementDeclCount & CHUNK_MASK;
618         ensureElementDeclCapacity(chunk);
619         fElementDeclName[chunk][index]                    = new QName();
620         fElementDeclType[chunk][index]                    = -1;
621         fElementDeclFirstAttributeDeclIndex[chunk][index] = -1;
622         fElementDeclLastAttributeDeclIndex[chunk][index]  = -1;
623         return fElementDeclCount++;
624     }
625 
626     protected void setElementDecl(int elementDeclIndex, XMLElementDecl elementDecl) {
627         if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
628             return;
629         }
630         int     chunk       = elementDeclIndex >> CHUNK_SHIFT;
631         int     index       = elementDeclIndex &  CHUNK_MASK;
632 
633         int     scope       = elementDecl.scope;
634 
635 
636         fElementDeclName[chunk][index].setValues(elementDecl.name);
637         fElementDeclType[chunk][index]                  = elementDecl.type;
638 
639 
640 
641         if (elementDecl.simpleType.list  == true ) {
642             fElementDeclType[chunk][index] |= LIST_FLAG;
643         }
644 
645         fElementIndexMap.put(elementDecl.name.rawname, elementDeclIndex);
646     }
647 
648 
649 
650 
651     protected void setFirstAttributeDeclIndex(int elementDeclIndex, int newFirstAttrIndex){
652 
653         if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) {
654             return;
655         }
656 
657         int chunk = elementDeclIndex >> CHUNK_SHIFT;
658         int index = elementDeclIndex &  CHUNK_MASK;
659 
660         fElementDeclFirstAttributeDeclIndex[chunk][index] = newFirstAttrIndex;
661     }
662 
663 
664     protected int createAttributeDecl() {
665         int chunk = fAttributeDeclCount >> CHUNK_SHIFT;
666         int index = fAttributeDeclCount & CHUNK_MASK;
667 
668         ensureAttributeDeclCapacity(chunk);
669         fAttributeDeclName[chunk][index]                    = new QName();
670         fAttributeDeclType[chunk][index]                    = -1;
671         fAttributeDeclEnumeration[chunk][index]             = null;
672         fAttributeDeclDefaultType[chunk][index]             = XMLSimpleType.DEFAULT_TYPE_IMPLIED;
673         fAttributeDeclDefaultValue[chunk][index]            = null;
674         fAttributeDeclNonNormalizedDefaultValue[chunk][index]            = null;
675         fAttributeDeclNextAttributeDeclIndex[chunk][index]  = -1;
676         return fAttributeDeclCount++;
677     }
678 
679 
680     protected void setAttributeDecl(int elementDeclIndex, int attributeDeclIndex,
681     XMLAttributeDecl attributeDecl) {
682         int attrChunk = attributeDeclIndex >> CHUNK_SHIFT;
683         int attrIndex = attributeDeclIndex &  CHUNK_MASK;
684         fAttributeDeclName[attrChunk][attrIndex].setValues(attributeDecl.name);
685         fAttributeDeclType[attrChunk][attrIndex]  =  attributeDecl.simpleType.type;
686 
687         if (attributeDecl.simpleType.list) {
688             fAttributeDeclType[attrChunk][attrIndex] |= LIST_FLAG;
689         }
690         fAttributeDeclEnumeration[attrChunk][attrIndex]  =  attributeDecl.simpleType.enumeration;
691         fAttributeDeclDefaultType[attrChunk][attrIndex]  =  attributeDecl.simpleType.defaultType;
692 
693         fAttributeDeclDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.defaultValue;
694         fAttributeDeclNonNormalizedDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.nonNormalizedDefaultValue;
695 
696         int elemChunk     = elementDeclIndex >> CHUNK_SHIFT;
697         int elemIndex     = elementDeclIndex &  CHUNK_MASK;
698         int index         = fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex];
699         while (index != -1) {
700             if (index == attributeDeclIndex) {
701                 break;
702             }
703             attrChunk = index >> CHUNK_SHIFT;
704             attrIndex = index & CHUNK_MASK;
705             index = fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex];
706         }
707         if (index == -1) {
708             if (fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] == -1) {
709                 fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex;
710             } else {
711                 index = fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex];
712                 attrChunk = index >> CHUNK_SHIFT;
713                 attrIndex = index & CHUNK_MASK;
714                 fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex] = attributeDeclIndex;
715             }
716             fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex;
717         }
718     }
719 
720     public void notationDecl(String name, XMLResourceIdentifier identifier,
721     Augmentations augs) throws XNIException {
722 
723 
724         XMLNotationDecl  notationDecl = new XMLNotationDecl();
725         notationDecl.setValues(name,identifier.getPublicId(),identifier.getLiteralSystemId(),
726         identifier.getBaseSystemId());
727         notationDecls.add(notationDecl);
728     }
729 
730     public List getNotationDecls(){
731         return notationDecls;
732     }
733 
734     //
735     // Private methods
736     //
737     private void printAttribute(int attributeDeclIndex) {
738 
739         XMLAttributeDecl attributeDecl = new XMLAttributeDecl();
740         if (getAttributeDecl(attributeDeclIndex, attributeDecl)) {
741             System.out.print(" { ");
742             System.out.print(attributeDecl.name.localpart);
743             System.out.print(" }");
744         }
745 
746     } // printAttribute(int)
747 
748 
749 
750     private void ensureElementDeclCapacity(int chunk) {
751         if (chunk >= fElementDeclName.length) {
752 
753             fElementDeclName = resize(fElementDeclName, fElementDeclName.length * 2);
754             fElementDeclType = resize(fElementDeclType, fElementDeclType.length * 2);
755             fElementDeclFirstAttributeDeclIndex = resize(fElementDeclFirstAttributeDeclIndex, fElementDeclFirstAttributeDeclIndex.length * 2);
756             fElementDeclLastAttributeDeclIndex = resize(fElementDeclLastAttributeDeclIndex, fElementDeclLastAttributeDeclIndex.length * 2);
757         }
758         else if (fElementDeclName[chunk] != null) {
759             return;
760         }
761 
762         fElementDeclName[chunk] = new QName[CHUNK_SIZE];
763         fElementDeclType[chunk] = new short[CHUNK_SIZE];
764         fElementDeclFirstAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
765         fElementDeclLastAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
766         return;
767     }
768 
769     private void ensureAttributeDeclCapacity(int chunk) {
770 
771         if (chunk >= fAttributeDeclName.length) {
772             fAttributeDeclName = resize(fAttributeDeclName, fAttributeDeclName.length * 2);
773             fAttributeDeclType = resize(fAttributeDeclType, fAttributeDeclType.length * 2);
774             fAttributeDeclEnumeration = resize(fAttributeDeclEnumeration, fAttributeDeclEnumeration.length * 2);
775             fAttributeDeclDefaultType = resize(fAttributeDeclDefaultType, fAttributeDeclDefaultType.length * 2);
776             fAttributeDeclDefaultValue = resize(fAttributeDeclDefaultValue, fAttributeDeclDefaultValue.length * 2);
777             fAttributeDeclNonNormalizedDefaultValue = resize(fAttributeDeclNonNormalizedDefaultValue, fAttributeDeclNonNormalizedDefaultValue.length * 2);
778             fAttributeDeclNextAttributeDeclIndex = resize(fAttributeDeclNextAttributeDeclIndex, fAttributeDeclNextAttributeDeclIndex.length * 2);
779         }
780         else if (fAttributeDeclName[chunk] != null) {
781             return;
782         }
783 
784         fAttributeDeclName[chunk] = new QName[CHUNK_SIZE];
785         fAttributeDeclType[chunk] = new short[CHUNK_SIZE];
786         fAttributeDeclEnumeration[chunk] = new String[CHUNK_SIZE][];
787         fAttributeDeclDefaultType[chunk] = new short[CHUNK_SIZE];
788         fAttributeDeclDefaultValue[chunk] = new String[CHUNK_SIZE];
789         fAttributeDeclNonNormalizedDefaultValue[chunk] = new String[CHUNK_SIZE];
790         fAttributeDeclNextAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
791         return;
792     }
793 
794 
795     // resize chunks
796 
797     private static short[][] resize(short array[][], int newsize) {
798         short newarray[][] = new short[newsize][];
799         System.arraycopy(array, 0, newarray, 0, array.length);
800         return newarray;
801     }
802 
803     private static int[][] resize(int array[][], int newsize) {
804         int newarray[][] = new int[newsize][];
805         System.arraycopy(array, 0, newarray, 0, array.length);
806         return newarray;
807     }
808 
809     private static QName[][] resize(QName array[][], int newsize) {
810         QName newarray[][] = new QName[newsize][];
811         System.arraycopy(array, 0, newarray, 0, array.length);
812         return newarray;
813     }
814 
815     private static String[][] resize(String array[][], int newsize) {
816         String newarray[][] = new String[newsize][];
817         System.arraycopy(array, 0, newarray, 0, array.length);
818         return newarray;
819     }
820 
821     private static String[][][] resize(String array[][][], int newsize) {
822         String newarray[][][] = new String[newsize] [][];
823         System.arraycopy(array, 0, newarray, 0, array.length);
824         return newarray;
825     }
826 
827     //
828     // Classes
829     //
830 
831 
832     /**
833      * A simple Hashtable implementation that takes a tuple (String, String)
834      * as the key and a int as value.
835      *
836      * @author Eric Ye, IBM
837      * @author Andy Clark, IBM
838      */
839     protected static final class QNameHashtable {
840 
841         //
842         // Constants
843         //
844         public static final boolean UNIQUE_STRINGS = true;
845 
846         /** Initial bucket size (4). */
847         private static final int INITIAL_BUCKET_SIZE = 4;
848 
849         // NOTE: Changed previous hashtable size from 512 to 101 so
850         //       that we get a better distribution for hashing. -Ac
851         /** Hashtable size (101). */
852         private static final int HASHTABLE_SIZE = 101;
853 
854         //
855         // Data
856         //
857         private Object[][] fHashTable = new Object[HASHTABLE_SIZE][];
858 
859         //
860         // Public methods
861         //
862         /** Associates the given value with the specified key tuple. */
863         public void put(String key, int value) {
864 
865             // REVISIT: Why +2? -Ac
866             int hash = (hash(key)+2) % HASHTABLE_SIZE;
867             Object[] bucket = fHashTable[hash];
868 
869             if (bucket == null) {
870                 bucket = new Object[1 + 2*INITIAL_BUCKET_SIZE];
871                 bucket[0] = new int[]{1};
872                 bucket[1] = key;
873                 bucket[2] = new int[]{value};
874                 fHashTable[hash] = bucket;
875             } else {
876                 int count = ((int[])bucket[0])[0];
877                 int offset = 1 + 2*count;
878                 if (offset == bucket.length) {
879                     int newSize = count + INITIAL_BUCKET_SIZE;
880                     Object[] newBucket = new Object[1 + 2*newSize];
881                     System.arraycopy(bucket, 0, newBucket, 0, offset);
882                     bucket = newBucket;
883                     fHashTable[hash] = bucket;
884                 }
885                 boolean found = false;
886                 int j=1;
887                 for (int i=0; i<count; i++){
888                     if ((String)bucket[j] == key) {
889                         ((int[])bucket[j+1])[0] = value;
890                         found = true;
891                         break;
892                     }
893                     j += 2;
894                 }
895                 if (! found) {
896                     bucket[offset++] = key;
897                     bucket[offset]= new int[]{value};
898                     ((int[])bucket[0])[0] = ++count;
899                 }
900 
901             }
902             //System.out.println("put("+key+" -> "+value+')');
903             //System.out.println("get("+key+") -> "+get(key));
904 
905         } // put(int,String,String,int)
906 
907         /** Returns the value associated with the specified key tuple. */
908         public int get(String key) {
909             int hash = (hash(key)+2) % HASHTABLE_SIZE;
910             Object[] bucket = fHashTable[hash];
911 
912             if (bucket == null) {
913                 return -1;
914             }
915             int count = ((int[])bucket[0])[0];
916 
917             int j=1;
918             for (int i=0; i<count; i++){
919                 if ((String)bucket[j] == key) {
920                     return ((int[])bucket[j+1])[0];
921                 }
922                 j += 2;
923             }
924             return -1;
925 
926         } // get(int,String,String)
927 
928         //
929         // Protected methods
930         //
931 
932         /** Returns a hash value for the specified symbol. */
933         protected int hash(String symbol) {
934 
935             if (symbol == null) {
936                 return 0;
937             }
938             int code = 0;
939             int length = symbol.length();
940             for (int i = 0; i < length; i++) {
941                 code = code * 37 + symbol.charAt(i);
942             }
943             return code & 0x7FFFFFF;
944 
945         } // hash(String):int
946 
947     }  // class QNameHashtable
948     /**
949      * Normalize the attribute value of a non CDATA default attribute
950      * collapsing sequences of space characters (x20)
951      *
952      * @param value The value to normalize
953      * @return Whether the value was changed or not.
954      */
955     private boolean normalizeDefaultAttrValue(XMLString value) {
956 
957         int oldLength = value.length;
958 
959         boolean skipSpace = true; // skip leading spaces
960         int current = value.offset;
961         int end = value.offset + value.length;
962         for (int i = value.offset; i < end; i++) {
963             if (value.ch[i] == ' ') {
964                 if (!skipSpace) {
965                     // take the first whitespace as a space and skip the others
966                     value.ch[current++] = ' ';
967                     skipSpace = true;
968                 }
969                 else {
970                     // just skip it.
971                 }
972             }
973             else {
974                 // simply shift non space chars if needed
975                 if (current != i) {
976                     value.ch[current] = value.ch[i];
977                 }
978                 current++;
979                 skipSpace = false;
980             }
981         }
982         if (current != end) {
983             if (skipSpace) {
984                 // if we finished on a space trim it
985                 current--;
986             }
987             // set the new value length
988             value.length = current - value.offset;
989             return true;
990         }
991         return false;
992     }
993     public void endDTD(Augmentations augs) throws XNIException {
994 
995     }
996 }