This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: FYI: GNU JAXP updates


I'm checking this in on the trunk and the 4.0 branch.

This pulls over some GNU JAXP fixes from Classpath.  I cherry-picked
the ones that are bug fixes for things we're specifically interested
in at the moment, mostly Eclipse.

Tom

Index: ChangeLog
from  Chris Burdess  <dog@gnu.org>

	* gnu/xml/dom/DomNode.java (notifyNode): grow listener array as
	required.

2005-03-13  Michael Koch  <konqueror@gmx.de>

	* gnu/xml/aelfred2/XmlParser.java: Fixed typo.

2005-03-11  Chris Burdess  <dog@gnu.org>

	* gnu/xml/aelfred2/SAXDriver.java: Corrected bug handling URI
	warnings.

2005-02-27  Chris Burdess  <dog@gnu.org>

	* gnu/xml/aelfred2/JAXPFactory.java,
	gnu/xml/aelfred2/SAXDriver.java,
	gnu/xml/aelfred2/XmlParser.java,
	gnu/xml/aelfred2/XmlReader.java: Applied GNU Classpath source code
	formatting conventions. Replaced arrays of Object with struct-like
	classes for easier maintainability. Made SAXDriver.stringInterning
	package private to allow access from XmlParser inside the loop without
	a method call overhead.

2005-03-11  Chris Burdess  <dog@gnu.org>

	* gnu/xml/aelfred2/SAXDriver.java: Corrected bug handling URI
	warnings.

Index: gnu/xml/aelfred2/JAXPFactory.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/xml/aelfred2/JAXPFactory.java,v
retrieving revision 1.1
diff -u -r1.1 JAXPFactory.java
--- gnu/xml/aelfred2/JAXPFactory.java 2 Feb 2005 00:42:07 -0000 1.1
+++ gnu/xml/aelfred2/JAXPFactory.java 29 Mar 2005 19:50:35 -0000
@@ -60,137 +60,172 @@
  *
  * @author David Brownell
  */
-public final class JAXPFactory extends SAXParserFactory
+public final class JAXPFactory
+  extends SAXParserFactory
 {
-    private Hashtable	flags = new Hashtable ();
+  
+  private Hashtable flags = new Hashtable();
 
-    /**
-     * Constructs a factory which normally returns a non-validating
-     * parser.
-     */
-    public JAXPFactory () { }
+  /**
+   * Constructs a factory which normally returns a non-validating
+   * parser.
+   */
+  public JAXPFactory()
+  {
+  }
 
-    public SAXParser newSAXParser ()
+  public SAXParser newSAXParser()
     throws ParserConfigurationException, SAXException
+  {
+    JaxpParser jaxp = new JaxpParser();
+    Enumeration e = flags.keys();
+    XMLReader parser = jaxp.getXMLReader();
+
+    parser.setFeature(SAXDriver.FEATURE + "namespaces",
+                      isNamespaceAware());
+    parser.setFeature(SAXDriver.FEATURE + "validation",
+                      isValidating());
+    // that makes SAX2 feature flags trump JAXP
+    
+    while (e.hasMoreElements())
+      {
+        String uri = (String) e.nextElement();
+        Boolean value = (Boolean) flags.get(uri);
+        parser.setFeature(uri, value.booleanValue());
+      }
+
+    return jaxp;
+  }
+
+  // yes, this "feature transfer" mechanism doesn't play well
+  
+  public void setFeature(String name, boolean value) 
+    throws ParserConfigurationException, SAXNotRecognizedException,
+           SAXNotSupportedException
+  {
+    try
+      {
+        // force "early" detection of errors where possible
+        // (flags can't necessarily be set before parsing)
+        new JaxpParser().getXMLReader().setFeature(name, value);
+        
+        flags.put(name, new Boolean(value));
+      }
+    catch (SAXNotRecognizedException e)
+      {
+        throw new SAXNotRecognizedException(name);
+      }
+    catch (SAXNotSupportedException e)
+      {
+        throw new SAXNotSupportedException(name);
+      }
+    catch (Exception e)
+      {
+        throw new ParserConfigurationException(e.getClass().getName()
+                                               + ": "
+                                               + e.getMessage());
+      }
+  }
+
+  public boolean getFeature(String name) 
+    throws ParserConfigurationException, SAXNotRecognizedException,
+           SAXNotSupportedException
+  {
+    Boolean value = (Boolean) flags.get(name);
+    
+    if (value != null)
+      {
+        return value.booleanValue();
+      }
+    else
+      {
+        try
+          {
+            return new JaxpParser().getXMLReader().getFeature(name);
+          }
+        catch (SAXNotRecognizedException e)
+          {
+            throw new SAXNotRecognizedException(name);
+          }
+        catch (SAXNotSupportedException e)
+          {
+            throw new SAXNotSupportedException(name);
+          }
+        catch (SAXException e)
+          {
+            throw new ParserConfigurationException(e.getClass().getName()
+                                                   + ": "
+                                                   + e.getMessage());
+          }
+      }
+  }
+           
+  private static class JaxpParser
+    extends SAXParser
+  {
+    
+    private XmlReader ae2 = new XmlReader();
+    private XMLReaderAdapter parser = null;
+    
+    JaxpParser()
     {
-	JaxpParser	jaxp = new JaxpParser ();
-	Enumeration	e = flags.keys ();
-	XMLReader	parser = jaxp.getXMLReader ();
-
-	parser.setFeature (
-		SAXDriver.FEATURE + "namespaces",
-		isNamespaceAware ());
-	parser.setFeature (
-		SAXDriver.FEATURE + "validation",
-		isValidating ());
-	// that makes SAX2 feature flags trump JAXP
-
-	while (e.hasMoreElements ()) {
-	    String	uri = (String) e.nextElement ();
-	    Boolean	value = (Boolean) flags.get (uri);
-	    parser.setFeature (uri, value.booleanValue ());
-	}
-
-	return jaxp;
-    }
-
-    // yes, this "feature transfer" mechanism doesn't play well
-
-    public void setFeature (String name, boolean value) 
-    throws
-	ParserConfigurationException,
-	SAXNotRecognizedException,
-	SAXNotSupportedException
-    {
-	try {
-	    // force "early" detection of errors where possible
-	    // (flags can't necessarily be set before parsing)
-	    new JaxpParser ().getXMLReader ().setFeature (name, value);
-
-	    flags.put (name, new Boolean (value));
-	} catch (SAXNotRecognizedException e) {
-	    throw new SAXNotRecognizedException (name);
-	} catch (SAXNotSupportedException e) {
-	    throw new SAXNotSupportedException (name);
-	} catch (Exception e) {
-	    throw new ParserConfigurationException (
-		  e.getClass ().getName ()
-		+ ": "
-		+ e.getMessage ());
-	}
-    }
-
-    public boolean getFeature (String name) 
-    throws
-	ParserConfigurationException,
-	SAXNotRecognizedException,
-	SAXNotSupportedException
-    {
-	Boolean	value = (Boolean) flags.get (name);
-	
-	if (value != null)
-	    return value.booleanValue ();
-	else
-	    try {
-		return new JaxpParser ().getXMLReader ().getFeature (name);
-	    } catch (SAXNotRecognizedException e) {
-		throw new SAXNotRecognizedException (name);
-	    } catch (SAXNotSupportedException e) {
-		throw new SAXNotSupportedException (name);
-	    } catch (SAXException e) {
-		throw new ParserConfigurationException (
-		      e.getClass ().getName ()
-		    + ": "
-		    + e.getMessage ());
-	    }
-    }
-
-    private static class JaxpParser extends SAXParser
-    {
-	private XmlReader	ae2 = new XmlReader ();
-	private XMLReaderAdapter parser = null;
-
-	JaxpParser () { }
-
-	public void setProperty (String id, Object value) 
-	throws SAXNotRecognizedException, SAXNotSupportedException
-	    { ae2.setProperty (id, value); }
-
-	public Object getProperty (String id) 
-	throws SAXNotRecognizedException, SAXNotSupportedException
-	    { return ae2.getProperty (id); }
-
-	public Parser getParser ()
-	throws SAXException
-	{ 
-	    if (parser == null)
-		parser = new XMLReaderAdapter (ae2);
-	    return parser;
-	}
-
-	public XMLReader getXMLReader ()
-	throws SAXException
-	    { return ae2; }
-
-	public boolean isNamespaceAware ()
-	{
-	    try {
-		return ae2.getFeature (SAXDriver.FEATURE + "namespaces");
-	    } catch (Exception e) {
-		throw new Error ();
-	    }
-	}
-
-	public boolean isValidating ()
-	{
-	    try {
-		return ae2.getFeature (SAXDriver.FEATURE + "validation");
-	    } catch (Exception e) {
-		throw new Error ();
-	    }
-	}
+    }
 
-        // TODO isXIncludeAware()
-        
+    public void setProperty(String id, Object value) 
+      throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+      ae2.setProperty(id, value);
+    }
+
+    public Object getProperty(String id) 
+      throws SAXNotRecognizedException, SAXNotSupportedException
+    {
+      return ae2.getProperty(id);
+    }
+
+    public Parser getParser()
+      throws SAXException
+    {
+      if (parser == null)
+        {
+          parser = new XMLReaderAdapter(ae2);
+        }
+      return parser;
     }
+
+    public XMLReader getXMLReader ()
+      throws SAXException
+    {
+      return ae2;
+    }
+
+    public boolean isNamespaceAware()
+    {
+      try
+        {
+          return ae2.getFeature(SAXDriver.FEATURE + "namespaces");
+        }
+      catch (Exception e)
+        {
+          throw new Error();
+        }
+    }
+    
+    public boolean isValidating()
+    {
+      try
+        {
+          return ae2.getFeature(SAXDriver.FEATURE + "validation");
+        }
+      catch (Exception e)
+        {
+          throw new Error();
+        }
+    }
+    
+    // TODO isXIncludeAware()
+    
+  }
+  
 }
+
Index: gnu/xml/aelfred2/SAXDriver.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/xml/aelfred2/SAXDriver.java,v
retrieving revision 1.2
diff -u -r1.2 SAXDriver.java
--- gnu/xml/aelfred2/SAXDriver.java 16 Feb 2005 19:25:02 -0000 1.2
+++ gnu/xml/aelfred2/SAXDriver.java 29 Mar 2005 19:50:35 -0000
@@ -60,15 +60,11 @@
 import java.util.Locale;
 import java.util.Stack;
 
-// maintaining 1.1 compatibility for now ... more portable, PJava, etc
-// Iterator, Hashmap and ArrayList ought to be faster
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Vector;
 
 import org.xml.sax.*;
 import org.xml.sax.ext.*;
@@ -133,1276 +129,1494 @@
  * @see org.xml.sax.Parser
  */
 final public class SAXDriver
