| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999,2000 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xerces" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, International |
| * Business Machines, Inc., http://www.apache.org. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| package org.apache.xerces.readers; |
| |
| import java.io.FileNotFoundException; |
| import java.io.UnsupportedEncodingException; |
| import java.net.MalformedURLException; |
| import java.util.Stack; |
| import java.util.Vector; |
| |
| import org.apache.xerces.framework.XMLErrorReporter; |
| import org.apache.xerces.utils.ImplementationMessages; |
| import org.apache.xerces.utils.QName; |
| import org.apache.xerces.utils.StringPool; |
| import org.apache.xerces.utils.URI; |
| import org.apache.xerces.utils.XMLCharacterProperties; |
| import org.apache.xerces.utils.XMLMessages; |
| |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.Locator; |
| import org.xml.sax.helpers.LocatorImpl; |
| |
| /** |
| * Default entity handler implementation. |
| * |
| * @version $Id$ |
| */ |
| public class DefaultEntityHandler |
| implements XMLEntityHandler, XMLEntityHandler.DTDHandler { |
| |
| public interface EventHandler { |
| public void startEntityReference(int entityName, int entityType, int entityContext) throws Exception; |
| public void endEntityReference(int entityName, int entityType, int entityContext) throws Exception; |
| public void sendEndOfInputNotifications(int entityName, boolean moreToFollow) throws Exception; |
| public void sendReaderChangeNotifications(XMLEntityHandler.EntityReader reader, int readerId) throws Exception; |
| public boolean externalEntityStandaloneCheck(); |
| public boolean getValidating(); |
| } |
| |
| // |
| // Data |
| // |
| private class ReaderState { |
| XMLEntityHandler.EntityReader reader; |
| InputSource source; |
| int entityName; |
| int entityType; |
| int entityContext; |
| String publicId; |
| String systemId; |
| int readerId; |
| int depth; |
| ReaderState nextReaderState; |
| } |
| private ReaderState fReaderStateFreeList = null; |
| private StringPool fStringPool = null; |
| private EventHandler fEventHandler = null; |
| private XMLEntityHandler.CharDataHandler fCharDataHandler = null; |
| private XMLErrorReporter fErrorReporter = null; |
| private EntityResolver fResolver = null; |
| private EntityPool fEntityPool = null; |
| private EntityPool fParameterEntityPool = null; |
| private byte[] fEntityTypeStack = null; |
| private int[] fEntityNameStack = null; |
| private int fEntityStackDepth = 0; |
| private Stack fReaderStack = new Stack(); |
| private XMLEntityHandler.EntityReader fReader = null; |
| private InputSource fSource = null; |
| private int fEntityName = -1; |
| private int fEntityType = -1; |
| private int fEntityContext = -1; |
| private String fPublicId = null; |
| private String fSystemId = null; |
| private int fReaderId = -1; |
| private int fReaderDepth = -1; |
| private int fNextReaderId = 0; |
| private NullReader fNullReader = null; |
| protected XMLEntityReaderFactory fReaderFactory = null; |
| private boolean fSendCharDataAsCharArray = false; |
| |
| public DefaultEntityHandler(StringPool stringPool, XMLErrorReporter errorReporter) { |
| fStringPool = stringPool; |
| fErrorReporter = errorReporter; |
| fReaderFactory = new DefaultReaderFactory(); |
| fEntityPool = new EntityPool(fStringPool, fErrorReporter, true); |
| } |
| |
| public void setEventHandler(EventHandler eventHandler) { |
| fEventHandler = eventHandler; |
| } |
| |
| public void setCharDataHandler(XMLEntityHandler.CharDataHandler charDataHandler) { |
| fCharDataHandler = charDataHandler; |
| } |
| |
| public XMLEntityHandler.CharDataHandler getCharDataHandler() { |
| return fCharDataHandler; |
| } |
| |
| /** |
| * Set char data processing preference. |
| */ |
| public void setSendCharDataAsCharArray(boolean flag) { |
| fSendCharDataAsCharArray = flag; |
| fReaderFactory.setSendCharDataAsCharArray(fSendCharDataAsCharArray); |
| } |
| |
| /** |
| * Set the reader factory. |
| */ |
| public void setReaderFactory(XMLEntityReaderFactory readerFactory) { |
| fReaderFactory = readerFactory; |
| fReaderFactory.setSendCharDataAsCharArray(fSendCharDataAsCharArray); |
| } |
| |
| /** |
| * Reset the entity handler. |
| */ |
| public void reset(StringPool stringPool) { |
| fStringPool = stringPool; |
| fEntityPool.reset(fStringPool); |
| fParameterEntityPool = null; |
| fReaderStack.removeAllElements(); |
| fEntityStackDepth = 0; |
| fReader = null; |
| fSource = null; |
| fEntityName = -1; |
| fEntityType = -1; |
| fEntityContext = -1; |
| fPublicId = null; |
| fSystemId = null; |
| fReaderId = -1; |
| fReaderDepth = -1; |
| fNextReaderId = 0; |
| } |
| |
| /** |
| * |
| */ |
| public void setAllowJavaEncodings(boolean flag) { |
| fReaderFactory.setAllowJavaEncodingName(flag); |
| } |
| /** |
| * |
| */ |
| public boolean getAllowJavaEncodings() { |
| return fReaderFactory.getAllowJavaEncodingName(); |
| } |
| |
| // |
| // |
| // |
| public int addInternalPEDecl(int name, int value, boolean isExternal) throws Exception { |
| if (fParameterEntityPool == null) |
| fParameterEntityPool = new EntityPool(fStringPool, fErrorReporter, false); |
| int entityHandle = fParameterEntityPool.addEntityDecl(name, value, -1, -1, -1, -1, isExternal); |
| return entityHandle; |
| } |
| public int addExternalPEDecl(int name, int publicId, int systemId, boolean isExternal) throws Exception { |
| if (fParameterEntityPool == null) |
| fParameterEntityPool = new EntityPool(fStringPool, fErrorReporter, false); |
| int entityHandle = fParameterEntityPool.addEntityDecl(name, -1, publicId, systemId, fStringPool.addSymbol(fSystemId), -1, isExternal); |
| return entityHandle; |
| } |
| public int addInternalEntityDecl(int name, int value, boolean isExternal) throws Exception { |
| int entityHandle = fEntityPool.addEntityDecl(name, value, -1, -1, -1, -1, isExternal); |
| return entityHandle; |
| } |
| public int addExternalEntityDecl(int name, int publicId, int systemId, boolean isExternal) throws Exception { |
| int entityHandle = fEntityPool.addEntityDecl(name, -1, publicId, systemId, fStringPool.addSymbol(fSystemId), -1, isExternal); |
| return entityHandle; |
| } |
| public int addUnparsedEntityDecl(int name, int publicId, int systemId, int notationName, boolean isExternal) throws Exception { |
| int entityHandle = fEntityPool.addEntityDecl(name, -1, publicId, systemId, fStringPool.addSymbol(fSystemId), notationName, isExternal); |
| if (!fEntityPool.isNotationDeclared(notationName)) { |
| Object[] args = { fStringPool.toString(name), |
| fStringPool.toString(notationName) }; |
| fEntityPool.addRequiredNotation(notationName, |
| fErrorReporter.getLocator(), |
| XMLMessages.MSG_NOTATION_NOT_DECLARED_FOR_UNPARSED_ENTITYDECL, |
| XMLMessages.VC_NOTATION_DECLARED, |
| args); |
| } |
| return entityHandle; |
| } |
| public int addNotationDecl(int notationName, int publicId, int systemId, boolean isExternal) throws Exception { |
| int notationHandle = fEntityPool.addNotationDecl(notationName, publicId, systemId, fStringPool.addSymbol(fSystemId), isExternal); |
| return notationHandle; |
| } |
| public boolean isUnparsedEntity(int entityName) { |
| int entityHandle = fEntityPool.lookupEntity(entityName); |
| return (entityHandle != -1 && fEntityPool.isUnparsedEntity(entityHandle)); |
| } |
| public boolean isNotationDeclared(int notationName) { |
| return fEntityPool.isNotationDeclared(notationName); |
| } |
| public void addRequiredNotation(int notationName, Locator locator, int majorCode, int minorCode, Object[] args) { |
| fEntityPool.addRequiredNotation(notationName, locator, majorCode, minorCode, args); |
| } |
| public void checkRequiredNotations() throws Exception { |
| fEntityPool.checkRequiredNotations(); |
| } |
| |
| protected int lookupEntity(int entityNameIndex) { |
| int entityIndex = fEntityPool.lookupEntity(entityNameIndex); |
| return entityIndex; |
| } |
| private void reportRecoverableXMLError(int majorCode, int minorCode, int stringIndex1) throws Exception { |
| Object[] args = { fStringPool.toString(stringIndex1) }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| majorCode, |
| minorCode, |
| args, |
| XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR); |
| } |
| public boolean externalReferenceInContent(int entityHandle) throws Exception { |
| boolean external = fEntityPool.isExternalEntity(entityHandle); |
| if (fEventHandler.externalEntityStandaloneCheck()) { |
| if (external) { |
| reportRecoverableXMLError(XMLMessages.MSG_EXTERNAL_ENTITY_NOT_PERMITTED, |
| XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION, |
| fEntityName); |
| } else if (fEntityPool.getEntityDeclIsExternal(entityHandle)) { |
| reportRecoverableXMLError(XMLMessages.MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE, |
| XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION, |
| fEntityName); |
| } |
| } |
| return external; |
| } |
| protected int valueOfReferenceInAttValue(int entityHandle) throws Exception { |
| if (fEventHandler.externalEntityStandaloneCheck() && fEntityPool.getEntityDeclIsExternal(entityHandle)) { |
| reportRecoverableXMLError(XMLMessages.MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE, |
| XMLMessages.VC_STANDALONE_DOCUMENT_DECLARATION, |
| fEntityName); |
| } |
| int entityValue = fEntityPool.getEntityValue(entityHandle); |
| return entityValue; |
| } |
| protected boolean isExternalEntity(int entityHandle) { |
| boolean external = fEntityPool.isExternalEntity(entityHandle); |
| return external; |
| } |
| protected int getEntityValue(int entityHandle) { |
| int value = fEntityPool.getEntityValue(entityHandle); |
| return value; |
| } |
| protected String getPublicIdOfEntity(int entityHandle) { |
| int publicId = fEntityPool.getPublicId(entityHandle); |
| return fStringPool.toString(publicId); |
| } |
| protected String getSystemIdOfEntity(int entityHandle) { |
| int systemId = fEntityPool.getSystemId(entityHandle); |
| return fStringPool.toString(systemId); |
| } |
| protected int lookupParameterEntity(int peName) throws Exception { |
| int entityHandle = -1; |
| if (fParameterEntityPool != null) |
| entityHandle = fParameterEntityPool.lookupEntity(peName); |
| return entityHandle; |
| } |
| protected boolean isExternalParameterEntity(int peIndex) { |
| boolean external = fParameterEntityPool.isExternalEntity(peIndex); |
| return external; |
| } |
| protected int getParameterEntityValue(int peIndex) { |
| int value = fParameterEntityPool.getEntityValue(peIndex); |
| return value; |
| } |
| protected String getPublicIdOfParameterEntity(int peIndex) { |
| int publicId = fParameterEntityPool.getPublicId(peIndex); |
| return fStringPool.toString(publicId); |
| } |
| protected String getSystemIdOfParameterEntity(int peIndex) { |
| int systemId = fParameterEntityPool.getSystemId(peIndex); |
| return fStringPool.toString(systemId); |
| } |
| |
| /** |
| * get the Entity reader. |
| */ |
| public XMLEntityHandler.EntityReader getEntityReader() { |
| return fReader; |
| } |
| |
| /** |
| * Adds a recognizer. |
| * |
| * @param recognizer The XML recognizer to add. |
| */ |
| public void addRecognizer(XMLDeclRecognizer recognizer) { |
| fReaderFactory.addRecognizer(recognizer); |
| } |
| |
| /** |
| * Sets the resolver used to resolve external entities. The EntityResolver |
| * interface supports resolution of public and system identifiers. |
| * |
| * @param resolver The new entity resolver. Passing a null value will |
| * uninstall the currently installed resolver. |
| */ |
| public void setEntityResolver(EntityResolver resolver) { |
| fResolver = resolver; |
| } |
| |
| /** |
| * Gets the resolver used to resolve external entities. The EntityResolver |
| * interface supports resolution of public and system identifiers. |
| * |
| * @return The current entity resolver. |
| */ |
| public EntityResolver getEntityResolver() { |
| return fResolver; |
| } |
| |
| /** |
| * Expands a system id and returns the system id as a URI, if |
| * it can be expanded. A return value of null means that the |
| * identifier is already expanded. An exception thrown |
| * indicates a failure to expand the id. |
| * |
| * @param systemId The systemId to be expanded. |
| * |
| * @return Returns the URI string representing the expanded system |
| * identifier. A null value indicates that the given |
| * system identifier is already expanded. |
| * |
| */ |
| public String expandSystemId(String systemId) { |
| return expandSystemId(systemId, fSystemId); |
| } |
| private String expandSystemId(String systemId, String currentSystemId) { |
| String id = systemId; |
| |
| // check for bad parameters id |
| if (id == null || id.length() == 0) { |
| return systemId; |
| } |
| |
| // if id already expanded, return |
| try { |
| URI uri = new URI(id); |
| if (uri != null) { |
| return systemId; |
| } |
| } |
| catch (URI.MalformedURIException e) { |
| // continue on... |
| } |
| |
| // normalize id |
| id = fixURI(id); |
| |
| // normalize base |
| URI base = null; |
| URI uri = null; |
| try { |
| if (currentSystemId == null) { |
| String dir; |
| try { |
| dir = fixURI(System.getProperty("user.dir")); |
| } |
| catch (SecurityException se) { |
| dir = ""; |
| } |
| if (!dir.endsWith("/")) { |
| dir = dir + "/"; |
| } |
| base = new URI("file", "", dir, null, null); |
| } |
| else { |
| base = new URI(currentSystemId); |
| } |
| |
| // expand id |
| uri = new URI(base, id); |
| } |
| catch (Exception e) { |
| // let it go through |
| } |
| if (uri == null) { |
| return systemId; |
| } |
| return uri.toString(); |
| } |
| |
| // |
| // Private methods |
| // |
| |
| /** |
| * Fixes a platform dependent filename to standard URI form. |
| * |
| * @param str The string to fix. |
| * |
| * @return Returns the fixed URI string. |
| */ |
| private static String fixURI(String str) { |
| |
| // handle platform dependent strings |
| str = str.replace(java.io.File.separatorChar, '/'); |
| |
| // Windows fix |
| if (str.length() >= 2) { |
| char ch1 = str.charAt(1); |
| if (ch1 == ':') { |
| char ch0 = Character.toUpperCase(str.charAt(0)); |
| if (ch0 >= 'A' && ch0 <= 'Z') { |
| str = "/" + str; |
| } |
| } |
| } |
| |
| // done |
| return str; |
| } |
| |
| public boolean startReadingFromDocument(InputSource source) throws Exception { |
| pushEntity(false, -2); // Document Entity |
| fSystemId = null; |
| pushNullReader(); |
| fEntityName = -2; // Document Entity |
| fEntityType = ENTITYTYPE_DOCUMENT; |
| fEntityContext = ENTITYREF_DOCUMENT; |
| fReaderDepth = 0; |
| fReaderId = fNextReaderId++; |
| fPublicId = source.getPublicId(); |
| fSystemId = source.getSystemId(); |
| fEventHandler.startEntityReference(fEntityName, fEntityType, fEntityContext); |
| fSystemId = expandSystemId(fSystemId, null); |
| fSource = source; |
| boolean xmlDecl = true; // xmlDecl if true, textDecl if false |
| try { |
| fReader = fReaderFactory.createReader(this, fErrorReporter, source, fSystemId, xmlDecl, fStringPool); |
| } catch (MalformedURLException mu) { |
| String errorSystemId = fSystemId; |
| fEventHandler.endEntityReference(fEntityName, fEntityType, fEntityContext); |
| popReader(); |
| popEntity(); |
| fReader = null; |
| Object[] args = { errorSystemId }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN, |
| ImplementationMessages.IO0, |
| 0, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } catch (FileNotFoundException fnf) { |
| String errorSystemId = fSystemId; |
| fEventHandler.endEntityReference(fEntityName, fEntityType, fEntityContext); |
| popReader(); |
| popEntity(); |
| fReader = null; |
| Object[] args = { errorSystemId }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN, |
| ImplementationMessages.IO0, |
| 0, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } catch (UnsupportedEncodingException uee) { |
| fEventHandler.endEntityReference(fEntityName, fEntityType, fEntityContext); |
| popReader(); |
| popEntity(); |
| fReader = null; |
| String encoding = uee.getMessage(); |
| if (encoding == null) { |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_ENCODING_REQUIRED, |
| XMLMessages.P81_REQUIRED, |
| null, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } else if (!XMLCharacterProperties.validEncName(encoding)) { |
| Object[] args = { encoding }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_ENCODINGDECL_INVALID, |
| XMLMessages.P81_INVALID_VALUE, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } else { |
| Object[] args = { encoding }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_ENCODING_NOT_SUPPORTED, |
| XMLMessages.P81_NOT_SUPPORTED, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } |
| } |
| fEventHandler.sendReaderChangeNotifications(fReader, fReaderId); |
| return fReader != null; |
| } |
| /** |
| * start reading from an external DTD subset |
| */ |
| public void startReadingFromExternalSubset(String publicId, String systemId, int readerDepth) throws Exception { |
| pushEntity(true, -1); |
| pushReader(); |
| pushNullReader(); |
| fEntityName = -1; // External Subset |
| fEntityType = ENTITYTYPE_EXTERNAL_SUBSET; |
| fEntityContext = ENTITYREF_EXTERNAL_SUBSET; |
| fReaderDepth = readerDepth; |
| fReaderId = fNextReaderId++; |
| fPublicId = publicId; |
| fSystemId = systemId; |
| startReadingFromExternalEntity(false, -1); |
| } |
| /** |
| * stop reading from an external DTD subset |
| */ |
| public void stopReadingFromExternalSubset() throws Exception { |
| if (!(fReader instanceof NullReader)) |
| throw new RuntimeException("FWK004 cannot happen 18"+"\n18"); |
| popReader(); |
| fEventHandler.sendReaderChangeNotifications(fReader, fReaderId); |
| } |
| |
| /** |
| * start reading from an external entity |
| */ |
| public boolean startReadingFromEntity(int entityName, int readerDepth, int context) throws Exception { |
| if (context > XMLEntityHandler.ENTITYREF_IN_CONTENT) |
| return startReadingFromParameterEntity(entityName, readerDepth, context); |
| int entityHandle = lookupEntity(entityName); |
| if (entityHandle < 0) { |
| int minorCode = XMLMessages.VC_ENTITY_DECLARED; |
| int errorType = XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR; |
| // REVISIT - the following test in insufficient... |
| if (fEntityContext == ENTITYREF_DOCUMENT || fEntityContext == ENTITYREF_IN_ATTVALUE) { |
| minorCode = XMLMessages.WFC_ENTITY_DECLARED; |
| errorType = XMLErrorReporter.ERRORTYPE_FATAL_ERROR; |
| } else if (!fEventHandler.getValidating()) { |
| return false; |
| } |
| Object[] args = { fStringPool.toString(entityName) }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_ENTITY_NOT_DECLARED, |
| minorCode, |
| args, |
| errorType); |
| return false; |
| } |
| if (context == ENTITYREF_IN_CONTENT) { |
| if (fEntityPool.isUnparsedEntity(entityHandle)) { |
| Object[] args = { fStringPool.toString(entityName) }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_REFERENCE_TO_UNPARSED_ENTITY, |
| XMLMessages.WFC_PARSED_ENTITY, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| return false; |
| } |
| } else { |
| if (isExternalEntity(entityHandle)) { |
| Object[] args = { fStringPool.toString(entityName) }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_REFERENCE_TO_EXTERNAL_ENTITY, |
| XMLMessages.WFC_NO_EXTERNAL_ENTITY_REFERENCES, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| return false; |
| } |
| } |
| if (!pushEntity(false, entityName)) { |
| Object[] args = { fStringPool.toString(entityName), |
| entityReferencePath(false, entityName) }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_RECURSIVE_REFERENCE, |
| XMLMessages.WFC_NO_RECURSION, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| return false; |
| } |
| pushReader(); |
| fEntityName = entityName; |
| fEntityContext = context; |
| fReaderDepth = readerDepth; |
| fReaderId = fNextReaderId++; |
| if (context != ENTITYREF_IN_CONTENT || !externalReferenceInContent(entityHandle)) { |
| fEntityType = ENTITYTYPE_INTERNAL; |
| fPublicId = null/*"Internal Entity: " + fStringPool.toString(entityName)*/; |
| fSystemId = fSystemId; // keep expandSystemId happy |
| int value = -1; |
| if (context == ENTITYREF_IN_CONTENT || context == ENTITYREF_IN_DEFAULTATTVALUE) |
| value = getEntityValue(entityHandle); |
| else |
| value = valueOfReferenceInAttValue(entityHandle); |
| startReadingFromInternalEntity(value, false); |
| return false; |
| } |
| fEntityType = ENTITYTYPE_EXTERNAL; |
| fPublicId = getPublicIdOfEntity(entityHandle); |
| fSystemId = getSystemIdOfEntity(entityHandle); |
| return startReadingFromExternalEntity(true, entityHandle); |
| } |
| private boolean startReadingFromParameterEntity(int peName, int readerDepth, int context) throws Exception { |
| int entityHandle = lookupParameterEntity(peName); |
| if (entityHandle == -1) { |
| // strange... this is a VC, not a WFC... |
| if (fEventHandler.getValidating()) { |
| reportRecoverableXMLError(XMLMessages.MSG_ENTITY_NOT_DECLARED, |
| XMLMessages.VC_ENTITY_DECLARED, |
| peName); |
| } |
| return false; |
| } |
| if (!pushEntity(true, peName)) { |
| Object[] args = { fStringPool.toString(peName), |
| entityReferencePath(true, peName) }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_RECURSIVE_PEREFERENCE, |
| XMLMessages.WFC_NO_RECURSION, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| return false; |
| } |
| pushReader(); |
| fEntityName = peName; |
| fEntityContext = context; |
| fReaderDepth = readerDepth; |
| fReaderId = fNextReaderId++; |
| if (!isExternalParameterEntity(entityHandle)) { |
| fEntityType = ENTITYTYPE_INTERNAL_PE; |
| fPublicId = null/*"Internal Entity: %" + fStringPool.toString(peName)*/; |
| fSystemId = fSystemId; // keep expandSystemId happy |
| int value = getParameterEntityValue(entityHandle); |
| startReadingFromInternalEntity(value, fEntityContext == ENTITYREF_IN_ENTITYVALUE ? false : true); |
| return false; |
| } |
| fEntityType = ENTITYTYPE_EXTERNAL_PE; |
| fPublicId = getPublicIdOfParameterEntity(entityHandle); |
| fSystemId = getSystemIdOfParameterEntity(entityHandle); |
| return startReadingFromExternalEntity(true, entityHandle); |
| } |
| private void startReadingFromInternalEntity(int value, boolean addSpaces) throws Exception { |
| if (fEntityContext == ENTITYREF_IN_ENTITYVALUE) { |
| // |
| // REVISIT - consider optimizing the case where the entire entity value |
| // consists of a single reference to a parameter entity and do not append |
| // the value to fLiteralData again, but re-use the offset/length of the |
| // referenced entity for the value of this entity. |
| // |
| } |
| fSource = null; |
| fEventHandler.startEntityReference(fEntityName, fEntityType, fEntityContext); |
| fReader = fReaderFactory.createStringReader(this, fErrorReporter, fSendCharDataAsCharArray, getLineNumber(), getColumnNumber(), value, fStringPool, addSpaces); // REVISIT - string reader needs better location support |
| fEventHandler.sendReaderChangeNotifications(fReader, fReaderId); |
| } |
| private boolean startReadingFromExternalEntity(boolean checkForTextDecl, int entityHandle) throws Exception { |
| if (fEntityContext == ENTITYREF_IN_ENTITYVALUE) { |
| // |
| // REVISIT - Can we get the spec changed ? |
| // There is a perverse edge case to handle here... We have a reference |
| // to an external PE within a literal EntityValue. For the PE to be |
| // well-formed, it must match the extPE production, but the code that |
| // appends the replacement text to the entity value is in no position |
| // to do a complete well-formedness check !! |
| // |
| } |
| if (fEntityContext == ENTITYREF_IN_DTD_WITHIN_MARKUP) { |
| // |
| // REVISIT - Can we get the spec changed ? |
| // There is a perverse edge case to handle here... We have a reference |
| // to an external PE within markup. For the PE to be well-formed, it |
| // must match the extPE production, which is probably not going to be |
| // very useful expanded in the middle of a markup declaration. The |
| // problem is that an empty file, a file containing just whitespace or |
| // another PE that is just empty or whitespace, matches extPE !! |
| // |
| } |
| fEventHandler.startEntityReference(fEntityName, fEntityType, fEntityContext); |
| String baseSystemId = null; |
| if (entityHandle != -1) { |
| if (fEntityType == ENTITYTYPE_EXTERNAL_PE) |
| baseSystemId = |
| fParameterEntityPool.getBaseSystemId(entityHandle); |
| else |
| baseSystemId = fEntityPool.getBaseSystemId(entityHandle); |
| } |
| if (baseSystemId == null) { |
| ReaderState rs = (ReaderState) fReaderStack.peek(); |
| baseSystemId = rs.systemId; |
| } |
| fSystemId = expandSystemId(fSystemId, baseSystemId); |
| fSource = fResolver == null ? null : fResolver.resolveEntity(fPublicId, fSystemId); |
| if (fSource == null) { |
| fSource = new InputSource(fSystemId); |
| if (fPublicId != null) |
| fSource.setPublicId(fPublicId); |
| } else { |
| if (fSource.getSystemId() != null) { |
| fSystemId = |
| expandSystemId(fSource.getSystemId(), baseSystemId); |
| } |
| if (fSource.getPublicId() != null) { |
| fPublicId = fSource.getPublicId(); |
| } |
| } |
| |
| boolean textDecl = false; // xmlDecl if true, textDecl if false |
| try { |
| fReader = fReaderFactory.createReader(this, fErrorReporter, fSource, fSystemId, textDecl, fStringPool); |
| } catch (MalformedURLException mu) { |
| String errorSystemId = fSystemId; |
| fEventHandler.endEntityReference(fEntityName, fEntityType, fEntityContext); |
| popReader(); |
| popEntity(); |
| fReader = null; |
| Object[] args = { errorSystemId }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN, |
| ImplementationMessages.IO0, |
| 0, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } catch (FileNotFoundException fnf) { |
| String errorSystemId = fSystemId; |
| fEventHandler.endEntityReference(fEntityName, fEntityType, fEntityContext); |
| popReader(); |
| popEntity(); |
| fReader = null; |
| Object[] args = { errorSystemId }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN, |
| ImplementationMessages.IO0, |
| 0, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } catch (UnsupportedEncodingException uee) { |
| fEventHandler.endEntityReference(fEntityName, fEntityType, fEntityContext); |
| popReader(); |
| popEntity(); |
| fReader = null; |
| String encoding = uee.getMessage(); |
| if (encoding == null) { |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_ENCODING_REQUIRED, |
| XMLMessages.P81_REQUIRED, |
| null, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } else if (!XMLCharacterProperties.validEncName(encoding)) { |
| Object[] args = { encoding }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_ENCODINGDECL_INVALID, |
| XMLMessages.P81_INVALID_VALUE, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } else { |
| Object[] args = { encoding }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| XMLMessages.MSG_ENCODING_NOT_SUPPORTED, |
| XMLMessages.P81_NOT_SUPPORTED, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| } |
| } |
| if (fReader == null || !checkForTextDecl) { |
| fEventHandler.sendReaderChangeNotifications(fReader, fReaderId); |
| return false; |
| } |
| int readerId = fReaderId; |
| fEventHandler.sendReaderChangeNotifications(fReader, fReaderId); |
| boolean parseTextDecl = fReader.lookingAtChar('<', false); |
| if (readerId != fReaderId) |
| parseTextDecl = false; |
| return parseTextDecl; |
| } |
| |
| // |
| // reader stack |
| // |
| private void pushNullReader() { |
| ReaderState rs = fReaderStateFreeList; |
| if (rs == null) |
| rs = new ReaderState(); |
| else |
| fReaderStateFreeList = rs.nextReaderState; |
| if (fNullReader == null) |
| fNullReader = new NullReader(); |
| rs.reader = fNullReader; |
| rs.source = null; |
| rs.entityName = -1; // Null Entity |
| rs.entityType = -1; // Null Entity |
| rs.entityContext = -1; // Null Entity |
| rs.publicId = "Null Entity"; |
| rs.systemId = fSystemId; |
| rs.readerId = fNextReaderId++; |
| rs.depth = -1; |
| rs.nextReaderState = null; |
| fReaderStack.push(rs); |
| } |
| private void pushReader() { |
| ReaderState rs = fReaderStateFreeList; |
| if (rs == null) |
| rs = new ReaderState(); |
| else |
| fReaderStateFreeList = rs.nextReaderState; |
| rs.reader = fReader; |
| rs.source = fSource; |
| rs.entityName = fEntityName; |
| rs.entityType = fEntityType; |
| rs.entityContext = fEntityContext; |
| rs.publicId = fPublicId; |
| rs.systemId = fSystemId; |
| rs.readerId = fReaderId; |
| rs.depth = fReaderDepth; |
| rs.nextReaderState = null; |
| fReaderStack.push(rs); |
| } |
| private void popReader() { |
| if (fReaderStack.empty()) |
| throw new RuntimeException("FWK004 cannot happen 19"+"\n19"); |
| ReaderState rs = (ReaderState) fReaderStack.pop(); |
| fReader = rs.reader; |
| fSource = rs.source; |
| fEntityName = rs.entityName; |
| fEntityType = rs.entityType; |
| fEntityContext = rs.entityContext; |
| fPublicId = rs.publicId; |
| fSystemId = rs.systemId; |
| fReaderId = rs.readerId; |
| fReaderDepth = rs.depth; |
| rs.nextReaderState = fReaderStateFreeList; |
| fReaderStateFreeList = rs; |
| } |
| |
| /** |
| * start an entity declaration |
| */ |
| public boolean startEntityDecl(boolean isPE, int entityName) throws Exception { |
| if (!pushEntity(isPE, entityName)) { |
| int majorCode = isPE ? XMLMessages.MSG_RECURSIVE_PEREFERENCE : XMLMessages.MSG_RECURSIVE_REFERENCE; |
| Object[] args = { fStringPool.toString(entityName), |
| entityReferencePath(isPE, entityName) }; |
| fErrorReporter.reportError(fErrorReporter.getLocator(), |
| XMLMessages.XML_DOMAIN, |
| majorCode, |
| XMLMessages.WFC_NO_RECURSION, |
| args, |
| XMLErrorReporter.ERRORTYPE_FATAL_ERROR); |
| return false; |
| } |
| return true; |
| } |
| /** |
| * end an entity declaration |
| */ |
| public void endEntityDecl() throws Exception { |
| popEntity(); |
| } |
| // |
| // entity stack |
| // |
| private boolean pushEntity(boolean isPE, int entityName) throws Exception { |
| if (entityName >= 0) { |
| for (int i = 0; i < fEntityStackDepth; i++) { |
| if (fEntityNameStack[i] == entityName && fEntityTypeStack[i] == (isPE ? 1 : 0)) { |
| return false; |
| } |
| } |
| } |
| if (fEntityTypeStack == null) { |
| fEntityTypeStack = new byte[8]; |
| fEntityNameStack = new int[8]; |
| } else if (fEntityStackDepth == fEntityTypeStack.length) { |
| byte[] newTypeStack = new byte[fEntityStackDepth * 2]; |
| System.arraycopy(fEntityTypeStack, 0, newTypeStack, 0, fEntityStackDepth); |
| fEntityTypeStack = newTypeStack; |
| int[] newNameStack = new int[fEntityStackDepth * 2]; |
| System.arraycopy(fEntityNameStack, 0, newNameStack, 0, fEntityStackDepth); |
| fEntityNameStack = newNameStack; |
| } |
| fEntityTypeStack[fEntityStackDepth] = (byte)(isPE ? 1 : 0); |
| fEntityNameStack[fEntityStackDepth] = entityName; |
| fEntityStackDepth++; |
| return true; |
| } |
| private String entityReferencePath(boolean isPE, int entityName) { |
| StringBuffer sb = new StringBuffer(); |
| sb.append("(top-level)"); |
| for (int i = 0; i < fEntityStackDepth; i++) { |
| if (fEntityNameStack[i] >= 0) { |
| sb.append('-'); |
| sb.append(fEntityTypeStack[i] == 1 ? '%' : '&'); |
| sb.append(fStringPool.toString(fEntityNameStack[i])); |
| sb.append(';'); |
| } |
| } |
| sb.append('-'); |
| sb.append(isPE ? '%' : '&'); |
| sb.append(fStringPool.toString(entityName)); |
| sb.append(';'); |
| return sb.toString(); |
| } |
| private void popEntity() throws Exception { |
| fEntityStackDepth--; |
| } |
| |
| // |
| // |
| // |
| /** |
| * This method is provided for scanner implementations. |
| */ |
| public int getReaderId() { |
| return fReaderId; |
| } |
| /** |
| * This method is provided for scanner implementations. |
| */ |
| public void setReaderDepth(int depth) { |
| fReaderDepth = depth; |
| } |
| /** |
| * This method is provided for scanner implementations. |
| */ |
| public int getReaderDepth() { |
| return fReaderDepth; |
| } |
| /** |
| * Return the public identifier of the <code>InputSource</code> that we are processing. |
| * |
| * @return The public identifier, or null if not provided. |
| */ |
| public String getPublicId() { |
| return fPublicId; |
| } |
| /** |
| * Return the system identifier of the <code>InputSource</code> that we are processing. |
| * |
| * @return The system identifier, or null if not provided. |
| */ |
| public String getSystemId() { |
| return fSystemId; |
| } |
| /** |
| * Return the line number of the current position within the document that we are processing. |
| * |
| * @return The current line number. |
| */ |
| public int getLineNumber() { |
| return fReader == null ? 0 : fReader.getLineNumber(); |
| } |
| /** |
| * Return the column number of the current position within the document that we are processing. |
| * |
| * @return The current column number. |
| */ |
| public int getColumnNumber() { |
| return fReader == null ? 0 : fReader.getColumnNumber(); |
| } |
| /** |
| * This method is called by the reader subclasses at the |
| * end of input, and also by the scanner directly to force |
| * a reader change during error recovery. |
| */ |
| public XMLEntityHandler.EntityReader changeReaders() throws Exception { |
| fEventHandler.sendEndOfInputNotifications(fEntityName, fReaderStack.size() > 1); |
| fEventHandler.endEntityReference(fEntityName, fEntityType, fEntityContext); |
| popReader(); |
| fEventHandler.sendReaderChangeNotifications(fReader, fReaderId); |
| popEntity(); |
| return fReader; |
| } |
| |
| // |
| // We use the null reader after we have reached the |
| // end of input for the document or external subset. |
| // |
| private final class NullReader implements XMLEntityHandler.EntityReader { |
| // |
| // |
| // |
| public NullReader() { |
| } |
| public int currentOffset() { |
| return -1; |
| } |
| public int getLineNumber() { |
| return -1; |
| } |
| public int getColumnNumber() { |
| return -1; |
| } |
| public void setInCDSect(boolean inCDSect) { |
| } |
| public boolean getInCDSect() { |
| return false; |
| } |
| public void append(XMLEntityHandler.CharBuffer charBuffer, int offset, int length) { |
| } |
| public int addString(int offset, int length) { |
| return -1; |
| } |
| public int addSymbol(int offset, int length) { |
| return -1; |
| } |
| public boolean lookingAtChar(char ch, boolean skipPastChar) { |
| return false; |
| } |
| public boolean lookingAtValidChar(boolean skipPastChar) { |
| return false; |
| } |
| public boolean lookingAtSpace(boolean skipPastChar) { |
| return false; |
| } |
| public void skipToChar(char ch) { |
| } |
| public void skipPastSpaces() { |
| } |
| public void skipPastName(char fastcheck) { |
| } |
| public void skipPastNmtoken(char fastcheck) { |
| } |
| public boolean skippedString(char[] s) { |
| return false; |
| } |
| public int scanInvalidChar() { |
| return -1; |
| } |
| public int scanCharRef(boolean hex) { |
| return XMLEntityHandler.CHARREF_RESULT_INVALID_CHAR; |
| } |
| public int scanStringLiteral() { |
| return XMLEntityHandler.STRINGLIT_RESULT_QUOTE_REQUIRED; |
| } |
| public int scanAttValue(char qchar, boolean asSymbol) { |
| return XMLEntityHandler.ATTVALUE_RESULT_INVALID_CHAR; |
| } |
| public int scanEntityValue(int qchar, boolean createString) { |
| return XMLEntityHandler.ENTITYVALUE_RESULT_INVALID_CHAR; |
| } |
| public boolean scanExpectedName(char fastcheck, StringPool.CharArrayRange expectedName) { |
| return false; |
| } |
| public void scanQName(char fastcheck, QName qname) { |
| qname.clear(); |
| } |
| public int scanName(char fastcheck) { |
| return -1; |
| } |
| public int scanContent(QName element) throws Exception { |
| return XMLEntityHandler.CONTENT_RESULT_INVALID_CHAR; |
| } |
| } |
| |
| // |
| // Entity Pool |
| // |
| |
| // |
| // Chunk size constants |
| // |
| static final int CHUNK_SHIFT = 5; // 2^5 = 32 |
| static final int CHUNK_SIZE = (1 << CHUNK_SHIFT); |
| static final int CHUNK_MASK = CHUNK_SIZE - 1; |
| static final int INITIAL_CHUNK_COUNT = (1 << (10 - CHUNK_SHIFT)); // 2^10 = 1k |
| |
| public final class EntityPool { |
| // |
| // Constants |
| // |
| |
| // |
| // Instance variables |
| // |
| private StringPool fStringPool = null; |
| private XMLErrorReporter fErrorReporter = null; |
| // |
| // We store both EntityDecl and NotationDecl instances in this pool. |
| // A NotationDecl has an fName field of -1. The fNotationDeclHead |
| // index is -1 if the NotationDecl list is empty, otherwise it contains |
| // the index of the the last NotationDecl in the list and the fValue |
| // field contains the index of the previous NotationDecl, or -1 when at |
| // the end of the list. |
| // |
| private int fEntityCount = 0; |
| private int[][] fName = new int[INITIAL_CHUNK_COUNT][]; |
| private int[][] fValue = new int[INITIAL_CHUNK_COUNT][]; |
| private int[][] fPublicId = new int[INITIAL_CHUNK_COUNT][]; |
| private int[][] fSystemId = new int[INITIAL_CHUNK_COUNT][]; |
| private int[][] fBaseSystemId = new int[INITIAL_CHUNK_COUNT][]; |
| private int[][] fNotationName = new int[INITIAL_CHUNK_COUNT][]; |
| private byte[][] fDeclIsExternal = new byte[INITIAL_CHUNK_COUNT][]; |
| private int fNotationListHead = -1; |
| private boolean fCreateStandardEntities = false; |
| private Vector fRequiredNotations = null; |
| // |
| // Constructor |
| // |
| public EntityPool(StringPool stringPool, XMLErrorReporter errorReporter, boolean createStandardEntities) { |
| fStringPool = stringPool; |
| fErrorReporter = errorReporter; |
| fCreateStandardEntities = createStandardEntities; |
| if (fCreateStandardEntities) { |
| createInternalEntity("lt", "<"); |
| createInternalEntity("gt", ">"); |
| createInternalEntity("amp", "&"); |
| createInternalEntity("apos", "\'"); |
| createInternalEntity("quot", "\""); |
| } |
| } |
| // |
| // |
| // |
| public void reset(StringPool stringPool) { |
| fStringPool = stringPool; |
| fEntityCount = 0; |
| fNotationListHead = -1; |
| if (fRequiredNotations != null) |
| fRequiredNotations.removeAllElements(); |
| if (fCreateStandardEntities) { |
| createInternalEntity("lt", "<"); |
| createInternalEntity("gt", ">"); |
| createInternalEntity("amp", "&"); |
| createInternalEntity("apos", "\'"); |
| createInternalEntity("quot", "\""); |
| } |
| } |
| // |
| // |
| // |
| private void createInternalEntity(String name, String value) { |
| int chunk = fEntityCount >> CHUNK_SHIFT; |
| int index = fEntityCount & CHUNK_MASK; |
| ensureCapacity(chunk); |
| fName[chunk][index] = fStringPool.addSymbol(name); |
| fValue[chunk][index] = fStringPool.addString(value); |
| fPublicId[chunk][index] = -1; |
| fSystemId[chunk][index] = -1; |
| fBaseSystemId[chunk][index] = -1; |
| fNotationName[chunk][index] = -1; |
| fEntityCount++; |
| } |
| // |
| // |
| // |
| private boolean ensureCapacity(int chunk) { |
| try { |
| return fName[chunk][0] == 0; |
| } catch (ArrayIndexOutOfBoundsException ex) { |
| int[][] newIntArray = new int[chunk * 2][]; |
| System.arraycopy(fName, 0, newIntArray, 0, chunk); |
| fName = newIntArray; |
| newIntArray = new int[chunk * 2][]; |
| System.arraycopy(fValue, 0, newIntArray, 0, chunk); |
| fValue = newIntArray; |
| newIntArray = new int[chunk * 2][]; |
| System.arraycopy(fPublicId, 0, newIntArray, 0, chunk); |
| fPublicId = newIntArray; |
| newIntArray = new int[chunk * 2][]; |
| System.arraycopy(fSystemId, 0, newIntArray, 0, chunk); |
| newIntArray = new int[chunk * 2][]; |
| System.arraycopy(fBaseSystemId, 0, newIntArray, 0, chunk); |
| fBaseSystemId = newIntArray; |
| fSystemId = newIntArray; |
| newIntArray = new int[chunk * 2][]; |
| System.arraycopy(fNotationName, 0, newIntArray, 0, chunk); |
| fNotationName = newIntArray; |
| byte[][] newByteArray = new byte[chunk * 2][]; |
| System.arraycopy(fDeclIsExternal, 0, newByteArray, 0, chunk); |
| fDeclIsExternal = newByteArray; |
| } catch (NullPointerException ex) { |
| } |
| fName[chunk] = new int[CHUNK_SIZE]; |
| fValue[chunk] = new int[CHUNK_SIZE]; |
| fPublicId[chunk] = new int[CHUNK_SIZE]; |
| fSystemId[chunk] = new int[CHUNK_SIZE]; |
| fBaseSystemId[chunk] = new int[CHUNK_SIZE]; |
| fNotationName[chunk] = new int[CHUNK_SIZE]; |
| fDeclIsExternal[chunk] = new byte[CHUNK_SIZE]; |
| return true; |
| } |
| public int addEntityDecl(int name, int value, int publicId, int systemId, int baseSystemId, int notationName, boolean isExternal) { |
| int chunk = fEntityCount >> CHUNK_SHIFT; |
| int index = fEntityCount & CHUNK_MASK; |
| ensureCapacity(chunk); |
| fName[chunk][index] = name; |
| fValue[chunk][index] = value; |
| fPublicId[chunk][index] = publicId; |
| fSystemId[chunk][index] = systemId; |
| fBaseSystemId[chunk][index] = baseSystemId; |
| fNotationName[chunk][index] = notationName; |
| fDeclIsExternal[chunk][index] = isExternal ? (byte)0x80 : (byte)0; |
| int entityIndex = fEntityCount++; |
| return entityIndex; |
| } |
| public int addNotationDecl(int notationName, int publicId, int systemId, int baseSystemId, boolean isExternal) { |
| int nIndex = fNotationListHead; |
| while (nIndex != -1) { |
| int chunk = nIndex >> CHUNK_SHIFT; |
| int index = nIndex & CHUNK_MASK; |
| if (fNotationName[chunk][index] == notationName) |
| return -1; |
| nIndex = fValue[chunk][index]; |
| } |
| int chunk = fEntityCount >> CHUNK_SHIFT; |
| int index = fEntityCount & CHUNK_MASK; |
| ensureCapacity(chunk); |
| fName[chunk][index] = -1; |
| fValue[chunk][index] = fNotationListHead; |
| fPublicId[chunk][index] = publicId; |
| fSystemId[chunk][index] = systemId; |
| fBaseSystemId[chunk][index] = baseSystemId; |
| fNotationName[chunk][index] = notationName; |
| fDeclIsExternal[chunk][index] = isExternal ? (byte)0x80 : (byte)0; |
| fNotationListHead = fEntityCount++; |
| return fNotationListHead; |
| } |
| public int lookupEntity(int nameIndex) { |
| if (nameIndex == -1) |
| return -1; |
| int chunk = 0; |
| int index = 0; |
| for (int entityIndex = 0; entityIndex < fEntityCount; entityIndex++) { |
| if (fName[chunk][index] == nameIndex) |
| return entityIndex; |
| if (++index == CHUNK_SIZE) { |
| chunk++; |
| index = 0; |
| } |
| } |
| return -1; |
| } |
| public boolean isExternalEntity(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return (fValue[chunk][index] == -1); |
| } |
| public boolean isUnparsedEntity(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return (fNotationName[chunk][index] != -1); |
| } |
| public boolean getEntityDeclIsExternal(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return (fDeclIsExternal[chunk][index] < 0); |
| } |
| public int getEntityName(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return fName[chunk][index]; |
| } |
| public int getEntityValue(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return fValue[chunk][index]; |
| } |
| public int getPublicId(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return fPublicId[chunk][index]; |
| } |
| public int getSystemId(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return fSystemId[chunk][index]; |
| } |
| public String getBaseSystemId(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| int baseIndex = fBaseSystemId[chunk][index]; |
| if (baseIndex == -1) { |
| return null; |
| } else { |
| return fStringPool.toString(baseIndex); |
| } |
| } |
| public boolean isNotationDeclared(int nameIndex) { |
| int nIndex = fNotationListHead; |
| while (nIndex != -1) { |
| int chunk = nIndex >> CHUNK_SHIFT; |
| int index = nIndex & CHUNK_MASK; |
| if (fNotationName[chunk][index] == nameIndex) |
| return true; |
| nIndex = fValue[chunk][index]; |
| } |
| return false; |
| } |
| public boolean getNotationDeclIsExternal(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return (fDeclIsExternal[chunk][index] < 0); |
| } |
| public int getNotationName(int entityIndex) { |
| int chunk = entityIndex >> CHUNK_SHIFT; |
| int index = entityIndex & CHUNK_MASK; |
| return fNotationName[chunk][index]; |
| } |
| class RequiredNotation { |
| RequiredNotation(int notationName, Locator locator, int majorCode, int minorCode, Object[] args) { |
| fNotationName = notationName; |
| fLocator = new LocatorImpl(locator); // snapshot of the current location |
| fMajorCode = majorCode; |
| fMinorCode = minorCode; |
| fArgs = args; |
| } |
| int fNotationName; |
| LocatorImpl fLocator; |
| int fMajorCode; |
| int fMinorCode; |
| Object[] fArgs; |
| }; |
| public void addRequiredNotation(int notationName, Locator locator, int majorCode, int minorCode, Object[] args) { |
| if (fRequiredNotations == null) |
| fRequiredNotations = new Vector(); |
| for (int index = 0; index < fRequiredNotations.size(); index++) { |
| RequiredNotation rn = (RequiredNotation)fRequiredNotations.elementAt(index); |
| if (rn.fNotationName == notationName) |
| return; // REVISIT - do we want to keep just the first, or all of them? |
| } |
| fRequiredNotations.addElement(new RequiredNotation(notationName, locator, majorCode, minorCode, args)); |
| } |
| public void checkRequiredNotations() throws Exception { |
| if (fRequiredNotations == null) |
| return; |
| for (int index = 0; index < fRequiredNotations.size(); index++) { |
| RequiredNotation rn = (RequiredNotation)fRequiredNotations.elementAt(index); |
| if (!isNotationDeclared(rn.fNotationName)) { |
| fErrorReporter.reportError(rn.fLocator, |
| XMLMessages.XML_DOMAIN, |
| rn.fMajorCode, |
| rn.fMinorCode, |
| rn.fArgs, |
| XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR); |
| } |
| } |
| } |
| } |
| } |