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