-    implements Locator, Attributes2, XMLReader, Parser, AttributeList
+  implements Locator, Attributes2, XMLReader, Parser, AttributeList
 {
-    private final DefaultHandler2	base = new DefaultHandler2 ();
-    private XmlParser			parser;
-
-    private EntityResolver		entityResolver = base;
-    private EntityResolver2		resolver2 = null;
-    private ContentHandler		contentHandler = base;
-    private DTDHandler			dtdHandler = base;
-    private ErrorHandler 		errorHandler = base;
-    private DeclHandler			declHandler = base;
-    private LexicalHandler		lexicalHandler = base;
-
-    private String			elementName;
-    private Stack			entityStack;
-
-    // one vector (of object/struct): faster, smaller
-    private List			attributesList;
-
-    private boolean			namespaces = true;
-    private boolean			xmlNames = false;
-    private boolean			extGE = true;
-    private boolean			extPE = true;
-    private boolean			resolveAll = true;
-    private boolean			useResolver2 = true;
-    private boolean                     stringInterning = true;
-
-    private int				attributeCount;
-    private boolean			attributes;
-    private String			nsTemp [];
-    private NamespaceSupport		prefixStack;
-
-    //
-    // Constructor.
-    //
-
-    /** Constructs a SAX Parser.  */
-    public SAXDriver ()
-    {
-      reset ();
-    }
-
-    private void reset ()
-    {
-      elementName = null;
-      entityStack = new Stack ();
-      attributesList = Collections.synchronizedList(new ArrayList());
-      attributeCount = 0;
-      attributes = false;
-      nsTemp = new String[3];
-      prefixStack = null;
-    }
+  
+  private final DefaultHandler2 base = new DefaultHandler2();
+  private XmlParser parser;
+  
+  private EntityResolver entityResolver = base;
+  private EntityResolver2 resolver2 = null;
+  private ContentHandler contentHandler = base;
+  private DTDHandler dtdHandler = base;
+  private ErrorHandler errorHandler = base;
+  private DeclHandler declHandler = base;
+  private LexicalHandler lexicalHandler = base;
+  
+  private String elementName;
+  private Stack entityStack;
+  
+  // one vector (of object/struct): faster, smaller
+  private List attributesList;
+  
+  private boolean namespaces = true;
+  private boolean xmlNames = false;
+  private boolean extGE = true;
+  private boolean extPE = true;
+  private boolean resolveAll = true;
+  private boolean useResolver2 = true;
+  
+  // package private to allow (read-only) access in XmlParser
+  boolean stringInterning = true;
+  
+  private int attributeCount;
+  private boolean attributes;
+  private String[] nsTemp;
+  private NamespaceSupport prefixStack;
+  
+  //
+  // Constructor.
+  //
+
+  /**
+   * Constructs a SAX Parser.
+   */
+  public SAXDriver()
+  {
+    reset();
+  }
 
+  private void reset()
+  {
+    elementName = null;
+    entityStack = new Stack();
+    attributesList = Collections.synchronizedList(new ArrayList());
+    attributeCount = 0;
+    attributes = false;
+    nsTemp = new String[3];
+    prefixStack = null;
+  }
 
-    //
-    // Implementation of org.xml.sax.Parser.
-    //
 
-    /**
-     * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
-     * only locales using the English language are supported.
-     * @param locale The locale for which diagnostics will be generated
-     */
-    public void setLocale (Locale locale)
-    throws SAXException
-    {
-	if ("en".equals (locale.getLanguage ()))
-	    return ;
-
-	throw new SAXException ("AElfred2 only supports English locales.");
-    }
+  //
+  // Implementation of org.xml.sax.Parser.
+  //
+
+  /**
+   * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
+   * only locales using the English language are supported.
+   * @param locale The locale for which diagnostics will be generated
+   */
+  public void setLocale(Locale locale)
+    throws SAXException
+  {
+    if ("en".equals(locale.getLanguage()))
+      {
+        return;
+      }
+    throw new SAXException ("AElfred2 only supports English locales.");
+  }
 
+  /**
+   * <b>SAX2</b>: Returns the object used when resolving external
+   * entities during parsing (both general and parameter entities).
+   */
+  public EntityResolver getEntityResolver()
+  {
+    return (entityResolver == base) ? null : entityResolver;
+  }
 
-    /**
-     * <b>SAX2</b>: Returns the object used when resolving external
-     * entities during parsing (both general and parameter entities).
-     */
-    public EntityResolver getEntityResolver ()
-    {
-	return (entityResolver == base) ? null : entityResolver;
-    }
+  /**
+   * <b>SAX1, SAX2</b>: Set the entity resolver for this parser.
+   * @param handler The object to receive entity events.
+   */
+  public void setEntityResolver(EntityResolver resolver)
+  {
+    if (resolver instanceof EntityResolver2)
+      {
+        resolver2 = (EntityResolver2) resolver;
+      }
+    else
+      {
+        resolver2 = null;
+      }
+    if (resolver == null)
+      {
+        resolver = base;
+      }
+    entityResolver = resolver;
+  }
 
-    /**
-     * <b>SAX1, SAX2</b>: Set the entity resolver for this parser.
-     * @param handler The object to receive entity events.
-     */
-    public void setEntityResolver (EntityResolver resolver)
-    {
-	if (resolver instanceof EntityResolver2)
-	    resolver2 = (EntityResolver2) resolver;
-	else
-	    resolver2 = null;
-	if (resolver == null)
-	    resolver = base;
-	entityResolver = resolver;
-    }
+  /**
+   * <b>SAX2</b>: Returns the object used to process declarations related
+   * to notations and unparsed entities.
+   */
+  public DTDHandler getDTDHandler()
+  {
+    return (dtdHandler == base) ? null : dtdHandler;
+  }
 
+  /**
+   * <b>SAX1, SAX2</b>: Set the DTD handler for this parser.
+   * @param handler The object to receive DTD events.
+   */
+  public void setDTDHandler(DTDHandler handler)
+  {
+    if (handler == null)
+      {
+        handler = base;
+      }
+    this.dtdHandler = handler;
+  }
 
-    /**
-     * <b>SAX2</b>: Returns the object used to process declarations related
-     * to notations and unparsed entities.
-     */
-    public DTDHandler getDTDHandler ()
-    {
-	return (dtdHandler == base) ? null : dtdHandler;
-    }
 
-    /**
-     * <b>SAX1, SAX2</b>: Set the DTD handler for this parser.
-     * @param handler The object to receive DTD events.
-     */
-    public void setDTDHandler (DTDHandler handler)
-    {
-	if (handler == null)
-	    handler = base;
-	this.dtdHandler = handler;
-    }
+  /**
+   * <b>SAX1</b>: Set the document handler for this parser.  If a
+   * content handler was set, this document handler will supplant it.
+   * The parser is set to report all XML 1.0 names rather than to
+   * filter out "xmlns" attributes (the "namespace-prefixes" feature
+   * is set to true).
+   *
+   * @deprecated SAX2 programs should use the XMLReader interface
+   *  and a ContentHandler.
+   *
+   * @param handler The object to receive document events.
+   */
+  public void setDocumentHandler(DocumentHandler handler)
+  {
+    contentHandler = new Adapter(handler);
+    xmlNames = true;
+  }
 
+  /**
+   * <b>SAX2</b>: Returns the object used to report the logical
+   * content of an XML document.
+   */
+  public ContentHandler getContentHandler()
+  {
+    return (contentHandler == base) ? null : contentHandler;
+  }
 
-    /**
-     * <b>SAX1</b>: Set the document handler for this parser.  If a
-     * content handler was set, this document handler will supplant it.
-     * The parser is set to report all XML 1.0 names rather than to
-     * filter out "xmlns" attributes (the "namespace-prefixes" feature
-     * is set to true).
-     *
-     * @deprecated SAX2 programs should use the XMLReader interface
-     *	and a ContentHandler.
-     *
-     * @param handler The object to receive document events.
-     */
-    public void setDocumentHandler (DocumentHandler handler)
-    {
-	contentHandler = new Adapter (handler);
-	xmlNames = true;
-    }
+  /**
+   * <b>SAX2</b>: Assigns the object used to report the logical
+   * content of an XML document.  If a document handler was set,
+   * this content handler will supplant it (but XML 1.0 style name
+   * reporting may remain enabled).
+   */
+  public void setContentHandler(ContentHandler handler)
+  {
+    if (handler == null)
+      {
+        handler = base;
+      }
+    contentHandler = handler;
+  }
 
-    /**
-     * <b>SAX2</b>: Returns the object used to report the logical
-     * content of an XML document.
-     */
-    public ContentHandler getContentHandler ()
-    {
-	return contentHandler == base ? null : contentHandler;
-    }
+  /**
+   * <b>SAX1, SAX2</b>: Set the error handler for this parser.
+   * @param handler The object to receive error events.
+   */
+  public void setErrorHandler(ErrorHandler handler)
+  {
+    if (handler == null)
+      {
+        handler = base;
+      }
+    this.errorHandler = handler;
+  }
 
-    /**
-     * <b>SAX2</b>: Assigns the object used to report the logical
-     * content of an XML document.  If a document handler was set,
-     * this content handler will supplant it (but XML 1.0 style name
-     * reporting may remain enabled).
-     */
-    public void setContentHandler (ContentHandler handler)
-    {
-	if (handler == null)
-	    handler = base;
-	contentHandler = handler;
-    }
+  /**
+   * <b>SAX2</b>: Returns the object used to receive callbacks for XML
+   * errors of all levels (fatal, nonfatal, warning); this is never null;
+   */
+  public ErrorHandler getErrorHandler()
+  {
+    return (errorHandler == base) ? null : errorHandler;
+  }
 
-    /**
-     * <b>SAX1, SAX2</b>: Set the error handler for this parser.
-     * @param handler The object to receive error events.
-     */
-    public void setErrorHandler (ErrorHandler handler)
-    {
-	if (handler == null)
-	    handler = base;
-	this.errorHandler = handler;
-    }
+  /**
+   * <b>SAX1, SAX2</b>: Auxiliary API to parse an XML document, used mostly
+   * when no URI is available.
+   * If you want anything useful to happen, you should set
+   * at least one type of handler.
+   * @param source The XML input source.  Don't set 'encoding' unless
+   *  you know for a fact that it's correct.
+   * @see #setEntityResolver
+   * @see #setDTDHandler
+   * @see #setContentHandler
+   * @see #setErrorHandler
+   * @exception SAXException The handlers may throw any SAXException,
+   *  and the parser normally throws SAXParseException objects.
+   * @exception IOException IOExceptions are normally through through
+   *  the parser if there are problems reading the source document.
+   */
+  public void parse(InputSource source)
+    throws SAXException, IOException
+  {
+    synchronized (base)
+      {
+        parser = new XmlParser();
+        if (namespaces)
+          {
+            prefixStack = new NamespaceSupport();
+          }
+        else if (!xmlNames)
+          {
+            throw new IllegalStateException();
+          }
+        parser.setHandler(this);
+        
+        try
+          {
+            Reader r = source.getCharacterStream();
+            InputStream in = source.getByteStream();
+                        
+            parser.doParse(source.getSystemId(),
+                           source.getPublicId(),
+                           r,
+                           in,
+                           source.getEncoding());
+          }
+        catch (SAXException e)
+          {
+            throw e;
+          }
+        catch (IOException e)
+          {
+            throw e;
+          }
+        catch (RuntimeException e)
+          {
+            throw e;
+          }
+        catch (Exception e)
+          {
+            throw new SAXParseException(e.getMessage(), this, e);
+          }
+        finally
+          {
+            contentHandler.endDocument();
+            reset();
+          }
+      }
+  }
 
-    /**
-     * <b>SAX2</b>: Returns the object used to receive callbacks for XML
-     * errors of all levels (fatal, nonfatal, warning); this is never null;
-     */
-    public ErrorHandler getErrorHandler ()
-	{ return errorHandler == base ? null : errorHandler; }
+  /**
+   * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a
+   * system identifier (URI).
+   */
+  public void parse(String systemId)
+    throws SAXException, IOException
+  {
+    parse(new InputSource(systemId));
+  }
 
+  //
+  // Implementation of SAX2 "XMLReader" interface
+  //
+  static final String FEATURE = "http://xml.org/sax/features/";;
+  static final String PROPERTY = "http://xml.org/sax/properties/";;
+
+  /**
+   * <b>SAX2</b>: Tells the value of the specified feature flag.
+   *
+   * @exception SAXNotRecognizedException thrown if the feature flag
+   *  is neither built in, nor yet assigned.
+   */
+  public boolean getFeature(String featureId)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+  {
+    if ((FEATURE + "validation").equals(featureId))
+      {
+        return false;
+      }
 
-    /**
-     * <b>SAX1, SAX2</b>: Auxiliary API to parse an XML document, used mostly
-     * when no URI is available.
-     * If you want anything useful to happen, you should set
-     * at least one type of handler.
-     * @param source The XML input source.  Don't set 'encoding' unless
-     *	you know for a fact that it's correct.
-     * @see #setEntityResolver
-     * @see #setDTDHandler
-     * @see #setContentHandler
-     * @see #setErrorHandler
-     * @exception SAXException The handlers may throw any SAXException,
-     *	and the parser normally throws SAXParseException objects.
-     * @exception IOException IOExceptions are normally through through
-     *	the parser if there are problems reading the source document.
-     */
-    public void parse (InputSource source)
-    throws SAXException, IOException
-    {
-	synchronized (base) {
-	    parser = new XmlParser ();
-	    if (namespaces)
-		prefixStack = new NamespaceSupport ();
-	    else if (!xmlNames)
-		throw new IllegalStateException ();
-	    parser.setHandler (this);
-
-	    try {
-
-	      Reader r = source.getCharacterStream();
-	      InputStream in = source.getByteStream();
-
-	      
-		parser.doParse (source.getSystemId (),
-			      source.getPublicId (),
-			      r,
-			      in,
-			      source.getEncoding ());
-	    } catch (SAXException e) {
-		throw e;
-	    } catch (IOException e) {
-		throw e;
-	    } catch (RuntimeException e) {
-		throw e;
-	    } catch (Exception e) {
-		throw new SAXParseException (e.getMessage (), this, e);
-	    } finally {
-		contentHandler.endDocument ();
-                reset();
-	    }
-	}
-    }
+    // external entities (both types) are optionally included
+    if ((FEATURE + "external-general-entities").equals(featureId))
+      {
+        return extGE;
+      }
+    if ((FEATURE + "external-parameter-entities").equals(featureId))
+      {
+        return extPE;
+      }
+    
+    // element/attribute names are as written in document; no mangling
+    if ((FEATURE + "namespace-prefixes").equals(featureId))
+      {
+        return xmlNames;
+      }
 
+    // report element/attribute namespaces?
+    if ((FEATURE + "namespaces").equals(featureId))
+      {
+        return namespaces;
+      }
 
-    /**
-     * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a
-     * system identifier (URI).
-     */
-    public void parse (String systemId)
-    throws SAXException, IOException
-    {
-	parse (new InputSource (systemId));
-    }
+    // all PEs and GEs are reported
+    if ((FEATURE + "lexical-handler/parameter-entities").equals(featureId))
+      {
+        return true;
+      }
 
-    //
-    // Implementation of SAX2 "XMLReader" interface
-    //
-    static final String	FEATURE = "http://xml.org/sax/features/";;
-    static final String	PROPERTY = "http://xml.org/sax/properties/";;
+    // default is true
+    if ((FEATURE + "string-interning").equals(featureId))
+      {
+        return stringInterning;
+      }
+  
+    // EXTENSIONS 1.1
+    
+    // always returns isSpecified info
+    if ((FEATURE + "use-attributes2").equals(featureId))
+      {
+        return true;
+      }
+  
+    // meaningful between startDocument/endDocument
+    if ((FEATURE + "is-standalone").equals(featureId))
+      {
+        if (parser == null)
+          {
+            throw new SAXNotSupportedException(featureId);
+          }
+        return parser.isStandalone();
+      }
 
-    /**
-     * <b>SAX2</b>: Tells the value of the specified feature flag.
-     *
-     * @exception SAXNotRecognizedException thrown if the feature flag
-     *	is neither built in, nor yet assigned.
-     */
-    public boolean getFeature (String featureId)
-    throws SAXNotRecognizedException, SAXNotSupportedException
-    {
-	if ((FEATURE + "validation").equals (featureId))
-	    return false;
+    // optionally don't absolutize URIs in declarations
+    if ((FEATURE + "resolve-dtd-uris").equals(featureId))
+      {
+        return resolveAll;
+      }
 
-	// external entities (both types) are optionally included
-	if ((FEATURE + "external-general-entities").equals (featureId))
-	    return extGE;
-	if ((FEATURE + "external-parameter-entities") .equals (featureId))
-	    return extPE;
-
-	// element/attribute names are as written in document; no mangling
-	if ((FEATURE + "namespace-prefixes").equals (featureId))
-	    return xmlNames;
-
-	// report element/attribute namespaces?
-	if ((FEATURE + "namespaces").equals (featureId))
-	    return namespaces;
-
-	// all PEs and GEs are reported
-	if ((FEATURE + "lexical-handler/parameter-entities").equals (featureId))
-	    return true;
-
-	// default is true
-	if ((FEATURE + "string-interning").equals (featureId))
-	    return stringInterning;
-	
-	// EXTENSIONS 1.1
-
-	// always returns isSpecified info
-	if ((FEATURE + "use-attributes2").equals (featureId))
-	    return true;
-	
-	// meaningful between startDocument/endDocument
-	if ((FEATURE + "is-standalone").equals (featureId)) {
-	    if (parser == null)
-		throw new SAXNotSupportedException (featureId);
-	    return parser.isStandalone ();
-	}
-
-	// optionally don't absolutize URIs in declarations
-	if ((FEATURE + "resolve-dtd-uris").equals (featureId))
-	    return resolveAll;
-
-	// optionally use resolver2 interface methods, if possible
-	if ((FEATURE + "use-entity-resolver2").equals (featureId))
-	    return useResolver2;
-	
-	throw new SAXNotRecognizedException (featureId);
-    }
+    // optionally use resolver2 interface methods, if possible
+    if ((FEATURE + "use-entity-resolver2").equals(featureId))
+      {
+        return useResolver2;
+      }
+  
+    throw new SAXNotRecognizedException(featureId);
+  }
 
-    // package private
-    DeclHandler getDeclHandler () { return declHandler; }
+  // package private
+  DeclHandler getDeclHandler()
+  {
+    return declHandler;
+  }
 
-    // package private
-    boolean resolveURIs () { return resolveAll; }
+  // package private
+  boolean resolveURIs()
+  {
+    return resolveAll;
+  }
 
-    /**
-     * <b>SAX2</b>:  Returns the specified property.
-     *
-     * @exception SAXNotRecognizedException thrown if the property value
-     *	is neither built in, nor yet stored.
-     */
-    public Object getProperty (String propertyId)
+  /**
+   * <b>SAX2</b>:  Returns the specified property.
+   *
+   * @exception SAXNotRecognizedException thrown if the property value
+   *  is neither built in, nor yet stored.
+   */
+  public Object getProperty(String propertyId)
     throws SAXNotRecognizedException
-    {
-	if ((PROPERTY + "declaration-handler").equals (propertyId))
-	    return declHandler == base ? null : declHandler;
+  {
+    if ((PROPERTY + "declaration-handler").equals(propertyId))
+      {
+        return (declHandler == base) ? null : declHandler;
+      }
 
-	if ((PROPERTY + "lexical-handler").equals (propertyId))
-	    return lexicalHandler == base ? null : lexicalHandler;
-	
-	// unknown properties
-	throw new SAXNotRecognizedException (propertyId);
-    }
+    if ((PROPERTY + "lexical-handler").equals(propertyId))
+      {
+        return (lexicalHandler == base) ? null : lexicalHandler;
+      }
+    
+    // unknown properties
+    throw new SAXNotRecognizedException(propertyId);
+  }
 
-    /**
-     * <b>SAX2</b>:  Sets the state of feature flags in this parser.  Some
-     * built-in feature flags are mutable.
-     */
-    public void setFeature (String featureId, boolean value)
+  /**
+   * <b>SAX2</b>:  Sets the state of feature flags in this parser.  Some
+   * built-in feature flags are mutable.
+   */
+  public void setFeature(String featureId, boolean value)
     throws SAXNotRecognizedException, SAXNotSupportedException
-    {
-	boolean	state;
-	
-	// Features with a defined value, we just change it if we can.
-	state = getFeature (featureId);
-
-	if (state == value)
-	    return;
-	if (parser != null)
-	    throw new SAXNotSupportedException ("not while parsing");
-
-	if ((FEATURE + "namespace-prefixes").equals (featureId)) {
-	    // in this implementation, this only affects xmlns reporting
-	    xmlNames = value;
-	    // forcibly prevent illegal parser state
-	    if (!xmlNames)
-		namespaces = true;
-	    return;
-	}
-
-	if ((FEATURE + "namespaces").equals (featureId)) {
-	    namespaces = value;
-	    // forcibly prevent illegal parser state
-	    if (!namespaces)
-		xmlNames = true;
-	    return;
-	}
-
-	if ((FEATURE + "external-general-entities").equals (featureId)) {
-	    extGE = value;
-	    return;
-	}
-	if ((FEATURE + "external-parameter-entities") .equals (featureId)) {
-	    extPE = value;
-	    return;
-	}
-	if ((FEATURE + "resolve-dtd-uris").equals (featureId)) {
-	    resolveAll = value;
-	    return;
-	}
-
-	if ((FEATURE + "use-entity-resolver2").equals (featureId)) {
-	    useResolver2 = value;
-	    return;
-	}
-
-	throw new SAXNotRecognizedException (featureId);
-    }
+  {
+    boolean state;
+  
+    // Features with a defined value, we just change it if we can.
+    state = getFeature (featureId);
+    
+    if (state == value)
+      {
+        return;
+      }
+    if (parser != null)
+      {
+        throw new SAXNotSupportedException("not while parsing");
+      }
 
-    /**
-     * <b>SAX2</b>:  Assigns the specified property.  Like SAX1 handlers,
-     * these may be changed at any time.
-     */
-    public void setProperty (String propertyId, Object value)
-    throws SAXNotRecognizedException, SAXNotSupportedException
-    {
-	// see if the property is recognized
-	getProperty (propertyId);
+    if ((FEATURE + "namespace-prefixes").equals(featureId))
+      {
+        // in this implementation, this only affects xmlns reporting
+        xmlNames = value;
+        // forcibly prevent illegal parser state
+        if (!xmlNames)
+          {
+            namespaces = true;
+          }
+        return;
+      }
 
-	// Properties with a defined value, we just change it if we can.
+    if ((FEATURE + "namespaces").equals(featureId))
+      {
+        namespaces = value;
+        // forcibly prevent illegal parser state
+        if (!namespaces)
+          {
+            xmlNames = true;
+          }
+        return;
+      }
 
-	if ((PROPERTY + "declaration-handler").equals (propertyId)) {
-	    if (value == null)
-		declHandler = base;
-	    else if (! (value instanceof DeclHandler))
-		throw new SAXNotSupportedException (propertyId);
-	    else
-		declHandler = (DeclHandler) value;
-	    return ;
-	}
-
-	if ((PROPERTY + "lexical-handler").equals (propertyId)) {
-	    if (value == null)
-		lexicalHandler = base;
-	    else if (! (value instanceof LexicalHandler))
-		throw new SAXNotSupportedException (propertyId);
-	    else
-		lexicalHandler = (LexicalHandler) value;
-	    return ;
-	}
+    if ((FEATURE + "external-general-entities").equals(featureId))
+      {
+        extGE = value;
+        return;
+      }
+    if ((FEATURE + "external-parameter-entities").equals(featureId))
+      {
+        extPE = value;
+        return;
+      }
+    if ((FEATURE + "resolve-dtd-uris").equals(featureId))
+      {
+        resolveAll = value;
+        return;
+      }
 
-	throw new SAXNotSupportedException (propertyId);
-    }
+    if ((FEATURE + "use-entity-resolver2").equals(featureId))
+      {
+        useResolver2 = value;
+        return;
+      }
 
+    throw new SAXNotRecognizedException(featureId);
+  }
 
-    //
-    // This is where the driver receives XmlParser callbacks and translates
-    // them into SAX callbacks.  Some more callbacks have been added for
-    // SAX2 support.
-    //
+  /**
+   * <b>SAX2</b>:  Assigns the specified property.  Like SAX1 handlers,
+   * these may be changed at any time.
+   */
+  public void setProperty(String propertyId, Object value)
+    throws SAXNotRecognizedException, SAXNotSupportedException
+  {
+    // see if the property is recognized
+    getProperty(propertyId);
+    
+    // Properties with a defined value, we just change it if we can.
+    
+    if ((PROPERTY + "declaration-handler").equals(propertyId))
+      {
+        if (value == null)
+          {
+            declHandler = base;
+          }
+        else if (!(value instanceof DeclHandler))
+          {
+            throw new SAXNotSupportedException(propertyId);
+          }
+        else
+          {
+            declHandler = (DeclHandler) value;
+          }
+        return ;
+      }
+    
+    if ((PROPERTY + "lexical-handler").equals(propertyId))
+      {
+        if (value == null)
+          {
+            lexicalHandler = base;
+          }
+        else if (!(value instanceof LexicalHandler))
+          {
+            throw new SAXNotSupportedException(propertyId);
+          }
+        else
+          {
+            lexicalHandler = (LexicalHandler) value;
+          }
+        return;
+      }
+    
+    throw new SAXNotSupportedException(propertyId);
+  }
 
-    void startDocument ()
-    throws SAXException
-    {
-	contentHandler.setDocumentLocator (this);
-	contentHandler.startDocument ();
-	attributesList.clear ();
-    }
+  //
+  // This is where the driver receives XmlParser callbacks and translates
+  // them into SAX callbacks.  Some more callbacks have been added for
+  // SAX2 support.
+  //
+
+  void startDocument()
+    throws SAXException
+  {
+    contentHandler.setDocumentLocator(this);
+    contentHandler.startDocument();
+    attributesList.clear();
+  }
 
-    void xmlDecl(String version,
-                 String encoding,
-                 boolean standalone,
-                 String inputEncoding)
-      throws SAXException
-    {
-      if (contentHandler instanceof ContentHandler2)
-        {
-          ((ContentHandler2) contentHandler).xmlDecl(version,
-                                                     encoding,
-                                                     standalone,
-                                                     inputEncoding);
-        }
-    }
+  void xmlDecl(String version,
+               String encoding,
+               boolean standalone,
+               String inputEncoding)
+    throws SAXException
+  {
+    if (contentHandler instanceof ContentHandler2)
+      {
+        ((ContentHandler2) contentHandler).xmlDecl(version,
+                                                   encoding,
+                                                   standalone,
+                                                   inputEncoding);
+      }
+  }
 
-    void skippedEntity (String name)
+  void skippedEntity(String name)
     throws SAXException
-	{ contentHandler.skippedEntity (name); }
+  {
+    contentHandler.skippedEntity(name);
+  }
 
-    InputSource getExternalSubset (String name, String baseURI)
+  InputSource getExternalSubset(String name, String baseURI)
     throws SAXException, IOException
-    {
-	if (resolver2 == null || !useResolver2 || !extPE)
-	    return null;
-	return resolver2.getExternalSubset (name, baseURI);
-    }
+  {
+    if (resolver2 == null || !useResolver2 || !extPE)
+      {
+        return null;
+      }
+    return resolver2.getExternalSubset(name, baseURI);
+  }
 
-    InputSource resolveEntity (boolean isPE, String name,
-    	InputSource in, String baseURI)
+  InputSource resolveEntity(boolean isPE, String name,
+                            InputSource in, String baseURI)
     throws SAXException, IOException
-    {
-	InputSource	source;
+  {
+    InputSource  source;
+    
+    // external entities might be skipped
+    if (isPE && !extPE)
+      {
+        return null;
+      }
+    if (!isPE && !extGE)
+      {
+        return null;
+      }
 
-	// external entities might be skipped
-	if (isPE && !extPE)
-	    return null;
-	if (!isPE && !extGE)
-	    return null;
-
-	// ... or not
-	lexicalHandler.startEntity (name);
-	if (resolver2 != null && useResolver2) {
-	    source = resolver2.resolveEntity (name, in.getPublicId (),
-			baseURI, in.getSystemId ());
-	    if (source == null) {
-		in.setSystemId (absolutize (baseURI,
-				in.getSystemId (), false));
-		source = in;
-	    }
-	} else {
-	    in.setSystemId (absolutize (baseURI, in.getSystemId (), false));
-	    source = entityResolver.resolveEntity (in.getPublicId (),
-			in.getSystemId ());
-	    if (source == null)
-		source = in;
-	}
-	startExternalEntity (name, source.getSystemId (), true);
-	return source;
-    }
+    // ... or not
+    lexicalHandler.startEntity(name);
+    if (resolver2 != null && useResolver2)
+      {
+        source = resolver2.resolveEntity(name, in.getPublicId(),
+                                         baseURI, in.getSystemId());
+        if (source == null)
+          {
+            in.setSystemId(absolutize(baseURI,
+                                      in.getSystemId(), false));
+            source = in;
+          }
+      }
+    else
+      {
+        in.setSystemId(absolutize(baseURI, in.getSystemId(), false));
+        source = entityResolver.resolveEntity(in.getPublicId(),
+                                              in.getSystemId());
+        if (source == null)
+          {
+            source = in;
+          }
+      }
+    startExternalEntity(name, source.getSystemId(), true);
+    return source;
+  }
 
-    // absolutize a system ID relative to the specified base URI
-    // (temporarily) package-visible for external entity decls
-    String absolutize (String baseURI, String systemId, boolean nice)
+  // absolutize a system ID relative to the specified base URI
+  // (temporarily) package-visible for external entity decls
+  String absolutize(String baseURI, String systemId, boolean nice)
     throws MalformedURLException, SAXException
-    {
-	// FIXME normalize system IDs -- when?
-	// - Convert to UTF-8
-	// - Map reserved and non-ASCII characters to %HH
-
-	try {
-	    if (baseURI == null) {
-		warn ("No base URI; hope this SYSTEM id is absolute: "
-			+ systemId);
-		return new URL (systemId).toString ();
-	    } else
-		return new URL (new URL (baseURI), systemId).toString ();
-
-	} catch (MalformedURLException e) {
-
-	    // Let unknown URI schemes pass through unless we need
-	    // the JVM to map them to i/o streams for us...
-	    if (!nice)
-		throw e;
-
-	    // sometimes sysids for notations or unparsed entities
-	    // aren't really URIs...
-	    warn ("Can't absolutize SYSTEM id: " + e.getMessage ());
-	    return systemId;
-	}
-    }
+  {
+    // FIXME normalize system IDs -- when?
+    // - Convert to UTF-8
+    // - Map reserved and non-ASCII characters to %HH
+    
+    try
+      {
+        if (baseURI == null)
+          {
+            if (XmlParser.uriWarnings)
+              {
+                warn ("No base URI; hope this SYSTEM id is absolute: "
+                      + systemId);
+              }
+            return new URL(systemId).toString();
+          }
+        else
+          {
+            return new URL(new URL(baseURI), systemId).toString();
+          }
+      }
+    catch (MalformedURLException e)
+      {
+        // Let unknown URI schemes pass through unless we need
+        // the JVM to map them to i/o streams for us...
+        if (!nice)
+          {
+            throw e;
+          }
+        
+        // sometimes sysids for notations or unparsed entities
+        // aren't really URIs...
+        warn("Can't absolutize SYSTEM id: " + e.getMessage());
+        return systemId;
+      }
+  }
 
-    void startExternalEntity (String name, String systemId,
-    	boolean stackOnly)
+  void startExternalEntity(String name, String systemId, boolean stackOnly)
     throws SAXException
-    {
-	// The following warning was deleted because the application has the
-	// option of not setting systemId. Sun's JAXP or Xerces seems to
-	// ignore this case.
-	/*
-	if (systemId == null)
-	    warn ("URI was not reported to parser for entity " + name);
-	*/
-	if (!stackOnly)		// spliced [dtd] needs startEntity
-	    lexicalHandler.startEntity (name);
-	entityStack.push (systemId);
-    }
+  {
+    // The following warning was deleted because the application has the
+    // option of not setting systemId. Sun's JAXP or Xerces seems to
+    // ignore this case.
+    /*
+       if (systemId == null)
+       warn ("URI was not reported to parser for entity " + name);
+     */
+    if (!stackOnly)  // spliced [dtd] needs startEntity
+      {
+        lexicalHandler.startEntity(name);
+      }
+    entityStack.push(systemId);
+  }
 
-    void endExternalEntity (String name)
+  void endExternalEntity(String name)
     throws SAXException
-    {
-	if (!"[document]".equals (name))
-	    lexicalHandler.endEntity (name);
-	entityStack.pop ();
-    }
+  {
+    if (!"[document]".equals(name))
+      {
+        lexicalHandler.endEntity(name);
+      }
+    entityStack.pop();
+  }
 
-    void startInternalEntity (String name)
+  void startInternalEntity(String name)
     throws SAXException
-    {
-	lexicalHandler.startEntity (name);
-    }
+  {
+    lexicalHandler.startEntity(name);
+  }
 
-    void endInternalEntity (String name)
+  void endInternalEntity(String name)
     throws SAXException
-    {
-	lexicalHandler.endEntity (name);
-    }
+  {
+    lexicalHandler.endEntity(name);
+  }
 
-    void doctypeDecl (String name, String publicId, String systemId)
+  void doctypeDecl(String name, String publicId, String systemId)
     throws SAXException
-    {
-	lexicalHandler.startDTD (name, publicId, systemId);
-	
-	// ... the "name" is a declaration and should be given
-	// to the DeclHandler (but sax2 doesn't).
-
-	// the IDs for the external subset are lexical details,
-	// as are the contents of the internal subset; but sax2
-	// doesn't provide the internal subset "pre-parse"
-    }
+  {
+    lexicalHandler.startDTD(name, publicId, systemId);
+  
+    // ... the "name" is a declaration and should be given
+    // to the DeclHandler (but sax2 doesn't).
+    
+    // the IDs for the external subset are lexical details,
+    // as are the contents of the internal subset; but sax2
+    // doesn't provide the internal subset "pre-parse"
+  }
+  
+  void notationDecl(String name, String publicId, String systemId,
+                    String baseUri)
+    throws SAXException
+  {
+    try
+      {
+        dtdHandler.notationDecl(name, publicId,
+                                (resolveAll && systemId != null)
+                                ? absolutize(baseUri, systemId, true)
+                                : systemId);
+      }
+    catch (IOException e)
+      {
+        // "can't happen"
+        throw new SAXParseException(e.getMessage(), this, e);
+      }
+  }
 
-    void notationDecl (String name, String ids [])
+  void unparsedEntityDecl(String name, String publicId, String systemId,
+                          String baseUri, String notation)
     throws SAXException
-    {
-	try {
-	    dtdHandler.notationDecl (name, ids [0],
-		(resolveAll && ids [1] != null)
-			? absolutize (ids [2], ids [1], true)
-			: ids [1]);
-	} catch (IOException e) {
-	    // "can't happen"
-	    throw new SAXParseException (e.getMessage (), this, e);
-	}
-    }
+  {
+    try
+      {
+        dtdHandler.unparsedEntityDecl(name, publicId,
+                                      resolveAll
+                                      ? absolutize(baseUri, systemId, true)
+                                      : systemId,
+                                      notation);
+      }
+    catch (IOException e)
+      {
+        // "can't happen"
+        throw new SAXParseException(e.getMessage(), this, e);
+      }
+  }
 
-    void unparsedEntityDecl (String name, String ids [], String notation)
+  void endDoctype()
     throws SAXException
-    {
-	try {
-	    dtdHandler.unparsedEntityDecl (name, ids [0],
-		    resolveAll
-			? absolutize (ids [2], ids [1], true)
-			: ids [1],
-		    notation);
-	} catch (IOException e) {
-	    // "can't happen"
-	    throw new SAXParseException (e.getMessage (), this, e);
-	}
-    }
+  {
+    lexicalHandler.endDTD();
+  }
 
-    void endDoctype ()
+  private void declarePrefix(String prefix, String uri)
     throws SAXException
-    {
-	lexicalHandler.endDTD ();
-    }
+  {
+    int index = uri.indexOf(':');
 
-    private void declarePrefix (String prefix, String uri)
-    throws SAXException
-    {
-	int index = uri.indexOf (':');
+    // many versions of nwalsh docbook stylesheets 
+    // have bogus URLs; so this can't be an error...
+    if (index < 1 && uri.length() != 0)
+      {
+        warn("relative URI for namespace: " + uri);
+      }
 
-	// many versions of nwalsh docbook stylesheets 
-	// have bogus URLs; so this can't be an error...
-	if (index < 1 && uri.length () != 0)
-	    warn ("relative URI for namespace: " + uri);
-
-	// FIXME:  char [0] must be ascii alpha; chars [1..index]
-	// must be ascii alphanumeric or in "+-." [RFC 2396]
-	
-	//Namespace Constraints
-	//name for xml prefix must be http://www.w3.org/XML/1998/namespace
-	boolean prefixEquality = prefix.equals("xml");
-	boolean uriEquality = uri.equals("http://www.w3.org/XML/1998/namespace";);
-	if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality))
-	   fatal ("xml is by definition bound to the namespace name " +
-	   		"http://www.w3.org/XML/1998/namespace";);
-	
-        //xmlns prefix declaration is illegal but xml prefix declaration is llegal...
-	if (prefixEquality && uriEquality)
-	   return;
-	
-        //name for xmlns prefix must be http://www.w3.org/2000/xmlns/
-	prefixEquality = prefix.equals("xmlns");
-	uriEquality = uri.equals("http://www.w3.org/2000/xmlns/";);
-	if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality))
-	   fatal("http://www.w3.org/2000/xmlns/ is by definition bound" +
-	   		" to prefix xmlns");
-	
-	//even if the uri is http://www.w3.org/2000/xmlns/ it is illegal to declare it
-	if (prefixEquality && uriEquality)
-	   fatal ("declaring the xmlns prefix is illegal");
-		
-	uri = uri.intern ();
-	prefixStack.declarePrefix (prefix, uri);
-	contentHandler.startPrefixMapping (prefix, uri);
-    }
+    // FIXME:  char [0] must be ascii alpha; chars [1..index]
+    // must be ascii alphanumeric or in "+-." [RFC 2396]
+    
+    //Namespace Constraints
+    //name for xml prefix must be http://www.w3.org/XML/1998/namespace
+    boolean prefixEquality = prefix.equals("xml");
+    boolean uriEquality = uri.equals("http://www.w3.org/XML/1998/namespace";);
+    if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality))
+      {
+        fatal("xml is by definition bound to the namespace name " +
+              "http://www.w3.org/XML/1998/namespace";);
+      }
+  
+    //xmlns prefix declaration is illegal but xml prefix declaration is llegal...
+    if (prefixEquality && uriEquality)
+      {
+        return;
+      }
+  
+    //name for xmlns prefix must be http://www.w3.org/2000/xmlns/
+    prefixEquality = prefix.equals("xmlns");
+    uriEquality = uri.equals("http://www.w3.org/2000/xmlns/";);
+    if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality))
+      {
+        fatal("http://www.w3.org/2000/xmlns/ is by definition bound" +
+              " to prefix xmlns");
+      }
+  
+    //even if the uri is http://www.w3.org/2000/xmlns/
+    // it is illegal to declare it
+    if (prefixEquality && uriEquality)
+      {
+        fatal ("declaring the xmlns prefix is illegal");
+      }
+  
+    uri = uri.intern();
+    prefixStack.declarePrefix(prefix, uri);
+    contentHandler.startPrefixMapping(prefix, uri);
+  }
 
