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