XMLDTDScannerImpl.java revision 1031:63c9e5adcfc8
1240616Sjimharris/*
2253112Sjimharris * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
3240616Sjimharris */
4240616Sjimharris
5240616Sjimharris/*
6240616Sjimharris * Licensed to the Apache Software Foundation (ASF) under one or more
7240616Sjimharris * contributor license agreements.  See the NOTICE file distributed with
8240616Sjimharris * this work for additional information regarding copyright ownership.
9240616Sjimharris * The ASF licenses this file to You under the Apache License, Version 2.0
10240616Sjimharris * (the "License"); you may not use this file except in compliance with
11240616Sjimharris * the License.  You may obtain a copy of the License at
12240616Sjimharris *
13240616Sjimharris *     http://www.apache.org/licenses/LICENSE-2.0
14240616Sjimharris *
15240616Sjimharris * Unless required by applicable law or agreed to in writing, software
16240616Sjimharris * distributed under the License is distributed on an "AS IS" BASIS,
17240616Sjimharris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18240616Sjimharris * See the License for the specific language governing permissions and
19240616Sjimharris * limitations under the License.
20240616Sjimharris */
21240616Sjimharris
22240616Sjimharrispackage com.sun.org.apache.xerces.internal.impl;
23240616Sjimharris
24240616Sjimharrisimport com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
25240616Sjimharrisimport com.sun.org.apache.xerces.internal.util.SymbolTable;
26240616Sjimharrisimport com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
27240616Sjimharrisimport com.sun.org.apache.xerces.internal.util.XMLChar;
28240616Sjimharrisimport com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
29240616Sjimharrisimport com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
30240616Sjimharrisimport com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
31240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
32240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
33248977Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
34248773Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XMLString;
35240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XNIException;
36240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
37240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
38240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
39240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner;
40240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
41248748Sjimharrisimport com.sun.org.apache.xerces.internal.xni.Augmentations;
42240616Sjimharrisimport com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar;
43241659Sjimharrisimport java.io.EOFException;
44241659Sjimharrisimport java.io.IOException;
45240616Sjimharris
46240616Sjimharris/**
47240616Sjimharris * This class is responsible for scanning the declarations found
48240616Sjimharris * in the internal and external subsets of a DTD in an XML document.
49240616Sjimharris * The scanner acts as the sources for the DTD information which is
50240616Sjimharris * communicated to the DTD handlers.
51240616Sjimharris * <p>
52240616Sjimharris * This component requires the following features and properties from the
53240616Sjimharris * component manager that uses it:
54240616Sjimharris * <ul>
55240616Sjimharris *  <li>http://xml.org/sax/features/validation</li>
56240616Sjimharris *  <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
57240616Sjimharris *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
58240616Sjimharris *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
59240616Sjimharris *  <li>http://apache.org/xml/properties/internal/entity-manager</li>
60243951Sjimharris * </ul>
61243951Sjimharris *
62240616Sjimharris * @author Arnaud  Le Hors, IBM
63240616Sjimharris * @author Andy Clark, IBM
64240616Sjimharris * @author Glenn Marcy, IBM
65240616Sjimharris * @author Eric Ye, IBM
66240616Sjimharris *
67241658Sjimharris */
68241658Sjimharrispublic class XMLDTDScannerImpl
69240616Sjimharrisextends XMLScanner
70252271Sjimharrisimplements XMLDTDScanner, XMLComponent, XMLEntityHandler {
71240616Sjimharris
72241664Sjimharris    //
73240616Sjimharris    // Constants
74240616Sjimharris    //
75240616Sjimharris
76240616Sjimharris    // scanner states
77240616Sjimharris
78240616Sjimharris    /** Scanner state: end of input. */
79241664Sjimharris    protected static final int SCANNER_STATE_END_OF_INPUT = 0;
80241664Sjimharris
81241664Sjimharris    /** Scanner state: text declaration. */
82241664Sjimharris    protected static final int SCANNER_STATE_TEXT_DECL = 1;
83241664Sjimharris
84241664Sjimharris    /** Scanner state: markup declaration. */
85241664Sjimharris    protected static final int SCANNER_STATE_MARKUP_DECL = 2;
86241664Sjimharris
87241664Sjimharris    // recognized features and properties
88248767Sjimharris
89241664Sjimharris    /** Recognized features. */
90241664Sjimharris    private static final String[] RECOGNIZED_FEATURES = {
91241664Sjimharris        VALIDATION,
92240616Sjimharris        NOTIFY_CHAR_REFS,
93240616Sjimharris    };
94240616Sjimharris
95240616Sjimharris    /** Feature defaults. */
96240616Sjimharris    private static final Boolean[] FEATURE_DEFAULTS = {
97240616Sjimharris        null,
98240616Sjimharris        Boolean.FALSE,
99240616Sjimharris    };
100240616Sjimharris
101248737Sjimharris    /** Recognized properties. */
102240616Sjimharris    private static final String[] RECOGNIZED_PROPERTIES = {
103248755Sjimharris        SYMBOL_TABLE,
104248749Sjimharris        ERROR_REPORTER,
105248749Sjimharris        ENTITY_MANAGER,
106240616Sjimharris    };
107248761Sjimharris
108248761Sjimharris    /** Property defaults. */
109248759Sjimharris    private static final Object[] PROPERTY_DEFAULTS = {
110248759Sjimharris        null,
111248759Sjimharris        null,
112241433Sjimharris        null,
113241433Sjimharris    };
114241433Sjimharris
115241433Sjimharris    // debugging
116248977Sjimharris
117248977Sjimharris    /** Debug scanner state. */
118248977Sjimharris    private static final boolean DEBUG_SCANNER_STATE = false;
119248977Sjimharris
120248977Sjimharris    //
121248977Sjimharris    // Data
122248977Sjimharris    //
123248977Sjimharris
124248977Sjimharris    // handlers
125248977Sjimharris
126248761Sjimharris    /** DTD handler. */
127248761Sjimharris    public XMLDTDHandler fDTDHandler = null;
128241659Sjimharris
129248769Sjimharris    /** DTD content model handler. */
130248769Sjimharris    protected XMLDTDContentModelHandler fDTDContentModelHandler;
131248769Sjimharris
132248769Sjimharris    // state
133248769Sjimharris
134248769Sjimharris    /** Scanner state. */
135248913Sjimharris    protected int fScannerState;
136248913Sjimharris
137248913Sjimharris    /** Standalone. */
138248977Sjimharris    protected boolean fStandalone;
139248977Sjimharris
140248977Sjimharris    /** Seen external DTD. */
141248913Sjimharris    protected boolean fSeenExternalDTD;
142241659Sjimharris
143241659Sjimharris    /** Seen external parameter entity. */
144241659Sjimharris    protected boolean fSeenExternalPE;
145248767Sjimharris
146248913Sjimharris    // private data
147248913Sjimharris
148248977Sjimharris    /** Start DTD called. */
149248913Sjimharris    private boolean fStartDTDCalled;
150248913Sjimharris
151241659Sjimharris    /** Default attribute */
152248749Sjimharris    private XMLAttributesImpl fAttributes = new XMLAttributesImpl();
153241659Sjimharris
154241659Sjimharris    /**
155248761Sjimharris     * Stack of content operators (either '|' or ',') in children
156241665Sjimharris     * content.
157241659Sjimharris     */
158241659Sjimharris    private int[] fContentStack = new int[5];
159248737Sjimharris
160248737Sjimharris    /** Size of content stack. */
161248737Sjimharris    private int fContentDepth;
162248737Sjimharris
163248759Sjimharris    /** Parameter entity stack to check well-formedness. */
164248760Sjimharris    private int[] fPEStack = new int[5];
165248759Sjimharris
166248759Sjimharris
167248737Sjimharris    /** Parameter entity stack to report start/end entity calls. */
168248737Sjimharris    private boolean[] fPEReport = new boolean[5];
169240616Sjimharris
170240616Sjimharris    /** Number of opened parameter entities. */
171248741Sjimharris    private int fPEDepth;
172241659Sjimharris
173240616Sjimharris    /** Markup depth. */
174240616Sjimharris    private int fMarkUpDepth;
175241658Sjimharris
176240616Sjimharris    /** Number of opened external entities. */
177241658Sjimharris    private int fExtEntityDepth;
178241658Sjimharris
179241658Sjimharris    /** Number of opened include sections. */
180241658Sjimharris    private int fIncludeSectDepth;
181240616Sjimharris
182240616Sjimharris    // temporary variables
183240616Sjimharris
184240616Sjimharris    /** Array of 3 strings. */
185240616Sjimharris    private String[] fStrings = new String[3];
186240616Sjimharris
187240616Sjimharris    /** String. */
188240616Sjimharris    private XMLString fString = new XMLString();
189240616Sjimharris
190240616Sjimharris    /** String buffer. */
191240616Sjimharris    private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
192240616Sjimharris
193240616Sjimharris    /** String buffer. */
194240616Sjimharris    private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
195241664Sjimharris
196240616Sjimharris    /** Literal text. */
197240616Sjimharris    private XMLString fLiteral = new XMLString();
198240616Sjimharris
199240616Sjimharris    /** Literal text. */
200240616Sjimharris    private XMLString fLiteral2 = new XMLString();
201240616Sjimharris
202240616Sjimharris    /** Enumeration values. */
203240616Sjimharris    private String[] fEnumeration = new String[5];
204241434Sjimharris
205240616Sjimharris    /** Enumeration values count. */
206240616Sjimharris    private int fEnumerationCount;
207240616Sjimharris
208240616Sjimharris    /** Ignore conditional section buffer. */
209240616Sjimharris    private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128);
210240616Sjimharris
211240616Sjimharris    /** Object contains grammar information for a non-validaing parser. */
212240616Sjimharris    DTDGrammar nvGrammarInfo = null;
213240616Sjimharris
214240616Sjimharris    boolean nonValidatingMode = false;
215240616Sjimharris    //
216240616Sjimharris    // Constructors
217248741Sjimharris    //
218248741Sjimharris
219241665Sjimharris    /** Default constructor. */
220240616Sjimharris    public XMLDTDScannerImpl() {
221240616Sjimharris    } // <init>()
222240616Sjimharris
223248746Sjimharris    /** Constructor for he use of non-XMLComponentManagers. */
224248746Sjimharris    public XMLDTDScannerImpl(SymbolTable symbolTable,
225241433Sjimharris            XMLErrorReporter errorReporter, XMLEntityManager entityManager) {
226241433Sjimharris        fSymbolTable = symbolTable;
227241433Sjimharris        fErrorReporter = errorReporter;
228241433Sjimharris        fEntityManager = entityManager;
229240616Sjimharris        entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
230240616Sjimharris    }
231240616Sjimharris
232240616Sjimharris    //
233240616Sjimharris    // XMLDTDScanner methods
234240616Sjimharris    //
235240616Sjimharris
236248738Sjimharris    /**
237249418Sjimharris     * Sets the input source.
238240616Sjimharris     *
239240616Sjimharris     * @param inputSource The input source or null.
240240616Sjimharris     *
241240616Sjimharris     * @throws IOException Thrown on i/o error.
242240616Sjimharris     */
243240616Sjimharris    public void setInputSource(XMLInputSource inputSource) throws IOException {
244240616Sjimharris        if (inputSource == null) {
245240616Sjimharris            // no system id was available
246240616Sjimharris            if (fDTDHandler != null) {
247249417Sjimharris                fDTDHandler.startDTD(null, null);
248249417Sjimharris                fDTDHandler.endDTD(null);
249240616Sjimharris            }
250240616Sjimharris            if (nonValidatingMode){
251240616Sjimharris                nvGrammarInfo.startDTD(null,null);
252240616Sjimharris                nvGrammarInfo.endDTD(null);
253240616Sjimharris            }
254240616Sjimharris            return;
255240616Sjimharris        }
256244413Sjimharris        fEntityManager.setEntityHandler(this);
257244413Sjimharris        fEntityManager.startDTDEntity(inputSource);
258244413Sjimharris    } // setInputSource(XMLInputSource)
259244413Sjimharris
260244413Sjimharris
261244413Sjimharris    public void setLimitAnalyzer(XMLLimitAnalyzer limitAnalyzer) {
262244413Sjimharris        fLimitAnalyzer = limitAnalyzer;
263244413Sjimharris    }
264240616Sjimharris
265240616Sjimharris    /**
266240616Sjimharris     * Scans the external subset of the document.
267240616Sjimharris     *
268240616Sjimharris     * @param complete True if the scanner should scan the document
269240616Sjimharris     *                 completely, pushing all events to the registered
270240616Sjimharris     *                 document handler. A value of false indicates that
271240616Sjimharris     *                 that the scanner should only scan the next portion
272240616Sjimharris     *                 of the document and return. A scanner instance is
273248754Sjimharris     *                 permitted to completely scan a document if it does
274240616Sjimharris     *                 not support this "pull" scanning model.
275240616Sjimharris     *
276240616Sjimharris     * @return True if there is more to scan, false otherwise.
277240616Sjimharris     */
278240616Sjimharris    public boolean scanDTDExternalSubset(boolean complete)
279240616Sjimharris    throws IOException, XNIException {
280240616Sjimharris
281240616Sjimharris        fEntityManager.setEntityHandler(this);
282248767Sjimharris        if (fScannerState == SCANNER_STATE_TEXT_DECL) {
283248754Sjimharris            fSeenExternalDTD = true;
284248767Sjimharris            boolean textDecl = scanTextDecl();
285248748Sjimharris            if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
286240616Sjimharris                return false;
287240616Sjimharris            }
288240616Sjimharris            else {
289240616Sjimharris                // next state is markup decls regardless of whether there
290240616Sjimharris                // is a TextDecl or not
291240616Sjimharris                setScannerState(SCANNER_STATE_MARKUP_DECL);
292240616Sjimharris                if (textDecl && !complete) {
293240616Sjimharris                    return true;
294240616Sjimharris                }
295240616Sjimharris            }
296240616Sjimharris        }
297240616Sjimharris        // keep dispatching "events"
298248762Sjimharris        do {
299248762Sjimharris            if (!scanDecls(complete)) {
300248762Sjimharris                return false;
301240616Sjimharris            }
302240616Sjimharris        } while (complete);
303240616Sjimharris
304240616Sjimharris        // return that there is more to scan
305240616Sjimharris        return true;
306240616Sjimharris
307248749Sjimharris    } // scanDTDExternalSubset(boolean):boolean
308248749Sjimharris
309248749Sjimharris    /**
310240616Sjimharris     * Scans the internal subset of the document.
311240616Sjimharris     *
312240616Sjimharris     * @param complete True if the scanner should scan the document
313240616Sjimharris     *                 completely, pushing all events to the registered
314240616Sjimharris     *                 document handler. A value of false indicates that
315240616Sjimharris     *                 that the scanner should only scan the next portion
316240616Sjimharris     *                 of the document and return. A scanner instance is
317240616Sjimharris     *                 permitted to completely scan a document if it does
318240616Sjimharris     *                 not support this "pull" scanning model.
319240616Sjimharris     * @param standalone True if the document was specified as standalone.
320248737Sjimharris     *                   This value is important for verifying certain
321248737Sjimharris     *                   well-formedness constraints.
322248737Sjimharris     * @param hasExternalDTD True if the document has an external DTD.
323248738Sjimharris     *                       This allows the scanner to properly notify
324248738Sjimharris     *                       the handler of the end of the DTD in the
325248755Sjimharris     *                       absence of an external subset.
326248755Sjimharris     *
327248767Sjimharris     * @return True if there is more to scan, false otherwise.
328248767Sjimharris     */
329248767Sjimharris    public boolean scanDTDInternalSubset(boolean complete, boolean standalone,
330240616Sjimharris    boolean hasExternalSubset)
331240616Sjimharris    throws IOException, XNIException {
332240616Sjimharris        // reset entity scanner
333240616Sjimharris        //xxx:stax getText() is supposed to return only DTD internal subset
334240616Sjimharris        //shouldn't we record position here before we go ahead ??
335240616Sjimharris
336240616Sjimharris        fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner();
337240616Sjimharris        fEntityManager.setEntityHandler(this);
338240616Sjimharris        fStandalone = standalone;
339240616Sjimharris        //System.out.println("state"+fScannerState);
340240616Sjimharris        if (fScannerState == SCANNER_STATE_TEXT_DECL) {
341240616Sjimharris            // call handler
342240616Sjimharris            if (fDTDHandler != null) {
343240616Sjimharris                fDTDHandler.startDTD(fEntityScanner, null);
344240616Sjimharris                fStartDTDCalled = true;
345240616Sjimharris            }
346240616Sjimharris
347240616Sjimharris            if (nonValidatingMode){
348240616Sjimharris                fStartDTDCalled = true;
349240616Sjimharris                nvGrammarInfo.startDTD(fEntityScanner,null);
350240616Sjimharris            }
351240616Sjimharris            // set starting state for internal subset
352240616Sjimharris            setScannerState(SCANNER_STATE_MARKUP_DECL);
353240616Sjimharris        }
354240616Sjimharris        // keep dispatching "events"
355240616Sjimharris        do {
356240616Sjimharris            if (!scanDecls(complete)) {
357240616Sjimharris                // call handler
358240616Sjimharris                if (fDTDHandler != null && hasExternalSubset == false) {
359240616Sjimharris                    fDTDHandler.endDTD(null);
360240616Sjimharris                }
361240616Sjimharris                if (nonValidatingMode && hasExternalSubset == false ){
362240616Sjimharris                    nvGrammarInfo.endDTD(null);
363240616Sjimharris                }
364240616Sjimharris                // we're done, set starting state for external subset
365240616Sjimharris                setScannerState(SCANNER_STATE_TEXT_DECL);
366240616Sjimharris                // we're done scanning DTD.
367240616Sjimharris                fLimitAnalyzer.reset(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT);
368240616Sjimharris                fLimitAnalyzer.reset(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT);
369240616Sjimharris                return false;
370240616Sjimharris            }
371240616Sjimharris        } while (complete);
372240616Sjimharris
373240616Sjimharris        // return that there is more to scan
374240616Sjimharris        return true;
375240616Sjimharris
376240616Sjimharris    } // scanDTDInternalSubset(boolean,boolean,boolean):boolean
377248773Sjimharris
378248773Sjimharris    /**
379248773Sjimharris     * Skip the DTD if javax.xml.stream.supportDTD is false.
380240616Sjimharris     *
381240616Sjimharris     * @param supportDTD The value of the property javax.xml.stream.supportDTD.
382240616Sjimharris     * @return true if DTD is skipped, false otherwise.
383240616Sjimharris     * @throws java.io.IOException if i/o error occurs
384240616Sjimharris     */
385240616Sjimharris    @Override
386240616Sjimharris    public boolean skipDTD(boolean supportDTD) throws IOException {
387240616Sjimharris        if (supportDTD)
388240616Sjimharris            return false;
389240616Sjimharris
390240616Sjimharris        fStringBuffer.clear();
391240616Sjimharris        while (fEntityScanner.scanData("]", fStringBuffer, 0)) {
392240616Sjimharris            int c = fEntityScanner.peekChar();
393248757Sjimharris            if (c != -1) {
394248757Sjimharris                if (XMLChar.isHighSurrogate(c)) {
395248757Sjimharris                    scanSurrogates(fStringBuffer);
396248757Sjimharris                }
397248757Sjimharris                if (isInvalidLiteral(c)) {
398240616Sjimharris                    reportFatalError("InvalidCharInDTD",
399240616Sjimharris                        new Object[] { Integer.toHexString(c) });
400240616Sjimharris                    fEntityScanner.scanChar(null);
401240616Sjimharris                }
402240616Sjimharris            }
403248758Sjimharris        }
404248758Sjimharris        fEntityScanner.fCurrentEntity.position--;
405248758Sjimharris        return true;
406248758Sjimharris    }
407240616Sjimharris
408240616Sjimharris    //
409240616Sjimharris    // XMLComponent methods
410240616Sjimharris    //
411240616Sjimharris
412240616Sjimharris    /**
413240616Sjimharris     * reset
414240616Sjimharris     *
415240616Sjimharris     * @param componentManager
416240616Sjimharris     */
417240616Sjimharris    public void reset(XMLComponentManager componentManager)
418240616Sjimharris    throws XMLConfigurationException {
419240616Sjimharris
420240616Sjimharris        super.reset(componentManager);
421240616Sjimharris        init();
422248737Sjimharris
423248737Sjimharris    } // reset(XMLComponentManager)
424248737Sjimharris
425248732Sjimharris    // this is made for something like XMLDTDLoader--XMLComponentManager-free operation...
426248732Sjimharris    public void reset() {
427240616Sjimharris        super.reset();
428248769Sjimharris        init();
429240616Sjimharris
430240616Sjimharris    }
431248736Sjimharris
432248746Sjimharris    public void reset(PropertyManager props) {
433248746Sjimharris        setPropertyManager(props);
434240616Sjimharris        super.reset(props);
435248763Sjimharris        init() ;
436241660Sjimharris        nonValidatingMode = true;
437241660Sjimharris        //Revisit : Create new grammar until we implement GrammarPool.
438241660Sjimharris        nvGrammarInfo = new DTDGrammar(fSymbolTable);
439241660Sjimharris    }
440248767Sjimharris    /**
441248767Sjimharris     * Returns a list of feature identifiers that are recognized by
442240616Sjimharris     * this component. This method may return null if no features
443240616Sjimharris     * are recognized by this component.
444240616Sjimharris     */
445252271Sjimharris    public String[] getRecognizedFeatures() {
446240616Sjimharris        return (String[])(RECOGNIZED_FEATURES.clone());
447248746Sjimharris    } // getRecognizedFeatures():String[]
448248746Sjimharris
449240616Sjimharris    /**
450241663Sjimharris     * Returns a list of property identifiers that are recognized by
451241663Sjimharris     * this component. This method may return null if no properties
452248761Sjimharris     * are recognized by this component.
453248767Sjimharris     */
454248767Sjimharris    public String[] getRecognizedProperties() {
455248767Sjimharris        return (String[])(RECOGNIZED_PROPERTIES.clone());
456248767Sjimharris    } // getRecognizedProperties():String[]
457248767Sjimharris
458240616Sjimharris    /**
459248746Sjimharris     * Returns the default state for a feature, or null if this
460248746Sjimharris     * component does not want to report a default value for this
461240616Sjimharris     * feature.
462240616Sjimharris     *
463248746Sjimharris     * @param featureId The feature identifier.
464248746Sjimharris     *
465240616Sjimharris     * @since Xerces 2.2.0
466240616Sjimharris     */
467240616Sjimharris    public Boolean getFeatureDefault(String featureId) {
468240616Sjimharris        for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
469248746Sjimharris            if (RECOGNIZED_FEATURES[i].equals(featureId)) {
470240616Sjimharris                return FEATURE_DEFAULTS[i];
471240616Sjimharris            }
472240616Sjimharris        }
473240616Sjimharris        return null;
474240616Sjimharris    } // getFeatureDefault(String):Boolean
475240616Sjimharris
476240616Sjimharris    /**
477240616Sjimharris     * Returns the default state for a property, or null if this
478240616Sjimharris     * component does not want to report a default value for this
479240616Sjimharris     * property.
480240616Sjimharris     *
481240616Sjimharris     * @param propertyId The property identifier.
482240616Sjimharris     *
483240616Sjimharris     * @since Xerces 2.2.0
484241659Sjimharris     */
485248771Sjimharris    public Object getPropertyDefault(String propertyId) {
486241659Sjimharris        for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
487241659Sjimharris            if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
488241659Sjimharris                return PROPERTY_DEFAULTS[i];
489241659Sjimharris            }
490248771Sjimharris        }
491248771Sjimharris        return null;
492248771Sjimharris    } // getPropertyDefault(String):Object
493248771Sjimharris
494248771Sjimharris    //
495248771Sjimharris    // XMLDTDSource methods
496248771Sjimharris    //
497241659Sjimharris
498248771Sjimharris    /**
499248913Sjimharris     * setDTDHandler
500248913Sjimharris     *
501248771Sjimharris     * @param dtdHandler
502248771Sjimharris     */
503241659Sjimharris    public void setDTDHandler(XMLDTDHandler dtdHandler) {
504248771Sjimharris        fDTDHandler = dtdHandler;
505248771Sjimharris    } // setDTDHandler(XMLDTDHandler)
506248913Sjimharris
507248913Sjimharris    /**
508248771Sjimharris     * getDTDHandler
509248771Sjimharris     *
510241659Sjimharris     * @return the XMLDTDHandler
511241659Sjimharris     */
512241659Sjimharris    public XMLDTDHandler getDTDHandler() {
513241661Sjimharris        return fDTDHandler;
514248913Sjimharris    } // getDTDHandler():  XMLDTDHandler
515241661Sjimharris
516241661Sjimharris    //
517241661Sjimharris    // XMLDTDContentModelSource methods
518248771Sjimharris    //
519248771Sjimharris
520248913Sjimharris    /**
521241661Sjimharris     * setDTDContentModelHandler
522241661Sjimharris     *
523241661Sjimharris     * @param dtdContentModelHandler
524248913Sjimharris     */
525248977Sjimharris    public void setDTDContentModelHandler(XMLDTDContentModelHandler
526248977Sjimharris    dtdContentModelHandler) {
527248977Sjimharris        fDTDContentModelHandler = dtdContentModelHandler;
528248977Sjimharris    } // setDTDContentModelHandler
529248977Sjimharris
530248977Sjimharris    /**
531248977Sjimharris     * getDTDContentModelHandler
532248977Sjimharris     *
533248977Sjimharris     * @return XMLDTDContentModelHandler
534248977Sjimharris     */
535248977Sjimharris    public XMLDTDContentModelHandler getDTDContentModelHandler() {
536248977Sjimharris        return fDTDContentModelHandler ;
537248977Sjimharris    } // setDTDContentModelHandler
538248977Sjimharris
539248977Sjimharris    //
540248977Sjimharris    // XMLEntityHandler methods
541248977Sjimharris    //
542248977Sjimharris
543241659Sjimharris    /**
544241659Sjimharris     * This method notifies of the start of an entity. The DTD has the
545248738Sjimharris     * pseudo-name of "[dtd]" parameter entity names start with '%'; and
546248760Sjimharris     * general entities are just specified by their name.
547248760Sjimharris     *
548248760Sjimharris     * @param name     The name of the entity.
549248767Sjimharris     * @param identifier The resource identifier.
550248738Sjimharris     * @param encoding The auto-detected IANA encoding name of the entity
551240616Sjimharris     *                 stream. This value will be null in those situations
552     *                 where the entity encoding is not auto-detected (e.g.
553     *                 internal entities or a document entity that is
554     *                 parsed from a java.io.Reader).
555     * @param augs     Additional information that may include infoset augmentations
556     *
557     * @throws XNIException Thrown by handler to signal an error.
558     */
559    public void startEntity(String name,
560                            XMLResourceIdentifier identifier,
561                            String encoding, Augmentations augs) throws XNIException {
562
563        super.startEntity(name, identifier, encoding, augs);
564
565        boolean dtdEntity = name.equals("[dtd]");
566        if (dtdEntity) {
567            // call handler
568            if (fDTDHandler != null && !fStartDTDCalled ) {
569                fDTDHandler.startDTD(fEntityScanner, null);
570            }
571            if (fDTDHandler != null) {
572                fDTDHandler.startExternalSubset(identifier,null);
573            }
574            fEntityManager.startExternalSubset();
575            fEntityStore.startExternalSubset();
576            fExtEntityDepth++;
577        }
578        else if (name.charAt(0) == '%') {
579            pushPEStack(fMarkUpDepth, fReportEntity);
580            if (fEntityScanner.isExternal()) {
581                fExtEntityDepth++;
582            }
583        }
584
585        // call handler
586        if (fDTDHandler != null && !dtdEntity && fReportEntity) {
587            fDTDHandler.startParameterEntity(name, identifier, encoding, null);
588        }
589
590    } // startEntity(String,XMLResourceIdentifier,String)
591
592    /**
593     * This method notifies the end of an entity. The DTD has the pseudo-name
594     * of "[dtd]" parameter entity names start with '%'; and general entities
595     * are just specified by their name.
596     *
597     * @param name The name of the entity.
598     *
599     * @throws XNIException Thrown by handler to signal an error.
600     */
601    public void endEntity(String name, Augmentations augs)
602    throws XNIException, IOException {
603
604        super.endEntity(name, augs);
605
606        // if there is no data after the doctype
607        //
608        if (fScannerState == SCANNER_STATE_END_OF_INPUT)
609            return;
610
611        // Handle end of PE
612        boolean reportEntity = fReportEntity;
613        if (name.startsWith("%")) {
614            reportEntity = peekReportEntity();
615            // check well-formedness of the entity
616            int startMarkUpDepth = popPEStack();
617            // throw fatalError if this entity was incomplete and
618            // was a freestanding decl
619            if(startMarkUpDepth == 0 &&
620            startMarkUpDepth < fMarkUpDepth) {
621                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
622                "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL",
623                new Object[]{ fEntityManager.fCurrentEntity.name},
624                XMLErrorReporter.SEVERITY_FATAL_ERROR);
625            }
626            if (startMarkUpDepth != fMarkUpDepth) {
627                reportEntity = false;
628                if (fValidation) {
629                    // Proper nesting of parameter entities is a Validity Constraint
630                    // and must not be enforced when validation is off
631                    fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
632                    "ImproperDeclarationNesting",
633                    new Object[]{ name },
634                    XMLErrorReporter.SEVERITY_ERROR);
635                }
636            }
637            if (fEntityScanner.isExternal()) {
638                fExtEntityDepth--;
639            }
640        }
641
642        // call handler
643        boolean dtdEntity = name.equals("[dtd]");
644        if (fDTDHandler != null && !dtdEntity && reportEntity) {
645            fDTDHandler.endParameterEntity(name, null);
646        }
647
648        // end DTD
649        if (dtdEntity) {
650            if (fIncludeSectDepth != 0) {
651                reportFatalError("IncludeSectUnterminated", null);
652            }
653            fScannerState = SCANNER_STATE_END_OF_INPUT;
654            // call handler
655            fEntityManager.endExternalSubset();
656            fEntityStore.endExternalSubset();
657
658            if (fDTDHandler != null) {
659                fDTDHandler.endExternalSubset(null);
660                fDTDHandler.endDTD(null);
661            }
662            fExtEntityDepth--;
663        }
664
665        //XML (Document Entity) is the last opened entity, however
666        //if for some reason DTD Scanner receives this callback
667        //there is something wrong (probably invalid XML), throw exception.
668        //or
669        //For standalone DTD loader, it might be the last opened entity
670        //and if this is the last opened entity and fMarkUpDepth != 0 or
671        //fIncludeSectDepth != 0 or fExtEntityDepth != 0 throw Exception
672        if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.LAST_ENTITY))
673            && ( fMarkUpDepth != 0 || fExtEntityDepth !=0 || fIncludeSectDepth != 0)){
674            throw new EOFException();
675        }
676
677    } // endEntity(String)
678
679    // helper methods
680
681    /**
682     * Sets the scanner state.
683     *
684     * @param state The new scanner state.
685     */
686    protected final void setScannerState(int state) {
687
688        fScannerState = state;
689        if (DEBUG_SCANNER_STATE) {
690            System.out.print("### setScannerState: ");
691            System.out.print(getScannerStateName(state));
692            //System.out.println();
693        }
694
695    } // setScannerState(int)
696
697    //
698    // Private methods
699    //
700
701    /** Returns the scanner state name. */
702    private static String getScannerStateName(int state) {
703
704        if (DEBUG_SCANNER_STATE) {
705            switch (state) {
706                case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
707                case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
708                case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL";
709            }
710        }
711
712        return "??? ("+state+')';
713
714    } // getScannerStateName(int):String
715
716    protected final boolean scanningInternalSubset() {
717        return fExtEntityDepth == 0;
718    }
719
720    /**
721     * start a parameter entity dealing with the textdecl if there is any
722     *
723     * @param name The name of the parameter entity to start (without the '%')
724     * @param literal Whether this is happening within a literal
725     */
726    protected void startPE(String name, boolean literal)
727    throws IOException, XNIException {
728        int depth = fPEDepth;
729        String pName = "%"+name;
730        if (fValidation && !fEntityStore.isDeclaredEntity(pName)) {
731            fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
732            new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
733        }
734        fEntityManager.startEntity(false, fSymbolTable.addSymbol(pName),
735        literal);
736        // if we actually got a new entity and it's external
737        // parse text decl if there is any
738        if (depth != fPEDepth && fEntityScanner.isExternal()) {
739            scanTextDecl();
740        }
741    }
742
743    /**
744     * Dispatch an XML "event".
745     *
746     * @param complete True if this method is intended to scan
747     *                 and dispatch as much as possible.
748     *
749     * @return True if a TextDecl was scanned.
750     *
751     * @throws IOException  Thrown on i/o error.
752     * @throws XNIException Thrown on parse error.
753     *
754     */
755    protected final boolean scanTextDecl()
756    throws IOException, XNIException {
757
758        // scan XMLDecl
759        boolean textDecl = false;
760        if (fEntityScanner.skipString("<?xml")) {
761            fMarkUpDepth++;
762            // NOTE: special case where document starts with a PI
763            //       whose name starts with "xml" (e.g. "xmlfoo")
764            if (isValidNameChar(fEntityScanner.peekChar())) {
765                fStringBuffer.clear();
766                fStringBuffer.append("xml");
767                while (isValidNameChar(fEntityScanner.peekChar())) {
768                    fStringBuffer.append((char)fEntityScanner.scanChar(null));
769                }
770                String target =
771                fSymbolTable.addSymbol(fStringBuffer.ch,
772                fStringBuffer.offset,
773                fStringBuffer.length);
774                scanPIData(target, fString);
775            }
776
777            // standard Text declaration
778            else {
779                // pseudo-attribute values
780                String version = null;
781                String encoding = null;
782
783                scanXMLDeclOrTextDecl(true, fStrings);
784                textDecl = true;
785                fMarkUpDepth--;
786
787                version = fStrings[0];
788                encoding = fStrings[1];
789
790                fEntityScanner.setEncoding(encoding);
791
792                // call handler
793                if (fDTDHandler != null) {
794                    fDTDHandler.textDecl(version, encoding, null);
795                }
796            }
797        }
798        fEntityManager.fCurrentEntity.mayReadChunks = true;
799
800        return textDecl;
801
802    } // scanTextDecl(boolean):boolean
803
804    /**
805     * Scans a processing data. This is needed to handle the situation
806     * where a document starts with a processing instruction whose
807     * target name <em>starts with</em> "xml". (e.g. xmlfoo)
808     *
809     * @param target The PI target
810     * @param data The string to fill in with the data
811     */
812    protected final void scanPIData(String target, XMLString data)
813    throws IOException, XNIException {
814        //Venu REVISIT
815        //      super.scanPIData(target, data);
816        fMarkUpDepth--;
817
818        // call handler
819        if (fDTDHandler != null) {
820            fDTDHandler.processingInstruction(target, data, null);
821        }
822
823    } // scanPIData(String)
824
825    /**
826     * Scans a comment.
827     * <p>
828     * <pre>
829     * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
830     * </pre>
831     * <p>
832     * <strong>Note:</strong> Called after scanning past '&lt;!--'
833     */
834    protected final void scanComment() throws IOException, XNIException {
835
836        fReportEntity = false;
837        scanComment(fStringBuffer);
838        fMarkUpDepth--;
839
840        // call handler
841        if (fDTDHandler != null) {
842            fDTDHandler.comment(fStringBuffer, null);
843        }
844        fReportEntity = true;
845
846    } // scanComment()
847
848    /**
849     * Scans an element declaration
850     * <p>
851     * <pre>
852     * [45]    elementdecl    ::=    '&lt;!ELEMENT' S Name S contentspec S? '>'
853     * [46]    contentspec    ::=    'EMPTY' | 'ANY' | Mixed | children
854     * </pre>
855     * <p>
856     * <strong>Note:</strong> Called after scanning past '&lt;!ELEMENT'
857     */
858    protected final void scanElementDecl() throws IOException, XNIException {
859
860        // spaces
861        fReportEntity = false;
862        if (!skipSeparator(true, !scanningInternalSubset())) {
863            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL",
864            null);
865        }
866
867        // element name
868        String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
869        if (name == null) {
870            reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL",
871            null);
872        }
873
874        // spaces
875        if (!skipSeparator(true, !scanningInternalSubset())) {
876            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL",
877            new Object[]{name});
878        }
879
880        // content model
881        if (fDTDContentModelHandler != null) {
882            fDTDContentModelHandler.startContentModel(name, null);
883        }
884        String contentModel = null;
885        fReportEntity = true;
886        if (fEntityScanner.skipString("EMPTY")) {
887            contentModel = "EMPTY";
888            // call handler
889            if (fDTDContentModelHandler != null) {
890                fDTDContentModelHandler.empty(null);
891            }
892        }
893        else if (fEntityScanner.skipString("ANY")) {
894            contentModel = "ANY";
895            // call handler
896            if (fDTDContentModelHandler != null) {
897                fDTDContentModelHandler.any(null);
898            }
899        }
900        else {
901            if (!fEntityScanner.skipChar('(', null)) {
902                reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
903                new Object[]{name});
904            }
905            if (fDTDContentModelHandler != null) {
906                fDTDContentModelHandler.startGroup(null);
907            }
908            fStringBuffer.clear();
909            fStringBuffer.append('(');
910            fMarkUpDepth++;
911            skipSeparator(false, !scanningInternalSubset());
912
913            // Mixed content model
914            if (fEntityScanner.skipString("#PCDATA")) {
915                scanMixed(name);
916            }
917            else {              // children content
918                scanChildren(name);
919            }
920            contentModel = fStringBuffer.toString();
921        }
922
923        // call handler
924        if (fDTDContentModelHandler != null) {
925            fDTDContentModelHandler.endContentModel(null);
926        }
927
928        fReportEntity = false;
929        skipSeparator(false, !scanningInternalSubset());
930        // end
931        if (!fEntityScanner.skipChar('>', null)) {
932            reportFatalError("ElementDeclUnterminated", new Object[]{name});
933        }
934        fReportEntity = true;
935        fMarkUpDepth--;
936
937        // call handler
938        if (fDTDHandler != null) {
939            fDTDHandler.elementDecl(name, contentModel, null);
940        }
941        if (nonValidatingMode) nvGrammarInfo.elementDecl(name, contentModel, null);
942    } // scanElementDecl()
943
944    /**
945     * scan Mixed content model
946     * This assumes the content model has been parsed up to #PCDATA and
947     * can simply append to fStringBuffer.
948     * <pre>
949     * [51]    Mixed    ::=    '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
950     *                       | '(' S? '#PCDATA' S? ')'
951     * </pre>
952     *
953     * @param elName The element type name this declaration is about.
954     *
955     * <strong>Note:</strong> Called after scanning past '(#PCDATA'.
956     */
957    private final void scanMixed(String elName)
958    throws IOException, XNIException {
959
960        String childName = null;
961
962        fStringBuffer.append("#PCDATA");
963        // call handler
964        if (fDTDContentModelHandler != null) {
965            fDTDContentModelHandler.pcdata(null);
966        }
967        skipSeparator(false, !scanningInternalSubset());
968        while (fEntityScanner.skipChar('|', null)) {
969            fStringBuffer.append('|');
970            // call handler
971            if (fDTDContentModelHandler != null) {
972                fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
973                null);
974            }
975            skipSeparator(false, !scanningInternalSubset());
976
977            childName = fEntityScanner.scanName(NameType.ENTITY);
978            if (childName == null) {
979                reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
980                new Object[]{elName});
981            }
982            fStringBuffer.append(childName);
983            // call handler
984            if (fDTDContentModelHandler != null) {
985                fDTDContentModelHandler.element(childName, null);
986            }
987            skipSeparator(false, !scanningInternalSubset());
988        }
989        // The following check must be done in a single call (as opposed to one
990        // for ')' and then one for '*') to guarantee that callbacks are
991        // properly nested. We do not want to trigger endEntity too early in
992        // case we cross the boundary of an entity between the two characters.
993        if (fEntityScanner.skipString(")*")) {
994            fStringBuffer.append(")*");
995            // call handler
996            if (fDTDContentModelHandler != null) {
997                fDTDContentModelHandler.endGroup(null);
998                fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE,
999                null);
1000            }
1001        }
1002        else if (childName != null) {
1003            reportFatalError("MixedContentUnterminated",
1004            new Object[]{elName});
1005        }
1006        else if (fEntityScanner.skipChar(')', null)){
1007            fStringBuffer.append(')');
1008            // call handler
1009            if (fDTDContentModelHandler != null) {
1010                fDTDContentModelHandler.endGroup(null);
1011            }
1012        }
1013        else {
1014            reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1015            new Object[]{elName});
1016        }
1017        fMarkUpDepth--;
1018        // we are done
1019    }
1020
1021    /**
1022     * scan children content model
1023     * This assumes it can simply append to fStringBuffer.
1024     * <pre>
1025     * [47]    children  ::=    (choice | seq) ('?' | '*' | '+')?
1026     * [48]    cp        ::=    (Name | choice | seq) ('?' | '*' | '+')?
1027     * [49]    choice    ::=    '(' S? cp ( S? '|' S? cp )+ S? ')'
1028     * [50]    seq       ::=    '(' S? cp ( S? ',' S? cp )* S? ')'
1029     * </pre>
1030     *
1031     * @param elName The element type name this declaration is about.
1032     *
1033     * <strong>Note:</strong> Called after scanning past the first open
1034     * paranthesis.
1035     */
1036    private final void scanChildren(String elName)
1037    throws IOException, XNIException {
1038
1039        fContentDepth = 0;
1040        pushContentStack(0);
1041        int currentOp = 0;
1042        int c;
1043        while (true) {
1044            if (fEntityScanner.skipChar('(', null)) {
1045                fMarkUpDepth++;
1046                fStringBuffer.append('(');
1047                // call handler
1048                if (fDTDContentModelHandler != null) {
1049                    fDTDContentModelHandler.startGroup(null);
1050                }
1051                // push current op on stack and reset it
1052                pushContentStack(currentOp);
1053                currentOp = 0;
1054                skipSeparator(false, !scanningInternalSubset());
1055                continue;
1056            }
1057            skipSeparator(false, !scanningInternalSubset());
1058            String childName = fEntityScanner.scanName(NameType.ELEMENTSTART);
1059            if (childName == null) {
1060                reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
1061                new Object[]{elName});
1062                return;
1063            }
1064            // call handler
1065            if (fDTDContentModelHandler != null) {
1066                fDTDContentModelHandler.element(childName, null);
1067            }
1068            fStringBuffer.append(childName);
1069            c = fEntityScanner.peekChar();
1070            if (c == '?' || c == '*' || c == '+') {
1071                // call handler
1072                if (fDTDContentModelHandler != null) {
1073                    short oc;
1074                    if (c == '?') {
1075                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1076                    }
1077                    else if (c == '*') {
1078                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1079                    }
1080                    else {
1081                        oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1082                    }
1083                    fDTDContentModelHandler.occurrence(oc, null);
1084                }
1085                fEntityScanner.scanChar(null);
1086                fStringBuffer.append((char)c);
1087            }
1088            while (true) {
1089                skipSeparator(false, !scanningInternalSubset());
1090                c = fEntityScanner.peekChar();
1091                if (c == ',' && currentOp != '|') {
1092                    currentOp = c;
1093                    // call handler
1094                    if (fDTDContentModelHandler != null) {
1095                        fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
1096                        null);
1097                    }
1098                    fEntityScanner.scanChar(null);
1099                    fStringBuffer.append(',');
1100                    break;
1101                }
1102                else if (c == '|' && currentOp != ',') {
1103                    currentOp = c;
1104                    // call handler
1105                    if (fDTDContentModelHandler != null) {
1106                        fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
1107                        null);
1108                    }
1109                    fEntityScanner.scanChar(null);
1110                    fStringBuffer.append('|');
1111                    break;
1112                }
1113                else if (c != ')') {
1114                    reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1115                    new Object[]{elName});
1116                }
1117                // call handler
1118                if (fDTDContentModelHandler != null) {
1119                    fDTDContentModelHandler.endGroup(null);
1120                }
1121                // restore previous op
1122                currentOp = popContentStack();
1123                short oc;
1124                // The following checks must be done in a single call (as
1125                // opposed to one for ')' and then one for '?', '*', and '+')
1126                // to guarantee that callbacks are properly nested. We do not
1127                // want to trigger endEntity too early in case we cross the
1128                // boundary of an entity between the two characters.
1129                if (fEntityScanner.skipString(")?")) {
1130                    fStringBuffer.append(")?");
1131                    // call handler
1132                    if (fDTDContentModelHandler != null) {
1133                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1134                        fDTDContentModelHandler.occurrence(oc, null);
1135                    }
1136                }
1137                else if (fEntityScanner.skipString(")+")) {
1138                    fStringBuffer.append(")+");
1139                    // call handler
1140                    if (fDTDContentModelHandler != null) {
1141                        oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1142                        fDTDContentModelHandler.occurrence(oc, null);
1143                    }
1144                }
1145                else if (fEntityScanner.skipString(")*")) {
1146                    fStringBuffer.append(")*");
1147                    // call handler
1148                    if (fDTDContentModelHandler != null) {
1149                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1150                        fDTDContentModelHandler.occurrence(oc, null);
1151                    }
1152                }
1153                else {
1154                    // no occurrence specified
1155                    fEntityScanner.scanChar(null);
1156                    fStringBuffer.append(')');
1157                }
1158                fMarkUpDepth--;
1159                if (fContentDepth == 0) {
1160                    return;
1161                }
1162            }
1163            skipSeparator(false, !scanningInternalSubset());
1164        }
1165    }
1166
1167    /**
1168     * Scans an attlist declaration
1169     * <p>
1170     * <pre>
1171     * [52]  AttlistDecl    ::=   '&lt;!ATTLIST' S Name AttDef* S? '>'
1172     * [53]  AttDef         ::=   S Name S AttType S DefaultDecl
1173     * </pre>
1174     * <p>
1175     * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1176     */
1177    protected final void scanAttlistDecl() throws IOException, XNIException {
1178
1179        // spaces
1180        fReportEntity = false;
1181        if (!skipSeparator(true, !scanningInternalSubset())) {
1182            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL",
1183            null);
1184        }
1185
1186        // element name
1187        String elName = fEntityScanner.scanName(NameType.ELEMENTSTART);
1188        if (elName == null) {
1189            reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL",
1190            null);
1191        }
1192
1193        // call handler
1194        if (fDTDHandler != null) {
1195            fDTDHandler.startAttlist(elName, null);
1196        }
1197
1198        // spaces
1199        if (!skipSeparator(true, !scanningInternalSubset())) {
1200            // no space, is it the end yet?
1201            if (fEntityScanner.skipChar('>', null)) {
1202                // yes, stop here
1203                // call handler
1204                if (fDTDHandler != null) {
1205                    fDTDHandler.endAttlist(null);
1206                }
1207                fMarkUpDepth--;
1208                return;
1209            }
1210            else {
1211                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF",
1212                new Object[]{elName});
1213            }
1214        }
1215
1216        // definitions
1217        while (!fEntityScanner.skipChar('>', null)) {
1218            String name = fEntityScanner.scanName(NameType.ATTRIBUTE);
1219            if (name == null) {
1220                reportFatalError("AttNameRequiredInAttDef",
1221                new Object[]{elName});
1222            }
1223            // spaces
1224            if (!skipSeparator(true, !scanningInternalSubset())) {
1225                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF",
1226                new Object[]{elName, name});
1227            }
1228            // type
1229            String type = scanAttType(elName, name);
1230
1231            // spaces
1232            if (!skipSeparator(true, !scanningInternalSubset())) {
1233                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF",
1234                new Object[]{elName, name});
1235            }
1236
1237            // default decl
1238            String defaultType = scanAttDefaultDecl(elName, name,
1239            type,
1240            fLiteral, fLiteral2);
1241            // REVISIT: Should we do anything with the non-normalized
1242            //          default attribute value? -Ac
1243            // yes--according to bug 5073.  - neilg
1244            String[] enumr = null;
1245            if( fDTDHandler != null || nonValidatingMode){
1246                if (fEnumerationCount != 0) {
1247                    enumr = new String[fEnumerationCount];
1248                    System.arraycopy(fEnumeration, 0, enumr,
1249                    0, fEnumerationCount);
1250                }
1251            }
1252            // call handler
1253            // Determine whether the default value to be passed should be null.
1254            // REVISIT: should probably check whether fLiteral.ch is null instead. LM.
1255            if (defaultType!=null && (defaultType.equals("#REQUIRED") ||
1256            defaultType.equals("#IMPLIED"))) {
1257                if (fDTDHandler != null){
1258                    fDTDHandler.attributeDecl(elName, name, type, enumr,
1259                    defaultType, null, null, null);
1260                }
1261                if(nonValidatingMode){
1262                    nvGrammarInfo.attributeDecl(elName, name, type, enumr,
1263                    defaultType, null, null, null);
1264
1265                }
1266            }
1267            else {
1268                if (fDTDHandler != null){
1269                    fDTDHandler.attributeDecl(elName, name, type, enumr,
1270                    defaultType, fLiteral, fLiteral2, null);
1271                }
1272                if(nonValidatingMode){
1273                    nvGrammarInfo.attributeDecl(elName, name, type, enumr,
1274                    defaultType, fLiteral, fLiteral2, null);
1275                }
1276            }
1277            skipSeparator(false, !scanningInternalSubset());
1278        }
1279
1280        // call handler
1281        if (fDTDHandler != null) {
1282            fDTDHandler.endAttlist(null);
1283        }
1284        fMarkUpDepth--;
1285        fReportEntity = true;
1286
1287    } // scanAttlistDecl()
1288
1289    /**
1290     * Scans an attribute type definition
1291     * <p>
1292     * <pre>
1293     * [54]  AttType        ::=   StringType | TokenizedType | EnumeratedType
1294     * [55]  StringType     ::=   'CDATA'
1295     * [56]  TokenizedType  ::=   'ID'
1296     *                          | 'IDREF'
1297     *                          | 'IDREFS'
1298     *                          | 'ENTITY'
1299     *                          | 'ENTITIES'
1300     *                          | 'NMTOKEN'
1301     *                          | 'NMTOKENS'
1302     * [57]  EnumeratedType ::=    NotationType | Enumeration
1303     * [58]  NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
1304     * [59]  Enumeration    ::=    '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
1305     * </pre>
1306     * <p>
1307     * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1308     *
1309     * @param elName The element type name this declaration is about.
1310     * @param atName The attribute name this declaration is about.
1311     */
1312    private final String scanAttType(String elName, String atName)
1313    throws IOException, XNIException {
1314
1315        String type = null;
1316        fEnumerationCount = 0;
1317        /*
1318         * Watchout: the order here is important: when a string happens to
1319         * be a substring of another string, the longer one needs to be
1320         * looked for first!!
1321         */
1322        if (fEntityScanner.skipString("CDATA")) {
1323            type = "CDATA";
1324        }
1325        else if (fEntityScanner.skipString("IDREFS")) {
1326            type = "IDREFS";
1327        }
1328        else if (fEntityScanner.skipString("IDREF")) {
1329            type = "IDREF";
1330        }
1331        else if (fEntityScanner.skipString("ID")) {
1332            type = "ID";
1333        }
1334        else if (fEntityScanner.skipString("ENTITY")) {
1335            type = "ENTITY";
1336        }
1337        else if (fEntityScanner.skipString("ENTITIES")) {
1338            type = "ENTITIES";
1339        }
1340        else if (fEntityScanner.skipString("NMTOKENS")) {
1341            type = "NMTOKENS";
1342        }
1343        else if (fEntityScanner.skipString("NMTOKEN")) {
1344            type = "NMTOKEN";
1345        }
1346        else if (fEntityScanner.skipString("NOTATION")) {
1347            type = "NOTATION";
1348            // spaces
1349            if (!skipSeparator(true, !scanningInternalSubset())) {
1350                reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE",
1351                new Object[]{elName, atName});
1352            }
1353            // open paren
1354            int c = fEntityScanner.scanChar(null);
1355            if (c != '(') {
1356                reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
1357                new Object[]{elName, atName});
1358            }
1359            fMarkUpDepth++;
1360            do {
1361                skipSeparator(false, !scanningInternalSubset());
1362                String aName = fEntityScanner.scanName(NameType.ATTRIBUTE);
1363                if (aName == null) {
1364                    reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
1365                    new Object[]{elName, atName});
1366                }
1367                ensureEnumerationSize(fEnumerationCount + 1);
1368                fEnumeration[fEnumerationCount++] = aName;
1369                skipSeparator(false, !scanningInternalSubset());
1370                c = fEntityScanner.scanChar(null);
1371            } while (c == '|');
1372            if (c != ')') {
1373                reportFatalError("NotationTypeUnterminated",
1374                new Object[]{elName, atName});
1375            }
1376            fMarkUpDepth--;
1377        }
1378        else {              // Enumeration
1379            type = "ENUMERATION";
1380            // open paren
1381            int c = fEntityScanner.scanChar(null);
1382            if (c != '(') {
1383                //                       "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
1384                reportFatalError("AttTypeRequiredInAttDef",
1385                new Object[]{elName, atName});
1386            }
1387            fMarkUpDepth++;
1388            do {
1389                skipSeparator(false, !scanningInternalSubset());
1390                String token = fEntityScanner.scanNmtoken();
1391                if (token == null) {
1392                    reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION",
1393                    new Object[]{elName, atName});
1394                }
1395                ensureEnumerationSize(fEnumerationCount + 1);
1396                fEnumeration[fEnumerationCount++] = token;
1397                skipSeparator(false, !scanningInternalSubset());
1398                c = fEntityScanner.scanChar(null);
1399            } while (c == '|');
1400            if (c != ')') {
1401                reportFatalError("EnumerationUnterminated",
1402                new Object[]{elName, atName});
1403            }
1404            fMarkUpDepth--;
1405        }
1406        return type;
1407
1408    } // scanAttType():String
1409
1410
1411    /**
1412     * Scans an attribute default declaration
1413     * <p>
1414     * <pre>
1415     * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
1416     * </pre>
1417     *
1418     * @param name The name of the attribute being scanned.
1419     * @param defaultVal The string to fill in with the default value.
1420     */
1421    protected final String scanAttDefaultDecl(String elName, String atName,
1422    String type,
1423    XMLString defaultVal,
1424    XMLString nonNormalizedDefaultVal)
1425    throws IOException, XNIException {
1426
1427        String defaultType = null;
1428        fString.clear();
1429        defaultVal.clear();
1430        if (fEntityScanner.skipString("#REQUIRED")) {
1431            defaultType = "#REQUIRED";
1432        }
1433        else if (fEntityScanner.skipString("#IMPLIED")) {
1434            defaultType = "#IMPLIED";
1435        }
1436        else {
1437            if (fEntityScanner.skipString("#FIXED")) {
1438                defaultType = "#FIXED";
1439                // spaces
1440                if (!skipSeparator(true, !scanningInternalSubset())) {
1441                    reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL",
1442                    new Object[]{elName, atName});
1443                }
1444            }
1445            // AttValue
1446            boolean isVC = !fStandalone  &&  (fSeenExternalDTD || fSeenExternalPE) ;
1447            scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName,
1448            fAttributes, 0, isVC, elName, false);
1449        }
1450        return defaultType;
1451
1452    } // ScanAttDefaultDecl
1453
1454    /**
1455     * Scans an entity declaration
1456     * <p>
1457     * <pre>
1458     * [70]    EntityDecl  ::=    GEDecl | PEDecl
1459     * [71]    GEDecl      ::=    '&lt;!ENTITY' S Name S EntityDef S? '>'
1460     * [72]    PEDecl      ::=    '&lt;!ENTITY' S '%' S Name S PEDef S? '>'
1461     * [73]    EntityDef   ::=    EntityValue | (ExternalID NDataDecl?)
1462     * [74]    PEDef       ::=    EntityValue | ExternalID
1463     * [75]    ExternalID  ::=    'SYSTEM' S SystemLiteral
1464     *                          | 'PUBLIC' S PubidLiteral S SystemLiteral
1465     * [76]    NDataDecl   ::=    S 'NDATA' S Name
1466     * </pre>
1467     * <p>
1468     * <strong>Note:</strong> Called after scanning past '&lt;!ENTITY'
1469     */
1470    private final void scanEntityDecl() throws IOException, XNIException {
1471
1472        boolean isPEDecl = false;
1473        boolean sawPERef = false;
1474        fReportEntity = false;
1475        if (fEntityScanner.skipSpaces()) {
1476            if (!fEntityScanner.skipChar('%', NameType.REFERENCE)) {
1477                isPEDecl = false; // <!ENTITY x "x">
1478            }
1479            else if (skipSeparator(true, !scanningInternalSubset())) {
1480                // <!ENTITY % x "x">
1481                isPEDecl = true;
1482            }
1483            else if (scanningInternalSubset()) {
1484                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1485                null);
1486                isPEDecl = true;
1487            }
1488            else if (fEntityScanner.peekChar() == '%') {
1489                // <!ENTITY %%x; "x"> is legal
1490                skipSeparator(false, !scanningInternalSubset());
1491                isPEDecl = true;
1492            }
1493            else {
1494                sawPERef = true;
1495            }
1496        }
1497        else if (scanningInternalSubset() || !fEntityScanner.skipChar('%', NameType.REFERENCE)) {
1498            // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
1499            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1500            null);
1501            isPEDecl = false;
1502        }
1503        else if (fEntityScanner.skipSpaces()) {
1504            // <!ENTITY% ...>
1505            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL",
1506            null);
1507            isPEDecl = false;
1508        }
1509        else {
1510            sawPERef = true;
1511        }
1512        if (sawPERef) {
1513            while (true) {
1514                String peName = fEntityScanner.scanName(NameType.REFERENCE);
1515                if (peName == null) {
1516                    reportFatalError("NameRequiredInPEReference", null);
1517                }
1518                else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
1519                    reportFatalError("SemicolonRequiredInPEReference",
1520                    new Object[]{peName});
1521                }
1522                else {
1523                    startPE(peName, false);
1524                }
1525                fEntityScanner.skipSpaces();
1526                if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
1527                    break;
1528                if (!isPEDecl) {
1529                    if (skipSeparator(true, !scanningInternalSubset())) {
1530                        isPEDecl = true;
1531                        break;
1532                    }
1533                    isPEDecl = fEntityScanner.skipChar('%', NameType.REFERENCE);
1534                }
1535            }
1536        }
1537
1538        // name
1539        String name = fEntityScanner.scanName(NameType.ENTITY);
1540        if (name == null) {
1541            reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null);
1542        }
1543
1544        // spaces
1545        if (!skipSeparator(true, !scanningInternalSubset())) {
1546            reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
1547            new Object[]{name});
1548        }
1549
1550        // external id
1551        scanExternalID(fStrings, false);
1552        String systemId = fStrings[0];
1553        String publicId = fStrings[1];
1554
1555        if (isPEDecl && systemId != null) {
1556            fSeenExternalPE = true;
1557        }
1558
1559        String notation = null;
1560        // NDATA
1561        boolean sawSpace = skipSeparator(true, !scanningInternalSubset());
1562        if (!isPEDecl && fEntityScanner.skipString("NDATA")) {
1563            // check whether there was space before NDATA
1564            if (!sawSpace) {
1565                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL",
1566                new Object[]{name});
1567            }
1568
1569            // spaces
1570            if (!skipSeparator(true, !scanningInternalSubset())) {
1571                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
1572                new Object[]{name});
1573            }
1574            notation = fEntityScanner.scanName(NameType.NOTATION);
1575            if (notation == null) {
1576                reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
1577                new Object[]{name});
1578            }
1579        }
1580
1581        // internal entity
1582        if (systemId == null) {
1583            scanEntityValue(name, isPEDecl, fLiteral, fLiteral2);
1584            // since we need it's value anyway, let's snag it so it doesn't get corrupted
1585            // if a new load takes place before we store the entity values
1586            fStringBuffer.clear();
1587            fStringBuffer2.clear();
1588            fStringBuffer.append(fLiteral.ch, fLiteral.offset, fLiteral.length);
1589            fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset, fLiteral2.length);
1590        }
1591
1592        // skip possible trailing space
1593        skipSeparator(false, !scanningInternalSubset());
1594
1595        // end
1596        if (!fEntityScanner.skipChar('>', null)) {
1597            reportFatalError("EntityDeclUnterminated", new Object[]{name});
1598        }
1599        fMarkUpDepth--;
1600
1601        // register entity and make callback
1602        if (isPEDecl) {
1603            name = "%" + name;
1604        }
1605        if (systemId != null) {
1606            String baseSystemId = fEntityScanner.getBaseSystemId();
1607            if (notation != null) {
1608                fEntityStore.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation);
1609            }
1610            else {
1611                fEntityStore.addExternalEntity(name, publicId, systemId,
1612                baseSystemId);
1613            }
1614            if (fDTDHandler != null) {
1615                //Venu Revisit : why false has been removed in expandSYstem
1616                fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId ));
1617
1618                if (notation != null) {
1619                    fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier,
1620                    notation, null);
1621                }
1622                else {
1623                    fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null);
1624                }
1625            }
1626        }
1627        else {
1628            fEntityStore.addInternalEntity(name, fStringBuffer.toString());
1629            if (fDTDHandler != null) {
1630                fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null);
1631            }
1632        }
1633        fReportEntity = true;
1634
1635    } // scanEntityDecl()
1636
1637    /**
1638     * Scans an entity value.
1639     *
1640     * @param value The string to fill in with the value.
1641     * @param nonNormalizedValue The string to fill in with the
1642     *                           non-normalized value.
1643     *
1644     * <strong>Note:</strong> This method uses fString, fStringBuffer (through
1645     * the use of scanCharReferenceValue), and fStringBuffer2, anything in them
1646     * at the time of calling is lost.
1647     */
1648    protected final void scanEntityValue(String entityName, boolean isPEDecl, XMLString value,
1649    XMLString nonNormalizedValue)
1650    throws IOException, XNIException {
1651        int quote = fEntityScanner.scanChar(null);
1652        if (quote != '\'' && quote != '"') {
1653            reportFatalError("OpenQuoteMissingInDecl", null);
1654        }
1655        // store at which depth of entities we start
1656        int entityDepth = fEntityDepth;
1657
1658        XMLString literal = fString;
1659        XMLString literal2 = fString;
1660        int countChar = 0;
1661        if (fLimitAnalyzer == null ) {
1662            fLimitAnalyzer = fEntityManager.fLimitAnalyzer;
1663         }
1664        fLimitAnalyzer.startEntity(entityName);
1665
1666        if (fEntityScanner.scanLiteral(quote, fString, false) != quote) {
1667            fStringBuffer.clear();
1668            fStringBuffer2.clear();
1669            int offset;
1670            do {
1671                countChar = 0;
1672                offset = fStringBuffer.length;
1673                fStringBuffer.append(fString);
1674                fStringBuffer2.append(fString);
1675                if (fEntityScanner.skipChar('&', NameType.REFERENCE)) {
1676                    if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
1677                        fStringBuffer2.append("&#");
1678                        scanCharReferenceValue(fStringBuffer, fStringBuffer2);
1679                    }
1680                    else {
1681                        fStringBuffer.append('&');
1682                        fStringBuffer2.append('&');
1683                        String eName = fEntityScanner.scanName(NameType.REFERENCE);
1684                        if (eName == null) {
1685                            reportFatalError("NameRequiredInReference",
1686                            null);
1687                        }
1688                        else {
1689                            fStringBuffer.append(eName);
1690                            fStringBuffer2.append(eName);
1691                        }
1692                        if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
1693                            reportFatalError("SemicolonRequiredInReference",
1694                            new Object[]{eName});
1695                        }
1696                        else {
1697                            fStringBuffer.append(';');
1698                            fStringBuffer2.append(';');
1699                        }
1700                    }
1701                }
1702                else if (fEntityScanner.skipChar('%', NameType.REFERENCE)) {
1703                    while (true) {
1704                        fStringBuffer2.append('%');
1705                        String peName = fEntityScanner.scanName(NameType.REFERENCE);
1706                        if (peName == null) {
1707                            reportFatalError("NameRequiredInPEReference",
1708                            null);
1709                        }
1710                        else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
1711                            reportFatalError("SemicolonRequiredInPEReference",
1712                            new Object[]{peName});
1713                        }
1714                        else {
1715                            if (scanningInternalSubset()) {
1716                                reportFatalError("PEReferenceWithinMarkup",
1717                                new Object[]{peName});
1718                            }
1719                            fStringBuffer2.append(peName);
1720                            fStringBuffer2.append(';');
1721                        }
1722                        startPE(peName, true);
1723                        // REVISIT: [Q] Why do we skip spaces here? -Ac
1724                        // REVISIT: This will make returning the non-
1725                        //          normalized value harder. -Ac
1726                        fEntityScanner.skipSpaces();
1727                        if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
1728                            break;
1729                    }
1730                }
1731                else {
1732                    int c = fEntityScanner.peekChar();
1733                    if (XMLChar.isHighSurrogate(c)) {
1734                        countChar++;
1735                        scanSurrogates(fStringBuffer2);
1736                    }
1737                    else if (isInvalidLiteral(c)) {
1738                        reportFatalError("InvalidCharInLiteral",
1739                        new Object[]{Integer.toHexString(c)});
1740                        fEntityScanner.scanChar(null);
1741                    }
1742                    // if it's not the delimiting quote or if it is but from a
1743                    // different entity than the one this literal started from,
1744                    // simply append the character to our buffer
1745                    else if (c != quote || entityDepth != fEntityDepth) {
1746                        fStringBuffer.append((char)c);
1747                        fStringBuffer2.append((char)c);
1748                        fEntityScanner.scanChar(null);
1749                    }
1750                }
1751                checkEntityLimit(isPEDecl, entityName, fStringBuffer.length - offset + countChar);
1752            } while (fEntityScanner.scanLiteral(quote, fString, false) != quote);
1753            checkEntityLimit(isPEDecl, entityName, fString.length);
1754            fStringBuffer.append(fString);
1755            fStringBuffer2.append(fString);
1756            literal = fStringBuffer;
1757            literal2 = fStringBuffer2;
1758        } else {
1759            checkEntityLimit(isPEDecl, entityName, literal);
1760        }
1761        value.setValues(literal);
1762        nonNormalizedValue.setValues(literal2);
1763        if (fLimitAnalyzer != null) {
1764            if (isPEDecl) {
1765                fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName);
1766            } else {
1767                fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName);
1768            }
1769        }
1770
1771        if (!fEntityScanner.skipChar(quote, null)) {
1772            reportFatalError("CloseQuoteMissingInDecl", null);
1773        }
1774    } // scanEntityValue(XMLString,XMLString):void
1775
1776    /**
1777     * Scans a notation declaration
1778     * <p>
1779     * <pre>
1780     * [82] NotationDecl ::= '&lt;!NOTATION' S Name S (ExternalID|PublicID) S? '>'
1781     * [83]  PublicID    ::= 'PUBLIC' S PubidLiteral
1782     * </pre>
1783     * <p>
1784     * <strong>Note:</strong> Called after scanning past '&lt;!NOTATION'
1785     */
1786    private final void scanNotationDecl() throws IOException, XNIException {
1787
1788        // spaces
1789        fReportEntity = false;
1790        if (!skipSeparator(true, !scanningInternalSubset())) {
1791            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL",
1792            null);
1793        }
1794
1795        // notation name
1796        String name = fEntityScanner.scanName(NameType.NOTATION);
1797        if (name == null) {
1798            reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
1799            null);
1800        }
1801
1802        // spaces
1803        if (!skipSeparator(true, !scanningInternalSubset())) {
1804            reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL",
1805            new Object[]{name});
1806        }
1807
1808        // external id
1809        scanExternalID(fStrings, true);
1810        String systemId = fStrings[0];
1811        String publicId = fStrings[1];
1812        String baseSystemId = fEntityScanner.getBaseSystemId();
1813
1814        if (systemId == null && publicId == null) {
1815            reportFatalError("ExternalIDorPublicIDRequired",
1816            new Object[]{name});
1817        }
1818
1819        // skip possible trailing space
1820        skipSeparator(false, !scanningInternalSubset());
1821
1822        // end
1823        if (!fEntityScanner.skipChar('>', null)) {
1824            reportFatalError("NotationDeclUnterminated", new Object[]{name});
1825        }
1826        fMarkUpDepth--;
1827
1828        fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId ));
1829        if (nonValidatingMode) nvGrammarInfo.notationDecl(name, fResourceIdentifier, null);
1830        // call handler
1831        if (fDTDHandler != null) {
1832            //Venu Revisit wby false has been removed.
1833            //fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
1834            fDTDHandler.notationDecl(name, fResourceIdentifier, null);
1835        }
1836        fReportEntity = true;
1837
1838    } // scanNotationDecl()
1839
1840    /**
1841     * Scans a conditional section. If it's a section to ignore the whole
1842     * section gets scanned through and this method only returns after the
1843     * closing bracket has been found. When it's an include section though, it
1844     * returns to let the main loop take care of scanning it. In that case the
1845     * end of the section if handled by the main loop (scanDecls).
1846     * <p>
1847     * <pre>
1848     * [61] conditionalSect   ::= includeSect | ignoreSect
1849     * [62] includeSect       ::= '&lt;![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1850     * [63] ignoreSect   ::= '&lt;![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
1851     * [64] ignoreSectContents ::= Ignore ('&lt;![' ignoreSectContents ']]>' Ignore)*
1852     * [65] Ignore            ::=    Char* - (Char* ('&lt;![' | ']]>') Char*)
1853     * </pre>
1854     * <p>
1855     * <strong>Note:</strong> Called after scanning past '&lt;![' */
1856    private final void scanConditionalSect(int currPEDepth)
1857    throws IOException, XNIException {
1858
1859        fReportEntity = false;
1860        skipSeparator(false, !scanningInternalSubset());
1861
1862        if (fEntityScanner.skipString("INCLUDE")) {
1863            skipSeparator(false, !scanningInternalSubset());
1864            if(currPEDepth != fPEDepth && fValidation) {
1865                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1866                "INVALID_PE_IN_CONDITIONAL",
1867                new Object[]{ fEntityManager.fCurrentEntity.name},
1868                XMLErrorReporter.SEVERITY_ERROR);
1869            }
1870            // call handler
1871            if (!fEntityScanner.skipChar('[', null)) {
1872                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1873            }
1874
1875            if (fDTDHandler != null) {
1876                fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE,
1877                null);
1878            }
1879            fIncludeSectDepth++;
1880            // just stop there and go back to the main loop
1881            fReportEntity = true;
1882        }
1883        else if (fEntityScanner.skipString("IGNORE")) {
1884            skipSeparator(false, !scanningInternalSubset());
1885            if(currPEDepth != fPEDepth && fValidation) {
1886                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1887                "INVALID_PE_IN_CONDITIONAL",
1888                new Object[]{ fEntityManager.fCurrentEntity.name},
1889                XMLErrorReporter.SEVERITY_ERROR);
1890            }
1891            // call handler
1892            if (fDTDHandler != null) {
1893                fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE,
1894                null);
1895            }
1896            if (!fEntityScanner.skipChar('[', null)) {
1897                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1898            }
1899            fReportEntity = true;
1900            int initialDepth = ++fIncludeSectDepth;
1901            if (fDTDHandler != null) {
1902                fIgnoreConditionalBuffer.clear();
1903            }
1904            while (true) {
1905                if (fEntityScanner.skipChar('<', null)) {
1906                    if (fDTDHandler != null) {
1907                        fIgnoreConditionalBuffer.append('<');
1908                    }
1909                    //
1910                    // These tests are split so that we handle cases like
1911                    // '<<![' and '<!<![' which we might otherwise miss.
1912                    //
1913                    if (fEntityScanner.skipChar('!', null)) {
1914                        if(fEntityScanner.skipChar('[', null)) {
1915                            if (fDTDHandler != null) {
1916                                fIgnoreConditionalBuffer.append("![");
1917                            }
1918                            fIncludeSectDepth++;
1919                        } else {
1920                            if (fDTDHandler != null) {
1921                                fIgnoreConditionalBuffer.append("!");
1922                            }
1923                        }
1924                    }
1925                }
1926                else if (fEntityScanner.skipChar(']', null)) {
1927                    if (fDTDHandler != null) {
1928                        fIgnoreConditionalBuffer.append(']');
1929                    }
1930                    //
1931                    // The same thing goes for ']<![' and '<]]>', etc.
1932                    //
1933                    if (fEntityScanner.skipChar(']', null)) {
1934                        if (fDTDHandler != null) {
1935                            fIgnoreConditionalBuffer.append(']');
1936                        }
1937                        while (fEntityScanner.skipChar(']', null)) {
1938                            /* empty loop body */
1939                            if (fDTDHandler != null) {
1940                                fIgnoreConditionalBuffer.append(']');
1941                            }
1942                        }
1943                        if (fEntityScanner.skipChar('>', null)) {
1944                            if (fIncludeSectDepth-- == initialDepth) {
1945                                fMarkUpDepth--;
1946                                // call handler
1947                                if (fDTDHandler != null) {
1948                                    fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0,
1949                                    fIgnoreConditionalBuffer.length - 2);
1950                                    fDTDHandler.ignoredCharacters(fLiteral, null);
1951                                    fDTDHandler.endConditional(null);
1952                                }
1953                                return;
1954                            } else if(fDTDHandler != null) {
1955                                fIgnoreConditionalBuffer.append('>');
1956                            }
1957                        }
1958                    }
1959                }
1960                else {
1961                    int c = fEntityScanner.scanChar(null);
1962                    if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
1963                        reportFatalError("IgnoreSectUnterminated", null);
1964                        return;
1965                    }
1966                    if (fDTDHandler != null) {
1967                        fIgnoreConditionalBuffer.append((char)c);
1968                    }
1969                }
1970            }
1971        }
1972        else {
1973            reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1974        }
1975
1976    } // scanConditionalSect()
1977
1978    /**
1979     * Dispatch an XML "event".
1980     *
1981     * @param complete True if this method is intended to scan
1982     *                 and dispatch as much as possible.
1983     *
1984     * @return True if there is more to scan.
1985     *
1986     * @throws IOException  Thrown on i/o error.
1987     * @throws XNIException Thrown on parse error.
1988     *
1989     */
1990    protected final boolean scanDecls(boolean complete)
1991    throws IOException, XNIException {
1992
1993        skipSeparator(false, true);
1994        boolean again = true;
1995        //System.out.println("scanDecls"+fScannerState);
1996        while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
1997            again = complete;
1998            if (fEntityScanner.skipChar('<', null)) {
1999                fMarkUpDepth++;
2000                if (fEntityScanner.skipChar('?', null)) {
2001                    fStringBuffer.clear();
2002                    scanPI(fStringBuffer);
2003                    fMarkUpDepth--; // we're done with this decl
2004                }
2005                else if (fEntityScanner.skipChar('!', null)) {
2006                    if (fEntityScanner.skipChar('-', null)) {
2007                        if (!fEntityScanner.skipChar('-', null)) {
2008                            reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
2009                            null);
2010                        } else {
2011                            scanComment();
2012                        }
2013                    }
2014                    else if (fEntityScanner.skipString("ELEMENT")) {
2015                        scanElementDecl();
2016                    }
2017                    else if (fEntityScanner.skipString("ATTLIST")) {
2018                        scanAttlistDecl();
2019                    }
2020                    else if (fEntityScanner.skipString("ENTITY")) {
2021                        scanEntityDecl();
2022                    }
2023                    else if (fEntityScanner.skipString("NOTATION")) {
2024                        scanNotationDecl();
2025                    }
2026                    else if (fEntityScanner.skipChar('[', null) &&
2027                    !scanningInternalSubset()) {
2028                        scanConditionalSect(fPEDepth);
2029                    }
2030                    else {
2031                        fMarkUpDepth--;
2032                        reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
2033                        null);
2034                    }
2035                }
2036                else {
2037                    fMarkUpDepth--;
2038                    reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
2039                }
2040            }
2041            else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']', null)) {
2042                // end of conditional section?
2043                if (!fEntityScanner.skipChar(']', null)
2044                || !fEntityScanner.skipChar('>', null)) {
2045                    reportFatalError("IncludeSectUnterminated", null);
2046                }
2047                // call handler
2048                if (fDTDHandler != null) {
2049                    fDTDHandler.endConditional(null);
2050                }
2051                // decreaseMarkupDepth();
2052                fIncludeSectDepth--;
2053                fMarkUpDepth--;
2054            }
2055            else if (scanningInternalSubset() &&
2056            fEntityScanner.peekChar() == ']') {
2057                // this is the end of the internal subset, let's stop here
2058                return false;
2059            }
2060            else if (fEntityScanner.skipSpaces()) {
2061                // simply skip
2062            }
2063            else {
2064                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
2065            }
2066            skipSeparator(false, true);
2067        }
2068        return fScannerState != SCANNER_STATE_END_OF_INPUT;
2069    }
2070
2071    /**
2072     * Skip separator. This is typically just whitespace but it can also be one
2073     * or more parameter entity references.
2074     * <p>
2075     * If there are some it "expands them" by calling the corresponding entity
2076     * from the entity manager.
2077     * <p>
2078     * This is recursive and will process has many refs as possible.
2079     *
2080     * @param spaceRequired Specify whether some leading whitespace should be
2081     *                      found
2082     * @param lookForPERefs Specify whether parameter entity references should
2083     *                      be looked for
2084     * @return True if any leading whitespace was found or the end of a
2085     *         parameter entity was crossed.
2086     */
2087    private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs)
2088    throws IOException, XNIException {
2089        int depth = fPEDepth;
2090        boolean sawSpace = fEntityScanner.skipSpaces();
2091        if (!lookForPERefs || !fEntityScanner.skipChar('%', NameType.REFERENCE)) {
2092            return !spaceRequired || sawSpace || (depth != fPEDepth);
2093        }
2094        while (true) {
2095            String name = fEntityScanner.scanName(NameType.ENTITY);
2096            if (name == null) {
2097                reportFatalError("NameRequiredInPEReference", null);
2098            }
2099            else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
2100                reportFatalError("SemicolonRequiredInPEReference",
2101                new Object[]{name});
2102            }
2103            startPE(name, false);
2104            fEntityScanner.skipSpaces();
2105            if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
2106                return true;
2107        }
2108    }
2109
2110
2111    /*
2112     * Element Children Content Stack
2113     */
2114    private final void pushContentStack(int c) {
2115        if (fContentStack.length == fContentDepth) {
2116            int[] newStack = new int[fContentDepth * 2];
2117            System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth);
2118            fContentStack = newStack;
2119        }
2120        fContentStack[fContentDepth++] = c;
2121    }
2122
2123    private final int popContentStack() {
2124        return fContentStack[--fContentDepth];
2125    }
2126
2127
2128    /*
2129     * Parameter Entity Stack
2130     */
2131    private final void pushPEStack(int depth, boolean report) {
2132        if (fPEStack.length == fPEDepth) {
2133            int[] newIntStack = new int[fPEDepth * 2];
2134            System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth);
2135            fPEStack = newIntStack;
2136            // report end/start calls
2137            boolean[] newBooleanStack = new boolean[fPEDepth * 2];
2138            System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth);
2139            fPEReport = newBooleanStack;
2140
2141        }
2142        fPEReport[fPEDepth] = report;
2143        fPEStack[fPEDepth++] = depth;
2144    }
2145
2146    /** pop the stack */
2147    private final int popPEStack() {
2148        return fPEStack[--fPEDepth];
2149    }
2150
2151    /** look at the top of the stack */
2152    private final boolean peekReportEntity() {
2153        return fPEReport[fPEDepth-1];
2154    }
2155
2156
2157    /*
2158     * Utility method
2159     */
2160    private final void ensureEnumerationSize(int size) {
2161        if (fEnumeration.length == size) {
2162            String[] newEnum = new String[size * 2];
2163            System.arraycopy(fEnumeration, 0, newEnum, 0, size);
2164            fEnumeration = newEnum;
2165        }
2166    }
2167
2168    // private methods
2169    private void init() {
2170        // reset state related data
2171        fStartDTDCalled = false;
2172        fExtEntityDepth = 0;
2173        fIncludeSectDepth = 0;
2174        fMarkUpDepth = 0;
2175        fPEDepth = 0;
2176
2177        fStandalone = false;
2178        fSeenExternalDTD = false;
2179        fSeenExternalPE = false;
2180
2181        // set starting state
2182        setScannerState(SCANNER_STATE_TEXT_DECL);
2183        //new SymbolTable());
2184
2185        fLimitAnalyzer = fEntityManager.fLimitAnalyzer;
2186        fSecurityManager = fEntityManager.fSecurityManager;
2187    }
2188
2189    public DTDGrammar getGrammar(){
2190        return nvGrammarInfo;
2191    }
2192
2193} // class XMLDTDScannerImpl
2194