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