0001: /*
0002: * $Id: XMLDTDScannerImpl.java,v 1.4 2006/11/29 22:01:31 spericas Exp $
0003: */
0004:
0005: /*
0006: * The contents of this file are subject to the terms
0007: * of the Common Development and Distribution License
0008: * (the License). You may not use this file except in
0009: * compliance with the License.
0010: *
0011: * You can obtain a copy of the license at
0012: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
0013: * See the License for the specific language governing
0014: * permissions and limitations under the License.
0015: *
0016: * When distributing Covered Code, include this CDDL
0017: * Header Notice in each file and include the License file
0018: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
0019: * If applicable, add the following below the CDDL Header,
0020: * with the fields enclosed by brackets [] replaced by
0021: * you own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * [Name of File] [ver.__] [Date]
0025: *
0026: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
0027: */
0028:
0029: /*
0030: * The Apache Software License, Version 1.1
0031: *
0032: *
0033: * Copyright (c) 1999-2003 The Apache Software Foundation.
0034: * All rights reserved.
0035: *
0036: * Redistribution and use in source and binary forms, with or without
0037: * modification, are permitted provided that the following conditions
0038: * are met:
0039: *
0040: * 1. Redistributions of source code must retain the above copyright
0041: * notice, this list of conditions and the following disclaimer.
0042: *
0043: * 2. Redistributions in binary form must reproduce the above copyright
0044: * notice, this list of conditions and the following disclaimer in
0045: * the documentation and/or other materials provided with the
0046: * distribution.
0047: *
0048: * 3. The end-user documentation included with the redistribution,
0049: * if any, must include the following acknowledgment:
0050: * "This product includes software developed by the
0051: * Apache Software Foundation (http://www.apache.org/)."
0052: * Alternately, this acknowledgment may appear in the software itself,
0053: * if and wherever such third-party acknowledgments normally appear.
0054: *
0055: * 4. The names "Xerces" and "Apache Software Foundation" must
0056: * not be used to endorse or promote products derived from this
0057: * software without prior written permission. For written
0058: * permission, please contact apache@apache.org.
0059: *
0060: * 5. Products derived from this software may not be called "Apache",
0061: * nor may "Apache" appear in their name, without prior written
0062: * permission of the Apache Software Foundation.
0063: *
0064: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0065: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0066: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0067: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0068: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0069: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0070: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0071: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0072: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0073: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0074: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0075: * SUCH DAMAGE.
0076: * ====================================================================
0077: *
0078: * This software consists of voluntary contributions made by many
0079: * individuals on behalf of the Apache Software Foundation and was
0080: * originally based on software copyright (c) 1999, International
0081: * Business Machines, Inc., http://www.apache.org. For more
0082: * information on the Apache Software Foundation, please see
0083: * <http://www.apache.org/>.
0084: */
0085:
0086: package com.sun.xml.stream;
0087:
0088: import com.sun.xml.stream.dtd.nonvalidating.DTDGrammar;
0089: import java.io.IOException;
0090:
0091: import com.sun.xml.stream.xerces.impl.msg.XMLMessageFormatter;
0092:
0093: import com.sun.xml.stream.xerces.util.SymbolTable;
0094: import com.sun.xml.stream.xerces.util.XMLAttributesImpl;
0095: import com.sun.xml.stream.xerces.util.XMLChar;
0096: import com.sun.xml.stream.xerces.util.XMLStringBuffer;
0097:
0098: import com.sun.xml.stream.xerces.xni.XMLDTDContentModelHandler;
0099: import com.sun.xml.stream.xerces.xni.XMLDTDHandler;
0100: import com.sun.xml.stream.xerces.xni.XMLResourceIdentifier;
0101: import com.sun.xml.stream.xerces.xni.XMLString;
0102: import com.sun.xml.stream.xerces.xni.XNIException;
0103: import com.sun.xml.stream.xerces.xni.parser.XMLComponent;
0104: import com.sun.xml.stream.xerces.xni.parser.XMLComponentManager;
0105: import com.sun.xml.stream.xerces.xni.parser.XMLConfigurationException;
0106: import com.sun.xml.stream.xerces.xni.parser.XMLDTDScanner;
0107: import com.sun.xml.stream.xerces.xni.parser.XMLInputSource;
0108:
0109: /**
0110: * This class is responsible for scanning the declarations found
0111: * in the internal and external subsets of a DTD in an XML document.
0112: * The scanner acts as the sources for the DTD information which is
0113: * communicated to the DTD handlers.
0114: * <p>
0115: * This component requires the following features and properties from the
0116: * component manager that uses it:
0117: * <ul>
0118: * <li>http://xml.org/sax/features/validation</li>
0119: * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
0120: * <li>http://apache.org/xml/properties/internal/symbol-table</li>
0121: * <li>http://apache.org/xml/properties/internal/error-reporter</li>
0122: * <li>http://apache.org/xml/properties/internal/entity-manager</li>
0123: * </ul>
0124: *
0125: * @author Arnaud Le Hors, IBM
0126: * @author Andy Clark, IBM
0127: * @author Glenn Marcy, IBM
0128: * @author Eric Ye, IBM
0129: * @author Sunitha Reddy, Sun Microsystems
0130: *
0131: * @version $Id: XMLDTDScannerImpl.java,v 1.4 2006/11/29 22:01:31 spericas Exp $
0132: */
0133: public class XMLDTDScannerImpl extends XMLScanner implements
0134: XMLDTDScanner, XMLComponent, XMLEntityHandler {
0135:
0136: //
0137: // Constants
0138: //
0139:
0140: // scanner states
0141:
0142: /** Scanner state: end of input. */
0143: protected static final int SCANNER_STATE_END_OF_INPUT = 0;
0144:
0145: /** Scanner state: text declaration. */
0146: protected static final int SCANNER_STATE_TEXT_DECL = 1;
0147:
0148: /** Scanner state: markup declaration. */
0149: protected static final int SCANNER_STATE_MARKUP_DECL = 2;
0150:
0151: // recognized features and properties
0152:
0153: /** Recognized features. */
0154: private static final String[] RECOGNIZED_FEATURES = { VALIDATION,
0155: NOTIFY_CHAR_REFS, };
0156:
0157: /** Feature defaults. */
0158: private static final Boolean[] FEATURE_DEFAULTS = { null,
0159: Boolean.FALSE, };
0160:
0161: /** Recognized properties. */
0162: private static final String[] RECOGNIZED_PROPERTIES = {
0163: SYMBOL_TABLE, ERROR_REPORTER, ENTITY_MANAGER, };
0164:
0165: /** Property defaults. */
0166: private static final Object[] PROPERTY_DEFAULTS = { null, null,
0167: null, };
0168:
0169: // debugging
0170:
0171: /** Debug scanner state. */
0172: private static final boolean DEBUG_SCANNER_STATE = false;
0173:
0174: //
0175: // Data
0176: //
0177:
0178: // handlers
0179:
0180: /** DTD handler. */
0181: public XMLDTDHandler fDTDHandler = null;
0182: //new com.sun.xml.stream.dtd.XMLDTDProcessor();
0183:
0184: /** DTD content model handler. */
0185: protected XMLDTDContentModelHandler fDTDContentModelHandler;
0186:
0187: // state
0188:
0189: /** Scanner state. */
0190: protected int fScannerState;
0191:
0192: /** Standalone. */
0193: protected boolean fStandalone;
0194:
0195: /** Seen external DTD. */
0196: protected boolean fSeenExternalDTD;
0197:
0198: /** Seen external parameter entity. */
0199: protected boolean fSeenExternalPE;
0200:
0201: // private data
0202:
0203: /** Start DTD called. */
0204: private boolean fStartDTDCalled;
0205:
0206: /** Default attribute */
0207: private XMLAttributesImpl fAttributes = new XMLAttributesImpl();
0208:
0209: /**
0210: * Stack of content operators (either '|' or ',') in children
0211: * content.
0212: */
0213: private int[] fContentStack = new int[5];
0214:
0215: /** Size of content stack. */
0216: private int fContentDepth;
0217:
0218: /** Parameter entity stack to check well-formedness. */
0219: private int[] fPEStack = new int[5];
0220:
0221: /** Parameter entity stack to report start/end entity calls. */
0222: private boolean[] fPEReport = new boolean[5];
0223:
0224: /** Number of opened parameter entities. */
0225: private int fPEDepth;
0226:
0227: /** Markup depth. */
0228: private int fMarkUpDepth;
0229:
0230: /** Number of opened external entities. */
0231: private int fExtEntityDepth;
0232:
0233: /** Number of opened include sections. */
0234: private int fIncludeSectDepth;
0235:
0236: // temporary variables
0237:
0238: /** Array of 3 strings. */
0239: private String[] fStrings = new String[3];
0240:
0241: /** String. */
0242: private XMLString fString = new XMLString();
0243:
0244: /** String buffer. */
0245: private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
0246:
0247: /** String buffer. */
0248: private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
0249:
0250: /** Literal text. */
0251: private XMLString fLiteral = new XMLString();
0252:
0253: /** Literal text. */
0254: private XMLString fLiteral2 = new XMLString();
0255:
0256: /** Enumeration values. */
0257: private String[] fEnumeration = new String[5];
0258:
0259: /** Enumeration values count. */
0260: private int fEnumerationCount;
0261:
0262: /** Ignore conditional section buffer. */
0263: private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(
0264: 128);
0265:
0266: /** Object contains grammar information for a non-validaing parser. */
0267: DTDGrammar nvGrammarInfo = null;
0268:
0269: boolean nonValidatingMode = true;
0270:
0271: //
0272: // Constructors
0273: //
0274:
0275: /** Default constructor. */
0276: public XMLDTDScannerImpl() {
0277: } // <init>()
0278:
0279: /** Constructor for he use of non-XMLComponentManagers. */
0280: public XMLDTDScannerImpl(SymbolTable symbolTable,
0281: XMLErrorReporter errorReporter,
0282: XMLEntityManager entityManager) {
0283: fSymbolTable = symbolTable;
0284: fErrorReporter = errorReporter;
0285: fEntityManager = entityManager;
0286: //entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
0287: }
0288:
0289: //
0290: // XMLDTDScanner methods
0291: //
0292:
0293: /**
0294: * Sets the input source.
0295: *
0296: * @param inputSource The input source or null.
0297: *
0298: * @throws IOException Thrown on i/o error.
0299: */
0300: public void setInputSource(XMLInputSource inputSource)
0301: throws IOException {
0302: if (inputSource == null) {
0303: // no system id was available
0304: if (fDTDHandler != null) {
0305: fDTDHandler.startDTD(null, null);
0306: fDTDHandler.endDTD(null);
0307: }
0308: if (nonValidatingMode) {
0309: nvGrammarInfo.startDTD(null, null);
0310: nvGrammarInfo.endDTD(null);
0311: }
0312: return;
0313: }
0314: fEntityManager.setEntityHandler(this );
0315: fEntityManager.startDTDEntity(inputSource);
0316: } // setInputSource(XMLInputSource)
0317:
0318: /**
0319: * Scans the external subset of the document.
0320: *
0321: * @param complete True if the scanner should scan the document
0322: * completely, pushing all events to the registered
0323: * document handler. A value of false indicates that
0324: * that the scanner should only scan the next portion
0325: * of the document and return. A scanner instance is
0326: * permitted to completely scan a document if it does
0327: * not support this "pull" scanning model.
0328: *
0329: * @return True if there is more to scan, false otherwise.
0330: */
0331: public boolean scanDTDExternalSubset(boolean complete)
0332: throws IOException, XNIException {
0333:
0334: fEntityManager.setEntityHandler(this );
0335: if (fScannerState == SCANNER_STATE_TEXT_DECL) {
0336: fSeenExternalDTD = true;
0337: boolean textDecl = scanTextDecl();
0338: if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
0339: return false;
0340: } else {
0341: // next state is markup decls regardless of whether there
0342: // is a TextDecl or not
0343: setScannerState(SCANNER_STATE_MARKUP_DECL);
0344: if (textDecl && !complete) {
0345: return true;
0346: }
0347: }
0348: }
0349: // keep dispatching "events"
0350: do {
0351: if (!scanDecls(complete)) {
0352: return false;
0353: }
0354: } while (complete);
0355:
0356: // return that there is more to scan
0357: return true;
0358:
0359: } // scanDTDExternalSubset(boolean):boolean
0360:
0361: /**
0362: * Scans the internal subset of the document.
0363: *
0364: * @param complete True if the scanner should scan the document
0365: * completely, pushing all events to the registered
0366: * document handler. A value of false indicates that
0367: * that the scanner should only scan the next portion
0368: * of the document and return. A scanner instance is
0369: * permitted to completely scan a document if it does
0370: * not support this "pull" scanning model.
0371: * @param standalone True if the document was specified as standalone.
0372: * This value is important for verifying certain
0373: * well-formedness constraints.
0374: * @param hasExternalDTD True if the document has an external DTD.
0375: * This allows the scanner to properly notify
0376: * the handler of the end of the DTD in the
0377: * absence of an external subset.
0378: *
0379: * @return True if there is more to scan, false otherwise.
0380: */
0381: public boolean scanDTDInternalSubset(boolean complete,
0382: boolean standalone, boolean hasExternalSubset)
0383: throws IOException, XNIException {
0384: // reset entity scanner
0385: //Venu check
0386: fEntityScanner = (XMLEntityReaderImpl) fEntityManager
0387: .getEntityReader();
0388: fEntityManager.setEntityHandler(this );
0389: fStandalone = standalone;
0390: //System.out.println("state"+fScannerState);
0391: if (fScannerState == SCANNER_STATE_TEXT_DECL) {
0392: // call handler
0393: if (fDTDHandler != null) {
0394: fDTDHandler.startDTD(fEntityScanner, null);
0395: fStartDTDCalled = true;
0396: }
0397:
0398: if (nonValidatingMode) {
0399: fStartDTDCalled = true;
0400: nvGrammarInfo.startDTD(fEntityScanner, null);
0401: }
0402: // set starting state for internal subset
0403: setScannerState(SCANNER_STATE_MARKUP_DECL);
0404: }
0405: // keep dispatching "events"
0406: do {
0407: if (!scanDecls(complete)) {
0408: // call handler
0409: if (fDTDHandler != null && hasExternalSubset == false) {
0410: fDTDHandler.endDTD(null);
0411: }
0412: if (nonValidatingMode && hasExternalSubset == false) {
0413: nvGrammarInfo.endDTD(null);
0414: }
0415: // we're done, set starting state for external subset
0416: setScannerState(SCANNER_STATE_TEXT_DECL);
0417: return false;
0418: }
0419: } while (complete);
0420:
0421: // return that there is more to scan
0422: return true;
0423:
0424: } // scanDTDInternalSubset(boolean,boolean,boolean):boolean
0425:
0426: //
0427: // XMLComponent methods
0428: //
0429:
0430: /**
0431: * reset
0432: *
0433: * @param componentManager
0434: */
0435: public void reset(XMLComponentManager componentManager)
0436: throws XMLConfigurationException {
0437:
0438: super .reset(componentManager);
0439: init();
0440:
0441: } // reset(XMLComponentManager)
0442:
0443: // this is made for something like XMLDTDLoader--XMLComponentManager-free operation...
0444: public void reset() {
0445: //super.reset();
0446: init();
0447: }
0448:
0449: public void reset(PropertyManager props) {
0450: setPropertyManager(props);
0451: super .reset(props);
0452:
0453: if (!fAttributeCacheInitDone) {
0454: for (int i = 0; i < initialCacheCount; i++) {
0455: attributeValueCache.add(new XMLString());
0456: stringBufferCache.add(new XMLStringBuffer());
0457: }
0458: fAttributeCacheInitDone = true;
0459: }
0460: fStringBufferIndex = 0;
0461: fAttributeCacheUsedCount = 0;
0462: init();
0463: }
0464:
0465: /**
0466: * Returns a list of feature identifiers that are recognized by
0467: * this component. This method may return null if no features
0468: * are recognized by this component.
0469: */
0470: public String[] getRecognizedFeatures() {
0471: return (String[]) (RECOGNIZED_FEATURES.clone());
0472: } // getRecognizedFeatures():String[]
0473:
0474: /**
0475: * Returns a list of property identifiers that are recognized by
0476: * this component. This method may return null if no properties
0477: * are recognized by this component.
0478: */
0479: public String[] getRecognizedProperties() {
0480: return (String[]) (RECOGNIZED_PROPERTIES.clone());
0481: } // getRecognizedProperties():String[]
0482:
0483: /**
0484: * Returns the default state for a feature, or null if this
0485: * component does not want to report a default value for this
0486: * feature.
0487: *
0488: * @param featureId The feature identifier.
0489: *
0490: * @since Xerces 2.2.0
0491: */
0492: public Boolean getFeatureDefault(String featureId) {
0493: for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
0494: if (RECOGNIZED_FEATURES[i].equals(featureId)) {
0495: return FEATURE_DEFAULTS[i];
0496: }
0497: }
0498: return null;
0499: } // getFeatureDefault(String):Boolean
0500:
0501: /**
0502: * Returns the default state for a property, or null if this
0503: * component does not want to report a default value for this
0504: * property.
0505: *
0506: * @param propertyId The property identifier.
0507: *
0508: * @since Xerces 2.2.0
0509: */
0510: public Object getPropertyDefault(String propertyId) {
0511: for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
0512: if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
0513: return PROPERTY_DEFAULTS[i];
0514: }
0515: }
0516: return null;
0517: } // getPropertyDefault(String):Object
0518:
0519: //
0520: // XMLDTDSource methods
0521: //
0522:
0523: /**
0524: * setDTDHandler
0525: *
0526: * @param dtdHandler
0527: */
0528: public void setDTDHandler(XMLDTDHandler dtdHandler) {
0529: fDTDHandler = dtdHandler;
0530: } // setDTDHandler(XMLDTDHandler)
0531:
0532: /**
0533: * getDTDHandler
0534: *
0535: * @return the XMLDTDHandler
0536: */
0537: public XMLDTDHandler getDTDHandler() {
0538: return fDTDHandler;
0539: } // getDTDHandler(): XMLDTDHandler
0540:
0541: //
0542: // XMLDTDContentModelSource methods
0543: //
0544:
0545: /**
0546: * setDTDContentModelHandler
0547: *
0548: * @param dtdContentModelHandler
0549: */
0550: public void setDTDContentModelHandler(
0551: XMLDTDContentModelHandler dtdContentModelHandler) {
0552: fDTDContentModelHandler = dtdContentModelHandler;
0553: } // setDTDContentModelHandler
0554:
0555: /**
0556: * getDTDContentModelHandler
0557: *
0558: * @return XMLDTDContentModelHandler
0559: */
0560: public XMLDTDContentModelHandler getDTDContentModelHandler() {
0561: return fDTDContentModelHandler;
0562: } // setDTDContentModelHandler
0563:
0564: //
0565: // XMLEntityHandler methods
0566: //
0567:
0568: /**
0569: * This method notifies of the start of an entity. The DTD has the
0570: * pseudo-name of "[dtd]" parameter entity names start with '%'; and
0571: * general entities are just specified by their name.
0572: *
0573: * @param name The name of the entity.
0574: * @param identifier The resource identifier.
0575: * @param encoding The auto-detected IANA encoding name of the entity
0576: * stream. This value will be null in those situations
0577: * where the entity encoding is not auto-detected (e.g.
0578: * internal entities or a document entity that is
0579: * parsed from a java.io.Reader).
0580: *
0581: * @throws XNIException Thrown by handler to signal an error.
0582: */
0583: public void startEntity(String name,
0584: XMLResourceIdentifier identifier, String encoding)
0585: throws XNIException {
0586:
0587: super .startEntity(name, identifier, encoding);
0588:
0589: boolean dtdEntity = name.equals("[dtd]");
0590: if (dtdEntity) {
0591: // call handler
0592: if (fDTDHandler != null && !fStartDTDCalled) {
0593: fDTDHandler.startDTD(fEntityScanner, null);
0594: }
0595: if (fDTDHandler != null) {
0596: fDTDHandler.startExternalSubset(identifier, null);
0597: }
0598: fEntityManager.startExternalSubset();
0599: fExtEntityDepth++;
0600: } else if (name.charAt(0) == '%') {
0601: pushPEStack(fMarkUpDepth, fReportEntity);
0602: if (fEntityScanner.isExternal()) {
0603: fExtEntityDepth++;
0604: }
0605: }
0606:
0607: // call handler
0608: if (fDTDHandler != null && !dtdEntity && fReportEntity) {
0609: fDTDHandler.startParameterEntity(name, identifier,
0610: encoding, null);
0611: }
0612:
0613: } // startEntity(String,XMLResourceIdentifier,String)
0614:
0615: /**
0616: * This method notifies the end of an entity. The DTD has the pseudo-name
0617: * of "[dtd]" parameter entity names start with '%'; and general entities
0618: * are just specified by their name.
0619: *
0620: * @param name The name of the entity.
0621: *
0622: * @throws XNIException Thrown by handler to signal an error.
0623: */
0624: public void endEntity(String name) throws XNIException, IOException {
0625:
0626: super .endEntity(name);
0627:
0628: // if there is no data after the doctype
0629: //
0630: if (fScannerState == SCANNER_STATE_END_OF_INPUT)
0631: return;
0632:
0633: // Handle end of PE
0634: boolean reportEntity = fReportEntity;
0635: if (name.startsWith("%")) {
0636: reportEntity = peekReportEntity();
0637: // check well-formedness of the enity
0638: int startMarkUpDepth = popPEStack();
0639: // throw fatalError if this entity was incomplete and
0640: // was a freestanding decl
0641: if (startMarkUpDepth == 0
0642: && startMarkUpDepth < fMarkUpDepth) {
0643: fErrorReporter
0644: .reportError(
0645: XMLMessageFormatter.XML_DOMAIN,
0646: "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL",
0647: new Object[] { fEntityManager.fCurrentEntity.name },
0648: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0649: }
0650: if (startMarkUpDepth != fMarkUpDepth) {
0651: reportEntity = false;
0652: if (fValidation) {
0653: // Proper nesting of parameter entities is a Validity Constraint
0654: // and must not be enforced when validation is off
0655: fErrorReporter.reportError(
0656: XMLMessageFormatter.XML_DOMAIN,
0657: "ImproperDeclarationNesting",
0658: new Object[] { name },
0659: XMLErrorReporter.SEVERITY_ERROR);
0660: }
0661: }
0662: if (fEntityScanner.isExternal()) {
0663: fExtEntityDepth--;
0664: }
0665: }
0666:
0667: // call handler
0668: boolean dtdEntity = name.equals("[dtd]");
0669: if (fDTDHandler != null && !dtdEntity && reportEntity) {
0670: fDTDHandler.endParameterEntity(name, null);
0671: }
0672:
0673: // end DTD
0674: if (dtdEntity) {
0675: if (fIncludeSectDepth != 0) {
0676: reportFatalError("IncludeSectUnterminated", null);
0677: }
0678: fScannerState = SCANNER_STATE_END_OF_INPUT;
0679: // call handler
0680: fEntityManager.endExternalSubset();
0681: if (fDTDHandler != null) {
0682: fDTDHandler.endExternalSubset(null);
0683: fDTDHandler.endDTD(null);
0684: }
0685: fExtEntityDepth--;
0686: }
0687:
0688: } // endEntity(String)
0689:
0690: // helper methods
0691:
0692: /**
0693: * Sets the scanner state.
0694: *
0695: * @param state The new scanner state.
0696: */
0697: protected final void setScannerState(int state) {
0698:
0699: fScannerState = state;
0700: if (DEBUG_SCANNER_STATE) {
0701: System.out.print("### setScannerState: ");
0702: System.out.print(getScannerStateName(state));
0703: System.out.println();
0704: }
0705:
0706: } // setScannerState(int)
0707:
0708: //
0709: // Private methods
0710: //
0711:
0712: /** Returns the scanner state name. */
0713: private static String getScannerStateName(int state) {
0714:
0715: if (DEBUG_SCANNER_STATE) {
0716: switch (state) {
0717: case SCANNER_STATE_END_OF_INPUT:
0718: return "SCANNER_STATE_END_OF_INPUT";
0719: case SCANNER_STATE_TEXT_DECL:
0720: return "SCANNER_STATE_TEXT_DECL";
0721: case SCANNER_STATE_MARKUP_DECL:
0722: return "SCANNER_STATE_MARKUP_DECL";
0723: }
0724: }
0725:
0726: return "??? (" + state + ')';
0727:
0728: } // getScannerStateName(int):String
0729:
0730: protected final boolean scanningInternalSubset() {
0731: return fExtEntityDepth == 0;
0732: }
0733:
0734: /**
0735: * start a parameter entity dealing with the textdecl if there is any
0736: *
0737: * @param name The name of the parameter entity to start (without the '%')
0738: * @param literal Whether this is happening within a literal
0739: */
0740: protected void startPE(String name, boolean literal)
0741: throws IOException, XNIException {
0742: int depth = fPEDepth;
0743: String pName = "%" + name;
0744: if (fValidation && !fEntityStore.isDeclaredEntity(pName)) {
0745: fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
0746: "EntityNotDeclared", new Object[] { name },
0747: XMLErrorReporter.SEVERITY_ERROR);
0748: }
0749: fEntityManager.startEntity(fSymbolTable.addSymbol(pName),
0750: literal);
0751: // if we actually got a new entity and it's external
0752: // parse text decl if there is any
0753: if (depth != fPEDepth && fEntityScanner.isExternal()) {
0754: scanTextDecl();
0755: }
0756: }
0757:
0758: /**
0759: * Dispatch an XML "event".
0760: *
0761: * @param complete True if this method is intended to scan
0762: * and dispatch as much as possible.
0763: *
0764: * @return True if a TextDecl was scanned.
0765: *
0766: * @throws IOException Thrown on i/o error.
0767: * @throws XNIException Thrown on parse error.
0768: *
0769: */
0770: protected final boolean scanTextDecl() throws IOException,
0771: XNIException {
0772:
0773: // scan XMLDecl
0774: boolean textDecl = false;
0775: if (fEntityScanner.skipString("<?xml")) {
0776: fMarkUpDepth++;
0777: // NOTE: special case where document starts with a PI
0778: // whose name starts with "xml" (e.g. "xmlfoo")
0779: if (isValidNameChar(fEntityScanner.peekChar())) {
0780: fStringBuffer.clear();
0781: fStringBuffer.append("xml");
0782: while (isValidNameChar(fEntityScanner.peekChar())) {
0783: fStringBuffer.append((char) fEntityScanner
0784: .scanChar());
0785: }
0786: String target = fSymbolTable.addSymbol(
0787: fStringBuffer.ch, fStringBuffer.offset,
0788: fStringBuffer.length);
0789: scanPIData(target, fString);
0790: }
0791:
0792: // standard Text declaration
0793: else {
0794: // pseudo-attribute values
0795: String version = null;
0796: String encoding = null;
0797:
0798: scanXMLDeclOrTextDecl(true, fStrings);
0799: textDecl = true;
0800: fMarkUpDepth--;
0801:
0802: version = fStrings[0];
0803: encoding = fStrings[1];
0804:
0805: fEntityScanner.setEncoding(encoding);
0806:
0807: // call handler
0808: if (fDTDHandler != null) {
0809: fDTDHandler.textDecl(version, encoding, null);
0810: }
0811: }
0812: }
0813: fEntityManager.fCurrentEntity.mayReadChunks = true;
0814:
0815: return textDecl;
0816:
0817: } // scanTextDecl(boolean):boolean
0818:
0819: /**
0820: * Scans a processing data. This is needed to handle the situation
0821: * where a document starts with a processing instruction whose
0822: * target name <em>starts with</em> "xml". (e.g. xmlfoo)
0823: *
0824: * @param target The PI target
0825: * @param data The string to fill in with the data
0826: */
0827: protected final void scanPIData(String target, XMLString data)
0828: throws IOException, XNIException {
0829: //Venu REVISIT
0830: // super.scanPIData(target, data);
0831: fMarkUpDepth--;
0832:
0833: // call handler
0834: if (fDTDHandler != null) {
0835: fDTDHandler.processingInstruction(target, data, null);
0836: }
0837:
0838: } // scanPIData(String)
0839:
0840: /**
0841: * Scans a comment.
0842: * <p>
0843: * <pre>
0844: * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
0845: * </pre>
0846: * <p>
0847: * <strong>Note:</strong> Called after scanning past '<!--'
0848: */
0849: protected final void scanComment() throws IOException, XNIException {
0850:
0851: fReportEntity = false;
0852: scanComment(fStringBuffer);
0853: fMarkUpDepth--;
0854:
0855: // call handler
0856: if (fDTDHandler != null) {
0857: fDTDHandler.comment(fStringBuffer, null);
0858: }
0859: fReportEntity = true;
0860:
0861: } // scanComment()
0862:
0863: /**
0864: * Scans an element declaration
0865: * <p>
0866: * <pre>
0867: * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
0868: * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
0869: * </pre>
0870: * <p>
0871: * <strong>Note:</strong> Called after scanning past '<!ELEMENT'
0872: */
0873: protected final void scanElementDecl() throws IOException,
0874: XNIException {
0875:
0876: // spaces
0877: fReportEntity = false;
0878: if (!skipSeparator(true, !scanningInternalSubset())) {
0879: reportFatalError(
0880: "MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL",
0881: null);
0882: }
0883:
0884: // element name
0885: String name = fEntityScanner.scanName();
0886: if (name == null) {
0887: reportFatalError(
0888: "MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL", null);
0889: }
0890:
0891: // spaces
0892: if (!skipSeparator(true, !scanningInternalSubset())) {
0893: reportFatalError(
0894: "MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL",
0895: new Object[] { name });
0896: }
0897:
0898: // content model
0899: if (fDTDContentModelHandler != null) {
0900: fDTDContentModelHandler.startContentModel(name, null);
0901: }
0902: String contentModel = null;
0903: fReportEntity = true;
0904: if (fEntityScanner.skipString("EMPTY")) {
0905: contentModel = "EMPTY";
0906: // call handler
0907: if (fDTDContentModelHandler != null) {
0908: fDTDContentModelHandler.empty(null);
0909: }
0910: } else if (fEntityScanner.skipString("ANY")) {
0911: contentModel = "ANY";
0912: // call handler
0913: if (fDTDContentModelHandler != null) {
0914: fDTDContentModelHandler.any(null);
0915: }
0916: } else {
0917: if (!fEntityScanner.skipChar('(')) {
0918: reportFatalError(
0919: "MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
0920: new Object[] { name });
0921: }
0922: if (fDTDContentModelHandler != null) {
0923: fDTDContentModelHandler.startGroup(null);
0924: }
0925: fStringBuffer.clear();
0926: fStringBuffer.append('(');
0927: fMarkUpDepth++;
0928: skipSeparator(false, !scanningInternalSubset());
0929:
0930: // Mixed content model
0931: if (fEntityScanner.skipString("#PCDATA")) {
0932: scanMixed(name);
0933: } else { // children content
0934: scanChildren(name);
0935: }
0936: contentModel = fStringBuffer.toString();
0937: }
0938:
0939: // call handler
0940: if (fDTDContentModelHandler != null) {
0941: fDTDContentModelHandler.endContentModel(null);
0942: }
0943:
0944: fReportEntity = false;
0945: skipSeparator(false, !scanningInternalSubset());
0946: // end
0947: if (!fEntityScanner.skipChar('>')) {
0948: reportFatalError("ElementDeclUnterminated",
0949: new Object[] { name });
0950: }
0951: fReportEntity = true;
0952: fMarkUpDepth--;
0953:
0954: // call handler
0955: if (fDTDHandler != null) {
0956: fDTDHandler.elementDecl(name, contentModel, null);
0957: }
0958: if (nonValidatingMode)
0959: nvGrammarInfo.elementDecl(name, contentModel, null);
0960: } // scanElementDecl()
0961:
0962: /**
0963: * scan Mixed content model
0964: * This assumes the content model has been parsed up to #PCDATA and
0965: * can simply append to fStringBuffer.
0966: * <pre>
0967: * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
0968: * | '(' S? '#PCDATA' S? ')'
0969: * </pre>
0970: *
0971: * @param elName The element type name this declaration is about.
0972: *
0973: * <strong>Note:</strong> Called after scanning past '(#PCDATA'.
0974: */
0975: private final void scanMixed(String elName) throws IOException,
0976: XNIException {
0977:
0978: String childName = null;
0979:
0980: fStringBuffer.append("#PCDATA");
0981: // call handler
0982: if (fDTDContentModelHandler != null) {
0983: fDTDContentModelHandler.pcdata(null);
0984: }
0985: skipSeparator(false, !scanningInternalSubset());
0986: while (fEntityScanner.skipChar('|')) {
0987: fStringBuffer.append('|');
0988: // call handler
0989: if (fDTDContentModelHandler != null) {
0990: fDTDContentModelHandler.separator(
0991: XMLDTDContentModelHandler.SEPARATOR_CHOICE,
0992: null);
0993: }
0994: skipSeparator(false, !scanningInternalSubset());
0995:
0996: childName = fEntityScanner.scanName();
0997: if (childName == null) {
0998: reportFatalError(
0999: "MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
1000: new Object[] { elName });
1001: }
1002: fStringBuffer.append(childName);
1003: // call handler
1004: if (fDTDContentModelHandler != null) {
1005: fDTDContentModelHandler.element(childName, null);
1006: }
1007: skipSeparator(false, !scanningInternalSubset());
1008: }
1009: // The following check must be done in a single call (as opposed to one
1010: // for ')' and then one for '*') to guarantee that callbacks are
1011: // properly nested. We do not want to trigger endEntity too early in
1012: // case we cross the boundary of an entity between the two characters.
1013: if (fEntityScanner.skipString(")*")) {
1014: fStringBuffer.append(")*");
1015: // call handler
1016: if (fDTDContentModelHandler != null) {
1017: fDTDContentModelHandler.endGroup(null);
1018: fDTDContentModelHandler.occurrence(
1019: XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE,
1020: null);
1021: }
1022: } else if (childName != null) {
1023: reportFatalError("MixedContentUnterminated",
1024: new Object[] { elName });
1025: } else if (fEntityScanner.skipChar(')')) {
1026: fStringBuffer.append(')');
1027: // call handler
1028: if (fDTDContentModelHandler != null) {
1029: fDTDContentModelHandler.endGroup(null);
1030: }
1031: } else {
1032: reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1033: new Object[] { elName });
1034: }
1035: fMarkUpDepth--;
1036: // we are done
1037: }
1038:
1039: /**
1040: * scan children content model
1041: * This assumes it can simply append to fStringBuffer.
1042: * <pre>
1043: * [47] children ::= (choice | seq) ('?' | '*' | '+')?
1044: * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
1045: * [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
1046: * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
1047: * </pre>
1048: *
1049: * @param elName The element type name this declaration is about.
1050: *
1051: * <strong>Note:</strong> Called after scanning past the first open
1052: * paranthesis.
1053: */
1054: private final void scanChildren(String elName) throws IOException,
1055: XNIException {
1056:
1057: fContentDepth = 0;
1058: pushContentStack(0);
1059: int currentOp = 0;
1060: int c;
1061: while (true) {
1062: if (fEntityScanner.skipChar('(')) {
1063: fMarkUpDepth++;
1064: fStringBuffer.append('(');
1065: // call handler
1066: if (fDTDContentModelHandler != null) {
1067: fDTDContentModelHandler.startGroup(null);
1068: }
1069: // push current op on stack and reset it
1070: pushContentStack(currentOp);
1071: currentOp = 0;
1072: skipSeparator(false, !scanningInternalSubset());
1073: continue;
1074: }
1075: skipSeparator(false, !scanningInternalSubset());
1076: String childName = fEntityScanner.scanName();
1077: if (childName == null) {
1078: reportFatalError(
1079: "MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
1080: new Object[] { elName });
1081: return;
1082: }
1083: // call handler
1084: if (fDTDContentModelHandler != null) {
1085: fDTDContentModelHandler.element(childName, null);
1086: }
1087: fStringBuffer.append(childName);
1088: c = fEntityScanner.peekChar();
1089: if (c == '?' || c == '*' || c == '+') {
1090: // call handler
1091: if (fDTDContentModelHandler != null) {
1092: short oc;
1093: if (c == '?') {
1094: oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1095: } else if (c == '*') {
1096: oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1097: } else {
1098: oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1099: }
1100: fDTDContentModelHandler.occurrence(oc, null);
1101: }
1102: fEntityScanner.scanChar();
1103: fStringBuffer.append((char) c);
1104: }
1105: while (true) {
1106: skipSeparator(false, !scanningInternalSubset());
1107: c = fEntityScanner.peekChar();
1108: if (c == ',' && currentOp != '|') {
1109: currentOp = c;
1110: // call handler
1111: if (fDTDContentModelHandler != null) {
1112: fDTDContentModelHandler
1113: .separator(
1114: XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
1115: null);
1116: }
1117: fEntityScanner.scanChar();
1118: fStringBuffer.append(',');
1119: break;
1120: } else if (c == '|' && currentOp != ',') {
1121: currentOp = c;
1122: // call handler
1123: if (fDTDContentModelHandler != null) {
1124: fDTDContentModelHandler
1125: .separator(
1126: XMLDTDContentModelHandler.SEPARATOR_CHOICE,
1127: null);
1128: }
1129: fEntityScanner.scanChar();
1130: fStringBuffer.append('|');
1131: break;
1132: } else if (c != ')') {
1133: reportFatalError(
1134: "MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1135: new Object[] { elName });
1136: }
1137: // call handler
1138: if (fDTDContentModelHandler != null) {
1139: fDTDContentModelHandler.endGroup(null);
1140: }
1141: // restore previous op
1142: currentOp = popContentStack();
1143: short oc;
1144: // The following checks must be done in a single call (as
1145: // opposed to one for ')' and then one for '?', '*', and '+')
1146: // to guarantee that callbacks are properly nested. We do not
1147: // want to trigger endEntity too early in case we cross the
1148: // boundary of an entity between the two characters.
1149: if (fEntityScanner.skipString(")?")) {
1150: fStringBuffer.append(")?");
1151: // call handler
1152: if (fDTDContentModelHandler != null) {
1153: oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1154: fDTDContentModelHandler.occurrence(oc, null);
1155: }
1156: } else if (fEntityScanner.skipString(")+")) {
1157: fStringBuffer.append(")+");
1158: // call handler
1159: if (fDTDContentModelHandler != null) {
1160: oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1161: fDTDContentModelHandler.occurrence(oc, null);
1162: }
1163: } else if (fEntityScanner.skipString(")*")) {
1164: fStringBuffer.append(")*");
1165: // call handler
1166: if (fDTDContentModelHandler != null) {
1167: oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1168: fDTDContentModelHandler.occurrence(oc, null);
1169: }
1170: } else {
1171: // no occurrence specified
1172: fEntityScanner.scanChar();
1173: fStringBuffer.append(')');
1174: }
1175: fMarkUpDepth--;
1176: if (fContentDepth == 0) {
1177: return;
1178: }
1179: }
1180: skipSeparator(false, !scanningInternalSubset());
1181: }
1182: }
1183:
1184: /**
1185: * Scans an attlist declaration
1186: * <p>
1187: * <pre>
1188: * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
1189: * [53] AttDef ::= S Name S AttType S DefaultDecl
1190: * </pre>
1191: * <p>
1192: * <strong>Note:</strong> Called after scanning past '<!ATTLIST'
1193: */
1194: protected final void scanAttlistDecl() throws IOException,
1195: XNIException {
1196:
1197: // spaces
1198: fReportEntity = false;
1199: if (!skipSeparator(true, !scanningInternalSubset())) {
1200: reportFatalError(
1201: "MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL",
1202: null);
1203: }
1204:
1205: // element name
1206: String elName = fEntityScanner.scanName();
1207: if (elName == null) {
1208: reportFatalError(
1209: "MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL", null);
1210: }
1211:
1212: // call handler
1213: if (fDTDHandler != null) {
1214: fDTDHandler.startAttlist(elName, null);
1215: }
1216:
1217: // spaces
1218: if (!skipSeparator(true, !scanningInternalSubset())) {
1219: // no space, is it the end yet?
1220: if (fEntityScanner.skipChar('>')) {
1221: // yes, stop here
1222: // call handler
1223: if (fDTDHandler != null) {
1224: fDTDHandler.endAttlist(null);
1225: }
1226: fMarkUpDepth--;
1227: return;
1228: } else {
1229: reportFatalError(
1230: "MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF",
1231: new Object[] { elName });
1232: }
1233: }
1234:
1235: // definitions
1236: while (!fEntityScanner.skipChar('>')) {
1237: String name = fEntityScanner.scanName();
1238: if (name == null) {
1239: reportFatalError("AttNameRequiredInAttDef",
1240: new Object[] { elName });
1241: }
1242: // spaces
1243: if (!skipSeparator(true, !scanningInternalSubset())) {
1244: reportFatalError(
1245: "MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF",
1246: new Object[] { elName, name });
1247: }
1248: // type
1249: String type = scanAttType(elName, name);
1250:
1251: // spaces
1252: if (!skipSeparator(true, !scanningInternalSubset())) {
1253: reportFatalError(
1254: "MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF",
1255: new Object[] { elName, name });
1256: }
1257:
1258: // default decl
1259: String defaultType = scanAttDefaultDecl(elName, name, type,
1260: fLiteral, fLiteral2);
1261: // REVISIT: Should we do anything with the non-normalized
1262: // default attribute value? -Ac
1263: // yes--according to bug 5073. - neilg
1264: String[] enumr = null;
1265: if (fDTDHandler != null || nonValidatingMode) {
1266: if (fEnumerationCount != 0) {
1267: enumr = new String[fEnumerationCount];
1268: System.arraycopy(fEnumeration, 0, enumr, 0,
1269: fEnumerationCount);
1270: }
1271: }
1272: // call handler
1273: // Determine whether the default value to be passed should be null.
1274: // REVISIT: should probably check whether fLiteral.ch is null instead. LM.
1275: if (defaultType != null
1276: && (defaultType.equals("#REQUIRED") || defaultType
1277: .equals("#IMPLIED"))) {
1278: if (fDTDHandler != null) {
1279: fDTDHandler.attributeDecl(elName, name, type,
1280: enumr, defaultType, null, null, null);
1281: }
1282: if (nonValidatingMode) {
1283: nvGrammarInfo.attributeDecl(elName, name, type,
1284: enumr, defaultType, null, null, null);
1285:
1286: }
1287: } else {
1288: if (fDTDHandler != null) {
1289: fDTDHandler.attributeDecl(elName, name, type,
1290: enumr, defaultType, fLiteral, fLiteral2,
1291: null);
1292: }
1293: if (nonValidatingMode) {
1294: nvGrammarInfo.attributeDecl(elName, name, type,
1295: enumr, defaultType, fLiteral, fLiteral2,
1296: null);
1297: }
1298: }
1299: skipSeparator(false, !scanningInternalSubset());
1300: }
1301:
1302: // call handler
1303: if (fDTDHandler != null) {
1304: fDTDHandler.endAttlist(null);
1305: }
1306: fMarkUpDepth--;
1307: fReportEntity = true;
1308:
1309: } // scanAttlistDecl()
1310:
1311: /**
1312: * Scans an attribute type definition
1313: * <p>
1314: * <pre>
1315: * [54] AttType ::= StringType | TokenizedType | EnumeratedType
1316: * [55] StringType ::= 'CDATA'
1317: * [56] TokenizedType ::= 'ID'
1318: * | 'IDREF'
1319: * | 'IDREFS'
1320: * | 'ENTITY'
1321: * | 'ENTITIES'
1322: * | 'NMTOKEN'
1323: * | 'NMTOKENS'
1324: * [57] EnumeratedType ::= NotationType | Enumeration
1325: * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
1326: * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
1327: * </pre>
1328: * <p>
1329: * <strong>Note:</strong> Called after scanning past '<!ATTLIST'
1330: *
1331: * @param elName The element type name this declaration is about.
1332: * @param atName The attribute name this declaration is about.
1333: */
1334: private final String scanAttType(String elName, String atName)
1335: throws IOException, XNIException {
1336:
1337: String type = null;
1338: fEnumerationCount = 0;
1339: /*
1340: * Watchout: the order here is important: when a string happens to
1341: * be a substring of another string, the longer one needs to be
1342: * looked for first!!
1343: */
1344: if (fEntityScanner.skipString("CDATA")) {
1345: type = "CDATA";
1346: } else if (fEntityScanner.skipString("IDREFS")) {
1347: type = "IDREFS";
1348: } else if (fEntityScanner.skipString("IDREF")) {
1349: type = "IDREF";
1350: } else if (fEntityScanner.skipString("ID")) {
1351: type = "ID";
1352: } else if (fEntityScanner.skipString("ENTITY")) {
1353: type = "ENTITY";
1354: } else if (fEntityScanner.skipString("ENTITIES")) {
1355: type = "ENTITIES";
1356: } else if (fEntityScanner.skipString("NMTOKENS")) {
1357: type = "NMTOKENS";
1358: } else if (fEntityScanner.skipString("NMTOKEN")) {
1359: type = "NMTOKEN";
1360: } else if (fEntityScanner.skipString("NOTATION")) {
1361: type = "NOTATION";
1362: // spaces
1363: if (!skipSeparator(true, !scanningInternalSubset())) {
1364: reportFatalError(
1365: "MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE",
1366: new Object[] { elName, atName });
1367: }
1368: // open paren
1369: int c = fEntityScanner.scanChar();
1370: if (c != '(') {
1371: reportFatalError(
1372: "MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
1373: new Object[] { elName, atName });
1374: }
1375: fMarkUpDepth++;
1376: do {
1377: skipSeparator(false, !scanningInternalSubset());
1378: String aName = fEntityScanner.scanName();
1379: if (aName == null) {
1380: reportFatalError(
1381: "MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
1382: new Object[] { elName, atName });
1383: }
1384: ensureEnumerationSize(fEnumerationCount + 1);
1385: fEnumeration[fEnumerationCount++] = aName;
1386: skipSeparator(false, !scanningInternalSubset());
1387: c = fEntityScanner.scanChar();
1388: } while (c == '|');
1389: if (c != ')') {
1390: reportFatalError("NotationTypeUnterminated",
1391: new Object[] { elName, atName });
1392: }
1393: fMarkUpDepth--;
1394: } else { // Enumeration
1395: type = "ENUMERATION";
1396: // open paren
1397: int c = fEntityScanner.scanChar();
1398: if (c != '(') {
1399: // "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
1400: reportFatalError("AttTypeRequiredInAttDef",
1401: new Object[] { elName, atName });
1402: }
1403: fMarkUpDepth++;
1404: do {
1405: skipSeparator(false, !scanningInternalSubset());
1406: String token = fEntityScanner.scanNmtoken();
1407: if (token == null) {
1408: reportFatalError(
1409: "MSG_NMTOKEN_REQUIRED_IN_ENUMERATION",
1410: new Object[] { elName, atName });
1411: }
1412: ensureEnumerationSize(fEnumerationCount + 1);
1413: fEnumeration[fEnumerationCount++] = token;
1414: skipSeparator(false, !scanningInternalSubset());
1415: c = fEntityScanner.scanChar();
1416: } while (c == '|');
1417: if (c != ')') {
1418: reportFatalError("EnumerationUnterminated",
1419: new Object[] { elName, atName });
1420: }
1421: fMarkUpDepth--;
1422: }
1423: return type;
1424:
1425: } // scanAttType():String
1426:
1427: /**
1428: * Scans an attribute default declaration
1429: * <p>
1430: * <pre>
1431: * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
1432: * </pre>
1433: *
1434: * @param name The name of the attribute being scanned.
1435: * @param defaultVal The string to fill in with the default value.
1436: */
1437: protected final String scanAttDefaultDecl(String elName,
1438: String atName, String type, XMLString defaultVal,
1439: XMLString nonNormalizedDefaultVal) throws IOException,
1440: XNIException {
1441:
1442: String defaultType = null;
1443: fString.clear();
1444: defaultVal.clear();
1445: if (fEntityScanner.skipString("#REQUIRED")) {
1446: defaultType = "#REQUIRED";
1447: } else if (fEntityScanner.skipString("#IMPLIED")) {
1448: defaultType = "#IMPLIED";
1449: } else {
1450: if (fEntityScanner.skipString("#FIXED")) {
1451: defaultType = "#FIXED";
1452: // spaces
1453: if (!skipSeparator(true, !scanningInternalSubset())) {
1454: reportFatalError(
1455: "MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL",
1456: new Object[] { elName, atName });
1457: }
1458: }
1459: // AttValue
1460: boolean isVC = !fStandalone
1461: && (fSeenExternalDTD || fSeenExternalPE);
1462: scanAttributeValue(defaultVal, nonNormalizedDefaultVal,
1463: atName, fAttributes, 0, isVC);
1464: }
1465: return defaultType;
1466:
1467: } // ScanAttDefaultDecl
1468:
1469: /**
1470: * Scans an entity declaration
1471: * <p>
1472: * <pre>
1473: * [70] EntityDecl ::= GEDecl | PEDecl
1474: * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
1475: * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
1476: * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
1477: * [74] PEDef ::= EntityValue | ExternalID
1478: * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1479: * | 'PUBLIC' S PubidLiteral S SystemLiteral
1480: * [76] NDataDecl ::= S 'NDATA' S Name
1481: * </pre>
1482: * <p>
1483: * <strong>Note:</strong> Called after scanning past '<!ENTITY'
1484: */
1485: private final void scanEntityDecl() throws IOException,
1486: XNIException {
1487:
1488: boolean isPEDecl = false;
1489: boolean sawPERef = false;
1490: fReportEntity = false;
1491: if (fEntityScanner.skipSpaces()) {
1492: if (!fEntityScanner.skipChar('%')) {
1493: isPEDecl = false; // <!ENTITY x "x">
1494: } else if (skipSeparator(true, !scanningInternalSubset())) {
1495: // <!ENTITY % x "x">
1496: isPEDecl = true;
1497: } else if (scanningInternalSubset()) {
1498: reportFatalError(
1499: "MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1500: null);
1501: isPEDecl = true;
1502: } else if (fEntityScanner.peekChar() == '%') {
1503: // <!ENTITY %%x; "x"> is legal
1504: skipSeparator(false, !scanningInternalSubset());
1505: isPEDecl = true;
1506: } else {
1507: sawPERef = true;
1508: }
1509: } else if (scanningInternalSubset()
1510: || !fEntityScanner.skipChar('%')) {
1511: // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
1512: reportFatalError(
1513: "MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1514: null);
1515: isPEDecl = false;
1516: } else if (fEntityScanner.skipSpaces()) {
1517: // <!ENTITY% ...>
1518: reportFatalError(
1519: "MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL", null);
1520: isPEDecl = false;
1521: } else {
1522: sawPERef = true;
1523: }
1524: if (sawPERef) {
1525: while (true) {
1526: String peName = fEntityScanner.scanName();
1527: if (peName == null) {
1528: reportFatalError("NameRequiredInPEReference", null);
1529: } else if (!fEntityScanner.skipChar(';')) {
1530: reportFatalError("SemicolonRequiredInPEReference",
1531: new Object[] { peName });
1532: } else {
1533: startPE(peName, false);
1534: }
1535: fEntityScanner.skipSpaces();
1536: if (!fEntityScanner.skipChar('%'))
1537: break;
1538: if (!isPEDecl) {
1539: if (skipSeparator(true, !scanningInternalSubset())) {
1540: isPEDecl = true;
1541: break;
1542: }
1543: isPEDecl = fEntityScanner.skipChar('%');
1544: }
1545: }
1546: }
1547:
1548: // name
1549: String name = fEntityScanner.scanName();
1550: if (name == null) {
1551: reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL",
1552: null);
1553: }
1554:
1555: // spaces
1556: if (!skipSeparator(true, !scanningInternalSubset())) {
1557: reportFatalError(
1558: "MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
1559: new Object[] { name });
1560: }
1561:
1562: // external id
1563: scanExternalID(fStrings, false);
1564: String systemId = fStrings[0];
1565: String publicId = fStrings[1];
1566:
1567: if (isPEDecl && systemId != null) {
1568: fSeenExternalPE = true;
1569: }
1570:
1571: String notation = null;
1572: // NDATA
1573: boolean sawSpace = skipSeparator(true,
1574: !scanningInternalSubset());
1575: if (!isPEDecl && fEntityScanner.skipString("NDATA")) {
1576: // check whether there was space before NDATA
1577: if (!sawSpace) {
1578: reportFatalError(
1579: "MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL",
1580: new Object[] { name });
1581: }
1582:
1583: // spaces
1584: if (!skipSeparator(true, !scanningInternalSubset())) {
1585: reportFatalError(
1586: "MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
1587: new Object[] { name });
1588: }
1589: notation = fEntityScanner.scanName();
1590: if (notation == null) {
1591: reportFatalError(
1592: "MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
1593: new Object[] { name });
1594: }
1595: }
1596:
1597: // internal entity
1598: if (systemId == null) {
1599: scanEntityValue(fLiteral, fLiteral2);
1600: // since we need it's value anyway, let's snag it so it doesn't get corrupted
1601: // if a new load takes place before we store the entity values
1602: fStringBuffer.clear();
1603: fStringBuffer2.clear();
1604: fStringBuffer.append(fLiteral.ch, fLiteral.offset,
1605: fLiteral.length);
1606: fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset,
1607: fLiteral2.length);
1608: }
1609:
1610: // skip possible trailing space
1611: skipSeparator(false, !scanningInternalSubset());
1612:
1613: // end
1614: if (!fEntityScanner.skipChar('>')) {
1615: reportFatalError("EntityDeclUnterminated",
1616: new Object[] { name });
1617: }
1618: fMarkUpDepth--;
1619:
1620: // register entity and make callback
1621: if (isPEDecl) {
1622: name = "%" + name;
1623: }
1624: if (systemId != null) {
1625: String baseSystemId = fEntityScanner.getBaseSystemId();
1626: if (notation != null) {
1627: fEntityStore.addUnparsedEntity(name, publicId,
1628: systemId, baseSystemId, notation);
1629: } else {
1630: fEntityStore.addExternalEntity(name, publicId,
1631: systemId, baseSystemId);
1632: }
1633: if (fDTDHandler != null) {
1634: //Venu Revisit : why false has been removed in expandSYstem
1635: fResourceIdentifier.setValues(publicId, systemId,
1636: baseSystemId, XMLEntityManager.expandSystemId(
1637: systemId, baseSystemId));
1638:
1639: if (notation != null) {
1640: fDTDHandler.unparsedEntityDecl(name,
1641: fResourceIdentifier, notation, null);
1642: } else {
1643: fDTDHandler.externalEntityDecl(name,
1644: fResourceIdentifier, null);
1645: }
1646: }
1647: } else {
1648: fEntityStore.addInternalEntity(name, fStringBuffer
1649: .toString());
1650: if (fDTDHandler != null) {
1651: fDTDHandler.internalEntityDecl(name, fStringBuffer,
1652: fStringBuffer2, null);
1653: }
1654: }
1655: fReportEntity = true;
1656:
1657: } // scanEntityDecl()
1658:
1659: /**
1660: * Scans an entity value.
1661: *
1662: * @param value The string to fill in with the value.
1663: * @param nonNormalizedValue The string to fill in with the
1664: * non-normalized value.
1665: *
1666: * <strong>Note:</strong> This method uses fString, fStringBuffer (through
1667: * the use of scanCharReferenceValue), and fStringBuffer2, anything in them
1668: * at the time of calling is lost.
1669: */
1670: protected final void scanEntityValue(XMLString value,
1671: XMLString nonNormalizedValue) throws IOException,
1672: XNIException {
1673: int quote = fEntityScanner.scanChar();
1674: if (quote != '\'' && quote != '"') {
1675: reportFatalError("OpenQuoteMissingInDecl", null);
1676: }
1677: // store at which depth of entities we start
1678: int entityDepth = fEntityDepth;
1679:
1680: XMLString literal = fString;
1681: XMLString literal2 = fString;
1682: if (fEntityScanner.scanLiteral(quote, fString) != quote) {
1683: fStringBuffer.clear();
1684: fStringBuffer2.clear();
1685: do {
1686: fStringBuffer.append(fString);
1687: fStringBuffer2.append(fString);
1688: if (fEntityScanner.skipChar('&')) {
1689: if (fEntityScanner.skipChar('#')) {
1690: fStringBuffer2.append("&#");
1691: scanCharReferenceValue(fStringBuffer,
1692: fStringBuffer2);
1693: } else {
1694: fStringBuffer.append('&');
1695: fStringBuffer2.append('&');
1696: String eName = fEntityScanner.scanName();
1697: if (eName == null) {
1698: reportFatalError("NameRequiredInReference",
1699: null);
1700: } else {
1701: fStringBuffer.append(eName);
1702: fStringBuffer2.append(eName);
1703: }
1704: if (!fEntityScanner.skipChar(';')) {
1705: reportFatalError(
1706: "SemicolonRequiredInReference",
1707: new Object[] { eName });
1708: } else {
1709: fStringBuffer.append(';');
1710: fStringBuffer2.append(';');
1711: }
1712: }
1713: } else if (fEntityScanner.skipChar('%')) {
1714: while (true) {
1715: fStringBuffer2.append('%');
1716: String peName = fEntityScanner.scanName();
1717: if (peName == null) {
1718: reportFatalError(
1719: "NameRequiredInPEReference", null);
1720: } else if (!fEntityScanner.skipChar(';')) {
1721: reportFatalError(
1722: "SemicolonRequiredInPEReference",
1723: new Object[] { peName });
1724: } else {
1725: if (scanningInternalSubset()) {
1726: reportFatalError(
1727: "PEReferenceWithinMarkup",
1728: new Object[] { peName });
1729: }
1730: fStringBuffer2.append(peName);
1731: fStringBuffer2.append(';');
1732: }
1733: startPE(peName, true);
1734: // REVISIT: [Q] Why do we skip spaces here? -Ac
1735: // REVISIT: This will make returning the non-
1736: // normalized value harder. -Ac
1737: fEntityScanner.skipSpaces();
1738: if (!fEntityScanner.skipChar('%'))
1739: break;
1740: }
1741: } else {
1742: int c = fEntityScanner.peekChar();
1743: if (XMLChar.isHighSurrogate(c)) {
1744: scanSurrogates(fStringBuffer2);
1745: } else if (isInvalidLiteral(c)) {
1746: reportFatalError("InvalidCharInLiteral",
1747: new Object[] { Integer.toHexString(c) });
1748: fEntityScanner.scanChar();
1749: }
1750: // if it's not the delimiting quote or if it is but from a
1751: // different entity than the one this literal started from,
1752: // simply append the character to our buffer
1753: else if (c != quote || entityDepth != fEntityDepth) {
1754: fStringBuffer.append((char) c);
1755: fStringBuffer2.append((char) c);
1756: fEntityScanner.scanChar();
1757: }
1758: }
1759: } while (fEntityScanner.scanLiteral(quote, fString) != quote);
1760: fStringBuffer.append(fString);
1761: fStringBuffer2.append(fString);
1762: literal = fStringBuffer;
1763: literal2 = fStringBuffer2;
1764: }
1765: value.setValues(literal);
1766: nonNormalizedValue.setValues(literal2);
1767: if (!fEntityScanner.skipChar(quote)) {
1768: reportFatalError("CloseQuoteMissingInDecl", null);
1769: }
1770: } // scanEntityValue(XMLString,XMLString):void
1771:
1772: /**
1773: * Scans a notation declaration
1774: * <p>
1775: * <pre>
1776: * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID|PublicID) S? '>'
1777: * [83] PublicID ::= 'PUBLIC' S PubidLiteral
1778: * </pre>
1779: * <p>
1780: * <strong>Note:</strong> Called after scanning past '<!NOTATION'
1781: */
1782: private final void scanNotationDecl() throws IOException,
1783: XNIException {
1784:
1785: // spaces
1786: fReportEntity = false;
1787: if (!skipSeparator(true, !scanningInternalSubset())) {
1788: reportFatalError(
1789: "MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL",
1790: null);
1791: }
1792:
1793: // notation name
1794: String name = fEntityScanner.scanName();
1795: if (name == null) {
1796: reportFatalError(
1797: "MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL", null);
1798: }
1799:
1800: // spaces
1801: if (!skipSeparator(true, !scanningInternalSubset())) {
1802: reportFatalError(
1803: "MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL",
1804: new Object[] { name });
1805: }
1806:
1807: // external id
1808: scanExternalID(fStrings, true);
1809: String systemId = fStrings[0];
1810: String publicId = fStrings[1];
1811: String baseSystemId = fEntityScanner.getBaseSystemId();
1812:
1813: if (systemId == null && publicId == null) {
1814: reportFatalError("ExternalIDorPublicIDRequired",
1815: new Object[] { name });
1816: }
1817:
1818: // skip possible trailing space
1819: skipSeparator(false, !scanningInternalSubset());
1820:
1821: // end
1822: if (!fEntityScanner.skipChar('>')) {
1823: reportFatalError("NotationDeclUnterminated",
1824: new Object[] { name });
1825: }
1826: fMarkUpDepth--;
1827:
1828: fResourceIdentifier
1829: .setValues(publicId, systemId, baseSystemId,
1830: XMLEntityManager.expandSystemId(systemId,
1831: baseSystemId));
1832: if (nonValidatingMode)
1833: nvGrammarInfo.notationDecl(name, fResourceIdentifier, null);
1834: // call handler
1835: if (fDTDHandler != null) {
1836: //Venu Revisit wby false has been removed.
1837: //fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
1838: fDTDHandler.notationDecl(name, fResourceIdentifier, null);
1839: }
1840: fReportEntity = true;
1841:
1842: } // scanNotationDecl()
1843:
1844: /**
1845: * Scans a conditional section. If it's a section to ignore the whole
1846: * section gets scanned through and this method only returns after the
1847: * closing bracket has been found. When it's an include section though, it
1848: * returns to let the main loop take care of scanning it. In that case the
1849: * end of the section if handled by the main loop (scanDecls).
1850: * <p>
1851: * <pre>
1852: * [61] conditionalSect ::= includeSect | ignoreSect
1853: * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1854: * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
1855: * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
1856: * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
1857: * </pre>
1858: * <p>
1859: * <strong>Note:</strong> Called after scanning past '<![' */
1860: private final void scanConditionalSect(int currPEDepth)
1861: throws IOException, XNIException {
1862:
1863: fReportEntity = false;
1864: skipSeparator(false, !scanningInternalSubset());
1865:
1866: if (fEntityScanner.skipString("INCLUDE")) {
1867: skipSeparator(false, !scanningInternalSubset());
1868: if (currPEDepth != fPEDepth && fValidation) {
1869: fErrorReporter
1870: .reportError(
1871: XMLMessageFormatter.XML_DOMAIN,
1872: "INVALID_PE_IN_CONDITIONAL",
1873: new Object[] { fEntityManager.fCurrentEntity.name },
1874: XMLErrorReporter.SEVERITY_ERROR);
1875: }
1876: // call handler
1877: if (!fEntityScanner.skipChar('[')) {
1878: reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1879: null);
1880: }
1881:
1882: if (fDTDHandler != null) {
1883: fDTDHandler.startConditional(
1884: XMLDTDHandler.CONDITIONAL_INCLUDE, null);
1885: }
1886: fIncludeSectDepth++;
1887: // just stop there and go back to the main loop
1888: fReportEntity = true;
1889: } else if (fEntityScanner.skipString("IGNORE")) {
1890: skipSeparator(false, !scanningInternalSubset());
1891: if (currPEDepth != fPEDepth && fValidation) {
1892: fErrorReporter
1893: .reportError(
1894: XMLMessageFormatter.XML_DOMAIN,
1895: "INVALID_PE_IN_CONDITIONAL",
1896: new Object[] { fEntityManager.fCurrentEntity.name },
1897: XMLErrorReporter.SEVERITY_ERROR);
1898: }
1899: // call handler
1900: if (fDTDHandler != null) {
1901: fDTDHandler.startConditional(
1902: XMLDTDHandler.CONDITIONAL_IGNORE, null);
1903: }
1904: if (!fEntityScanner.skipChar('[')) {
1905: reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1906: null);
1907: }
1908: fReportEntity = true;
1909: int initialDepth = ++fIncludeSectDepth;
1910: if (fDTDHandler != null) {
1911: fIgnoreConditionalBuffer.clear();
1912: }
1913: while (true) {
1914: if (fEntityScanner.skipChar('<')) {
1915: if (fDTDHandler != null) {
1916: fIgnoreConditionalBuffer.append('<');
1917: }
1918: //
1919: // These tests are split so that we handle cases like
1920: // '<<![' and '<!<![' which we might otherwise miss.
1921: //
1922: if (fEntityScanner.skipChar('!')) {
1923: if (fEntityScanner.skipChar('[')) {
1924: if (fDTDHandler != null) {
1925: fIgnoreConditionalBuffer.append("![");
1926: }
1927: fIncludeSectDepth++;
1928: } else {
1929: if (fDTDHandler != null) {
1930: fIgnoreConditionalBuffer.append("!");
1931: }
1932: }
1933: }
1934: } else if (fEntityScanner.skipChar(']')) {
1935: if (fDTDHandler != null) {
1936: fIgnoreConditionalBuffer.append(']');
1937: }
1938: //
1939: // The same thing goes for ']<![' and '<]]>', etc.
1940: //
1941: if (fEntityScanner.skipChar(']')) {
1942: if (fDTDHandler != null) {
1943: fIgnoreConditionalBuffer.append(']');
1944: }
1945: while (fEntityScanner.skipChar(']')) {
1946: /* empty loop body */
1947: if (fDTDHandler != null) {
1948: fIgnoreConditionalBuffer.append(']');
1949: }
1950: }
1951: if (fEntityScanner.skipChar('>')) {
1952: if (fIncludeSectDepth-- == initialDepth) {
1953: fMarkUpDepth--;
1954: // call handler
1955: if (fDTDHandler != null) {
1956: fLiteral
1957: .setValues(
1958: fIgnoreConditionalBuffer.ch,
1959: 0,
1960: fIgnoreConditionalBuffer.length - 2);
1961: fDTDHandler.ignoredCharacters(
1962: fLiteral, null);
1963: fDTDHandler.endConditional(null);
1964: }
1965: return;
1966: } else if (fDTDHandler != null) {
1967: fIgnoreConditionalBuffer.append('>');
1968: }
1969: }
1970: }
1971: } else {
1972: int c = fEntityScanner.scanChar();
1973: if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
1974: reportFatalError("IgnoreSectUnterminated", null);
1975: return;
1976: }
1977: if (fDTDHandler != null) {
1978: fIgnoreConditionalBuffer.append((char) c);
1979: }
1980: }
1981: }
1982: } else {
1983: reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1984: }
1985:
1986: } // scanConditionalSect()
1987:
1988: /**
1989: * Dispatch an XML "event".
1990: *
1991: * @param complete True if this method is intended to scan
1992: * and dispatch as much as possible.
1993: *
1994: * @return True if there is more to scan.
1995: *
1996: * @throws IOException Thrown on i/o error.
1997: * @throws XNIException Thrown on parse error.
1998: *
1999: */
2000: protected final boolean scanDecls(boolean complete)
2001: throws IOException, XNIException {
2002:
2003: skipSeparator(false, true);
2004: boolean again = true;
2005: //System.out.println("scanDecls"+fScannerState);
2006: while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
2007: again = complete;
2008: if (fEntityScanner.skipChar('<')) {
2009: fMarkUpDepth++;
2010: if (fEntityScanner.skipChar('?')) {
2011: fStringBuffer.clear();
2012: scanPI(fStringBuffer);
2013: } else if (fEntityScanner.skipChar('!')) {
2014: if (fEntityScanner.skipChar('-')) {
2015: if (!fEntityScanner.skipChar('-')) {
2016: reportFatalError(
2017: "MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
2018: null);
2019: } else {
2020: scanComment();
2021: }
2022: } else if (fEntityScanner.skipString("ELEMENT")) {
2023: scanElementDecl();
2024: } else if (fEntityScanner.skipString("ATTLIST")) {
2025: scanAttlistDecl();
2026: } else if (fEntityScanner.skipString("ENTITY")) {
2027: scanEntityDecl();
2028: } else if (fEntityScanner.skipString("NOTATION")) {
2029: scanNotationDecl();
2030: } else if (fEntityScanner.skipChar('[')
2031: && !scanningInternalSubset()) {
2032: scanConditionalSect(fPEDepth);
2033: } else {
2034: fMarkUpDepth--;
2035: reportFatalError(
2036: "MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
2037: null);
2038: }
2039: } else {
2040: fMarkUpDepth--;
2041: reportFatalError(
2042: "MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
2043: }
2044: } else if (fIncludeSectDepth > 0
2045: && fEntityScanner.skipChar(']')) {
2046: // end of conditional section?
2047: if (!fEntityScanner.skipChar(']')
2048: || !fEntityScanner.skipChar('>')) {
2049: reportFatalError("IncludeSectUnterminated", null);
2050: }
2051: // call handler
2052: if (fDTDHandler != null) {
2053: fDTDHandler.endConditional(null);
2054: }
2055: // decreaseMarkupDepth();
2056: fIncludeSectDepth--;
2057: fMarkUpDepth--;
2058: } else if (scanningInternalSubset()
2059: && fEntityScanner.peekChar() == ']') {
2060: // this is the end of the internal subset, let's stop here
2061: return false;
2062: } else if (fEntityScanner.skipSpaces()) {
2063: // simply skip
2064: } else {
2065: reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
2066: null);
2067: }
2068: skipSeparator(false, true);
2069: }
2070: return fScannerState != SCANNER_STATE_END_OF_INPUT;
2071: }
2072:
2073: /**
2074: * Skip separator. This is typically just whitespace but it can also be one
2075: * or more parameter entity references.
2076: * <p>
2077: * If there are some it "expands them" by calling the corresponding entity
2078: * from the entity manager.
2079: * <p>
2080: * This is recursive and will process has many refs as possible.
2081: *
2082: * @param spaceRequired Specify whether some leading whitespace should be
2083: * found
2084: * @param lookForPERefs Specify whether parameter entity references should
2085: * be looked for
2086: * @return True if any leading whitespace was found or the end of a
2087: * parameter entity was crossed.
2088: */
2089: private boolean skipSeparator(boolean spaceRequired,
2090: boolean lookForPERefs) throws IOException, XNIException {
2091: int depth = fPEDepth;
2092: boolean sawSpace = fEntityScanner.skipSpaces();
2093: if (!lookForPERefs || !fEntityScanner.skipChar('%')) {
2094: return !spaceRequired || sawSpace || (depth != fPEDepth);
2095: }
2096: while (true) {
2097: String name = fEntityScanner.scanName();
2098: if (name == null) {
2099: reportFatalError("NameRequiredInPEReference", null);
2100: } else if (!fEntityScanner.skipChar(';')) {
2101: reportFatalError("SemicolonRequiredInPEReference",
2102: new Object[] { name });
2103: }
2104: startPE(name, false);
2105: fEntityScanner.skipSpaces();
2106: if (!fEntityScanner.skipChar('%'))
2107: return true;
2108: }
2109: }
2110:
2111: /*
2112: * Element Children Content Stack
2113: */
2114: private final void pushContentStack(int c) {
2115: if (fContentStack.length == fContentDepth) {
2116: int[] newStack = new int[fContentDepth * 2];
2117: System.arraycopy(fContentStack, 0, newStack, 0,
2118: fContentDepth);
2119: fContentStack = newStack;
2120: }
2121: fContentStack[fContentDepth++] = c;
2122: }
2123:
2124: private final int popContentStack() {
2125: return fContentStack[--fContentDepth];
2126: }
2127:
2128: /*
2129: * Parameter Entity Stack
2130: */
2131: private final void pushPEStack(int depth, boolean report) {
2132: if (fPEStack.length == fPEDepth) {
2133: int[] newIntStack = new int[fPEDepth * 2];
2134: System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth);
2135: fPEStack = newIntStack;
2136: // report end/start calls
2137: boolean[] newBooleanStack = new boolean[fPEDepth * 2];
2138: System
2139: .arraycopy(fPEReport, 0, newBooleanStack, 0,
2140: fPEDepth);
2141: fPEReport = newBooleanStack;
2142:
2143: }
2144: fPEReport[fPEDepth] = report;
2145: fPEStack[fPEDepth++] = depth;
2146: }
2147:
2148: /** pop the stack */
2149: private final int popPEStack() {
2150: return fPEStack[--fPEDepth];
2151: }
2152:
2153: /** look at the top of the stack */
2154: private final boolean peekReportEntity() {
2155: return fPEReport[fPEDepth - 1];
2156: }
2157:
2158: /*
2159: * Utility method
2160: */
2161: private final void ensureEnumerationSize(int size) {
2162: if (fEnumeration.length == size) {
2163: String[] newEnum = new String[size * 2];
2164: System.arraycopy(fEnumeration, 0, newEnum, 0, size);
2165: fEnumeration = newEnum;
2166: }
2167: }
2168:
2169: // private methods
2170: private void init() {
2171: // reset state related data
2172: fStartDTDCalled = false;
2173: fExtEntityDepth = 0;
2174: fIncludeSectDepth = 0;
2175: fMarkUpDepth = 0;
2176: fPEDepth = 0;
2177:
2178: fStandalone = false;
2179: fSeenExternalDTD = false;
2180: fSeenExternalPE = false;
2181:
2182: // set starting state
2183: fSymbolTable = (SymbolTable) fPropertyManager
2184: .getProperty(Constants.XERCES_PROPERTY_PREFIX
2185: + Constants.SYMBOL_TABLE_PROPERTY);
2186: setScannerState(SCANNER_STATE_TEXT_DECL);
2187: //Revisit : Create new grammar until we implement GrammarPool.
2188: nvGrammarInfo = new DTDGrammar(fSymbolTable);
2189: //new SymbolTable());
2190: }
2191:
2192: public DTDGrammar getGrammar() {
2193: return nvGrammarInfo;
2194: }
2195:
2196: } // class XMLDTDScannerImpl
|