1 /*
   2  * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xerces.internal.parsers;
  22 
  23 import com.sun.org.apache.xerces.internal.impl.Constants;
  24 import com.sun.org.apache.xerces.internal.util.EntityResolver2Wrapper;
  25 import com.sun.org.apache.xerces.internal.util.EntityResolverWrapper;
  26 import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
  27 import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter;
  28 import com.sun.org.apache.xerces.internal.util.Status;
  29 import com.sun.org.apache.xerces.internal.util.SymbolHash;
  30 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  31 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  32 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  33 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  34 import com.sun.org.apache.xerces.internal.xni.QName;
  35 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  36 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  37 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  38 import com.sun.org.apache.xerces.internal.xni.XMLString;
  39 import com.sun.org.apache.xerces.internal.xni.XNIException;
  40 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  41 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  42 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
  43 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  44 import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
  45 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
  46 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  47 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
  48 import com.sun.org.apache.xerces.internal.xs.PSVIProvider;
  49 import java.io.CharConversionException;
  50 import java.io.IOException;
  51 import java.util.Locale;
  52 import javax.xml.XMLConstants;
  53 import org.xml.sax.AttributeList;
  54 import org.xml.sax.ContentHandler;
  55 import org.xml.sax.DTDHandler;
  56 import org.xml.sax.DocumentHandler;
  57 import org.xml.sax.EntityResolver;
  58 import org.xml.sax.ErrorHandler;
  59 import org.xml.sax.InputSource;
  60 import org.xml.sax.Parser;
  61 import org.xml.sax.SAXException;
  62 import org.xml.sax.SAXNotRecognizedException;
  63 import org.xml.sax.SAXNotSupportedException;
  64 import org.xml.sax.SAXParseException;
  65 import org.xml.sax.XMLReader;
  66 import org.xml.sax.ext.Attributes2;
  67 import org.xml.sax.ext.DeclHandler;
  68 import org.xml.sax.ext.EntityResolver2;
  69 import org.xml.sax.ext.LexicalHandler;
  70 import org.xml.sax.ext.Locator2;
  71 import org.xml.sax.helpers.LocatorImpl;
  72 
  73 /**
  74  * This is the base class of all SAX parsers. It implements both the
  75  * SAX1 and SAX2 parser functionality, while the actual pipeline is
  76  * defined in the parser configuration.
  77  *
  78  * @author Arnaud Le Hors, IBM
  79  * @author Andy Clark, IBM
  80  *
  81  */
  82 @SuppressWarnings("deprecation")
  83 public abstract class AbstractSAXParser
  84     extends AbstractXMLDocumentParser
  85     implements PSVIProvider, // PSVI
  86               Parser, XMLReader // SAX1, SAX2
  87 {
  88 
  89     //
  90     // Constants
  91     //
  92 
  93     // features
  94 
  95     /** Feature identifier: namespaces. */
  96     protected static final String NAMESPACES =
  97         Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
  98 
  99     /** Feature identifier: namespace prefixes. */
 100     protected static final String NAMESPACE_PREFIXES =
 101         Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE;
 102 
 103     /** Feature id: string interning. */
 104     protected static final String STRING_INTERNING =
 105         Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE;
 106 
 107     /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */
 108     // this is not meant to be a recognized feature, but we need it here to use
 109     // if it is already a recognized feature for the pipeline
 110     protected static final String ALLOW_UE_AND_NOTATION_EVENTS =
 111         Constants.SAX_FEATURE_PREFIX + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE;
 112 
 113     /** Recognized features. */
 114     private static final String[] RECOGNIZED_FEATURES = {
 115         NAMESPACES,
 116         NAMESPACE_PREFIXES,
 117         STRING_INTERNING,
 118     };
 119 
 120     // properties
 121 
 122     /** Property id: lexical handler. */
 123     protected static final String LEXICAL_HANDLER =
 124         Constants.SAX_PROPERTY_PREFIX + Constants.LEXICAL_HANDLER_PROPERTY;
 125 
 126     /** Property id: declaration handler. */
 127     protected static final String DECLARATION_HANDLER =
 128         Constants.SAX_PROPERTY_PREFIX + Constants.DECLARATION_HANDLER_PROPERTY;
 129 
 130     /** Property id: DOM node. */
 131     protected static final String DOM_NODE =
 132         Constants.SAX_PROPERTY_PREFIX + Constants.DOM_NODE_PROPERTY;
 133 
 134     /** Property id: security manager. */
 135     private static final String SECURITY_MANAGER =
 136         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 137 
 138     /** Recognized properties. */
 139     private static final String[] RECOGNIZED_PROPERTIES = {
 140         LEXICAL_HANDLER,
 141         DECLARATION_HANDLER,
 142         DOM_NODE,
 143     };
 144 
 145     //
 146     // Data
 147     //
 148 
 149     // features
 150 
 151     /** Namespaces. */
 152     protected boolean fNamespaces;
 153 
 154     /** Namespace prefixes. */
 155     protected boolean fNamespacePrefixes = false;
 156 
 157     /** Lexical handler parameter entities. */
 158     protected boolean fLexicalHandlerParameterEntities = true;
 159 
 160     /** Standalone document declaration. */
 161     protected boolean fStandalone;
 162 
 163     /** Resolve DTD URIs. */
 164     protected boolean fResolveDTDURIs = true;
 165 
 166     /** Use EntityResolver2. */
 167     protected boolean fUseEntityResolver2 = true;
 168 
 169     /**
 170      * XMLNS URIs: Namespace declarations in the
 171      * http://www.w3.org/2000/xmlns/ namespace.
 172      */
 173     protected boolean fXMLNSURIs = false;
 174 
 175     // parser handlers
 176 
 177     /** Content handler. */
 178     protected ContentHandler fContentHandler;
 179 
 180     /** Document handler. */
 181     protected DocumentHandler fDocumentHandler;
 182 
 183     /** Namespace context */
 184     protected NamespaceContext fNamespaceContext;
 185 
 186     /** DTD handler. */
 187     protected org.xml.sax.DTDHandler fDTDHandler;
 188 
 189     /** Decl handler. */
 190     protected DeclHandler fDeclHandler;
 191 
 192     /** Lexical handler. */
 193     protected LexicalHandler fLexicalHandler;
 194 
 195     protected QName fQName = new QName();
 196 
 197     // state
 198 
 199     /**
 200      * True if a parse is in progress. This state is needed because
 201      * some features/properties cannot be set while parsing (e.g.
 202      * validation and namespaces).
 203      */
 204     protected boolean fParseInProgress = false;
 205 
 206     // track the version of the document being parsed
 207     protected String fVersion;
 208 
 209     // temp vars
 210     private final AttributesProxy fAttributesProxy = new AttributesProxy();
 211     private Augmentations fAugmentations = null;
 212 
 213 
 214     // temporary buffer for sending normalized values
 215     // REVISIT: what should be the size of the buffer?
 216     private static final int BUFFER_SIZE = 20;
 217     private char[] fCharBuffer =  new char[BUFFER_SIZE];
 218 
 219     // allows us to keep track of whether an attribute has
 220     // been declared twice, so that we can avoid exposing the
 221     // second declaration to any registered DeclHandler
 222     protected SymbolHash fDeclaredAttrs = null;
 223 
 224     //
 225     // Constructors
 226     //
 227 
 228     /** Default constructor. */
 229     protected AbstractSAXParser(XMLParserConfiguration config) {
 230         super(config);
 231 
 232         config.addRecognizedFeatures(RECOGNIZED_FEATURES);
 233         config.addRecognizedProperties(RECOGNIZED_PROPERTIES);
 234 
 235         try {
 236             config.setFeature(ALLOW_UE_AND_NOTATION_EVENTS, false);
 237         }
 238         catch (XMLConfigurationException e) {
 239             // it wasn't a recognized feature, so we don't worry about it
 240         }
 241     } // <init>(XMLParserConfiguration)
 242 
 243     //
 244     // XMLDocumentHandler methods
 245     //
 246 
 247     /**
 248      * The start of the document.
 249      *
 250      * @param locator The document locator, or null if the document
 251      *                 location cannot be reported during the parsing
 252      *                 of this document. However, it is <em>strongly</em>
 253      *                 recommended that a locator be supplied that can
 254      *                 at least report the system identifier of the
 255      *                 document.
 256      * @param encoding The auto-detected IANA encoding name of the entity
 257      *                 stream. This value will be null in those situations
 258      *                 where the entity encoding is not auto-detected (e.g.
 259      *                 internal entities or a document entity that is
 260      *                 parsed from a java.io.Reader).
 261      * @param namespaceContext
 262      *                 The namespace context in effect at the
 263      *                 start of this document.
 264      *                 This object represents the current context.
 265      *                 Implementors of this class are responsible
 266      *                 for copying the namespace bindings from the
 267      *                 the current context (and its parent contexts)
 268      *                 if that information is important.
 269      * @param augs     Additional information that may include infoset augmentations
 270      *
 271      * @throws XNIException Thrown by handler to signal an error.
 272      */
 273     public void startDocument(XMLLocator locator, String encoding,
 274                               NamespaceContext namespaceContext, Augmentations augs)
 275         throws XNIException {
 276 
 277         fNamespaceContext = namespaceContext;
 278 
 279         try {
 280             // SAX1
 281             if (fDocumentHandler != null) {
 282                 if (locator != null) {
 283                     fDocumentHandler.setDocumentLocator(new LocatorProxy(locator));
 284                 }
 285                 fDocumentHandler.startDocument();
 286             }
 287 
 288             // SAX2
 289             if (fContentHandler != null) {
 290                 if (locator != null) {
 291                     fContentHandler.setDocumentLocator(new LocatorProxy(locator));
 292                 }
 293                 fContentHandler.startDocument();
 294             }
 295         }
 296         catch (SAXException e) {
 297             throw new XNIException(e);
 298         }
 299 
 300     } // startDocument(locator,encoding,augs)
 301 
 302     /**
 303      * Notifies of the presence of an XMLDecl line in the document. If
 304      * present, this method will be called immediately following the
 305      * startDocument call.
 306      *
 307      * @param version    The XML version.
 308      * @param encoding   The IANA encoding name of the document, or null if
 309      *                   not specified.
 310      * @param standalone The standalone value, or null if not specified.
 311      * @param augs   Additional information that may include infoset augmentations
 312      *
 313      * @throws XNIException Thrown by handler to signal an error.
 314      */
 315     public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
 316         throws XNIException {
 317         // the version need only be set once; if
 318         // document's XML 1.0|1.1, that's how it'll stay
 319         fVersion = version;
 320         fStandalone = "yes".equals(standalone);
 321     } // xmlDecl(String,String,String)
 322 
 323     /**
 324      * Notifies of the presence of the DOCTYPE line in the document.
 325      *
 326      * @param rootElement The name of the root element.
 327      * @param publicId    The public identifier if an external DTD or null
 328      *                    if the external DTD is specified using SYSTEM.
 329      * @param systemId    The system identifier if an external DTD, null
 330      *                    otherwise.
 331      * @param augs     Additional information that may include infoset augmentations
 332      *
 333      * @throws XNIException Thrown by handler to signal an error.
 334      */
 335     public void doctypeDecl(String rootElement,
 336                             String publicId, String systemId, Augmentations augs)
 337         throws XNIException {
 338         fInDTD = true;
 339 
 340         try {
 341             // SAX2 extension
 342             if (fLexicalHandler != null) {
 343                 fLexicalHandler.startDTD(rootElement, publicId, systemId);
 344             }
 345         }
 346         catch (SAXException e) {
 347             throw new XNIException(e);
 348         }
 349 
 350         // is there a DeclHandler?
 351         if(fDeclHandler != null) {
 352             fDeclaredAttrs = new SymbolHash();
 353         }
 354 
 355     } // doctypeDecl(String,String,String)
 356 
 357         /**
 358      * This method notifies of the start of an entity. The DTD has the
 359      * pseudo-name of "[dtd]" parameter entity names start with '%'; and
 360      * general entity names are just the entity name.
 361      * <p>
 362      * <strong>Note:</strong> Since the document is an entity, the handler
 363      * will be notified of the start of the document entity by calling the
 364      * startEntity method with the entity name "[xml]" <em>before</em> calling
 365      * the startDocument method. When exposing entity boundaries through the
 366      * SAX API, the document entity is never reported, however.
 367      * <p>
 368      * <strong>Note:</strong> This method is not called for entity references
 369      * appearing as part of attribute values.
 370      *
 371      * @param name     The name of the entity.
 372      * @param identifier The resource identifier.
 373      * @param encoding The auto-detected IANA encoding name of the entity
 374      *                 stream. This value will be null in those situations
 375      *                 where the entity encoding is not auto-detected (e.g.
 376      *                 internal parameter entities).
 377      * @param augs     Additional information that may include infoset augmentations
 378      *
 379      * @throws XNIException Thrown by handler to signal an error.
 380      */
 381     public void startGeneralEntity(String name, XMLResourceIdentifier identifier,
 382                                    String encoding, Augmentations augs)
 383         throws XNIException {
 384 
 385         try {
 386             // Only report startEntity if this entity was actually read.
 387             if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
 388                 // report skipped entity to content handler
 389                 if (fContentHandler != null) {
 390                     fContentHandler.skippedEntity(name);
 391                 }
 392             }
 393             else {
 394                 // SAX2 extension
 395                 if (fLexicalHandler != null) {
 396                     fLexicalHandler.startEntity(name);
 397                 }
 398             }
 399         }
 400         catch (SAXException e) {
 401             throw new XNIException(e);
 402         }
 403 
 404     } // startGeneralEntity(String,String,String,String,String)
 405 
 406     /**
 407      * This method notifies the end of an entity. The DTD has the pseudo-name
 408      * of "[dtd]" parameter entity names start with '%'; and general entity
 409      * names are just the entity name.
 410      * <p>
 411      * <strong>Note:</strong> Since the document is an entity, the handler
 412      * will be notified of the end of the document entity by calling the
 413      * endEntity method with the entity name "[xml]" <em>after</em> calling
 414      * the endDocument method. When exposing entity boundaries through the
 415      * SAX API, the document entity is never reported, however.
 416      * <p>
 417      * <strong>Note:</strong> This method is not called for entity references
 418      * appearing as part of attribute values.
 419      *
 420      * @param name The name of the entity.
 421      * @param augs     Additional information that may include infoset augmentations
 422      *
 423      * @throws XNIException Thrown by handler to signal an error.
 424      */
 425     public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
 426 
 427         try {
 428             // Only report endEntity if this entity was actually read.
 429             if (augs == null || !Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
 430                 // SAX2 extension
 431                 if (fLexicalHandler != null) {
 432                     fLexicalHandler.endEntity(name);
 433                 }
 434             }
 435         }
 436         catch (SAXException e) {
 437             throw new XNIException(e);
 438         }
 439 
 440     } // endEntity(String)
 441 
 442      /**
 443      * The start of an element. If the document specifies the start element
 444      * by using an empty tag, then the startElement method will immediately
 445      * be followed by the endElement method, with no intervening methods.
 446      *
 447      * @param element    The name of the element.
 448      * @param attributes The element attributes.
 449      * @param augs     Additional information that may include infoset augmentations
 450      *
 451      * @throws XNIException Thrown by handler to signal an error.
 452      */
 453     public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
 454         throws XNIException {
 455 
 456         try {
 457             // SAX1
 458             if (fDocumentHandler != null) {
 459                 // REVISIT: should we support schema-normalized-value for SAX1 events
 460                 //
 461                 fAttributesProxy.setAttributes(attributes);
 462                 fDocumentHandler.startElement(element.rawname, fAttributesProxy);
 463             }
 464 
 465             // SAX2
 466             if (fContentHandler != null) {
 467 
 468                 if (fNamespaces) {
 469                     // send prefix mapping events
 470                     startNamespaceMapping();
 471 
 472                     // REVISIT: It should not be necessary to iterate over the attribute
 473                     // list when the set of [namespace attributes] is empty for this
 474                     // element. This should be computable from the NamespaceContext, but
 475                     // since we currently don't report the mappings for the xml prefix
 476                     // we cannot use the declared prefix count for the current context
 477                     // to skip this section. -- mrglavas
 478                     int len = attributes.getLength();
 479                     if (!fNamespacePrefixes) {
 480                         for (int i = len - 1; i >= 0; --i) {
 481                             attributes.getName(i, fQName);
 482                             if ((fQName.prefix == XMLSymbols.PREFIX_XMLNS) ||
 483                                (fQName.rawname == XMLSymbols.PREFIX_XMLNS)) {
 484                                 // remove namespace declaration attributes
 485                                 attributes.removeAttributeAt(i);
 486                             }
 487                         }
 488                     }
 489                     else if (!fXMLNSURIs) {
 490                         for (int i = len - 1; i >= 0; --i) {
 491                             attributes.getName(i, fQName);
 492                             if ((fQName.prefix == XMLSymbols.PREFIX_XMLNS) ||
 493                                (fQName.rawname == XMLSymbols.PREFIX_XMLNS)) {
 494                                 // localpart should be empty string as per SAX documentation:
 495                                 // http://www.saxproject.org/?selected=namespaces
 496                                 fQName.prefix = "";
 497                                 fQName.uri = "";
 498                                 fQName.localpart = "";
 499                                 attributes.setName(i, fQName);
 500                             }
 501                         }
 502                     }
 503                 }
 504 
 505                 fAugmentations = augs;
 506 
 507                 String uri = element.uri != null ? element.uri : "";
 508                 String localpart = fNamespaces ? element.localpart : "";
 509                 fAttributesProxy.setAttributes(attributes);
 510                 fContentHandler.startElement(uri, localpart, element.rawname,
 511                                              fAttributesProxy);
 512             }
 513         }
 514         catch (SAXException e) {
 515             throw new XNIException(e);
 516         }
 517 
 518     } // startElement(QName,XMLAttributes)
 519 
 520     /**
 521      * Character content.
 522      *
 523      * @param text The content.
 524      * @param augs     Additional information that may include infoset augmentations
 525      *
 526      * @throws XNIException Thrown by handler to signal an error.
 527      */
 528     public void characters(XMLString text, Augmentations augs) throws XNIException {
 529 
 530         // if type is union (XML Schema) it is possible that we receive
 531         // character call with empty data
 532         if (text.length == 0) {
 533             return;
 534         }
 535 
 536 
 537         try {
 538             // SAX1
 539             if (fDocumentHandler != null) {
 540                 // REVISIT: should we support schema-normalized-value for SAX1 events
 541                 //
 542                 fDocumentHandler.characters(text.ch, text.offset, text.length);
 543             }
 544 
 545             // SAX2
 546             if (fContentHandler != null) {
 547                 fContentHandler.characters(text.ch, text.offset, text.length);
 548             }
 549         }
 550         catch (SAXException e) {
 551             throw new XNIException(e);
 552         }
 553 
 554     } // characters(XMLString)
 555 
 556     /**
 557      * Ignorable whitespace. For this method to be called, the document
 558      * source must have some way of determining that the text containing
 559      * only whitespace characters should be considered ignorable. For
 560      * example, the validator can determine if a length of whitespace
 561      * characters in the document are ignorable based on the element
 562      * content model.
 563      *
 564      * @param text The ignorable whitespace.
 565      * @param augs     Additional information that may include infoset augmentations
 566      *
 567      * @throws XNIException Thrown by handler to signal an error.
 568      */
 569     public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
 570 
 571         try {
 572             // SAX1
 573             if (fDocumentHandler != null) {
 574                 fDocumentHandler.ignorableWhitespace(text.ch, text.offset, text.length);
 575             }
 576 
 577             // SAX2
 578             if (fContentHandler != null) {
 579                 fContentHandler.ignorableWhitespace(text.ch, text.offset, text.length);
 580             }
 581         }
 582         catch (SAXException e) {
 583             throw new XNIException(e);
 584         }
 585 
 586     } // ignorableWhitespace(XMLString)
 587 
 588     /**
 589      * The end of an element.
 590      *
 591      * @param element The name of the element.
 592      * @param augs     Additional information that may include infoset augmentations
 593      *
 594      * @throws XNIException Thrown by handler to signal an error.
 595      */
 596     public void endElement(QName element, Augmentations augs) throws XNIException {
 597 
 598 
 599         try {
 600             // SAX1
 601             if (fDocumentHandler != null) {
 602                 fDocumentHandler.endElement(element.rawname);
 603             }
 604 
 605             // SAX2
 606             if (fContentHandler != null) {
 607                 fAugmentations = augs;
 608                 String uri = element.uri != null ? element.uri : "";
 609                 String localpart = fNamespaces ? element.localpart : "";
 610                 fContentHandler.endElement(uri, localpart,
 611                                            element.rawname);
 612                 if (fNamespaces) {
 613                     endNamespaceMapping();
 614                 }
 615             }
 616         }
 617         catch (SAXException e) {
 618             throw new XNIException(e);
 619         }
 620 
 621     } // endElement(QName)
 622 
 623         /**
 624      * The start of a CDATA section.
 625      * @param augs     Additional information that may include infoset augmentations
 626      *
 627      * @throws XNIException Thrown by handler to signal an error.
 628      */
 629     public void startCDATA(Augmentations augs) throws XNIException {
 630 
 631         try {
 632             // SAX2 extension
 633             if (fLexicalHandler != null) {
 634                 fLexicalHandler.startCDATA();
 635             }
 636         }
 637         catch (SAXException e) {
 638             throw new XNIException(e);
 639         }
 640 
 641     } // startCDATA()
 642 
 643     /**
 644      * The end of a CDATA section.
 645      * @param augs     Additional information that may include infoset augmentations
 646      *
 647      * @throws XNIException Thrown by handler to signal an error.
 648      */
 649     public void endCDATA(Augmentations augs) throws XNIException {
 650 
 651         try {
 652             // SAX2 extension
 653             if (fLexicalHandler != null) {
 654                 fLexicalHandler.endCDATA();
 655             }
 656         }
 657         catch (SAXException e) {
 658             throw new XNIException(e);
 659         }
 660 
 661     } // endCDATA()
 662 
 663     /**
 664      * A comment.
 665      *
 666      * @param text The text in the comment.
 667      * @param augs     Additional information that may include infoset augmentations
 668      *
 669      * @throws XNIException Thrown by application to signal an error.
 670      */
 671     public void comment(XMLString text, Augmentations augs) throws XNIException {
 672 
 673         try {
 674             // SAX2 extension
 675             if (fLexicalHandler != null) {
 676                 fLexicalHandler.comment(text.ch, 0, text.length);
 677             }
 678         }
 679         catch (SAXException e) {
 680             throw new XNIException(e);
 681         }
 682 
 683     } // comment(XMLString)
 684 
 685     /**
 686      * A processing instruction. Processing instructions consist of a
 687      * target name and, optionally, text data. The data is only meaningful
 688      * to the application.
 689      * <p>
 690      * Typically, a processing instruction's data will contain a series
 691      * of pseudo-attributes. These pseudo-attributes follow the form of
 692      * element attributes but are <strong>not</strong> parsed or presented
 693      * to the application as anything other than text. The application is
 694      * responsible for parsing the data.
 695      *
 696      * @param target The target.
 697      * @param data   The data or null if none specified.
 698      * @param augs     Additional information that may include infoset augmentations
 699      *
 700      * @throws XNIException Thrown by handler to signal an error.
 701      */
 702     public void processingInstruction(String target, XMLString data, Augmentations augs)
 703         throws XNIException {
 704 
 705         //
 706         // REVISIT - I keep running into SAX apps that expect
 707         //   null data to be an empty string, which is contrary
 708         //   to the comment for this method in the SAX API.
 709         //
 710 
 711         try {
 712             // SAX1
 713             if (fDocumentHandler != null) {
 714                 fDocumentHandler.processingInstruction(target,
 715                                                        data.toString());
 716             }
 717 
 718             // SAX2
 719             if (fContentHandler != null) {
 720                 fContentHandler.processingInstruction(target, data.toString());
 721             }
 722         }
 723         catch (SAXException e) {
 724             throw new XNIException(e);
 725         }
 726 
 727     } // processingInstruction(String,XMLString)
 728 
 729 
 730     /**
 731      * The end of the document.
 732      * @param augs     Additional information that may include infoset augmentations
 733      *
 734      * @throws XNIException Thrown by handler to signal an error.
 735      */
 736     public void endDocument(Augmentations augs) throws XNIException {
 737 
 738         try {
 739             // SAX1
 740             if (fDocumentHandler != null) {
 741                 fDocumentHandler.endDocument();
 742             }
 743 
 744             // SAX2
 745             if (fContentHandler != null) {
 746                 fContentHandler.endDocument();
 747             }
 748         }
 749         catch (SAXException e) {
 750             throw new XNIException(e);
 751         }
 752 
 753     } // endDocument()
 754 
 755     //
 756     // XMLDTDHandler methods
 757     //
 758 
 759     /**
 760      * The start of the DTD external subset.
 761      *
 762      * @param augs Additional information that may include infoset
 763      *                      augmentations.
 764      *
 765      * @throws XNIException Thrown by handler to signal an error.
 766      */
 767     public void startExternalSubset(XMLResourceIdentifier identifier,
 768                                     Augmentations augs) throws XNIException {
 769         startParameterEntity("[dtd]", null, null, augs);
 770     }
 771 
 772     /**
 773      * The end of the DTD external subset.
 774      *
 775      * @param augs Additional information that may include infoset
 776      *                      augmentations.
 777      *
 778      * @throws XNIException Thrown by handler to signal an error.
 779      */
 780     public void endExternalSubset(Augmentations augs) throws XNIException {
 781         endParameterEntity("[dtd]", augs);
 782     }
 783 
 784     /**
 785      * This method notifies of the start of parameter entity. The DTD has the
 786      * pseudo-name of "[dtd]" parameter entity names start with '%'; and
 787      * general entity names are just the entity name.
 788      * <p>
 789      * <strong>Note:</strong> Since the document is an entity, the handler
 790      * will be notified of the start of the document entity by calling the
 791      * startEntity method with the entity name "[xml]" <em>before</em> calling
 792      * the startDocument method. When exposing entity boundaries through the
 793      * SAX API, the document entity is never reported, however.
 794      * <p>
 795      * <strong>Note:</strong> This method is not called for entity references
 796      * appearing as part of attribute values.
 797      *
 798      * @param name     The name of the parameter entity.
 799      * @param identifier The resource identifier.
 800      * @param encoding The auto-detected IANA encoding name of the entity
 801      *                 stream. This value will be null in those situations
 802      *                 where the entity encoding is not auto-detected (e.g.
 803      *                 internal parameter entities).
 804      * @param augs Additional information that may include infoset
 805      *                      augmentations.
 806      *
 807      * @throws XNIException Thrown by handler to signal an error.
 808      */
 809     public void startParameterEntity(String name,
 810                                      XMLResourceIdentifier identifier,
 811                                      String encoding, Augmentations augs)
 812         throws XNIException {
 813 
 814         try {
 815             // Only report startEntity if this entity was actually read.
 816             if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
 817                 // report skipped entity to content handler
 818                 if (fContentHandler != null) {
 819                     fContentHandler.skippedEntity(name);
 820                 }
 821             }
 822             else {
 823                 // SAX2 extension
 824                 if (fLexicalHandler != null && fLexicalHandlerParameterEntities) {
 825                     fLexicalHandler.startEntity(name);
 826                 }
 827             }
 828         }
 829         catch (SAXException e) {
 830             throw new XNIException(e);
 831         }
 832 
 833     } // startParameterEntity(String,identifier,String,Augmentation)
 834 
 835     /**
 836      * This method notifies the end of an entity. The DTD has the pseudo-name
 837      * of "[dtd]" parameter entity names start with '%'; and general entity
 838      * names are just the entity name.
 839      * <p>
 840      * <strong>Note:</strong> Since the document is an entity, the handler
 841      * will be notified of the end of the document entity by calling the
 842      * endEntity method with the entity name "[xml]" <em>after</em> calling
 843      * the endDocument method. When exposing entity boundaries through the
 844      * SAX API, the document entity is never reported, however.
 845      * <p>
 846      * <strong>Note:</strong> This method is not called for entity references
 847      * appearing as part of attribute values.
 848      *
 849      * @param name The name of the parameter entity.
 850      * @param augs Additional information that may include infoset
 851      *                      augmentations.
 852      *
 853      * @throws XNIException Thrown by handler to signal an error.
 854      */
 855     public void endParameterEntity(String name, Augmentations augs) throws XNIException {
 856 
 857         try {
 858             // Only report endEntity if this entity was actually read.
 859             if (augs == null || !Boolean.TRUE.equals(augs.getItem(Constants.ENTITY_SKIPPED))) {
 860                 // SAX2 extension
 861                 if (fLexicalHandler != null && fLexicalHandlerParameterEntities) {
 862                     fLexicalHandler.endEntity(name);
 863                 }
 864             }
 865         }
 866         catch (SAXException e) {
 867             throw new XNIException(e);
 868         }
 869 
 870     } // endEntity(String)
 871 
 872     /**
 873      * An element declaration.
 874      *
 875      * @param name         The name of the element.
 876      * @param contentModel The element content model.
 877      *
 878      * @param augs Additional information that may include infoset
 879      *                      augmentations.
 880      *
 881      * @throws XNIException Thrown by handler to signal an error.
 882      */
 883     public void elementDecl(String name, String contentModel, Augmentations augs)
 884         throws XNIException {
 885 
 886         try {
 887             // SAX2 extension
 888             if (fDeclHandler != null) {
 889                 fDeclHandler.elementDecl(name, contentModel);
 890             }
 891         }
 892         catch (SAXException e) {
 893             throw new XNIException(e);
 894         }
 895 
 896     } // elementDecl(String,String, Augmentations)
 897 
 898     /**
 899      * An attribute declaration.
 900      *
 901      * @param elementName   The name of the element that this attribute
 902      *                      is associated with.
 903      * @param attributeName The name of the attribute.
 904      * @param type          The attribute type. This value will be one of
 905      *                      the following: "CDATA", "ENTITY", "ENTITIES",
 906      *                      "ENUMERATION", "ID", "IDREF", "IDREFS",
 907      *                      "NMTOKEN", "NMTOKENS", or "NOTATION".
 908      * @param enumeration   If the type has the value "ENUMERATION" or
 909      *                      "NOTATION", this array holds the allowed attribute
 910      *                      values; otherwise, this array is null.
 911      * @param defaultType   The attribute default type. This value will be
 912      *                      one of the following: "#FIXED", "#IMPLIED",
 913      *                      "#REQUIRED", or null.
 914      * @param defaultValue  The attribute default value, or null if no
 915      *                      default value is specified.
 916      *
 917      * @param nonNormalizedDefaultValue  The attribute default value with no normalization
 918      *                      performed, or null if no default value is specified.
 919      * @param augs Additional information that may include infoset
 920      *                      augmentations.
 921      *
 922      * @throws XNIException Thrown by handler to signal an error.
 923      */
 924     public void attributeDecl(String elementName, String attributeName,
 925                               String type, String[] enumeration,
 926                               String defaultType, XMLString defaultValue,
 927                               XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException {
 928 
 929         try {
 930             // SAX2 extension
 931             if (fDeclHandler != null) {
 932                 // used as a key to detect duplicate attribute definitions.
 933                 String elemAttr = new StringBuffer(elementName).append("<").append(attributeName).toString();
 934                 if(fDeclaredAttrs.get(elemAttr) != null) {
 935                     // we aren't permitted to return duplicate attribute definitions
 936                     return;
 937                 }
 938                 fDeclaredAttrs.put(elemAttr, Boolean.TRUE);
 939                 if (type.equals("NOTATION") ||
 940                     type.equals("ENUMERATION")) {
 941 
 942                     StringBuffer str = new StringBuffer();
 943                     if (type.equals("NOTATION")) {
 944                       str.append(type);
 945                       str.append(" (");
 946                     }
 947                     else {
 948                       str.append("(");
 949                     }
 950                     for (int i = 0; i < enumeration.length; i++) {
 951                         str.append(enumeration[i]);
 952                         if (i < enumeration.length - 1) {
 953                             str.append('|');
 954                         }
 955                     }
 956                     str.append(')');
 957                     type = str.toString();
 958                 }
 959                 String value = (defaultValue==null) ? null : defaultValue.toString();
 960                 fDeclHandler.attributeDecl(elementName, attributeName,
 961                                            type, defaultType, value);
 962             }
 963         }
 964         catch (SAXException e) {
 965             throw new XNIException(e);
 966         }
 967 
 968     } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations)
 969 
 970     /**
 971      * An internal entity declaration.
 972      *
 973      * @param name The name of the entity. Parameter entity names start with
 974      *             '%', whereas the name of a general entity is just the
 975      *             entity name.
 976      * @param text The value of the entity.
 977      * @param nonNormalizedText The non-normalized value of the entity. This
 978      *             value contains the same sequence of characters that was in
 979      *             the internal entity declaration, without any entity
 980      *             references expanded.
 981      *
 982      * @param augs Additional information that may include infoset
 983      *                      augmentations.
 984      *
 985      * @throws XNIException Thrown by handler to signal an error.
 986      */
 987     public void internalEntityDecl(String name, XMLString text,
 988                                    XMLString nonNormalizedText,
 989                                    Augmentations augs) throws XNIException {
 990 
 991         try {
 992             // SAX2 extensions
 993             if (fDeclHandler != null) {
 994                 fDeclHandler.internalEntityDecl(name, text.toString());
 995             }
 996         }
 997         catch (SAXException e) {
 998             throw new XNIException(e);
 999         }
1000 
1001     } // internalEntityDecl(String,XMLString,XMLString)
1002 
1003     /**
1004      * An external entity declaration.
1005      *
1006      * @param name     The name of the entity. Parameter entity names start
1007      *                 with '%', whereas the name of a general entity is just
1008      *                 the entity name.
1009      * @param identifier    An object containing all location information
1010      *                      pertinent to this entity.
1011      * @param augs Additional information that may include infoset
1012      *                      augmentations.
1013      *
1014      * @throws XNIException Thrown by handler to signal an error.
1015      */
1016     public void externalEntityDecl(String name, XMLResourceIdentifier identifier,
1017                                    Augmentations augs) throws XNIException {
1018         try {
1019             // SAX2 extension
1020             if (fDeclHandler != null) {
1021                 String publicId = identifier.getPublicId();
1022                 String systemId = fResolveDTDURIs ?
1023                     identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
1024                 fDeclHandler.externalEntityDecl(name, publicId, systemId);
1025             }
1026         }
1027         catch (SAXException e) {
1028             throw new XNIException(e);
1029         }
1030 
1031     } // externalEntityDecl(String,,XMLResourceIdentifier, Augmentations)
1032 
1033     /**
1034      * An unparsed entity declaration.
1035      *
1036      * @param name     The name of the entity.
1037      * @param identifier    An object containing all location information
1038      *                      pertinent to this entity.
1039      * @param notation The name of the notation.
1040      *
1041      * @param augs Additional information that may include infoset
1042      *                      augmentations.
1043      *
1044      * @throws XNIException Thrown by handler to signal an error.
1045      */
1046     public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier,
1047                                    String notation,
1048                                    Augmentations augs) throws XNIException {
1049         try {
1050             // SAX2 extension
1051             if (fDTDHandler != null) {
1052                 String publicId = identifier.getPublicId();
1053                 String systemId = fResolveDTDURIs ?
1054                     identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
1055                 fDTDHandler.unparsedEntityDecl(name, publicId, systemId, notation);
1056             }
1057         }
1058         catch (SAXException e) {
1059             throw new XNIException(e);
1060         }
1061 
1062     } // unparsedEntityDecl(String,XMLResourceIdentifier, String, Augmentations)
1063 
1064     /**
1065      * A notation declaration
1066      *
1067      * @param name     The name of the notation.
1068      * @param identifier    An object containing all location information
1069      *                      pertinent to this notation.
1070      * @param augs Additional information that may include infoset
1071      *                      augmentations.
1072      *
1073      * @throws XNIException Thrown by handler to signal an error.
1074      */
1075     public void notationDecl(String name, XMLResourceIdentifier identifier,
1076                              Augmentations augs) throws XNIException {
1077         try {
1078             // SAX1 and SAX2
1079             if (fDTDHandler != null) {
1080                 String publicId = identifier.getPublicId();
1081                 String systemId = fResolveDTDURIs ?
1082                     identifier.getExpandedSystemId() : identifier.getLiteralSystemId();
1083                 fDTDHandler.notationDecl(name, publicId, systemId);
1084             }
1085         }
1086         catch (SAXException e) {
1087             throw new XNIException(e);
1088         }
1089 
1090     } // notationDecl(String,XMLResourceIdentifier, Augmentations)
1091 
1092     /**
1093      * The end of the DTD.
1094      *
1095      * @param augs Additional information that may include infoset
1096      *                      augmentations.
1097      *
1098      * @throws XNIException Thrown by handler to signal an error.
1099      */
1100     public void endDTD(Augmentations augs) throws XNIException {
1101         fInDTD = false;
1102 
1103         try {
1104             // SAX2 extension
1105             if (fLexicalHandler != null) {
1106                 fLexicalHandler.endDTD();
1107             }
1108         }
1109         catch (SAXException e) {
1110             throw new XNIException(e);
1111         }
1112         if(fDeclaredAttrs != null) {
1113             // help out the GC
1114             fDeclaredAttrs.clear();
1115         }
1116 
1117     } // endDTD()
1118 
1119     //
1120     // Parser and XMLReader methods
1121     //
1122 
1123     /**
1124      * Parses the input source specified by the given system identifier.
1125      * <p>
1126      * This method is equivalent to the following:
1127      * <pre>
1128      *     parse(new InputSource(systemId));
1129      * </pre>
1130      *
1131      * @param systemId The system identifier (URI).
1132      *
1133      * @exception org.xml.sax.SAXException Throws exception on SAX error.
1134      * @exception java.io.IOException Throws exception on i/o error.
1135      */
1136     public void parse(String systemId) throws SAXException, IOException {
1137 
1138         // parse document
1139         XMLInputSource source = new XMLInputSource(null, systemId, null, false);
1140         try {
1141             parse(source);
1142         }
1143 
1144         // wrap XNI exceptions as SAX exceptions
1145         catch (XMLParseException e) {
1146             Exception ex = e.getException();
1147             if (ex == null || ex instanceof CharConversionException) {
1148                 // must be a parser exception; mine it for locator info and throw
1149                 // a SAXParseException
1150                 LocatorImpl locatorImpl = new LocatorImpl(){
1151                     public String getXMLVersion() {
1152                         return fVersion;
1153                     }
1154                     // since XMLParseExceptions know nothing about encoding,
1155                     // we cannot return anything meaningful in this context.
1156                     // We *could* consult the LocatorProxy, but the
1157                     // application can do this itself if it wishes to possibly
1158                     // be mislead.
1159                     public String getEncoding() {
1160                         return null;
1161                     }
1162                 };
1163                 locatorImpl.setPublicId(e.getPublicId());
1164                 locatorImpl.setSystemId(e.getExpandedSystemId());
1165                 locatorImpl.setLineNumber(e.getLineNumber());
1166                 locatorImpl.setColumnNumber(e.getColumnNumber());
1167                 throw (ex == null) ?
1168                         new SAXParseException(e.getMessage(), locatorImpl) :
1169                         new SAXParseException(e.getMessage(), locatorImpl, ex);
1170             }
1171             if (ex instanceof SAXException) {
1172                 // why did we create an XMLParseException?
1173                 throw (SAXException)ex;
1174             }
1175             if (ex instanceof IOException) {
1176                 throw (IOException)ex;
1177             }
1178             throw new SAXException(ex);
1179         }
1180         catch (XNIException e) {
1181             Exception ex = e.getException();
1182             if (ex == null) {
1183                 throw new SAXException(e.getMessage());
1184             }
1185             if (ex instanceof SAXException) {
1186                 throw (SAXException)ex;
1187             }
1188             if (ex instanceof IOException) {
1189                 throw (IOException)ex;
1190             }
1191             throw new SAXException(ex);
1192         }
1193 
1194     } // parse(String)
1195 
1196     /**
1197      * parse
1198      *
1199      * @param inputSource
1200      *
1201      * @exception org.xml.sax.SAXException
1202      * @exception java.io.IOException
1203      */
1204     public void parse(InputSource inputSource)
1205         throws SAXException, IOException {
1206 
1207         // parse document
1208         try {
1209             XMLInputSource xmlInputSource =
1210                 new XMLInputSource(inputSource.getPublicId(),
1211                                    inputSource.getSystemId(),
1212                                    null, false);
1213             xmlInputSource.setByteStream(inputSource.getByteStream());
1214             xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
1215             xmlInputSource.setEncoding(inputSource.getEncoding());
1216             parse(xmlInputSource);
1217         }
1218 
1219         // wrap XNI exceptions as SAX exceptions
1220         catch (XMLParseException e) {
1221             Exception ex = e.getException();
1222             if (ex == null || ex instanceof CharConversionException) {
1223                 // must be a parser exception; mine it for locator info and throw
1224                 // a SAXParseException
1225                 LocatorImpl locatorImpl = new LocatorImpl() {
1226                     public String getXMLVersion() {
1227                         return fVersion;
1228                     }
1229                     // since XMLParseExceptions know nothing about encoding,
1230                     // we cannot return anything meaningful in this context.
1231                     // We *could* consult the LocatorProxy, but the
1232                     // application can do this itself if it wishes to possibly
1233                     // be mislead.
1234                     public String getEncoding() {
1235                         return null;
1236                     }
1237                 };
1238                 locatorImpl.setPublicId(e.getPublicId());
1239                 locatorImpl.setSystemId(e.getExpandedSystemId());
1240                 locatorImpl.setLineNumber(e.getLineNumber());
1241                 locatorImpl.setColumnNumber(e.getColumnNumber());
1242                 throw (ex == null) ?
1243                         new SAXParseException(e.getMessage(), locatorImpl) :
1244                         new SAXParseException(e.getMessage(), locatorImpl, ex);
1245             }
1246             if (ex instanceof SAXException) {
1247                 // why did we create an XMLParseException?
1248                 throw (SAXException)ex;
1249             }
1250             if (ex instanceof IOException) {
1251                 throw (IOException)ex;
1252             }
1253             throw new SAXException(ex);
1254         }
1255         catch (XNIException e) {
1256             Exception ex = e.getException();
1257             if (ex == null) {
1258                 throw new SAXException(e.getMessage());
1259             }
1260             if (ex instanceof SAXException) {
1261                 throw (SAXException)ex;
1262             }
1263             if (ex instanceof IOException) {
1264                 throw (IOException)ex;
1265             }
1266             throw new SAXException(ex);
1267         }
1268 
1269     } // parse(InputSource)
1270 
1271     /**
1272      * Sets the resolver used to resolve external entities. The EntityResolver
1273      * interface supports resolution of public and system identifiers.
1274      *
1275      * @param resolver The new entity resolver. Passing a null value will
1276      *                 uninstall the currently installed resolver.
1277      */
1278     public void setEntityResolver(EntityResolver resolver) {
1279 
1280         try {
1281             XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER);
1282             if (fUseEntityResolver2 && resolver instanceof EntityResolver2) {
1283                 if (xer instanceof EntityResolver2Wrapper) {
1284                     EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer;
1285                     er2w.setEntityResolver((EntityResolver2) resolver);
1286                 }
1287                 else {
1288                     fConfiguration.setProperty(ENTITY_RESOLVER,
1289                             new EntityResolver2Wrapper((EntityResolver2) resolver));
1290                 }
1291             }
1292             else {
1293                 if (xer instanceof EntityResolverWrapper) {
1294                     EntityResolverWrapper erw = (EntityResolverWrapper) xer;
1295                     erw.setEntityResolver(resolver);
1296                 }
1297                 else {
1298                     fConfiguration.setProperty(ENTITY_RESOLVER,
1299                             new EntityResolverWrapper(resolver));
1300                 }
1301             }
1302         }
1303         catch (XMLConfigurationException e) {
1304             // do nothing
1305         }
1306 
1307     } // setEntityResolver(EntityResolver)
1308 
1309     /**
1310      * Return the current entity resolver.
1311      *
1312      * @return The current entity resolver, or null if none
1313      *         has been registered.
1314      * @see #setEntityResolver
1315      */
1316     public EntityResolver getEntityResolver() {
1317 
1318         EntityResolver entityResolver = null;
1319         try {
1320             XMLEntityResolver xmlEntityResolver =
1321                 (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER);
1322             if (xmlEntityResolver != null) {
1323                 if (xmlEntityResolver instanceof EntityResolverWrapper) {
1324                     entityResolver =
1325                         ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver();
1326                 }
1327                 else if (xmlEntityResolver instanceof EntityResolver2Wrapper) {
1328                     entityResolver =
1329                         ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver();
1330                 }
1331             }
1332         }
1333         catch (XMLConfigurationException e) {
1334             // do nothing
1335         }
1336         return entityResolver;
1337 
1338     } // getEntityResolver():EntityResolver
1339 
1340     /**
1341      * Allow an application to register an error event handler.
1342      *
1343      * <p>If the application does not register an error handler, all
1344      * error events reported by the SAX parser will be silently
1345      * ignored; however, normal processing may not continue.  It is
1346      * highly recommended that all SAX applications implement an
1347      * error handler to avoid unexpected bugs.</p>
1348      *
1349      * <p>Applications may register a new or different handler in the
1350      * middle of a parse, and the SAX parser must begin using the new
1351      * handler immediately.</p>
1352      *
1353      * @param errorHandler The error handler.
1354      * @see #getErrorHandler
1355      */
1356     public void setErrorHandler(ErrorHandler errorHandler) {
1357 
1358         try {
1359             XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER);
1360             if (xeh instanceof ErrorHandlerWrapper) {
1361                 ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh;
1362                 ehw.setErrorHandler(errorHandler);
1363             }
1364             else {
1365                 fConfiguration.setProperty(ERROR_HANDLER,
1366                         new ErrorHandlerWrapper(errorHandler));
1367             }
1368         }
1369         catch (XMLConfigurationException e) {
1370             // do nothing
1371         }
1372 
1373     } // setErrorHandler(ErrorHandler)
1374 
1375     /**
1376      * Return the current error handler.
1377      *
1378      * @return The current error handler, or null if none
1379      *         has been registered.
1380      * @see #setErrorHandler
1381      */
1382     public ErrorHandler getErrorHandler() {
1383 
1384         ErrorHandler errorHandler = null;
1385         try {
1386             XMLErrorHandler xmlErrorHandler =
1387                 (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER);
1388             if (xmlErrorHandler != null &&
1389                 xmlErrorHandler instanceof ErrorHandlerWrapper) {
1390                 errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler();
1391             }
1392         }
1393         catch (XMLConfigurationException e) {
1394             // do nothing
1395         }
1396         return errorHandler;
1397 
1398     } // getErrorHandler():ErrorHandler
1399 
1400     /**
1401      * Set the locale to use for messages.
1402      *
1403      * @param locale The locale object to use for localization of messages.
1404      *
1405      * @exception SAXException An exception thrown if the parser does not
1406      *                         support the specified locale.
1407      *
1408      * @see org.xml.sax.Parser
1409      */
1410     public void setLocale(Locale locale) throws SAXException {
1411         //REVISIT:this methods is not part of SAX2 interfaces, we should throw exception
1412         //if any application uses SAX2 and sets locale also. -nb
1413         fConfiguration.setLocale(locale);
1414 
1415     } // setLocale(Locale)
1416 
1417     /**
1418      * Allow an application to register a DTD event handler.
1419      * <p>
1420      * If the application does not register a DTD handler, all DTD
1421      * events reported by the SAX parser will be silently ignored.
1422      * <p>
1423      * Applications may register a new or different handler in the
1424      * middle of a parse, and the SAX parser must begin using the new
1425      * handler immediately.
1426      *
1427      * @param dtdHandler The DTD handler.
1428      *
1429 
1430      * @see #getDTDHandler
1431      */
1432     public void setDTDHandler(DTDHandler dtdHandler) {
1433         fDTDHandler = dtdHandler;
1434     } // setDTDHandler(DTDHandler)
1435 
1436     //
1437     // Parser methods
1438     //
1439 
1440     /**
1441      * Allow an application to register a document event handler.
1442      * <p>
1443      * If the application does not register a document handler, all
1444      * document events reported by the SAX parser will be silently
1445      * ignored (this is the default behaviour implemented by
1446      * HandlerBase).
1447      * <p>
1448      * Applications may register a new or different handler in the
1449      * middle of a parse, and the SAX parser must begin using the new
1450      * handler immediately.
1451      *
1452      * @param documentHandler The document handler.
1453      */
1454     public void setDocumentHandler(DocumentHandler documentHandler) {
1455         fDocumentHandler = documentHandler;
1456     } // setDocumentHandler(DocumentHandler)
1457 
1458     //
1459     // XMLReader methods
1460     //
1461 
1462     /**
1463      * Allow an application to register a content event handler.
1464      * <p>
1465      * If the application does not register a content handler, all
1466      * content events reported by the SAX parser will be silently
1467      * ignored.
1468      * <p>
1469      * Applications may register a new or different handler in the
1470      * middle of a parse, and the SAX parser must begin using the new
1471      * handler immediately.
1472      *
1473      * @param contentHandler The content handler.
1474      *
1475      * @see #getContentHandler
1476      */
1477     public void setContentHandler(ContentHandler contentHandler) {
1478         fContentHandler = contentHandler;
1479     } // setContentHandler(ContentHandler)
1480 
1481     /**
1482      * Return the current content handler.
1483      *
1484      * @return The current content handler, or null if none
1485      *         has been registered.
1486      *
1487      * @see #setContentHandler
1488      */
1489     public ContentHandler getContentHandler() {
1490         return fContentHandler;
1491     } // getContentHandler():ContentHandler
1492 
1493     /**
1494      * Return the current DTD handler.
1495      *
1496      * @return The current DTD handler, or null if none
1497      *         has been registered.
1498      * @see #setDTDHandler
1499      */
1500     public DTDHandler getDTDHandler() {
1501         return fDTDHandler;
1502     } // getDTDHandler():DTDHandler
1503 
1504     /**
1505      * Set the state of any feature in a SAX2 parser.  The parser
1506      * might not recognize the feature, and if it does recognize
1507      * it, it might not be able to fulfill the request.
1508      *
1509      * @param featureId The unique identifier (URI) of the feature.
1510      * @param state The requested state of the feature (true or false).
1511      *
1512      * @exception SAXNotRecognizedException If the
1513      *            requested feature is not known.
1514      * @exception SAXNotSupportedException If the
1515      *            requested feature is known, but the requested
1516      *            state is not supported.
1517      */
1518     public void setFeature(String featureId, boolean state)
1519         throws SAXNotRecognizedException, SAXNotSupportedException {
1520 
1521         try {
1522             //
1523             // SAX2 Features
1524             //
1525 
1526             if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) {
1527                 final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length();
1528 
1529                 // http://xml.org/sax/features/namespaces
1530                 if (suffixLength == Constants.NAMESPACES_FEATURE.length() &&
1531                     featureId.endsWith(Constants.NAMESPACES_FEATURE)) {
1532                     fConfiguration.setFeature(featureId, state);
1533                     fNamespaces = state;
1534                     return;
1535                 }
1536 
1537                 // http://xml.org/sax/features/namespace-prefixes
1538                 //   controls the reporting of raw prefixed names and Namespace
1539                 //   declarations (xmlns* attributes): when this feature is false
1540                 //   (the default), raw prefixed names may optionally be reported,
1541                 //   and xmlns* attributes must not be reported.
1542                 //
1543                 if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() &&
1544                     featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) {
1545                     fConfiguration.setFeature(featureId, state);
1546                     fNamespacePrefixes = state;
1547                     return;
1548                 }
1549 
1550                 // http://xml.org/sax/features/string-interning
1551                 //   controls the use of java.lang.String#intern() for strings
1552                 //   passed to SAX handlers.
1553                 //
1554                 if (suffixLength == Constants.STRING_INTERNING_FEATURE.length() &&
1555                     featureId.endsWith(Constants.STRING_INTERNING_FEATURE)) {
1556                     if (!state) {
1557                         throw new SAXNotSupportedException(
1558                             SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1559                             "false-not-supported", new Object [] {featureId}));
1560                     }
1561                     return;
1562                 }
1563 
1564                 // http://xml.org/sax/features/lexical-handler/parameter-entities
1565                 //   controls whether the beginning and end of parameter entities
1566                 //   will be reported to the LexicalHandler.
1567                 //
1568                 if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() &&
1569                     featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) {
1570                     fLexicalHandlerParameterEntities = state;
1571                     return;
1572                 }
1573 
1574                 // http://xml.org/sax/features/resolve-dtd-uris
1575                 //   controls whether system identifiers will be absolutized relative to
1576                 //   their base URIs before reporting.
1577                 //
1578                 if (suffixLength == Constants.RESOLVE_DTD_URIS_FEATURE.length() &&
1579                     featureId.endsWith(Constants.RESOLVE_DTD_URIS_FEATURE)) {
1580                     fResolveDTDURIs = state;
1581                     return;
1582                 }
1583 
1584                 // http://xml.org/sax/features/unicode-normalization-checking
1585                 //   controls whether Unicode normalization checking is performed
1586                 //   as per Appendix B of the XML 1.1 specification
1587                 //
1588                 if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() &&
1589                     featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) {
1590                     // REVISIT: Allow this feature to be set once Unicode normalization
1591                     // checking is supported -- mrglavas.
1592                     if (state) {
1593                         throw new SAXNotSupportedException(
1594                             SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1595                             "true-not-supported", new Object [] {featureId}));
1596                     }
1597                     return;
1598                 }
1599 
1600                 // http://xml.org/sax/features/xmlns-uris
1601                 //   controls whether the parser reports that namespace declaration
1602                 //   attributes as being in the namespace: http://www.w3.org/2000/xmlns/
1603                 //
1604                 if (suffixLength == Constants.XMLNS_URIS_FEATURE.length() &&
1605                     featureId.endsWith(Constants.XMLNS_URIS_FEATURE)) {
1606                     fXMLNSURIs = state;
1607                     return;
1608                 }
1609 
1610                 // http://xml.org/sax/features/use-entity-resolver2
1611                 //   controls whether the methods of an object implementing
1612                 //   org.xml.sax.ext.EntityResolver2 will be used by the parser.
1613                 //
1614                 if (suffixLength == Constants.USE_ENTITY_RESOLVER2_FEATURE.length() &&
1615                     featureId.endsWith(Constants.USE_ENTITY_RESOLVER2_FEATURE)) {
1616                     if (state != fUseEntityResolver2) {
1617                         fUseEntityResolver2 = state;
1618                         // Refresh EntityResolver wrapper.
1619                         setEntityResolver(getEntityResolver());
1620                     }
1621                     return;
1622                 }
1623 
1624                 //
1625                 // Read only features.
1626                 //
1627 
1628                 // http://xml.org/sax/features/is-standalone
1629                 //   reports whether the document specified a standalone document declaration.
1630                 // http://xml.org/sax/features/use-attributes2
1631                 //   reports whether Attributes objects passed to startElement also implement
1632                 //   the org.xml.sax.ext.Attributes2 interface.
1633                 // http://xml.org/sax/features/use-locator2
1634                 //   reports whether Locator objects passed to setDocumentLocator also implement
1635                 //   the org.xml.sax.ext.Locator2 interface.
1636                 // http://xml.org/sax/features/xml-1.1
1637                 //   reports whether the parser supports both XML 1.1 and XML 1.0.
1638                 if ((suffixLength == Constants.IS_STANDALONE_FEATURE.length() &&
1639                     featureId.endsWith(Constants.IS_STANDALONE_FEATURE)) ||
1640                     (suffixLength == Constants.USE_ATTRIBUTES2_FEATURE.length() &&
1641                     featureId.endsWith(Constants.USE_ATTRIBUTES2_FEATURE)) ||
1642                     (suffixLength == Constants.USE_LOCATOR2_FEATURE.length() &&
1643                     featureId.endsWith(Constants.USE_LOCATOR2_FEATURE)) ||
1644                     (suffixLength == Constants.XML_11_FEATURE.length() &&
1645                     featureId.endsWith(Constants.XML_11_FEATURE))) {
1646                     throw new SAXNotSupportedException(
1647                         SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1648                         "feature-read-only", new Object [] {featureId}));
1649                 }
1650 
1651 
1652                 //
1653                 // Drop through and perform default processing
1654                 //
1655             }
1656             else if (featureId.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
1657                 if (state) {
1658                     if (fConfiguration.getProperty(SECURITY_MANAGER )==null) {
1659                         fConfiguration.setProperty(SECURITY_MANAGER, new XMLSecurityManager());
1660                     }
1661                 }
1662             }
1663 
1664             //
1665             // Default handling
1666             //
1667 
1668             fConfiguration.setFeature(featureId, state);
1669         }
1670         catch (XMLConfigurationException e) {
1671             String identifier = e.getIdentifier();
1672             if (e.getType() == Status.NOT_RECOGNIZED) {
1673                 throw new SAXNotRecognizedException(
1674                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1675                     "feature-not-recognized", new Object [] {identifier}));
1676             }
1677             else {
1678                 throw new SAXNotSupportedException(
1679                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1680                     "feature-not-supported", new Object [] {identifier}));
1681             }
1682         }
1683 
1684     } // setFeature(String,boolean)
1685 
1686     /**
1687      * Query the state of a feature.
1688      *
1689      * Query the current state of any feature in a SAX2 parser.  The
1690      * parser might not recognize the feature.
1691      *
1692      * @param featureId The unique identifier (URI) of the feature
1693      *                  being set.
1694      * @return The current state of the feature.
1695      * @exception org.xml.sax.SAXNotRecognizedException If the
1696      *            requested feature is not known.
1697      * @exception SAXNotSupportedException If the
1698      *            requested feature is known but not supported.
1699      */
1700     public boolean getFeature(String featureId)
1701         throws SAXNotRecognizedException, SAXNotSupportedException {
1702 
1703         try {
1704             //
1705             // SAX2 Features
1706             //
1707 
1708             if (featureId.startsWith(Constants.SAX_FEATURE_PREFIX)) {
1709                 final int suffixLength = featureId.length() - Constants.SAX_FEATURE_PREFIX.length();
1710 
1711                 // http://xml.org/sax/features/namespace-prefixes
1712                 //   controls the reporting of raw prefixed names and Namespace
1713                 //   declarations (xmlns* attributes): when this feature is false
1714                 //   (the default), raw prefixed names may optionally be reported,
1715                 //   and xmlns* attributes must not be reported.
1716                 //
1717                 if (suffixLength == Constants.NAMESPACE_PREFIXES_FEATURE.length() &&
1718                     featureId.endsWith(Constants.NAMESPACE_PREFIXES_FEATURE)) {
1719                     boolean state = fConfiguration.getFeature(featureId);
1720                     return state;
1721                 }
1722                 // http://xml.org/sax/features/string-interning
1723                 //   controls the use of java.lang.String#intern() for strings
1724                 //   passed to SAX handlers.
1725                 //
1726                 if (suffixLength == Constants.STRING_INTERNING_FEATURE.length() &&
1727                     featureId.endsWith(Constants.STRING_INTERNING_FEATURE)) {
1728                     return true;
1729                 }
1730 
1731                 // http://xml.org/sax/features/is-standalone
1732                 //   reports whether the document specified a standalone document declaration.
1733                 //
1734                 if (suffixLength == Constants.IS_STANDALONE_FEATURE.length() &&
1735                     featureId.endsWith(Constants.IS_STANDALONE_FEATURE)) {
1736                     return fStandalone;
1737                 }
1738 
1739                 // http://xml.org/sax/features/xml-1.1
1740                 //   reports whether the parser supports both XML 1.1 and XML 1.0.
1741                 //
1742                 if (suffixLength == Constants.XML_11_FEATURE.length() &&
1743                     featureId.endsWith(Constants.XML_11_FEATURE)) {
1744                     return (fConfiguration instanceof XML11Configurable);
1745                 }
1746 
1747                 // http://xml.org/sax/features/lexical-handler/parameter-entities
1748                 //   controls whether the beginning and end of parameter entities
1749                 //   will be reported to the LexicalHandler.
1750                 //
1751                 if (suffixLength == Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE.length() &&
1752                     featureId.endsWith(Constants.LEXICAL_HANDLER_PARAMETER_ENTITIES_FEATURE)) {
1753                     return fLexicalHandlerParameterEntities;
1754                 }
1755 
1756                 // http://xml.org/sax/features/resolve-dtd-uris
1757                 //   controls whether system identifiers will be absolutized relative to
1758                 //   their base URIs before reporting.
1759                 if (suffixLength == Constants.RESOLVE_DTD_URIS_FEATURE.length() &&
1760                     featureId.endsWith(Constants.RESOLVE_DTD_URIS_FEATURE)) {
1761                     return fResolveDTDURIs;
1762                 }
1763 
1764                 // http://xml.org/sax/features/xmlns-uris
1765                 //   controls whether the parser reports that namespace declaration
1766                 //   attributes as being in the namespace: http://www.w3.org/2000/xmlns/
1767                 //
1768                 if (suffixLength == Constants.XMLNS_URIS_FEATURE.length() &&
1769                     featureId.endsWith(Constants.XMLNS_URIS_FEATURE)) {
1770                     return fXMLNSURIs;
1771                 }
1772 
1773                 // http://xml.org/sax/features/unicode-normalization-checking
1774                 //   controls whether Unicode normalization checking is performed
1775                 //   as per Appendix B of the XML 1.1 specification
1776                 //
1777                 if (suffixLength == Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE.length() &&
1778                     featureId.endsWith(Constants.UNICODE_NORMALIZATION_CHECKING_FEATURE)) {
1779                     // REVISIT: Allow this feature to be set once Unicode normalization
1780                     // checking is supported -- mrglavas.
1781                     return false;
1782                 }
1783 
1784                 // http://xml.org/sax/features/use-entity-resolver2
1785                 //   controls whether the methods of an object implementing
1786                 //   org.xml.sax.ext.EntityResolver2 will be used by the parser.
1787                 //
1788                 if (suffixLength == Constants.USE_ENTITY_RESOLVER2_FEATURE.length() &&
1789                     featureId.endsWith(Constants.USE_ENTITY_RESOLVER2_FEATURE)) {
1790                     return fUseEntityResolver2;
1791                 }
1792 
1793                 // http://xml.org/sax/features/use-attributes2
1794                 //   reports whether Attributes objects passed to startElement also implement
1795                 //   the org.xml.sax.ext.Attributes2 interface.
1796                 // http://xml.org/sax/features/use-locator2
1797                 //   reports whether Locator objects passed to setDocumentLocator also implement
1798                 //   the org.xml.sax.ext.Locator2 interface.
1799                 //
1800                 if ((suffixLength == Constants.USE_ATTRIBUTES2_FEATURE.length() &&
1801                     featureId.endsWith(Constants.USE_ATTRIBUTES2_FEATURE)) ||
1802                     (suffixLength == Constants.USE_LOCATOR2_FEATURE.length() &&
1803                     featureId.endsWith(Constants.USE_LOCATOR2_FEATURE))) {
1804                     return true;
1805                 }
1806 
1807 
1808                 //
1809                 // Drop through and perform default processing
1810                 //
1811             }
1812 
1813             //
1814             // Xerces Features
1815             //
1816 
1817             /*
1818             else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) {
1819                 //
1820                 // Drop through and perform default processing
1821                 //
1822             }
1823             */
1824 
1825             return fConfiguration.getFeature(featureId);
1826         }
1827         catch (XMLConfigurationException e) {
1828             String identifier = e.getIdentifier();
1829             if (e.getType() == Status.NOT_RECOGNIZED) {
1830                 throw new SAXNotRecognizedException(
1831                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1832                     "feature-not-recognized", new Object [] {identifier}));
1833             }
1834             else {
1835                 throw new SAXNotSupportedException(
1836                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1837                     "feature-not-supported", new Object [] {identifier}));
1838             }
1839         }
1840 
1841     } // getFeature(String):boolean
1842 
1843     /**
1844      * Set the value of any property in a SAX2 parser.  The parser
1845      * might not recognize the property, and if it does recognize
1846      * it, it might not support the requested value.
1847      *
1848      * @param propertyId The unique identifier (URI) of the property
1849      *                   being set.
1850      * @param value The value to which the property is being set.
1851      *
1852      * @exception SAXNotRecognizedException If the
1853      *            requested property is not known.
1854      * @exception SAXNotSupportedException If the
1855      *            requested property is known, but the requested
1856      *            value is not supported.
1857      */
1858     public void setProperty(String propertyId, Object value)
1859         throws SAXNotRecognizedException, SAXNotSupportedException {
1860 
1861         try {
1862             //
1863             // SAX2 core properties
1864             //
1865 
1866             if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
1867                 final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length();
1868 
1869                 //
1870                 // http://xml.org/sax/properties/lexical-handler
1871                 // Value type: org.xml.sax.ext.LexicalHandler
1872                 // Access: read/write, pre-parse only
1873                 //   Set the lexical event handler.
1874                 //
1875                 if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() &&
1876                     propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) {
1877                     try {
1878                         setLexicalHandler((LexicalHandler)value);
1879                     }
1880                     catch (ClassCastException e) {
1881                         throw new SAXNotSupportedException(
1882                             SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1883                             "incompatible-class", new Object [] {propertyId, "org.xml.sax.ext.LexicalHandler"}));
1884                     }
1885                     return;
1886                 }
1887                 //
1888                 // http://xml.org/sax/properties/declaration-handler
1889                 // Value type: org.xml.sax.ext.DeclHandler
1890                 // Access: read/write, pre-parse only
1891                 //   Set the DTD declaration event handler.
1892                 //
1893                 if (suffixLength == Constants.DECLARATION_HANDLER_PROPERTY.length() &&
1894                     propertyId.endsWith(Constants.DECLARATION_HANDLER_PROPERTY)) {
1895                     try {
1896                         setDeclHandler((DeclHandler)value);
1897                     }
1898                     catch (ClassCastException e) {
1899                         throw new SAXNotSupportedException(
1900                             SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1901                             "incompatible-class", new Object [] {propertyId, "org.xml.sax.ext.DeclHandler"}));
1902                     }
1903                     return;
1904                 }
1905                 //
1906                 // http://xml.org/sax/properties/dom-node
1907                 // Value type: DOM Node
1908                 // Access: read-only
1909                 //   Get the DOM node currently being visited, if the SAX parser is
1910                 //   iterating over a DOM tree.  If the parser recognises and
1911                 //   supports this property but is not currently visiting a DOM
1912                 //   node, it should return null (this is a good way to check for
1913                 //   availability before the parse begins).
1914                 // http://xml.org/sax/properties/document-xml-version
1915                 // Value type: java.lang.String
1916                 // Access: read-only
1917                 //   The literal string describing the actual XML version of the document.
1918                 //
1919                 if ((suffixLength == Constants.DOM_NODE_PROPERTY.length() &&
1920                     propertyId.endsWith(Constants.DOM_NODE_PROPERTY)) ||
1921                     (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() &&
1922                     propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY))) {
1923                     throw new SAXNotSupportedException(
1924                         SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1925                         "property-read-only", new Object [] {propertyId}));
1926                 }
1927                 //
1928                 // Drop through and perform default processing
1929                 //
1930             }
1931 
1932             //
1933             // Xerces Properties
1934             //
1935 
1936             /*
1937             else if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) {
1938                 //
1939                 // Drop through and perform default processing
1940                 //
1941             }
1942             */
1943 
1944             //
1945             // Perform default processing
1946             //
1947 
1948             fConfiguration.setProperty(propertyId, value);
1949         }
1950         catch (XMLConfigurationException e) {
1951             String identifier = e.getIdentifier();
1952             if (e.getType() == Status.NOT_RECOGNIZED) {
1953                 throw new SAXNotRecognizedException(
1954                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1955                     "property-not-recognized", new Object [] {identifier}));
1956             }
1957             else {
1958                 throw new SAXNotSupportedException(
1959                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
1960                     "property-not-supported", new Object [] {identifier}));
1961             }
1962         }
1963 
1964     } // setProperty(String,Object)
1965 
1966     /**
1967      * Query the value of a property.
1968      *
1969      * Return the current value of a property in a SAX2 parser.
1970      * The parser might not recognize the property.
1971      *
1972      * @param propertyId The unique identifier (URI) of the property
1973      *                   being set.
1974      * @return The current value of the property.
1975      * @exception org.xml.sax.SAXNotRecognizedException If the
1976      *            requested property is not known.
1977      * @exception SAXNotSupportedException If the
1978      *            requested property is known but not supported.
1979      */
1980     public Object getProperty(String propertyId)
1981         throws SAXNotRecognizedException, SAXNotSupportedException {
1982 
1983         try {
1984             //
1985             // SAX2 core properties
1986             //
1987 
1988             if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
1989                 final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length();
1990 
1991                 //
1992                 // http://xml.org/sax/properties/document-xml-version
1993                 // Value type: java.lang.String
1994                 // Access: read-only
1995                 //   The literal string describing the actual XML version of the document.
1996                 //
1997                 if (suffixLength == Constants.DOCUMENT_XML_VERSION_PROPERTY.length() &&
1998                     propertyId.endsWith(Constants.DOCUMENT_XML_VERSION_PROPERTY)) {
1999                     return fVersion;
2000                 }
2001 
2002                 //
2003                 // http://xml.org/sax/properties/lexical-handler
2004                 // Value type: org.xml.sax.ext.LexicalHandler
2005                 // Access: read/write, pre-parse only
2006                 //   Set the lexical event handler.
2007                 //
2008                 if (suffixLength == Constants.LEXICAL_HANDLER_PROPERTY.length() &&
2009                     propertyId.endsWith(Constants.LEXICAL_HANDLER_PROPERTY)) {
2010                     return getLexicalHandler();
2011                 }
2012                 //
2013                 // http://xml.org/sax/properties/declaration-handler
2014                 // Value type: org.xml.sax.ext.DeclHandler
2015                 // Access: read/write, pre-parse only
2016                 //   Set the DTD declaration event handler.
2017                 //
2018                 if (suffixLength == Constants.DECLARATION_HANDLER_PROPERTY.length() &&
2019                     propertyId.endsWith(Constants.DECLARATION_HANDLER_PROPERTY)) {
2020                     return getDeclHandler();
2021                 }
2022 
2023                 //
2024                 // http://xml.org/sax/properties/dom-node
2025                 // Value type: DOM Node
2026                 // Access: read-only
2027                 //   Get the DOM node currently being visited, if the SAX parser is
2028                 //   iterating over a DOM tree.  If the parser recognises and
2029                 //   supports this property but is not currently visiting a DOM
2030                 //   node, it should return null (this is a good way to check for
2031                 //   availability before the parse begins).
2032                 //
2033                 if (suffixLength == Constants.DOM_NODE_PROPERTY.length() &&
2034                     propertyId.endsWith(Constants.DOM_NODE_PROPERTY)) {
2035                     // we are not iterating a DOM tree
2036                     throw new SAXNotSupportedException(
2037                         SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2038                         "dom-node-read-not-supported", null));
2039                 }
2040 
2041                 //
2042                 // Drop through and perform default processing
2043                 //
2044             }
2045 
2046             //
2047             // Xerces properties
2048             //
2049 
2050             /*
2051             else if (propertyId.startsWith(XERCES_PROPERTIES_PREFIX)) {
2052                 //
2053                 // Drop through and perform default processing
2054                 //
2055             }
2056             */
2057 
2058             //
2059             // Perform default processing
2060             //
2061 
2062             return fConfiguration.getProperty(propertyId);
2063         }
2064         catch (XMLConfigurationException e) {
2065             String identifier = e.getIdentifier();
2066             if (e.getType() == Status.NOT_RECOGNIZED) {
2067                 throw new SAXNotRecognizedException(
2068                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2069                     "property-not-recognized", new Object [] {identifier}));
2070             }
2071             else {
2072                 throw new SAXNotSupportedException(
2073                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2074                     "property-not-supported", new Object [] {identifier}));
2075             }
2076         }
2077 
2078     } // getProperty(String):Object
2079 
2080     //
2081     // Protected methods
2082     //
2083 
2084     // SAX2 core properties
2085 
2086     /**
2087      * Set the DTD declaration event handler.
2088      * <p>
2089      * This method is the equivalent to the property:
2090      * <pre>
2091      * http://xml.org/sax/properties/declaration-handler
2092      * </pre>
2093      *
2094      * @param handler The new handler.
2095      *
2096      * @see #getDeclHandler
2097      * @see #setProperty
2098      */
2099     protected void setDeclHandler(DeclHandler handler)
2100         throws SAXNotRecognizedException, SAXNotSupportedException {
2101 
2102         if (fParseInProgress) {
2103             throw new SAXNotSupportedException(
2104                 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2105                 "property-not-parsing-supported",
2106                 new Object [] {"http://xml.org/sax/properties/declaration-handler"}));
2107         }
2108         fDeclHandler = handler;
2109 
2110     } // setDeclHandler(DeclHandler)
2111 
2112     /**
2113      * Returns the DTD declaration event handler.
2114      *
2115      * @see #setDeclHandler
2116      */
2117     protected DeclHandler getDeclHandler()
2118         throws SAXNotRecognizedException, SAXNotSupportedException {
2119         return fDeclHandler;
2120     } // getDeclHandler():DeclHandler
2121 
2122     /**
2123      * Set the lexical event handler.
2124      * <p>
2125      * This method is the equivalent to the property:
2126      * <pre>
2127      * http://xml.org/sax/properties/lexical-handler
2128      * </pre>
2129      *
2130      * @param handler lexical event handler
2131      *
2132      * @see #getLexicalHandler
2133      * @see #setProperty
2134      */
2135     protected void setLexicalHandler(LexicalHandler handler)
2136         throws SAXNotRecognizedException, SAXNotSupportedException {
2137 
2138         if (fParseInProgress) {
2139             throw new SAXNotSupportedException(
2140                 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
2141                 "property-not-parsing-supported",
2142                 new Object [] {"http://xml.org/sax/properties/lexical-handler"}));
2143         }
2144         fLexicalHandler = handler;
2145 
2146     } // setLexicalHandler(LexicalHandler)
2147 
2148     /**
2149      * Returns the lexical handler.
2150      *
2151      * @see #setLexicalHandler
2152      */
2153     protected LexicalHandler getLexicalHandler()
2154         throws SAXNotRecognizedException, SAXNotSupportedException {
2155         return fLexicalHandler;
2156     } // getLexicalHandler():LexicalHandler
2157 
2158     /**
2159      * Send startPrefixMapping events
2160      */
2161     protected final void startNamespaceMapping() throws SAXException{
2162         int count = fNamespaceContext.getDeclaredPrefixCount();
2163         if (count > 0) {
2164             String prefix = null;
2165             String uri = null;
2166             for (int i = 0; i < count; i++) {
2167                 prefix = fNamespaceContext.getDeclaredPrefixAt(i);
2168                 uri = fNamespaceContext.getURI(prefix);
2169                 fContentHandler.startPrefixMapping(prefix,
2170                     (uri == null) ? "" : uri);
2171             }
2172         }
2173     }
2174 
2175     /**
2176      * Send endPrefixMapping events
2177      */
2178     protected final void endNamespaceMapping() throws SAXException {
2179         int count = fNamespaceContext.getDeclaredPrefixCount();
2180         if (count > 0) {
2181             for (int i = 0; i < count; i++) {
2182                 fContentHandler.endPrefixMapping(fNamespaceContext.getDeclaredPrefixAt(i));
2183             }
2184         }
2185     }
2186 
2187     //
2188     // XMLDocumentParser methods
2189     //
2190 
2191     /**
2192      * Reset all components before parsing.
2193      *
2194      * @throws XNIException Thrown if an error occurs during initialization.
2195      */
2196     public void reset() throws XNIException {
2197         super.reset();
2198 
2199         // reset state
2200         fInDTD = false;
2201         fVersion = "1.0";
2202         fStandalone = false;
2203 
2204         // features
2205         fNamespaces = fConfiguration.getFeature(NAMESPACES);
2206         fNamespacePrefixes = fConfiguration.getFeature(NAMESPACE_PREFIXES);
2207         fAugmentations = null;
2208         fDeclaredAttrs = null;
2209 
2210     } // reset()
2211 
2212     //
2213     // Classes
2214     //
2215 
2216     protected class LocatorProxy
2217         implements Locator2 {
2218 
2219         //
2220         // Data
2221         //
2222 
2223         /** XML locator. */
2224         protected XMLLocator fLocator;
2225 
2226         //
2227         // Constructors
2228         //
2229 
2230         /** Constructs an XML locator proxy. */
2231         public LocatorProxy(XMLLocator locator) {
2232             fLocator = locator;
2233         }
2234 
2235         //
2236         // Locator methods
2237         //
2238 
2239         /** Public identifier. */
2240         public String getPublicId() {
2241             return fLocator.getPublicId();
2242         }
2243 
2244         /** System identifier. */
2245         public String getSystemId() {
2246             return fLocator.getExpandedSystemId();
2247         }
2248         /** Line number. */
2249         public int getLineNumber() {
2250             return fLocator.getLineNumber();
2251         }
2252 
2253         /** Column number. */
2254         public int getColumnNumber() {
2255             return fLocator.getColumnNumber();
2256         }
2257 
2258         // Locator2 methods
2259         public String getXMLVersion() {
2260             return fLocator.getXMLVersion();
2261         }
2262 
2263         public String getEncoding() {
2264             return fLocator.getEncoding();
2265         }
2266 
2267     } // class LocatorProxy
2268 
2269     protected static final class AttributesProxy
2270         implements AttributeList, Attributes2 {
2271 
2272         //
2273         // Data
2274         //
2275 
2276         /** XML attributes. */
2277         protected XMLAttributes fAttributes;
2278 
2279         //
2280         // Public methods
2281         //
2282 
2283         /** Sets the XML attributes. */
2284         public void setAttributes(XMLAttributes attributes) {
2285             fAttributes = attributes;
2286         } // setAttributes(XMLAttributes)
2287 
2288         public int getLength() {
2289             return fAttributes.getLength();
2290         }
2291 
2292         public String getName(int i) {
2293             return fAttributes.getQName(i);
2294         }
2295 
2296         public String getQName(int index) {
2297             return fAttributes.getQName(index);
2298         }
2299 
2300         public String getURI(int index) {
2301             // REVISIT: this hides the fact that internally we use
2302             //          null instead of empty string
2303             //          SAX requires URI to be a string or an empty string
2304             String uri= fAttributes.getURI(index);
2305             return uri != null ? uri : "";
2306         }
2307 
2308         public String getLocalName(int index) {
2309             return fAttributes.getLocalName(index);
2310         }
2311 
2312         public String getType(int i) {
2313             return fAttributes.getType(i);
2314         }
2315 
2316         public String getType(String name) {
2317             return fAttributes.getType(name);
2318         }
2319 
2320         public String getType(String uri, String localName) {
2321             return uri.equals("") ? fAttributes.getType(null, localName) :
2322                                     fAttributes.getType(uri, localName);
2323         }
2324 
2325         public String getValue(int i) {
2326             return fAttributes.getValue(i);
2327         }
2328 
2329         public String getValue(String name) {
2330             return fAttributes.getValue(name);
2331         }
2332 
2333         public String getValue(String uri, String localName) {
2334             return uri.equals("") ? fAttributes.getValue(null, localName) :
2335                                     fAttributes.getValue(uri, localName);
2336         }
2337 
2338         public int getIndex(String qName) {
2339             return fAttributes.getIndex(qName);
2340         }
2341 
2342         public int getIndex(String uri, String localPart) {
2343             return uri.equals("") ? fAttributes.getIndex(null, localPart) :
2344                                     fAttributes.getIndex(uri, localPart);
2345         }
2346 
2347         // Attributes2 methods
2348         // REVISIT: Localize exception messages. -- mrglavas
2349         public boolean isDeclared(int index) {
2350             if (index < 0 || index >= fAttributes.getLength()) {
2351                 throw new ArrayIndexOutOfBoundsException(index);
2352             }
2353             return Boolean.TRUE.equals(
2354                 fAttributes.getAugmentations(index).getItem(
2355                 Constants.ATTRIBUTE_DECLARED));
2356         }
2357 
2358         public boolean isDeclared(String qName) {
2359             int index = getIndex(qName);
2360             if (index == -1) {
2361                 throw new IllegalArgumentException(qName);
2362             }
2363             return Boolean.TRUE.equals(
2364                 fAttributes.getAugmentations(index).getItem(
2365                 Constants.ATTRIBUTE_DECLARED));
2366         }
2367 
2368         public boolean isDeclared(String uri, String localName) {
2369             int index = getIndex(uri, localName);
2370             if (index == -1) {
2371                 throw new IllegalArgumentException(localName);
2372             }
2373             return Boolean.TRUE.equals(
2374                 fAttributes.getAugmentations(index).getItem(
2375                 Constants.ATTRIBUTE_DECLARED));
2376         }
2377 
2378         public boolean isSpecified(int index) {
2379             if (index < 0 || index >= fAttributes.getLength()) {
2380                 throw new ArrayIndexOutOfBoundsException(index);
2381             }
2382             return fAttributes.isSpecified(index);
2383         }
2384 
2385         public boolean isSpecified(String qName) {
2386             int index = getIndex(qName);
2387             if (index == -1) {
2388                 throw new IllegalArgumentException(qName);
2389             }
2390             return fAttributes.isSpecified(index);
2391         }
2392 
2393         public boolean isSpecified(String uri, String localName) {
2394             int index = getIndex(uri, localName);
2395             if (index == -1) {
2396                 throw new IllegalArgumentException(localName);
2397             }
2398             return fAttributes.isSpecified(index);
2399         }
2400 
2401     } // class AttributesProxy
2402 
2403 
2404     // PSVIProvider methods
2405 
2406     public ElementPSVI getElementPSVI(){
2407         return (fAugmentations != null)?(ElementPSVI)fAugmentations.getItem(Constants.ELEMENT_PSVI):null;
2408     }
2409 
2410 
2411     public AttributePSVI getAttributePSVI(int index){
2412 
2413         return (AttributePSVI)fAttributesProxy.fAttributes.getAugmentations(index).getItem(Constants.ATTRIBUTE_PSVI);
2414     }
2415 
2416 
2417     public AttributePSVI getAttributePSVIByName(String uri,
2418                                                 String localname){
2419         return (AttributePSVI)fAttributesProxy.fAttributes.getAugmentations(uri, localname).getItem(Constants.ATTRIBUTE_PSVI);
2420     }
2421 
2422 } // class AbstractSAXParser