1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xerces.internal.parsers;
23
24import com.sun.org.apache.xerces.internal.impl.Constants;
25import com.sun.org.apache.xerces.internal.util.EntityResolver2Wrapper;
26import com.sun.org.apache.xerces.internal.util.EntityResolverWrapper;
27import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
28import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter;
29import com.sun.org.apache.xerces.internal.util.Status;
30import com.sun.org.apache.xerces.internal.util.SymbolHash;
31import com.sun.org.apache.xerces.internal.util.XMLSymbols;
32import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
33import com.sun.org.apache.xerces.internal.xni.Augmentations;
34import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
35import com.sun.org.apache.xerces.internal.xni.QName;
36import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
37import com.sun.org.apache.xerces.internal.xni.XMLLocator;
38import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
39import com.sun.org.apache.xerces.internal.xni.XMLString;
40import com.sun.org.apache.xerces.internal.xni.XNIException;
41import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
42import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
43import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
44import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
45import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
46import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
47import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
48import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
49import com.sun.org.apache.xerces.internal.xs.PSVIProvider;
50import java.io.IOException;
51import java.util.Locale;
52import javax.xml.XMLConstants;
53import org.xml.sax.AttributeList;
54import org.xml.sax.ContentHandler;
55import org.xml.sax.DTDHandler;
56import org.xml.sax.DocumentHandler;
57import org.xml.sax.EntityResolver;
58import org.xml.sax.ErrorHandler;
59import org.xml.sax.InputSource;
60import org.xml.sax.Parser;
61import org.xml.sax.SAXException;
62import org.xml.sax.SAXNotRecognizedException;
63import org.xml.sax.SAXNotSupportedException;
64import org.xml.sax.SAXParseException;
65import org.xml.sax.XMLReader;
66import org.xml.sax.ext.Attributes2;
67import org.xml.sax.ext.DeclHandler;
68import org.xml.sax.ext.EntityResolver2;
69import org.xml.sax.ext.LexicalHandler;
70import org.xml.sax.ext.Locator2;
71import org.xml.sax.helpers.LocatorImpl;
72
73/**
74 * This is the base class of all SAX parsers. It implements both the
75 * SAX1 and SAX2 parser functionality, while the actual pipeline is
76 * defined in the parser configuration.
77 *
78 * @author Arnaud Le Hors, IBM
79 * @author Andy Clark, IBM
80 *
81 */
82public 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, false);
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, false);
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
2418