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.readers;
0059:
0060: import java.io.FileNotFoundException;
0061: import java.io.UnsupportedEncodingException;
0062: import java.net.MalformedURLException;
0063: import java.util.Stack;
0064: import java.util.Vector;
0065:
0066: import org.apache.xerces.framework.XMLErrorReporter;
0067: import org.apache.xerces.utils.ImplementationMessages;
0068: import org.apache.xerces.utils.QName;
0069: import org.apache.xerces.utils.StringPool;
0070: import org.apache.xerces.utils.URI;
0071: import org.apache.xerces.utils.XMLCharacterProperties;
0072: import org.apache.xerces.utils.XMLMessages;
0073:
0074: import org.xml.sax.EntityResolver;
0075: import org.xml.sax.InputSource;
0076: import org.xml.sax.Locator;
0077: import org.xml.sax.helpers.LocatorImpl;
0078:
0079: /**
0080: * Default entity handler implementation.
0081: *
0082: * @version $Id: DefaultEntityHandler.java,v 1.8.2.2 2001/11/05 19:48:21 neilg Exp $
0083: */
0084: public class DefaultEntityHandler implements XMLEntityHandler,
0085: XMLEntityHandler.DTDHandler {
0086:
0087: public interface EventHandler {
0088: public void startEntityReference(int entityName,
0089: int entityType, int entityContext) throws Exception;
0090:
0091: public void endEntityReference(int entityName, int entityType,
0092: int entityContext) throws Exception;
0093:
0094: public void sendEndOfInputNotifications(int entityName,
0095: boolean moreToFollow) throws Exception;
0096:
0097: public void sendReaderChangeNotifications(
0098: XMLEntityHandler.EntityReader reader, int readerId)
0099: throws Exception;
0100:
0101: public boolean externalEntityStandaloneCheck();
0102:
0103: public boolean getValidating();
0104: }
0105:
0106: //
0107: // Data
0108: //
0109: private class ReaderState {
0110: XMLEntityHandler.EntityReader reader;
0111: InputSource source;
0112: int entityName;
0113: int entityType;
0114: int entityContext;
0115: String publicId;
0116: String systemId;
0117: int readerId;
0118: int depth;
0119: ReaderState nextReaderState;
0120: }
0121:
0122: private ReaderState fReaderStateFreeList = null;
0123: private StringPool fStringPool = null;
0124: private EventHandler fEventHandler = null;
0125: private XMLEntityHandler.CharDataHandler fCharDataHandler = null;
0126: private XMLErrorReporter fErrorReporter = null;
0127: private EntityResolver fResolver = null;
0128: private EntityPool fEntityPool = null;
0129: private EntityPool fParameterEntityPool = null;
0130: private byte[] fEntityTypeStack = null;
0131: private int[] fEntityNameStack = null;
0132: private int fEntityStackDepth = 0;
0133: private Stack fReaderStack = new Stack();
0134: private XMLEntityHandler.EntityReader fReader = null;
0135: private InputSource fSource = null;
0136: private int fEntityName = -1;
0137: private int fEntityType = -1;
0138: private int fEntityContext = -1;
0139: private String fPublicId = null;
0140: private String fSystemId = null;
0141: private int fReaderId = -1;
0142: private int fReaderDepth = -1;
0143: private int fNextReaderId = 0;
0144: private NullReader fNullReader = null;
0145: protected XMLEntityReaderFactory fReaderFactory = null;
0146: private boolean fSendCharDataAsCharArray = false;
0147:
0148: public DefaultEntityHandler(StringPool stringPool,
0149: XMLErrorReporter errorReporter) {
0150: fStringPool = stringPool;
0151: fErrorReporter = errorReporter;
0152: fReaderFactory = new DefaultReaderFactory();
0153: fEntityPool = new EntityPool(fStringPool, fErrorReporter, true);
0154: }
0155:
0156: public void setEventHandler(EventHandler eventHandler) {
0157: fEventHandler = eventHandler;
0158: }
0159:
0160: public void setCharDataHandler(
0161: XMLEntityHandler.CharDataHandler charDataHandler) {
0162: fCharDataHandler = charDataHandler;
0163: }
0164:
0165: public XMLEntityHandler.CharDataHandler getCharDataHandler() {
0166: return fCharDataHandler;
0167: }
0168:
0169: /**
0170: * Set char data processing preference.
0171: */
0172: public void setSendCharDataAsCharArray(boolean flag) {
0173: fSendCharDataAsCharArray = flag;
0174: fReaderFactory
0175: .setSendCharDataAsCharArray(fSendCharDataAsCharArray);
0176: }
0177:
0178: /**
0179: * Set the reader factory.
0180: */
0181: public void setReaderFactory(XMLEntityReaderFactory readerFactory) {
0182: fReaderFactory = readerFactory;
0183: fReaderFactory
0184: .setSendCharDataAsCharArray(fSendCharDataAsCharArray);
0185: }
0186:
0187: /**
0188: * Reset the entity handler.
0189: */
0190: public void reset(StringPool stringPool) {
0191: fStringPool = stringPool;
0192: fEntityPool.reset(fStringPool);
0193: fParameterEntityPool = null;
0194: fReaderStack.removeAllElements();
0195: fEntityStackDepth = 0;
0196: fReader = null;
0197: fSource = null;
0198: fEntityName = -1;
0199: fEntityType = -1;
0200: fEntityContext = -1;
0201: fPublicId = null;
0202: fSystemId = null;
0203: fReaderId = -1;
0204: fReaderDepth = -1;
0205: fNextReaderId = 0;
0206: }
0207:
0208: /**
0209: *
0210: */
0211: public void setAllowJavaEncodings(boolean flag) {
0212: fReaderFactory.setAllowJavaEncodingName(flag);
0213: }
0214:
0215: /**
0216: *
0217: */
0218: public boolean getAllowJavaEncodings() {
0219: return fReaderFactory.getAllowJavaEncodingName();
0220: }
0221:
0222: //
0223: //
0224: //
0225: public int addInternalPEDecl(int name, int value, boolean isExternal)
0226: throws Exception {
0227: if (fParameterEntityPool == null)
0228: fParameterEntityPool = new EntityPool(fStringPool,
0229: fErrorReporter, false);
0230: int entityHandle = fParameterEntityPool.addEntityDecl(name,
0231: value, -1, -1, -1, -1, isExternal);
0232: return entityHandle;
0233: }
0234:
0235: public int addExternalPEDecl(int name, int publicId, int systemId,
0236: boolean isExternal) throws Exception {
0237: if (fParameterEntityPool == null)
0238: fParameterEntityPool = new EntityPool(fStringPool,
0239: fErrorReporter, false);
0240: int entityHandle = fParameterEntityPool.addEntityDecl(name, -1,
0241: publicId, systemId, fStringPool.addSymbol(fSystemId),
0242: -1, isExternal);
0243: return entityHandle;
0244: }
0245:
0246: public int addInternalEntityDecl(int name, int value,
0247: boolean isExternal) throws Exception {
0248: int entityHandle = fEntityPool.addEntityDecl(name, value, -1,
0249: -1, -1, -1, isExternal);
0250: return entityHandle;
0251: }
0252:
0253: public int addExternalEntityDecl(int name, int publicId,
0254: int systemId, boolean isExternal) throws Exception {
0255: int entityHandle = fEntityPool.addEntityDecl(name, -1,
0256: publicId, systemId, fStringPool.addSymbol(fSystemId),
0257: -1, isExternal);
0258: return entityHandle;
0259: }
0260:
0261: public int addUnparsedEntityDecl(int name, int publicId,
0262: int systemId, int notationName, boolean isExternal)
0263: throws Exception {
0264: int entityHandle = fEntityPool.addEntityDecl(name, -1,
0265: publicId, systemId, fStringPool.addSymbol(fSystemId),
0266: notationName, isExternal);
0267: if (!fEntityPool.isNotationDeclared(notationName)) {
0268: Object[] args = { fStringPool.toString(name),
0269: fStringPool.toString(notationName) };
0270: fEntityPool
0271: .addRequiredNotation(
0272: notationName,
0273: fErrorReporter.getLocator(),
0274: XMLMessages.MSG_NOTATION_NOT_DECLARED_FOR_UNPARSED_ENTITYDECL,
0275: XMLMessages.VC_NOTATION_DECLARED, args);
0276: }
0277: return entityHandle;
0278: }
0279:
0280: public int addNotationDecl(int notationName, int publicId,
0281: int systemId, boolean isExternal) throws Exception {
0282: int notationHandle = fEntityPool.addNotationDecl(notationName,
0283: publicId, systemId, fStringPool.addSymbol(fSystemId),
0284: isExternal);
0285: return notationHandle;
0286: }
0287:
0288: public boolean isUnparsedEntity(int entityName) {
0289: int entityHandle = fEntityPool.lookupEntity(entityName);
0290: return (entityHandle != -1 && fEntityPool
0291: .isUnparsedEntity(entityHandle));
0292: }
0293:
0294: public boolean isNotationDeclared(int notationName) {
0295: return fEntityPool.isNotationDeclared(notationName);
0296: }
0297:
0298: public void addRequiredNotation(int notationName, Locator locator,
0299: int majorCode, int minorCode, Object[] args) {
0300: fEntityPool.addRequiredNotation(notationName, locator,
0301: majorCode, minorCode, args);
0302: }
0303:
0304: public void checkRequiredNotations() throws Exception {
0305: fEntityPool.checkRequiredNotations();
0306: }
0307:
0308: protected int lookupEntity(int entityNameIndex) {
0309: int entityIndex = fEntityPool.lookupEntity(entityNameIndex);
0310: return entityIndex;
0311: }
0312:
0313: private void reportRecoverableXMLError(int majorCode,
0314: int minorCode, int stringIndex1) throws Exception {
0315: Object[] args = { fStringPool.toString(stringIndex1) };
0316: fErrorReporter.reportError(fErrorReporter.getLocator(),
0317: XMLMessages.XML_DOMAIN, majorCode, minorCode, args,
0318: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
0319: }
0320:
0321: public boolean externalReferenceInContent(int entityHandle)
0322: throws Exception {
0323: boolean external = fEntityPool.isExternalEntity(entityHandle);
0324: if (fEventHandler.externalEntityStandaloneCheck()) {
0325: if (external) {
0326: reportRecoverableXMLError(
0327: XMLMessages.MSG_EXTERNAL_ENTITY_NOT_PERMITTED,
0328: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
0329: fEntityName);
0330: } else if (fEntityPool
0331: .getEntityDeclIsExternal(entityHandle)) {
0332: reportRecoverableXMLError(
0333: XMLMessages.MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE,
0334: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
0335: fEntityName);
0336: }
0337: }
0338: return external;
0339: }
0340:
0341: protected int valueOfReferenceInAttValue(int entityHandle)
0342: throws Exception {
0343: if (fEventHandler.externalEntityStandaloneCheck()
0344: && fEntityPool.getEntityDeclIsExternal(entityHandle)) {
0345: reportRecoverableXMLError(
0346: XMLMessages.MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE,
0347: XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION,
0348: fEntityName);
0349: }
0350: int entityValue = fEntityPool.getEntityValue(entityHandle);
0351: return entityValue;
0352: }
0353:
0354: protected boolean isExternalEntity(int entityHandle) {
0355: boolean external = fEntityPool.isExternalEntity(entityHandle);
0356: return external;
0357: }
0358:
0359: protected int getEntityValue(int entityHandle) {
0360: int value = fEntityPool.getEntityValue(entityHandle);
0361: return value;
0362: }
0363:
0364: protected String getPublicIdOfEntity(int entityHandle) {
0365: int publicId = fEntityPool.getPublicId(entityHandle);
0366: return fStringPool.toString(publicId);
0367: }
0368:
0369: protected String getSystemIdOfEntity(int entityHandle) {
0370: int systemId = fEntityPool.getSystemId(entityHandle);
0371: return fStringPool.toString(systemId);
0372: }
0373:
0374: protected int lookupParameterEntity(int peName) throws Exception {
0375: int entityHandle = -1;
0376: if (fParameterEntityPool != null)
0377: entityHandle = fParameterEntityPool.lookupEntity(peName);
0378: return entityHandle;
0379: }
0380:
0381: protected boolean isExternalParameterEntity(int peIndex) {
0382: boolean external = fParameterEntityPool
0383: .isExternalEntity(peIndex);
0384: return external;
0385: }
0386:
0387: protected int getParameterEntityValue(int peIndex) {
0388: int value = fParameterEntityPool.getEntityValue(peIndex);
0389: return value;
0390: }
0391:
0392: protected String getPublicIdOfParameterEntity(int peIndex) {
0393: int publicId = fParameterEntityPool.getPublicId(peIndex);
0394: return fStringPool.toString(publicId);
0395: }
0396:
0397: protected String getSystemIdOfParameterEntity(int peIndex) {
0398: int systemId = fParameterEntityPool.getSystemId(peIndex);
0399: return fStringPool.toString(systemId);
0400: }
0401:
0402: /**
0403: * get the Entity reader.
0404: */
0405: public XMLEntityHandler.EntityReader getEntityReader() {
0406: return fReader;
0407: }
0408:
0409: /**
0410: * Adds a recognizer.
0411: *
0412: * @param recognizer The XML recognizer to add.
0413: */
0414: public void addRecognizer(XMLDeclRecognizer recognizer) {
0415: fReaderFactory.addRecognizer(recognizer);
0416: }
0417:
0418: /**
0419: * Sets the resolver used to resolve external entities. The EntityResolver
0420: * interface supports resolution of public and system identifiers.
0421: *
0422: * @param resolver The new entity resolver. Passing a null value will
0423: * uninstall the currently installed resolver.
0424: */
0425: public void setEntityResolver(EntityResolver resolver) {
0426: fResolver = resolver;
0427: }
0428:
0429: /**
0430: * Gets the resolver used to resolve external entities. The EntityResolver
0431: * interface supports resolution of public and system identifiers.
0432: *
0433: * @return The current entity resolver.
0434: */
0435: public EntityResolver getEntityResolver() {
0436: return fResolver;
0437: }
0438:
0439: /**
0440: * Expands a system id and returns the system id as a URI, if
0441: * it can be expanded. A return value of null means that the
0442: * identifier is already expanded. An exception thrown
0443: * indicates a failure to expand the id.
0444: *
0445: * @param systemId The systemId to be expanded.
0446: *
0447: * @return Returns the URI string representing the expanded system
0448: * identifier. A null value indicates that the given
0449: * system identifier is already expanded.
0450: *
0451: */
0452: public String expandSystemId(String systemId) {
0453: return expandSystemId(systemId, fSystemId);
0454: }
0455:
0456: private String expandSystemId(String systemId,
0457: String currentSystemId) {
0458: String id = systemId;
0459:
0460: // check for bad parameters id
0461: if (id == null || id.length() == 0) {
0462: // REVISIT: returning null here will result in NPE
0463: // for notations and entity declarations
0464: return "";
0465: }
0466:
0467: // if id already expanded, return
0468: try {
0469: URI uri = new URI(id);
0470: if (uri != null) {
0471: return systemId;
0472: }
0473: } catch (URI.MalformedURIException e) {
0474: // continue on...
0475: }
0476:
0477: // normalize id
0478: id = fixURI(id);
0479:
0480: // normalize base
0481: URI base = null;
0482: URI uri = null;
0483: try {
0484: if (currentSystemId == null) {
0485: String dir;
0486: try {
0487: dir = fixURI(System.getProperty("user.dir"));
0488: } catch (SecurityException se) {
0489: dir = "";
0490: }
0491: if (!dir.endsWith("/")) {
0492: dir = dir + "/";
0493: }
0494: base = new URI("file", "", dir, null, null);
0495: } else {
0496: base = new URI(currentSystemId);
0497: }
0498:
0499: // expand id
0500: uri = new URI(base, id);
0501: } catch (Exception e) {
0502: // let it go through
0503: }
0504: if (uri == null) {
0505: return systemId;
0506: }
0507: return uri.toString();
0508: }
0509:
0510: //
0511: // Private methods
0512: //
0513:
0514: /**
0515: * Fixes a platform dependent filename to standard URI form.
0516: *
0517: * @param str The string to fix.
0518: *
0519: * @return Returns the fixed URI string.
0520: */
0521: private static String fixURI(String str) {
0522:
0523: // handle platform dependent strings
0524: str = str.replace(java.io.File.separatorChar, '/');
0525:
0526: // Windows fix
0527: if (str.length() >= 2) {
0528: char ch1 = str.charAt(1);
0529: if (ch1 == ':') {
0530: char ch0 = Character.toUpperCase(str.charAt(0));
0531: if (ch0 >= 'A' && ch0 <= 'Z') {
0532: str = "/" + str;
0533: }
0534: }
0535: }
0536:
0537: // done
0538: return str;
0539: }
0540:
0541: public boolean startReadingFromDocument(InputSource source)
0542: throws Exception {
0543: pushEntity(false, -2); // Document Entity
0544: fSystemId = null;
0545: pushNullReader();
0546: fEntityName = -2; // Document Entity
0547: fEntityType = ENTITYTYPE_DOCUMENT;
0548: fEntityContext = ENTITYREF_DOCUMENT;
0549: fReaderDepth = 0;
0550: fReaderId = fNextReaderId++;
0551: fPublicId = source.getPublicId();
0552: fSystemId = source.getSystemId();
0553: fEventHandler.startEntityReference(fEntityName, fEntityType,
0554: fEntityContext);
0555: fSystemId = expandSystemId(fSystemId, null);
0556: fSource = source;
0557: boolean xmlDecl = true; // xmlDecl if true, textDecl if false
0558: try {
0559: fReader = fReaderFactory.createReader(this , fErrorReporter,
0560: source, fSystemId, xmlDecl, fStringPool);
0561: } catch (MalformedURLException mu) {
0562: String errorSystemId = fSystemId;
0563: fEventHandler.endEntityReference(fEntityName, fEntityType,
0564: fEntityContext);
0565: popReader();
0566: popEntity();
0567: fReader = null;
0568: Object[] args = { errorSystemId };
0569: fErrorReporter
0570: .reportError(
0571: fErrorReporter.getLocator(),
0572: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
0573: ImplementationMessages.IO0, 0, args,
0574: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0575: } catch (FileNotFoundException fnf) {
0576: // according to the JAXP spec, SAXExceptions should not be
0577: // generated in this case! - neilg
0578: String errorSystemId = fSystemId;
0579: fEventHandler.endEntityReference(fEntityName, fEntityType,
0580: fEntityContext);
0581: popReader();
0582: popEntity();
0583: fReader = null;
0584: Object[] args = { errorSystemId };
0585: fErrorReporter
0586: .reportError(
0587: fErrorReporter.getLocator(),
0588: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
0589: ImplementationMessages.IO0,
0590: 0,
0591: args,
0592: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
0593: throw fnf;
0594: } catch (UnsupportedEncodingException uee) {
0595: fEventHandler.endEntityReference(fEntityName, fEntityType,
0596: fEntityContext);
0597: popReader();
0598: popEntity();
0599: fReader = null;
0600: String encoding = uee.getMessage();
0601: if (encoding == null) {
0602: fErrorReporter.reportError(fErrorReporter.getLocator(),
0603: XMLMessages.XML_DOMAIN,
0604: XMLMessages.MSG_ENCODING_REQUIRED,
0605: XMLMessages.P81_REQUIRED, null,
0606: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0607: } else if (!XMLCharacterProperties.validEncName(encoding)) {
0608: Object[] args = { encoding };
0609: fErrorReporter.reportError(fErrorReporter.getLocator(),
0610: XMLMessages.XML_DOMAIN,
0611: XMLMessages.MSG_ENCODINGDECL_INVALID,
0612: XMLMessages.P81_INVALID_VALUE, args,
0613: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0614: } else {
0615: Object[] args = { encoding };
0616: fErrorReporter.reportError(fErrorReporter.getLocator(),
0617: XMLMessages.XML_DOMAIN,
0618: XMLMessages.MSG_ENCODING_NOT_SUPPORTED,
0619: XMLMessages.P81_NOT_SUPPORTED, args,
0620: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0621: }
0622: }
0623: fEventHandler.sendReaderChangeNotifications(fReader, fReaderId);
0624: return fReader != null;
0625: }
0626:
0627: /**
0628: * start reading from an external DTD subset
0629: */
0630: public void startReadingFromExternalSubset(String publicId,
0631: String systemId, int readerDepth) throws Exception {
0632: pushEntity(true, -1);
0633: pushReader();
0634: pushNullReader();
0635: fEntityName = -1; // External Subset
0636: fEntityType = ENTITYTYPE_EXTERNAL_SUBSET;
0637: fEntityContext = ENTITYREF_EXTERNAL_SUBSET;
0638: fReaderDepth = readerDepth;
0639: fReaderId = fNextReaderId++;
0640: fPublicId = publicId;
0641: fSystemId = systemId;
0642: startReadingFromExternalEntity(false, -1);
0643: }
0644:
0645: /**
0646: * stop reading from an external DTD subset
0647: */
0648: public void stopReadingFromExternalSubset() throws Exception {
0649: if (!(fReader instanceof NullReader))
0650: throw new RuntimeException("FWK004 cannot happen 18"
0651: + "\n18");
0652: popReader();
0653: fEventHandler.sendReaderChangeNotifications(fReader, fReaderId);
0654: }
0655:
0656: /**
0657: * start reading from an external entity
0658: */
0659: public boolean startReadingFromEntity(int entityName,
0660: int readerDepth, int context) throws Exception {
0661: if (context > XMLEntityHandler.ENTITYREF_IN_CONTENT)
0662: return startReadingFromParameterEntity(entityName,
0663: readerDepth, context);
0664: int entityHandle = lookupEntity(entityName);
0665: if (entityHandle < 0) {
0666: int minorCode = XMLMessages.VC_ENTITY_DECLARED;
0667: int errorType = XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR;
0668: // REVISIT - the following test in insufficient...
0669: if (fEntityContext == ENTITYREF_DOCUMENT
0670: || fEntityContext == ENTITYREF_IN_ATTVALUE) {
0671: minorCode = XMLMessages.WFC_ENTITY_DECLARED;
0672: errorType = XMLErrorReporter.ERRORTYPE_FATAL_ERROR;
0673: } else if (!fEventHandler.getValidating()) {
0674: return false;
0675: }
0676: Object[] args = { fStringPool.toString(entityName) };
0677: fErrorReporter.reportError(fErrorReporter.getLocator(),
0678: XMLMessages.XML_DOMAIN,
0679: XMLMessages.MSG_ENTITY_NOT_DECLARED, minorCode,
0680: args, errorType);
0681: return false;
0682: }
0683: if (context == ENTITYREF_IN_CONTENT) {
0684: if (fEntityPool.isUnparsedEntity(entityHandle)) {
0685: Object[] args = { fStringPool.toString(entityName) };
0686: fErrorReporter.reportError(fErrorReporter.getLocator(),
0687: XMLMessages.XML_DOMAIN,
0688: XMLMessages.MSG_REFERENCE_TO_UNPARSED_ENTITY,
0689: XMLMessages.WFC_PARSED_ENTITY, args,
0690: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0691: return false;
0692: }
0693: } else {
0694: if (isExternalEntity(entityHandle)) {
0695: Object[] args = { fStringPool.toString(entityName) };
0696: fErrorReporter.reportError(fErrorReporter.getLocator(),
0697: XMLMessages.XML_DOMAIN,
0698: XMLMessages.MSG_REFERENCE_TO_EXTERNAL_ENTITY,
0699: XMLMessages.WFC_NO_EXTERNAL_ENTITY_REFERENCES,
0700: args, XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0701: return false;
0702: }
0703: }
0704: if (!pushEntity(false, entityName)) {
0705: Object[] args = { fStringPool.toString(entityName),
0706: entityReferencePath(false, entityName) };
0707: fErrorReporter.reportError(fErrorReporter.getLocator(),
0708: XMLMessages.XML_DOMAIN,
0709: XMLMessages.MSG_RECURSIVE_REFERENCE,
0710: XMLMessages.WFC_NO_RECURSION, args,
0711: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0712: return false;
0713: }
0714: pushReader();
0715: fEntityName = entityName;
0716: fEntityContext = context;
0717: fReaderDepth = readerDepth;
0718: fReaderId = fNextReaderId++;
0719: if (context != ENTITYREF_IN_CONTENT
0720: || !externalReferenceInContent(entityHandle)) {
0721: fEntityType = ENTITYTYPE_INTERNAL;
0722: fPublicId = null/*"Internal Entity: " + fStringPool.toString(entityName)*/;
0723: fSystemId = fSystemId; // keep expandSystemId happy
0724: int value = -1;
0725: if (context == ENTITYREF_IN_CONTENT
0726: || context == ENTITYREF_IN_DEFAULTATTVALUE)
0727: value = getEntityValue(entityHandle);
0728: else
0729: value = valueOfReferenceInAttValue(entityHandle);
0730: startReadingFromInternalEntity(value, false);
0731: return false;
0732: }
0733: fEntityType = ENTITYTYPE_EXTERNAL;
0734: fPublicId = getPublicIdOfEntity(entityHandle);
0735: fSystemId = getSystemIdOfEntity(entityHandle);
0736: return startReadingFromExternalEntity(true, entityHandle);
0737: }
0738:
0739: private boolean startReadingFromParameterEntity(int peName,
0740: int readerDepth, int context) throws Exception {
0741: int entityHandle = lookupParameterEntity(peName);
0742: if (entityHandle == -1) {
0743: // strange... this is a VC, not a WFC...
0744: if (fEventHandler.getValidating()) {
0745: reportRecoverableXMLError(
0746: XMLMessages.MSG_ENTITY_NOT_DECLARED,
0747: XMLMessages.VC_ENTITY_DECLARED, peName);
0748: }
0749: return false;
0750: }
0751: if (!pushEntity(true, peName)) {
0752: Object[] args = { fStringPool.toString(peName),
0753: entityReferencePath(true, peName) };
0754: fErrorReporter.reportError(fErrorReporter.getLocator(),
0755: XMLMessages.XML_DOMAIN,
0756: XMLMessages.MSG_RECURSIVE_PEREFERENCE,
0757: XMLMessages.WFC_NO_RECURSION, args,
0758: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0759: return false;
0760: }
0761: pushReader();
0762: fEntityName = peName;
0763: fEntityContext = context;
0764: fReaderDepth = readerDepth;
0765: fReaderId = fNextReaderId++;
0766: if (!isExternalParameterEntity(entityHandle)) {
0767: fEntityType = ENTITYTYPE_INTERNAL_PE;
0768: fPublicId = null/*"Internal Entity: %" + fStringPool.toString(peName)*/;
0769: fSystemId = fSystemId; // keep expandSystemId happy
0770: int value = getParameterEntityValue(entityHandle);
0771: startReadingFromInternalEntity(value,
0772: fEntityContext == ENTITYREF_IN_ENTITYVALUE ? false
0773: : true);
0774: return false;
0775: }
0776: fEntityType = ENTITYTYPE_EXTERNAL_PE;
0777: fPublicId = getPublicIdOfParameterEntity(entityHandle);
0778: fSystemId = getSystemIdOfParameterEntity(entityHandle);
0779: return startReadingFromExternalEntity(true, entityHandle);
0780: }
0781:
0782: private void startReadingFromInternalEntity(int value,
0783: boolean addSpaces) throws Exception {
0784: if (fEntityContext == ENTITYREF_IN_ENTITYVALUE) {
0785: //
0786: // REVISIT - consider optimizing the case where the entire entity value
0787: // consists of a single reference to a parameter entity and do not append
0788: // the value to fLiteralData again, but re-use the offset/length of the
0789: // referenced entity for the value of this entity.
0790: //
0791: }
0792: fSource = null;
0793: fEventHandler.startEntityReference(fEntityName, fEntityType,
0794: fEntityContext);
0795: fReader = fReaderFactory.createStringReader(this ,
0796: fErrorReporter, fSendCharDataAsCharArray,
0797: getLineNumber(), getColumnNumber(), value, fStringPool,
0798: addSpaces); // REVISIT - string reader needs better location support
0799: fEventHandler.sendReaderChangeNotifications(fReader, fReaderId);
0800: }
0801:
0802: private boolean startReadingFromExternalEntity(
0803: boolean checkForTextDecl, int entityHandle)
0804: throws Exception {
0805: if (fEntityContext == ENTITYREF_IN_ENTITYVALUE) {
0806: //
0807: // REVISIT - Can we get the spec changed ?
0808: // There is a perverse edge case to handle here... We have a reference
0809: // to an external PE within a literal EntityValue. For the PE to be
0810: // well-formed, it must match the extPE production, but the code that
0811: // appends the replacement text to the entity value is in no position
0812: // to do a complete well-formedness check !!
0813: //
0814: }
0815: if (fEntityContext == ENTITYREF_IN_DTD_WITHIN_MARKUP) {
0816: //
0817: // REVISIT - Can we get the spec changed ?
0818: // There is a perverse edge case to handle here... We have a reference
0819: // to an external PE within markup. For the PE to be well-formed, it
0820: // must match the extPE production, which is probably not going to be
0821: // very useful expanded in the middle of a markup declaration. The
0822: // problem is that an empty file, a file containing just whitespace or
0823: // another PE that is just empty or whitespace, matches extPE !!
0824: //
0825: }
0826: fEventHandler.startEntityReference(fEntityName, fEntityType,
0827: fEntityContext);
0828: String baseSystemId = null;
0829: if (entityHandle != -1) {
0830: if (fEntityType == ENTITYTYPE_EXTERNAL_PE)
0831: baseSystemId = fParameterEntityPool
0832: .getBaseSystemId(entityHandle);
0833: else
0834: baseSystemId = fEntityPool
0835: .getBaseSystemId(entityHandle);
0836: }
0837: if (baseSystemId == null) {
0838: ReaderState rs = (ReaderState) fReaderStack.peek();
0839: baseSystemId = rs.systemId;
0840: }
0841: fSystemId = expandSystemId(fSystemId, baseSystemId);
0842: fSource = fResolver == null ? null : fResolver.resolveEntity(
0843: fPublicId, fSystemId);
0844: if (fSource == null) {
0845: fSource = new InputSource(fSystemId);
0846: if (fPublicId != null)
0847: fSource.setPublicId(fPublicId);
0848: } else {
0849: if (fSource.getSystemId() != null) {
0850: fSystemId = expandSystemId(fSource.getSystemId(),
0851: baseSystemId);
0852: }
0853: if (fSource.getPublicId() != null) {
0854: fPublicId = fSource.getPublicId();
0855: }
0856: }
0857:
0858: boolean textDecl = false; // xmlDecl if true, textDecl if false
0859: try {
0860: fReader = fReaderFactory.createReader(this , fErrorReporter,
0861: fSource, fSystemId, textDecl, fStringPool);
0862: } catch (MalformedURLException mu) {
0863: String errorSystemId = fSystemId;
0864: fEventHandler.endEntityReference(fEntityName, fEntityType,
0865: fEntityContext);
0866: popReader();
0867: popEntity();
0868: fReader = null;
0869: Object[] args = { errorSystemId };
0870: fErrorReporter
0871: .reportError(
0872: fErrorReporter.getLocator(),
0873: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
0874: ImplementationMessages.IO0, 0, args,
0875: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0876: } catch (FileNotFoundException fnf) {
0877: String errorSystemId = fSystemId;
0878: fEventHandler.endEntityReference(fEntityName, fEntityType,
0879: fEntityContext);
0880: popReader();
0881: popEntity();
0882: fReader = null;
0883: Object[] args = { errorSystemId };
0884: fErrorReporter
0885: .reportError(
0886: fErrorReporter.getLocator(),
0887: ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
0888: ImplementationMessages.IO0, 0, args,
0889: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0890: } catch (UnsupportedEncodingException uee) {
0891: fEventHandler.endEntityReference(fEntityName, fEntityType,
0892: fEntityContext);
0893: popReader();
0894: popEntity();
0895: fReader = null;
0896: String encoding = uee.getMessage();
0897: if (encoding == null) {
0898: fErrorReporter.reportError(fErrorReporter.getLocator(),
0899: XMLMessages.XML_DOMAIN,
0900: XMLMessages.MSG_ENCODING_REQUIRED,
0901: XMLMessages.P81_REQUIRED, null,
0902: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0903: } else if (!XMLCharacterProperties.validEncName(encoding)) {
0904: Object[] args = { encoding };
0905: fErrorReporter.reportError(fErrorReporter.getLocator(),
0906: XMLMessages.XML_DOMAIN,
0907: XMLMessages.MSG_ENCODINGDECL_INVALID,
0908: XMLMessages.P81_INVALID_VALUE, args,
0909: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0910: } else {
0911: Object[] args = { encoding };
0912: fErrorReporter.reportError(fErrorReporter.getLocator(),
0913: XMLMessages.XML_DOMAIN,
0914: XMLMessages.MSG_ENCODING_NOT_SUPPORTED,
0915: XMLMessages.P81_NOT_SUPPORTED, args,
0916: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
0917: }
0918: }
0919: if (fReader == null || !checkForTextDecl) {
0920: fEventHandler.sendReaderChangeNotifications(fReader,
0921: fReaderId);
0922: return false;
0923: }
0924: int readerId = fReaderId;
0925: fEventHandler.sendReaderChangeNotifications(fReader, fReaderId);
0926: boolean parseTextDecl = fReader.lookingAtChar('<', false);
0927: if (readerId != fReaderId)
0928: parseTextDecl = false;
0929: return parseTextDecl;
0930: }
0931:
0932: //
0933: // reader stack
0934: //
0935: private void pushNullReader() {
0936: ReaderState rs = fReaderStateFreeList;
0937: if (rs == null)
0938: rs = new ReaderState();
0939: else
0940: fReaderStateFreeList = rs.nextReaderState;
0941: if (fNullReader == null)
0942: fNullReader = new NullReader();
0943: rs.reader = fNullReader;
0944: rs.source = null;
0945: rs.entityName = -1; // Null Entity
0946: rs.entityType = -1; // Null Entity
0947: rs.entityContext = -1; // Null Entity
0948: rs.publicId = "Null Entity";
0949: rs.systemId = fSystemId;
0950: rs.readerId = fNextReaderId++;
0951: rs.depth = -1;
0952: rs.nextReaderState = null;
0953: fReaderStack.push(rs);
0954: }
0955:
0956: private void pushReader() {
0957: ReaderState rs = fReaderStateFreeList;
0958: if (rs == null)
0959: rs = new ReaderState();
0960: else
0961: fReaderStateFreeList = rs.nextReaderState;
0962: rs.reader = fReader;
0963: rs.source = fSource;
0964: rs.entityName = fEntityName;
0965: rs.entityType = fEntityType;
0966: rs.entityContext = fEntityContext;
0967: rs.publicId = fPublicId;
0968: rs.systemId = fSystemId;
0969: rs.readerId = fReaderId;
0970: rs.depth = fReaderDepth;
0971: rs.nextReaderState = null;
0972: fReaderStack.push(rs);
0973: }
0974:
0975: private void popReader() {
0976: if (fReaderStack.empty())
0977: throw new RuntimeException("FWK004 cannot happen 19"
0978: + "\n19");
0979: ReaderState rs = (ReaderState) fReaderStack.pop();
0980: fReader = rs.reader;
0981: fSource = rs.source;
0982: fEntityName = rs.entityName;
0983: fEntityType = rs.entityType;
0984: fEntityContext = rs.entityContext;
0985: fPublicId = rs.publicId;
0986: fSystemId = rs.systemId;
0987: fReaderId = rs.readerId;
0988: fReaderDepth = rs.depth;
0989: rs.nextReaderState = fReaderStateFreeList;
0990: fReaderStateFreeList = rs;
0991: }
0992:
0993: /**
0994: * start an entity declaration
0995: */
0996: public boolean startEntityDecl(boolean isPE, int entityName)
0997: throws Exception {
0998: if (!pushEntity(isPE, entityName)) {
0999: int majorCode = isPE ? XMLMessages.MSG_RECURSIVE_PEREFERENCE
1000: : XMLMessages.MSG_RECURSIVE_REFERENCE;
1001: Object[] args = { fStringPool.toString(entityName),
1002: entityReferencePath(isPE, entityName) };
1003: fErrorReporter.reportError(fErrorReporter.getLocator(),
1004: XMLMessages.XML_DOMAIN, majorCode,
1005: XMLMessages.WFC_NO_RECURSION, args,
1006: XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
1007: return false;
1008: }
1009: return true;
1010: }
1011:
1012: /**
1013: * end an entity declaration
1014: */
1015: public void endEntityDecl() throws Exception {
1016: popEntity();
1017: }
1018:
1019: //
1020: // entity stack
1021: //
1022: private boolean pushEntity(boolean isPE, int entityName)
1023: throws Exception {
1024: if (entityName >= 0) {
1025: for (int i = 0; i < fEntityStackDepth; i++) {
1026: if (fEntityNameStack[i] == entityName
1027: && fEntityTypeStack[i] == (isPE ? 1 : 0)) {
1028: return false;
1029: }
1030: }
1031: }
1032: if (fEntityTypeStack == null) {
1033: fEntityTypeStack = new byte[8];
1034: fEntityNameStack = new int[8];
1035: } else if (fEntityStackDepth == fEntityTypeStack.length) {
1036: byte[] newTypeStack = new byte[fEntityStackDepth * 2];
1037: System.arraycopy(fEntityTypeStack, 0, newTypeStack, 0,
1038: fEntityStackDepth);
1039: fEntityTypeStack = newTypeStack;
1040: int[] newNameStack = new int[fEntityStackDepth * 2];
1041: System.arraycopy(fEntityNameStack, 0, newNameStack, 0,
1042: fEntityStackDepth);
1043: fEntityNameStack = newNameStack;
1044: }
1045: fEntityTypeStack[fEntityStackDepth] = (byte) (isPE ? 1 : 0);
1046: fEntityNameStack[fEntityStackDepth] = entityName;
1047: fEntityStackDepth++;
1048: return true;
1049: }
1050:
1051: private String entityReferencePath(boolean isPE, int entityName) {
1052: StringBuffer sb = new StringBuffer();
1053: sb.append("(top-level)");
1054: for (int i = 0; i < fEntityStackDepth; i++) {
1055: if (fEntityNameStack[i] >= 0) {
1056: sb.append('-');
1057: sb.append(fEntityTypeStack[i] == 1 ? '%' : '&');
1058: sb.append(fStringPool.toString(fEntityNameStack[i]));
1059: sb.append(';');
1060: }
1061: }
1062: sb.append('-');
1063: sb.append(isPE ? '%' : '&');
1064: sb.append(fStringPool.toString(entityName));
1065: sb.append(';');
1066: return sb.toString();
1067: }
1068:
1069: private void popEntity() throws Exception {
1070: fEntityStackDepth--;
1071: }
1072:
1073: //
1074: //
1075: //
1076: /**
1077: * This method is provided for scanner implementations.
1078: */
1079: public int getReaderId() {
1080: return fReaderId;
1081: }
1082:
1083: /**
1084: * This method is provided for scanner implementations.
1085: */
1086: public void setReaderDepth(int depth) {
1087: fReaderDepth = depth;
1088: }
1089:
1090: /**
1091: * This method is provided for scanner implementations.
1092: */
1093: public int getReaderDepth() {
1094: return fReaderDepth;
1095: }
1096:
1097: /**
1098: * Return the public identifier of the <code>InputSource</code> that we are processing.
1099: *
1100: * @return The public identifier, or null if not provided.
1101: */
1102: public String getPublicId() {
1103: return fPublicId;
1104: }
1105:
1106: /**
1107: * Return the system identifier of the <code>InputSource</code> that we are processing.
1108: *
1109: * @return The system identifier, or null if not provided.
1110: */
1111: public String getSystemId() {
1112: return fSystemId;
1113: }
1114:
1115: /**
1116: * Return the line number of the current position within the document that we are processing.
1117: *
1118: * @return The current line number.
1119: */
1120: public int getLineNumber() {
1121: return fReader == null ? 0 : fReader.getLineNumber();
1122: }
1123:
1124: /**
1125: * Return the column number of the current position within the document that we are processing.
1126: *
1127: * @return The current column number.
1128: */
1129: public int getColumnNumber() {
1130: return fReader == null ? 0 : fReader.getColumnNumber();
1131: }
1132:
1133: /**
1134: * This method is called by the reader subclasses at the
1135: * end of input, and also by the scanner directly to force
1136: * a reader change during error recovery.
1137: */
1138: public XMLEntityHandler.EntityReader changeReaders()
1139: throws Exception {
1140: fEventHandler.sendEndOfInputNotifications(fEntityName,
1141: fReaderStack.size() > 1);
1142: fEventHandler.endEntityReference(fEntityName, fEntityType,
1143: fEntityContext);
1144: popReader();
1145: fEventHandler.sendReaderChangeNotifications(fReader, fReaderId);
1146: popEntity();
1147: return fReader;
1148: }
1149:
1150: //
1151: // We use the null reader after we have reached the
1152: // end of input for the document or external subset.
1153: //
1154: private final class NullReader implements
1155: XMLEntityHandler.EntityReader {
1156: //
1157: //
1158: //
1159: public NullReader() {
1160: }
1161:
1162: public int currentOffset() {
1163: return -1;
1164: }
1165:
1166: public int getLineNumber() {
1167: return -1;
1168: }
1169:
1170: public int getColumnNumber() {
1171: return -1;
1172: }
1173:
1174: public void setInCDSect(boolean inCDSect) {
1175: }
1176:
1177: public boolean getInCDSect() {
1178: return false;
1179: }
1180:
1181: public void append(XMLEntityHandler.CharBuffer charBuffer,
1182: int offset, int length) {
1183: }
1184:
1185: public int addString(int offset, int length) {
1186: return -1;
1187: }
1188:
1189: public int addSymbol(int offset, int length) {
1190: return -1;
1191: }
1192:
1193: public boolean lookingAtChar(char ch, boolean skipPastChar) {
1194: return false;
1195: }
1196:
1197: public boolean lookingAtValidChar(boolean skipPastChar) {
1198: return false;
1199: }
1200:
1201: public boolean lookingAtSpace(boolean skipPastChar) {
1202: return false;
1203: }
1204:
1205: public void skipToChar(char ch) {
1206: }
1207:
1208: public void skipPastSpaces() {
1209: }
1210:
1211: public void skipPastName(char fastcheck) {
1212: }
1213:
1214: public void skipPastNmtoken(char fastcheck) {
1215: }
1216:
1217: public boolean skippedString(char[] s) {
1218: return false;
1219: }
1220:
1221: public int scanInvalidChar() {
1222: return -1;
1223: }
1224:
1225: public int scanCharRef(boolean hex) {
1226: return XMLEntityHandler.CHARREF_RESULT_INVALID_CHAR;
1227: }
1228:
1229: public int scanStringLiteral() {
1230: return XMLEntityHandler.STRINGLIT_RESULT_QUOTE_REQUIRED;
1231: }
1232:
1233: public int scanAttValue(char qchar, boolean asSymbol) {
1234: return XMLEntityHandler.ATTVALUE_RESULT_INVALID_CHAR;
1235: }
1236:
1237: public int scanEntityValue(int qchar, boolean createString) {
1238: return XMLEntityHandler.ENTITYVALUE_RESULT_INVALID_CHAR;
1239: }
1240:
1241: public boolean scanExpectedName(char fastcheck,
1242: StringPool.CharArrayRange expectedName) {
1243: return false;
1244: }
1245:
1246: public void scanQName(char fastcheck, QName qname) {
1247: qname.clear();
1248: }
1249:
1250: public int scanName(char fastcheck) {
1251: return -1;
1252: }
1253:
1254: public int scanContent(QName element) throws Exception {
1255: return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR;
1256: }
1257: }
1258:
1259: //
1260: // Entity Pool
1261: //
1262:
1263: //
1264: // Chunk size constants
1265: //
1266: static final int CHUNK_SHIFT = 5; // 2^5 = 32
1267: static final int CHUNK_SIZE = (1 << CHUNK_SHIFT);
1268: static final int CHUNK_MASK = CHUNK_SIZE - 1;
1269: static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k
1270:
1271: public final class EntityPool {
1272: //
1273: // Constants
1274: //
1275:
1276: //
1277: // Instance variables
1278: //
1279: private StringPool fStringPool = null;
1280: private XMLErrorReporter fErrorReporter = null;
1281: //
1282: // We store both EntityDecl and NotationDecl instances in this pool.
1283: // A NotationDecl has an fName field of -1. The fNotationDeclHead
1284: // index is -1 if the NotationDecl list is empty, otherwise it contains
1285: // the index of the the last NotationDecl in the list and the fValue
1286: // field contains the index of the previous NotationDecl, or -1 when at
1287: // the end of the list.
1288: //
1289: private int fEntityCount = 0;
1290: private int[][] fName = new int[INITIAL_CHUNK_COUNT][];
1291: private int[][] fValue = new int[INITIAL_CHUNK_COUNT][];
1292: private int[][] fPublicId = new int[INITIAL_CHUNK_COUNT][];
1293: private int[][] fSystemId = new int[INITIAL_CHUNK_COUNT][];
1294: private int[][] fBaseSystemId = new int[INITIAL_CHUNK_COUNT][];
1295: private int[][] fNotationName = new int[INITIAL_CHUNK_COUNT][];
1296: private byte[][] fDeclIsExternal = new byte[INITIAL_CHUNK_COUNT][];
1297: private int fNotationListHead = -1;
1298: private boolean fCreateStandardEntities = false;
1299: private Vector fRequiredNotations = null;
1300:
1301: //
1302: // Constructor
1303: //
1304: public EntityPool(StringPool stringPool,
1305: XMLErrorReporter errorReporter,
1306: boolean createStandardEntities) {
1307: fStringPool = stringPool;
1308: fErrorReporter = errorReporter;
1309: fCreateStandardEntities = createStandardEntities;
1310: if (fCreateStandardEntities) {
1311: createInternalEntity("lt", "<");
1312: createInternalEntity("gt", ">");
1313: createInternalEntity("amp", "&");
1314: createInternalEntity("apos", "\'");
1315: createInternalEntity("quot", "\"");
1316: }
1317: }
1318:
1319: //
1320: //
1321: //
1322: public void reset(StringPool stringPool) {
1323: fStringPool = stringPool;
1324: fEntityCount = 0;
1325: fNotationListHead = -1;
1326: if (fRequiredNotations != null)
1327: fRequiredNotations.removeAllElements();
1328: if (fCreateStandardEntities) {
1329: createInternalEntity("lt", "<");
1330: createInternalEntity("gt", ">");
1331: createInternalEntity("amp", "&");
1332: createInternalEntity("apos", "\'");
1333: createInternalEntity("quot", "\"");
1334: }
1335: }
1336:
1337: //
1338: //
1339: //
1340: private void createInternalEntity(String name, String value) {
1341: int chunk = fEntityCount >> CHUNK_SHIFT;
1342: int index = fEntityCount & CHUNK_MASK;
1343: ensureCapacity(chunk);
1344: fName[chunk][index] = fStringPool.addSymbol(name);
1345: fValue[chunk][index] = fStringPool.addString(value);
1346: fPublicId[chunk][index] = -1;
1347: fSystemId[chunk][index] = -1;
1348: fBaseSystemId[chunk][index] = -1;
1349: fNotationName[chunk][index] = -1;
1350: fEntityCount++;
1351: }
1352:
1353: //
1354: //
1355: //
1356: private void ensureCapacity(int chunk) {
1357: if (chunk >= fName.length) {
1358: int[][] newIntArray = new int[chunk * 2][];
1359: System.arraycopy(fName, 0, newIntArray, 0, chunk);
1360: fName = newIntArray;
1361: newIntArray = new int[chunk * 2][];
1362: System.arraycopy(fValue, 0, newIntArray, 0, chunk);
1363: fValue = newIntArray;
1364: newIntArray = new int[chunk * 2][];
1365: System.arraycopy(fPublicId, 0, newIntArray, 0, chunk);
1366: fPublicId = newIntArray;
1367:
1368: newIntArray = new int[chunk * 2][];
1369: System.arraycopy(fSystemId, 0, newIntArray, 0, chunk);
1370: fSystemId = newIntArray;
1371:
1372: newIntArray = new int[chunk * 2][];
1373: System.arraycopy(fBaseSystemId, 0, newIntArray, 0,
1374: chunk);
1375: fBaseSystemId = newIntArray;
1376:
1377: newIntArray = new int[chunk * 2][];
1378: System.arraycopy(fNotationName, 0, newIntArray, 0,
1379: chunk);
1380: fNotationName = newIntArray;
1381: byte[][] newByteArray = new byte[chunk * 2][];
1382: System.arraycopy(fDeclIsExternal, 0, newByteArray, 0,
1383: chunk);
1384: fDeclIsExternal = newByteArray;
1385: } else if (fName[chunk] != null) {
1386: return;
1387: }
1388: fName[chunk] = new int[CHUNK_SIZE];
1389: fValue[chunk] = new int[CHUNK_SIZE];
1390: fPublicId[chunk] = new int[CHUNK_SIZE];
1391: fSystemId[chunk] = new int[CHUNK_SIZE];
1392: fBaseSystemId[chunk] = new int[CHUNK_SIZE];
1393: fNotationName[chunk] = new int[CHUNK_SIZE];
1394: fDeclIsExternal[chunk] = new byte[CHUNK_SIZE];
1395: }
1396:
1397: public int addEntityDecl(int name, int value, int publicId,
1398: int systemId, int baseSystemId, int notationName,
1399: boolean isExternal) {
1400: int chunk = fEntityCount >> CHUNK_SHIFT;
1401: int index = fEntityCount & CHUNK_MASK;
1402: ensureCapacity(chunk);
1403: fName[chunk][index] = name;
1404: fValue[chunk][index] = value;
1405: fPublicId[chunk][index] = publicId;
1406: fSystemId[chunk][index] = systemId;
1407: fBaseSystemId[chunk][index] = baseSystemId;
1408: fNotationName[chunk][index] = notationName;
1409: fDeclIsExternal[chunk][index] = isExternal ? (byte) 0x80
1410: : (byte) 0;
1411: int entityIndex = fEntityCount++;
1412: return entityIndex;
1413: }
1414:
1415: public int addNotationDecl(int notationName, int publicId,
1416: int systemId, int baseSystemId, boolean isExternal) {
1417: int nIndex = fNotationListHead;
1418: while (nIndex != -1) {
1419: int chunk = nIndex >> CHUNK_SHIFT;
1420: int index = nIndex & CHUNK_MASK;
1421: if (fNotationName[chunk][index] == notationName)
1422: return -1;
1423: nIndex = fValue[chunk][index];
1424: }
1425: int chunk = fEntityCount >> CHUNK_SHIFT;
1426: int index = fEntityCount & CHUNK_MASK;
1427: ensureCapacity(chunk);
1428: fName[chunk][index] = -1;
1429: fValue[chunk][index] = fNotationListHead;
1430: fPublicId[chunk][index] = publicId;
1431: fSystemId[chunk][index] = systemId;
1432: fBaseSystemId[chunk][index] = baseSystemId;
1433: fNotationName[chunk][index] = notationName;
1434: fDeclIsExternal[chunk][index] = isExternal ? (byte) 0x80
1435: : (byte) 0;
1436: fNotationListHead = fEntityCount++;
1437: return fNotationListHead;
1438: }
1439:
1440: public int lookupEntity(int nameIndex) {
1441: if (nameIndex == -1)
1442: return -1;
1443: int chunk = 0;
1444: int index = 0;
1445: for (int entityIndex = 0; entityIndex < fEntityCount; entityIndex++) {
1446: if (fName[chunk][index] == nameIndex)
1447: return entityIndex;
1448: if (++index == CHUNK_SIZE) {
1449: chunk++;
1450: index = 0;
1451: }
1452: }
1453: return -1;
1454: }
1455:
1456: public boolean isExternalEntity(int entityIndex) {
1457: int chunk = entityIndex >> CHUNK_SHIFT;
1458: int index = entityIndex & CHUNK_MASK;
1459: return (fValue[chunk][index] == -1);
1460: }
1461:
1462: public boolean isUnparsedEntity(int entityIndex) {
1463: int chunk = entityIndex >> CHUNK_SHIFT;
1464: int index = entityIndex & CHUNK_MASK;
1465: return (fNotationName[chunk][index] != -1);
1466: }
1467:
1468: public boolean getEntityDeclIsExternal(int entityIndex) {
1469: int chunk = entityIndex >> CHUNK_SHIFT;
1470: int index = entityIndex & CHUNK_MASK;
1471: return (fDeclIsExternal[chunk][index] < 0);
1472: }
1473:
1474: public int getEntityName(int entityIndex) {
1475: int chunk = entityIndex >> CHUNK_SHIFT;
1476: int index = entityIndex & CHUNK_MASK;
1477: return fName[chunk][index];
1478: }
1479:
1480: public int getEntityValue(int entityIndex) {
1481: int chunk = entityIndex >> CHUNK_SHIFT;
1482: int index = entityIndex & CHUNK_MASK;
1483: return fValue[chunk][index];
1484: }
1485:
1486: public int getPublicId(int entityIndex) {
1487: int chunk = entityIndex >> CHUNK_SHIFT;
1488: int index = entityIndex & CHUNK_MASK;
1489: return fPublicId[chunk][index];
1490: }
1491:
1492: public int getSystemId(int entityIndex) {
1493: int chunk = entityIndex >> CHUNK_SHIFT;
1494: int index = entityIndex & CHUNK_MASK;
1495: return fSystemId[chunk][index];
1496: }
1497:
1498: public String getBaseSystemId(int entityIndex) {
1499: int chunk = entityIndex >> CHUNK_SHIFT;
1500: int index = entityIndex & CHUNK_MASK;
1501: int baseIndex = fBaseSystemId[chunk][index];
1502: if (baseIndex == -1) {
1503: return null;
1504: } else {
1505: return fStringPool.toString(baseIndex);
1506: }
1507: }
1508:
1509: public boolean isNotationDeclared(int nameIndex) {
1510: int nIndex = fNotationListHead;
1511: while (nIndex != -1) {
1512: int chunk = nIndex >> CHUNK_SHIFT;
1513: int index = nIndex & CHUNK_MASK;
1514: if (fNotationName[chunk][index] == nameIndex)
1515: return true;
1516: nIndex = fValue[chunk][index];
1517: }
1518: return false;
1519: }
1520:
1521: public boolean getNotationDeclIsExternal(int entityIndex) {
1522: int chunk = entityIndex >> CHUNK_SHIFT;
1523: int index = entityIndex & CHUNK_MASK;
1524: return (fDeclIsExternal[chunk][index] < 0);
1525: }
1526:
1527: public int getNotationName(int entityIndex) {
1528: int chunk = entityIndex >> CHUNK_SHIFT;
1529: int index = entityIndex & CHUNK_MASK;
1530: return fNotationName[chunk][index];
1531: }
1532:
1533: class RequiredNotation {
1534: RequiredNotation(int notationName, Locator locator,
1535: int majorCode, int minorCode, Object[] args) {
1536: fNotationName = notationName;
1537: fLocator = new LocatorImpl(locator); // snapshot of the current location
1538: fMajorCode = majorCode;
1539: fMinorCode = minorCode;
1540: fArgs = args;
1541: }
1542:
1543: int fNotationName;
1544: LocatorImpl fLocator;
1545: int fMajorCode;
1546: int fMinorCode;
1547: Object[] fArgs;
1548: };
1549:
1550: public void addRequiredNotation(int notationName,
1551: Locator locator, int majorCode, int minorCode,
1552: Object[] args) {
1553: if (fRequiredNotations == null)
1554: fRequiredNotations = new Vector();
1555: for (int index = 0; index < fRequiredNotations.size(); index++) {
1556: RequiredNotation rn = (RequiredNotation) fRequiredNotations
1557: .elementAt(index);
1558: if (rn.fNotationName == notationName)
1559: return; // REVISIT - do we want to keep just the first, or all of them?
1560: }
1561: fRequiredNotations.addElement(new RequiredNotation(
1562: notationName, locator, majorCode, minorCode, args));
1563: }
1564:
1565: public void checkRequiredNotations() throws Exception {
1566: if (fRequiredNotations == null)
1567: return;
1568: for (int index = 0; index < fRequiredNotations.size(); index++) {
1569: RequiredNotation rn = (RequiredNotation) fRequiredNotations
1570: .elementAt(index);
1571: if (!isNotationDeclared(rn.fNotationName)) {
1572: fErrorReporter
1573: .reportError(
1574: rn.fLocator,
1575: XMLMessages.XML_DOMAIN,
1576: rn.fMajorCode,
1577: rn.fMinorCode,
1578: rn.fArgs,
1579: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
1580: }
1581: }
1582: }
1583: }
1584: }
|