0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: *
0005: * Copyright (c) 1999,2000 The Apache Software Foundation. All rights
0006: * reserved.
0007: *
0008: * Redistribution and use in source and binary forms, with or without
0009: * modification, are permitted provided that the following conditions
0010: * are met:
0011: *
0012: * 1. Redistributions of source code must retain the above copyright
0013: * notice, this list of conditions and the following disclaimer.
0014: *
0015: * 2. Redistributions in binary form must reproduce the above copyright
0016: * notice, this list of conditions and the following disclaimer in
0017: * the documentation and/or other materials provided with the
0018: * distribution.
0019: *
0020: * 3. The end-user documentation included with the redistribution,
0021: * if any, must include the following acknowledgment:
0022: * "This product includes software developed by the
0023: * Apache Software Foundation (http://www.apache.org/)."
0024: * Alternately, this acknowledgment may appear in the software itself,
0025: * if and wherever such third-party acknowledgments normally appear.
0026: *
0027: * 4. The names "Xerces" and "Apache Software Foundation" must
0028: * not be used to endorse or promote products derived from this
0029: * software without prior written permission. For written
0030: * permission, please contact apache@apache.org.
0031: *
0032: * 5. Products derived from this software may not be called "Apache",
0033: * nor may "Apache" appear in their name, without prior written
0034: * permission of the Apache Software Foundation.
0035: *
0036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: * SUCH DAMAGE.
0048: * ====================================================================
0049: *
0050: * This software consists of voluntary contributions made by many
0051: * individuals on behalf of the Apache Software Foundation and was
0052: * originally based on software copyright (c) 1999, International
0053: * Business Machines, Inc., http://www.apache.org. For more
0054: * information on the Apache Software Foundation, please see
0055: * <http://www.apache.org/>.
0056: */
0057:
0058: package org.apache.xerces.framework;
0059:
0060: import org.apache.xerces.readers.XMLEntityHandler;
0061: import org.apache.xerces.readers.DefaultEntityHandler;
0062: import org.apache.xerces.utils.QName;
0063: import org.apache.xerces.utils.StringPool;
0064: import org.apache.xerces.utils.XMLCharacterProperties;
0065: import org.apache.xerces.utils.XMLMessages;
0066: import org.apache.xerces.validators.common.Grammar;
0067: import org.apache.xerces.validators.common.GrammarResolver;
0068: import org.apache.xerces.validators.common.XMLAttributeDecl;
0069: import org.apache.xerces.validators.common.XMLElementDecl;
0070: import org.apache.xerces.validators.dtd.DTDGrammar;
0071:
0072: import org.xml.sax.Locator;
0073: import org.xml.sax.SAXParseException;
0074:
0075: import java.util.StringTokenizer;
0076:
0077: /**
0078: * Default implementation of an XML DTD scanner.
0079: * <p>
0080: * Clients who wish to scan a DTD should implement
0081: * XMLDTDScanner.EventHandler to provide the desired behavior
0082: * when various DTD components are encountered.
0083: * <p>
0084: * To process the DTD, the client application should follow the
0085: * following sequence:
0086: * <ol>
0087: * <li>call scanDocTypeDecl() to scan the DOCTYPE declaration
0088: * <li>call getReadingExternalEntity() to determine if scanDocTypeDecl found an
0089: * external subset
0090: * <li>if scanning an external subset, call scanDecls(true) to process the external subset
0091: * </ol>
0092: *
0093: * @see XMLDTDScanner.EventHandler
0094: * @version $Id: XMLDTDScanner.java,v 1.19 2001/04/26 17:45:50 lmartin Exp $
0095: */
0096: public final class XMLDTDScanner {
0097: //
0098: // Constants
0099: //
0100: //
0101: // [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
0102: //
0103: private static final char[] version_string = { 'v', 'e', 'r', 's',
0104: 'i', 'o', 'n' };
0105: //
0106: // [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
0107: //
0108: private static final char[] element_string = { 'E', 'L', 'E', 'M',
0109: 'E', 'N', 'T' };
0110: //
0111: // [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
0112: //
0113: private static final char[] empty_string = { 'E', 'M', 'P', 'T',
0114: 'Y' };
0115: private static final char[] any_string = { 'A', 'N', 'Y' };
0116: //
0117: // [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
0118: // | '(' S? '#PCDATA' S? ')'
0119: //
0120: private static final char[] pcdata_string = { '#', 'P', 'C', 'D',
0121: 'A', 'T', 'A' };
0122: //
0123: // [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
0124: //
0125: private static final char[] attlist_string = { 'A', 'T', 'T', 'L',
0126: 'I', 'S', 'T' };
0127: //
0128: // [55] StringType ::= 'CDATA'
0129: //
0130: private static final char[] cdata_string = { 'C', 'D', 'A', 'T',
0131: 'A' };
0132: //
0133: // [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' | 'ENTITIES'
0134: // | 'NMTOKEN' | 'NMTOKENS'
0135: //
0136: // Note: We search for common substrings always trying to move forward
0137: //
0138: // 'ID' - Common prefix of ID, IDREF and IDREFS
0139: // 'REF' - Common substring of IDREF and IDREFS after matching ID prefix
0140: // 'ENTIT' - Common prefix of ENTITY and ENTITIES
0141: // 'IES' - Suffix of ENTITIES
0142: // 'NMTOKEN' - Common prefix of NMTOKEN and NMTOKENS
0143: //
0144: private static final char[] id_string = { 'I', 'D' };
0145: private static final char[] ref_string = { 'R', 'E', 'F' };
0146: private static final char[] entit_string = { 'E', 'N', 'T', 'I',
0147: 'T' };
0148: private static final char[] ies_string = { 'I', 'E', 'S' };
0149: private static final char[] nmtoken_string = { 'N', 'M', 'T', 'O',
0150: 'K', 'E', 'N' };
0151: //
0152: // [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
0153: // [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
0154: //
0155: private static final char[] notation_string = { 'N', 'O', 'T', 'A',
0156: 'T', 'I', 'O', 'N' };
0157: //
0158: // [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
0159: //
0160: private static final char[] required_string = { '#', 'R', 'E', 'Q',
0161: 'U', 'I', 'R', 'E', 'D' };
0162: private static final char[] implied_string = { '#', 'I', 'M', 'P',
0163: 'L', 'I', 'E', 'D' };
0164: private static final char[] fixed_string = { '#', 'F', 'I', 'X',
0165: 'E', 'D' };
0166: //
0167: // [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
0168: //
0169: private static final char[] include_string = { 'I', 'N', 'C', 'L',
0170: 'U', 'D', 'E' };
0171: //
0172: // [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
0173: //
0174: private static final char[] ignore_string = { 'I', 'G', 'N', 'O',
0175: 'R', 'E' };
0176: //
0177: // [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
0178: // [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
0179: //
0180: private static final char[] entity_string = { 'E', 'N', 'T', 'I',
0181: 'T', 'Y' };
0182: //
0183: // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
0184: // | 'PUBLIC' S PubidLiteral S SystemLiteral
0185: // [83] PublicID ::= 'PUBLIC' S PubidLiteral
0186: //
0187: private static final char[] system_string = { 'S', 'Y', 'S', 'T',
0188: 'E', 'M' };
0189: private static final char[] public_string = { 'P', 'U', 'B', 'L',
0190: 'I', 'C' };
0191: //
0192: // [76] NDataDecl ::= S 'NDATA' S Name
0193: //
0194: private static final char[] ndata_string = { 'N', 'D', 'A', 'T',
0195: 'A' };
0196: //
0197: // [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
0198: //
0199: private static final char[] encoding_string = { 'e', 'n', 'c', 'o',
0200: 'd', 'i', 'n', 'g' };
0201: //
0202: // Instance Variables
0203: //
0204: private DTDGrammar fDTDGrammar = null;
0205: private GrammarResolver fGrammarResolver = null;
0206: private boolean fNamespacesEnabled = false;
0207: private boolean fValidationEnabled = false;
0208: private boolean fLoadExternalDTD = true;
0209: private XMLElementDecl fTempElementDecl = new XMLElementDecl();
0210: private XMLAttributeDecl fTempAttributeDecl = new XMLAttributeDecl();
0211: private QName fElementQName = new QName();
0212: private QName fAttributeQName = new QName();
0213: private QName fElementRefQName = new QName();
0214: private EventHandler fEventHandler = null;
0215: private XMLDocumentHandler.DTDHandler fDTDHandler = null;
0216: private StringPool fStringPool = null;
0217: private XMLErrorReporter fErrorReporter = null;
0218: private XMLEntityHandler fEntityHandler = null;
0219: private XMLEntityHandler.EntityReader fEntityReader = null;
0220: private XMLEntityHandler.CharBuffer fLiteralData = null;
0221: private int fReaderId = -1;
0222: private int fSystemLiteral = -1;
0223: private int fPubidLiteral = -1;
0224: private int[] fOpStack = null;
0225: private int[] fNodeIndexStack = null;
0226: private int[] fPrevNodeIndexStack = null;
0227: private int fScannerState = SCANNER_STATE_INVALID;
0228: private int fIncludeSectDepth = 0;
0229: private int fDoctypeReader = -1;
0230: private int fExternalSubsetReader = -1;
0231: private int fDefaultAttValueReader = -1;
0232: private int fDefaultAttValueElementType = -1;
0233: private int fDefaultAttValueAttrName = -1;
0234: private int fDefaultAttValueOffset = -1;
0235: private int fDefaultAttValueMark = -1;
0236: private int fEntityValueReader = -1;
0237: private int fEntityValueMark = -1;
0238: private int fXMLSymbol = -1;
0239: private int fXMLNamespace = -1;
0240: private int fXMLSpace = -1;
0241: private int fDefault = -1;
0242: private int fPreserve = -1;
0243: private int fScannerMarkupDepth = 0;
0244: private int fScannerParenDepth = 0;
0245:
0246: //
0247: // Constructors
0248: //
0249: public XMLDTDScanner(StringPool stringPool,
0250: XMLErrorReporter errorReporter,
0251: XMLEntityHandler entityHandler,
0252: XMLEntityHandler.CharBuffer literalData) {
0253: fStringPool = stringPool;
0254: fErrorReporter = errorReporter;
0255: fEntityHandler = entityHandler;
0256: fLiteralData = literalData;
0257: init();
0258: }
0259:
0260: /**
0261: * Set the event handler
0262: *
0263: * @param eventHandler The place to send our callbacks.
0264: */
0265: public void setEventHandler(XMLDTDScanner.EventHandler eventHandler) {
0266: fEventHandler = eventHandler;
0267: }
0268:
0269: /** Set the DTD handler. */
0270: public void setDTDHandler(XMLDocumentHandler.DTDHandler dtdHandler) {
0271: fDTDHandler = dtdHandler;
0272: }
0273:
0274: /** Sets the grammar resolver. */
0275: public void setGrammarResolver(GrammarResolver resolver) {
0276: fGrammarResolver = resolver;
0277: }
0278:
0279: /** set fNamespacesEnabled **/
0280: public void setNamespacesEnabled(boolean enabled) {
0281: fNamespacesEnabled = enabled;
0282: }
0283:
0284: /** set fValidationEnabled **/
0285: public void setValidationEnabled(boolean enabled) {
0286: fValidationEnabled = enabled;
0287: }
0288:
0289: /** Sets whether the parser loads the external DTD. */
0290: public void setLoadExternalDTD(boolean enabled) {
0291: fLoadExternalDTD = enabled;
0292: }
0293:
0294: /**
0295: * Is the XMLDTDScanner reading from an external entity?
0296: *
0297: * This will be true, in particular if there was an external subset
0298: *
0299: * @return true if the XMLDTDScanner is reading from an external entity.
0300: */
0301: public boolean getReadingExternalEntity() {
0302: return fReaderId != fDoctypeReader;
0303: }
0304:
0305: /**
0306: * Is the scanner reading a ContentSpec?
0307: *
0308: * @return true if the scanner is reading a ContentSpec
0309: */
0310: public boolean getReadingContentSpec() {
0311: return getScannerState() == SCANNER_STATE_CONTENTSPEC;
0312: }
0313:
0314: /**
0315: * Report the markup nesting depth. This allows a client to
0316: * perform validation checks for correct markup nesting. This keeps
0317: * scanning and validation separate.
0318: *
0319: * @return the markup nesting depth
0320: */
0321: public int markupDepth() {
0322: return fScannerMarkupDepth;
0323: }
0324:
0325: private int increaseMarkupDepth() {
0326: return fScannerMarkupDepth++;
0327: }
0328:
0329: private int decreaseMarkupDepth() {
0330: return fScannerMarkupDepth--;
0331: }
0332:
0333: /**
0334: * Report the parenthesis nesting depth. This allows a client to
0335: * perform validation checks for correct parenthesis balancing. This keeps
0336: * scanning and validation separate.
0337: *
0338: * @return the parenthesis depth
0339: */
0340: public int parenDepth() {
0341: return fScannerParenDepth;
0342: }
0343:
0344: private void setParenDepth(int parenDepth) {
0345: fScannerParenDepth = parenDepth;
0346: }
0347:
0348: private void increaseParenDepth() {
0349: fScannerParenDepth++;
0350: }
0351:
0352: private void decreaseParenDepth() {
0353: fScannerParenDepth--;
0354: }
0355:
0356: //
0357: //
0358: //
0359: /**
0360: * Allow XMLDTDScanner to be reused. This method is called from an
0361: * XMLParser reset method, which passes the StringPool to be used
0362: * by the reset DTD scanner instance.
0363: *
0364: * @param stringPool the string pool to be used by XMLDTDScanner.
0365: */
0366: public void reset(StringPool stringPool,
0367: XMLEntityHandler.CharBuffer literalData) throws Exception {
0368: fStringPool = stringPool;
0369: fLiteralData = literalData;
0370: fEntityReader = null;
0371: fReaderId = -1;
0372: fSystemLiteral = -1;
0373: fPubidLiteral = -1;
0374: fOpStack = null;
0375: fNodeIndexStack = null;
0376: fPrevNodeIndexStack = null;
0377: fScannerState = SCANNER_STATE_INVALID;
0378: fIncludeSectDepth = 0;
0379: fDoctypeReader = -1;
0380: fExternalSubsetReader = -1;
0381: fDefaultAttValueReader = -1;
0382: fDefaultAttValueElementType = -1;
0383: fDefaultAttValueAttrName = -1;
0384: fDefaultAttValueOffset = -1;
0385: fDefaultAttValueMark = -1;
0386: fEntityValueReader = -1;
0387: fEntityValueMark = -1;
0388: fScannerMarkupDepth = 0;
0389: fScannerParenDepth = 0;
0390: init();
0391: }
0392:
0393: private void init() {
0394: fXMLSymbol = fStringPool.addSymbol("xml");
0395: fXMLNamespace = fStringPool
0396: .addSymbol("http://www.w3.org/XML/1998/namespace");
0397:
0398: fXMLSpace = fStringPool.addSymbol("xml:space");
0399: fDefault = fStringPool.addSymbol("default");
0400: fPreserve = fStringPool.addSymbol("preserve");
0401: }
0402:
0403: //
0404: // Interfaces
0405: //
0406:
0407: /**
0408: * This interface must be implemented by the users of the XMLDTDScanner class.
0409: * These methods form the abstraction between the implementation semantics and the
0410: * more generic task of scanning the DTD-specific XML grammar.
0411: */
0412: public interface EventHandler {
0413:
0414: /** Start of DTD. */
0415: public void callStartDTD() throws Exception;
0416:
0417: /** End of DTD. */
0418: public void callEndDTD() throws Exception;
0419:
0420: /**
0421: * Signal the Text declaration of an external entity.
0422: *
0423: * @param version the handle in the string pool for the version number
0424: * @param encoding the handle in the string pool for the encoding
0425: * @exception java.lang.Exception
0426: */
0427: public void callTextDecl(int version, int encoding)
0428: throws Exception;
0429:
0430: /**
0431: * Called when the doctype decl is scanned
0432: *
0433: * @param rootElementType handle of the rootElement
0434: * @param publicId StringPool handle of the public id
0435: * @param systemId StringPool handle of the system id
0436: * @exception java.lang.Exception
0437: */
0438: public void doctypeDecl(QName rootElement, int publicId,
0439: int systemId) throws Exception;
0440:
0441: /**
0442: * Called when the DTDScanner starts reading from the external subset
0443: *
0444: * @param publicId StringPool handle of the public id
0445: * @param systemId StringPool handle of the system id
0446: * @exception java.lang.Exception
0447: */
0448: public void startReadingFromExternalSubset(int publicId,
0449: int systemId) throws Exception;
0450:
0451: /**
0452: * Called when the DTDScanner stop reading from the external subset
0453: *
0454: * @exception java.lang.Exception
0455: */
0456: public void stopReadingFromExternalSubset() throws Exception;
0457:
0458: /**
0459: * Add an element declaration (forward reference)
0460: *
0461: * @param handle to the name of the element being declared
0462: * @return handle to the element whose declaration was added
0463: * @exception java.lang.Exception
0464: */
0465: public int addElementDecl(QName elementDecl) throws Exception;
0466:
0467: /**
0468: * Add an element declaration
0469: *
0470: * @param handle to the name of the element being declared
0471: * @param contentSpecType handle to the type name of the content spec
0472: * @param ContentSpec handle to the content spec node for the contentSpecType
0473: * @return handle to the element declaration that was added
0474: * @exception java.lang.Exception
0475: */
0476: public int addElementDecl(QName elementDecl,
0477: int contentSpecType, int contentSpec, boolean isExternal)
0478: throws Exception;
0479:
0480: /**
0481: * Add an attribute definition
0482: *
0483: * @param handle to the element whose attribute is being declared
0484: * @param attName StringPool handle to the attribute name being declared
0485: * @param attType type of the attribute
0486: * @param enumeration StringPool handle of the attribute's enumeration list (if any)
0487: * @param attDefaultType an integer value denoting the DefaultDecl value
0488: * @param attDefaultValue StringPool handle of this attribute's default value
0489: * @return handle to the attribute definition
0490: * @exception java.lang.Exception
0491: */
0492: public int addAttDef(QName elementDecl, QName attributeDecl,
0493: int attType, boolean attList, int enumeration,
0494: int attDefaultType, int attDefaultValue,
0495: boolean isExternal) throws Exception;
0496:
0497: /**
0498: * create an XMLContentSpec for a leaf
0499: *
0500: * @param nameIndex StringPool handle to the name (Element) for the node
0501: * @return handle to the newly create XMLContentSpec
0502: * @exception java.lang.Exception
0503: */
0504: public int addUniqueLeafNode(int nameIndex) throws Exception;
0505:
0506: /**
0507: * Create an XMLContentSpec for a single non-leaf
0508: *
0509: * @param nodeType the type of XMLContentSpec to create - from XMLContentSpec.CONTENTSPECNODE_*
0510: * @param nodeValue handle to an XMLContentSpec
0511: * @return handle to the newly create XMLContentSpec
0512: * @exception java.lang.Exception
0513: */
0514: public int addContentSpecNode(int nodeType, int nodeValue)
0515: throws Exception;
0516:
0517: /**
0518: * Create an XMLContentSpec for a two child leaf
0519: *
0520: * @param nodeType the type of XMLContentSpec to create - from XMLContentSpec.CONTENTSPECNODE_*
0521: * @param leftNodeIndex handle to an XMLContentSpec
0522: * @param rightNodeIndex handle to an XMLContentSpec
0523: * @return handle to the newly create XMLContentSpec
0524: * @exception java.lang.Exception
0525: */
0526: public int addContentSpecNode(int nodeType, int leftNodeIndex,
0527: int rightNodeIndex) throws Exception;
0528:
0529: /**
0530: * Create a string representation of an XMLContentSpec tree
0531: *
0532: * @param handle to an XMLContentSpec
0533: * @return String representation of the content spec tree
0534: * @exception java.lang.Exception
0535: */
0536: public String getContentSpecNodeAsString(int nodeIndex)
0537: throws Exception;
0538:
0539: /**
0540: * Start the scope of an entity declaration.
0541: *
0542: * @return <code>true</code> on success; otherwise
0543: * <code>false</code> if the entity declaration is recursive.
0544: * @exception java.lang.Exception
0545: */
0546: public boolean startEntityDecl(boolean isPE, int entityName)
0547: throws Exception;
0548:
0549: /**
0550: * End the scope of an entity declaration.
0551: * @exception java.lang.Exception
0552: */
0553: public void endEntityDecl() throws Exception;
0554:
0555: /**
0556: * Add a declaration for an internal parameter entity
0557: *
0558: * @param name StringPool handle of the parameter entity name
0559: * @param value StringPool handle of the parameter entity value
0560: * @return handle to the parameter entity declaration
0561: * @exception java.lang.Exception
0562: */
0563: public int addInternalPEDecl(int name, int value)
0564: throws Exception;
0565:
0566: /**
0567: * Add a declaration for an external parameter entity
0568: *
0569: * @param name StringPool handle of the parameter entity name
0570: * @param publicId StringPool handle of the publicId
0571: * @param systemId StringPool handle of the systemId
0572: * @return handle to the parameter entity declaration
0573: * @exception java.lang.Exception
0574: */
0575: public int addExternalPEDecl(int name, int publicId,
0576: int systemId) throws Exception;
0577:
0578: /**
0579: * Add a declaration for an internal entity
0580: *
0581: * @param name StringPool handle of the entity name
0582: * @param value StringPool handle of the entity value
0583: * @return handle to the entity declaration
0584: * @exception java.lang.Exception
0585: */
0586: public int addInternalEntityDecl(int name, int value)
0587: throws Exception;
0588:
0589: /**
0590: * Add a declaration for an entity
0591: *
0592: * @param name StringPool handle of the entity name
0593: * @param publicId StringPool handle of the publicId
0594: * @param systemId StringPool handle of the systemId
0595: * @return handle to the entity declaration
0596: * @exception java.lang.Exception
0597: */
0598: public int addExternalEntityDecl(int name, int publicId,
0599: int systemId) throws Exception;
0600:
0601: /**
0602: * Add a declaration for an unparsed entity
0603: *
0604: * @param name StringPool handle of the entity name
0605: * @param publicId StringPool handle of the publicId
0606: * @param systemId StringPool handle of the systemId
0607: * @param notationName StringPool handle of the notationName
0608: * @return handle to the entity declaration
0609: * @exception java.lang.Exception
0610: */
0611: public int addUnparsedEntityDecl(int name, int publicId,
0612: int systemId, int notationName) throws Exception;
0613:
0614: /**
0615: * Called when the scanner start scanning an enumeration
0616: * @return StringPool handle to a string list that will hold the enumeration names
0617: * @exception java.lang.Exception
0618: */
0619: public int startEnumeration() throws Exception;
0620:
0621: /**
0622: * Add a name to an enumeration
0623: * @param enumIndex StringPool handle to the string list for the enumeration
0624: * @param elementType handle to the element that owns the attribute with the enumeration
0625: * @param attrName StringPool handle to the name of the attribut with the enumeration
0626: * @param nameIndex StringPool handle to the name to be added to the enumeration
0627: * @param isNotationType true if the enumeration is an enumeration of NOTATION names
0628: * @exception java.lang.Exception
0629: */
0630: public void addNameToEnumeration(int enumIndex,
0631: int elementType, int attrName, int nameIndex,
0632: boolean isNotationType) throws Exception;
0633:
0634: /**
0635: * Finish processing an enumeration
0636: *
0637: * @param enumIndex handle to the string list which holds the enumeration to be finshed.
0638: * @exception java.lang.Exception
0639: */
0640: public void endEnumeration(int enumIndex) throws Exception;
0641:
0642: /**
0643: * Add a declaration for a notation
0644: *
0645: * @param notationName
0646: * @param publicId
0647: * @param systemId
0648: * @return handle to the notation declaration
0649: * @exception java.lang.Exception
0650: */
0651: public int addNotationDecl(int notationName, int publicId,
0652: int systemId) throws Exception;
0653:
0654: /**
0655: * Called when a comment has been scanned
0656: *
0657: * @param data StringPool handle of the comment text
0658: * @exception java.lang.Exception
0659: */
0660: public void callComment(int data) throws Exception;
0661:
0662: /**
0663: * Called when a processing instruction has been scanned
0664: * @param piTarget StringPool handle of the PI target
0665: * @param piData StringPool handle of the PI data
0666: * @exception java.lang.Exception
0667: */
0668: public void callProcessingInstruction(int piTarget, int piData)
0669: throws Exception;
0670:
0671: /**
0672: * Supports DOM Level 2 internalSubset additions.
0673: * Called when the internal subset is completely scanned.
0674: */
0675: public void internalSubset(int internalSubset) throws Exception;
0676: }
0677:
0678: //
0679: //
0680: //
0681:
0682: /** Report a recoverable xml error. */
0683: protected void reportRecoverableXMLError(int majorCode,
0684: int minorCode, int stringIndex1) throws Exception {
0685:
0686: Object[] args = { fStringPool.toString(stringIndex1) };
0687: fErrorReporter.reportError(fErrorReporter.getLocator(),
0688: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0689: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
0690:
0691: } // reportRecoverableXMLError(int,int,int)
0692:
0693: /** Report a recoverable xml error. */
0694: protected void reportRecoverableXMLError(int majorCode,
0695: int minorCode, String string1) throws Exception {
0696:
0697: Object[] args = { string1 };
0698: fErrorReporter.reportError(fErrorReporter.getLocator(),
0699: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0700: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
0701:
0702: } // reportRecoverableXMLError(int,int,String)
0703:
0704: /** Report a recoverable xml error. */
0705: protected void reportRecoverableXMLError(int majorCode,
0706: int minorCode, String string1, String string2)
0707: throws Exception {
0708:
0709: Object[] args = { string1, string2 };
0710: fErrorReporter.reportError(fErrorReporter.getLocator(),
0711: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0712: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
0713:
0714: } // reportRecoverableXMLError(int,int,String,String)
0715:
0716: private void reportFatalXMLError(int majorCode, int minorCode)
0717: throws Exception {
0718: fErrorReporter.reportError(fErrorReporter.getLocator(),
0719: XMLMessages.XML_DOMAIN, majorCode, minorCode, null,
0720: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0721: }
0722:
0723: private void reportFatalXMLError(int majorCode, int minorCode,
0724: int stringIndex1) throws Exception {
0725: Object[] args = { fStringPool.toString(stringIndex1) };
0726: fErrorReporter.reportError(fErrorReporter.getLocator(),
0727: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0728: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0729: }
0730:
0731: private void reportFatalXMLError(int majorCode, int minorCode,
0732: String string1) throws Exception {
0733: Object[] args = { string1 };
0734: fErrorReporter.reportError(fErrorReporter.getLocator(),
0735: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0736: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0737: }
0738:
0739: private void reportFatalXMLError(int majorCode, int minorCode,
0740: int stringIndex1, int stringIndex2) throws Exception {
0741: Object[] args = { fStringPool.toString(stringIndex1),
0742: fStringPool.toString(stringIndex2) };
0743: fErrorReporter.reportError(fErrorReporter.getLocator(),
0744: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0745: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0746: }
0747:
0748: private void reportFatalXMLError(int majorCode, int minorCode,
0749: String string1, String string2) throws Exception {
0750: Object[] args = { string1, string2 };
0751: fErrorReporter.reportError(fErrorReporter.getLocator(),
0752: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0753: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0754: }
0755:
0756: private void reportFatalXMLError(int majorCode, int minorCode,
0757: String string1, String string2, String string3)
0758: throws Exception {
0759: Object[] args = { string1, string2, string3 };
0760: fErrorReporter.reportError(fErrorReporter.getLocator(),
0761: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0762: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0763: }
0764:
0765: private void abortMarkup(int majorCode, int minorCode)
0766: throws Exception {
0767: reportFatalXMLError(majorCode, minorCode);
0768: skipPastEndOfCurrentMarkup();
0769: }
0770:
0771: private void abortMarkup(int majorCode, int minorCode,
0772: int stringIndex1) throws Exception {
0773: reportFatalXMLError(majorCode, minorCode, stringIndex1);
0774: skipPastEndOfCurrentMarkup();
0775: }
0776:
0777: private void abortMarkup(int majorCode, int minorCode,
0778: String string1) throws Exception {
0779: reportFatalXMLError(majorCode, minorCode, string1);
0780: skipPastEndOfCurrentMarkup();
0781: }
0782:
0783: private void abortMarkup(int majorCode, int minorCode,
0784: int stringIndex1, int stringIndex2) throws Exception {
0785: reportFatalXMLError(majorCode, minorCode, stringIndex1,
0786: stringIndex2);
0787: skipPastEndOfCurrentMarkup();
0788: }
0789:
0790: private void skipPastEndOfCurrentMarkup() throws Exception {
0791: fEntityReader.skipToChar('>');
0792: if (fEntityReader.lookingAtChar('>', true))
0793: decreaseMarkupDepth();
0794: }
0795:
0796: //
0797: //
0798: //
0799: static private final int SCANNER_STATE_INVALID = -1;
0800: static private final int SCANNER_STATE_END_OF_INPUT = 0;
0801: static private final int SCANNER_STATE_DOCTYPEDECL = 50;
0802: static private final int SCANNER_STATE_MARKUP_DECL = 51;
0803: static private final int SCANNER_STATE_TEXTDECL = 53;
0804: static private final int SCANNER_STATE_COMMENT = 54;
0805: static private final int SCANNER_STATE_PI = 55;
0806: static private final int SCANNER_STATE_DEFAULT_ATTRIBUTE_VALUE = 56;
0807: static private final int SCANNER_STATE_CONTENTSPEC = 57;
0808: static private final int SCANNER_STATE_ENTITY_VALUE = 58;
0809: static private final int SCANNER_STATE_SYSTEMLITERAL = 59;
0810: static private final int SCANNER_STATE_PUBIDLITERAL = 60;
0811:
0812: private int setScannerState(int scannerState) {
0813: int prevState = fScannerState;
0814: fScannerState = scannerState;
0815: return prevState;
0816: }
0817:
0818: private int getScannerState() {
0819: return fScannerState;
0820: }
0821:
0822: private void restoreScannerState(int scannerState) {
0823: if (fScannerState != SCANNER_STATE_END_OF_INPUT)
0824: fScannerState = scannerState;
0825: }
0826:
0827: /**
0828: * Change readers
0829: *
0830: * @param nextReader the new reader that the scanner will use
0831: * @param nextReaderId id of the reader to change to
0832: * @exception throws java.lang.Exception
0833: */
0834: public void readerChange(XMLEntityHandler.EntityReader nextReader,
0835: int nextReaderId) throws Exception {
0836: fEntityReader = nextReader;
0837: fReaderId = nextReaderId;
0838: if (fScannerState == SCANNER_STATE_DEFAULT_ATTRIBUTE_VALUE) {
0839: fDefaultAttValueOffset = fEntityReader.currentOffset();
0840: fDefaultAttValueMark = fDefaultAttValueOffset;
0841: } else if (fScannerState == SCANNER_STATE_ENTITY_VALUE) {
0842: fEntityValueMark = fEntityReader.currentOffset();
0843: }
0844: }
0845:
0846: /**
0847: * Handle the end of input
0848: *
0849: * @param entityName the handle in the string pool of the name of the entity which has reached end of input
0850: * @param moreToFollow if true, there is still input left to process in other readers
0851: * @exception java.lang.Exception
0852: */
0853: public void endOfInput(int entityNameIndex, boolean moreToFollow)
0854: throws Exception {
0855: if (fValidationEnabled) {
0856: int readerDepth = fEntityHandler.getReaderDepth();
0857: if (getReadingContentSpec()) {
0858: int parenDepth = parenDepth();
0859: if (readerDepth != parenDepth) {
0860: reportRecoverableXMLError(
0861: XMLMessages.MSG_IMPROPER_GROUP_NESTING,
0862: XMLMessages.VC_PROPER_GROUP_PE_NESTING,
0863: entityNameIndex);
0864: }
0865: } else {
0866: int markupDepth = markupDepth();
0867: if (readerDepth != markupDepth) {
0868: reportRecoverableXMLError(
0869: XMLMessages.MSG_IMPROPER_DECLARATION_NESTING,
0870: XMLMessages.VC_PROPER_DECLARATION_PE_NESTING,
0871: entityNameIndex);
0872: }
0873: }
0874: }
0875: //REVISIT, why are we doing this?
0876: moreToFollow = fReaderId != fExternalSubsetReader;
0877:
0878: // System.out.println("current Scanner state " + getScannerState() +","+ fScannerState + moreToFollow);
0879: switch (fScannerState) {
0880: case SCANNER_STATE_INVALID:
0881: throw new RuntimeException(
0882: "FWK004 XMLDTDScanner.endOfInput: cannot happen: 2"
0883: + "\n2");
0884: case SCANNER_STATE_END_OF_INPUT:
0885: break;
0886: case SCANNER_STATE_MARKUP_DECL:
0887: if (!moreToFollow && fIncludeSectDepth > 0) {
0888: reportFatalXMLError(
0889: XMLMessages.MSG_INCLUDESECT_UNTERMINATED,
0890: XMLMessages.P62_UNTERMINATED);
0891: }
0892: break;
0893: case SCANNER_STATE_DOCTYPEDECL:
0894: throw new RuntimeException(
0895: "FWK004 XMLDTDScanner.endOfInput: cannot happen: 2.5"
0896: + "\n2.5");
0897: // break;
0898: case SCANNER_STATE_TEXTDECL:
0899: // REVISIT reportFatalXMLError(XMLMessages.MSG_ATTVAL0);
0900: break;
0901: case SCANNER_STATE_SYSTEMLITERAL:
0902: if (!moreToFollow) {
0903: reportFatalXMLError(
0904: XMLMessages.MSG_SYSTEMID_UNTERMINATED,
0905: XMLMessages.P11_UNTERMINATED);
0906: } else {
0907: // REVISIT reportFatalXMLError(XMLMessages.MSG_ATTVAL0);
0908: }
0909: break;
0910: case SCANNER_STATE_PUBIDLITERAL:
0911: if (!moreToFollow) {
0912: reportFatalXMLError(
0913: XMLMessages.MSG_PUBLICID_UNTERMINATED,
0914: XMLMessages.P12_UNTERMINATED);
0915: } else {
0916: // REVISIT reportFatalXMLError(XMLMessages.MSG_ATTVAL0);
0917: }
0918: break;
0919: case SCANNER_STATE_COMMENT:
0920: if (!moreToFollow && !getReadingExternalEntity()) {
0921: reportFatalXMLError(
0922: XMLMessages.MSG_COMMENT_UNTERMINATED,
0923: XMLMessages.P15_UNTERMINATED);
0924: } else {
0925: //
0926: // REVISIT - HACK !!! code changed to pass incorrect OASIS test 'invalid--001'
0927: // Uncomment the next line to conform to the spec...
0928: //
0929: //reportFatalXMLError(XMLMessages.MSG_COMMENT_NOT_IN_ONE_ENTITY,
0930: // XMLMessages.P78_NOT_WELLFORMED);
0931: }
0932: break;
0933: case SCANNER_STATE_PI:
0934: if (!moreToFollow) {
0935: reportFatalXMLError(XMLMessages.MSG_PI_UNTERMINATED,
0936: XMLMessages.P16_UNTERMINATED);
0937: } else {
0938: reportFatalXMLError(
0939: XMLMessages.MSG_PI_NOT_IN_ONE_ENTITY,
0940: XMLMessages.P78_NOT_WELLFORMED);
0941: }
0942: break;
0943: case SCANNER_STATE_DEFAULT_ATTRIBUTE_VALUE:
0944: if (!moreToFollow) {
0945: reportFatalXMLError(
0946: XMLMessages.MSG_ATTRIBUTE_VALUE_UNTERMINATED,
0947: XMLMessages.P10_UNTERMINATED,
0948: fDefaultAttValueElementType,
0949: fDefaultAttValueAttrName);
0950: } else if (fReaderId == fDefaultAttValueReader) {
0951: // REVISIT reportFatalXMLError(XMLMessages.MSG_ATTVAL0);
0952: } else {
0953: fEntityReader.append(fLiteralData,
0954: fDefaultAttValueMark, fDefaultAttValueOffset
0955: - fDefaultAttValueMark);
0956: }
0957: break;
0958: case SCANNER_STATE_CONTENTSPEC:
0959: break;
0960: case SCANNER_STATE_ENTITY_VALUE:
0961: if (fReaderId == fEntityValueReader) {
0962: // REVISIT reportFatalXMLError(XMLMessages.MSG_ATTVAL0);
0963: } else {
0964: fEntityReader.append(fLiteralData, fEntityValueMark,
0965: fEntityReader.currentOffset()
0966: - fEntityValueMark);
0967: }
0968: break;
0969: default:
0970: throw new RuntimeException(
0971: "FWK004 XMLDTDScanner.endOfInput: cannot happen: 3"
0972: + "\n3");
0973: }
0974: if (!moreToFollow) {
0975: setScannerState(SCANNER_STATE_END_OF_INPUT);
0976: }
0977: }
0978:
0979: //
0980: // [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
0981: //
0982: private int scanCharRef() throws Exception {
0983: int valueOffset = fEntityReader.currentOffset();
0984: boolean hex = fEntityReader.lookingAtChar('x', true);
0985: int num = fEntityReader.scanCharRef(hex);
0986: if (num < 0) {
0987: switch (num) {
0988: case XMLEntityHandler.CHARREF_RESULT_SEMICOLON_REQUIRED:
0989: reportFatalXMLError(
0990: XMLMessages.MSG_SEMICOLON_REQUIRED_IN_CHARREF,
0991: XMLMessages.P66_SEMICOLON_REQUIRED);
0992: return -1;
0993: case XMLEntityHandler.CHARREF_RESULT_INVALID_CHAR:
0994: int majorCode = hex ? XMLMessages.MSG_HEXDIGIT_REQUIRED_IN_CHARREF
0995: : XMLMessages.MSG_DIGIT_REQUIRED_IN_CHARREF;
0996: int minorCode = hex ? XMLMessages.P66_HEXDIGIT_REQUIRED
0997: : XMLMessages.P66_DIGIT_REQUIRED;
0998: reportFatalXMLError(majorCode, minorCode);
0999: return -1;
1000: case XMLEntityHandler.CHARREF_RESULT_OUT_OF_RANGE:
1001: num = 0x110000; // this will cause the right error to be reported below...
1002: break;
1003: }
1004: }
1005: //
1006: // [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] // any Unicode character, excluding the
1007: // | [#xE000-#xFFFD] | [#x10000-#x10FFFF] // surrogate blocks, FFFE, and FFFF.
1008: //
1009: if (num < 0x20) {
1010: if (num == 0x09 || num == 0x0A || num == 0x0D) {
1011: return num;
1012: }
1013: } else if (num <= 0xD7FF
1014: || (num >= 0xE000 && (num <= 0xFFFD || (num >= 0x10000 && num <= 0x10FFFF)))) {
1015: return num;
1016: }
1017: int valueLength = fEntityReader.currentOffset() - valueOffset;
1018: reportFatalXMLError(XMLMessages.MSG_INVALID_CHARREF,
1019: XMLMessages.WFC_LEGAL_CHARACTER, fEntityReader
1020: .addString(valueOffset, valueLength));
1021: return -1;
1022: }
1023:
1024: //
1025: // From the standard:
1026: //
1027: // [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
1028: //
1029: // Called after scanning past '<!--'
1030: //
1031: private void scanComment() throws Exception {
1032: int commentOffset = fEntityReader.currentOffset();
1033: boolean sawDashDash = false;
1034: int previousState = setScannerState(SCANNER_STATE_COMMENT);
1035: while (fScannerState == SCANNER_STATE_COMMENT) {
1036: if (fEntityReader.lookingAtChar('-', false)) {
1037: int nextEndOffset = fEntityReader.currentOffset();
1038: int endOffset = 0;
1039: fEntityReader.lookingAtChar('-', true);
1040: int offset = fEntityReader.currentOffset();
1041: int count = 1;
1042: while (fEntityReader.lookingAtChar('-', true)) {
1043: count++;
1044: endOffset = nextEndOffset;
1045: nextEndOffset = offset;
1046: offset = fEntityReader.currentOffset();
1047: }
1048: if (count > 1) {
1049: if (fEntityReader.lookingAtChar('>', true)) {
1050: if (!sawDashDash && count > 2) {
1051: reportFatalXMLError(
1052: XMLMessages.MSG_DASH_DASH_IN_COMMENT,
1053: XMLMessages.P15_DASH_DASH);
1054: sawDashDash = true;
1055: }
1056: decreaseMarkupDepth();
1057: int comment = fEntityReader.addString(
1058: commentOffset, endOffset
1059: - commentOffset);
1060: fDTDGrammar.callComment(comment);
1061: if (fDTDHandler != null) {
1062: fDTDHandler.comment(comment);
1063: }
1064: restoreScannerState(previousState);
1065: return;
1066: } else if (!sawDashDash) {
1067: reportFatalXMLError(
1068: XMLMessages.MSG_DASH_DASH_IN_COMMENT,
1069: XMLMessages.P15_DASH_DASH);
1070: sawDashDash = true;
1071: }
1072: }
1073: } else {
1074: if (!fEntityReader.lookingAtValidChar(true)) {
1075: int invChar = fEntityReader.scanInvalidChar();
1076: if (fScannerState != SCANNER_STATE_END_OF_INPUT) {
1077: if (invChar >= 0) {
1078: reportFatalXMLError(
1079: XMLMessages.MSG_INVALID_CHAR_IN_COMMENT,
1080: XMLMessages.P15_INVALID_CHARACTER,
1081: Integer.toHexString(invChar));
1082: }
1083: }
1084: }
1085: }
1086: }
1087: restoreScannerState(previousState);
1088: }
1089:
1090: //
1091: // From the standard:
1092: //
1093: // [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
1094: // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
1095: //
1096: private void scanPI(int piTarget) throws Exception {
1097: String piTargetString = fStringPool.toString(piTarget);
1098: if (piTargetString.length() == 3
1099: && (piTargetString.charAt(0) == 'X' || piTargetString
1100: .charAt(0) == 'x')
1101: && (piTargetString.charAt(1) == 'M' || piTargetString
1102: .charAt(1) == 'm')
1103: && (piTargetString.charAt(2) == 'L' || piTargetString
1104: .charAt(2) == 'l')) {
1105: abortMarkup(XMLMessages.MSG_RESERVED_PITARGET,
1106: XMLMessages.P17_RESERVED_PITARGET);
1107: return;
1108: }
1109: int prevState = setScannerState(SCANNER_STATE_PI);
1110: int piDataOffset = -1;
1111: int piDataLength = 0;
1112: if (!fEntityReader.lookingAtSpace(true)) {
1113: if (!fEntityReader.lookingAtChar('?', true)
1114: || !fEntityReader.lookingAtChar('>', true)) {
1115: if (fScannerState != SCANNER_STATE_END_OF_INPUT) {
1116: abortMarkup(XMLMessages.MSG_SPACE_REQUIRED_IN_PI,
1117: XMLMessages.P16_WHITESPACE_REQUIRED);
1118: restoreScannerState(prevState);
1119: }
1120: return;
1121: }
1122: decreaseMarkupDepth();
1123: restoreScannerState(prevState);
1124: } else {
1125: fEntityReader.skipPastSpaces();
1126: piDataOffset = fEntityReader.currentOffset();
1127: while (fScannerState == SCANNER_STATE_PI) {
1128: while (fEntityReader.lookingAtChar('?', false)) {
1129: int offset = fEntityReader.currentOffset();
1130: fEntityReader.lookingAtChar('?', true);
1131: if (fEntityReader.lookingAtChar('>', true)) {
1132: piDataLength = offset - piDataOffset;
1133: decreaseMarkupDepth();
1134: restoreScannerState(prevState);
1135: break;
1136: }
1137: }
1138: if (fScannerState != SCANNER_STATE_PI)
1139: break;
1140: if (!fEntityReader.lookingAtValidChar(true)) {
1141: int invChar = fEntityReader.scanInvalidChar();
1142: if (fScannerState != SCANNER_STATE_END_OF_INPUT) {
1143: if (invChar >= 0) {
1144: reportFatalXMLError(
1145: XMLMessages.MSG_INVALID_CHAR_IN_PI,
1146: XMLMessages.P16_INVALID_CHARACTER,
1147: Integer.toHexString(invChar));
1148: }
1149: skipPastEndOfCurrentMarkup();
1150: restoreScannerState(prevState);
1151: }
1152: return;
1153: }
1154: }
1155: }
1156: int piData = piDataLength == 0 ? StringPool.EMPTY_STRING
1157: : fEntityReader.addString(piDataOffset, piDataLength);
1158: fDTDGrammar.callProcessingInstruction(piTarget, piData);
1159: if (fDTDHandler != null) {
1160: fDTDHandler.processingInstruction(piTarget, piData);
1161: }
1162: }
1163:
1164: //
1165: // From the standard:
1166: //
1167: // [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
1168: // ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
1169: // [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl
1170: // | NotationDecl | PI | Comment
1171: //
1172: // Called after scanning '<!DOCTYPE'
1173: //
1174: /**
1175: * This routine is called after the <!DOCTYPE portion of a DOCTYPE
1176: * line has been called. scanDocTypeDecl goes onto scan the rest of the DOCTYPE
1177: * decl. If an internal DTD subset exists, it is scanned. If an external DTD
1178: * subset exists, scanDocTypeDecl sets up the state necessary to process it.
1179: *
1180: * @return true if successful
1181: * @exception java.lang.Exception
1182: */
1183: public boolean scanDoctypeDecl() throws Exception {
1184: //System.out.println("XMLDTDScanner#scanDoctypeDecl()");
1185:
1186: fDTDGrammar = new DTDGrammar(fStringPool);
1187: fDTDGrammar.callStartDTD();
1188: increaseMarkupDepth();
1189: fEntityReader = fEntityHandler.getEntityReader();
1190: fReaderId = fEntityHandler.getReaderId();
1191: fDoctypeReader = fReaderId;
1192: setScannerState(SCANNER_STATE_DOCTYPEDECL);
1193: if (!fEntityReader.lookingAtSpace(true)) {
1194: abortMarkup(
1195: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_ROOT_ELEMENT_TYPE_IN_DOCTYPEDECL,
1196: XMLMessages.P28_SPACE_REQUIRED);
1197: return false;
1198: }
1199: fEntityReader.skipPastSpaces();
1200: scanElementType(fEntityReader, ' ', fElementQName);
1201: if (fElementQName.rawname == -1) {
1202: abortMarkup(XMLMessages.MSG_ROOT_ELEMENT_TYPE_REQUIRED,
1203: XMLMessages.P28_ROOT_ELEMENT_TYPE_REQUIRED);
1204: return false;
1205: }
1206: boolean lbrkt;
1207: boolean scanExternalSubset = false;
1208: int publicId = -1;
1209: int systemId = -1;
1210: if (fEntityReader.lookingAtSpace(true)) {
1211: fEntityReader.skipPastSpaces();
1212: if (!(lbrkt = fEntityReader.lookingAtChar('[', true))
1213: && !fEntityReader.lookingAtChar('>', false)) {
1214: if (!scanExternalID(false)) {
1215: skipPastEndOfCurrentMarkup();
1216: return false;
1217: }
1218: if (fValidationEnabled || fLoadExternalDTD) {
1219: scanExternalSubset = true;
1220: }
1221: publicId = fPubidLiteral;
1222: systemId = fSystemLiteral;
1223: fEntityReader.skipPastSpaces();
1224: lbrkt = fEntityReader.lookingAtChar('[', true);
1225: }
1226: } else
1227: lbrkt = fEntityReader.lookingAtChar('[', true);
1228: fDTDGrammar.doctypeDecl(fElementQName, publicId, systemId);
1229: if (fDTDHandler != null) {
1230: fDTDHandler.startDTD(fElementQName, publicId, systemId);
1231: }
1232: if (lbrkt) {
1233: scanDecls(false);
1234: fEntityReader.skipPastSpaces();
1235: }
1236: if (!fEntityReader.lookingAtChar('>', true)) {
1237: if (fScannerState != SCANNER_STATE_END_OF_INPUT) {
1238: abortMarkup(XMLMessages.MSG_DOCTYPEDECL_UNTERMINATED,
1239: XMLMessages.P28_UNTERMINATED,
1240: fElementQName.rawname);
1241: }
1242: return false;
1243: }
1244:
1245: decreaseMarkupDepth();
1246:
1247: //System.out.println(" scanExternalSubset: "+scanExternalSubset);
1248: if (scanExternalSubset) {
1249: ((DefaultEntityHandler) fEntityHandler)
1250: .startReadingFromExternalSubset(fStringPool
1251: .toString(publicId), fStringPool
1252: .toString(systemId), markupDepth());
1253: fDTDGrammar.startReadingFromExternalSubset(publicId,
1254: systemId);
1255: } else {
1256: fDTDGrammar.callEndDTD();
1257: if (fDTDHandler != null) {
1258: fDTDHandler.endDTD();
1259: }
1260: }
1261:
1262: fGrammarResolver.putGrammar("", fDTDGrammar);
1263:
1264: return true;
1265: }
1266:
1267: //
1268: // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1269: // | 'PUBLIC' S PubidLiteral S SystemLiteral
1270: // [83] PublicID ::= 'PUBLIC' S PubidLiteral
1271: //
1272: private boolean scanExternalID(boolean scanPublicID)
1273: throws Exception {
1274: fSystemLiteral = -1;
1275: fPubidLiteral = -1;
1276: int offset = fEntityReader.currentOffset();
1277: if (fEntityReader.skippedString(system_string)) {
1278: if (!fEntityReader.lookingAtSpace(true)) {
1279: reportFatalXMLError(
1280: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_SYSTEMLITERAL_IN_EXTERNALID,
1281: XMLMessages.P75_SPACE_REQUIRED);
1282: return false;
1283: }
1284: fEntityReader.skipPastSpaces();
1285: if (getReadingExternalEntity() == true) { //Are we in external subset?
1286: checkForPEReference(false);//If so Check for PE Ref
1287: }
1288: return scanSystemLiteral();
1289: }
1290: if (fEntityReader.skippedString(public_string)) {
1291: if (!fEntityReader.lookingAtSpace(true)) {
1292: reportFatalXMLError(
1293: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_PUBIDLITERAL_IN_EXTERNALID,
1294: XMLMessages.P75_SPACE_REQUIRED);
1295: return false;
1296: }
1297: fEntityReader.skipPastSpaces();
1298: if (!scanPubidLiteral())
1299: return false;
1300: if (scanPublicID) {
1301: //
1302: // [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
1303: //
1304: if (!fEntityReader.lookingAtSpace(true))
1305: return true; // no S, not an ExternalID
1306: fEntityReader.skipPastSpaces();
1307: if (fEntityReader.lookingAtChar('>', false)) // matches end of NotationDecl
1308: return true;
1309: } else {
1310: if (!fEntityReader.lookingAtSpace(true)) {
1311: reportFatalXMLError(
1312: XMLMessages.MSG_SPACE_REQUIRED_AFTER_PUBIDLITERAL_IN_EXTERNALID,
1313: XMLMessages.P75_SPACE_REQUIRED);
1314: return false;
1315: }
1316: fEntityReader.skipPastSpaces();
1317: }
1318: return scanSystemLiteral();
1319: }
1320: reportFatalXMLError(XMLMessages.MSG_EXTERNALID_REQUIRED,
1321: XMLMessages.P75_INVALID);
1322: return false;
1323: }
1324:
1325: //
1326: // [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
1327: //
1328: // REVISIT - need to look into uri escape mechanism for non-ascii characters.
1329: //
1330: private boolean scanSystemLiteral() throws Exception {
1331: boolean single;
1332: if (!(single = fEntityReader.lookingAtChar('\'', true))
1333: && !fEntityReader.lookingAtChar('\"', true)) {
1334: reportFatalXMLError(
1335: XMLMessages.MSG_QUOTE_REQUIRED_IN_SYSTEMID,
1336: XMLMessages.P11_QUOTE_REQUIRED);
1337: return false;
1338: }
1339: int prevState = setScannerState(SCANNER_STATE_SYSTEMLITERAL);
1340: int offset = fEntityReader.currentOffset();
1341: char qchar = single ? '\'' : '\"';
1342: boolean dataok = true;
1343: boolean fragment = false;
1344: while (!fEntityReader.lookingAtChar(qchar, false)) {
1345: //ericye
1346: //System.out.println("XMLDTDScanner#scanDoctypeDecl() 3333333, "+fReaderId+", " + fScannerState+", " +fExternalSubsetReader);
1347: if (fEntityReader.lookingAtChar('#', true)) {
1348: fragment = true;
1349: } else if (!fEntityReader.lookingAtValidChar(true)) {
1350: //System.out.println("XMLDTDScanner#scanDoctypeDecl() 555555 scan state: " + fScannerState);
1351: dataok = false;
1352: int invChar = fEntityReader.scanInvalidChar();
1353: if (fScannerState == SCANNER_STATE_END_OF_INPUT)
1354: return false;
1355: if (invChar >= 0) {
1356: reportFatalXMLError(
1357: XMLMessages.MSG_INVALID_CHAR_IN_SYSTEMID,
1358: XMLMessages.P11_INVALID_CHARACTER, Integer
1359: .toHexString(invChar));
1360: }
1361: }
1362: }
1363: if (dataok) {
1364: fSystemLiteral = fEntityReader.addString(offset,
1365: fEntityReader.currentOffset() - offset);
1366: if (fragment) {
1367: // NOTE: RECOVERABLE ERROR
1368: Object[] args = { fStringPool.toString(fSystemLiteral) };
1369: fErrorReporter.reportError(fErrorReporter.getLocator(),
1370: XMLMessages.XML_DOMAIN,
1371: XMLMessages.MSG_URI_FRAGMENT_IN_SYSTEMID,
1372: XMLMessages.P11_URI_FRAGMENT, args,
1373: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1374: }
1375: }
1376: fEntityReader.lookingAtChar(qchar, true);
1377: restoreScannerState(prevState);
1378: return dataok;
1379: }
1380:
1381: //
1382: // [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1383: // [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
1384: //
1385: private boolean scanPubidLiteral() throws Exception {
1386: boolean single;
1387: if (!(single = fEntityReader.lookingAtChar('\'', true))
1388: && !fEntityReader.lookingAtChar('\"', true)) {
1389: reportFatalXMLError(
1390: XMLMessages.MSG_QUOTE_REQUIRED_IN_PUBLICID,
1391: XMLMessages.P12_QUOTE_REQUIRED);
1392: return false;
1393: }
1394: char qchar = single ? '\'' : '\"';
1395: int prevState = setScannerState(SCANNER_STATE_PUBIDLITERAL);
1396: boolean dataok = true;
1397: while (true) {
1398: if (fEntityReader.lookingAtChar((char) 0x09, true)) {
1399: dataok = false;
1400: reportFatalXMLError(XMLMessages.MSG_PUBIDCHAR_ILLEGAL,
1401: XMLMessages.P12_INVALID_CHARACTER, "9");
1402: }
1403: if (!fEntityReader.lookingAtSpace(true))
1404: break;
1405: }
1406: int offset = fEntityReader.currentOffset();
1407: int dataOffset = fLiteralData.length();
1408: int toCopy = offset;
1409: while (true) {
1410: if (fEntityReader.lookingAtChar(qchar, true)) {
1411: if (dataok && offset - toCopy > 0)
1412: fEntityReader.append(fLiteralData, toCopy, offset
1413: - toCopy);
1414: break;
1415: }
1416: if (fEntityReader.lookingAtChar((char) 0x09, true)) {
1417: dataok = false;
1418: reportFatalXMLError(XMLMessages.MSG_PUBIDCHAR_ILLEGAL,
1419: XMLMessages.P12_INVALID_CHARACTER, "9");
1420: continue;
1421: }
1422: if (fEntityReader.lookingAtSpace(true)) {
1423: if (dataok && offset - toCopy > 0)
1424: fEntityReader.append(fLiteralData, toCopy, offset
1425: - toCopy);
1426: while (true) {
1427: if (fEntityReader.lookingAtChar((char) 0x09, true)) {
1428: dataok = false;
1429: reportFatalXMLError(
1430: XMLMessages.MSG_PUBIDCHAR_ILLEGAL,
1431: XMLMessages.P12_INVALID_CHARACTER, "9");
1432: break;
1433: } else if (!fEntityReader.lookingAtSpace(true)) {
1434: break;
1435: }
1436: }
1437: if (fEntityReader.lookingAtChar(qchar, true))
1438: break;
1439: if (dataok) {
1440: fLiteralData.append(' ');
1441: offset = fEntityReader.currentOffset();
1442: toCopy = offset;
1443: }
1444: continue;
1445: }
1446: if (!fEntityReader.lookingAtValidChar(true)) {
1447: int invChar = fEntityReader.scanInvalidChar();
1448: if (fScannerState == SCANNER_STATE_END_OF_INPUT)
1449: return false;
1450: dataok = false;
1451: if (invChar >= 0) {
1452: reportFatalXMLError(
1453: XMLMessages.MSG_INVALID_CHAR_IN_PUBLICID,
1454: XMLMessages.P12_INVALID_CHARACTER, Integer
1455: .toHexString(invChar));
1456: }
1457: }
1458: if (dataok)
1459: offset = fEntityReader.currentOffset();
1460: }
1461: if (dataok) {
1462: int dataLength = fLiteralData.length() - dataOffset;
1463: fPubidLiteral = fLiteralData.addString(dataOffset,
1464: dataLength);
1465: String publicId = fStringPool.toString(fPubidLiteral);
1466: int invCharIndex = validPublicId(publicId);
1467: if (invCharIndex >= 0) {
1468: reportFatalXMLError(XMLMessages.MSG_PUBIDCHAR_ILLEGAL,
1469: XMLMessages.P12_INVALID_CHARACTER, Integer
1470: .toHexString(publicId
1471: .charAt(invCharIndex)));
1472: return false;
1473: }
1474: }
1475: restoreScannerState(prevState);
1476: return dataok;
1477: }
1478:
1479: //
1480: // [??] intSubsetDecl = '[' (markupdecl | PEReference | S)* ']'
1481: //
1482: // [31] extSubsetDecl ::= ( markupdecl | conditionalSect | PEReference | S )*
1483: // [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1484: //
1485: // [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl
1486: // | NotationDecl | PI | Comment
1487: //
1488: // [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
1489: //
1490: // [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
1491: //
1492: // [70] EntityDecl ::= GEDecl | PEDecl
1493: // [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
1494: // [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
1495: //
1496: // [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
1497: //
1498: // [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
1499: //
1500: // [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
1501: //
1502: // [61] conditionalSect ::= includeSect | ignoreSect
1503: // [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1504: // [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
1505: // [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
1506: // [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
1507: //
1508: /**
1509: * Scan markup declarations
1510: *
1511: * @param extSubset true if the scanner is scanning an external subset, false
1512: * if it is scanning an internal subset
1513: * @exception java.lang.Exception
1514: */
1515: public void scanDecls(boolean extSubset) throws Exception {
1516: int subsetOffset = fEntityReader.currentOffset();
1517: if (extSubset)
1518: fExternalSubsetReader = fReaderId;
1519: fIncludeSectDepth = 0;
1520: boolean parseTextDecl = extSubset;
1521: int prevState = setScannerState(SCANNER_STATE_MARKUP_DECL);
1522: while (fScannerState == SCANNER_STATE_MARKUP_DECL) {
1523:
1524: boolean newParseTextDecl = false;
1525: if (fEntityReader.lookingAtChar(']', false)
1526: && !getReadingExternalEntity()) {
1527: int subsetLength = fEntityReader.currentOffset()
1528: - subsetOffset;
1529: int internalSubset = fEntityReader.addString(
1530: subsetOffset, subsetLength);
1531: fDTDGrammar.internalSubset(internalSubset);
1532: if (fDTDHandler != null) {
1533: fDTDHandler.internalSubset(internalSubset);
1534: }
1535: fEntityReader.lookingAtChar(']', true);
1536: restoreScannerState(prevState);
1537: return;
1538: }
1539: if (fEntityReader.lookingAtChar('<', true)) {
1540: int olddepth = markupDepth();
1541: increaseMarkupDepth();
1542: if (fEntityReader.lookingAtChar('!', true)) {
1543: if (fEntityReader.lookingAtChar('-', true)) {
1544: if (fEntityReader.lookingAtChar('-', true)) {
1545: scanComment();
1546: } else {
1547: abortMarkup(
1548: XMLMessages.MSG_MARKUP_NOT_RECOGNIZED_IN_DTD,
1549: XMLMessages.P29_NOT_RECOGNIZED);
1550: }
1551: } else if (fEntityReader.lookingAtChar('[', true)
1552: && getReadingExternalEntity()) {
1553: checkForPEReference(false);
1554: if (fEntityReader.skippedString(include_string)) {
1555: checkForPEReference(false);
1556: if (!fEntityReader.lookingAtChar('[', true)) {
1557: abortMarkup(
1558: XMLMessages.MSG_MARKUP_NOT_RECOGNIZED_IN_DTD,
1559: XMLMessages.P29_NOT_RECOGNIZED);
1560: } else {
1561: fIncludeSectDepth++;
1562: }
1563: } else if (fEntityReader
1564: .skippedString(ignore_string)) {
1565: checkForPEReference(false);
1566: if (!fEntityReader.lookingAtChar('[', true)) {
1567: abortMarkup(
1568: XMLMessages.MSG_MARKUP_NOT_RECOGNIZED_IN_DTD,
1569: XMLMessages.P29_NOT_RECOGNIZED);
1570: } else
1571: scanIgnoreSectContents();
1572: } else {
1573: abortMarkup(
1574: XMLMessages.MSG_MARKUP_NOT_RECOGNIZED_IN_DTD,
1575: XMLMessages.P29_NOT_RECOGNIZED);
1576: }
1577: } else if (fEntityReader
1578: .skippedString(element_string)) {
1579: scanElementDecl();
1580: } else if (fEntityReader
1581: .skippedString(attlist_string))
1582: scanAttlistDecl();
1583: else if (fEntityReader.skippedString(entity_string))
1584: scanEntityDecl();
1585: else if (fEntityReader
1586: .skippedString(notation_string))
1587: scanNotationDecl();
1588: else {
1589: abortMarkup(
1590: XMLMessages.MSG_MARKUP_NOT_RECOGNIZED_IN_DTD,
1591: XMLMessages.P29_NOT_RECOGNIZED);
1592: }
1593: } else if (fEntityReader.lookingAtChar('?', true)) {
1594: int piTarget = fEntityReader.scanName(' ');
1595: if (piTarget == -1) {
1596: abortMarkup(XMLMessages.MSG_PITARGET_REQUIRED,
1597: XMLMessages.P16_REQUIRED);
1598: } else if ("xml".equals(fStringPool
1599: .toString(piTarget))) {
1600: if (fEntityReader.lookingAtSpace(true)) {
1601: if (parseTextDecl) { // a TextDecl looks like a PI with the target 'xml'
1602: scanTextDecl();
1603: } else {
1604: abortMarkup(
1605: XMLMessages.MSG_TEXTDECL_MUST_BE_FIRST,
1606: XMLMessages.P30_TEXTDECL_MUST_BE_FIRST);
1607: }
1608: } else { // a PI target matching 'xml'
1609: abortMarkup(
1610: XMLMessages.MSG_RESERVED_PITARGET,
1611: XMLMessages.P17_RESERVED_PITARGET);
1612: }
1613: } else
1614: // PI
1615: scanPI(piTarget);
1616: } else {
1617: abortMarkup(
1618: XMLMessages.MSG_MARKUP_NOT_RECOGNIZED_IN_DTD,
1619: XMLMessages.P29_NOT_RECOGNIZED);
1620: }
1621: } else if (fEntityReader.lookingAtSpace(true)) {
1622: fEntityReader.skipPastSpaces();
1623: } else if (fEntityReader.lookingAtChar('%', true)) {
1624: //
1625: // [69] PEReference ::= '%' Name ';'
1626: //
1627: int nameOffset = fEntityReader.currentOffset();
1628: fEntityReader.skipPastName(';');
1629: int nameLength = fEntityReader.currentOffset()
1630: - nameOffset;
1631: if (nameLength == 0) {
1632: reportFatalXMLError(
1633: XMLMessages.MSG_NAME_REQUIRED_IN_PEREFERENCE,
1634: XMLMessages.P69_NAME_REQUIRED);
1635: } else if (!fEntityReader.lookingAtChar(';', true)) {
1636: reportFatalXMLError(
1637: XMLMessages.MSG_SEMICOLON_REQUIRED_IN_PEREFERENCE,
1638: XMLMessages.P69_SEMICOLON_REQUIRED,
1639: fEntityReader.addString(nameOffset,
1640: nameLength));
1641: } else {
1642: int peNameIndex = fEntityReader.addSymbol(
1643: nameOffset, nameLength);
1644: newParseTextDecl = fEntityHandler
1645: .startReadingFromEntity(
1646: peNameIndex,
1647: markupDepth(),
1648: XMLEntityHandler.ENTITYREF_IN_DTD_AS_MARKUP);
1649: }
1650: } else if (fIncludeSectDepth > 0
1651: && fEntityReader.lookingAtChar(']', true)) {
1652: if (!fEntityReader.lookingAtChar(']', true)
1653: || !fEntityReader.lookingAtChar('>', true)) {
1654: abortMarkup(
1655: XMLMessages.MSG_INCLUDESECT_UNTERMINATED,
1656: XMLMessages.P62_UNTERMINATED);
1657: } else
1658: decreaseMarkupDepth();
1659: fIncludeSectDepth--;
1660: } else {
1661: if (!fEntityReader.lookingAtValidChar(false)) {
1662: int invChar = fEntityReader.scanInvalidChar();
1663: if (fScannerState == SCANNER_STATE_END_OF_INPUT)
1664: break;
1665: if (invChar >= 0) {
1666: if (!extSubset) {
1667: reportFatalXMLError(
1668: XMLMessages.MSG_INVALID_CHAR_IN_INTERNAL_SUBSET,
1669: XMLMessages.P28_INVALID_CHARACTER,
1670: Integer.toHexString(invChar));
1671: } else {
1672: reportFatalXMLError(
1673: XMLMessages.MSG_INVALID_CHAR_IN_EXTERNAL_SUBSET,
1674: XMLMessages.P30_INVALID_CHARACTER,
1675: Integer.toHexString(invChar));
1676: }
1677: }
1678: } else {
1679: reportFatalXMLError(
1680: XMLMessages.MSG_MARKUP_NOT_RECOGNIZED_IN_DTD,
1681: XMLMessages.P29_NOT_RECOGNIZED);
1682: fEntityReader.lookingAtValidChar(true);
1683: }
1684: }
1685: parseTextDecl = newParseTextDecl;
1686: }
1687: if (extSubset) {
1688:
1689: ((DefaultEntityHandler) fEntityHandler)
1690: .stopReadingFromExternalSubset();
1691:
1692: fDTDGrammar.stopReadingFromExternalSubset();
1693: fDTDGrammar.callEndDTD();
1694: if (fDTDHandler != null) {
1695: fDTDHandler.endDTD();
1696: }
1697: // REVISIT: What should the namspace URI of a DTD be?
1698: fGrammarResolver.putGrammar("", fDTDGrammar);
1699: }
1700: }
1701:
1702: //
1703: // [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
1704: // [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
1705: //
1706: private void scanIgnoreSectContents() throws Exception {
1707: int initialDepth = ++fIncludeSectDepth;
1708: while (true) {
1709: if (fEntityReader.lookingAtChar('<', true)) {
1710: //
1711: // These tests are split so that we handle cases like
1712: // '<<![' and '<!<![' which we might otherwise miss.
1713: //
1714: if (fEntityReader.lookingAtChar('!', true)
1715: && fEntityReader.lookingAtChar('[', true))
1716: fIncludeSectDepth++;
1717: } else if (fEntityReader.lookingAtChar(']', true)) {
1718: //
1719: // The same thing goes for ']<![' and '<]]>', etc.
1720: //
1721: if (fEntityReader.lookingAtChar(']', true)) {
1722: while (fEntityReader.lookingAtChar(']', true)) {
1723: /* empty loop body */
1724: }
1725: if (fEntityReader.lookingAtChar('>', true)) {
1726: if (fIncludeSectDepth-- == initialDepth) {
1727: decreaseMarkupDepth();
1728: return;
1729: }
1730: }
1731: }
1732: } else if (!fEntityReader.lookingAtValidChar(true)) {
1733: int invChar = fEntityReader.scanInvalidChar();
1734: if (fScannerState == SCANNER_STATE_END_OF_INPUT)
1735: return;
1736: if (invChar >= 0) {
1737: reportFatalXMLError(
1738: XMLMessages.MSG_INVALID_CHAR_IN_IGNORESECT,
1739: XMLMessages.P65_INVALID_CHARACTER, Integer
1740: .toHexString(invChar));
1741: }
1742: }
1743: }
1744: }
1745:
1746: //
1747: // From the standard:
1748: //
1749: // [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
1750: // [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
1751: // [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
1752: // [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
1753: //
1754: private void scanTextDecl() throws Exception {
1755: int version = -1;
1756: int encoding = -1;
1757: final int TEXTDECL_START = 0;
1758: final int TEXTDECL_VERSION = 1;
1759: final int TEXTDECL_ENCODING = 2;
1760: final int TEXTDECL_FINISHED = 3;
1761: int prevState = setScannerState(SCANNER_STATE_TEXTDECL);
1762: int state = TEXTDECL_START;
1763: do {
1764: fEntityReader.skipPastSpaces();
1765: int offset = fEntityReader.currentOffset();
1766: if (state == TEXTDECL_START
1767: && fEntityReader.skippedString(version_string)) {
1768: state = TEXTDECL_VERSION;
1769: } else if (fEntityReader.skippedString(encoding_string)) {
1770: state = TEXTDECL_ENCODING;
1771: } else {
1772: abortMarkup(XMLMessages.MSG_ENCODINGDECL_REQUIRED,
1773: XMLMessages.P77_ENCODINGDECL_REQUIRED);
1774: restoreScannerState(prevState);
1775: return;
1776: }
1777: int length = fEntityReader.currentOffset() - offset;
1778: fEntityReader.skipPastSpaces();
1779: if (!fEntityReader.lookingAtChar('=', true)) {
1780: int minorCode = state == TEXTDECL_VERSION ? XMLMessages.P24_EQ_REQUIRED
1781: : XMLMessages.P80_EQ_REQUIRED;
1782: abortMarkup(XMLMessages.MSG_EQ_REQUIRED_IN_TEXTDECL,
1783: minorCode, fEntityReader.addString(offset,
1784: length));
1785: restoreScannerState(prevState);
1786: return;
1787: }
1788: fEntityReader.skipPastSpaces();
1789: int result = fEntityReader.scanStringLiteral();
1790: switch (result) {
1791: case XMLEntityHandler.STRINGLIT_RESULT_QUOTE_REQUIRED: {
1792: int minorCode = state == TEXTDECL_VERSION ? XMLMessages.P24_QUOTE_REQUIRED
1793: : XMLMessages.P80_QUOTE_REQUIRED;
1794: abortMarkup(XMLMessages.MSG_QUOTE_REQUIRED_IN_TEXTDECL,
1795: minorCode, fEntityReader.addString(offset,
1796: length));
1797: restoreScannerState(prevState);
1798: return;
1799: }
1800: case XMLEntityHandler.STRINGLIT_RESULT_INVALID_CHAR:
1801: int invChar = fEntityReader.scanInvalidChar();
1802: if (fScannerState != SCANNER_STATE_END_OF_INPUT) {
1803: if (invChar >= 0) {
1804: int minorCode = state == TEXTDECL_VERSION ? XMLMessages.P26_INVALID_CHARACTER
1805: : XMLMessages.P81_INVALID_CHARACTER;
1806: reportFatalXMLError(
1807: XMLMessages.MSG_INVALID_CHAR_IN_TEXTDECL,
1808: minorCode, Integer.toHexString(invChar));
1809: }
1810: skipPastEndOfCurrentMarkup();
1811: restoreScannerState(prevState);
1812: }
1813: return;
1814: default:
1815: break;
1816: }
1817: switch (state) {
1818: case TEXTDECL_VERSION:
1819: //
1820: // version="..."
1821: //
1822: version = result;
1823: String versionString = fStringPool.toString(version);
1824: if (!"1.0".equals(versionString)) {
1825: if (!validVersionNum(versionString)) {
1826: abortMarkup(
1827: XMLMessages.MSG_VERSIONINFO_INVALID,
1828: XMLMessages.P26_INVALID_VALUE,
1829: versionString);
1830: restoreScannerState(prevState);
1831: return;
1832: }
1833: // NOTE: RECOVERABLE ERROR
1834: Object[] args = { versionString };
1835: fErrorReporter
1836: .reportError(
1837: fErrorReporter.getLocator(),
1838: XMLMessages.XML_DOMAIN,
1839: XMLMessages.MSG_VERSION_NOT_SUPPORTED,
1840: XMLMessages.P26_NOT_SUPPORTED,
1841: args,
1842: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1843: // REVISIT - hope it is a compatible version...
1844: // skipPastEndOfCurrentMarkup();
1845: // return;
1846: }
1847: if (!fEntityReader.lookingAtSpace(true)) {
1848: abortMarkup(
1849: XMLMessages.MSG_SPACE_REQUIRED_IN_TEXTDECL,
1850: XMLMessages.P80_WHITESPACE_REQUIRED);
1851: restoreScannerState(prevState);
1852: return;
1853: }
1854: break;
1855: case TEXTDECL_ENCODING:
1856: //
1857: // encoding = "..."
1858: //
1859: encoding = result;
1860: String encodingString = fStringPool.toString(encoding);
1861: if (!validEncName(encodingString)) {
1862: abortMarkup(XMLMessages.MSG_ENCODINGDECL_INVALID,
1863: XMLMessages.P81_INVALID_VALUE,
1864: encodingString);
1865: restoreScannerState(prevState);
1866: return;
1867: }
1868: fEntityReader.skipPastSpaces();
1869: state = TEXTDECL_FINISHED;
1870: break;
1871: }
1872: } while (state != TEXTDECL_FINISHED);
1873: if (!fEntityReader.lookingAtChar('?', true)
1874: || !fEntityReader.lookingAtChar('>', true)) {
1875: abortMarkup(XMLMessages.MSG_TEXTDECL_UNTERMINATED,
1876: XMLMessages.P77_UNTERMINATED);
1877: restoreScannerState(prevState);
1878: return;
1879: }
1880: decreaseMarkupDepth();
1881: fDTDGrammar.callTextDecl(version, encoding);
1882: if (fDTDHandler != null) {
1883: fDTDHandler.textDecl(version, encoding);
1884: }
1885: restoreScannerState(prevState);
1886: }
1887:
1888: private QName fElementDeclQName = new QName();
1889:
1890: /**
1891: * Scans an element declaration.
1892: * <pre>
1893: * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
1894: * </pre>
1895: */
1896: private void scanElementDecl() throws Exception {
1897:
1898: if (!checkForPEReference(true)) {
1899: abortMarkup(
1900: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL,
1901: XMLMessages.P45_SPACE_REQUIRED);
1902: return;
1903: }
1904: checkForElementTypeWithPEReference(fEntityReader, ' ',
1905: fElementQName);
1906: if (fElementQName.rawname == -1) {
1907: abortMarkup(
1908: XMLMessages.MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL,
1909: XMLMessages.P45_ELEMENT_TYPE_REQUIRED);
1910: return;
1911: }
1912: if (fDTDHandler != null) {
1913: fElementDeclQName.setValues(fElementQName);
1914: }
1915: if (!checkForPEReference(true)) {
1916: abortMarkup(
1917: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL,
1918: XMLMessages.P45_SPACE_REQUIRED,
1919: fElementQName.rawname);
1920: return;
1921: }
1922: int contentSpecType = -1;
1923: int contentSpec = -1;
1924: if (fEntityReader.skippedString(empty_string)) {
1925: contentSpecType = XMLElementDecl.TYPE_EMPTY;
1926: } else if (fEntityReader.skippedString(any_string)) {
1927: contentSpecType = XMLElementDecl.TYPE_ANY;
1928: } else if (!fEntityReader.lookingAtChar('(', true)) {
1929: abortMarkup(
1930: XMLMessages.MSG_CONTENTSPEC_REQUIRED_IN_ELEMENTDECL,
1931: XMLMessages.P45_CONTENTSPEC_REQUIRED,
1932: fElementQName.rawname);
1933: return;
1934: } else {
1935: int contentSpecReader = fReaderId;
1936: int contentSpecReaderDepth = fEntityHandler
1937: .getReaderDepth();
1938: int prevState = setScannerState(SCANNER_STATE_CONTENTSPEC);
1939: int oldDepth = parenDepth();
1940: fEntityHandler.setReaderDepth(oldDepth);
1941: increaseParenDepth();
1942: checkForPEReference(false);
1943: boolean skippedPCDATA = fEntityReader
1944: .skippedString(pcdata_string);
1945: if (skippedPCDATA) {
1946: contentSpecType = XMLElementDecl.TYPE_MIXED_SIMPLE;
1947: // REVISIT: Validation. Should we pass in QName?
1948: contentSpec = scanMixed(fElementQName);
1949: } else {
1950: contentSpecType = XMLElementDecl.TYPE_CHILDREN;
1951: // REVISIT: Validation. Should we pass in QName?
1952: contentSpec = scanChildren(fElementQName);
1953: }
1954: boolean success = contentSpec != -1;
1955: restoreScannerState(prevState);
1956: fEntityHandler.setReaderDepth(contentSpecReaderDepth);
1957: if (!success) {
1958: setParenDepth(oldDepth);
1959: skipPastEndOfCurrentMarkup();
1960: return;
1961: } else {
1962: if (parenDepth() != oldDepth) // REVISIT - should not be needed
1963: // System.out.println("nesting depth mismatch");
1964: ;
1965: }
1966: }
1967: checkForPEReference(false);
1968: if (!fEntityReader.lookingAtChar('>', true)) {
1969: abortMarkup(XMLMessages.MSG_ELEMENTDECL_UNTERMINATED,
1970: XMLMessages.P45_UNTERMINATED, fElementQName.rawname);
1971: return;
1972: }
1973: decreaseMarkupDepth();
1974: int elementIndex = fDTDGrammar.getElementDeclIndex(
1975: fElementQName, -1);
1976: boolean elementDeclIsExternal = getReadingExternalEntity();
1977: if (elementIndex == -1) {
1978: elementIndex = fDTDGrammar
1979: .addElementDecl(fElementQName, contentSpecType,
1980: contentSpec, elementDeclIsExternal);
1981: //System.out.println("XMLDTDScanner#scanElementDecl->DTDGrammar#addElementDecl: "+elementIndex+" ("+fElementQName.localpart+","+fStringPool.toString(fElementQName.localpart)+')');
1982: } else {
1983: //now check if we already add this element Decl by foward reference
1984: fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl);
1985: if (fTempElementDecl.type == -1) {
1986: fTempElementDecl.type = contentSpecType;
1987: fTempElementDecl.contentSpecIndex = contentSpec;
1988: fDTDGrammar.setElementDeclDTD(elementIndex,
1989: fTempElementDecl);
1990: fDTDGrammar.setElementDeclIsExternal(elementIndex,
1991: elementDeclIsExternal);
1992: } else {
1993: //REVISIT, valiate VC duplicate element type.
1994: if (fValidationEnabled)
1995: //&&
1996: // (elemenetDeclIsExternal==fDTDGrammar.getElementDeclIsExternal(elementIndex)
1997: {
1998:
1999: reportRecoverableXMLError(
2000: XMLMessages.MSG_ELEMENT_ALREADY_DECLARED,
2001: XMLMessages.VC_UNIQUE_ELEMENT_TYPE_DECLARATION,
2002: fStringPool.toString(fElementQName.rawname));
2003: }
2004: }
2005: }
2006: if (fDTDHandler != null) {
2007: fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl);
2008: fDTDHandler.elementDecl(fElementDeclQName, contentSpecType,
2009: contentSpec, fDTDGrammar);
2010: }
2011:
2012: } // scanElementDecl()
2013:
2014: /**
2015: * Scans mixed content model. Called after scanning past '(' S? '#PCDATA'
2016: * <pre>
2017: * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')'
2018: * </pre>
2019: */
2020: private int scanMixed(QName element) throws Exception {
2021:
2022: int valueIndex = -1; // -1 is special value for #PCDATA
2023: int prevNodeIndex = -1;
2024: boolean starRequired = false;
2025: int[] valueSeen = new int[32];
2026: int valueCount = 0;
2027: boolean dupAttrType = false;
2028: int nodeIndex = -1;
2029:
2030: while (true) {
2031: if (fValidationEnabled) {
2032: for (int i = 0; i < valueCount; i++) {
2033: if (valueSeen[i] == valueIndex) {
2034: dupAttrType = true;
2035: break;
2036: }
2037: }
2038: }
2039: if (dupAttrType && fValidationEnabled) {
2040: reportRecoverableXMLError(
2041: XMLMessages.MSG_DUPLICATE_TYPE_IN_MIXED_CONTENT,
2042: XMLMessages.VC_NO_DUPLICATE_TYPES, valueIndex);
2043: dupAttrType = false;
2044:
2045: } else {
2046: try {
2047: valueSeen[valueCount] = valueIndex;
2048: } catch (ArrayIndexOutOfBoundsException ae) {
2049: int[] newArray = new int[valueSeen.length * 2];
2050: System.arraycopy(valueSeen, 0, newArray, 0,
2051: valueSeen.length);
2052: valueSeen = newArray;
2053: valueSeen[valueCount] = valueIndex;
2054: }
2055: valueCount++;
2056:
2057: nodeIndex = fDTDGrammar.addUniqueLeafNode(valueIndex);
2058: }
2059:
2060: checkForPEReference(false);
2061: if (!fEntityReader.lookingAtChar('|', true)) {
2062: if (!fEntityReader.lookingAtChar(')', true)) {
2063: reportFatalXMLError(
2064: XMLMessages.MSG_CLOSE_PAREN_REQUIRED_IN_MIXED,
2065: XMLMessages.P51_CLOSE_PAREN_REQUIRED,
2066: element.rawname);
2067: return -1;
2068: }
2069: decreaseParenDepth();
2070: if (nodeIndex == -1) {
2071: nodeIndex = prevNodeIndex;
2072: } else if (prevNodeIndex != -1) {
2073: nodeIndex = fDTDGrammar.addContentSpecNode(
2074: XMLContentSpec.CONTENTSPECNODE_CHOICE,
2075: prevNodeIndex, nodeIndex);
2076: }
2077: if (fEntityReader.lookingAtChar('*', true)) {
2078: nodeIndex = fDTDGrammar
2079: .addContentSpecNode(
2080: XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE,
2081: nodeIndex);
2082: } else if (starRequired) {
2083: reportFatalXMLError(
2084: XMLMessages.MSG_MIXED_CONTENT_UNTERMINATED,
2085: XMLMessages.P51_UNTERMINATED,
2086: fStringPool.toString(element.rawname),
2087: fDTDGrammar
2088: .getContentSpecNodeAsString(nodeIndex));
2089: return -1;
2090: }
2091: return nodeIndex;
2092: }
2093: if (nodeIndex != -1) {
2094: if (prevNodeIndex != -1) {
2095: nodeIndex = fDTDGrammar.addContentSpecNode(
2096: XMLContentSpec.CONTENTSPECNODE_CHOICE,
2097: prevNodeIndex, nodeIndex);
2098: }
2099: prevNodeIndex = nodeIndex;
2100: }
2101: starRequired = true;
2102: checkForPEReference(false);
2103: checkForElementTypeWithPEReference(fEntityReader, ')',
2104: fElementRefQName);
2105: valueIndex = fElementRefQName.rawname;
2106: if (valueIndex == -1) {
2107: reportFatalXMLError(
2108: XMLMessages.MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT,
2109: XMLMessages.P51_ELEMENT_TYPE_REQUIRED,
2110: element.rawname);
2111: return -1;
2112: }
2113: }
2114:
2115: } // scanMixed(QName):int
2116:
2117: /**
2118: * Scans a children content model.
2119: * <pre>
2120: * [47] children ::= (choice | seq) ('?' | '*' | '+')?
2121: * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
2122: * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
2123: * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
2124: * </pre>
2125: */
2126: private int scanChildren(QName element) throws Exception {
2127:
2128: int depth = 1;
2129: initializeContentModelStack(depth);
2130: while (true) {
2131: if (fEntityReader.lookingAtChar('(', true)) {
2132: increaseParenDepth();
2133: checkForPEReference(false);
2134: depth++;
2135: initializeContentModelStack(depth);
2136: continue;
2137: }
2138: checkForElementTypeWithPEReference(fEntityReader, ')',
2139: fElementRefQName);
2140: int valueIndex = fElementRefQName.rawname;
2141: if (valueIndex == -1) {
2142: reportFatalXMLError(
2143: XMLMessages.MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN,
2144: XMLMessages.P47_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED,
2145: element.rawname);
2146: return -1;
2147: }
2148: fNodeIndexStack[depth] = fDTDGrammar.addContentSpecNode(
2149: XMLContentSpec.CONTENTSPECNODE_LEAF, valueIndex);
2150: if (fEntityReader.lookingAtChar('?', true)) {
2151: fNodeIndexStack[depth] = fDTDGrammar
2152: .addContentSpecNode(
2153: XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE,
2154: fNodeIndexStack[depth]);
2155: } else if (fEntityReader.lookingAtChar('*', true)) {
2156: fNodeIndexStack[depth] = fDTDGrammar
2157: .addContentSpecNode(
2158: XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE,
2159: fNodeIndexStack[depth]);
2160: } else if (fEntityReader.lookingAtChar('+', true)) {
2161: fNodeIndexStack[depth] = fDTDGrammar
2162: .addContentSpecNode(
2163: XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE,
2164: fNodeIndexStack[depth]);
2165: }
2166: while (true) {
2167: checkForPEReference(false);
2168: if (fOpStack[depth] != XMLContentSpec.CONTENTSPECNODE_SEQ
2169: && fEntityReader.lookingAtChar('|', true)) {
2170: if (fPrevNodeIndexStack[depth] != -1) {
2171: fNodeIndexStack[depth] = fDTDGrammar
2172: .addContentSpecNode(fOpStack[depth],
2173: fPrevNodeIndexStack[depth],
2174: fNodeIndexStack[depth]);
2175: }
2176: fPrevNodeIndexStack[depth] = fNodeIndexStack[depth];
2177: fOpStack[depth] = XMLContentSpec.CONTENTSPECNODE_CHOICE;
2178: break;
2179: } else if (fOpStack[depth] != XMLContentSpec.CONTENTSPECNODE_CHOICE
2180: && fEntityReader.lookingAtChar(',', true)) {
2181: if (fPrevNodeIndexStack[depth] != -1) {
2182: fNodeIndexStack[depth] = fDTDGrammar
2183: .addContentSpecNode(fOpStack[depth],
2184: fPrevNodeIndexStack[depth],
2185: fNodeIndexStack[depth]);
2186: }
2187: fPrevNodeIndexStack[depth] = fNodeIndexStack[depth];
2188: fOpStack[depth] = XMLContentSpec.CONTENTSPECNODE_SEQ;
2189: break;
2190: } else {
2191: if (!fEntityReader.lookingAtChar(')', true)) {
2192: reportFatalXMLError(
2193: XMLMessages.MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN,
2194: XMLMessages.P47_CLOSE_PAREN_REQUIRED,
2195: element.rawname);
2196: }
2197: decreaseParenDepth();
2198: if (fPrevNodeIndexStack[depth] != -1) {
2199: fNodeIndexStack[depth] = fDTDGrammar
2200: .addContentSpecNode(fOpStack[depth],
2201: fPrevNodeIndexStack[depth],
2202: fNodeIndexStack[depth]);
2203: }
2204: int nodeIndex = fNodeIndexStack[depth--];
2205: fNodeIndexStack[depth] = nodeIndex;
2206: if (fEntityReader.lookingAtChar('?', true)) {
2207: fNodeIndexStack[depth] = fDTDGrammar
2208: .addContentSpecNode(
2209: XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE,
2210: fNodeIndexStack[depth]);
2211: } else if (fEntityReader.lookingAtChar('*', true)) {
2212: fNodeIndexStack[depth] = fDTDGrammar
2213: .addContentSpecNode(
2214: XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE,
2215: fNodeIndexStack[depth]);
2216: } else if (fEntityReader.lookingAtChar('+', true)) {
2217: fNodeIndexStack[depth] = fDTDGrammar
2218: .addContentSpecNode(
2219: XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE,
2220: fNodeIndexStack[depth]);
2221: }
2222: if (depth == 0) {
2223: return fNodeIndexStack[0];
2224: }
2225: }
2226: }
2227: checkForPEReference(false);
2228: }
2229:
2230: } // scanChildren(QName):int
2231:
2232: //
2233: // [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
2234: // [53] AttDef ::= S Name S AttType S DefaultDecl
2235: // [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
2236: //
2237: private void scanAttlistDecl() throws Exception {
2238: if (!checkForPEReference(true)) {
2239: abortMarkup(
2240: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL,
2241: XMLMessages.P52_SPACE_REQUIRED);
2242: return;
2243: }
2244: checkForElementTypeWithPEReference(fEntityReader, ' ',
2245: fElementQName);
2246: int elementTypeIndex = fElementQName.rawname;
2247: if (elementTypeIndex == -1) {
2248: abortMarkup(
2249: XMLMessages.MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL,
2250: XMLMessages.P52_ELEMENT_TYPE_REQUIRED);
2251: return;
2252: }
2253: int elementIndex = fDTDGrammar.getElementDeclIndex(
2254: fElementQName, -1);
2255: if (elementIndex == -1) {
2256: elementIndex = fDTDGrammar.addElementDecl(fElementQName);
2257: //System.out.println("XMLDTDScanner#scanAttListDecl->DTDGrammar#addElementDecl: "+elementIndex+" ("+fElementQName.localpart+","+fStringPool.toString(fElementQName.localpart)+')');
2258: }
2259: boolean sawSpace = checkForPEReference(true);
2260: if (fEntityReader.lookingAtChar('>', true)) {
2261: decreaseMarkupDepth();
2262: return;
2263: }
2264: // REVISIT - review this code...
2265: if (!sawSpace) {
2266: if (fEntityReader.lookingAtSpace(true)) {
2267: fEntityReader.skipPastSpaces();
2268: } else
2269: reportFatalXMLError(
2270: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF,
2271: XMLMessages.P53_SPACE_REQUIRED);
2272: } else {
2273: if (fEntityReader.lookingAtSpace(true)) {
2274: fEntityReader.skipPastSpaces();
2275: }
2276: }
2277: if (fEntityReader.lookingAtChar('>', true)) {
2278: decreaseMarkupDepth();
2279: return;
2280: }
2281: while (true) {
2282: checkForAttributeNameWithPEReference(fEntityReader, ' ',
2283: fAttributeQName);
2284: int attDefName = fAttributeQName.rawname;
2285: if (attDefName == -1) {
2286: abortMarkup(
2287: XMLMessages.MSG_ATTRIBUTE_NAME_REQUIRED_IN_ATTDEF,
2288: XMLMessages.P53_NAME_REQUIRED,
2289: fElementQName.rawname);
2290: return;
2291: }
2292: if (!checkForPEReference(true)) {
2293: abortMarkup(
2294: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF,
2295: XMLMessages.P53_SPACE_REQUIRED);
2296: return;
2297: }
2298: int attDefType = -1;
2299: boolean attDefList = false;
2300: int attDefEnumeration = -1;
2301: if (fEntityReader.skippedString(cdata_string)) {
2302: attDefType = XMLAttributeDecl.TYPE_CDATA;
2303: } else if (fEntityReader.skippedString(id_string)) {
2304: if (!fEntityReader.skippedString(ref_string)) {
2305: attDefType = XMLAttributeDecl.TYPE_ID;
2306: } else if (!fEntityReader.lookingAtChar('S', true)) {
2307: attDefType = XMLAttributeDecl.TYPE_IDREF;
2308: } else {
2309: attDefType = XMLAttributeDecl.TYPE_IDREF;
2310: attDefList = true;
2311: }
2312: } else if (fEntityReader.skippedString(entit_string)) {
2313: if (fEntityReader.lookingAtChar('Y', true)) {
2314: attDefType = XMLAttributeDecl.TYPE_ENTITY;
2315: } else if (fEntityReader.skippedString(ies_string)) {
2316: attDefType = XMLAttributeDecl.TYPE_ENTITY;
2317: attDefList = true;
2318: } else {
2319: abortMarkup(
2320: XMLMessages.MSG_ATTTYPE_REQUIRED_IN_ATTDEF,
2321: XMLMessages.P53_ATTTYPE_REQUIRED,
2322: elementTypeIndex, attDefName);
2323: return;
2324: }
2325: } else if (fEntityReader.skippedString(nmtoken_string)) {
2326: if (fEntityReader.lookingAtChar('S', true)) {
2327: attDefType = XMLAttributeDecl.TYPE_NMTOKEN;
2328: attDefList = true;
2329: } else {
2330: attDefType = XMLAttributeDecl.TYPE_NMTOKEN;
2331: }
2332: } else if (fEntityReader.skippedString(notation_string)) {
2333: if (!checkForPEReference(true)) {
2334: abortMarkup(
2335: XMLMessages.MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE,
2336: XMLMessages.P58_SPACE_REQUIRED,
2337: elementTypeIndex, attDefName);
2338: return;
2339: }
2340: if (!fEntityReader.lookingAtChar('(', true)) {
2341: abortMarkup(
2342: XMLMessages.MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE,
2343: XMLMessages.P58_OPEN_PAREN_REQUIRED,
2344: elementTypeIndex, attDefName);
2345: return;
2346: }
2347: increaseParenDepth();
2348: attDefType = XMLAttributeDecl.TYPE_NOTATION;
2349: attDefEnumeration = scanEnumeration(elementTypeIndex,
2350: attDefName, true);
2351: if (attDefEnumeration == -1) {
2352: skipPastEndOfCurrentMarkup();
2353: return;
2354: }
2355: } else if (fEntityReader.lookingAtChar('(', true)) {
2356: increaseParenDepth();
2357: attDefType = XMLAttributeDecl.TYPE_ENUMERATION;
2358: attDefEnumeration = scanEnumeration(elementTypeIndex,
2359: attDefName, false);
2360: if (attDefEnumeration == -1) {
2361: skipPastEndOfCurrentMarkup();
2362: return;
2363: }
2364: } else {
2365: abortMarkup(XMLMessages.MSG_ATTTYPE_REQUIRED_IN_ATTDEF,
2366: XMLMessages.P53_ATTTYPE_REQUIRED,
2367: elementTypeIndex, attDefName);
2368: return;
2369: }
2370: if (!checkForPEReference(true)) {
2371: abortMarkup(
2372: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF,
2373: XMLMessages.P53_SPACE_REQUIRED,
2374: elementTypeIndex, attDefName);
2375: return;
2376: }
2377: int attDefDefaultType = -1;
2378: int attDefDefaultValue = -1;
2379: if (fEntityReader.skippedString(required_string)) {
2380: attDefDefaultType = XMLAttributeDecl.DEFAULT_TYPE_REQUIRED;
2381: } else if (fEntityReader.skippedString(implied_string)) {
2382: attDefDefaultType = XMLAttributeDecl.DEFAULT_TYPE_IMPLIED;
2383: } else {
2384: if (fEntityReader.skippedString(fixed_string)) {
2385: if (!checkForPEReference(true)) {
2386: abortMarkup(
2387: XMLMessages.MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL,
2388: XMLMessages.P60_SPACE_REQUIRED,
2389: elementTypeIndex, attDefName);
2390: return;
2391: }
2392: attDefDefaultType = XMLAttributeDecl.DEFAULT_TYPE_FIXED;
2393: } else
2394: attDefDefaultType = XMLAttributeDecl.DEFAULT_TYPE_DEFAULT;
2395:
2396: //fElementQName.setValues(-1, elementTypeIndex, elementTypeIndex);
2397:
2398: // if attribute name has a prefix "xml", bind it to the XML Namespace.
2399: // since this is the only pre-defined namespace.
2400: /***
2401: if (fAttributeQName.prefix == fXMLSymbol) {
2402: fAttributeQName.uri = fXMLNamespace;
2403: }
2404: else
2405: fAttributeQName.setValues(-1, attDefName, attDefName);
2406: ****/
2407:
2408: attDefDefaultValue = scanDefaultAttValue(fElementQName,
2409: fAttributeQName, attDefType, attDefEnumeration);
2410:
2411: //normalize and check VC: Attribute Default Legal
2412: if (attDefDefaultValue != -1
2413: && attDefType != XMLAttributeDecl.TYPE_CDATA) {
2414: attDefDefaultValue = normalizeDefaultAttValue(
2415: fAttributeQName, attDefDefaultValue,
2416: attDefType, attDefEnumeration, attDefList);
2417: }
2418:
2419: if (attDefDefaultValue == -1) {
2420: skipPastEndOfCurrentMarkup();
2421: return;
2422: }
2423: }
2424: if (attDefName == fXMLSpace) {
2425: boolean ok = false;
2426: if (attDefType == XMLAttributeDecl.TYPE_ENUMERATION) {
2427: int index = attDefEnumeration;
2428: if (index != -1) {
2429: ok = (fStringPool.stringListLength(index) == 1 && (fStringPool
2430: .stringInList(index, fDefault) || fStringPool
2431: .stringInList(index, fPreserve)))
2432: || (fStringPool.stringListLength(index) == 2
2433: && fStringPool.stringInList(
2434: index, fDefault) && fStringPool
2435: .stringInList(index, fPreserve));
2436: }
2437: }
2438: if (!ok) {
2439: reportFatalXMLError(
2440: XMLMessages.MSG_XML_SPACE_DECLARATION_ILLEGAL,
2441: XMLMessages.S2_10_DECLARATION_ILLEGAL,
2442: elementTypeIndex);
2443: }
2444: }
2445: sawSpace = checkForPEReference(true);
2446:
2447: // if attribute name has a prefix "xml", bind it to the XML Namespace.
2448: // since this is the only pre-defined namespace.
2449: if (fAttributeQName.prefix == fXMLSymbol) {
2450: fAttributeQName.uri = fXMLNamespace;
2451: }
2452:
2453: if (fEntityReader.lookingAtChar('>', true)) {
2454: int attDefIndex = addAttDef(fElementQName,
2455: fAttributeQName, attDefType, attDefList,
2456: attDefEnumeration, attDefDefaultType,
2457: attDefDefaultValue, getReadingExternalEntity());
2458: //System.out.println("XMLDTDScanner#scanAttlistDecl->DTDGrammar#addAttDef: "+attDefIndex+
2459: // " ("+fElementQName.localpart+","+fStringPool.toString(fElementQName.rawname)+')'+
2460: // " ("+fAttributeQName.localpart+","+fStringPool.toString(fAttributeQName.rawname)+')');
2461: decreaseMarkupDepth();
2462: return;
2463: }
2464: // REVISIT - review this code...
2465: if (!sawSpace) {
2466: if (fEntityReader.lookingAtSpace(true)) {
2467: fEntityReader.skipPastSpaces();
2468: } else
2469: reportFatalXMLError(
2470: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF,
2471: XMLMessages.P53_SPACE_REQUIRED);
2472: } else {
2473: if (fEntityReader.lookingAtSpace(true)) {
2474: fEntityReader.skipPastSpaces();
2475: }
2476: }
2477: if (fEntityReader.lookingAtChar('>', true)) {
2478: int attDefIndex = addAttDef(fElementQName,
2479: fAttributeQName, attDefType, attDefList,
2480: attDefEnumeration, attDefDefaultType,
2481: attDefDefaultValue, getReadingExternalEntity());
2482: //System.out.println("XMLDTDScanner#scanAttlistDecl->DTDGrammar#addAttDef: "+attDefIndex+
2483: // " ("+fElementQName.localpart+","+fStringPool.toString(fElementQName.rawname)+')'+
2484: // " ("+fAttributeQName.localpart+","+fStringPool.toString(fAttributeQName.rawname)+')');
2485: decreaseMarkupDepth();
2486: return;
2487: }
2488: int attDefIndex = addAttDef(fElementQName, fAttributeQName,
2489: attDefType, attDefList, attDefEnumeration,
2490: attDefDefaultType, attDefDefaultValue,
2491: getReadingExternalEntity());
2492: //System.out.println("XMLDTDScanner#scanAttlistDecl->DTDGrammar#addAttDef: "+attDefIndex+
2493: // " ("+fElementQName.localpart+","+fStringPool.toString(fElementQName.rawname)+')'+
2494: // " ("+fAttributeQName.localpart+","+fStringPool.toString(fAttributeQName.rawname)+')');
2495: }
2496: }
2497:
2498: private int addAttDef(QName element, QName attribute,
2499: int attDefType, boolean attDefList, int attDefEnumeration,
2500: int attDefDefaultType, int attDefDefaultValue,
2501: boolean isExternal) throws Exception {
2502:
2503: if (fDTDHandler != null) {
2504: String enumString = attDefEnumeration != -1 ? fStringPool
2505: .stringListAsString(attDefEnumeration) : null;
2506: fDTDHandler.attlistDecl(element, attribute, attDefType,
2507: attDefList, enumString, attDefDefaultType,
2508: attDefDefaultValue);
2509: }
2510: int elementIndex = fDTDGrammar.getElementDeclIndex(element, -1);
2511: if (elementIndex == -1) {
2512: // REPORT Internal error here
2513: } else {
2514: int attlistIndex = fDTDGrammar
2515: .getFirstAttributeDeclIndex(elementIndex);
2516: int dupID = -1;
2517: int dupNotation = -1;
2518: while (attlistIndex != -1) {
2519: fDTDGrammar.getAttributeDecl(attlistIndex,
2520: fTempAttributeDecl);
2521:
2522: // REVISIT: Validation. Attributes are also tuples.
2523: if (fStringPool.equalNames(
2524: fTempAttributeDecl.name.rawname,
2525: attribute.rawname)) {
2526: /******
2527: if (fWarningOnDuplicateAttDef) {
2528: Object[] args = { fStringPool.toString(fElementType[elemChunk][elemIndex]),
2529: fStringPool.toString(attributeDecl.rawname) };
2530: fErrorReporter.reportError(fErrorReporter.getLocator(),
2531: XMLMessages.XML_DOMAIN,
2532: XMLMessages.MSG_DUPLICATE_ATTDEF,
2533: XMLMessages.P53_DUPLICATE,
2534: args,
2535: XMLErrorReporter.ERRORTYPE_WARNING);
2536: }
2537: ******/
2538: return -1;
2539: }
2540:
2541: if (fValidationEnabled) {
2542: if (attDefType == XMLAttributeDecl.TYPE_ID
2543: && fTempAttributeDecl.type == XMLAttributeDecl.TYPE_ID) {
2544: dupID = fTempAttributeDecl.name.rawname;
2545: }
2546: if (attDefType == XMLAttributeDecl.TYPE_NOTATION
2547: && fTempAttributeDecl.type == XMLAttributeDecl.TYPE_NOTATION) {
2548: dupNotation = fTempAttributeDecl.name.rawname;
2549: }
2550: }
2551: attlistIndex = fDTDGrammar
2552: .getNextAttributeDeclIndex(attlistIndex);
2553: }
2554: if (fValidationEnabled) {
2555: if (dupID != -1) {
2556: Object[] args = {
2557: fStringPool.toString(element.rawname),
2558: fStringPool.toString(dupID),
2559: fStringPool.toString(attribute.rawname) };
2560: fErrorReporter
2561: .reportError(
2562: fErrorReporter.getLocator(),
2563: XMLMessages.XML_DOMAIN,
2564: XMLMessages.MSG_MORE_THAN_ONE_ID_ATTRIBUTE,
2565: XMLMessages.VC_ONE_ID_PER_ELEMENT_TYPE,
2566: args,
2567: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2568: return -1;
2569: }
2570: if (dupNotation != -1) {
2571: Object[] args = {
2572: fStringPool.toString(element.rawname),
2573: fStringPool.toString(dupNotation),
2574: fStringPool.toString(attribute.rawname) };
2575: fErrorReporter
2576: .reportError(
2577: fErrorReporter.getLocator(),
2578: XMLMessages.XML_DOMAIN,
2579: XMLMessages.MSG_MORE_THAN_ONE_NOTATION_ATTRIBUTE,
2580: XMLMessages.VC_ONE_NOTATION_PER_ELEMENT_TYPE,
2581: args,
2582: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
2583: return -1;
2584: }
2585: }
2586: }
2587: return fDTDGrammar.addAttDef(element, attribute, attDefType,
2588: attDefList, attDefEnumeration, attDefDefaultType,
2589: attDefDefaultValue, isExternal);
2590:
2591: }
2592:
2593: //
2594: // [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
2595: // [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
2596: //
2597: private int scanEnumeration(int elementType, int attrName,
2598: boolean isNotationType) throws Exception {
2599: int enumIndex = fDTDGrammar.startEnumeration();
2600: while (true) {
2601: checkForPEReference(false);
2602: int nameIndex = isNotationType ? checkForNameWithPEReference(
2603: fEntityReader, ')')
2604: : checkForNmtokenWithPEReference(fEntityReader, ')');
2605: if (nameIndex == -1) {
2606: if (isNotationType) {
2607: reportFatalXMLError(
2608: XMLMessages.MSG_NAME_REQUIRED_IN_NOTATIONTYPE,
2609: XMLMessages.P58_NAME_REQUIRED, elementType,
2610: attrName);
2611: } else {
2612: reportFatalXMLError(
2613: XMLMessages.MSG_NMTOKEN_REQUIRED_IN_ENUMERATION,
2614: XMLMessages.P59_NMTOKEN_REQUIRED,
2615: elementType, attrName);
2616: }
2617: fDTDGrammar.endEnumeration(enumIndex);
2618: return -1;
2619: }
2620: fDTDGrammar.addNameToEnumeration(enumIndex, elementType,
2621: attrName, nameIndex, isNotationType);
2622: /*****/
2623: if (isNotationType
2624: && !((DefaultEntityHandler) fEntityHandler)
2625: .isNotationDeclared(nameIndex)) {
2626: Object[] args = { fStringPool.toString(elementType),
2627: fStringPool.toString(attrName),
2628: fStringPool.toString(nameIndex) };
2629: ((DefaultEntityHandler) fEntityHandler)
2630: .addRequiredNotation(
2631: nameIndex,
2632: fErrorReporter.getLocator(),
2633: XMLMessages.MSG_NOTATION_NOT_DECLARED_FOR_NOTATIONTYPE_ATTRIBUTE,
2634: XMLMessages.VC_NOTATION_DECLARED, args);
2635: }
2636: /*****/
2637: checkForPEReference(false);
2638: if (!fEntityReader.lookingAtChar('|', true)) {
2639: fDTDGrammar.endEnumeration(enumIndex);
2640: if (!fEntityReader.lookingAtChar(')', true)) {
2641: if (isNotationType) {
2642: reportFatalXMLError(
2643: XMLMessages.MSG_NOTATIONTYPE_UNTERMINATED,
2644: XMLMessages.P58_UNTERMINATED,
2645: elementType, attrName);
2646: } else {
2647: reportFatalXMLError(
2648: XMLMessages.MSG_ENUMERATION_UNTERMINATED,
2649: XMLMessages.P59_UNTERMINATED,
2650: elementType, attrName);
2651: }
2652: return -1;
2653: }
2654: decreaseParenDepth();
2655: return enumIndex;
2656: }
2657: }
2658: }
2659:
2660: //
2661: // [10] AttValue ::= '"' ([^<&"] | Reference)* '"'
2662: // | "'" ([^<&'] | Reference)* "'"
2663: //
2664: /**
2665: * Scan the default value in an attribute declaration
2666: *
2667: * @param elementType handle to the element that owns the attribute
2668: * @param attrName handle in the string pool for the attribute name
2669: * @return handle in the string pool for the default attribute value
2670: * @exception java.lang.Exception
2671: */
2672: public int scanDefaultAttValue(QName element, QName attribute)
2673: throws Exception {
2674: boolean single;
2675: if (!(single = fEntityReader.lookingAtChar('\'', true))
2676: && !fEntityReader.lookingAtChar('\"', true)) {
2677: reportFatalXMLError(
2678: XMLMessages.MSG_QUOTE_REQUIRED_IN_ATTVALUE,
2679: XMLMessages.P10_QUOTE_REQUIRED, element.rawname,
2680: attribute.rawname);
2681: return -1;
2682: }
2683: int previousState = setScannerState(SCANNER_STATE_DEFAULT_ATTRIBUTE_VALUE);
2684: char qchar = single ? '\'' : '\"';
2685: fDefaultAttValueReader = fReaderId;
2686: fDefaultAttValueElementType = element.rawname;
2687: fDefaultAttValueAttrName = attribute.rawname;
2688: boolean setMark = true;
2689: int dataOffset = fLiteralData.length();
2690: while (true) {
2691: fDefaultAttValueOffset = fEntityReader.currentOffset();
2692: if (setMark) {
2693: fDefaultAttValueMark = fDefaultAttValueOffset;
2694: setMark = false;
2695: }
2696: if (fEntityReader.lookingAtChar(qchar, true)) {
2697: if (fReaderId == fDefaultAttValueReader)
2698: break;
2699: continue;
2700: }
2701: if (fEntityReader.lookingAtChar(' ', true)) {
2702: continue;
2703: }
2704: boolean skippedCR;
2705: if ((skippedCR = fEntityReader.lookingAtChar((char) 0x0D,
2706: true))
2707: || fEntityReader.lookingAtSpace(true)) {
2708: if (fDefaultAttValueOffset - fDefaultAttValueMark > 0)
2709: fEntityReader.append(fLiteralData,
2710: fDefaultAttValueMark,
2711: fDefaultAttValueOffset
2712: - fDefaultAttValueMark);
2713: setMark = true;
2714: fLiteralData.append(' ');
2715: if (skippedCR)
2716: fEntityReader.lookingAtChar((char) 0x0A, true);
2717: continue;
2718: }
2719: if (fEntityReader.lookingAtChar('&', true)) {
2720: if (fDefaultAttValueOffset - fDefaultAttValueMark > 0)
2721: fEntityReader.append(fLiteralData,
2722: fDefaultAttValueMark,
2723: fDefaultAttValueOffset
2724: - fDefaultAttValueMark);
2725: setMark = true;
2726: //
2727: // Check for character reference first.
2728: //
2729: if (fEntityReader.lookingAtChar('#', true)) {
2730: int ch = scanCharRef();
2731: if (ch != -1) {
2732: if (ch < 0x10000)
2733: fLiteralData.append((char) ch);
2734: else {
2735: fLiteralData
2736: .append((char) (((ch - 0x00010000) >> 10) + 0xd800));
2737: fLiteralData
2738: .append((char) (((ch - 0x00010000) & 0x3ff) + 0xdc00));
2739: }
2740: }
2741: } else {
2742: //
2743: // Entity reference
2744: //
2745: int nameOffset = fEntityReader.currentOffset();
2746: fEntityReader.skipPastName(';');
2747: int nameLength = fEntityReader.currentOffset()
2748: - nameOffset;
2749: if (nameLength == 0) {
2750: reportFatalXMLError(
2751: XMLMessages.MSG_NAME_REQUIRED_IN_REFERENCE,
2752: XMLMessages.P68_NAME_REQUIRED);
2753: } else if (!fEntityReader.lookingAtChar(';', true)) {
2754: reportFatalXMLError(
2755: XMLMessages.MSG_SEMICOLON_REQUIRED_IN_REFERENCE,
2756: XMLMessages.P68_SEMICOLON_REQUIRED,
2757: fEntityReader.addString(nameOffset,
2758: nameLength));
2759: } else {
2760: int entityNameIndex = fEntityReader.addSymbol(
2761: nameOffset, nameLength);
2762: fEntityHandler
2763: .startReadingFromEntity(
2764: entityNameIndex,
2765: markupDepth(),
2766: XMLEntityHandler.ENTITYREF_IN_DEFAULTATTVALUE);
2767: }
2768: }
2769: continue;
2770: }
2771: if (fEntityReader.lookingAtChar('<', true)) {
2772: if (fDefaultAttValueOffset - fDefaultAttValueMark > 0)
2773: fEntityReader.append(fLiteralData,
2774: fDefaultAttValueMark,
2775: fDefaultAttValueOffset
2776: - fDefaultAttValueMark);
2777: setMark = true;
2778: reportFatalXMLError(
2779: XMLMessages.MSG_LESSTHAN_IN_ATTVALUE,
2780: XMLMessages.WFC_NO_LESSTHAN_IN_ATTVALUE,
2781: element.rawname, attribute.rawname);
2782: continue;
2783: }
2784: if (!fEntityReader.lookingAtValidChar(true)) {
2785: if (fDefaultAttValueOffset - fDefaultAttValueMark > 0)
2786: fEntityReader.append(fLiteralData,
2787: fDefaultAttValueMark,
2788: fDefaultAttValueOffset
2789: - fDefaultAttValueMark);
2790: setMark = true;
2791: int invChar = fEntityReader.scanInvalidChar();
2792: if (fScannerState == SCANNER_STATE_END_OF_INPUT)
2793: return -1;
2794: if (invChar >= 0) {
2795: reportFatalXMLError(
2796: XMLMessages.MSG_INVALID_CHAR_IN_ATTVALUE,
2797: XMLMessages.P10_INVALID_CHARACTER,
2798: fStringPool.toString(element.rawname),
2799: fStringPool.toString(attribute.rawname),
2800: Integer.toHexString(invChar));
2801: }
2802: continue;
2803: }
2804: }
2805: restoreScannerState(previousState);
2806: int dataLength = fLiteralData.length() - dataOffset;
2807: if (dataLength == 0) {
2808: return fEntityReader.addString(fDefaultAttValueMark,
2809: fDefaultAttValueOffset - fDefaultAttValueMark);
2810: }
2811: if (fDefaultAttValueOffset - fDefaultAttValueMark > 0) {
2812: fEntityReader.append(fLiteralData, fDefaultAttValueMark,
2813: fDefaultAttValueOffset - fDefaultAttValueMark);
2814: dataLength = fLiteralData.length() - dataOffset;
2815: }
2816: return fLiteralData.addString(dataOffset, dataLength);
2817: }
2818:
2819: //
2820: // [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
2821: //
2822: private void scanNotationDecl() throws Exception {
2823: if (!checkForPEReference(true)) {
2824: abortMarkup(
2825: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL,
2826: XMLMessages.P82_SPACE_REQUIRED);
2827: return;
2828: }
2829: int notationName = checkForNameWithPEReference(fEntityReader,
2830: ' ');
2831: if (notationName == -1) {
2832: abortMarkup(
2833: XMLMessages.MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL,
2834: XMLMessages.P82_NAME_REQUIRED);
2835: return;
2836: }
2837: if (!checkForPEReference(true)) {
2838: abortMarkup(
2839: XMLMessages.MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL,
2840: XMLMessages.P82_SPACE_REQUIRED, notationName);
2841: return;
2842: }
2843: if (!scanExternalID(true)) {
2844: skipPastEndOfCurrentMarkup();
2845: return;
2846: }
2847: checkForPEReference(false);
2848: if (!fEntityReader.lookingAtChar('>', true)) {
2849: abortMarkup(XMLMessages.MSG_NOTATIONDECL_UNTERMINATED,
2850: XMLMessages.P82_UNTERMINATED, notationName);
2851: return;
2852: }
2853: decreaseMarkupDepth();
2854: /****
2855: System.out.println(fStringPool.toString(notationName)+","
2856: +fStringPool.toString(fPubidLiteral) + ","
2857: +fStringPool.toString(fSystemLiteral) + ","
2858: +getReadingExternalEntity());
2859: /****/
2860:
2861: int notationIndex = ((DefaultEntityHandler) fEntityHandler)
2862: .addNotationDecl(notationName, fPubidLiteral,
2863: fSystemLiteral, getReadingExternalEntity());
2864: fDTDGrammar.addNotationDecl(notationName, fPubidLiteral,
2865: fSystemLiteral);
2866: if (fDTDHandler != null) {
2867: fDTDHandler.notationDecl(notationName, fPubidLiteral,
2868: fSystemLiteral);
2869: }
2870: }
2871:
2872: //
2873: // [70] EntityDecl ::= GEDecl | PEDecl
2874: // [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
2875: // [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
2876: // [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
2877: // [74] PEDef ::= EntityValue | ExternalID
2878: // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
2879: // | 'PUBLIC' S PubidLiteral S SystemLiteral
2880: // [76] NDataDecl ::= S 'NDATA' S Name
2881: // [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"'
2882: // | "'" ([^%&'] | PEReference | Reference)* "'"
2883: //
2884: // Called after scanning 'ENTITY'
2885: //
2886: private void scanEntityDecl() throws Exception {
2887: boolean isPEDecl = false;
2888: boolean sawPERef = false;
2889: if (fEntityReader.lookingAtSpace(true)) {
2890: fEntityReader.skipPastSpaces();
2891: if (!fEntityReader.lookingAtChar('%', true)) {
2892: isPEDecl = false; // <!ENTITY x "x">
2893: } else if (fEntityReader.lookingAtSpace(true)) {
2894: checkForPEReference(false); // <!ENTITY % x "x">
2895: isPEDecl = true;
2896: } else if (!getReadingExternalEntity()) {
2897: reportFatalXMLError(
2898: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_PEDECL,
2899: XMLMessages.P72_SPACE);
2900: isPEDecl = true;
2901: } else if (fEntityReader.lookingAtChar('%', false)) {
2902: checkForPEReference(false); // <!ENTITY %%x; "x"> is legal
2903: isPEDecl = true;
2904: } else {
2905: sawPERef = true;
2906: }
2907: } else if (!getReadingExternalEntity()
2908: || !fEntityReader.lookingAtChar('%', true)) {
2909: // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
2910: reportFatalXMLError(
2911: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL,
2912: XMLMessages.P70_SPACE);
2913: isPEDecl = false;
2914: } else if (fEntityReader.lookingAtSpace(false)) {
2915: // <!ENTITY% ...>
2916: reportFatalXMLError(
2917: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL,
2918: XMLMessages.P72_SPACE);
2919: isPEDecl = false;
2920: } else {
2921: sawPERef = true;
2922: }
2923: if (sawPERef) {
2924: while (true) {
2925: int nameOffset = fEntityReader.currentOffset();
2926: fEntityReader.skipPastName(';');
2927: int nameLength = fEntityReader.currentOffset()
2928: - nameOffset;
2929: if (nameLength == 0) {
2930: reportFatalXMLError(
2931: XMLMessages.MSG_NAME_REQUIRED_IN_PEREFERENCE,
2932: XMLMessages.P69_NAME_REQUIRED);
2933: } else if (!fEntityReader.lookingAtChar(';', true)) {
2934: reportFatalXMLError(
2935: XMLMessages.MSG_SEMICOLON_REQUIRED_IN_PEREFERENCE,
2936: XMLMessages.P69_SEMICOLON_REQUIRED,
2937: fEntityReader.addString(nameOffset,
2938: nameLength));
2939: } else {
2940: int peNameIndex = fEntityReader.addSymbol(
2941: nameOffset, nameLength);
2942: int readerDepth = (fScannerState == SCANNER_STATE_CONTENTSPEC) ? parenDepth()
2943: : markupDepth();
2944: fEntityHandler
2945: .startReadingFromEntity(
2946: peNameIndex,
2947: readerDepth,
2948: XMLEntityHandler.ENTITYREF_IN_DTD_WITHIN_MARKUP);
2949: }
2950: fEntityReader.skipPastSpaces();
2951: if (!fEntityReader.lookingAtChar('%', true))
2952: break;
2953: if (!isPEDecl) {
2954: if (fEntityReader.lookingAtSpace(true)) {
2955: checkForPEReference(false);
2956: isPEDecl = true;
2957: break;
2958: }
2959: isPEDecl = fEntityReader.lookingAtChar('%', true);
2960: }
2961: }
2962: }
2963: int entityName = checkForNameWithPEReference(fEntityReader, ' ');
2964: if (entityName == -1) {
2965: abortMarkup(
2966: XMLMessages.MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL,
2967: XMLMessages.P70_REQUIRED_NAME);
2968: return;
2969: }
2970: if (!fDTDGrammar.startEntityDecl(isPEDecl, entityName)) {
2971: skipPastEndOfCurrentMarkup();
2972: return;
2973: }
2974: if (!checkForPEReference(true)) {
2975: abortMarkup(
2976: XMLMessages.MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL,
2977: XMLMessages.P70_REQUIRED_SPACE, entityName);
2978: fDTDGrammar.endEntityDecl();
2979: return;
2980: }
2981: if (isPEDecl) {
2982: boolean single;
2983: if ((single = fEntityReader.lookingAtChar('\'', true))
2984: || fEntityReader.lookingAtChar('\"', true)) {
2985: int value = scanEntityValue(single);
2986: if (value == -1) {
2987: skipPastEndOfCurrentMarkup();
2988: fDTDGrammar.endEntityDecl();
2989: return;
2990: }
2991: checkForPEReference(false);
2992: if (!fEntityReader.lookingAtChar('>', true)) {
2993: abortMarkup(
2994: XMLMessages.MSG_ENTITYDECL_UNTERMINATED,
2995: XMLMessages.P72_UNTERMINATED, entityName);
2996: fDTDGrammar.endEntityDecl();
2997: return;
2998: }
2999: decreaseMarkupDepth();
3000: fDTDGrammar.endEntityDecl();
3001:
3002: // a hack by Eric
3003: //REVISIT
3004: fDTDGrammar.addInternalPEDecl(entityName, value);
3005: if (fDTDHandler != null) {
3006: fDTDHandler.internalPEDecl(entityName, value);
3007: }
3008: int entityIndex = ((DefaultEntityHandler) fEntityHandler)
3009: .addInternalPEDecl(entityName, value,
3010: getReadingExternalEntity());
3011:
3012: } else {
3013: if (!scanExternalID(false)) {
3014: skipPastEndOfCurrentMarkup();
3015: fDTDGrammar.endEntityDecl();
3016: return;
3017: }
3018: checkForPEReference(false);
3019: if (!fEntityReader.lookingAtChar('>', true)) {
3020: abortMarkup(
3021: XMLMessages.MSG_ENTITYDECL_UNTERMINATED,
3022: XMLMessages.P72_UNTERMINATED, entityName);
3023: fDTDGrammar.endEntityDecl();
3024: return;
3025: }
3026: decreaseMarkupDepth();
3027: fDTDGrammar.endEntityDecl();
3028:
3029: //a hack by Eric
3030: //REVISIT
3031: fDTDGrammar.addExternalPEDecl(entityName,
3032: fPubidLiteral, fSystemLiteral);
3033: if (fDTDHandler != null) {
3034: fDTDHandler.externalPEDecl(entityName,
3035: fPubidLiteral, fSystemLiteral);
3036: }
3037: int entityIndex = ((DefaultEntityHandler) fEntityHandler)
3038: .addExternalPEDecl(entityName, fPubidLiteral,
3039: fSystemLiteral,
3040: getReadingExternalEntity());
3041: }
3042: } else {
3043: boolean single;
3044: if ((single = fEntityReader.lookingAtChar('\'', true))
3045: || fEntityReader.lookingAtChar('\"', true)) {
3046: int value = scanEntityValue(single);
3047: if (value == -1) {
3048: skipPastEndOfCurrentMarkup();
3049: fDTDGrammar.endEntityDecl();
3050: return;
3051: }
3052: checkForPEReference(false);
3053: if (!fEntityReader.lookingAtChar('>', true)) {
3054: abortMarkup(
3055: XMLMessages.MSG_ENTITYDECL_UNTERMINATED,
3056: XMLMessages.P71_UNTERMINATED, entityName);
3057: fDTDGrammar.endEntityDecl();
3058: return;
3059: }
3060: decreaseMarkupDepth();
3061: fDTDGrammar.endEntityDecl();
3062:
3063: //a hack by Eric
3064: //REVISIT
3065: fDTDGrammar.addInternalEntityDecl(entityName, value);
3066: if (fDTDHandler != null) {
3067: fDTDHandler.internalEntityDecl(entityName, value);
3068: }
3069: int entityIndex = ((DefaultEntityHandler) fEntityHandler)
3070: .addInternalEntityDecl(entityName, value,
3071: getReadingExternalEntity());
3072: } else {
3073: if (!scanExternalID(false)) {
3074: skipPastEndOfCurrentMarkup();
3075: fDTDGrammar.endEntityDecl();
3076: return;
3077: }
3078: boolean unparsed = false;
3079: if (fEntityReader.lookingAtSpace(true)) {
3080: fEntityReader.skipPastSpaces();
3081: unparsed = fEntityReader
3082: .skippedString(ndata_string);
3083: }
3084: if (!unparsed) {
3085: checkForPEReference(false);
3086: if (!fEntityReader.lookingAtChar('>', true)) {
3087: abortMarkup(
3088: XMLMessages.MSG_ENTITYDECL_UNTERMINATED,
3089: XMLMessages.P72_UNTERMINATED,
3090: entityName);
3091: fDTDGrammar.endEntityDecl();
3092: return;
3093: }
3094: decreaseMarkupDepth();
3095: fDTDGrammar.endEntityDecl();
3096:
3097: //a hack by Eric
3098: //REVISIT
3099: fDTDGrammar.addExternalEntityDecl(entityName,
3100: fPubidLiteral, fSystemLiteral);
3101: if (fDTDHandler != null) {
3102: fDTDHandler.externalEntityDecl(entityName,
3103: fPubidLiteral, fSystemLiteral);
3104: }
3105: int entityIndex = ((DefaultEntityHandler) fEntityHandler)
3106: .addExternalEntityDecl(entityName,
3107: fPubidLiteral, fSystemLiteral,
3108: getReadingExternalEntity());
3109:
3110: } else {
3111: if (!fEntityReader.lookingAtSpace(true)) {
3112: abortMarkup(
3113: XMLMessages.MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL,
3114: XMLMessages.P76_SPACE_REQUIRED,
3115: entityName);
3116: fDTDGrammar.endEntityDecl();
3117: return;
3118: }
3119: fEntityReader.skipPastSpaces();
3120: int ndataOffset = fEntityReader.currentOffset();
3121: fEntityReader.skipPastName('>');
3122: int ndataLength = fEntityReader.currentOffset()
3123: - ndataOffset;
3124: if (ndataLength == 0) {
3125: abortMarkup(
3126: XMLMessages.MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL,
3127: XMLMessages.P76_REQUIRED, entityName);
3128: fDTDGrammar.endEntityDecl();
3129: return;
3130: }
3131: int notationName = fEntityReader.addSymbol(
3132: ndataOffset, ndataLength);
3133: checkForPEReference(false);
3134: if (!fEntityReader.lookingAtChar('>', true)) {
3135: abortMarkup(
3136: XMLMessages.MSG_ENTITYDECL_UNTERMINATED,
3137: XMLMessages.P72_UNTERMINATED,
3138: entityName);
3139: fDTDGrammar.endEntityDecl();
3140: return;
3141: }
3142: decreaseMarkupDepth();
3143: fDTDGrammar.endEntityDecl();
3144:
3145: //a hack by Eric
3146: //REVISIT
3147: fDTDGrammar
3148: .addUnparsedEntityDecl(entityName,
3149: fPubidLiteral, fSystemLiteral,
3150: notationName);
3151: if (fDTDHandler != null) {
3152: fDTDHandler.unparsedEntityDecl(entityName,
3153: fPubidLiteral, fSystemLiteral,
3154: notationName);
3155: }
3156: /****
3157: System.out.println("----addUnparsedEntity--- "+ fStringPool.toString(entityName)+","
3158: +fStringPool.toString(notationName)+","
3159: +fStringPool.toString(fPubidLiteral) + ","
3160: +fStringPool.toString(fSystemLiteral) + ","
3161: +getReadingExternalEntity());
3162: /****/
3163: int entityIndex = ((DefaultEntityHandler) fEntityHandler)
3164: .addUnparsedEntityDecl(entityName,
3165: fPubidLiteral, fSystemLiteral,
3166: notationName,
3167: getReadingExternalEntity());
3168: }
3169: }
3170: }
3171: }
3172:
3173: //
3174: // [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"'
3175: // | "'" ([^%&'] | PEReference | Reference)* "'"
3176: //
3177: private int scanEntityValue(boolean single) throws Exception {
3178: char qchar = single ? '\'' : '\"';
3179: fEntityValueMark = fEntityReader.currentOffset();
3180: int entityValue = fEntityReader.scanEntityValue(qchar, true);
3181: if (entityValue < 0)
3182: entityValue = scanComplexEntityValue(qchar, entityValue);
3183: return entityValue;
3184: }
3185:
3186: private int scanComplexEntityValue(char qchar, int result)
3187: throws Exception {
3188: int previousState = setScannerState(SCANNER_STATE_ENTITY_VALUE);
3189: fEntityValueReader = fReaderId;
3190: int dataOffset = fLiteralData.length();
3191: while (true) {
3192: switch (result) {
3193: case XMLEntityHandler.ENTITYVALUE_RESULT_FINISHED: {
3194: int offset = fEntityReader.currentOffset();
3195: fEntityReader.lookingAtChar(qchar, true);
3196: restoreScannerState(previousState);
3197: int dataLength = fLiteralData.length() - dataOffset;
3198: if (dataLength == 0) {
3199: return fEntityReader.addString(fEntityValueMark,
3200: offset - fEntityValueMark);
3201: }
3202: if (offset - fEntityValueMark > 0) {
3203: fEntityReader
3204: .append(fLiteralData, fEntityValueMark,
3205: offset - fEntityValueMark);
3206: dataLength = fLiteralData.length() - dataOffset;
3207: }
3208: return fLiteralData.addString(dataOffset, dataLength);
3209: }
3210: case XMLEntityHandler.ENTITYVALUE_RESULT_REFERENCE: {
3211: int offset = fEntityReader.currentOffset();
3212: if (offset - fEntityValueMark > 0)
3213: fEntityReader
3214: .append(fLiteralData, fEntityValueMark,
3215: offset - fEntityValueMark);
3216: fEntityReader.lookingAtChar('&', true);
3217: //
3218: // Check for character reference first.
3219: //
3220: if (fEntityReader.lookingAtChar('#', true)) {
3221: int ch = scanCharRef();
3222: if (ch != -1) {
3223: if (ch < 0x10000)
3224: fLiteralData.append((char) ch);
3225: else {
3226: fLiteralData
3227: .append((char) (((ch - 0x00010000) >> 10) + 0xd800));
3228: fLiteralData
3229: .append((char) (((ch - 0x00010000) & 0x3ff) + 0xdc00));
3230: }
3231: }
3232: fEntityValueMark = fEntityReader.currentOffset();
3233: } else {
3234: //
3235: // Entity reference
3236: //
3237: int nameOffset = fEntityReader.currentOffset();
3238: fEntityReader.skipPastName(';');
3239: int nameLength = fEntityReader.currentOffset()
3240: - nameOffset;
3241: if (nameLength == 0) {
3242: reportFatalXMLError(
3243: XMLMessages.MSG_NAME_REQUIRED_IN_REFERENCE,
3244: XMLMessages.P68_NAME_REQUIRED);
3245: fEntityValueMark = fEntityReader
3246: .currentOffset();
3247: } else if (!fEntityReader.lookingAtChar(';', true)) {
3248: reportFatalXMLError(
3249: XMLMessages.MSG_SEMICOLON_REQUIRED_IN_REFERENCE,
3250: XMLMessages.P68_SEMICOLON_REQUIRED,
3251: fEntityReader.addString(nameOffset,
3252: nameLength));
3253: fEntityValueMark = fEntityReader
3254: .currentOffset();
3255: } else {
3256: //
3257: // 4.4.7 Bypassed
3258: //
3259: // When a general entity reference appears in the EntityValue in an
3260: // entity declaration, it is bypassed and left as is.
3261: //
3262: fEntityValueMark = offset;
3263: }
3264: }
3265: break;
3266: }
3267: case XMLEntityHandler.ENTITYVALUE_RESULT_PEREF: {
3268: int offset = fEntityReader.currentOffset();
3269: if (offset - fEntityValueMark > 0)
3270: fEntityReader
3271: .append(fLiteralData, fEntityValueMark,
3272: offset - fEntityValueMark);
3273: fEntityReader.lookingAtChar('%', true);
3274: int nameOffset = fEntityReader.currentOffset();
3275: fEntityReader.skipPastName(';');
3276: int nameLength = fEntityReader.currentOffset()
3277: - nameOffset;
3278: if (nameLength == 0) {
3279: reportFatalXMLError(
3280: XMLMessages.MSG_NAME_REQUIRED_IN_PEREFERENCE,
3281: XMLMessages.P69_NAME_REQUIRED);
3282: } else if (!fEntityReader.lookingAtChar(';', true)) {
3283: reportFatalXMLError(
3284: XMLMessages.MSG_SEMICOLON_REQUIRED_IN_PEREFERENCE,
3285: XMLMessages.P69_SEMICOLON_REQUIRED,
3286: fEntityReader.addString(nameOffset,
3287: nameLength));
3288: } else if (!getReadingExternalEntity()) {
3289: reportFatalXMLError(
3290: XMLMessages.MSG_PEREFERENCE_WITHIN_MARKUP,
3291: XMLMessages.WFC_PES_IN_INTERNAL_SUBSET,
3292: fEntityReader.addString(nameOffset,
3293: nameLength));
3294: } else {
3295: int peNameIndex = fEntityReader.addSymbol(
3296: nameOffset, nameLength);
3297: fEntityHandler.startReadingFromEntity(peNameIndex,
3298: markupDepth(),
3299: XMLEntityHandler.ENTITYREF_IN_ENTITYVALUE);
3300: }
3301: fEntityValueMark = fEntityReader.currentOffset();
3302: break;
3303: }
3304: case XMLEntityHandler.ENTITYVALUE_RESULT_INVALID_CHAR: {
3305: int offset = fEntityReader.currentOffset();
3306: if (offset - fEntityValueMark > 0)
3307: fEntityReader
3308: .append(fLiteralData, fEntityValueMark,
3309: offset - fEntityValueMark);
3310: int invChar = fEntityReader.scanInvalidChar();
3311: if (fScannerState == SCANNER_STATE_END_OF_INPUT)
3312: return -1;
3313: if (invChar >= 0) {
3314: reportFatalXMLError(
3315: XMLMessages.MSG_INVALID_CHAR_IN_ENTITYVALUE,
3316: XMLMessages.P9_INVALID_CHARACTER, Integer
3317: .toHexString(invChar));
3318: }
3319: fEntityValueMark = fEntityReader.currentOffset();
3320: break;
3321: }
3322: case XMLEntityHandler.ENTITYVALUE_RESULT_END_OF_INPUT:
3323: // all the work is done by the previous reader, just invoke the next one now.
3324: break;
3325: default:
3326: break;
3327: }
3328: result = fEntityReader
3329: .scanEntityValue(
3330: fReaderId == fEntityValueReader ? qchar
3331: : -1, false);
3332: }
3333: }
3334:
3335: //
3336: //
3337: //
3338: private boolean checkForPEReference(boolean spaceRequired)
3339: throws Exception {
3340: boolean sawSpace = true;
3341: if (spaceRequired)
3342: sawSpace = fEntityReader.lookingAtSpace(true);
3343: fEntityReader.skipPastSpaces();
3344: if (!getReadingExternalEntity())
3345: return sawSpace;
3346: if (!fEntityReader.lookingAtChar('%', true))
3347: return sawSpace;
3348: while (true) {
3349: int nameOffset = fEntityReader.currentOffset();
3350: fEntityReader.skipPastName(';');
3351: int nameLength = fEntityReader.currentOffset() - nameOffset;
3352: if (nameLength == 0) {
3353: reportFatalXMLError(
3354: XMLMessages.MSG_NAME_REQUIRED_IN_PEREFERENCE,
3355: XMLMessages.P69_NAME_REQUIRED);
3356: } else if (!fEntityReader.lookingAtChar(';', true)) {
3357: reportFatalXMLError(
3358: XMLMessages.MSG_SEMICOLON_REQUIRED_IN_PEREFERENCE,
3359: XMLMessages.P69_SEMICOLON_REQUIRED,
3360: fEntityReader.addString(nameOffset, nameLength));
3361: } else {
3362: int peNameIndex = fEntityReader.addSymbol(nameOffset,
3363: nameLength);
3364: int readerDepth = (fScannerState == SCANNER_STATE_CONTENTSPEC) ? parenDepth()
3365: : markupDepth();
3366: fEntityHandler
3367: .startReadingFromEntity(
3368: peNameIndex,
3369: readerDepth,
3370: XMLEntityHandler.ENTITYREF_IN_DTD_WITHIN_MARKUP);
3371: }
3372: fEntityReader.skipPastSpaces();
3373: if (!fEntityReader.lookingAtChar('%', true))
3374: return true;
3375: }
3376: }
3377:
3378: //
3379: // content model stack
3380: //
3381: private void initializeContentModelStack(int depth) {
3382: if (fOpStack == null) {
3383: fOpStack = new int[8];
3384: fNodeIndexStack = new int[8];
3385: fPrevNodeIndexStack = new int[8];
3386: } else if (depth == fOpStack.length) {
3387: int[] newStack = new int[depth * 2];
3388: System.arraycopy(fOpStack, 0, newStack, 0, depth);
3389: fOpStack = newStack;
3390: newStack = new int[depth * 2];
3391: System.arraycopy(fNodeIndexStack, 0, newStack, 0, depth);
3392: fNodeIndexStack = newStack;
3393: newStack = new int[depth * 2];
3394: System
3395: .arraycopy(fPrevNodeIndexStack, 0, newStack, 0,
3396: depth);
3397: fPrevNodeIndexStack = newStack;
3398: }
3399: fOpStack[depth] = -1;
3400: fNodeIndexStack[depth] = -1;
3401: fPrevNodeIndexStack[depth] = -1;
3402: }
3403:
3404: private boolean validVersionNum(String version) {
3405: return XMLCharacterProperties.validVersionNum(version);
3406: }
3407:
3408: private boolean validEncName(String encoding) {
3409: return XMLCharacterProperties.validEncName(encoding);
3410: }
3411:
3412: private int validPublicId(String publicId) {
3413: return XMLCharacterProperties.validPublicId(publicId);
3414: }
3415:
3416: private void scanElementType(
3417: XMLEntityHandler.EntityReader entityReader, char fastchar,
3418: QName element) throws Exception {
3419:
3420: if (!fNamespacesEnabled) {
3421: element.clear();
3422: element.localpart = entityReader.scanName(fastchar);
3423: element.rawname = element.localpart;
3424: return;
3425: }
3426: entityReader.scanQName(fastchar, element);
3427: if (entityReader.lookingAtChar(':', false)) {
3428: fErrorReporter.reportError(fErrorReporter.getLocator(),
3429: XMLMessages.XML_DOMAIN,
3430: XMLMessages.MSG_TWO_COLONS_IN_QNAME,
3431: XMLMessages.P5_INVALID_CHARACTER, null,
3432: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
3433: entityReader.skipPastNmtoken(' ');
3434: }
3435:
3436: } // scanElementType(XMLEntityHandler.EntityReader,char,QName)
3437:
3438: public void checkForElementTypeWithPEReference(
3439: XMLEntityHandler.EntityReader entityReader, char fastchar,
3440: QName element) throws Exception {
3441:
3442: if (!fNamespacesEnabled) {
3443: element.clear();
3444: element.localpart = entityReader.scanName(fastchar);
3445: element.rawname = element.localpart;
3446: return;
3447: }
3448: entityReader.scanQName(fastchar, element);
3449: if (entityReader.lookingAtChar(':', false)) {
3450: fErrorReporter.reportError(fErrorReporter.getLocator(),
3451: XMLMessages.XML_DOMAIN,
3452: XMLMessages.MSG_TWO_COLONS_IN_QNAME,
3453: XMLMessages.P5_INVALID_CHARACTER, null,
3454: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
3455: entityReader.skipPastNmtoken(' ');
3456: }
3457:
3458: } // checkForElementTypeWithPEReference(XMLEntityHandler.EntityReader,char,QName)
3459:
3460: public void checkForAttributeNameWithPEReference(
3461: XMLEntityHandler.EntityReader entityReader, char fastchar,
3462: QName attribute) throws Exception {
3463:
3464: if (!fNamespacesEnabled) {
3465: attribute.clear();
3466: attribute.localpart = entityReader.scanName(fastchar);
3467: attribute.rawname = attribute.localpart;
3468: return;
3469: }
3470:
3471: entityReader.scanQName(fastchar, attribute);
3472: if (entityReader.lookingAtChar(':', false)) {
3473: fErrorReporter.reportError(fErrorReporter.getLocator(),
3474: XMLMessages.XML_DOMAIN,
3475: XMLMessages.MSG_TWO_COLONS_IN_QNAME,
3476: XMLMessages.P5_INVALID_CHARACTER, null,
3477: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
3478: entityReader.skipPastNmtoken(' ');
3479: }
3480:
3481: } // checkForAttributeNameWithPEReference(XMLEntityHandler.EntityReader,char,QName)
3482:
3483: public int checkForNameWithPEReference(
3484: XMLEntityHandler.EntityReader entityReader, char fastcheck)
3485: throws Exception {
3486: //
3487: // REVISIT - what does this have to do with PE references?
3488: //
3489: int valueIndex = entityReader.scanName(fastcheck);
3490: return valueIndex;
3491: }
3492:
3493: public int checkForNmtokenWithPEReference(
3494: XMLEntityHandler.EntityReader entityReader, char fastcheck)
3495: throws Exception {
3496: //
3497: // REVISIT - what does this have to do with PE references?
3498: //
3499: int nameOffset = entityReader.currentOffset();
3500: entityReader.skipPastNmtoken(fastcheck);
3501: int nameLength = entityReader.currentOffset() - nameOffset;
3502: if (nameLength == 0)
3503: return -1;
3504: int valueIndex = entityReader.addSymbol(nameOffset, nameLength);
3505: return valueIndex;
3506: }
3507:
3508: public int scanDefaultAttValue(QName element, QName attribute,
3509: int attType, int enumeration) throws Exception {
3510: /***/
3511: if (fValidationEnabled && attType == XMLAttributeDecl.TYPE_ID) {
3512: reportRecoverableXMLError(
3513: XMLMessages.MSG_ID_DEFAULT_TYPE_INVALID,
3514: XMLMessages.VC_ID_ATTRIBUTE_DEFAULT, fStringPool
3515: .toString(attribute.rawname));
3516: }
3517: /***/
3518: int defaultAttValue = scanDefaultAttValue(element, attribute);
3519: if (defaultAttValue == -1)
3520: return -1;
3521: // REVISIT
3522: /***
3523: if (attType != fCDATASymbol) {
3524: // REVISIT: Validation. Should we pass in the element or is this
3525: // default attribute value normalization?
3526: defaultAttValue = fValidator.normalizeAttValue(null, attribute, defaultAttValue, attType, enumeration);
3527: }
3528: /***/
3529: return defaultAttValue;
3530: }
3531:
3532: public int normalizeDefaultAttValue(QName attribute,
3533: int defaultAttValue, int attType, int enumeration,
3534: boolean list) throws Exception {
3535: //
3536: // Normalize attribute based upon attribute type...
3537: //
3538: String attValue = fStringPool.toString(defaultAttValue);
3539:
3540: if (list) {
3541: StringTokenizer tokenizer = new StringTokenizer(attValue);
3542: StringBuffer sb = new StringBuffer(attValue.length());
3543: boolean ok = true;
3544: if (tokenizer.hasMoreTokens()) {
3545: while (true) {
3546: String nmtoken = tokenizer.nextToken();
3547: if (attType == XMLAttributeDecl.TYPE_NMTOKEN) {
3548: if (fValidationEnabled
3549: && !XMLCharacterProperties
3550: .validNmtoken(nmtoken)) {
3551: ok = false;
3552: }
3553: } else if (attType == XMLAttributeDecl.TYPE_IDREF
3554: || attType == XMLAttributeDecl.TYPE_ENTITY) {
3555: if (fValidationEnabled
3556: && !XMLCharacterProperties
3557: .validName(nmtoken)) {
3558: ok = false;
3559: }
3560: // REVISIT: a Hack!!! THis is to pass SUN test /invalid/attr11.xml and attr12.xml
3561: // not consistent with XML1.0 spec VC: Attribute Default Legal
3562: if (fValidationEnabled
3563: && attType == XMLAttributeDecl.TYPE_ENTITY)
3564: if (!((DefaultEntityHandler) fEntityHandler)
3565: .isUnparsedEntity(defaultAttValue)) {
3566: reportRecoverableXMLError(
3567: XMLMessages.MSG_ENTITY_INVALID,
3568: XMLMessages.VC_ENTITY_NAME,
3569: fStringPool
3570: .toString(attribute.rawname),
3571: nmtoken);
3572: }
3573:
3574: }
3575: sb.append(nmtoken);
3576: if (!tokenizer.hasMoreTokens()) {
3577: break;
3578: }
3579: sb.append(' ');
3580: }
3581: }
3582: String newAttValue = sb.toString();
3583: if (fValidationEnabled
3584: && (!ok || newAttValue.length() == 0)) {
3585: reportRecoverableXMLError(
3586: XMLMessages.MSG_ATT_DEFAULT_INVALID,
3587: XMLMessages.VC_ATTRIBUTE_DEFAULT_LEGAL,
3588: fStringPool.toString(attribute.rawname),
3589: newAttValue);
3590: }
3591: if (!newAttValue.equals(attValue)) {
3592: defaultAttValue = fStringPool.addString(newAttValue);
3593: }
3594: return defaultAttValue;
3595: } else {
3596: String newAttValue = attValue.trim();
3597:
3598: if (fValidationEnabled) {
3599: // REVISIT - can we release the old string?
3600: if (newAttValue != attValue) {
3601: defaultAttValue = fStringPool
3602: .addSymbol(newAttValue);
3603: } else {
3604: defaultAttValue = fStringPool
3605: .addSymbol(defaultAttValue);
3606: }
3607: if (attType == XMLAttributeDecl.TYPE_ENTITY
3608: || attType == XMLAttributeDecl.TYPE_ID
3609: || attType == XMLAttributeDecl.TYPE_IDREF
3610: || attType == XMLAttributeDecl.TYPE_NOTATION) {
3611:
3612: // REVISIT: A Hack!!! THis is to pass SUN test /invalid/attr11.xml and attr12.xml
3613: // not consistent with XML1.0 spec VC: Attribute Default Legal
3614: if (attType == XMLAttributeDecl.TYPE_ENTITY)
3615: if (!((DefaultEntityHandler) fEntityHandler)
3616: .isUnparsedEntity(defaultAttValue)) {
3617: reportRecoverableXMLError(
3618: XMLMessages.MSG_ENTITY_INVALID,
3619: XMLMessages.VC_ENTITY_NAME,
3620: fStringPool
3621: .toString(attribute.rawname),
3622: newAttValue);
3623: }
3624:
3625: if (!XMLCharacterProperties.validName(newAttValue)) {
3626: reportRecoverableXMLError(
3627: XMLMessages.MSG_ATT_DEFAULT_INVALID,
3628: XMLMessages.VC_ATTRIBUTE_DEFAULT_LEGAL,
3629: fStringPool.toString(attribute.rawname),
3630: newAttValue);
3631: }
3632:
3633: } else if (attType == XMLAttributeDecl.TYPE_NMTOKEN
3634: || attType == XMLAttributeDecl.TYPE_ENUMERATION) {
3635:
3636: if (!XMLCharacterProperties
3637: .validNmtoken(newAttValue)) {
3638: reportRecoverableXMLError(
3639: XMLMessages.MSG_ATT_DEFAULT_INVALID,
3640: XMLMessages.VC_ATTRIBUTE_DEFAULT_LEGAL,
3641: fStringPool.toString(attribute.rawname),
3642: newAttValue);
3643: }
3644: }
3645:
3646: if (attType == XMLAttributeDecl.TYPE_NOTATION
3647: || attType == XMLAttributeDecl.TYPE_ENUMERATION) {
3648:
3649: if (!fStringPool.stringInList(enumeration,
3650: defaultAttValue)) {
3651: reportRecoverableXMLError(
3652: XMLMessages.MSG_ATT_DEFAULT_INVALID,
3653: XMLMessages.VC_ATTRIBUTE_DEFAULT_LEGAL,
3654: fStringPool.toString(attribute.rawname),
3655: newAttValue);
3656: }
3657: }
3658:
3659: } else if (newAttValue != attValue) {
3660: // REVISIT - can we release the old string?
3661: defaultAttValue = fStringPool.addSymbol(newAttValue);
3662: }
3663: }
3664:
3665: return defaultAttValue;
3666: }
3667: /***
3668: public boolean scanDoctypeDecl(boolean standalone) throws Exception {
3669: fStandaloneReader = standalone ? fEntityHandler.getReaderId() : -1;
3670: fDeclsAreExternal = false;
3671: if (!fDTDScanner.scanDoctypeDecl()) {
3672: return false;
3673: }
3674: if (fDTDScanner.getReadingExternalEntity()) {
3675: fDTDScanner.scanDecls(true);
3676: }
3677: fDTDHandler.endDTD();
3678: return true;
3679: }
3680: /***/
3681:
3682: } // class XMLDTDScanner
|