-    void attribute (String qname, String value, boolean isSpecified)
+  void attribute(String qname, String value, boolean isSpecified)
     throws SAXException
-    {
-	if (!attributes) {
-	    attributes = true;
-	    if (namespaces)
-		prefixStack.pushContext ();
-	}
-
-	// process namespace decls immediately;
-	// then maybe forget this as an attribute
-	if (namespaces) {
-	    int	index;
-
-      // default NS declaration?
-      if (getFeature (FEATURE + "string-interning")) {
-        if ("xmlns" == qname) {
-          declarePrefix ("", value);
-          if (!xmlNames)
-            return;
-        }
-        // NS prefix declaration?
-        else if ((index = qname.indexOf (':')) == 5
-                 && qname.startsWith ("xmlns")) {
-          String		prefix = qname.substring (6);
-          
-          if (prefix.equals(""))
-          	fatal ("missing prefix in namespace declaration attribute");	
-          if (value.length () == 0) {
-            verror ("missing URI in namespace declaration attribute: "
-                    + qname);
-          } else
-            declarePrefix (prefix, value);
-          if (!xmlNames)
-            return;
-        }
-      } else {
-        if ("xmlns".equals(qname)) {
-          declarePrefix ("", value);
-          if (!xmlNames)
-            return;
-        }
-        // NS prefix declaration?
-        else if ((index = qname.indexOf (':')) == 5
-                 && qname.startsWith ("xmlns")) {
-          String		prefix = qname.substring (6);
-          
-          if (value.length () == 0) {
-            verror ("missing URI in namespace decl attribute: "
-                    + qname);
-          } else
-            declarePrefix (prefix, value);
-          if (!xmlNames)
-            return;
-        }
+  {
+    if (!attributes)
+      {
+        attributes = true;
+        if (namespaces)
+          {
+            prefixStack.pushContext();
+          }
+      }
+    
+    // process namespace decls immediately;
+    // then maybe forget this as an attribute
+    if (namespaces)
+      {
+        int index;
+        
+        // default NS declaration?
+        if (stringInterning)
+          {
+            if ("xmlns" == qname)
+              {
+                declarePrefix("", value);
+                if (!xmlNames)
+                  {
+                    return;
+                  }
+              }
+            // NS prefix declaration?
+            else if ((index = qname.indexOf(':')) == 5
+                     && qname.startsWith("xmlns"))
+              {
+                String prefix = qname.substring(6);
+              
+                if (prefix.equals(""))
+                  {
+                    fatal("missing prefix " +
+                          "in namespace declaration attribute");  
+                  }
+                if (value.length() == 0)
+                  {
+                    verror("missing URI in namespace declaration attribute: "
+                           + qname);
+                  }
+                else
+                  {
+                    declarePrefix(prefix, value);
+                  }
+                if (!xmlNames)
+                  {
+                    return;
+                  }
+              }
+          }
+        else
+          {
+            if ("xmlns".equals(qname))
+              {
+                declarePrefix("", value);
+                if (!xmlNames)
+                  {
+                    return;
+                  }
+              }
+            // NS prefix declaration?
+            else if ((index = qname.indexOf(':')) == 5
+                     && qname.startsWith("xmlns"))
+              {
+                String prefix = qname.substring(6);
+                
+                if (value.length() == 0)
+                  {
+                    verror("missing URI in namespace decl attribute: "
+                           + qname);
+                  }
+                else
+                  {
+                    declarePrefix(prefix, value);
+                  }
+                if (!xmlNames)
+                  {
+                    return;
+                  }
+              }
+          }
       }
+    // remember this attribute ...
+    attributeCount++;
+    
+    // attribute type comes from querying parser's DTD records
+    attributesList.add(new Attribute(qname, value, isSpecified));
+    
   }
-	// remember this attribute ...
-
-	attributeCount++;
-	
-	// attribute type comes from querying parser's DTD records
-	attributesList.add(new Attribute(qname, value, isSpecified));
-
-    }
-
-    void startElement (String elname)
+  
+  void startElement(String elname)
     throws SAXException
-    {
-	ContentHandler handler = contentHandler;
-
-	//
-	// NOTE:  this implementation of namespace support adds something
-	// like six percent to parsing CPU time, in a large (~50 MB)
-	// document that doesn't use namespaces at all.  (Measured by PC
-	// sampling, with a bug where endElement processing was omitted.)
-	// [Measurement referred to older implementation, older JVM ...]
-	//
-	// It ought to become notably faster in such cases.  Most
-	// costs are the prefix stack calling Hashtable.get() (2%),
-	// String.hashCode() (1.5%) and about 1.3% each for pushing
-	// the context, and two chunks of name processing.
-	//
-
-	if (!attributes) {
-	    if (namespaces)
-		prefixStack.pushContext ();
-	} else if (namespaces) {
-
-	    // now we can patch up namespace refs; we saw all the
-	    // declarations, so now we'll do the Right Thing
-	    Iterator itt = attributesList.iterator ();
-	    while(itt.hasNext())
-	    {
-	    	Attribute attribute = (Attribute) itt.next();
-	    	String	qname = attribute.name;
-		int	index;
-
-    // default NS declaration?
-    if (getFeature (FEATURE + "string-interning")) {
-      if ("xmlns" == qname)
-		    continue;
-    } else {
-      if ("xmlns".equals(qname))
-		    continue;
-    }
-               //Illegal in the new Namespaces Draft
-               //should it be only in 1.1 docs??
-               if (qname.equals (":"))
-                   fatal ("namespace names consisting of a single colon " +
-                   		"character are invalid");
-		index = qname.indexOf (':');
-
-		// NS prefix declaration?
-		if (index == 5 && qname.startsWith ("xmlns"))
-		    continue;
-
-		// it's not a NS decl; patch namespace info items
-		if (prefixStack.processName (qname, nsTemp, true) == null)
-		    fatal ("undeclared attribute prefix in: " + qname);
-		else {
-		    attribute.nameSpace = nsTemp[0];
-		    attribute.localName = nsTemp[1];
-		}
-	    }
-	}
-
-	// save element name so attribute callbacks work
-	elementName = elname;
-	if (namespaces) {
-	    if (prefixStack.processName (elname, nsTemp, false) == null) {
-		fatal ("undeclared element prefix in: " + elname);
-		nsTemp [0] = nsTemp [1] = "";
-	    }
-	    handler.startElement (nsTemp [0], nsTemp [1], elname, this);
-	} else
-	    handler.startElement ("", "", elname, this);
-	// elementName = null;
-
-	// elements with no attributes are pretty common!
-	if (attributes) {
-	    attributesList.clear();
-	    attributeCount = 0;
-	    attributes = false;
-	}
-    }
+  {
+    ContentHandler handler = contentHandler;
 
-    void endElement (String elname)
+    //
+    // NOTE:  this implementation of namespace support adds something
+    // like six percent to parsing CPU time, in a large (~50 MB)
+    // document that doesn't use namespaces at all.  (Measured by PC
+    // sampling, with a bug where endElement processing was omitted.)
+    // [Measurement referred to older implementation, older JVM ...]
+    //
+    // It ought to become notably faster in such cases.  Most
+    // costs are the prefix stack calling Hashtable.get() (2%),
+    // String.hashCode() (1.5%) and about 1.3% each for pushing
+    // the context, and two chunks of name processing.
+    //
+    
+    if (!attributes)
+      {
+        if (namespaces)
+          {
+            prefixStack.pushContext();
+          }
+      }
+    else if (namespaces)
+      {
+      
+        // now we can patch up namespace refs; we saw all the
+        // declarations, so now we'll do the Right Thing
+        Iterator itt = attributesList.iterator();
+        while (itt.hasNext())
+          {
+            Attribute attribute = (Attribute) itt.next();
+            String qname = attribute.name;
+            int index;
+            
+            // default NS declaration?
+            if (stringInterning)
+              {
+                if ("xmlns" == qname)
+                  {
+                    continue;
+                  }
+              }
+            else
+              {
+                if ("xmlns".equals(qname))
+                  {
+                    continue;
+                  }
+              }
+            //Illegal in the new Namespaces Draft
+            //should it be only in 1.1 docs??
+            if (qname.equals (":"))
+              {
+                fatal("namespace names consisting of a single colon " +
+                      "character are invalid");
+              }
+            index = qname.indexOf(':');
+            
+            // NS prefix declaration?
+            if (index == 5 && qname.startsWith("xmlns"))
+              {
+                continue;
+              }
+            
+            // it's not a NS decl; patch namespace info items
+            if (prefixStack.processName(qname, nsTemp, true) == null)
+              {
+                fatal("undeclared attribute prefix in: " + qname);
+              }
+            else
+              {
+                attribute.nameSpace = nsTemp[0];
+                attribute.localName = nsTemp[1];
+              }
+          }
+      }
+    
+    // save element name so attribute callbacks work
+    elementName = elname;
+    if (namespaces)
+      {
+        if (prefixStack.processName(elname, nsTemp, false) == null)
+          {
+            fatal("undeclared element prefix in: " + elname);
+            nsTemp[0] = nsTemp[1] = "";
+          }
+        handler.startElement(nsTemp[0], nsTemp[1], elname, this);
+      }
+    else
+      {
+        handler.startElement("", "", elname, this);
+      }
+    // elementName = null;
+    
+    // elements with no attributes are pretty common!
+    if (attributes)
+      {
+        attributesList.clear();
+        attributeCount = 0;
+        attributes = false;
+      }
+  }
+  
+  void endElement(String elname)
     throws SAXException
-    {
-	ContentHandler	handler = contentHandler;
+  {
+    ContentHandler handler = contentHandler;
 
-	if (!namespaces) {
-	    handler.endElement ("", "", elname);
-	    return;
-	}
-	prefixStack.processName (elname, nsTemp, false);
-	handler.endElement (nsTemp [0], nsTemp [1], elname);
-
-	Enumeration	prefixes = prefixStack.getDeclaredPrefixes ();
-
-	while (prefixes.hasMoreElements ())
-	    handler.endPrefixMapping ((String) prefixes.nextElement ());
-	prefixStack.popContext ();
-    }
+    if (!namespaces)
+      {
+        handler.endElement("", "", elname);
+        return;
+      }
+    prefixStack.processName(elname, nsTemp, false);
+    handler.endElement(nsTemp[0], nsTemp[1], elname);
+    
+    Enumeration prefixes = prefixStack.getDeclaredPrefixes();
+    
+    while (prefixes.hasMoreElements())
+      {
+        handler.endPrefixMapping((String) prefixes.nextElement());
+      }
+    prefixStack.popContext();
+  }
 
-    void startCDATA ()
+  void startCDATA()
     throws SAXException
-    {
-	lexicalHandler.startCDATA ();
-    }
+  {
+    lexicalHandler.startCDATA();
+  }
 
-    void charData (char ch[], int start, int length)
+  void charData(char[] ch, int start, int length)
     throws SAXException
-    {
-	contentHandler.characters (ch, start, length);
-    }
+  {
+    contentHandler.characters(ch, start, length);
+  }
 
-    void endCDATA ()
+  void endCDATA()
     throws SAXException
-    {
-	lexicalHandler.endCDATA ();
-    }
+  {
+    lexicalHandler.endCDATA();
+  }
 
-    void ignorableWhitespace (char ch[], int start, int length)
+  void ignorableWhitespace(char[] ch, int start, int length)
     throws SAXException
-    {
-	contentHandler.ignorableWhitespace (ch, start, length);
-    }
+  {
+    contentHandler.ignorableWhitespace(ch, start, length);
+  }
 
-    void processingInstruction (String target, String data)
+  void processingInstruction(String target, String data)
     throws SAXException
-    {
-	contentHandler.processingInstruction (target, data);
-    }
+  {
+    contentHandler.processingInstruction(target, data);
+  }
 
-    void comment (char ch[], int start, int length)
+  void comment(char[] ch, int start, int length)
     throws SAXException
-    {
-	if (lexicalHandler != base)
-	    lexicalHandler.comment (ch, start, length);
-    }
+  {
+    if (lexicalHandler != base)
+      {
+        lexicalHandler.comment(ch, start, length);
+      }
+  }
 
-    void fatal (String message)
+  void fatal(String message)
     throws SAXException
-    {
-	SAXParseException fatal;
-	
-	fatal = new SAXParseException (message, this);
-	errorHandler.fatalError (fatal);
-
-	// Even if the application can continue ... we can't!
-	throw fatal;
-    }
+  {
+    SAXParseException fatal;
+  
+    fatal = new SAXParseException(message, this);
+    errorHandler.fatalError(fatal);
 
-    // We can safely report a few validity errors that
-    // make layered SAX2 DTD validation more conformant
-    void verror (String message)
-    throws SAXException
-    {
-	SAXParseException err;
-	
-	err = new SAXParseException (message, this);
-	errorHandler.error (err);
-    }
+    // Even if the application can continue ... we can't!
+    throw fatal;
+  }
 
-    void warn (String message)
+  // We can safely report a few validity errors that
+  // make layered SAX2 DTD validation more conformant
+  void verror(String message)
+    throws SAXException
+  {
+    SAXParseException err;
+    
+    err = new SAXParseException(message, this);
+    errorHandler.error(err);
+  }
+  
+  void warn(String message)
     throws SAXException
-    {
-	SAXParseException err;
-	
-	err = new SAXParseException (message, this);
-	errorHandler.warning (err);
-    }
-
+  {
+    SAXParseException err;
+  
+    err = new SAXParseException(message, this);
+    errorHandler.warning(err);
+  }
 
-    //
-    // Implementation of org.xml.sax.Attributes.
-    //
+  //
+  // Implementation of org.xml.sax.Attributes.
+  //
+
+  /**
+   * <b>SAX1 AttributeList, SAX2 Attributes</b> method
+   * (don't invoke on parser);
+   */
+  public int getLength()
+  {
+    return attributesList.size();
+  }
 
-    /**
-     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
-     * (don't invoke on parser);
-     */
-    public int getLength ()
-    {
-	return attributesList.size();
-    }
+  /**
+   * <b>SAX2 Attributes</b> method (don't invoke on parser);
+   */
+  public String getURI(int index)
+  {
+    if (index < 0 || index >= attributesList.size())
+      {
+        return null;
+      }
+    return ((Attribute) attributesList.get(index)).nameSpace;
+  }
 
-    /**
-     * <b>SAX2 Attributes</b> method (don't invoke on parser);
-     */
-    public String getURI (int index)
-    {
-        if (index < 0 || index >= attributesList.size())
-          {
-            return null;
-          }
-	return ((Attribute) attributesList.get(index)).nameSpace;
-    }
+  /**
+   * <b>SAX2 Attributes</b> method (don't invoke on parser);
+   */
+  public String getLocalName(int index)
+  {
+    if (index < 0 || index >= attributesList.size())
+      {
+        return null;
+      }
+    Attribute attr = (Attribute) attributesList.get(index);
+    // FIXME attr.localName is sometimes null, why?
+    if (namespaces && attr.localName == null)
+      {
+        // XXX fix this here for now
+        int ci = attr.name.indexOf(':');
+        attr.localName = (ci == -1) ? attr.name :
+          attr.name.substring(ci + 1);
+      }
+    return (attr.localName == null) ? "" : attr.localName;
+  }
 
-    /**
-     * <b>SAX2 Attributes</b> method (don't invoke on parser);
-     */
-    public String getLocalName (int index)
-    {
-        if (index < 0 || index >= attributesList.size())
-          {
-            return null;
-          }
-        Attribute attr = (Attribute) attributesList.get(index);
-        // FIXME attr.localName is sometimes null, why?
-        if (namespaces && attr.localName == null)
-          {
-            // XXX fix this here for now
-            int ci = attr.name.indexOf(':');
-            attr.localName = (ci == -1) ? attr.name :
-              attr.name.substring(ci + 1);
-          }
-        return (attr.localName == null) ? "" : attr.localName;
-    }
+  /**
+   * <b>SAX2 Attributes</b> method (don't invoke on parser);
+   */
+  public String getQName(int index)
+  {
+    if (index < 0 || index >= attributesList.size())
+      {
+      return null;
+      }
+    Attribute attr = (Attribute) attributesList.get(index);
+    return (attr.name == null) ? "" : attr.name;
+  }
 
-    /**
-     * <b>SAX2 Attributes</b> method (don't invoke on parser);
-     */
-    public String getQName (int index)
-    {
-        if (index < 0 || index >= attributesList.size())
-          {
-            return null;
-          }
-        Attribute attr = (Attribute) attributesList.get(index);
-    	return (attr.name == null) ? "" : attr.name;
-    }
+  /**
+   * <b>SAX1 AttributeList</b> method (don't invoke on parser);
+   */
+  public String getName(int index)
+  {
+    return getQName(index);
+  }
 
-    /**
-     * <b>SAX1 AttributeList</b> method (don't invoke on parser);
-     */
-    public String getName (int index)
-    {
-    	return getQName(index);
-    }
+  /**
+   * <b>SAX1 AttributeList, SAX2 Attributes</b> method
+   * (don't invoke on parser);
+   */
+  public String getType(int index)
+  {
+    if (index < 0 || index >= attributesList.size())
+      {
+        return null;
+      }
+    String type = parser.getAttributeType(elementName, getQName(index));
+    if (type == null)
+      {
+        return "CDATA";
+      }
+    // ... use DeclHandler.attributeDecl to see enumerations
+    if (type == "ENUMERATION")
+      {
+        return "NMTOKEN";
+      }
+    return type;
+  }
 
-    /**
-     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
-     * (don't invoke on parser);
-     */
-    public String getType (int index)
-    {
-        if (index < 0 || index >= attributesList.size())
-          {
-            return null;
-          }
-	String	type = parser.getAttributeType(elementName, getQName(index));
-	if (type == null)
-          {
-	    return "CDATA";
-          }
-	// ... use DeclHandler.attributeDecl to see enumerations
-        if (type == "ENUMERATION")
-          {
-            return "NMTOKEN";
-          }
-        return type;
-    }
+  /**
+   * <b>SAX1 AttributeList, SAX2 Attributes</b> method
+   * (don't invoke on parser);
+   */
+  public String getValue(int index)
+  {
+    if (index < 0 || index >= attributesList.size())
+      {
+        return null;
+      }
+    return ((Attribute) attributesList.get(index)).value;
+  }
 
+  /**
+   * <b>SAX2 Attributes</b> method (don't invoke on parser);
+   */
+  public int getIndex(String uri, String local)
+    {
+      int length = getLength();
+      
+      for (int i = 0; i < length; i++)
+        {
+          if (!getURI(i).equals(uri))
+            {
+              continue;
+            }
+          if (getLocalName(i).equals(local))
+            {
+              return i;
+            }
+        }
+      return -1;
+  }
 
-    /**
-     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
-     * (don't invoke on parser);
-     */
-    public String getValue (int index)
-    {
-        if (index < 0 || index >= attributesList.size())
+  /**
+   * <b>SAX2 Attributes</b> method (don't invoke on parser);
+   */
+  public int getIndex(String xmlName)
+  {
+    int length = getLength();
+    
+    for (int i = 0; i < length; i++)
+      {
+        if (getQName(i).equals(xmlName))
           {
-            return null;
+            return i;
           }
-    	return ((Attribute) attributesList.get(index)).value;
-    }
-
+      }
+    return -1;
+  }
 
-    /**
-     * <b>SAX2 Attributes</b> method (don't invoke on parser);
-     */
-    public int getIndex (String uri, String local)
-    {
-	int length = getLength();
+  /**
+   * <b>SAX2 Attributes</b> method (don't invoke on parser);
+   */
+  public String getType(String uri, String local)
+  {
+    int index = getIndex(uri, local);
+    
+    if (index < 0)
+      {
+        return null;
+      }
+    return getType(index);
+  }
 
-	for (int i = 0; i < length; i++)
-          {
-            if (!getURI(i).equals(uri))
-              {
-		continue;
-              }
-	    if (getLocalName(i).equals(local))
-              {
-		return i;
-              }
-          }
-	return -1;
-    }
+  /**
+   * <b>SAX1 AttributeList, SAX2 Attributes</b> method
+   * (don't invoke on parser);
+   */
+  public String getType(String xmlName)
+  {
+    int index = getIndex(xmlName);
+    
+    if (index < 0)
+      {
+        return null;
+      }
+    return getType(index);
+  }
 
+  /**
+   * <b>SAX Attributes</b> method (don't invoke on parser);
+   */
+  public String getValue(String uri, String local)
+  {
+    int index = getIndex(uri, local);
+    
+    if (index < 0)
+      {
+        return null;
+      }
+    return getValue(index);
+  }
 
-    /**
-     * <b>SAX2 Attributes</b> method (don't invoke on parser);
-     */
-    public int getIndex (String xmlName)
-    {
-	int length = getLength();
+  /**
+   * <b>SAX1 AttributeList, SAX2 Attributes</b> method
+   * (don't invoke on parser);
+   */
+  public String getValue(String xmlName)
+  {
+    int index = getIndex(xmlName);
+    
+    if (index < 0)
+      {
+        return null;
+      }
+    return getValue(index);
+  }
 
-	for (int i = 0; i < length; i++)
-          {
-            if (getQName(i).equals(xmlName))
-              {
-		return i;
-              }
-          }
-	return -1;
-    }
+  //
+  // Implementation of org.xml.sax.ext.Attributes2
+  //
+
+  /** @return false unless the attribute was declared in the DTD.
+   * @throws java.lang.ArrayIndexOutOfBoundsException
+   *   When the supplied index does not identify an attribute.
+   */  
+  public boolean isDeclared(int index)
+  {
+    if (index < 0 || index >= attributeCount)
+      {
+        throw new ArrayIndexOutOfBoundsException();
+      }
+    String type = parser.getAttributeType(elementName, getQName(index));
+    return (type != null);
+  }
 
+  /** @return false unless the attribute was declared in the DTD.
+   * @throws java.lang.IllegalArgumentException
+   *   When the supplied names do not identify an attribute.
+   */
+  public boolean isDeclared(String qName)
+  {
+    int index = getIndex(qName);
+    if (index < 0)
+      {
+        throw new IllegalArgumentException();
+      }
+    String type = parser.getAttributeType(elementName, qName);
+    return (type != null);
+  }
 
-    /**
-     * <b>SAX2 Attributes</b> method (don't invoke on parser);
-     */
-    public String getType (String uri, String local)
-    {
-	int index = getIndex(uri, local);
+  /** @return false unless the attribute was declared in the DTD.
+   * @throws java.lang.IllegalArgumentException
+   *   When the supplied names do not identify an attribute.
+   */
+  public boolean isDeclared(String uri, String localName)
+  {
+    int index = getIndex(uri, localName);
+    return isDeclared(index);
+  }
 
-	if (index < 0)
-          {
-	    return null;
-          }
-	return getType(index);
-    }
+  /**
+   * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
+   */
+  public boolean isSpecified(int index)
+  {
+    return ((Attribute) attributesList.get(index)).specified;
+  }
 
+  /**
+   * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
+   */
+  public boolean isSpecified(String uri, String local)
+  {
+    int index = getIndex (uri, local);
+    return isSpecified(index);
+  }
 
-    /**
-     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
-     * (don't invoke on parser);
-     */
-    public String getType (String xmlName)
-    {
-	int index = getIndex(xmlName);
+  /**
+   * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
+   */
+  public boolean isSpecified(String xmlName)
+  {
+    int index = getIndex (xmlName);
+    return isSpecified(index);
+  }
 
-	if (index < 0)
-          {
-	    return null;
-          }
-	return getType(index);
-    }
+  //
+  // Implementation of org.xml.sax.Locator.
+  //
+
+  /**
+   * <b>SAX Locator</b> method (don't invoke on parser);
+   */
+  public String getPublicId()
+  {
+    return null;   // FIXME track public IDs too
+  }
 
+  /**
+   * <b>SAX Locator</b> method (don't invoke on parser);
+   */
+  public String getSystemId()
+  {
+    if (entityStack.empty())
+      {
+        return null;
+      }
+    else
+      {
+        return (String) entityStack.peek();
+      }
+  }
 
-    /**
-     * <b>SAX Attributes</b> method (don't invoke on parser);
-     */
-    public String getValue (String uri, String local)
-    {
-	int index = getIndex(uri, local);
+  /**
+   * <b>SAX Locator</b> method (don't invoke on parser);
+   */
+  public int getLineNumber()
+  {
+    return parser.getLineNumber();
+  }
 
-	if (index < 0)
-          {
-	    return null;
-          }
-	return getValue(index);
-    }
+  /**
+   * <b>SAX Locator</b> method (don't invoke on parser);
+   */
+  public int getColumnNumber()
+  {
+    return parser.getColumnNumber();
+  }
 
+  // adapter between SAX2 content handler and SAX1 document handler callbacks
+  private static class Adapter
+    implements ContentHandler
+  {
+    
+    private DocumentHandler docHandler;
 
-    /**
-     * <b>SAX1 AttributeList, SAX2 Attributes</b> method
-     * (don't invoke on parser);
-     */
-    public String getValue (String xmlName)
+    Adapter(DocumentHandler dh)
     {
-	int index = getIndex(xmlName);
-
-	if (index < 0)
-          {
-	    return null;
-          }
-	return getValue(index);
+      docHandler = dh;
     }
 
-
-    //
-    // Implementation of org.xml.sax.ext.Attributes2
-    //
-
-
-    /** @return false unless the attribute was declared in the DTD.
-     * @throws java.lang.ArrayIndexOutOfBoundsException
-     *   When the supplied index does not identify an attribute.
-     */    
-    public boolean isDeclared (int index)
+    public void setDocumentLocator(Locator l)
     {
-	if (index < 0 || index >= attributeCount) 
-	    throw new ArrayIndexOutOfBoundsException ();
-        String type = parser.getAttributeType(elementName, getQName(index));
-        return (type != null);
+      docHandler.setDocumentLocator(l);
     }
-
-    /** @return false unless the attribute was declared in the DTD.
-     * @throws java.lang.IllegalArgumentException
-     *   When the supplied names do not identify an attribute.
-     */
-    public boolean isDeclared (String qName)
+  
+    public void startDocument()
+      throws SAXException
     {
-	int index = getIndex (qName);
-	if (index < 0)
-	    throw new IllegalArgumentException ();
-        String type = parser.getAttributeType(elementName, qName);
-        return (type != null);
+      docHandler.startDocument();
     }
-
-    /** @return false unless the attribute was declared in the DTD.
-     * @throws java.lang.IllegalArgumentException
-     *   When the supplied names do not identify an attribute.
-     */
-    public boolean isDeclared (String uri, String localName)
+  
+    public void processingInstruction(String target, String data)
+      throws SAXException
     {
-	int index = getIndex (uri, localName);
-        return isDeclared(index);
+      docHandler.processingInstruction(target, data);
     }
-
-
-    /**
-     * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
-     */
-    public boolean isSpecified (int index)
+  
+    public void startPrefixMapping(String prefix, String uri)
     {
-	return ((Attribute) attributesList.get(index)).specified;
+      /* ignored */
     }
 
-    /**
-     * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
-     */
-    public boolean isSpecified (String uri, String local)
+    public void startElement(String namespace,
+                             String local,
+                             String name,
+                             Attributes attrs)
+      throws SAXException
     {
-	int index = getIndex (uri, local);
-        return isSpecified(index);
+      docHandler.startElement(name, (AttributeList) attrs);
     }
 
-    /**
-     * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
-     */
-    public boolean isSpecified (String xmlName)
+    public void characters(char[] buf, int offset, int len)
+      throws SAXException
     {
-	int index = getIndex (xmlName);
-        return isSpecified(index);
+      docHandler.characters(buf, offset, len);
     }
 
-
-    //
-    // Implementation of org.xml.sax.Locator.
-    //
-
-    /**
-     * <b>SAX Locator</b> method (don't invoke on parser);
-     */
-    public String getPublicId ()
+    public void ignorableWhitespace(char[] buf, int offset, int len)
+      throws SAXException
     {
-	return null; 		// FIXME track public IDs too
+      docHandler.ignorableWhitespace(buf, offset, len);
     }
 
-    /**
-     * <b>SAX Locator</b> method (don't invoke on parser);
-     */
-    public String getSystemId ()
+    public void skippedEntity(String name)
     {
-	if (entityStack.empty ())
-	    return null;
-	else
-	    return (String) entityStack.peek ();
+      /* ignored */
     }
 
-    /**
-     * <b>SAX Locator</b> method (don't invoke on parser);
-     */
-    public int getLineNumber ()
+    public void endElement(String u, String l, String name)
+      throws SAXException
     {
-	return parser.getLineNumber ();
+      docHandler.endElement(name);
     }
 
-    /**
-     * <b>SAX Locator</b> method (don't invoke on parser);
-     */
-    public int getColumnNumber ()
+    public void endPrefixMapping(String prefix)
     {
-	return parser.getColumnNumber ();
+      /* ignored */
     }
 
-    // adapter between SAX2 content handler and SAX1 document handler callbacks
-    private static class Adapter implements ContentHandler
+    public void endDocument()
+      throws SAXException
     {
-	private DocumentHandler		docHandler;
-
-	Adapter (DocumentHandler dh)
-	    { docHandler = dh; }
-
-
-	public void setDocumentLocator (Locator l)
-	    { docHandler.setDocumentLocator (l); }
-	
-	public void startDocument () throws SAXException
-	    { docHandler.startDocument (); }
-	
-	public void processingInstruction (String target, String data)
-	throws SAXException
-	    { docHandler.processingInstruction (target, data); }
-	
-	public void startPrefixMapping (String prefix, String uri)
-	    { /* ignored */ }
-
-	public void startElement (
-	    String	namespace,
-	    String	local,
-	    String	name,
-	    Attributes	attrs
-	) throws SAXException
-	    { docHandler.startElement (name, (AttributeList) attrs); }
-
-	public void characters (char buf [], int offset, int len)
-	throws SAXException
-	    { docHandler.characters (buf, offset, len); }
-
-	public void ignorableWhitespace (char buf [], int offset, int len)
-	throws SAXException
-	    { docHandler.ignorableWhitespace (buf, offset, len); }
-
-	public void skippedEntity (String name)
-	    { /* ignored */ }
-
-	public void endElement (String u, String l, String name)
-	throws SAXException
-	    { docHandler.endElement (name); }
-
-	public void endPrefixMapping (String prefix)
-	    { /* ignored */ }
-
-	public void endDocument () throws SAXException
-	    { docHandler.endDocument (); }
+      docHandler.endDocument();
     }
-}
-
-class Attribute
-{
+  }
 
+  private static class Attribute
+  {
+    
     String name;
     String value;
     String nameSpace;
     String localName;
     boolean specified;
-
+    
     Attribute(String name, String value, boolean specified)
     {
-        this.name = name;
-        this.value = value;
-        this.nameSpace = "";
-        this.specified = specified;
+      this.name = name;
+      this.value = value;
+      this.nameSpace = "";
+      this.specified = specified;
     }
-}
+    
+  }
 
+}
Index: gnu/xml/aelfred2/XmlParser.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/xml/aelfred2/XmlParser.java,v
retrieving revision 1.1
diff -u -r1.1 XmlParser.java
--- gnu/xml/aelfred2/XmlParser.java 2 Feb 2005 00:42:07 -0000 1.1
+++ gnu/xml/aelfred2/XmlParser.java 29 Mar 2005 19:50:36 -0000
@@ -53,6 +53,8 @@
 
 package gnu.xml.aelfred2;
 
