| /* |
| * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. |
| */ |
| |
| /* |
| * Copyright 2005 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.sun.xml.internal.stream.dtd.nonvalidating; |
| |
| import java.util.Hashtable; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import com.sun.org.apache.xerces.internal.util.SymbolTable; |
| import com.sun.org.apache.xerces.internal.xni.Augmentations; |
| import com.sun.org.apache.xerces.internal.xni.QName; |
| import com.sun.org.apache.xerces.internal.util.XMLSymbols; |
| import com.sun.org.apache.xerces.internal.xni.XMLLocator; |
| import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; |
| import com.sun.org.apache.xerces.internal.xni.XMLString; |
| import com.sun.org.apache.xerces.internal.xni.XNIException; |
| import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelSource; |
| import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource; |
| |
| /** |
| * A DTD grammar. This class implements the XNI handler interfaces |
| * for DTD information so that it can build the approprate validation |
| * structures automatically from the callbacks. |
| * |
| * @author Eric Ye, IBM |
| * @author Jeffrey Rodriguez, IBM |
| * @author Andy Clark, IBM |
| * @author Neil Graham, IBM |
| * |
| */ |
| public class DTDGrammar { |
| |
| |
| /** Top level scope (-1). */ |
| public static final int TOP_LEVEL_SCOPE = -1; |
| |
| // private |
| |
| /** Chunk shift (8). */ |
| private static final int CHUNK_SHIFT = 8; // 2^8 = 256 |
| |
| /** Chunk size (1 << CHUNK_SHIFT). */ |
| private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT); |
| |
| /** Chunk mask (CHUNK_SIZE - 1). */ |
| private static final int CHUNK_MASK = CHUNK_SIZE - 1; |
| |
| /** Initial chunk count (1 << (10 - CHUNK_SHIFT)). */ |
| private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k |
| |
| /** List flag (0x80). */ |
| private static final short LIST_FLAG = 0x80; |
| |
| /** List mask (~LIST_FLAG). */ |
| private static final short LIST_MASK = ~LIST_FLAG; |
| |
| // debugging |
| |
| /** Debug DTDGrammar. */ |
| private static final boolean DEBUG = false; |
| |
| // |
| // Data |
| // |
| |
| protected XMLDTDSource fDTDSource = null; |
| protected XMLDTDContentModelSource fDTDContentModelSource = null; |
| |
| /** Current element index. */ |
| protected int fCurrentElementIndex; |
| |
| /** Current attribute index. */ |
| protected int fCurrentAttributeIndex; |
| |
| /** fReadingExternalDTD */ |
| protected boolean fReadingExternalDTD = false; |
| |
| /** Symbol table. */ |
| private SymbolTable fSymbolTable; |
| private ArrayList notationDecls = new ArrayList(); |
| |
| // element declarations |
| |
| /** Number of element declarations. */ |
| private int fElementDeclCount = 0; |
| |
| /** Element declaration name. */ |
| private QName fElementDeclName[][] = new QName[INITIAL_CHUNK_COUNT][]; |
| |
| /** |
| * Element declaration type. |
| * @see XMLElementDecl |
| */ |
| private short fElementDeclType[][] = new short[INITIAL_CHUNK_COUNT][]; |
| |
| |
| /** First attribute declaration of an element declaration. */ |
| private int fElementDeclFirstAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][]; |
| |
| /** Last attribute declaration of an element declaration. */ |
| private int fElementDeclLastAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][]; |
| |
| // attribute declarations |
| |
| /** Number of attribute declarations. */ |
| private int fAttributeDeclCount = 0 ; |
| |
| /** Attribute declaration name. */ |
| private QName fAttributeDeclName[][] = new QName[INITIAL_CHUNK_COUNT][]; |
| |
| /** |
| * Attribute declaration type. |
| * @see XMLAttributeDecl |
| */ |
| private short fAttributeDeclType[][] = new short[INITIAL_CHUNK_COUNT][]; |
| |
| /** Attribute declaration enumeration values. */ |
| private String[] fAttributeDeclEnumeration[][] = new String[INITIAL_CHUNK_COUNT][][]; |
| private short fAttributeDeclDefaultType[][] = new short[INITIAL_CHUNK_COUNT][]; |
| private String fAttributeDeclDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][]; |
| private String fAttributeDeclNonNormalizedDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][]; |
| private int fAttributeDeclNextAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][]; |
| |
| /** Element index mapping table. */ |
| private QNameHashtable fElementIndexMap = new QNameHashtable(); |
| |
| /** Temporary qualified name. */ |
| private QName fQName = new QName(); |
| |
| /** Temporary Attribute decl. */ |
| protected XMLAttributeDecl fAttributeDecl = new XMLAttributeDecl(); |
| |
| /** Element declaration. */ |
| private XMLElementDecl fElementDecl = new XMLElementDecl(); |
| |
| /** Simple type. */ |
| private XMLSimpleType fSimpleType = new XMLSimpleType(); |
| |
| |
| /** table of XMLElementDecl */ |
| Hashtable fElementDeclTab = new Hashtable(); |
| |
| /** Default constructor. */ |
| public DTDGrammar(SymbolTable symbolTable) { |
| fSymbolTable = symbolTable; |
| } |
| |
| public int getAttributeDeclIndex(int elementDeclIndex, String attributeDeclName) { |
| if (elementDeclIndex == -1) { |
| return -1; |
| } |
| int attDefIndex = getFirstAttributeDeclIndex(elementDeclIndex); |
| while (attDefIndex != -1) { |
| getAttributeDecl(attDefIndex, fAttributeDecl); |
| |
| if (fAttributeDecl.name.rawname == attributeDeclName |
| || attributeDeclName.equals(fAttributeDecl.name.rawname) ) { |
| return attDefIndex; |
| } |
| attDefIndex = getNextAttributeDeclIndex(attDefIndex); |
| } |
| return -1; |
| } |
| |
| /** |
| * The start of the DTD. |
| * |
| * @param locator The document locator, or null if the document |
| * location cannot be reported during the parsing of |
| * the document DTD. However, it is <em>strongly</em> |
| * recommended that a locator be supplied that can |
| * at least report the base system identifier of the |
| * DTD. |
| * |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException { |
| } // startDTD(XMLLocator) |
| |
| // startExternalSubset(Augmentations) |
| |
| // endExternalSubset(Augmentations) |
| |
| /** |
| * An element declaration. |
| * |
| * @param name The name of the element. |
| * @param contentModel The element content model. |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void elementDecl(String name, String contentModel, Augmentations augs) |
| throws XNIException { |
| |
| XMLElementDecl tmpElementDecl = (XMLElementDecl) fElementDeclTab.get(name) ; |
| if ( tmpElementDecl != null ) { |
| if (tmpElementDecl.type == -1) { |
| fCurrentElementIndex = getElementDeclIndex(name); |
| } |
| else { |
| // duplicate element, ignored. |
| return; |
| } |
| } |
| else { |
| fCurrentElementIndex = createElementDecl();//create element decl |
| } |
| |
| XMLElementDecl elementDecl = new XMLElementDecl(); |
| QName elementName = new QName(null, name, name, null); |
| |
| elementDecl.name.setValues(elementName); |
| elementDecl.scope= -1; |
| if (contentModel.equals("EMPTY")) { |
| elementDecl.type = XMLElementDecl.TYPE_EMPTY; |
| } |
| else if (contentModel.equals("ANY")) { |
| elementDecl.type = XMLElementDecl.TYPE_ANY; |
| } |
| else if (contentModel.startsWith("(") ) { |
| if (contentModel.indexOf("#PCDATA") > 0 ) { |
| elementDecl.type = XMLElementDecl.TYPE_MIXED; |
| } |
| else { |
| elementDecl.type = XMLElementDecl.TYPE_CHILDREN; |
| } |
| } |
| |
| |
| //add(or set) this elementDecl to the local cache |
| this.fElementDeclTab.put(name, elementDecl ); |
| |
| fElementDecl = elementDecl; |
| |
| |
| if ( DEBUG ) { |
| System.out.println( "name = " + fElementDecl.name.localpart ); |
| System.out.println( "Type = " + fElementDecl.type ); |
| } |
| |
| setElementDecl(fCurrentElementIndex, fElementDecl );//set internal structure |
| |
| int chunk = fCurrentElementIndex >> CHUNK_SHIFT; |
| ensureElementDeclCapacity(chunk); |
| } |
| |
| /** |
| * An attribute declaration. |
| * |
| * @param elementName The name of the element that this attribute |
| * is associated with. |
| * @param attributeName The name of the attribute. |
| * @param type The attribute type. This value will be one of |
| * the following: "CDATA", "ENTITY", "ENTITIES", |
| * "ENUMERATION", "ID", "IDREF", "IDREFS", |
| * "NMTOKEN", "NMTOKENS", or "NOTATION". |
| * @param enumeration If the type has the value "ENUMERATION", this |
| * array holds the allowed attribute values; |
| * otherwise, this array is null. |
| * @param defaultType The attribute default type. This value will be |
| * one of the following: "#FIXED", "#IMPLIED", |
| * "#REQUIRED", or null. |
| * @param defaultValue The attribute default value, or null if no |
| * default value is specified. |
| * @param nonNormalizedDefaultValue The attribute default value with no normalization |
| * performed, or null if no default value is specified. |
| * |
| * @param augs Additional information that may include infoset |
| * augmentations. |
| * @throws XNIException Thrown by handler to signal an error. |
| */ |
| public void attributeDecl(String elementName, String attributeName, |
| String type, String[] enumeration, |
| String defaultType, XMLString defaultValue, |
| XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException { |
| |
| if (type != XMLSymbols.fCDATASymbol && defaultValue != null) { |
| normalizeDefaultAttrValue(defaultValue); |
| } |
| |
| if ( this.fElementDeclTab.containsKey( (String) elementName) ) { |
| //if ElementDecl has already being created in the Grammar then remove from table, |
| //this.fElementDeclTab.remove( (String) elementName ); |
| } |
| // then it is forward reference to a element decl, create the elementDecl first. |
| else { |
| fCurrentElementIndex = createElementDecl();//create element decl |
| |
| XMLElementDecl elementDecl = new XMLElementDecl(); |
| elementDecl.name.setValues(null, elementName, elementName, null); |
| |
| elementDecl.scope= -1; |
| |
| //add(or set) this elementDecl to the local cache |
| this.fElementDeclTab.put(elementName, elementDecl ); |
| |
| //set internal structure |
| setElementDecl(fCurrentElementIndex, elementDecl ); |
| } |
| |
| //Get Grammar index to grammar array |
| int elementIndex = getElementDeclIndex(elementName); |
| |
| //return, when more than one definition is provided for the same attribute of given element type |
| //only the first declaration is binding and later declarations are ignored |
| if (getAttributeDeclIndex(elementIndex, attributeName) != -1) { |
| return; |
| } |
| |
| fCurrentAttributeIndex = createAttributeDecl();// Create current Attribute Decl |
| |
| fSimpleType.clear(); |
| if ( defaultType != null ) { |
| if ( defaultType.equals( "#FIXED") ) { |
| fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_FIXED; |
| } else if ( defaultType.equals( "#IMPLIED") ) { |
| fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_IMPLIED; |
| } else if ( defaultType.equals( "#REQUIRED") ) { |
| fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_REQUIRED; |
| } |
| } |
| if ( DEBUG ) { |
| System.out.println("defaultvalue = " + defaultValue.toString() ); |
| } |
| fSimpleType.defaultValue = defaultValue!=null ? defaultValue.toString() : null; |
| fSimpleType.nonNormalizedDefaultValue = nonNormalizedDefaultValue!=null ? nonNormalizedDefaultValue.toString() : null; |
| fSimpleType.enumeration = enumeration; |
| |
| if (type.equals("CDATA")) { |
| fSimpleType.type = XMLSimpleType.TYPE_CDATA; |
| } |
| else if ( type.equals("ID") ) { |
| fSimpleType.type = XMLSimpleType.TYPE_ID; |
| } |
| else if ( type.startsWith("IDREF") ) { |
| fSimpleType.type = XMLSimpleType.TYPE_IDREF; |
| if (type.indexOf("S") > 0) { |
| fSimpleType.list = true; |
| } |
| } |
| else if (type.equals("ENTITIES")) { |
| fSimpleType.type = XMLSimpleType.TYPE_ENTITY; |
| fSimpleType.list = true; |
| } |
| else if (type.equals("ENTITY")) { |
| fSimpleType.type = XMLSimpleType.TYPE_ENTITY; |
| } |
| else if (type.equals("NMTOKENS")) { |
| fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN; |
| fSimpleType.list = true; |
| } |
| else if (type.equals("NMTOKEN")) { |
| fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN; |
| } |
| else if (type.startsWith("NOTATION") ) { |
| fSimpleType.type = XMLSimpleType.TYPE_NOTATION; |
| } |
| else if (type.startsWith("ENUMERATION") ) { |
| fSimpleType.type = XMLSimpleType.TYPE_ENUMERATION; |
| } |
| else { |
| // REVISIT: Report error message. -Ac |
| System.err.println("!!! unknown attribute type "+type); |
| } |
| // REVISIT: The datatype should be stored with the attribute value |
| // and not special-cased in the XMLValidator. -Ac |
| //fSimpleType.datatypeValidator = fDatatypeValidatorFactory.createDatatypeValidator(type, null, facets, fSimpleType.list); |
| |
| fQName.setValues(null, attributeName, attributeName, null); |
| fAttributeDecl.setValues( fQName, fSimpleType, false ); |
| |
| setAttributeDecl(elementIndex, fCurrentAttributeIndex, fAttributeDecl); |
| |
| int chunk = fCurrentAttributeIndex >> CHUNK_SHIFT; |
| ensureAttributeDeclCapacity(chunk); |
| } // attributeDecl(String,String,String,String[],String,XMLString,XMLString, Augmentations) |
| |
| /** Returns the symbol table. */ |
| public SymbolTable getSymbolTable() { |
| return fSymbolTable; |
| } // getSymbolTable():SymbolTable |
| |
| /** |
| * Returns the index of the first element declaration. This index |
| * is then used to query more information about the element declaration. |
| * |
| * @see #getNextElementDeclIndex |
| * @see #getElementDecl |
| */ |
| public int getFirstElementDeclIndex() { |
| return fElementDeclCount >= 0 ? 0 : -1; |
| } // getFirstElementDeclIndex():int |
| |
| /** |
| * Returns the next index of the element declaration following the |
| * specified element declaration. |
| * |
| * @param elementDeclIndex The element declaration index. |
| */ |
| public int getNextElementDeclIndex(int elementDeclIndex) { |
| return elementDeclIndex < fElementDeclCount - 1 |
| ? elementDeclIndex + 1 : -1; |
| } // getNextElementDeclIndex(int):int |
| |
| /** |
| * getElementDeclIndex |
| * |
| * @param elementDeclName |
| * |
| * @return index of the elementDeclName in scope |
| */ |
| public int getElementDeclIndex(String elementDeclName) { |
| int mapping = fElementIndexMap.get(elementDeclName); |
| //System.out.println("getElementDeclIndex("+elementDeclName+") -> "+mapping); |
| return mapping; |
| } // getElementDeclIndex(String):int |
| |
| /** Returns the element decl index. |
| * @param elementDeclQName qualilfied name of the element |
| */ |
| public int getElementDeclIndex(QName elementDeclQName) { |
| return getElementDeclIndex(elementDeclQName.rawname); |
| } // getElementDeclIndex(QName):int |
| |
| /** make separate function for getting contentSpecType of element. |
| * we can avoid setting of the element values. |
| */ |
| |
| public short getContentSpecType(int elementIndex){ |
| if (elementIndex < 0 || elementIndex >= fElementDeclCount) { |
| return -1 ; |
| } |
| |
| int chunk = elementIndex >> CHUNK_SHIFT; |
| int index = elementIndex & CHUNK_MASK; |
| |
| if(fElementDeclType[chunk][index] == -1){ |
| return -1 ; |
| } |
| else{ |
| return (short) (fElementDeclType[chunk][index] & LIST_MASK); |
| } |
| } |
| |
| /** |
| * getElementDecl |
| * |
| * @param elementDeclIndex |
| * @param elementDecl The values of this structure are set by this call. |
| * |
| * @return True if find the element, False otherwise. |
| */ |
| public boolean getElementDecl(int elementDeclIndex, |
| XMLElementDecl elementDecl) { |
| |
| if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { |
| return false; |
| } |
| |
| int chunk = elementDeclIndex >> CHUNK_SHIFT; |
| int index = elementDeclIndex & CHUNK_MASK; |
| |
| elementDecl.name.setValues(fElementDeclName[chunk][index]); |
| |
| if (fElementDeclType[chunk][index] == -1) { |
| elementDecl.type = -1; |
| elementDecl.simpleType.list = false; |
| } else { |
| elementDecl.type = (short) (fElementDeclType[chunk][index] & LIST_MASK); |
| elementDecl.simpleType.list = (fElementDeclType[chunk][index] & LIST_FLAG) != 0; |
| } |
| |
| elementDecl.simpleType.defaultType = -1; |
| elementDecl.simpleType.defaultValue = null; |
| return true; |
| |
| } |
| |
| // REVISIT: Make this getAttributeDeclCount/getAttributeDeclAt. -Ac |
| |
| /** |
| * getFirstAttributeDeclIndex |
| * |
| * @param elementDeclIndex |
| * |
| * @return index of the first attribute for element declaration elementDeclIndex |
| */ |
| public int getFirstAttributeDeclIndex(int elementDeclIndex) { |
| int chunk = elementDeclIndex >> CHUNK_SHIFT; |
| int index = elementDeclIndex & CHUNK_MASK; |
| |
| return fElementDeclFirstAttributeDeclIndex[chunk][index]; |
| } // getFirstAttributeDeclIndex |
| |
| /** |
| * getNextAttributeDeclIndex |
| * |
| * @param attributeDeclIndex |
| * |
| * @return index of the next attribute of the attribute at attributeDeclIndex |
| */ |
| public int getNextAttributeDeclIndex(int attributeDeclIndex) { |
| int chunk = attributeDeclIndex >> CHUNK_SHIFT; |
| int index = attributeDeclIndex & CHUNK_MASK; |
| |
| return fAttributeDeclNextAttributeDeclIndex[chunk][index]; |
| } |
| |
| /** |
| * getAttributeDecl |
| * |
| * @param attributeDeclIndex |
| * @param attributeDecl The values of this structure are set by this call. |
| * |
| * @return true if getAttributeDecl was able to fill in the value of attributeDecl |
| */ |
| public boolean getAttributeDecl(int attributeDeclIndex, XMLAttributeDecl attributeDecl) { |
| if (attributeDeclIndex < 0 || attributeDeclIndex >= fAttributeDeclCount) { |
| return false; |
| } |
| int chunk = attributeDeclIndex >> CHUNK_SHIFT; |
| int index = attributeDeclIndex & CHUNK_MASK; |
| |
| attributeDecl.name.setValues(fAttributeDeclName[chunk][index]); |
| |
| short attributeType; |
| boolean isList; |
| |
| if (fAttributeDeclType[chunk][index] == -1) { |
| |
| attributeType = -1; |
| isList = false; |
| } else { |
| attributeType = (short) (fAttributeDeclType[chunk][index] & LIST_MASK); |
| isList = (fAttributeDeclType[chunk][index] & LIST_FLAG) != 0; |
| } |
| attributeDecl.simpleType.setValues(attributeType,fAttributeDeclName[chunk][index].localpart, |
| fAttributeDeclEnumeration[chunk][index], |
| isList, fAttributeDeclDefaultType[chunk][index], |
| fAttributeDeclDefaultValue[chunk][index], |
| fAttributeDeclNonNormalizedDefaultValue[chunk][index]); |
| return true; |
| |
| } // getAttributeDecl |
| |
| |
| /** |
| * Returns whether the given attribute is of type CDATA or not |
| * |
| * @param elName The element name. |
| * @param atName The attribute name. |
| * |
| * @return true if the attribute is of type CDATA |
| */ |
| public boolean isCDATAAttribute(QName elName, QName atName) { |
| int elDeclIdx = getElementDeclIndex(elName); |
| if (getAttributeDecl(elDeclIdx, fAttributeDecl) |
| && fAttributeDecl.simpleType.type != XMLSimpleType.TYPE_CDATA){ |
| return false; |
| } |
| return true; |
| } |
| |
| |
| |
| public void printElements( ) { |
| int elementDeclIndex = 0; |
| XMLElementDecl elementDecl = new XMLElementDecl(); |
| while (getElementDecl(elementDeclIndex++, elementDecl)) { |
| |
| System.out.println("element decl: "+elementDecl.name+ |
| ", "+ elementDecl.name.rawname ); |
| |
| } |
| } |
| |
| public void printAttributes(int elementDeclIndex) { |
| int attributeDeclIndex = getFirstAttributeDeclIndex(elementDeclIndex); |
| System.out.print(elementDeclIndex); |
| System.out.print(" ["); |
| while (attributeDeclIndex != -1) { |
| System.out.print(' '); |
| System.out.print(attributeDeclIndex); |
| printAttribute(attributeDeclIndex); |
| attributeDeclIndex = getNextAttributeDeclIndex(attributeDeclIndex); |
| if (attributeDeclIndex != -1) { |
| System.out.print(","); |
| } |
| } |
| System.out.println(" ]"); |
| } |
| |
| |
| protected int createElementDecl() { |
| int chunk = fElementDeclCount >> CHUNK_SHIFT; |
| int index = fElementDeclCount & CHUNK_MASK; |
| ensureElementDeclCapacity(chunk); |
| fElementDeclName[chunk][index] = new QName(); |
| fElementDeclType[chunk][index] = -1; |
| fElementDeclFirstAttributeDeclIndex[chunk][index] = -1; |
| fElementDeclLastAttributeDeclIndex[chunk][index] = -1; |
| return fElementDeclCount++; |
| } |
| |
| protected void setElementDecl(int elementDeclIndex, XMLElementDecl elementDecl) { |
| if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { |
| return; |
| } |
| int chunk = elementDeclIndex >> CHUNK_SHIFT; |
| int index = elementDeclIndex & CHUNK_MASK; |
| |
| int scope = elementDecl.scope; |
| |
| |
| fElementDeclName[chunk][index].setValues(elementDecl.name); |
| fElementDeclType[chunk][index] = elementDecl.type; |
| |
| |
| |
| if (elementDecl.simpleType.list == true ) { |
| fElementDeclType[chunk][index] |= LIST_FLAG; |
| } |
| |
| fElementIndexMap.put(elementDecl.name.rawname, elementDeclIndex); |
| } |
| |
| |
| |
| |
| protected void setFirstAttributeDeclIndex(int elementDeclIndex, int newFirstAttrIndex){ |
| |
| if (elementDeclIndex < 0 || elementDeclIndex >= fElementDeclCount) { |
| return; |
| } |
| |
| int chunk = elementDeclIndex >> CHUNK_SHIFT; |
| int index = elementDeclIndex & CHUNK_MASK; |
| |
| fElementDeclFirstAttributeDeclIndex[chunk][index] = newFirstAttrIndex; |
| } |
| |
| |
| protected int createAttributeDecl() { |
| int chunk = fAttributeDeclCount >> CHUNK_SHIFT; |
| int index = fAttributeDeclCount & CHUNK_MASK; |
| |
| ensureAttributeDeclCapacity(chunk); |
| fAttributeDeclName[chunk][index] = new QName(); |
| fAttributeDeclType[chunk][index] = -1; |
| fAttributeDeclEnumeration[chunk][index] = null; |
| fAttributeDeclDefaultType[chunk][index] = XMLSimpleType.DEFAULT_TYPE_IMPLIED; |
| fAttributeDeclDefaultValue[chunk][index] = null; |
| fAttributeDeclNonNormalizedDefaultValue[chunk][index] = null; |
| fAttributeDeclNextAttributeDeclIndex[chunk][index] = -1; |
| return fAttributeDeclCount++; |
| } |
| |
| |
| protected void setAttributeDecl(int elementDeclIndex, int attributeDeclIndex, |
| XMLAttributeDecl attributeDecl) { |
| int attrChunk = attributeDeclIndex >> CHUNK_SHIFT; |
| int attrIndex = attributeDeclIndex & CHUNK_MASK; |
| fAttributeDeclName[attrChunk][attrIndex].setValues(attributeDecl.name); |
| fAttributeDeclType[attrChunk][attrIndex] = attributeDecl.simpleType.type; |
| |
| if (attributeDecl.simpleType.list) { |
| fAttributeDeclType[attrChunk][attrIndex] |= LIST_FLAG; |
| } |
| fAttributeDeclEnumeration[attrChunk][attrIndex] = attributeDecl.simpleType.enumeration; |
| fAttributeDeclDefaultType[attrChunk][attrIndex] = attributeDecl.simpleType.defaultType; |
| |
| fAttributeDeclDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.defaultValue; |
| fAttributeDeclNonNormalizedDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.nonNormalizedDefaultValue; |
| |
| int elemChunk = elementDeclIndex >> CHUNK_SHIFT; |
| int elemIndex = elementDeclIndex & CHUNK_MASK; |
| int index = fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex]; |
| while (index != -1) { |
| if (index == attributeDeclIndex) { |
| break; |
| } |
| attrChunk = index >> CHUNK_SHIFT; |
| attrIndex = index & CHUNK_MASK; |
| index = fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex]; |
| } |
| if (index == -1) { |
| if (fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] == -1) { |
| fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex; |
| } else { |
| index = fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex]; |
| attrChunk = index >> CHUNK_SHIFT; |
| attrIndex = index & CHUNK_MASK; |
| fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex] = attributeDeclIndex; |
| } |
| fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex; |
| } |
| } |
| |
| public void notationDecl(String name, XMLResourceIdentifier identifier, |
| Augmentations augs) throws XNIException { |
| |
| |
| XMLNotationDecl notationDecl = new XMLNotationDecl(); |
| notationDecl.setValues(name,identifier.getPublicId(),identifier.getLiteralSystemId(), |
| identifier.getBaseSystemId()); |
| notationDecls.add(notationDecl); |
| } |
| |
| public List getNotationDecls(){ |
| return notationDecls; |
| } |
| |
| // |
| // Private methods |
| // |
| private void printAttribute(int attributeDeclIndex) { |
| |
| XMLAttributeDecl attributeDecl = new XMLAttributeDecl(); |
| if (getAttributeDecl(attributeDeclIndex, attributeDecl)) { |
| System.out.print(" { "); |
| System.out.print(attributeDecl.name.localpart); |
| System.out.print(" }"); |
| } |
| |
| } // printAttribute(int) |
| |
| |
| |
| private void ensureElementDeclCapacity(int chunk) { |
| if (chunk >= fElementDeclName.length) { |
| |
| fElementDeclName = resize(fElementDeclName, fElementDeclName.length * 2); |
| fElementDeclType = resize(fElementDeclType, fElementDeclType.length * 2); |
| fElementDeclFirstAttributeDeclIndex = resize(fElementDeclFirstAttributeDeclIndex, fElementDeclFirstAttributeDeclIndex.length * 2); |
| fElementDeclLastAttributeDeclIndex = resize(fElementDeclLastAttributeDeclIndex, fElementDeclLastAttributeDeclIndex.length * 2); |
| } |
| else if (fElementDeclName[chunk] != null) { |
| return; |
| } |
| |
| fElementDeclName[chunk] = new QName[CHUNK_SIZE]; |
| fElementDeclType[chunk] = new short[CHUNK_SIZE]; |
| fElementDeclFirstAttributeDeclIndex[chunk] = new int[CHUNK_SIZE]; |
| fElementDeclLastAttributeDeclIndex[chunk] = new int[CHUNK_SIZE]; |
| return; |
| } |
| |
| private void ensureAttributeDeclCapacity(int chunk) { |
| |
| if (chunk >= fAttributeDeclName.length) { |
| fAttributeDeclName = resize(fAttributeDeclName, fAttributeDeclName.length * 2); |
| fAttributeDeclType = resize(fAttributeDeclType, fAttributeDeclType.length * 2); |
| fAttributeDeclEnumeration = resize(fAttributeDeclEnumeration, fAttributeDeclEnumeration.length * 2); |
| fAttributeDeclDefaultType = resize(fAttributeDeclDefaultType, fAttributeDeclDefaultType.length * 2); |
| fAttributeDeclDefaultValue = resize(fAttributeDeclDefaultValue, fAttributeDeclDefaultValue.length * 2); |
| fAttributeDeclNonNormalizedDefaultValue = resize(fAttributeDeclNonNormalizedDefaultValue, fAttributeDeclNonNormalizedDefaultValue.length * 2); |
| fAttributeDeclNextAttributeDeclIndex = resize(fAttributeDeclNextAttributeDeclIndex, fAttributeDeclNextAttributeDeclIndex.length * 2); |
| } |
| else if (fAttributeDeclName[chunk] != null) { |
| return; |
| } |
| |
| fAttributeDeclName[chunk] = new QName[CHUNK_SIZE]; |
| fAttributeDeclType[chunk] = new short[CHUNK_SIZE]; |
| fAttributeDeclEnumeration[chunk] = new String[CHUNK_SIZE][]; |
| fAttributeDeclDefaultType[chunk] = new short[CHUNK_SIZE]; |
| fAttributeDeclDefaultValue[chunk] = new String[CHUNK_SIZE]; |
| fAttributeDeclNonNormalizedDefaultValue[chunk] = new String[CHUNK_SIZE]; |
| fAttributeDeclNextAttributeDeclIndex[chunk] = new int[CHUNK_SIZE]; |
| return; |
| } |
| |
| |
| // resize chunks |
| |
| private static short[][] resize(short array[][], int newsize) { |
| short newarray[][] = new short[newsize][]; |
| System.arraycopy(array, 0, newarray, 0, array.length); |
| return newarray; |
| } |
| |
| private static int[][] resize(int array[][], int newsize) { |
| int newarray[][] = new int[newsize][]; |
| System.arraycopy(array, 0, newarray, 0, array.length); |
| return newarray; |
| } |
| |
| private static QName[][] resize(QName array[][], int newsize) { |
| QName newarray[][] = new QName[newsize][]; |
| System.arraycopy(array, 0, newarray, 0, array.length); |
| return newarray; |
| } |
| |
| private static String[][] resize(String array[][], int newsize) { |
| String newarray[][] = new String[newsize][]; |
| System.arraycopy(array, 0, newarray, 0, array.length); |
| return newarray; |
| } |
| |
| private static String[][][] resize(String array[][][], int newsize) { |
| String newarray[][][] = new String[newsize] [][]; |
| System.arraycopy(array, 0, newarray, 0, array.length); |
| return newarray; |
| } |
| |
| // |
| // Classes |
| // |
| |
| |
| /** |
| * A simple Hashtable implementation that takes a tuple (String, String) |
| * as the key and a int as value. |
| * |
| * @author Eric Ye, IBM |
| * @author Andy Clark, IBM |
| */ |
| protected static final class QNameHashtable { |
| |
| // |
| // Constants |
| // |
| public static final boolean UNIQUE_STRINGS = true; |
| |
| /** Initial bucket size (4). */ |
| private static final int INITIAL_BUCKET_SIZE = 4; |
| |
| // NOTE: Changed previous hashtable size from 512 to 101 so |
| // that we get a better distribution for hashing. -Ac |
| /** Hashtable size (101). */ |
| private static final int HASHTABLE_SIZE = 101; |
| |
| // |
| // Data |
| // |
| private Object[][] fHashTable = new Object[HASHTABLE_SIZE][]; |
| |
| // |
| // Public methods |
| // |
| /** Associates the given value with the specified key tuple. */ |
| public void put(String key, int value) { |
| |
| // REVISIT: Why +2? -Ac |
| int hash = (hash(key)+2) % HASHTABLE_SIZE; |
| Object[] bucket = fHashTable[hash]; |
| |
| if (bucket == null) { |
| bucket = new Object[1 + 2*INITIAL_BUCKET_SIZE]; |
| bucket[0] = new int[]{1}; |
| bucket[1] = key; |
| bucket[2] = new int[]{value}; |
| fHashTable[hash] = bucket; |
| } else { |
| int count = ((int[])bucket[0])[0]; |
| int offset = 1 + 2*count; |
| if (offset == bucket.length) { |
| int newSize = count + INITIAL_BUCKET_SIZE; |
| Object[] newBucket = new Object[1 + 2*newSize]; |
| System.arraycopy(bucket, 0, newBucket, 0, offset); |
| bucket = newBucket; |
| fHashTable[hash] = bucket; |
| } |
| boolean found = false; |
| int j=1; |
| for (int i=0; i<count; i++){ |
| if ((String)bucket[j] == key) { |
| ((int[])bucket[j+1])[0] = value; |
| found = true; |
| break; |
| } |
| j += 2; |
| } |
| if (! found) { |
| bucket[offset++] = key; |
| bucket[offset]= new int[]{value}; |
| ((int[])bucket[0])[0] = ++count; |
| } |
| |
| } |
| //System.out.println("put("+key+" -> "+value+')'); |
| //System.out.println("get("+key+") -> "+get(key)); |
| |
| } // put(int,String,String,int) |
| |
| /** Returns the value associated with the specified key tuple. */ |
| public int get(String key) { |
| int hash = (hash(key)+2) % HASHTABLE_SIZE; |
| Object[] bucket = fHashTable[hash]; |
| |
| if (bucket == null) { |
| return -1; |
| } |
| int count = ((int[])bucket[0])[0]; |
| |
| int j=1; |
| for (int i=0; i<count; i++){ |
| if ((String)bucket[j] == key) { |
| return ((int[])bucket[j+1])[0]; |
| } |
| j += 2; |
| } |
| return -1; |
| |
| } // get(int,String,String) |
| |
| // |
| // Protected methods |
| // |
| |
| /** Returns a hash value for the specified symbol. */ |
| protected int hash(String symbol) { |
| |
| if (symbol == null) { |
| return 0; |
| } |
| int code = 0; |
| int length = symbol.length(); |
| for (int i = 0; i < length; i++) { |
| code = code * 37 + symbol.charAt(i); |
| } |
| return code & 0x7FFFFFF; |
| |
| } // hash(String):int |
| |
| } // class QNameHashtable |
| /** |
| * Normalize the attribute value of a non CDATA default attribute |
| * collapsing sequences of space characters (x20) |
| * |
| * @param value The value to normalize |
| * @return Whether the value was changed or not. |
| */ |
| private boolean normalizeDefaultAttrValue(XMLString value) { |
| |
| int oldLength = value.length; |
| |
| boolean skipSpace = true; // skip leading spaces |
| int current = value.offset; |
| int end = value.offset + value.length; |
| for (int i = value.offset; i < end; i++) { |
| if (value.ch[i] == ' ') { |
| if (!skipSpace) { |
| // take the first whitespace as a space and skip the others |
| value.ch[current++] = ' '; |
| skipSpace = true; |
| } |
| else { |
| // just skip it. |
| } |
| } |
| else { |
| // simply shift non space chars if needed |
| if (current != i) { |
| value.ch[current] = value.ch[i]; |
| } |
| current++; |
| skipSpace = false; |
| } |
| } |
| if (current != end) { |
| if (skipSpace) { |
| // if we finished on a space trim it |
| current--; |
| } |
| // set the new value length |
| value.length = current - value.offset; |
| return true; |
| } |
| return false; |
| } |
| public void endDTD(Augmentations augs) throws XNIException { |
| |
| } |
| } |