0001: /*
0002: * $Id: DTDGrammar.java,v 1.2 2006/04/01 06:01:41 jeffsuttor Exp $
0003: */
0004:
0005: /*
0006: * The contents of this file are subject to the terms
0007: * of the Common Development and Distribution License
0008: * (the License). You may not use this file except in
0009: * compliance with the License.
0010: *
0011: * You can obtain a copy of the license at
0012: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
0013: * See the License for the specific language governing
0014: * permissions and limitations under the License.
0015: *
0016: * When distributing Covered Code, include this CDDL
0017: * Header Notice in each file and include the License file
0018: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
0019: * If applicable, add the following below the CDDL Header,
0020: * with the fields enclosed by brackets [] replaced by
0021: * you own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * [Name of File] [ver.__] [Date]
0025: *
0026: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
0027: */
0028:
0029: /*
0030: * The Apache Software License, Version 1.1
0031: *
0032: *
0033: * Copyright (c) 1999-2002 The Apache Software Foundation.
0034: * All rights reserved.
0035: *
0036: * Redistribution and use in source and binary forms, with or without
0037: * modification, are permitted provided that the following conditions
0038: * are met:
0039: *
0040: * 1. Redistributions of source code must retain the above copyright
0041: * notice, this list of conditions and the following disclaimer.
0042: *
0043: * 2. Redistributions in binary form must reproduce the above copyright
0044: * notice, this list of conditions and the following disclaimer in
0045: * the documentation and/or other materials provided with the
0046: * distribution.
0047: *
0048: * 3. The end-user documentation included with the redistribution,
0049: * if any, must include the following acknowledgment:
0050: * "This product includes software developed by the
0051: * Apache Software Foundation (http://www.apache.org/)."
0052: * Alternately, this acknowledgment may appear in the software itself,
0053: * if and wherever such third-party acknowledgments normally appear.
0054: *
0055: * 4. The names "Xerces" and "Apache Software Foundation" must
0056: * not be used to endorse or promote products derived from this
0057: * software without prior written permission. For written
0058: * permission, please contact apache@apache.org.
0059: *
0060: * 5. Products derived from this software may not be called "Apache",
0061: * nor may "Apache" appear in their name, without prior written
0062: * permission of the Apache Software Foundation.
0063: *
0064: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0065: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0066: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0067: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0068: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0069: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0070: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0071: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0072: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0073: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0074: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0075: * SUCH DAMAGE.
0076: * ====================================================================
0077: *
0078: * This software consists of voluntary contributions made by many
0079: * individuals on behalf of the Apache Software Foundation and was
0080: * originally based on software copyright (c) 1999, International
0081: * Business Machines, Inc., http://www.apache.org. For more
0082: * information on the Apache Software Foundation, please see
0083: * <http://www.apache.org/>.
0084: *
0085: * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
0086: * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
0087: */
0088:
0089: package com.sun.xml.stream.dtd.nonvalidating;
0090:
0091: import java.util.Hashtable;
0092: import java.util.ArrayList;
0093: import java.util.List;
0094:
0095: import com.sun.xml.stream.xerces.util.SymbolTable;
0096: import com.sun.xml.stream.xerces.xni.Augmentations;
0097: import com.sun.xml.stream.xerces.xni.QName;
0098: import com.sun.xml.stream.xerces.util.XMLSymbols;
0099: import com.sun.xml.stream.xerces.xni.XMLLocator;
0100: import com.sun.xml.stream.xerces.xni.XMLResourceIdentifier;
0101: import com.sun.xml.stream.xerces.xni.XMLString;
0102: import com.sun.xml.stream.xerces.xni.XNIException;
0103: import com.sun.xml.stream.xerces.xni.parser.XMLDTDContentModelSource;
0104: import com.sun.xml.stream.xerces.xni.parser.XMLDTDSource;
0105:
0106: /**
0107: * A DTD grammar. This class implements the XNI handler interfaces
0108: * for DTD information so that it can build the approprate validation
0109: * structures automatically from the callbacks.
0110: *
0111: * @author Eric Ye, IBM
0112: * @author Jeffrey Rodriguez, IBM
0113: * @author Andy Clark, IBM
0114: * @author Neil Graham, IBM
0115: *
0116: * @version $Id: DTDGrammar.java,v 1.2 2006/04/01 06:01:41 jeffsuttor Exp $
0117: */
0118: public class DTDGrammar {
0119:
0120: /** Top level scope (-1). */
0121: public static final int TOP_LEVEL_SCOPE = -1;
0122:
0123: // private
0124:
0125: /** Chunk shift (8). */
0126: private static final int CHUNK_SHIFT = 8; // 2^8 = 256
0127:
0128: /** Chunk size (1 << CHUNK_SHIFT). */
0129: private static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
0130:
0131: /** Chunk mask (CHUNK_SIZE - 1). */
0132: private static final int CHUNK_MASK = CHUNK_SIZE - 1;
0133:
0134: /** Initial chunk count (1 << (10 - CHUNK_SHIFT)). */
0135: private static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k
0136:
0137: /** List flag (0x80). */
0138: private static final short LIST_FLAG = 0x80;
0139:
0140: /** List mask (~LIST_FLAG). */
0141: private static final short LIST_MASK = ~LIST_FLAG;
0142:
0143: // debugging
0144:
0145: /** Debug DTDGrammar. */
0146: private static final boolean DEBUG = false;
0147:
0148: //
0149: // Data
0150: //
0151:
0152: protected XMLDTDSource fDTDSource = null;
0153: protected XMLDTDContentModelSource fDTDContentModelSource = null;
0154:
0155: /** Current element index. */
0156: protected int fCurrentElementIndex;
0157:
0158: /** Current attribute index. */
0159: protected int fCurrentAttributeIndex;
0160:
0161: /** fReadingExternalDTD */
0162: protected boolean fReadingExternalDTD = false;
0163:
0164: /** Symbol table. */
0165: private SymbolTable fSymbolTable;
0166: private ArrayList notationDecls = new ArrayList();
0167:
0168: // element declarations
0169:
0170: /** Number of element declarations. */
0171: private int fElementDeclCount = 0;
0172:
0173: /** Element declaration name. */
0174: private QName fElementDeclName[][] = new QName[INITIAL_CHUNK_COUNT][];
0175:
0176: /**
0177: * Element declaration type.
0178: * @see XMLElementDecl
0179: */
0180: private short fElementDeclType[][] = new short[INITIAL_CHUNK_COUNT][];
0181:
0182: /** First attribute declaration of an element declaration. */
0183: private int fElementDeclFirstAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
0184:
0185: /** Last attribute declaration of an element declaration. */
0186: private int fElementDeclLastAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
0187:
0188: // attribute declarations
0189:
0190: /** Number of attribute declarations. */
0191: private int fAttributeDeclCount = 0;
0192:
0193: /** Attribute declaration name. */
0194: private QName fAttributeDeclName[][] = new QName[INITIAL_CHUNK_COUNT][];
0195:
0196: // is this grammar immutable? (fully constructed and not changeable)
0197: private boolean fIsImmutable = false;
0198:
0199: /**
0200: * Attribute declaration type.
0201: * @see XMLAttributeDecl
0202: */
0203: private short fAttributeDeclType[][] = new short[INITIAL_CHUNK_COUNT][];
0204:
0205: /** Attribute declaration enumeration values. */
0206: private String[] fAttributeDeclEnumeration[][] = new String[INITIAL_CHUNK_COUNT][][];
0207: private short fAttributeDeclDefaultType[][] = new short[INITIAL_CHUNK_COUNT][];
0208: private String fAttributeDeclDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][];
0209: private String fAttributeDeclNonNormalizedDefaultValue[][] = new String[INITIAL_CHUNK_COUNT][];
0210: private int fAttributeDeclNextAttributeDeclIndex[][] = new int[INITIAL_CHUNK_COUNT][];
0211:
0212: /** Element index mapping table. */
0213: private QNameHashtable fElementIndexMap = new QNameHashtable();
0214:
0215: /** Temporary qualified name. */
0216: private QName fQName = new QName();
0217:
0218: /** Temporary qualified name. */
0219: private QName fQName2 = new QName();
0220:
0221: /** Temporary Attribute decl. */
0222: protected XMLAttributeDecl fAttributeDecl = new XMLAttributeDecl();
0223:
0224: // for buildSyntaxTree method
0225:
0226: private int fLeafCount = 0;
0227: private int fEpsilonIndex = -1;
0228:
0229: /** Element declaration. */
0230: private XMLElementDecl fElementDecl = new XMLElementDecl();
0231:
0232: /** Simple type. */
0233: private XMLSimpleType fSimpleType = new XMLSimpleType();
0234:
0235: /** table of XMLElementDecl */
0236: Hashtable fElementDeclTab = new Hashtable();
0237:
0238: /** Children content model operation stack. */
0239: private short[] fOpStack = null;
0240:
0241: /** Children content model index stack. */
0242: private int[] fNodeIndexStack = null;
0243:
0244: /** Children content model previous node index stack. */
0245: private int[] fPrevNodeIndexStack = null;
0246:
0247: /** Stack depth */
0248: private int fDepth = 0;
0249:
0250: int valueIndex = -1;
0251: int prevNodeIndex = -1;
0252: int nodeIndex = -1;
0253:
0254: /** Default constructor. */
0255: public DTDGrammar(SymbolTable symbolTable) {
0256: fSymbolTable = symbolTable;
0257: }
0258:
0259: public int getAttributeDeclIndex(int elementDeclIndex,
0260: String attributeDeclName) {
0261: if (elementDeclIndex == -1) {
0262: return -1;
0263: }
0264: int attDefIndex = getFirstAttributeDeclIndex(elementDeclIndex);
0265: while (attDefIndex != -1) {
0266: getAttributeDecl(attDefIndex, fAttributeDecl);
0267:
0268: if (fAttributeDecl.name.rawname == attributeDeclName
0269: || attributeDeclName
0270: .equals(fAttributeDecl.name.rawname)) {
0271: return attDefIndex;
0272: }
0273: attDefIndex = getNextAttributeDeclIndex(attDefIndex);
0274: }
0275: return -1;
0276: }
0277:
0278: /**
0279: * The start of the DTD.
0280: *
0281: * @param locator The document locator, or null if the document
0282: * location cannot be reported during the parsing of
0283: * the document DTD. However, it is <em>strongly</em>
0284: * recommended that a locator be supplied that can
0285: * at least report the base system identifier of the
0286: * DTD.
0287: *
0288: * @param augs Additional information that may include infoset
0289: * augmentations.
0290: * @throws XNIException Thrown by handler to signal an error.
0291: */
0292: public void startDTD(XMLLocator locator, Augmentations augs)
0293: throws XNIException {
0294: //Initialize stack
0295: fOpStack = null;
0296: fNodeIndexStack = null;
0297: fPrevNodeIndexStack = null;
0298: } // startDTD(XMLLocator)
0299:
0300: // startExternalSubset(Augmentations)
0301:
0302: // endExternalSubset(Augmentations)
0303:
0304: /**
0305: * An element declaration.
0306: *
0307: * @param name The name of the element.
0308: * @param contentModel The element content model.
0309: * @param augs Additional information that may include infoset
0310: * augmentations.
0311: * @throws XNIException Thrown by handler to signal an error.
0312: */
0313: public void elementDecl(String name, String contentModel,
0314: Augmentations augs) throws XNIException {
0315:
0316: XMLElementDecl tmpElementDecl = (XMLElementDecl) fElementDeclTab
0317: .get(name);
0318: if (tmpElementDecl != null) {
0319: if (tmpElementDecl.type == -1) {
0320: fCurrentElementIndex = getElementDeclIndex(name);
0321: } else {
0322: // duplicate element, ignored.
0323: return;
0324: }
0325: } else {
0326: fCurrentElementIndex = createElementDecl();//create element decl
0327: }
0328:
0329: XMLElementDecl elementDecl = new XMLElementDecl();
0330: QName elementName = new QName(null, name, name, null);
0331:
0332: elementDecl.name.setValues(elementName);
0333: elementDecl.scope = -1;
0334: if (contentModel.equals("EMPTY")) {
0335: elementDecl.type = XMLElementDecl.TYPE_EMPTY;
0336: } else if (contentModel.equals("ANY")) {
0337: elementDecl.type = XMLElementDecl.TYPE_ANY;
0338: } else if (contentModel.startsWith("(")) {
0339: if (contentModel.indexOf("#PCDATA") > 0) {
0340: elementDecl.type = XMLElementDecl.TYPE_MIXED;
0341: } else {
0342: elementDecl.type = XMLElementDecl.TYPE_CHILDREN;
0343: }
0344: }
0345:
0346: //add(or set) this elementDecl to the local cache
0347: this .fElementDeclTab.put(name, elementDecl);
0348:
0349: fElementDecl = elementDecl;
0350:
0351: if (DEBUG) {
0352: System.out.println("name = " + fElementDecl.name.localpart);
0353: System.out.println("Type = " + fElementDecl.type);
0354: }
0355:
0356: setElementDecl(fCurrentElementIndex, fElementDecl);//set internal structure
0357:
0358: int chunk = fCurrentElementIndex >> CHUNK_SHIFT;
0359: int index = fCurrentElementIndex & CHUNK_MASK;
0360: ensureElementDeclCapacity(chunk);
0361:
0362: }
0363:
0364: /**
0365: * An attribute declaration.
0366: *
0367: * @param elementName The name of the element that this attribute
0368: * is associated with.
0369: * @param attributeName The name of the attribute.
0370: * @param type The attribute type. This value will be one of
0371: * the following: "CDATA", "ENTITY", "ENTITIES",
0372: * "ENUMERATION", "ID", "IDREF", "IDREFS",
0373: * "NMTOKEN", "NMTOKENS", or "NOTATION".
0374: * @param enumeration If the type has the value "ENUMERATION", this
0375: * array holds the allowed attribute values;
0376: * otherwise, this array is null.
0377: * @param defaultType The attribute default type. This value will be
0378: * one of the following: "#FIXED", "#IMPLIED",
0379: * "#REQUIRED", or null.
0380: * @param defaultValue The attribute default value, or null if no
0381: * default value is specified.
0382: * @param nonNormalizedDefaultValue The attribute default value with no normalization
0383: * performed, or null if no default value is specified.
0384: *
0385: * @param augs Additional information that may include infoset
0386: * augmentations.
0387: * @throws XNIException Thrown by handler to signal an error.
0388: */
0389: public void attributeDecl(String elementName, String attributeName,
0390: String type, String[] enumeration, String defaultType,
0391: XMLString defaultValue,
0392: XMLString nonNormalizedDefaultValue, Augmentations augs)
0393: throws XNIException {
0394:
0395: if (type != XMLSymbols.fCDATASymbol && defaultValue != null) {
0396: normalizeDefaultAttrValue(defaultValue);
0397: }
0398:
0399: if (this .fElementDeclTab.containsKey((String) elementName)) {
0400: //if ElementDecl has already being created in the Grammar then remove from table,
0401: //this.fElementDeclTab.remove( (String) elementName );
0402: }
0403: // then it is forward reference to a element decl, create the elementDecl first.
0404: else {
0405: fCurrentElementIndex = createElementDecl();//create element decl
0406:
0407: XMLElementDecl elementDecl = new XMLElementDecl();
0408: elementDecl.name.setValues(null, elementName, elementName,
0409: null);
0410:
0411: elementDecl.scope = -1;
0412:
0413: //add(or set) this elementDecl to the local cache
0414: this .fElementDeclTab.put(elementName, elementDecl);
0415:
0416: //set internal structure
0417: setElementDecl(fCurrentElementIndex, elementDecl);
0418: }
0419:
0420: //Get Grammar index to grammar array
0421: int elementIndex = getElementDeclIndex(elementName);
0422:
0423: //return, when more than one definition is provided for the same attribute of given element type
0424: //only the first declaration is binding and later declarations are ignored
0425: if (getAttributeDeclIndex(elementIndex, attributeName) != -1) {
0426: return;
0427: }
0428:
0429: fCurrentAttributeIndex = createAttributeDecl();// Create current Attribute Decl
0430:
0431: fSimpleType.clear();
0432: if (defaultType != null) {
0433: if (defaultType.equals("#FIXED")) {
0434: fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_FIXED;
0435: } else if (defaultType.equals("#IMPLIED")) {
0436: fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_IMPLIED;
0437: } else if (defaultType.equals("#REQUIRED")) {
0438: fSimpleType.defaultType = fSimpleType.DEFAULT_TYPE_REQUIRED;
0439: }
0440: }
0441: if (DEBUG) {
0442: System.out.println("defaultvalue = "
0443: + defaultValue.toString());
0444: }
0445: fSimpleType.defaultValue = defaultValue != null ? defaultValue
0446: .toString() : null;
0447: fSimpleType.nonNormalizedDefaultValue = nonNormalizedDefaultValue != null ? nonNormalizedDefaultValue
0448: .toString()
0449: : null;
0450: fSimpleType.enumeration = enumeration;
0451:
0452: if (type.equals("CDATA")) {
0453: fSimpleType.type = XMLSimpleType.TYPE_CDATA;
0454: } else if (type.equals("ID")) {
0455: fSimpleType.type = XMLSimpleType.TYPE_ID;
0456: } else if (type.startsWith("IDREF")) {
0457: fSimpleType.type = XMLSimpleType.TYPE_IDREF;
0458: if (type.indexOf("S") > 0) {
0459: fSimpleType.list = true;
0460: }
0461: } else if (type.equals("ENTITIES")) {
0462: fSimpleType.type = XMLSimpleType.TYPE_ENTITY;
0463: fSimpleType.list = true;
0464: } else if (type.equals("ENTITY")) {
0465: fSimpleType.type = XMLSimpleType.TYPE_ENTITY;
0466: } else if (type.equals("NMTOKENS")) {
0467: fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN;
0468: fSimpleType.list = true;
0469: } else if (type.equals("NMTOKEN")) {
0470: fSimpleType.type = XMLSimpleType.TYPE_NMTOKEN;
0471: } else if (type.startsWith("NOTATION")) {
0472: fSimpleType.type = XMLSimpleType.TYPE_NOTATION;
0473: } else if (type.startsWith("ENUMERATION")) {
0474: fSimpleType.type = XMLSimpleType.TYPE_ENUMERATION;
0475: } else {
0476: // REVISIT: Report error message. -Ac
0477: System.err.println("!!! unknown attribute type " + type);
0478: }
0479: // REVISIT: The datatype should be stored with the attribute value
0480: // and not special-cased in the XMLValidator. -Ac
0481: //fSimpleType.datatypeValidator = fDatatypeValidatorFactory.createDatatypeValidator(type, null, facets, fSimpleType.list);
0482:
0483: fQName.setValues(null, attributeName, attributeName, null);
0484: fAttributeDecl.setValues(fQName, fSimpleType, false);
0485:
0486: setAttributeDecl(elementIndex, fCurrentAttributeIndex,
0487: fAttributeDecl);
0488:
0489: int chunk = fCurrentAttributeIndex >> CHUNK_SHIFT;
0490: int index = fCurrentAttributeIndex & CHUNK_MASK;
0491: ensureAttributeDeclCapacity(chunk);
0492:
0493: } // attributeDecl(String,String,String,String[],String,XMLString,XMLString, Augmentations)
0494:
0495: /** Returns the symbol table. */
0496: public SymbolTable getSymbolTable() {
0497: return fSymbolTable;
0498: } // getSymbolTable():SymbolTable
0499:
0500: /**
0501: * Returns the index of the first element declaration. This index
0502: * is then used to query more information about the element declaration.
0503: *
0504: * @see #getNextElementDeclIndex
0505: * @see #getElementDecl
0506: */
0507: public int getFirstElementDeclIndex() {
0508: return fElementDeclCount >= 0 ? 0 : -1;
0509: } // getFirstElementDeclIndex():int
0510:
0511: /**
0512: * Returns the next index of the element declaration following the
0513: * specified element declaration.
0514: *
0515: * @param elementDeclIndex The element declaration index.
0516: */
0517: public int getNextElementDeclIndex(int elementDeclIndex) {
0518: return elementDeclIndex < fElementDeclCount - 1 ? elementDeclIndex + 1
0519: : -1;
0520: } // getNextElementDeclIndex(int):int
0521:
0522: /**
0523: * getElementDeclIndex
0524: *
0525: * @param elementDeclName
0526: *
0527: * @return index of the elementDeclName in scope
0528: */
0529: public int getElementDeclIndex(String elementDeclName) {
0530: int mapping = fElementIndexMap.get(elementDeclName);
0531: //System.out.println("getElementDeclIndex("+elementDeclName+") -> "+mapping);
0532: return mapping;
0533: } // getElementDeclIndex(String):int
0534:
0535: /** Returns the element decl index.
0536: * @param elementDeclQName qualilfied name of the element
0537: */
0538: public int getElementDeclIndex(QName elementDeclQName) {
0539: return getElementDeclIndex(elementDeclQName.rawname);
0540: } // getElementDeclIndex(QName):int
0541:
0542: /** make separate function for getting contentSpecType of element.
0543: * we can avoid setting of the element values.
0544: */
0545:
0546: public short getContentSpecType(int elementIndex) {
0547: if (elementIndex < 0 || elementIndex >= fElementDeclCount) {
0548: return -1;
0549: }
0550:
0551: int chunk = elementIndex >> CHUNK_SHIFT;
0552: int index = elementIndex & CHUNK_MASK;
0553:
0554: if (fElementDeclType[chunk][index] == -1) {
0555: return -1;
0556: } else {
0557: return (short) (fElementDeclType[chunk][index] & LIST_MASK);
0558: }
0559: }
0560:
0561: /**
0562: * getElementDecl
0563: *
0564: * @param elementDeclIndex
0565: * @param elementDecl The values of this structure are set by this call.
0566: *
0567: * @return True if find the element, False otherwise.
0568: */
0569: public boolean getElementDecl(int elementDeclIndex,
0570: XMLElementDecl elementDecl) {
0571:
0572: if (elementDeclIndex < 0
0573: || elementDeclIndex >= fElementDeclCount) {
0574: return false;
0575: }
0576:
0577: int chunk = elementDeclIndex >> CHUNK_SHIFT;
0578: int index = elementDeclIndex & CHUNK_MASK;
0579:
0580: elementDecl.name.setValues(fElementDeclName[chunk][index]);
0581:
0582: if (fElementDeclType[chunk][index] == -1) {
0583: elementDecl.type = -1;
0584: elementDecl.simpleType.list = false;
0585: } else {
0586: elementDecl.type = (short) (fElementDeclType[chunk][index] & LIST_MASK);
0587: elementDecl.simpleType.list = (fElementDeclType[chunk][index] & LIST_FLAG) != 0;
0588: }
0589:
0590: elementDecl.simpleType.defaultType = -1;
0591: elementDecl.simpleType.defaultValue = null;
0592: return true;
0593:
0594: }
0595:
0596: // REVISIT: Make this getAttributeDeclCount/getAttributeDeclAt. -Ac
0597:
0598: /**
0599: * getFirstAttributeDeclIndex
0600: *
0601: * @param elementDeclIndex
0602: *
0603: * @return index of the first attribute for element declaration elementDeclIndex
0604: */
0605: public int getFirstAttributeDeclIndex(int elementDeclIndex) {
0606: int chunk = elementDeclIndex >> CHUNK_SHIFT;
0607: int index = elementDeclIndex & CHUNK_MASK;
0608:
0609: return fElementDeclFirstAttributeDeclIndex[chunk][index];
0610: } // getFirstAttributeDeclIndex
0611:
0612: /**
0613: * getNextAttributeDeclIndex
0614: *
0615: * @param attributeDeclIndex
0616: *
0617: * @return index of the next attribute of the attribute at attributeDeclIndex
0618: */
0619: public int getNextAttributeDeclIndex(int attributeDeclIndex) {
0620: int chunk = attributeDeclIndex >> CHUNK_SHIFT;
0621: int index = attributeDeclIndex & CHUNK_MASK;
0622:
0623: return fAttributeDeclNextAttributeDeclIndex[chunk][index];
0624: }
0625:
0626: /**
0627: * getAttributeDecl
0628: *
0629: * @param attributeDeclIndex
0630: * @param attributeDecl The values of this structure are set by this call.
0631: *
0632: * @return true if getAttributeDecl was able to fill in the value of attributeDecl
0633: */
0634: public boolean getAttributeDecl(int attributeDeclIndex,
0635: XMLAttributeDecl attributeDecl) {
0636: if (attributeDeclIndex < 0
0637: || attributeDeclIndex >= fAttributeDeclCount) {
0638: return false;
0639: }
0640: int chunk = attributeDeclIndex >> CHUNK_SHIFT;
0641: int index = attributeDeclIndex & CHUNK_MASK;
0642:
0643: attributeDecl.name.setValues(fAttributeDeclName[chunk][index]);
0644:
0645: short attributeType;
0646: boolean isList;
0647:
0648: if (fAttributeDeclType[chunk][index] == -1) {
0649:
0650: attributeType = -1;
0651: isList = false;
0652: } else {
0653: attributeType = (short) (fAttributeDeclType[chunk][index] & LIST_MASK);
0654: isList = (fAttributeDeclType[chunk][index] & LIST_FLAG) != 0;
0655: }
0656: attributeDecl.simpleType.setValues(attributeType,
0657: fAttributeDeclName[chunk][index].localpart,
0658: fAttributeDeclEnumeration[chunk][index], isList,
0659: fAttributeDeclDefaultType[chunk][index],
0660: fAttributeDeclDefaultValue[chunk][index],
0661: fAttributeDeclNonNormalizedDefaultValue[chunk][index]);
0662: return true;
0663:
0664: } // getAttributeDecl
0665:
0666: /**
0667: * Returns whether the given attribute is of type CDATA or not
0668: *
0669: * @param elName The element name.
0670: * @param atName The attribute name.
0671: *
0672: * @return true if the attribute is of type CDATA
0673: */
0674: public boolean isCDATAAttribute(QName elName, QName atName) {
0675: int elDeclIdx = getElementDeclIndex(elName);
0676: int atDeclIdx = getAttributeDeclIndex(elDeclIdx, atName.rawname);
0677: if (getAttributeDecl(elDeclIdx, fAttributeDecl)
0678: && fAttributeDecl.simpleType.type != XMLSimpleType.TYPE_CDATA) {
0679: return false;
0680: }
0681: return true;
0682: }
0683:
0684: public void printElements() {
0685: int elementDeclIndex = 0;
0686: XMLElementDecl elementDecl = new XMLElementDecl();
0687: while (getElementDecl(elementDeclIndex++, elementDecl)) {
0688:
0689: System.out.println("element decl: " + elementDecl.name
0690: + ", " + elementDecl.name.rawname);
0691:
0692: }
0693: }
0694:
0695: public void printAttributes(int elementDeclIndex) {
0696: int attributeDeclIndex = getFirstAttributeDeclIndex(elementDeclIndex);
0697: System.out.print(elementDeclIndex);
0698: System.out.print(" [");
0699: while (attributeDeclIndex != -1) {
0700: System.out.print(' ');
0701: System.out.print(attributeDeclIndex);
0702: printAttribute(attributeDeclIndex);
0703: attributeDeclIndex = getNextAttributeDeclIndex(attributeDeclIndex);
0704: if (attributeDeclIndex != -1) {
0705: System.out.print(",");
0706: }
0707: }
0708: System.out.println(" ]");
0709: }
0710:
0711: protected int createElementDecl() {
0712: int chunk = fElementDeclCount >> CHUNK_SHIFT;
0713: int index = fElementDeclCount & CHUNK_MASK;
0714: ensureElementDeclCapacity(chunk);
0715: fElementDeclName[chunk][index] = new QName();
0716: fElementDeclType[chunk][index] = -1;
0717: fElementDeclFirstAttributeDeclIndex[chunk][index] = -1;
0718: fElementDeclLastAttributeDeclIndex[chunk][index] = -1;
0719: return fElementDeclCount++;
0720: }
0721:
0722: protected void setElementDecl(int elementDeclIndex,
0723: XMLElementDecl elementDecl) {
0724: if (elementDeclIndex < 0
0725: || elementDeclIndex >= fElementDeclCount) {
0726: return;
0727: }
0728: int chunk = elementDeclIndex >> CHUNK_SHIFT;
0729: int index = elementDeclIndex & CHUNK_MASK;
0730:
0731: int scope = elementDecl.scope;
0732:
0733: fElementDeclName[chunk][index].setValues(elementDecl.name);
0734: fElementDeclType[chunk][index] = elementDecl.type;
0735:
0736: if (elementDecl.simpleType.list == true) {
0737: fElementDeclType[chunk][index] |= LIST_FLAG;
0738: }
0739:
0740: fElementIndexMap
0741: .put(elementDecl.name.rawname, elementDeclIndex);
0742: }
0743:
0744: protected void setFirstAttributeDeclIndex(int elementDeclIndex,
0745: int newFirstAttrIndex) {
0746:
0747: if (elementDeclIndex < 0
0748: || elementDeclIndex >= fElementDeclCount) {
0749: return;
0750: }
0751:
0752: int chunk = elementDeclIndex >> CHUNK_SHIFT;
0753: int index = elementDeclIndex & CHUNK_MASK;
0754:
0755: fElementDeclFirstAttributeDeclIndex[chunk][index] = newFirstAttrIndex;
0756: }
0757:
0758: protected int createAttributeDecl() {
0759: int chunk = fAttributeDeclCount >> CHUNK_SHIFT;
0760: int index = fAttributeDeclCount & CHUNK_MASK;
0761:
0762: ensureAttributeDeclCapacity(chunk);
0763: fAttributeDeclName[chunk][index] = new QName();
0764: fAttributeDeclType[chunk][index] = -1;
0765: fAttributeDeclEnumeration[chunk][index] = null;
0766: fAttributeDeclDefaultType[chunk][index] = XMLSimpleType.DEFAULT_TYPE_IMPLIED;
0767: fAttributeDeclDefaultValue[chunk][index] = null;
0768: fAttributeDeclNonNormalizedDefaultValue[chunk][index] = null;
0769: fAttributeDeclNextAttributeDeclIndex[chunk][index] = -1;
0770: return fAttributeDeclCount++;
0771: }
0772:
0773: protected void setAttributeDecl(int elementDeclIndex,
0774: int attributeDeclIndex, XMLAttributeDecl attributeDecl) {
0775: int attrChunk = attributeDeclIndex >> CHUNK_SHIFT;
0776: int attrIndex = attributeDeclIndex & CHUNK_MASK;
0777: fAttributeDeclName[attrChunk][attrIndex]
0778: .setValues(attributeDecl.name);
0779: fAttributeDeclType[attrChunk][attrIndex] = attributeDecl.simpleType.type;
0780:
0781: if (attributeDecl.simpleType.list) {
0782: fAttributeDeclType[attrChunk][attrIndex] |= LIST_FLAG;
0783: }
0784: fAttributeDeclEnumeration[attrChunk][attrIndex] = attributeDecl.simpleType.enumeration;
0785: fAttributeDeclDefaultType[attrChunk][attrIndex] = attributeDecl.simpleType.defaultType;
0786:
0787: fAttributeDeclDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.defaultValue;
0788: fAttributeDeclNonNormalizedDefaultValue[attrChunk][attrIndex] = attributeDecl.simpleType.nonNormalizedDefaultValue;
0789:
0790: int elemChunk = elementDeclIndex >> CHUNK_SHIFT;
0791: int elemIndex = elementDeclIndex & CHUNK_MASK;
0792: int index = fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex];
0793: while (index != -1) {
0794: if (index == attributeDeclIndex) {
0795: break;
0796: }
0797: attrChunk = index >> CHUNK_SHIFT;
0798: attrIndex = index & CHUNK_MASK;
0799: index = fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex];
0800: }
0801: if (index == -1) {
0802: if (fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] == -1) {
0803: fElementDeclFirstAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex;
0804: } else {
0805: index = fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex];
0806: attrChunk = index >> CHUNK_SHIFT;
0807: attrIndex = index & CHUNK_MASK;
0808: fAttributeDeclNextAttributeDeclIndex[attrChunk][attrIndex] = attributeDeclIndex;
0809: }
0810: fElementDeclLastAttributeDeclIndex[elemChunk][elemIndex] = attributeDeclIndex;
0811: }
0812: }
0813:
0814: public void notationDecl(String name,
0815: XMLResourceIdentifier identifier, Augmentations augs)
0816: throws XNIException {
0817:
0818: XMLNotationDecl notationDecl = new XMLNotationDecl();
0819: notationDecl.setValues(name, identifier.getPublicId(),
0820: identifier.getLiteralSystemId(), identifier
0821: .getBaseSystemId());
0822: notationDecls.add(notationDecl);
0823: }
0824:
0825: public List getNotationDecls() {
0826: return notationDecls;
0827: }
0828:
0829: //
0830: // Private methods
0831: //
0832: private void printAttribute(int attributeDeclIndex) {
0833:
0834: XMLAttributeDecl attributeDecl = new XMLAttributeDecl();
0835: if (getAttributeDecl(attributeDeclIndex, attributeDecl)) {
0836: System.out.print(" { ");
0837: System.out.print(attributeDecl.name.localpart);
0838: System.out.print(" }");
0839: }
0840:
0841: } // printAttribute(int)
0842:
0843: private void ensureElementDeclCapacity(int chunk) {
0844: if (chunk >= fElementDeclName.length) {
0845:
0846: fElementDeclName = resize(fElementDeclName,
0847: fElementDeclName.length * 2);
0848: fElementDeclType = resize(fElementDeclType,
0849: fElementDeclType.length * 2);
0850: fElementDeclFirstAttributeDeclIndex = resize(
0851: fElementDeclFirstAttributeDeclIndex,
0852: fElementDeclFirstAttributeDeclIndex.length * 2);
0853: fElementDeclLastAttributeDeclIndex = resize(
0854: fElementDeclLastAttributeDeclIndex,
0855: fElementDeclLastAttributeDeclIndex.length * 2);
0856: } else if (fElementDeclName[chunk] != null) {
0857: return;
0858: }
0859:
0860: fElementDeclName[chunk] = new QName[CHUNK_SIZE];
0861: fElementDeclType[chunk] = new short[CHUNK_SIZE];
0862: fElementDeclFirstAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
0863: fElementDeclLastAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
0864: return;
0865: }
0866:
0867: private void ensureAttributeDeclCapacity(int chunk) {
0868:
0869: if (chunk >= fAttributeDeclName.length) {
0870: fAttributeDeclName = resize(fAttributeDeclName,
0871: fAttributeDeclName.length * 2);
0872: fAttributeDeclType = resize(fAttributeDeclType,
0873: fAttributeDeclType.length * 2);
0874: fAttributeDeclEnumeration = resize(
0875: fAttributeDeclEnumeration,
0876: fAttributeDeclEnumeration.length * 2);
0877: fAttributeDeclDefaultType = resize(
0878: fAttributeDeclDefaultType,
0879: fAttributeDeclDefaultType.length * 2);
0880: fAttributeDeclDefaultValue = resize(
0881: fAttributeDeclDefaultValue,
0882: fAttributeDeclDefaultValue.length * 2);
0883: fAttributeDeclNonNormalizedDefaultValue = resize(
0884: fAttributeDeclNonNormalizedDefaultValue,
0885: fAttributeDeclNonNormalizedDefaultValue.length * 2);
0886: fAttributeDeclNextAttributeDeclIndex = resize(
0887: fAttributeDeclNextAttributeDeclIndex,
0888: fAttributeDeclNextAttributeDeclIndex.length * 2);
0889: } else if (fAttributeDeclName[chunk] != null) {
0890: return;
0891: }
0892:
0893: fAttributeDeclName[chunk] = new QName[CHUNK_SIZE];
0894: fAttributeDeclType[chunk] = new short[CHUNK_SIZE];
0895: fAttributeDeclEnumeration[chunk] = new String[CHUNK_SIZE][];
0896: fAttributeDeclDefaultType[chunk] = new short[CHUNK_SIZE];
0897: fAttributeDeclDefaultValue[chunk] = new String[CHUNK_SIZE];
0898: fAttributeDeclNonNormalizedDefaultValue[chunk] = new String[CHUNK_SIZE];
0899: fAttributeDeclNextAttributeDeclIndex[chunk] = new int[CHUNK_SIZE];
0900: return;
0901: }
0902:
0903: // resize chunks
0904:
0905: private static byte[][] resize(byte array[][], int newsize) {
0906: byte newarray[][] = new byte[newsize][];
0907: System.arraycopy(array, 0, newarray, 0, array.length);
0908: return newarray;
0909: }
0910:
0911: private static short[][] resize(short array[][], int newsize) {
0912: short newarray[][] = new short[newsize][];
0913: System.arraycopy(array, 0, newarray, 0, array.length);
0914: return newarray;
0915: }
0916:
0917: private static int[][] resize(int array[][], int newsize) {
0918: int newarray[][] = new int[newsize][];
0919: System.arraycopy(array, 0, newarray, 0, array.length);
0920: return newarray;
0921: }
0922:
0923: private static Object[][] resize(Object array[][], int newsize) {
0924: Object newarray[][] = new Object[newsize][];
0925: System.arraycopy(array, 0, newarray, 0, array.length);
0926: return newarray;
0927: }
0928:
0929: private static QName[][] resize(QName array[][], int newsize) {
0930: QName newarray[][] = new QName[newsize][];
0931: System.arraycopy(array, 0, newarray, 0, array.length);
0932: return newarray;
0933: }
0934:
0935: private static String[][] resize(String array[][], int newsize) {
0936: String newarray[][] = new String[newsize][];
0937: System.arraycopy(array, 0, newarray, 0, array.length);
0938: return newarray;
0939: }
0940:
0941: private static String[][][] resize(String array[][][], int newsize) {
0942: String newarray[][][] = new String[newsize][][];
0943: System.arraycopy(array, 0, newarray, 0, array.length);
0944: return newarray;
0945: }
0946:
0947: //
0948: // Classes
0949: //
0950:
0951: /**
0952: * A simple Hashtable implementation that takes a tuple (String, String)
0953: * as the key and a int as value.
0954: *
0955: * @author Eric Ye, IBM
0956: * @author Andy Clark, IBM
0957: */
0958: protected static final class QNameHashtable {
0959:
0960: //
0961: // Constants
0962: //
0963: public static final boolean UNIQUE_STRINGS = true;
0964:
0965: /** Initial bucket size (4). */
0966: private static final int INITIAL_BUCKET_SIZE = 4;
0967:
0968: // NOTE: Changed previous hashtable size from 512 to 101 so
0969: // that we get a better distribution for hashing. -Ac
0970: /** Hashtable size (101). */
0971: private static final int HASHTABLE_SIZE = 101;
0972:
0973: //
0974: // Data
0975: //
0976: private Object[][] fHashTable = new Object[HASHTABLE_SIZE][];
0977:
0978: //
0979: // Public methods
0980: //
0981: /** Associates the given value with the specified key tuple. */
0982: public void put(String key, int value) {
0983:
0984: // REVISIT: Why +2? -Ac
0985: int hash = (hash(key) + 2) % HASHTABLE_SIZE;
0986: Object[] bucket = fHashTable[hash];
0987:
0988: if (bucket == null) {
0989: bucket = new Object[1 + 2 * INITIAL_BUCKET_SIZE];
0990: bucket[0] = new int[] { 1 };
0991: bucket[1] = key;
0992: bucket[2] = new int[] { value };
0993: fHashTable[hash] = bucket;
0994: } else {
0995: int count = ((int[]) bucket[0])[0];
0996: int offset = 1 + 2 * count;
0997: if (offset == bucket.length) {
0998: int newSize = count + INITIAL_BUCKET_SIZE;
0999: Object[] newBucket = new Object[1 + 2 * newSize];
1000: System.arraycopy(bucket, 0, newBucket, 0, offset);
1001: bucket = newBucket;
1002: fHashTable[hash] = bucket;
1003: }
1004: boolean found = false;
1005: int j = 1;
1006: for (int i = 0; i < count; i++) {
1007: if ((String) bucket[j] == key) {
1008: ((int[]) bucket[j + 1])[0] = value;
1009: found = true;
1010: break;
1011: }
1012: j += 2;
1013: }
1014: if (!found) {
1015: bucket[offset++] = key;
1016: bucket[offset] = new int[] { value };
1017: ((int[]) bucket[0])[0] = ++count;
1018: }
1019:
1020: }
1021: //System.out.println("put("+key+" -> "+value+')');
1022: //System.out.println("get("+key+") -> "+get(key));
1023:
1024: } // put(int,String,String,int)
1025:
1026: /** Returns the value associated with the specified key tuple. */
1027: public int get(String key) {
1028: int hash = (hash(key) + 2) % HASHTABLE_SIZE;
1029: Object[] bucket = fHashTable[hash];
1030:
1031: if (bucket == null) {
1032: return -1;
1033: }
1034: int count = ((int[]) bucket[0])[0];
1035:
1036: int j = 1;
1037: for (int i = 0; i < count; i++) {
1038: if ((String) bucket[j] == key) {
1039: return ((int[]) bucket[j + 1])[0];
1040: }
1041: j += 2;
1042: }
1043: return -1;
1044:
1045: } // get(int,String,String)
1046:
1047: //
1048: // Protected methods
1049: //
1050:
1051: /** Returns a hash value for the specified symbol. */
1052: protected int hash(String symbol) {
1053:
1054: if (symbol == null) {
1055: return 0;
1056: }
1057: int code = 0;
1058: int length = symbol.length();
1059: for (int i = 0; i < length; i++) {
1060: code = code * 37 + symbol.charAt(i);
1061: }
1062: return code & 0x7FFFFFF;
1063:
1064: } // hash(String):int
1065:
1066: } // class QNameHashtable
1067:
1068: /**
1069: * Normalize the attribute value of a non CDATA default attribute
1070: * collapsing sequences of space characters (x20)
1071: *
1072: * @param value The value to normalize
1073: * @return Whether the value was changed or not.
1074: */
1075: private boolean normalizeDefaultAttrValue(XMLString value) {
1076:
1077: int oldLength = value.length;
1078:
1079: boolean skipSpace = true; // skip leading spaces
1080: int current = value.offset;
1081: int end = value.offset + value.length;
1082: for (int i = value.offset; i < end; i++) {
1083: if (value.ch[i] == ' ') {
1084: if (!skipSpace) {
1085: // take the first whitespace as a space and skip the others
1086: value.ch[current++] = ' ';
1087: skipSpace = true;
1088: } else {
1089: // just skip it.
1090: }
1091: } else {
1092: // simply shift non space chars if needed
1093: if (current != i) {
1094: value.ch[current] = value.ch[i];
1095: }
1096: current++;
1097: skipSpace = false;
1098: }
1099: }
1100: if (current != end) {
1101: if (skipSpace) {
1102: // if we finished on a space trim it
1103: current--;
1104: }
1105: // set the new value length
1106: value.length = current - value.offset;
1107: return true;
1108: }
1109: return false;
1110: }
1111:
1112: public void endDTD(Augmentations augs) throws XNIException {
1113:
1114: }
1115: }
|