+import gnu.java.security.action.GetPropertyAction;
+
 import java.io.BufferedInputStream;
 import java.io.CharConversionException;
 import java.io.EOFException;
@@ -63,12 +65,11 @@
 import java.io.UnsupportedEncodingException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.security.AccessController;
 
-// maintaining 1.1 compatibility for now ...
-// Iterator and Hashmap ought to be faster
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Stack;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.LinkedList;
 
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -86,1511 +87,1838 @@
  */
 final class XmlParser
 {
-    // avoid slow per-character readCh()
-    private final static boolean USE_CHEATS = true;
 
+  // avoid slow per-character readCh()
+  private final static boolean USE_CHEATS = true;
 
-    //////////////////////////////////////////////////////////////////////
-    // Constructors.
-    ////////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////////
+  // Constants.
+  ////////////////////////////////////////////////////////////////////////
+  
+  //
+  // Constants for element content type.
+  //
+  
+  /**
+   * Constant: an element has not been declared.
+   * @see #getElementContentType
+   */
+  public final static int CONTENT_UNDECLARED = 0;
+  
+  /**
+   * Constant: the element has a content model of ANY.
+   * @see #getElementContentType
+   */
+  public final static int CONTENT_ANY = 1;
+  
+  /**
+   * Constant: the element has declared content of EMPTY.
+   * @see #getElementContentType
+   */
+  public final static int CONTENT_EMPTY = 2;
+  
+  /**
+   * Constant: the element has mixed content.
+   * @see #getElementContentType
+   */
+  public final static int CONTENT_MIXED = 3;
+  
+  /**
+   * Constant: the element has element content.
+   * @see #getElementContentType
+   */
+  public final static int CONTENT_ELEMENTS = 4;
+  
+  
+  //
+  // Constants for the entity type.
+  //
+  
+  /**
+   * Constant: the entity has not been declared.
+   * @see #getEntityType
+   */
+  public final static int ENTITY_UNDECLARED = 0;
+  
+  /**
+   * Constant: the entity is internal.
+   * @see #getEntityType
+   */
+  public final static int ENTITY_INTERNAL = 1;
+  
+  /**
+   * Constant: the entity is external, non-parsable data.
+   * @see #getEntityType
+   */
+  public final static int ENTITY_NDATA = 2;
+  
+  /**
+   * Constant: the entity is external XML data.
+   * @see #getEntityType
+   */
+  public final static int ENTITY_TEXT = 3;
+    
+  //
+  // Attribute type constants are interned literal strings.
+  //
+  
+  //
+  // Constants for supported encodings.  "external" is just a flag.
+  //
+  private final static int ENCODING_EXTERNAL = 0;
+  private final static int ENCODING_UTF_8 = 1;
+  private final static int ENCODING_ISO_8859_1 = 2;
+  private final static int ENCODING_UCS_2_12 = 3;
+  private final static int ENCODING_UCS_2_21 = 4;
+  private final static int ENCODING_UCS_4_1234 = 5;
+  private final static int ENCODING_UCS_4_4321 = 6;
+  private final static int ENCODING_UCS_4_2143 = 7;
+  private final static int ENCODING_UCS_4_3412 = 8;
+  private final static int ENCODING_ASCII = 9;
+  
+  //
+  // Constants for attribute default value.
+  //
+  
+  /**
+   * Constant: the attribute is not declared.
+   * @see #getAttributeDefaultValueType
+   */
+  public final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30;
+  
+  /**
+   * Constant: the attribute has a literal default value specified.
+   * @see #getAttributeDefaultValueType
+   * @see #getAttributeDefaultValue
+   */
+  public final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31;
+  
+  /**
+   * Constant: the attribute was declared #IMPLIED.
+   * @see #getAttributeDefaultValueType
+   */
+  public final static int ATTRIBUTE_DEFAULT_IMPLIED = 32;
+  
+  /**
+   * Constant: the attribute was declared #REQUIRED.
+   * @see #getAttributeDefaultValueType
+   */
+  public final static int ATTRIBUTE_DEFAULT_REQUIRED = 33;
+  
+  /**
+   * Constant: the attribute was declared #FIXED.
+   * @see #getAttributeDefaultValueType
+   * @see #getAttributeDefaultValue
+   */
+  public final static int ATTRIBUTE_DEFAULT_FIXED = 34;
+    
+  //
+  // Constants for input.
+  //
+  private final static int INPUT_NONE = 0;
+  private final static int INPUT_INTERNAL = 1;
+  private final static int INPUT_STREAM = 3;
+  private final static int INPUT_READER = 5;
+  
+  //
+  // Flags for reading literals.
+  //
+  // expand general entity refs (attribute values in dtd and content)
+  private final static int LIT_ENTITY_REF = 2;
+  // normalize this value (space chars) (attributes, public ids)
+  private final static int LIT_NORMALIZE = 4;
+  // literal is an attribute value 
+  private final static int LIT_ATTRIBUTE = 8;
+  // don't expand parameter entities
+  private final static int LIT_DISABLE_PE = 16;
+  // don't expand [or parse] character refs
+  private final static int LIT_DISABLE_CREF = 32;
+  // don't parse general entity refs
+  private final static int LIT_DISABLE_EREF = 64;
+  // literal is a public ID value 
+  private final static int LIT_PUBID = 256;
+    
+  //
+  // Flags affecting PE handling in DTDs (if expandPE is true).
+  // PEs expand with space padding, except inside literals.
+  //
+  private final static int CONTEXT_NORMAL = 0;
+  private final static int CONTEXT_LITERAL = 1;
+  
+  // Emit warnings for relative URIs with no base URI.
+  static boolean uriWarnings;
+  static
+  {
+    String key = "gnu.xml.aelfred2.XmlParser.uriWarnings";
+    GetPropertyAction a = new GetPropertyAction(key);
+    uriWarnings = "true".equals(AccessController.doPrivileged(a));      
+  }
+    
+  //
+  // The current XML handler interface.
+  //
+  private SAXDriver handler;
+  
+  //
+  // I/O information.
+  //
+  private Reader reader;   // current reader
+  private InputStream is;     // current input stream
+  private int line;     // current line number
+  private int column;   // current column number
+  private int sourceType;   // type of input source
+  private LinkedList inputStack;   // stack of input soruces
+  private URLConnection externalEntity; // current external entity
+  private int encoding;   // current character encoding
+  private int currentByteCount; // bytes read from current source
+  private InputSource scratch;  // temporary
+  
+  //
+  // Buffers for decoded but unparsed character input.
+  //
+  private char[] readBuffer;
+  private int readBufferPos;
+  private int readBufferLength;
+  private int readBufferOverflow;  // overflow from last data chunk.
+  
+  //
+  // Buffer for undecoded raw byte input.
+  //
+  private final static int READ_BUFFER_MAX = 16384;
+  private byte[] rawReadBuffer;
+  
+  
+  //
+  // Buffer for attribute values, char refs, DTD stuff.
+  //
+  private static int DATA_BUFFER_INITIAL = 4096;
+  private char[] dataBuffer;
+  private int dataBufferPos;
+  
+  //
+  // Buffer for parsed names.
+  //
+  private static int NAME_BUFFER_INITIAL = 1024;
+  private char[] nameBuffer;
+  private int nameBufferPos;
+  
+  //
+  // Save any standalone flag
+  //
+  private boolean docIsStandalone;
+  
+  //
+  // Hashtables for DTD information on elements, entities, and notations.
+  // Populated until we start ignoring decls (because of skipping a PE)
+  //
+  private HashMap elementInfo;
+  private HashMap entityInfo;
+  private HashMap notationInfo;
+  private boolean skippedPE;
+  
+  //
+  // Element type currently in force.
+  //
+  private String currentElement;
+  private int currentElementContent;
+  
+  //
+  // Stack of entity names, to detect recursion.
+  //
+  private LinkedList entityStack;
+  
+  //
+  // PE expansion is enabled in most chunks of the DTD, not all.
+  // When it's enabled, literals are treated differently.
+  //
+  private boolean inLiteral;
+  private boolean expandPE;
+  private boolean peIsError;
+  
+  //
+  // can't report entity expansion inside two constructs:
+  // - attribute expansions (internal entities only)
+  // - markup declarations (parameter entities only)
+  //
+  private boolean doReport;
+  
+  //
+  // Symbol table, for caching interned names.
+  //
+  // These show up wherever XML names or nmtokens are used:  naming elements,
+  // attributes, PIs, notations, entities, and enumerated attribute values.
+  //
+  // NOTE:  This hashtable doesn't grow.  The default size is intended to be
+  // rather large for most documents.  Example:  one snapshot of the DocBook
+  // XML 4.1 DTD used only about 350 such names.  As a rule, only pathological
+  // documents (ones that don't reuse names) should ever see much collision.
+  //
+  // Be sure that SYMBOL_TABLE_LENGTH always stays prime, for best hashing.
+  // "2039" keeps the hash table size at about two memory pages on typical
+  // 32 bit hardware.
+  //
+  private final static int SYMBOL_TABLE_LENGTH = 2039;
+  
+  private Object[][] symbolTable;
+  
+  //
+  // Hash table of attributes found in current start tag.
+  //
+  private String[] tagAttributes;
+  private int tagAttributePos;
+  
+  //
+  // Utility flag: have we noticed a CR while reading the last
+  // data chunk?  If so, we will have to go back and normalise
+  // CR or CR/LF line ends.
+  //
+  private boolean sawCR;
+  
+  //
+  // Utility flag: are we in CDATA?  If so, whitespace isn't ignorable.
+  // 
+  private boolean inCDATA;
+  
+  //
+  // Xml version.
+  //  
+  private static final int XML_10 = 0; 
+  private static final int XML_11 = 1; 
+  private int xmlVersion = XML_10;
+
+  //////////////////////////////////////////////////////////////////////
+  // Constructors.
+  ////////////////////////////////////////////////////////////////////////
+  
+  /**
+   * Construct a new parser with no associated handler.
+   * @see #setHandler
+   * @see #parse
+   */
+  // package private
+  XmlParser()
+  {
+  }
 
+  /**
+   * Set the handler that will receive parsing events.
+   * @param handler The handler to receive callback events.
+   * @see #parse
+   */
+  // package private
+  void setHandler(SAXDriver handler)
+  {
+    this.handler = handler;
+  }
 
-    /**
-     * Construct a new parser with no associated handler.
-     * @see #setHandler
-     * @see #parse
-     */
-    // package private
-    XmlParser ()
-    {
-    }
+  /**
+   * Parse an XML document from the character stream, byte stream, or URI
+   * that you provide (in that order of preference).  Any URI that you
+   * supply will become the base URI for resolving relative URI, and may
+   * be used to acquire a reader or byte stream.
+   *
+   * <p> Only one thread at a time may use this parser; since it is
+   * private to this package, post-parse cleanup is done by the caller,
+   * which MUST NOT REUSE the parser (just null it).
+   *
+   * @param systemId Absolute URI of the document; should never be null,
+   *	but may be so iff a reader <em>or</em> a stream is provided.
+   * @param publicId The public identifier of the document, or null.
+   * @param reader A character stream; must be null if stream isn't.
+   * @param stream A byte input stream; must be null if reader isn't.
+   * @param encoding The suggested encoding, or null if unknown.
+   * @exception java.lang.Exception Basically SAXException or IOException
+   */
+  // package private 
+  void doParse(String systemId, String publicId, Reader reader,
+               InputStream stream, String encoding)
+    throws Exception
+  {
+    if (handler == null)
+      {
+        throw new IllegalStateException("no callback handler");
+      }
 
+    initializeVariables();
 
-    /**
-     * Set the handler that will receive parsing events.
-     * @param handler The handler to receive callback events.
-     * @see #parse
-     */
-    // package private
-    void setHandler (SAXDriver handler)
-    {
-	this.handler = handler;
-    }
+    // predeclare the built-in entities here (replacement texts)
+    // we don't need to intern(), since we're guaranteed literals
+    // are always (globally) interned.
+    setInternalEntity("amp", "&#38;");
+    setInternalEntity("lt", "&#60;");
+    setInternalEntity("gt", "&#62;");
+    setInternalEntity("apos", "&#39;");
+    setInternalEntity("quot", "&#34;");
+
+    try
+      {
+        // pushURL first to ensure locator is correct in startDocument
+        // ... it might report an IO or encoding exception.
+        handler.startDocument();
+        pushURL(false, "[document]",
+                // default baseURI: null
+                new ExternalIdentifiers(publicId, systemId, null),
+                reader, stream, encoding, false);
+        
+        parseDocument();
+      }
+    catch (EOFException e)
+      {
+        //empty input
+        error("empty document, with no root element.");
+      }
+    finally
+      {
+        if (reader != null)
+          {
+            try
+              {
+                reader.close();
+              }
+            catch (IOException e)
+              {
+                /* ignore */
+              }
+          }
+        if (stream != null)
+          {
+            try
+              {
+                stream.close();
+              }
+            catch (IOException e)
+              {
+                /* ignore */
+              }
+          }
+        if (is != null)
+          {
+            try
+              {
+                is.close();
+              }
+            catch (IOException e)
+              {
+                /* ignore */
+              }
+          }
+        scratch = null;
+      }
+  }
 
+  //////////////////////////////////////////////////////////////////////
+  // Error reporting.
+  //////////////////////////////////////////////////////////////////////
+    
+  /**
+   * Report an error.
+   * @param message The error message.
+   * @param textFound The text that caused the error (or null).
+   * @see SAXDriver#error
+   * @see #line
+   */
+  private void error(String message, String textFound, String textExpected)
+    throws SAXException
+  {
+    if (textFound != null)
+      {
+        message = message + " (found \"" + textFound + "\")";
+      }
+    if (textExpected != null)
+      {
+        message = message + " (expected \"" + textExpected + "\")";
+      }
+    handler.fatal(message);
+    
+    // "can't happen"
+    throw new SAXException(message);
+  }
 
-    /**
-     * Parse an XML document from the character stream, byte stream, or URI
-     * that you provide (in that order of preference).  Any URI that you
-     * supply will become the base URI for resolving relative URI, and may
-     * be used to acquire a reader or byte stream.
-     *
-     * <p> Only one thread at a time may use this parser; since it is
-     * private to this package, post-parse cleanup is done by the caller,
-     * which MUST NOT REUSE the parser (just null it).
-     *
-     * @param systemId Absolute URI of the document; should never be null,
-     *	but may be so iff a reader <em>or</em> a stream is provided.
-     * @param publicId The public identifier of the document, or null.
-     * @param reader A character stream; must be null if stream isn't.
-     * @param stream A byte input stream; must be null if reader isn't.
-     * @param encoding The suggested encoding, or null if unknown.
-     * @exception java.lang.Exception Basically SAXException or IOException
-     */
-    // package private 
-    void doParse (
-	String		systemId,
-	String		publicId,
-	Reader		reader,
-	InputStream	stream,
-	String		encoding
-    ) throws Exception
-    {
-	if (handler == null)
-	    throw new IllegalStateException ("no callback handler");
+  /**
+   * Report a serious error.
+   * @param message The error message.
+   * @param textFound The text that caused the error (or null).
+   */
+  private void error(String message, char textFound, String textExpected)
+    throws SAXException
+  {
+    error(message, new Character(textFound).toString(), textExpected);
+  }
 
-	initializeVariables ();
+  /**
+   * Report typical case fatal errors.
+   */
+  private void error(String message)
+    throws SAXException
+  {
+    handler.fatal(message);
+  }
 
-	// predeclare the built-in entities here (replacement texts)
-	// we don't need to intern(), since we're guaranteed literals
-	// are always (globally) interned.
-	setInternalEntity ("amp", "&#38;");
-	setInternalEntity ("lt", "&#60;");
-	setInternalEntity ("gt", "&#62;");
-	setInternalEntity ("apos", "&#39;");
-	setInternalEntity ("quot", "&#34;");
-
-	try {
-	    // pushURL first to ensure locator is correct in startDocument
-	    // ... it might report an IO or encoding exception.
-	    handler.startDocument ();
-	    pushURL (false, "[document]",
-			// default baseURI: null
-		    new String [] { publicId, systemId, null},
-		    reader, stream, encoding, false);
-
-	    parseDocument ();
-	} catch (EOFException e){
-	    //empty input
-	    error("empty document, with no root element.");
-	}finally {
-	    if (reader != null)
-		try { reader.close ();
-		} catch (IOException e) { /* ignore */ }
-	    if (stream != null)
-		try { stream.close ();
-		} catch (IOException e) { /* ignore */ }
-	    if (is != null)
-		try { is.close ();
-		} catch (IOException e) { /* ignore */ }
-	    if (reader != null)
-		try {
-		    reader.close ();
-		} catch (IOException e) { /* ignore */
-		}
-	    scratch = null;
-	}
-    }
+  //////////////////////////////////////////////////////////////////////
+  // Major syntactic productions.
+  //////////////////////////////////////////////////////////////////////
 
+  /**
+   * Parse an XML document.
+   * <pre>
+   * [1] document ::= prolog element Misc*
+   * </pre>
+   * <p>This is the top-level parsing function for a single XML
+   * document.  As a minimum, a well-formed document must have
+   * a document element, and a valid document must have a prolog
+   * (one with doctype) as well.
+   */
+  private void parseDocument()
+    throws Exception
+  {
+    try
+      {                                       // added by MHK
+        boolean sawDTD = parseProlog();
+        require('<');
+        parseElement(!sawDTD);
+      }
+    catch (EOFException ee)
+      {                 // added by MHK
+        error("premature end of file", "[EOF]", null);
+      }
+    
+    try
+      {
+        parseMisc();   //skip all white, PIs, and comments
+        char c = readCh();    //if this doesn't throw an exception...
+        error("unexpected characters after document end", c, null);
+      }
+    catch (EOFException e)
+      {
+        return;
+      }
+  }
+  
+  static final char[] startDelimComment = { '<', '!', '-', '-' };
+  static final char[] endDelimComment = { '-', '-' };
 
-    ////////////////////////////////////////////////////////////////////////
-    // Constants.
-    ////////////////////////////////////////////////////////////////////////
+  /**
+   * Skip a comment.
+   * <pre>
+   * [15] Comment ::= '&lt;!--' ((Char - '-') | ('-' (Char - '-')))* "-->"
+   * </pre>
+   * <p> (The <code>&lt;!--</code> has already been read.)
+   */
+  private void parseComment()
+    throws Exception
+  {
+    char c;
+    boolean saved = expandPE;
+    
+    expandPE = false;
+    parseUntil(endDelimComment);
+    require('>');
+    expandPE = saved;
+    handler.comment(dataBuffer, 0, dataBufferPos);
+    dataBufferPos = 0;
+  }
+  
+  static final char[] startDelimPI = { '<', '?' };
+  static final char[] endDelimPI = { '?', '>' };
 
-    //
-    // Constants for element content type.
-    //
+  /**
+   * Parse a processing instruction and do a call-back.
+   * <pre>
+   * [16] PI ::= '&lt;?' PITarget
+   *    (S (Char* - (Char* '?&gt;' Char*)))?
+   *    '?&gt;'
+   * [17] PITarget ::= Name - ( ('X'|'x') ('M'|m') ('L'|l') )
+   * </pre>
+   * <p> (The <code>&lt;?</code> has already been read.)
+   */
+  private void parsePI()
+    throws SAXException, IOException
+  {
+    String name;
+    boolean saved = expandPE;
+    
+    expandPE = false;
+    name = readNmtoken(true);
+    //NE08
+    if (name.indexOf(':') >= 0)
+      {
+        error("Illegal character(':') in processing instruction name ",
+              name, null);
+      }
+    if ("xml".equalsIgnoreCase(name))
+      {
+        error("Illegal processing instruction target", name, null);
+      }
+    if (!tryRead(endDelimPI))
+      {
+        requireWhitespace();
+        parseUntil(endDelimPI);
+      }
+    expandPE = saved;
+    handler.processingInstruction(name, dataBufferToString());
+  }
+  
+  static final char[] endDelimCDATA = { ']', ']', '>' };
 
-    /**
-     * Constant: an element has not been declared.
-     * @see #getElementContentType
-     */
-    public final static int CONTENT_UNDECLARED = 0;
+  private boolean isDirtyCurrentElement;
 
-    /**
-     * Constant: the element has a content model of ANY.
-     * @see #getElementContentType
-     */
-    public final static int CONTENT_ANY = 1;
+  /**
+   * Parse a CDATA section.
+   * <pre>
+   * [18] CDSect ::= CDStart CData CDEnd
+   * [19] CDStart ::= '&lt;![CDATA['
+   * [20] CData ::= (Char* - (Char* ']]&gt;' Char*))
+   * [21] CDEnd ::= ']]&gt;'
+   * </pre>
+   * <p> (The '&lt;![CDATA[' has already been read.)
+   */
+  private void parseCDSect()
+    throws Exception
+  {
+    parseUntil(endDelimCDATA);
+    dataBufferFlush();
+  }
 
-    /**
-     * Constant: the element has declared content of EMPTY.
-     * @see #getElementContentType
-     */
-    public final static int CONTENT_EMPTY = 2;
+  /**
+   * Parse the prolog of an XML document.
+   * <pre>
+   * [22] prolog ::= XMLDecl? Misc* (Doctypedecl Misc*)?
+   * </pre>
+   * <p>We do not look for the XML declaration here, because it was
+   * handled by pushURL ().
+   * @see pushURL
+   * @return true if a DTD was read.
+   */
+  private boolean parseProlog()
+    throws Exception
+  {
+    parseMisc();
 
-    /**
-     * Constant: the element has mixed content.
-     * @see #getElementContentType
-     */
-    public final static int CONTENT_MIXED = 3;
+    if (tryRead("<!DOCTYPE"))
+      {
+        parseDoctypedecl();
+        parseMisc();
+        return true;
+      }
+    return false;
+  }
 
-    /**
-     * Constant: the element has element content.
-     * @see #getElementContentType
-     */
-    public final static int CONTENT_ELEMENTS = 4;
+  private void checkLegalVersion(String version)
+    throws SAXException
+  {
+    int len = version.length();
+    for (int i = 0; i < len; i++)
+      {
+        char c = version.charAt(i);
+        if ('0' <= c && c <= '9')
+          {
+            continue;
+          }
+        if (c == '_' || c == '.' || c == ':' || c == '-')
+          {
+            continue;
+          }
+        if ('a' <= c && c <= 'z')
+          {
+            continue;
+          }
+        if ('A' <= c && c <= 'Z')
+          {
+            continue;
+          }
+        error ("illegal character in version", version, "1.0");
+      }
+  }
 
+  /**
+   * Parse the XML declaration.
+   * <pre>
+   * [23] XMLDecl ::= '&lt;?xml' VersionInfo EncodingDecl? SDDecl? S? '?&gt;'
+   * [24] VersionInfo ::= S 'version' Eq
+   *    ("'" VersionNum "'" | '"' VersionNum '"' )
+   * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')*
+   * [32] SDDecl ::= S 'standalone' Eq
+   *    ( "'"" ('yes' | 'no') "'"" | '"' ("yes" | "no") '"' )
+   * [80] EncodingDecl ::= S 'encoding' Eq
+   *    ( "'" EncName "'" | "'" EncName "'" )
+   * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+   * </pre>
+   * <p> (The <code>&lt;?xml</code> and whitespace have already been read.)
+   * @return the encoding in the declaration, uppercased; or null
+   * @see #parseTextDecl
+   * @see #setupDecoding
+   */
+  private String parseXMLDecl(boolean ignoreEncoding)
+    throws SAXException, IOException
+  {
+    String version;
+    String encodingName = null;
+    String standalone = null;
+    int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
+    String inputEncoding = null;
+        
+    switch (this.encoding)
+      {
+      case ENCODING_EXTERNAL:
+      case ENCODING_UTF_8:
+        inputEncoding = "UTF-8";
+        break;
+      case ENCODING_ISO_8859_1:
+        inputEncoding = "ISO-8859-1";
+        break;
+      case ENCODING_UCS_2_12:
+        inputEncoding = "UTF-16BE";
+        break;
+      case ENCODING_UCS_2_21:
+        inputEncoding = "UTF-16LE";
+        break;
+      }
+    
+    // Read the version.
+    require("version");
+    parseEq();
+    checkLegalVersion(version = readLiteral(flags));
+    if (!version.equals("1.0"))
+      {
+        if (version.equals("1.1"))
+          {
+            handler.warn("expected XML version 1.0, not: " + version);
+            xmlVersion = XML_11;
+          }
+        else
+          {
+            error("illegal XML version", version, "1.0 or 1.1");
+          }
+      }
+    else
+      {
+        xmlVersion = XML_10;
+      }
+    // Try reading an encoding declaration.
+    boolean white = tryWhitespace();
+    
+    if (tryRead("encoding"))
+      {
+        if (!white)
+          {
+            error("whitespace required before 'encoding='");
+          }
+        parseEq();
+        encodingName = readLiteral(flags);
+        if (!ignoreEncoding)
+          {
+            setupDecoding(encodingName);
+          }
+      }
+    
+    // Try reading a standalone declaration
+    if (encodingName != null)
+      {
+        white = tryWhitespace();
+      }
+    if (tryRead("standalone"))
+      {
+        if (!white)
+          {
+            error("whitespace required before 'standalone='");
+          }
+        parseEq();
+        standalone = readLiteral(flags);
+        if ("yes".equals(standalone))
+          {
+            docIsStandalone = true;
+          }
+        else if (!"no".equals(standalone))
+          {
+            error("standalone flag must be 'yes' or 'no'");
+          }
+      }
 
-    //
-    // Constants for the entity type.
-    //
+    skipWhitespace();
+    require("?>");
 
-    /**
-     * Constant: the entity has not been declared.
-     * @see #getEntityType
-     */
-    public final static int ENTITY_UNDECLARED = 0;
+    if (inputEncoding == null)
+      {
+        inputEncoding = encodingName;
+      }
+    handler.xmlDecl(version, encodingName, docIsStandalone,
+                    inputEncoding);
+    
+    return encodingName;
+  }
 
-    /**
-     * Constant: the entity is internal.
-     * @see #getEntityType
-     */
-    public final static int ENTITY_INTERNAL = 1;
+  /**
+   * Parse a text declaration.
+   * <pre>
+   * [79] TextDecl ::= '&lt;?xml' VersionInfo? EncodingDecl S? '?&gt;'
+   * [80] EncodingDecl ::= S 'encoding' Eq
+   *    ( '"' EncName '"' | "'" EncName "'" )
+   * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+   * </pre>
+   * <p> (The <code>&lt;?xml</code>' and whitespace have already been read.)
+   * @return the encoding in the declaration, uppercased; or null
+   * @see #parseXMLDecl
+   * @see #setupDecoding
+   */
+  private String parseTextDecl(boolean ignoreEncoding)
+    throws SAXException, IOException
+  {
+    String encodingName = null;
+    int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF;
 
-    /**
-     * Constant: the entity is external, non-parsable data.
-     * @see #getEntityType
-     */
-    public final static int ENTITY_NDATA = 2;
+    // Read an optional version.
+    if (tryRead ("version"))
+      {
+        String version;
+        parseEq();
+        checkLegalVersion(version = readLiteral(flags));
+        
+        if (version.equals("1.1"))
+          {
+            if (xmlVersion == XML_10)
+              {
+                error("external subset has later version number.", "1.0",
+                      version);    
+              }
+            handler.warn("expected XML version 1.0, not: " + version);
+            xmlVersion = XML_11;
+          }
+        else if (!version.equals("1.0"))
+          {
+            error("illegal XML version", version, "1.0 or 1.1");
+          }
+        requireWhitespace();
+      }
+    
+    // Read the encoding.
+    require("encoding");
+    parseEq();
+    encodingName = readLiteral(flags);
+    if (!ignoreEncoding)
+      {
+        setupDecoding(encodingName);
+      }
+    skipWhitespace();
+    require("?>");
+    
+    return encodingName;
+  }
 
-    /**
-     * Constant: the entity is external XML data.
-     * @see #getEntityType
+  /**
+   * Sets up internal state so that we can decode an entity using the
+   * specified encoding.  This is used when we start to read an entity
+   * and we have been given knowledge of its encoding before we start to
+   * read any data (e.g. from a SAX input source or from a MIME type).
+   *
+   * <p> It is also used after autodetection, at which point only very
+   * limited adjustments to the encoding may be used (switching between
+   * related builtin decoders).
+   *
+   * @param encodingName The name of the encoding specified by the user.
+   * @exception IOException if the encoding isn't supported either
+   *  internally to this parser, or by the hosting JVM.
+   * @see #parseXMLDecl
+   * @see #parseTextDecl
      */
-    public final static int ENTITY_TEXT = 3;
-
-
-    //
-    // Attribute type constants are interned literal strings.
-    //
-
-    //
-    // Constants for supported encodings.  "external" is just a flag.
-    //
-    private final static int ENCODING_EXTERNAL = 0;
-    private final static int ENCODING_UTF_8 = 1;
-    private final static int ENCODING_ISO_8859_1 = 2;
-    private final static int ENCODING_UCS_2_12 = 3;
-    private final static int ENCODING_UCS_2_21 = 4;
-    private final static int ENCODING_UCS_4_1234 = 5;
-    private final static int ENCODING_UCS_4_4321 = 6;
-    private final static int ENCODING_UCS_4_2143 = 7;
-    private final static int ENCODING_UCS_4_3412 = 8;
-    private final static int ENCODING_ASCII = 9;
-
-
-    //
-    // Constants for attribute default value.
-    //
-
-    /**
-     * Constant: the attribute is not declared.
-     * @see #getAttributeDefaultValueType
-     */
-    public final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30;
-
-    /**
-     * Constant: the attribute has a literal default value specified.
-     * @see #getAttributeDefaultValueType
-     * @see #getAttributeDefaultValue
-     */
-    public final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31;
-
-    /**
-     * Constant: the attribute was declared #IMPLIED.
-     * @see #getAttributeDefaultValueType
-     */
-    public final static int ATTRIBUTE_DEFAULT_IMPLIED = 32;
-
-    /**
-     * Constant: the attribute was declared #REQUIRED.
-     * @see #getAttributeDefaultValueType
-     */
-    public final static int ATTRIBUTE_DEFAULT_REQUIRED = 33;
-
-    /**
-     * Constant: the attribute was declared #FIXED.
-     * @see #getAttributeDefaultValueType
-     * @see #getAttributeDefaultValue
-     */
-    public final static int ATTRIBUTE_DEFAULT_FIXED = 34;
-
-
-    //
-    // Constants for input.
-    //
-    private final static int INPUT_NONE = 0;
-    private final static int INPUT_INTERNAL = 1;
-    private final static int INPUT_STREAM = 3;
-    private final static int INPUT_READER = 5;
-
-
-    //
-    // Flags for reading literals.
-    //
-	// expand general entity refs (attribute values in dtd and content)
-    private final static int LIT_ENTITY_REF = 2;
-	// normalize this value (space chars) (attributes, public ids)
-    private final static int LIT_NORMALIZE = 4;
-	// literal is an attribute value 
-    private final static int LIT_ATTRIBUTE = 8;
-	// don't expand parameter entities
-    private final static int LIT_DISABLE_PE = 16;
-	// don't expand [or parse] character refs
-    private final static int LIT_DISABLE_CREF = 32;
-	// don't parse general entity refs
-    private final static int LIT_DISABLE_EREF = 64;
-	// literal is a public ID value 
-    private final static int LIT_PUBID = 256;
-
-
-    //
-    // Flags affecting PE handling in DTDs (if expandPE is true).
-    // PEs expand with space padding, except inside literals.
-    //
-    private final static int CONTEXT_NORMAL = 0;
-    private final static int CONTEXT_LITERAL = 1;
-
-
-    //////////////////////////////////////////////////////////////////////
-    // Error reporting.
-    //////////////////////////////////////////////////////////////////////
-
-
-    /**
-     * Report an error.
-     * @param message The error message.
-     * @param textFound The text that caused the error (or null).
-     * @see SAXDriver#error
-     * @see #line
-     */
-    private void error (String message, String textFound, String textExpected)
-    throws SAXException
-    {
-	if (textFound != null) {
-	    message = message + " (found \"" + textFound + "\")";
-	}
-	if (textExpected != null) {
-	    message = message + " (expected \"" + textExpected + "\")";
-	}
-	handler.fatal (message);
-
-	// "can't happen"
-	throw new SAXException (message);
-    }
-
-
-    /**
-     * Report a serious error.
-     * @param message The error message.
-     * @param textFound The text that caused the error (or null).
-     */
-    private void error (String message, char textFound, String textExpected)
-    throws SAXException
-    {
-	error (message, new Character (textFound).toString (), textExpected);
-    }
-
-    /** Report typical case fatal errors. */
-    private void error (String message)
-    throws SAXException
-    {
-	handler.fatal (message);
-    }
-
-
-    //////////////////////////////////////////////////////////////////////
-    // Major syntactic productions.
-    //////////////////////////////////////////////////////////////////////
-
-
-    /**
-     * Parse an XML document.
-     * <pre>
-     * [1] document ::= prolog element Misc*
-     * </pre>
-     * <p>This is the top-level parsing function for a single XML
-     * document.  As a minimum, a well-formed document must have
-     * a document element, and a valid document must have a prolog
-     * (one with doctype) as well.
-     */
-    private void parseDocument ()
-    throws Exception
-    {
-        try {                                       // added by MHK
-    	    boolean sawDTD = parseProlog ();
-    	    require ('<');
-    	    parseElement (!sawDTD);
-        } catch (EOFException ee) {                 // added by MHK
-            error("premature end of file", "[EOF]", null);
-        }
-        
-    	try {
-    	    parseMisc ();   //skip all white, PIs, and comments
-    	    char c = readCh ();    //if this doesn't throw an exception...
-    	    error ("unexpected characters after document end", c, null);
-    	} catch (EOFException e) {
-    	    return;
-    	}
-    }
-
-    static final char	startDelimComment [] = { '<', '!', '-', '-' };
-    static final char	endDelimComment [] = { '-', '-' };
-
-    /**
-     * Skip a comment.
-     * <pre>
-     * [15] Comment ::= '&lt;!--' ((Char - '-') | ('-' (Char - '-')))* "-->"
-     * </pre>
-     * <p> (The <code>&lt;!--</code> has already been read.)
-     */
-    private void parseComment ()
-    throws Exception
-    {
-	char c;
-	boolean saved = expandPE;
-
-	expandPE = false;
-	parseUntil (endDelimComment);
-	require ('>');
-	expandPE = saved;
-	handler.comment (dataBuffer, 0, dataBufferPos);
-	dataBufferPos = 0;
-    }
-
-    static final char	startDelimPI [] = { '<', '?' };
-    static final char	endDelimPI [] = { '?', '>' };
-
-    /**
-     * Parse a processing instruction and do a call-back.
-     * <pre>
-     * [16] PI ::= '&lt;?' PITarget
-     *		(S (Char* - (Char* '?&gt;' Char*)))?
-     *		'?&gt;'
-     * [17] PITarget ::= Name - ( ('X'|'x') ('M'|m') ('L'|l') )
-     * </pre>
-     * <p> (The <code>&lt;?</code> has already been read.)
-     */
-    private void parsePI ()
+  private void setupDecoding(String encodingName)
     throws SAXException, IOException
-    {
-	String name;
-	boolean saved = expandPE;
-
-	expandPE = false;
-	name = readNmtoken (true);
-	//NE08
-	if (name.indexOf(':') >= 0)
-           error ("Illegal character(':') in processing instruction name ", name, null);
-	if ("xml".equalsIgnoreCase (name))
-	    error ("Illegal processing instruction target", name, null);
-	if (!tryRead (endDelimPI)) {
-	    requireWhitespace ();
-	    parseUntil (endDelimPI);
-	}
-	expandPE = saved;
-	handler.processingInstruction (name, dataBufferToString ());
-    }
-
-
-    static final char	endDelimCDATA [] = { ']', ']', '>' };
-
-	private boolean isDirtyCurrentElement;
-
-    /**
-     * Parse a CDATA section.
-     * <pre>
-     * [18] CDSect ::= CDStart CData CDEnd
-     * [19] CDStart ::= '&lt;![CDATA['
-     * [20] CData ::= (Char* - (Char* ']]&gt;' Char*))
-     * [21] CDEnd ::= ']]&gt;'
-     * </pre>
-     * <p> (The '&lt;![CDATA[' has already been read.)
-     */
-    private void parseCDSect ()
+  {
+    encodingName = encodingName.toUpperCase();
+    
+    // ENCODING_EXTERNAL indicates an encoding that wasn't
+    // autodetected ... we can use builtin decoders, or
+    // ones from the JVM (InputStreamReader).
+    
+    // Otherwise we can only tweak what was autodetected, and
+    // only for single byte (ASCII derived) builtin encodings.
+    
+    // ASCII-derived encodings
+    if (encoding == ENCODING_UTF_8 || encoding == ENCODING_EXTERNAL)
+      {
+        if (encodingName.equals("ISO-8859-1")
+            || encodingName.equals("8859_1")
+            || encodingName.equals("ISO8859_1"))
+          {
+            encoding = ENCODING_ISO_8859_1;
+            return;
+          }
+        else if (encodingName.equals("US-ASCII")
+                 || encodingName.equals("ASCII"))
+          {
+            encoding = ENCODING_ASCII;
+            return;
+          }
+        else if (encodingName.equals("UTF-8")
+                 || encodingName.equals("UTF8"))
+          {
+            encoding = ENCODING_UTF_8;
+            return;
+          }
+        else if (encoding != ENCODING_EXTERNAL)
+          {
+            // used to start with a new reader ...
+            throw new UnsupportedEncodingException(encodingName);
+          }
+        // else fallthrough ...
+        // it's ASCII-ish and something other than a builtin
+      }
+    
+    // Unicode and such
+    if (encoding == ENCODING_UCS_2_12 || encoding == ENCODING_UCS_2_21)
+      {
+        if (!(encodingName.equals("ISO-10646-UCS-2")
+              || encodingName.equals("UTF-16")
+              || encodingName.equals("UTF-16BE")
+              || encodingName.equals("UTF-16LE")))
+          {
+            error("unsupported Unicode encoding", encodingName, "UTF-16");
+          }
+        return;
+      }
+    
+    // four byte encodings
+    if (encoding == ENCODING_UCS_4_1234
+        || encoding == ENCODING_UCS_4_4321
+        || encoding == ENCODING_UCS_4_2143
+        || encoding == ENCODING_UCS_4_3412)
+      {
+        // Strictly:  "UCS-4" == "UTF-32BE"; also, "UTF-32LE" exists
+        if (!encodingName.equals("ISO-10646-UCS-4"))
+          {
+            error("unsupported 32-bit encoding", encodingName,
+                  "ISO-10646-UCS-4");
+          }
+        return;
+      }
+    
+    // assert encoding == ENCODING_EXTERNAL
+    // if (encoding != ENCODING_EXTERNAL)
+    //     throw new RuntimeException ("e