1 /*
2  * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xerces.internal.impl;
22 
23 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
24 import com.sun.org.apache.xerces.internal.util.SymbolTable;
25 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
26 import com.sun.org.apache.xerces.internal.util.XMLChar;
27 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
28 import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
29 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
30 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
31 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
32 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
33 import com.sun.org.apache.xerces.internal.xni.XMLString;
34 import com.sun.org.apache.xerces.internal.xni.XNIException;
35 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
36 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
37 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
38 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner;
39 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
40 import com.sun.org.apache.xerces.internal.xni.Augmentations;
41 import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar;
42 import java.io.EOFException;
43 import java.io.IOException;
44 
45 /**
46  * This class is responsible for scanning the declarations found
47  * in the internal and external subsets of a DTD in an XML document.
48  * The scanner acts as the sources for the DTD information which is
49  * communicated to the DTD handlers.
50  * <p>
51  * This component requires the following features and properties from the
52  * component manager that uses it:
53  * <ul>
54  *  <li>http://xml.org/sax/features/validation</li>
55  *  <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
56  *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
57  *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
58  *  <li>http://apache.org/xml/properties/internal/entity-manager</li>
59  * </ul>
60  *
61  * @author Arnaud  Le Hors, IBM
62  * @author Andy Clark, IBM
63  * @author Glenn Marcy, IBM
64  * @author Eric Ye, IBM
65  *
66  * @LastModified: Feb 2020
67  */
68 public class XMLDTDScannerImpl
69 extends XMLScanner
70 implements XMLDTDScanner, XMLComponent, XMLEntityHandler {
71 
72     //
73     // Constants
74     //
75 
76     // scanner states
77 
78     /** Scanner state: end of input. */
79     protected static final int SCANNER_STATE_END_OF_INPUT = 0;
80 
81     /** Scanner state: text declaration. */
82     protected static final int SCANNER_STATE_TEXT_DECL = 1;
83 
84     /** Scanner state: markup declaration. */
85     protected static final int SCANNER_STATE_MARKUP_DECL = 2;
86 
87     // recognized features and properties
88 
89     /** Recognized features. */
90     private static final String[] RECOGNIZED_FEATURES = {
91         VALIDATION,
92         NOTIFY_CHAR_REFS,
93     };
94 
95     /** Feature defaults. */
96     private static final Boolean[] FEATURE_DEFAULTS = {
97         null,
98         Boolean.FALSE,
99     };
100 
101     /** Recognized properties. */
102     private static final String[] RECOGNIZED_PROPERTIES = {
103         SYMBOL_TABLE,
104         ERROR_REPORTER,
105         ENTITY_MANAGER,
106     };
107 
108     /** Property defaults. */
109     private static final Object[] PROPERTY_DEFAULTS = {
110         null,
111         null,
112         null,
113     };
114 
115     // debugging
116 
117     /** Debug scanner state. */
118     private static final boolean DEBUG_SCANNER_STATE = false;
119 
120     //
121     // Data
122     //
123 
124     // handlers
125 
126     /** DTD handler. */
127     public XMLDTDHandler fDTDHandler = null;
128 
129     /** DTD content model handler. */
130     protected XMLDTDContentModelHandler fDTDContentModelHandler;
131 
132     // state
133 
134     /** Scanner state. */
135     protected int fScannerState;
136 
137     /** Standalone. */
138     protected boolean fStandalone;
139 
140     /** Seen external DTD. */
141     protected boolean fSeenExternalDTD;
142 
143     /** Seen external parameter entity. */
144     protected boolean fSeenExternalPE;
145 
146     // private data
147 
148     /** Start DTD called. */
149     private boolean fStartDTDCalled;
150 
151     /** Default attribute */
152     private XMLAttributesImpl fAttributes = new XMLAttributesImpl();
153 
154     /**
155      * Stack of content operators (either '|' or ',') in children
156      * content.
157      */
158     private int[] fContentStack = new int[5];
159 
160     /** Size of content stack. */
161     private int fContentDepth;
162 
163     /** Parameter entity stack to check well-formedness. */
164     private int[] fPEStack = new int[5];
165 
166 
167     /** Parameter entity stack to report start/end entity calls. */
168     private boolean[] fPEReport = new boolean[5];
169 
170     /** Number of opened parameter entities. */
171     private int fPEDepth;
172 
173     /** Markup depth. */
174     private int fMarkUpDepth;
175 
176     /** Number of opened external entities. */
177     private int fExtEntityDepth;
178 
179     /** Number of opened include sections. */
180     private int fIncludeSectDepth;
181 
182     // temporary variables
183 
184     /** Array of 3 strings. */
185     private String[] fStrings = new String[3];
186 
187     /** String. */
188     private XMLString fString = new XMLString();
189 
190     /** String buffer. */
191     private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
192 
193     /** String buffer. */
194     private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
195 
196     /** Literal text. */
197     private XMLString fLiteral = new XMLString();
198 
199     /** Literal text. */
200     private XMLString fLiteral2 = new XMLString();
201 
202     /** Enumeration values. */
203     private String[] fEnumeration = new String[5];
204 
205     /** Enumeration values count. */
206     private int fEnumerationCount;
207 
208     /** Ignore conditional section buffer. */
209     private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128);
210 
211     /** Object contains grammar information for a non-validaing parser. */
212     DTDGrammar nvGrammarInfo = null;
213 
214     boolean nonValidatingMode = false;
215     //
216     // Constructors
217     //
218 
219     /** Default constructor. */
XMLDTDScannerImpl()220     public XMLDTDScannerImpl() {
221     } // <init>()
222 
223     /** Constructor for he use of non-XMLComponentManagers. */
XMLDTDScannerImpl(SymbolTable symbolTable, XMLErrorReporter errorReporter, XMLEntityManager entityManager)224     public XMLDTDScannerImpl(SymbolTable symbolTable,
225             XMLErrorReporter errorReporter, XMLEntityManager entityManager) {
226         fSymbolTable = symbolTable;
227         fErrorReporter = errorReporter;
228         fEntityManager = entityManager;
229         entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
230     }
231 
232     //
233     // XMLDTDScanner methods
234     //
235 
236     /**
237      * Sets the input source.
238      *
239      * @param inputSource The input source or null.
240      *
241      * @throws IOException Thrown on i/o error.
242      */
setInputSource(XMLInputSource inputSource)243     public void setInputSource(XMLInputSource inputSource) throws IOException {
244         if (inputSource == null) {
245             // no system id was available
246             if (fDTDHandler != null) {
247                 fDTDHandler.startDTD(null, null);
248                 fDTDHandler.endDTD(null);
249             }
250             if (nonValidatingMode){
251                 nvGrammarInfo.startDTD(null,null);
252                 nvGrammarInfo.endDTD(null);
253             }
254             return;
255         }
256         fEntityManager.setEntityHandler(this);
257         fEntityManager.startDTDEntity(inputSource);
258     } // setInputSource(XMLInputSource)
259 
260 
setLimitAnalyzer(XMLLimitAnalyzer limitAnalyzer)261     public void setLimitAnalyzer(XMLLimitAnalyzer limitAnalyzer) {
262         fLimitAnalyzer = limitAnalyzer;
263     }
264 
265     /**
266      * Scans the external subset of the document.
267      *
268      * @param complete True if the scanner should scan the document
269      *                 completely, pushing all events to the registered
270      *                 document handler. A value of false indicates that
271      *                 that the scanner should only scan the next portion
272      *                 of the document and return. A scanner instance is
273      *                 permitted to completely scan a document if it does
274      *                 not support this "pull" scanning model.
275      *
276      * @return True if there is more to scan, false otherwise.
277      */
scanDTDExternalSubset(boolean complete)278     public boolean scanDTDExternalSubset(boolean complete)
279     throws IOException, XNIException {
280 
281         fEntityManager.setEntityHandler(this);
282         if (fScannerState == SCANNER_STATE_TEXT_DECL) {
283             fSeenExternalDTD = true;
284             boolean textDecl = scanTextDecl();
285             if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
286                 return false;
287             }
288             else {
289                 // next state is markup decls regardless of whether there
290                 // is a TextDecl or not
291                 setScannerState(SCANNER_STATE_MARKUP_DECL);
292                 if (textDecl && !complete) {
293                     return true;
294                 }
295             }
296         }
297         // keep dispatching "events"
298         do {
299             if (!scanDecls(complete)) {
300                 return false;
301             }
302         } while (complete);
303 
304         // return that there is more to scan
305         return true;
306 
307     } // scanDTDExternalSubset(boolean):boolean
308 
309     /**
310      * Scans the internal subset of the document.
311      *
312      * @param complete True if the scanner should scan the document
313      *                 completely, pushing all events to the registered
314      *                 document handler. A value of false indicates that
315      *                 that the scanner should only scan the next portion
316      *                 of the document and return. A scanner instance is
317      *                 permitted to completely scan a document if it does
318      *                 not support this "pull" scanning model.
319      * @param standalone True if the document was specified as standalone.
320      *                   This value is important for verifying certain
321      *                   well-formedness constraints.
322      * @param hasExternalDTD True if the document has an external DTD.
323      *                       This allows the scanner to properly notify
324      *                       the handler of the end of the DTD in the
325      *                       absence of an external subset.
326      *
327      * @return True if there is more to scan, false otherwise.
328      */
scanDTDInternalSubset(boolean complete, boolean standalone, boolean hasExternalSubset)329     public boolean scanDTDInternalSubset(boolean complete, boolean standalone,
330     boolean hasExternalSubset)
331     throws IOException, XNIException {
332         // reset entity scanner
333         //xxx:stax getText() is supposed to return only DTD internal subset
334         //shouldn't we record position here before we go ahead ??
335 
336         fEntityScanner = fEntityManager.getEntityScanner();
337         fEntityManager.setEntityHandler(this);
338         fStandalone = standalone;
339         //System.out.println("state"+fScannerState);
340         if (fScannerState == SCANNER_STATE_TEXT_DECL) {
341             // call handler
342             if (fDTDHandler != null) {
343                 fDTDHandler.startDTD(fEntityScanner, null);
344                 fStartDTDCalled = true;
345             }
346 
347             if (nonValidatingMode){
348                 fStartDTDCalled = true;
349                 nvGrammarInfo.startDTD(fEntityScanner,null);
350             }
351             // set starting state for internal subset
352             setScannerState(SCANNER_STATE_MARKUP_DECL);
353         }
354         // keep dispatching "events"
355         do {
356             if (!scanDecls(complete)) {
357                 // call handler
358                 if (fDTDHandler != null && hasExternalSubset == false) {
359                     fDTDHandler.endDTD(null);
360                 }
361                 if (nonValidatingMode && hasExternalSubset == false ){
362                     nvGrammarInfo.endDTD(null);
363                 }
364                 // we're done, set starting state for external subset
365                 setScannerState(SCANNER_STATE_TEXT_DECL);
366                 // we're done scanning DTD.
367                 fLimitAnalyzer.reset(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT);
368                 fLimitAnalyzer.reset(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT);
369                 return false;
370             }
371         } while (complete);
372 
373         // return that there is more to scan
374         return true;
375 
376     } // scanDTDInternalSubset(boolean,boolean,boolean):boolean
377 
378     /**
379      * Skip the DTD if javax.xml.stream.supportDTD is false.
380      *
381      * @param supportDTD The value of the property javax.xml.stream.supportDTD.
382      * @return true if DTD is skipped, false otherwise.
383      * @throws java.io.IOException if i/o error occurs
384      */
385     @Override
skipDTD(boolean supportDTD)386     public boolean skipDTD(boolean supportDTD) throws IOException {
387         if (supportDTD)
388             return false;
389 
390         fStringBuffer.clear();
391         while (fEntityScanner.scanData("]", fStringBuffer, 0)) {
392             int c = fEntityScanner.peekChar();
393             if (c != -1) {
394                 if (XMLChar.isHighSurrogate(c)) {
395                     scanSurrogates(fStringBuffer);
396                 }
397                 if (isInvalidLiteral(c)) {
398                     reportFatalError("InvalidCharInDTD",
399                         new Object[] { Integer.toHexString(c) });
400                     fEntityScanner.scanChar(null);
401                 }
402             }
403         }
404         fEntityScanner.fCurrentEntity.position--;
405         return true;
406     }
407 
408     //
409     // XMLComponent methods
410     //
411 
412     /**
413      * reset
414      *
415      * @param componentManager
416      */
reset(XMLComponentManager componentManager)417     public void reset(XMLComponentManager componentManager)
418     throws XMLConfigurationException {
419 
420         super.reset(componentManager);
421         init();
422 
423     } // reset(XMLComponentManager)
424 
425     // this is made for something like XMLDTDLoader--XMLComponentManager-free operation...
reset()426     public void reset() {
427         super.reset();
428         init();
429 
430     }
431 
reset(PropertyManager props)432     public void reset(PropertyManager props) {
433         setPropertyManager(props);
434         super.reset(props);
435         init() ;
436         nonValidatingMode = true;
437         //Revisit : Create new grammar until we implement GrammarPool.
438         nvGrammarInfo = new DTDGrammar(fSymbolTable);
439     }
440     /**
441      * Returns a list of feature identifiers that are recognized by
442      * this component. This method may return null if no features
443      * are recognized by this component.
444      */
getRecognizedFeatures()445     public String[] getRecognizedFeatures() {
446         return RECOGNIZED_FEATURES.clone();
447     } // getRecognizedFeatures():String[]
448 
449     /**
450      * Returns a list of property identifiers that are recognized by
451      * this component. This method may return null if no properties
452      * are recognized by this component.
453      */
getRecognizedProperties()454     public String[] getRecognizedProperties() {
455         return RECOGNIZED_PROPERTIES.clone();
456     } // getRecognizedProperties():String[]
457 
458     /**
459      * Returns the default state for a feature, or null if this
460      * component does not want to report a default value for this
461      * feature.
462      *
463      * @param featureId The feature identifier.
464      *
465      * @since Xerces 2.2.0
466      */
getFeatureDefault(String featureId)467     public Boolean getFeatureDefault(String featureId) {
468         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
469             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
470                 return FEATURE_DEFAULTS[i];
471             }
472         }
473         return null;
474     } // getFeatureDefault(String):Boolean
475 
476     /**
477      * Returns the default state for a property, or null if this
478      * component does not want to report a default value for this
479      * property.
480      *
481      * @param propertyId The property identifier.
482      *
483      * @since Xerces 2.2.0
484      */
getPropertyDefault(String propertyId)485     public Object getPropertyDefault(String propertyId) {
486         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
487             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
488                 return PROPERTY_DEFAULTS[i];
489             }
490         }
491         return null;
492     } // getPropertyDefault(String):Object
493 
494     //
495     // XMLDTDSource methods
496     //
497 
498     /**
499      * setDTDHandler
500      *
501      * @param dtdHandler
502      */
setDTDHandler(XMLDTDHandler dtdHandler)503     public void setDTDHandler(XMLDTDHandler dtdHandler) {
504         fDTDHandler = dtdHandler;
505     } // setDTDHandler(XMLDTDHandler)
506 
507     /**
508      * getDTDHandler
509      *
510      * @return the XMLDTDHandler
511      */
getDTDHandler()512     public XMLDTDHandler getDTDHandler() {
513         return fDTDHandler;
514     } // getDTDHandler():  XMLDTDHandler
515 
516     //
517     // XMLDTDContentModelSource methods
518     //
519 
520     /**
521      * setDTDContentModelHandler
522      *
523      * @param dtdContentModelHandler
524      */
setDTDContentModelHandler(XMLDTDContentModelHandler dtdContentModelHandler)525     public void setDTDContentModelHandler(XMLDTDContentModelHandler
526     dtdContentModelHandler) {
527         fDTDContentModelHandler = dtdContentModelHandler;
528     } // setDTDContentModelHandler
529 
530     /**
531      * getDTDContentModelHandler
532      *
533      * @return XMLDTDContentModelHandler
534      */
getDTDContentModelHandler()535     public XMLDTDContentModelHandler getDTDContentModelHandler() {
536         return fDTDContentModelHandler ;
537     } // setDTDContentModelHandler
538 
539     //
540     // XMLEntityHandler methods
541     //
542 
543     /**
544      * This method notifies of the start of an entity. The DTD has the
545      * pseudo-name of "[dtd]" parameter entity names start with '%'; and
546      * general entities are just specified by their name.
547      *
548      * @param name     The name of the entity.
549      * @param identifier The resource identifier.
550      * @param encoding The auto-detected IANA encoding name of the entity
551      *                 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      */
startEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs)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      */
endEntity(String name, Augmentations augs)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         boolean dtdEntity = name.equals("[dtd]");
612         // Handle end of PE
613         boolean reportEntity = fReportEntity;
614         if (name.startsWith("%")) {
615             reportEntity = peekReportEntity();
616             // check well-formedness of the entity
617             int startMarkUpDepth = popPEStack();
618             // throw fatalError if this entity was incomplete and
619             // was a freestanding decl
620             if (startMarkUpDepth == 0 && 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             // call handler
641             if (fDTDHandler != null && reportEntity) {
642                 fDTDHandler.endParameterEntity(name, null);
643             }
644         }
645 
646         // end DTD
647         if (dtdEntity) {
648             if (fIncludeSectDepth != 0) {
649                 reportFatalError("IncludeSectUnterminated", null);
650             }
651             fScannerState = SCANNER_STATE_END_OF_INPUT;
652             // call handler
653             fEntityManager.endExternalSubset();
654             fEntityStore.endExternalSubset();
655 
656             if (fDTDHandler != null) {
657                 fDTDHandler.endExternalSubset(null);
658                 fDTDHandler.endDTD(null);
659             }
660             fExtEntityDepth--;
661         }
662 
663         //XML (Document Entity) is the last opened entity, however
664         //if for some reason DTD Scanner receives this callback
665         //there is something wrong (probably invalid XML), throw exception.
666         //or
667         //For standalone DTD loader, it might be the last opened entity
668         //and if this is the last opened entity and fMarkUpDepth != 0 or
669         //fIncludeSectDepth != 0 or fExtEntityDepth != 0 throw Exception
670         if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.LAST_ENTITY))
671             && ( fMarkUpDepth != 0 || fExtEntityDepth !=0 || fIncludeSectDepth != 0)){
672             throw new EOFException();
673         }
674 
675     } // endEntity(String)
676 
677     // helper methods
678 
679     /**
680      * Sets the scanner state.
681      *
682      * @param state The new scanner state.
683      */
setScannerState(int state)684     protected final void setScannerState(int state) {
685 
686         fScannerState = state;
687         if (DEBUG_SCANNER_STATE) {
688             System.out.print("### setScannerState: ");
689             System.out.print(getScannerStateName(state));
690             //System.out.println();
691         }
692 
693     } // setScannerState(int)
694 
695     //
696     // Private methods
697     //
698 
699     /** Returns the scanner state name. */
getScannerStateName(int state)700     private static String getScannerStateName(int state) {
701 
702         if (DEBUG_SCANNER_STATE) {
703             switch (state) {
704                 case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
705                 case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
706                 case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL";
707             }
708         }
709 
710         return "??? ("+state+')';
711 
712     } // getScannerStateName(int):String
713 
scanningInternalSubset()714     protected final boolean scanningInternalSubset() {
715         return fExtEntityDepth == 0;
716     }
717 
718     /**
719      * start a parameter entity dealing with the textdecl if there is any
720      *
721      * @param name The name of the parameter entity to start (without the '%')
722      * @param literal Whether this is happening within a literal
723      */
startPE(String name, boolean literal)724     protected void startPE(String name, boolean literal)
725     throws IOException, XNIException {
726         int depth = fPEDepth;
727         String pName = "%"+name;
728         if (fValidation && !fEntityStore.isDeclaredEntity(pName)) {
729             fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
730             new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
731         }
732         fEntityManager.startEntity(false, fSymbolTable.addSymbol(pName),
733         literal);
734         // if we actually got a new entity and it's external
735         // parse text decl if there is any
736         if (depth != fPEDepth && fEntityScanner.isExternal()) {
737             scanTextDecl();
738         }
739     }
740 
741     /**
742      * Dispatch an XML "event".
743      *
744      * @param complete True if this method is intended to scan
745      *                 and dispatch as much as possible.
746      *
747      * @return True if a TextDecl was scanned.
748      *
749      * @throws IOException  Thrown on i/o error.
750      * @throws XNIException Thrown on parse error.
751      *
752      */
scanTextDecl()753     protected final boolean scanTextDecl()
754     throws IOException, XNIException {
755 
756         // scan XMLDecl
757         boolean textDecl = false;
758         if (fEntityScanner.skipString("<?xml")) {
759             fMarkUpDepth++;
760             // NOTE: special case where document starts with a PI
761             //       whose name starts with "xml" (e.g. "xmlfoo")
762             if (isValidNameChar(fEntityScanner.peekChar())) {
763                 fStringBuffer.clear();
764                 fStringBuffer.append("xml");
765                 while (isValidNameChar(fEntityScanner.peekChar())) {
766                     fStringBuffer.append((char)fEntityScanner.scanChar(null));
767                 }
768                 String target =
769                 fSymbolTable.addSymbol(fStringBuffer.ch,
770                 fStringBuffer.offset,
771                 fStringBuffer.length);
772                 scanPIData(target, fString);
773             }
774 
775             // standard Text declaration
776             else {
777                 // pseudo-attribute values
778                 String version = null;
779                 String encoding = null;
780 
781                 scanXMLDeclOrTextDecl(true, fStrings);
782                 textDecl = true;
783                 fMarkUpDepth--;
784 
785                 version = fStrings[0];
786                 encoding = fStrings[1];
787 
788                 fEntityScanner.setEncoding(encoding);
789 
790                 // call handler
791                 if (fDTDHandler != null) {
792                     fDTDHandler.textDecl(version, encoding, null);
793                 }
794             }
795         }
796         fEntityManager.fCurrentEntity.mayReadChunks = true;
797 
798         return textDecl;
799 
800     } // scanTextDecl(boolean):boolean
801 
802     /**
803      * Scans a processing data. This is needed to handle the situation
804      * where a document starts with a processing instruction whose
805      * target name <em>starts with</em> "xml". (e.g. xmlfoo)
806      *
807      * @param target The PI target
808      * @param data The string to fill in with the data
809      */
scanPIData(String target, XMLString data)810     protected final void scanPIData(String target, XMLString data)
811     throws IOException, XNIException {
812         //Venu REVISIT
813         //      super.scanPIData(target, data);
814         fMarkUpDepth--;
815 
816         // call handler
817         if (fDTDHandler != null) {
818             fDTDHandler.processingInstruction(target, data, null);
819         }
820 
821     } // scanPIData(String)
822 
823     /**
824      * Scans a comment.
825      * <p>
826      * <pre>
827      * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
828      * </pre>
829      * <p>
830      * <strong>Note:</strong> Called after scanning past '&lt;!--'
831      */
scanComment()832     protected final void scanComment() throws IOException, XNIException {
833 
834         fReportEntity = false;
835         scanComment(fStringBuffer);
836         fMarkUpDepth--;
837 
838         // call handler
839         if (fDTDHandler != null) {
840             fDTDHandler.comment(fStringBuffer, null);
841         }
842         fReportEntity = true;
843 
844     } // scanComment()
845 
846     /**
847      * Scans an element declaration
848      * <p>
849      * <pre>
850      * [45]    elementdecl    ::=    '&lt;!ELEMENT' S Name S contentspec S? '>'
851      * [46]    contentspec    ::=    'EMPTY' | 'ANY' | Mixed | children
852      * </pre>
853      * <p>
854      * <strong>Note:</strong> Called after scanning past '&lt;!ELEMENT'
855      */
scanElementDecl()856     protected final void scanElementDecl() throws IOException, XNIException {
857 
858         // spaces
859         fReportEntity = false;
860         if (!skipSeparator(true, !scanningInternalSubset())) {
861             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL",
862             null);
863         }
864 
865         // element name
866         String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
867         if (name == null) {
868             reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL",
869             null);
870         }
871 
872         // spaces
873         if (!skipSeparator(true, !scanningInternalSubset())) {
874             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL",
875             new Object[]{name});
876         }
877 
878         // content model
879         if (fDTDContentModelHandler != null) {
880             fDTDContentModelHandler.startContentModel(name, null);
881         }
882         String contentModel = null;
883         fReportEntity = true;
884         if (fEntityScanner.skipString("EMPTY")) {
885             contentModel = "EMPTY";
886             // call handler
887             if (fDTDContentModelHandler != null) {
888                 fDTDContentModelHandler.empty(null);
889             }
890         }
891         else if (fEntityScanner.skipString("ANY")) {
892             contentModel = "ANY";
893             // call handler
894             if (fDTDContentModelHandler != null) {
895                 fDTDContentModelHandler.any(null);
896             }
897         }
898         else {
899             if (!fEntityScanner.skipChar('(', null)) {
900                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
901                 new Object[]{name});
902             }
903             if (fDTDContentModelHandler != null) {
904                 fDTDContentModelHandler.startGroup(null);
905             }
906             fStringBuffer.clear();
907             fStringBuffer.append('(');
908             fMarkUpDepth++;
909             skipSeparator(false, !scanningInternalSubset());
910 
911             // Mixed content model
912             if (fEntityScanner.skipString("#PCDATA")) {
913                 scanMixed(name);
914             }
915             else {              // children content
916                 scanChildren(name);
917             }
918             contentModel = fStringBuffer.toString();
919         }
920 
921         // call handler
922         if (fDTDContentModelHandler != null) {
923             fDTDContentModelHandler.endContentModel(null);
924         }
925 
926         fReportEntity = false;
927         skipSeparator(false, !scanningInternalSubset());
928         // end
929         if (!fEntityScanner.skipChar('>', null)) {
930             reportFatalError("ElementDeclUnterminated", new Object[]{name});
931         }
932         fReportEntity = true;
933         fMarkUpDepth--;
934 
935         // call handler
936         if (fDTDHandler != null) {
937             fDTDHandler.elementDecl(name, contentModel, null);
938         }
939         if (nonValidatingMode) nvGrammarInfo.elementDecl(name, contentModel, null);
940     } // scanElementDecl()
941 
942     /**
943      * scan Mixed content model
944      * This assumes the content model has been parsed up to #PCDATA and
945      * can simply append to fStringBuffer.
946      * <pre>
947      * [51]    Mixed    ::=    '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
948      *                       | '(' S? '#PCDATA' S? ')'
949      * </pre>
950      *
951      * @param elName The element type name this declaration is about.
952      *
953      * <strong>Note:</strong> Called after scanning past '(#PCDATA'.
954      */
scanMixed(String elName)955     private final void scanMixed(String elName)
956     throws IOException, XNIException {
957 
958         String childName = null;
959 
960         fStringBuffer.append("#PCDATA");
961         // call handler
962         if (fDTDContentModelHandler != null) {
963             fDTDContentModelHandler.pcdata(null);
964         }
965         skipSeparator(false, !scanningInternalSubset());
966         while (fEntityScanner.skipChar('|', null)) {
967             fStringBuffer.append('|');
968             // call handler
969             if (fDTDContentModelHandler != null) {
970                 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
971                 null);
972             }
973             skipSeparator(false, !scanningInternalSubset());
974 
975             childName = fEntityScanner.scanName(NameType.ENTITY);
976             if (childName == null) {
977                 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
978                 new Object[]{elName});
979             }
980             fStringBuffer.append(childName);
981             // call handler
982             if (fDTDContentModelHandler != null) {
983                 fDTDContentModelHandler.element(childName, null);
984             }
985             skipSeparator(false, !scanningInternalSubset());
986         }
987         // The following check must be done in a single call (as opposed to one
988         // for ')' and then one for '*') to guarantee that callbacks are
989         // properly nested. We do not want to trigger endEntity too early in
990         // case we cross the boundary of an entity between the two characters.
991         if (fEntityScanner.skipString(")*")) {
992             fStringBuffer.append(")*");
993             // call handler
994             if (fDTDContentModelHandler != null) {
995                 fDTDContentModelHandler.endGroup(null);
996                 fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE,
997                 null);
998             }
999         }
1000         else if (childName != null) {
1001             reportFatalError("MixedContentUnterminated",
1002             new Object[]{elName});
1003         }
1004         else if (fEntityScanner.skipChar(')', null)){
1005             fStringBuffer.append(')');
1006             // call handler
1007             if (fDTDContentModelHandler != null) {
1008                 fDTDContentModelHandler.endGroup(null);
1009             }
1010         }
1011         else {
1012             reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1013             new Object[]{elName});
1014         }
1015         fMarkUpDepth--;
1016         // we are done
1017     }
1018 
1019     /**
1020      * scan children content model
1021      * This assumes it can simply append to fStringBuffer.
1022      * <pre>
1023      * [47]    children  ::=    (choice | seq) ('?' | '*' | '+')?
1024      * [48]    cp        ::=    (Name | choice | seq) ('?' | '*' | '+')?
1025      * [49]    choice    ::=    '(' S? cp ( S? '|' S? cp )+ S? ')'
1026      * [50]    seq       ::=    '(' S? cp ( S? ',' S? cp )* S? ')'
1027      * </pre>
1028      *
1029      * @param elName The element type name this declaration is about.
1030      *
1031      * <strong>Note:</strong> Called after scanning past the first open
1032      * paranthesis.
1033      */
scanChildren(String elName)1034     private final void scanChildren(String elName)
1035     throws IOException, XNIException {
1036 
1037         fContentDepth = 0;
1038         pushContentStack(0);
1039         int currentOp = 0;
1040         int c;
1041         while (true) {
1042             if (fEntityScanner.skipChar('(', null)) {
1043                 fMarkUpDepth++;
1044                 fStringBuffer.append('(');
1045                 // call handler
1046                 if (fDTDContentModelHandler != null) {
1047                     fDTDContentModelHandler.startGroup(null);
1048                 }
1049                 // push current op on stack and reset it
1050                 pushContentStack(currentOp);
1051                 currentOp = 0;
1052                 skipSeparator(false, !scanningInternalSubset());
1053                 continue;
1054             }
1055             skipSeparator(false, !scanningInternalSubset());
1056             String childName = fEntityScanner.scanName(NameType.ELEMENTSTART);
1057             if (childName == null) {
1058                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
1059                 new Object[]{elName});
1060                 return;
1061             }
1062             // call handler
1063             if (fDTDContentModelHandler != null) {
1064                 fDTDContentModelHandler.element(childName, null);
1065             }
1066             fStringBuffer.append(childName);
1067             c = fEntityScanner.peekChar();
1068             if (c == '?' || c == '*' || c == '+') {
1069                 // call handler
1070                 if (fDTDContentModelHandler != null) {
1071                     short oc;
1072                     if (c == '?') {
1073                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1074                     }
1075                     else if (c == '*') {
1076                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1077                     }
1078                     else {
1079                         oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1080                     }
1081                     fDTDContentModelHandler.occurrence(oc, null);
1082                 }
1083                 fEntityScanner.scanChar(null);
1084                 fStringBuffer.append((char)c);
1085             }
1086             while (true) {
1087                 skipSeparator(false, !scanningInternalSubset());
1088                 c = fEntityScanner.peekChar();
1089                 if (c == ',' && currentOp != '|') {
1090                     currentOp = c;
1091                     // call handler
1092                     if (fDTDContentModelHandler != null) {
1093                         fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
1094                         null);
1095                     }
1096                     fEntityScanner.scanChar(null);
1097                     fStringBuffer.append(',');
1098                     break;
1099                 }
1100                 else if (c == '|' && currentOp != ',') {
1101                     currentOp = c;
1102                     // call handler
1103                     if (fDTDContentModelHandler != null) {
1104                         fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
1105                         null);
1106                     }
1107                     fEntityScanner.scanChar(null);
1108                     fStringBuffer.append('|');
1109                     break;
1110                 }
1111                 else if (c != ')') {
1112                     reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1113                     new Object[]{elName});
1114                 }
1115                 // call handler
1116                 if (fDTDContentModelHandler != null) {
1117                     fDTDContentModelHandler.endGroup(null);
1118                 }
1119                 // restore previous op
1120                 currentOp = popContentStack();
1121                 short oc;
1122                 // The following checks must be done in a single call (as
1123                 // opposed to one for ')' and then one for '?', '*', and '+')
1124                 // to guarantee that callbacks are properly nested. We do not
1125                 // want to trigger endEntity too early in case we cross the
1126                 // boundary of an entity between the two characters.
1127                 if (fEntityScanner.skipString(")?")) {
1128                     fStringBuffer.append(")?");
1129                     // call handler
1130                     if (fDTDContentModelHandler != null) {
1131                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1132                         fDTDContentModelHandler.occurrence(oc, null);
1133                     }
1134                 }
1135                 else if (fEntityScanner.skipString(")+")) {
1136                     fStringBuffer.append(")+");
1137                     // call handler
1138                     if (fDTDContentModelHandler != null) {
1139                         oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1140                         fDTDContentModelHandler.occurrence(oc, null);
1141                     }
1142                 }
1143                 else if (fEntityScanner.skipString(")*")) {
1144                     fStringBuffer.append(")*");
1145                     // call handler
1146                     if (fDTDContentModelHandler != null) {
1147                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1148                         fDTDContentModelHandler.occurrence(oc, null);
1149                     }
1150                 }
1151                 else {
1152                     // no occurrence specified
1153                     fEntityScanner.scanChar(null);
1154                     fStringBuffer.append(')');
1155                 }
1156                 fMarkUpDepth--;
1157                 if (fContentDepth == 0) {
1158                     return;
1159                 }
1160             }
1161             skipSeparator(false, !scanningInternalSubset());
1162         }
1163     }
1164 
1165     /**
1166      * Scans an attlist declaration
1167      * <p>
1168      * <pre>
1169      * [52]  AttlistDecl    ::=   '&lt;!ATTLIST' S Name AttDef* S? '>'
1170      * [53]  AttDef         ::=   S Name S AttType S DefaultDecl
1171      * </pre>
1172      * <p>
1173      * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1174      */
scanAttlistDecl()1175     protected final void scanAttlistDecl() throws IOException, XNIException {
1176 
1177         // spaces
1178         fReportEntity = false;
1179         if (!skipSeparator(true, !scanningInternalSubset())) {
1180             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL",
1181             null);
1182         }
1183 
1184         // element name
1185         String elName = fEntityScanner.scanName(NameType.ELEMENTSTART);
1186         if (elName == null) {
1187             reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL",
1188             null);
1189         }
1190 
1191         // call handler
1192         if (fDTDHandler != null) {
1193             fDTDHandler.startAttlist(elName, null);
1194         }
1195 
1196         // spaces
1197         if (!skipSeparator(true, !scanningInternalSubset())) {
1198             // no space, is it the end yet?
1199             if (fEntityScanner.skipChar('>', null)) {
1200                 // yes, stop here
1201                 // call handler
1202                 if (fDTDHandler != null) {
1203                     fDTDHandler.endAttlist(null);
1204                 }
1205                 fMarkUpDepth--;
1206                 return;
1207             }
1208             else {
1209                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF",
1210                 new Object[]{elName});
1211             }
1212         }
1213 
1214         // definitions
1215         while (!fEntityScanner.skipChar('>', null)) {
1216             String name = fEntityScanner.scanName(NameType.ATTRIBUTENAME);
1217             if (name == null) {
1218                 reportFatalError("AttNameRequiredInAttDef",
1219                 new Object[]{elName});
1220             }
1221             // spaces
1222             if (!skipSeparator(true, !scanningInternalSubset())) {
1223                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF",
1224                 new Object[]{elName, name});
1225             }
1226             // type
1227             String type = scanAttType(elName, name);
1228 
1229             // spaces
1230             if (!skipSeparator(true, !scanningInternalSubset())) {
1231                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF",
1232                 new Object[]{elName, name});
1233             }
1234 
1235             // default decl
1236             String defaultType = scanAttDefaultDecl(elName, name,
1237             type,
1238             fLiteral, fLiteral2);
1239             // REVISIT: Should we do anything with the non-normalized
1240             //          default attribute value? -Ac
1241             // yes--according to bug 5073.  - neilg
1242             String[] enumr = null;
1243             if( fDTDHandler != null || nonValidatingMode){
1244                 if (fEnumerationCount != 0) {
1245                     enumr = new String[fEnumerationCount];
1246                     System.arraycopy(fEnumeration, 0, enumr,
1247                     0, fEnumerationCount);
1248                 }
1249             }
1250             // call handler
1251             // Determine whether the default value to be passed should be null.
1252             // REVISIT: should probably check whether fLiteral.ch is null instead. LM.
1253             if (defaultType!=null && (defaultType.equals("#REQUIRED") ||
1254             defaultType.equals("#IMPLIED"))) {
1255                 if (fDTDHandler != null){
1256                     fDTDHandler.attributeDecl(elName, name, type, enumr,
1257                     defaultType, null, null, null);
1258                 }
1259                 if(nonValidatingMode){
1260                     nvGrammarInfo.attributeDecl(elName, name, type, enumr,
1261                     defaultType, null, null, null);
1262 
1263                 }
1264             }
1265             else {
1266                 if (fDTDHandler != null){
1267                     fDTDHandler.attributeDecl(elName, name, type, enumr,
1268                     defaultType, fLiteral, fLiteral2, null);
1269                 }
1270                 if(nonValidatingMode){
1271                     nvGrammarInfo.attributeDecl(elName, name, type, enumr,
1272                     defaultType, fLiteral, fLiteral2, null);
1273                 }
1274             }
1275             skipSeparator(false, !scanningInternalSubset());
1276         }
1277 
1278         // call handler
1279         if (fDTDHandler != null) {
1280             fDTDHandler.endAttlist(null);
1281         }
1282         fMarkUpDepth--;
1283         fReportEntity = true;
1284 
1285     } // scanAttlistDecl()
1286 
1287     /**
1288      * Scans an attribute type definition
1289      * <p>
1290      * <pre>
1291      * [54]  AttType        ::=   StringType | TokenizedType | EnumeratedType
1292      * [55]  StringType     ::=   'CDATA'
1293      * [56]  TokenizedType  ::=   'ID'
1294      *                          | 'IDREF'
1295      *                          | 'IDREFS'
1296      *                          | 'ENTITY'
1297      *                          | 'ENTITIES'
1298      *                          | 'NMTOKEN'
1299      *                          | 'NMTOKENS'
1300      * [57]  EnumeratedType ::=    NotationType | Enumeration
1301      * [58]  NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
1302      * [59]  Enumeration    ::=    '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
1303      * </pre>
1304      * <p>
1305      * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1306      *
1307      * @param elName The element type name this declaration is about.
1308      * @param atName The attribute name this declaration is about.
1309      */
scanAttType(String elName, String atName)1310     private final String scanAttType(String elName, String atName)
1311     throws IOException, XNIException {
1312 
1313         String type = null;
1314         fEnumerationCount = 0;
1315         /*
1316          * Watchout: the order here is important: when a string happens to
1317          * be a substring of another string, the longer one needs to be
1318          * looked for first!!
1319          */
1320         if (fEntityScanner.skipString("CDATA")) {
1321             type = "CDATA";
1322         }
1323         else if (fEntityScanner.skipString("IDREFS")) {
1324             type = "IDREFS";
1325         }
1326         else if (fEntityScanner.skipString("IDREF")) {
1327             type = "IDREF";
1328         }
1329         else if (fEntityScanner.skipString("ID")) {
1330             type = "ID";
1331         }
1332         else if (fEntityScanner.skipString("ENTITY")) {
1333             type = "ENTITY";
1334         }
1335         else if (fEntityScanner.skipString("ENTITIES")) {
1336             type = "ENTITIES";
1337         }
1338         else if (fEntityScanner.skipString("NMTOKENS")) {
1339             type = "NMTOKENS";
1340         }
1341         else if (fEntityScanner.skipString("NMTOKEN")) {
1342             type = "NMTOKEN";
1343         }
1344         else if (fEntityScanner.skipString("NOTATION")) {
1345             type = "NOTATION";
1346             // spaces
1347             if (!skipSeparator(true, !scanningInternalSubset())) {
1348                 reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE",
1349                 new Object[]{elName, atName});
1350             }
1351             // open paren
1352             int c = fEntityScanner.scanChar(null);
1353             if (c != '(') {
1354                 reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
1355                 new Object[]{elName, atName});
1356             }
1357             fMarkUpDepth++;
1358             do {
1359                 skipSeparator(false, !scanningInternalSubset());
1360                 String aName = fEntityScanner.scanName(NameType.ATTRIBUTENAME);
1361                 if (aName == null) {
1362                     reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
1363                     new Object[]{elName, atName});
1364                 }
1365                 ensureEnumerationSize(fEnumerationCount + 1);
1366                 fEnumeration[fEnumerationCount++] = aName;
1367                 skipSeparator(false, !scanningInternalSubset());
1368                 c = fEntityScanner.scanChar(null);
1369             } while (c == '|');
1370             if (c != ')') {
1371                 reportFatalError("NotationTypeUnterminated",
1372                 new Object[]{elName, atName});
1373             }
1374             fMarkUpDepth--;
1375         }
1376         else {              // Enumeration
1377             type = "ENUMERATION";
1378             // open paren
1379             int c = fEntityScanner.scanChar(null);
1380             if (c != '(') {
1381                 //                       "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
1382                 reportFatalError("AttTypeRequiredInAttDef",
1383                 new Object[]{elName, atName});
1384             }
1385             fMarkUpDepth++;
1386             do {
1387                 skipSeparator(false, !scanningInternalSubset());
1388                 String token = fEntityScanner.scanNmtoken();
1389                 if (token == null) {
1390                     reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION",
1391                     new Object[]{elName, atName});
1392                 }
1393                 ensureEnumerationSize(fEnumerationCount + 1);
1394                 fEnumeration[fEnumerationCount++] = token;
1395                 skipSeparator(false, !scanningInternalSubset());
1396                 c = fEntityScanner.scanChar(null);
1397             } while (c == '|');
1398             if (c != ')') {
1399                 reportFatalError("EnumerationUnterminated",
1400                 new Object[]{elName, atName});
1401             }
1402             fMarkUpDepth--;
1403         }
1404         return type;
1405 
1406     } // scanAttType():String
1407 
1408 
1409     /**
1410      * Scans an attribute default declaration
1411      * <p>
1412      * <pre>
1413      * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
1414      * </pre>
1415      *
1416      * @param name The name of the attribute being scanned.
1417      * @param defaultVal The string to fill in with the default value.
1418      */
scanAttDefaultDecl(String elName, String atName, String type, XMLString defaultVal, XMLString nonNormalizedDefaultVal)1419     protected final String scanAttDefaultDecl(String elName, String atName,
1420     String type,
1421     XMLString defaultVal,
1422     XMLString nonNormalizedDefaultVal)
1423     throws IOException, XNIException {
1424 
1425         String defaultType = null;
1426         fString.clear();
1427         defaultVal.clear();
1428         if (fEntityScanner.skipString("#REQUIRED")) {
1429             defaultType = "#REQUIRED";
1430         }
1431         else if (fEntityScanner.skipString("#IMPLIED")) {
1432             defaultType = "#IMPLIED";
1433         }
1434         else {
1435             if (fEntityScanner.skipString("#FIXED")) {
1436                 defaultType = "#FIXED";
1437                 // spaces
1438                 if (!skipSeparator(true, !scanningInternalSubset())) {
1439                     reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL",
1440                     new Object[]{elName, atName});
1441                 }
1442             }
1443             // AttValue
1444             boolean isVC = !fStandalone  &&  (fSeenExternalDTD || fSeenExternalPE) ;
1445             scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName,
1446             fAttributes, 0, isVC, elName, false);
1447         }
1448         return defaultType;
1449 
1450     } // ScanAttDefaultDecl
1451 
1452     /**
1453      * Scans an entity declaration
1454      * <p>
1455      * <pre>
1456      * [70]    EntityDecl  ::=    GEDecl | PEDecl
1457      * [71]    GEDecl      ::=    '&lt;!ENTITY' S Name S EntityDef S? '>'
1458      * [72]    PEDecl      ::=    '&lt;!ENTITY' S '%' S Name S PEDef S? '>'
1459      * [73]    EntityDef   ::=    EntityValue | (ExternalID NDataDecl?)
1460      * [74]    PEDef       ::=    EntityValue | ExternalID
1461      * [75]    ExternalID  ::=    'SYSTEM' S SystemLiteral
1462      *                          | 'PUBLIC' S PubidLiteral S SystemLiteral
1463      * [76]    NDataDecl   ::=    S 'NDATA' S Name
1464      * </pre>
1465      * <p>
1466      * <strong>Note:</strong> Called after scanning past '&lt;!ENTITY'
1467      */
scanEntityDecl()1468     private final void scanEntityDecl() throws IOException, XNIException {
1469 
1470         boolean isPEDecl = false;
1471         boolean sawPERef = false;
1472         fReportEntity = false;
1473         if (fEntityScanner.skipSpaces()) {
1474             if (!fEntityScanner.skipChar('%', NameType.REFERENCE)) {
1475                 isPEDecl = false; // <!ENTITY x "x">
1476             }
1477             else if (skipSeparator(true, !scanningInternalSubset())) {
1478                 // <!ENTITY % x "x">
1479                 isPEDecl = true;
1480             }
1481             else if (scanningInternalSubset()) {
1482                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1483                 null);
1484                 isPEDecl = true;
1485             }
1486             else if (fEntityScanner.peekChar() == '%') {
1487                 // <!ENTITY %%x; "x"> is legal
1488                 skipSeparator(false, !scanningInternalSubset());
1489                 isPEDecl = true;
1490             }
1491             else {
1492                 sawPERef = true;
1493             }
1494         }
1495         else if (scanningInternalSubset() || !fEntityScanner.skipChar('%', NameType.REFERENCE)) {
1496             // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
1497             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1498             null);
1499             isPEDecl = false;
1500         }
1501         else if (fEntityScanner.skipSpaces()) {
1502             // <!ENTITY% ...>
1503             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL",
1504             null);
1505             isPEDecl = false;
1506         }
1507         else {
1508             sawPERef = true;
1509         }
1510         if (sawPERef) {
1511             while (true) {
1512                 String peName = fEntityScanner.scanName(NameType.REFERENCE);
1513                 if (peName == null) {
1514                     reportFatalError("NameRequiredInPEReference", null);
1515                 }
1516                 else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
1517                     reportFatalError("SemicolonRequiredInPEReference",
1518                     new Object[]{peName});
1519                 }
1520                 else {
1521                     startPE(peName, false);
1522                 }
1523                 fEntityScanner.skipSpaces();
1524                 if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
1525                     break;
1526                 if (!isPEDecl) {
1527                     if (skipSeparator(true, !scanningInternalSubset())) {
1528                         isPEDecl = true;
1529                         break;
1530                     }
1531                     isPEDecl = fEntityScanner.skipChar('%', NameType.REFERENCE);
1532                 }
1533             }
1534         }
1535 
1536         // name
1537         String name = fEntityScanner.scanName(NameType.ENTITY);
1538         if (name == null) {
1539             reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null);
1540         }
1541 
1542         // spaces
1543         if (!skipSeparator(true, !scanningInternalSubset())) {
1544             reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
1545             new Object[]{name});
1546         }
1547 
1548         // external id
1549         scanExternalID(fStrings, false);
1550         String systemId = fStrings[0];
1551         String publicId = fStrings[1];
1552 
1553         if (isPEDecl && systemId != null) {
1554             fSeenExternalPE = true;
1555         }
1556 
1557         String notation = null;
1558         // NDATA
1559         boolean sawSpace = skipSeparator(true, !scanningInternalSubset());
1560         if (!isPEDecl && fEntityScanner.skipString("NDATA")) {
1561             // check whether there was space before NDATA
1562             if (!sawSpace) {
1563                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL",
1564                 new Object[]{name});
1565             }
1566 
1567             // spaces
1568             if (!skipSeparator(true, !scanningInternalSubset())) {
1569                 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
1570                 new Object[]{name});
1571             }
1572             notation = fEntityScanner.scanName(NameType.NOTATION);
1573             if (notation == null) {
1574                 reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
1575                 new Object[]{name});
1576             }
1577         }
1578 
1579         // internal entity
1580         if (systemId == null) {
1581             scanEntityValue(name, isPEDecl, fLiteral, fLiteral2);
1582             // since we need it's value anyway, let's snag it so it doesn't get corrupted
1583             // if a new load takes place before we store the entity values
1584             fStringBuffer.clear();
1585             fStringBuffer2.clear();
1586             fStringBuffer.append(fLiteral.ch, fLiteral.offset, fLiteral.length);
1587             fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset, fLiteral2.length);
1588         }
1589 
1590         // skip possible trailing space
1591         skipSeparator(false, !scanningInternalSubset());
1592 
1593         // end
1594         if (!fEntityScanner.skipChar('>', null)) {
1595             reportFatalError("EntityDeclUnterminated", new Object[]{name});
1596         }
1597         fMarkUpDepth--;
1598 
1599         // register entity and make callback
1600         if (isPEDecl) {
1601             name = "%" + name;
1602         }
1603         if (systemId != null) {
1604             String baseSystemId = fEntityScanner.getBaseSystemId();
1605             if (notation != null) {
1606                 fEntityStore.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation);
1607             }
1608             else {
1609                 fEntityStore.addExternalEntity(name, publicId, systemId,
1610                 baseSystemId);
1611             }
1612             if (fDTDHandler != null) {
1613                 //Venu Revisit : why false has been removed in expandSYstem
1614                 fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId ));
1615 
1616                 if (notation != null) {
1617                     fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier,
1618                     notation, null);
1619                 }
1620                 else {
1621                     fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null);
1622                 }
1623             }
1624         }
1625         else {
1626             fEntityStore.addInternalEntity(name, fStringBuffer.toString());
1627             if (fDTDHandler != null) {
1628                 fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null);
1629             }
1630         }
1631         fReportEntity = true;
1632 
1633     } // scanEntityDecl()
1634 
1635     /**
1636      * Scans an entity value.
1637      *
1638      * @param value The string to fill in with the value.
1639      * @param nonNormalizedValue The string to fill in with the
1640      *                           non-normalized value.
1641      *
1642      * <strong>Note:</strong> This method uses fString, fStringBuffer (through
1643      * the use of scanCharReferenceValue), and fStringBuffer2, anything in them
1644      * at the time of calling is lost.
1645      */
scanEntityValue(String entityName, boolean isPEDecl, XMLString value, XMLString nonNormalizedValue)1646     protected final void scanEntityValue(String entityName, boolean isPEDecl, XMLString value,
1647     XMLString nonNormalizedValue)
1648     throws IOException, XNIException {
1649         int quote = fEntityScanner.scanChar(null);
1650         if (quote != '\'' && quote != '"') {
1651             reportFatalError("OpenQuoteMissingInDecl", null);
1652         }
1653         // store at which depth of entities we start
1654         int entityDepth = fEntityDepth;
1655 
1656         XMLString literal = fString;
1657         XMLString literal2 = fString;
1658         int countChar = 0;
1659         if (fLimitAnalyzer == null ) {
1660             fLimitAnalyzer = fEntityManager.fLimitAnalyzer;
1661          }
1662         fLimitAnalyzer.startEntity(entityName);
1663 
1664         if (fEntityScanner.scanLiteral(quote, fString, false) != quote) {
1665             fStringBuffer.clear();
1666             fStringBuffer2.clear();
1667             int offset;
1668             do {
1669                 countChar = 0;
1670                 offset = fStringBuffer.length;
1671                 fStringBuffer.append(fString);
1672                 fStringBuffer2.append(fString);
1673                 if (fEntityScanner.skipChar('&', NameType.REFERENCE)) {
1674                     if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
1675                         fStringBuffer2.append("&#");
1676                         scanCharReferenceValue(fStringBuffer, fStringBuffer2);
1677                     }
1678                     else {
1679                         fStringBuffer.append('&');
1680                         fStringBuffer2.append('&');
1681                         String eName = fEntityScanner.scanName(NameType.REFERENCE);
1682                         if (eName == null) {
1683                             reportFatalError("NameRequiredInReference",
1684                             null);
1685                         }
1686                         else {
1687                             fStringBuffer.append(eName);
1688                             fStringBuffer2.append(eName);
1689                         }
1690                         if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
1691                             reportFatalError("SemicolonRequiredInReference",
1692                             new Object[]{eName});
1693                         }
1694                         else {
1695                             fStringBuffer.append(';');
1696                             fStringBuffer2.append(';');
1697                         }
1698                     }
1699                 }
1700                 else if (fEntityScanner.skipChar('%', NameType.REFERENCE)) {
1701                     while (true) {
1702                         fStringBuffer2.append('%');
1703                         String peName = fEntityScanner.scanName(NameType.REFERENCE);
1704                         if (peName == null) {
1705                             reportFatalError("NameRequiredInPEReference",
1706                             null);
1707                         }
1708                         else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
1709                             reportFatalError("SemicolonRequiredInPEReference",
1710                             new Object[]{peName});
1711                         }
1712                         else {
1713                             if (scanningInternalSubset()) {
1714                                 reportFatalError("PEReferenceWithinMarkup",
1715                                 new Object[]{peName});
1716                             }
1717                             fStringBuffer2.append(peName);
1718                             fStringBuffer2.append(';');
1719                         }
1720                         startPE(peName, true);
1721                         // REVISIT: [Q] Why do we skip spaces here? -Ac
1722                         // REVISIT: This will make returning the non-
1723                         //          normalized value harder. -Ac
1724                         fEntityScanner.skipSpaces();
1725                         if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
1726                             break;
1727                     }
1728                 }
1729                 else {
1730                     int c = fEntityScanner.peekChar();
1731                     if (XMLChar.isHighSurrogate(c)) {
1732                         countChar++;
1733                         scanSurrogates(fStringBuffer2);
1734                     }
1735                     else if (isInvalidLiteral(c)) {
1736                         reportFatalError("InvalidCharInLiteral",
1737                         new Object[]{Integer.toHexString(c)});
1738                         fEntityScanner.scanChar(null);
1739                     }
1740                     // if it's not the delimiting quote or if it is but from a
1741                     // different entity than the one this literal started from,
1742                     // simply append the character to our buffer
1743                     else if (c != quote || entityDepth != fEntityDepth) {
1744                         fStringBuffer.append((char)c);
1745                         fStringBuffer2.append((char)c);
1746                         fEntityScanner.scanChar(null);
1747                     }
1748                 }
1749                 checkEntityLimit(isPEDecl, entityName, fStringBuffer.length - offset + countChar);
1750             } while (fEntityScanner.scanLiteral(quote, fString, false) != quote);
1751             checkEntityLimit(isPEDecl, entityName, fString.length);
1752             fStringBuffer.append(fString);
1753             fStringBuffer2.append(fString);
1754             literal = fStringBuffer;
1755             literal2 = fStringBuffer2;
1756         } else {
1757             checkEntityLimit(isPEDecl, entityName, literal);
1758         }
1759         value.setValues(literal);
1760         nonNormalizedValue.setValues(literal2);
1761         if (fLimitAnalyzer != null) {
1762             if (isPEDecl) {
1763                 fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName);
1764             } else {
1765                 fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName);
1766             }
1767         }
1768 
1769         if (!fEntityScanner.skipChar(quote, null)) {
1770             reportFatalError("CloseQuoteMissingInDecl", null);
1771         }
1772     } // scanEntityValue(XMLString,XMLString):void
1773 
1774     /**
1775      * Scans a notation declaration
1776      * <p>
1777      * <pre>
1778      * [82] NotationDecl ::= '&lt;!NOTATION' S Name S (ExternalID|PublicID) S? '>'
1779      * [83]  PublicID    ::= 'PUBLIC' S PubidLiteral
1780      * </pre>
1781      * <p>
1782      * <strong>Note:</strong> Called after scanning past '&lt;!NOTATION'
1783      */
scanNotationDecl()1784     private final void scanNotationDecl() throws IOException, XNIException {
1785 
1786         // spaces
1787         fReportEntity = false;
1788         if (!skipSeparator(true, !scanningInternalSubset())) {
1789             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL",
1790             null);
1791         }
1792 
1793         // notation name
1794         String name = fEntityScanner.scanName(NameType.NOTATION);
1795         if (name == null) {
1796             reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
1797             null);
1798         }
1799 
1800         // spaces
1801         if (!skipSeparator(true, !scanningInternalSubset())) {
1802             reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL",
1803             new Object[]{name});
1804         }
1805 
1806         // external id
1807         scanExternalID(fStrings, true);
1808         String systemId = fStrings[0];
1809         String publicId = fStrings[1];
1810         String baseSystemId = fEntityScanner.getBaseSystemId();
1811 
1812         if (systemId == null && publicId == null) {
1813             reportFatalError("ExternalIDorPublicIDRequired",
1814             new Object[]{name});
1815         }
1816 
1817         // skip possible trailing space
1818         skipSeparator(false, !scanningInternalSubset());
1819 
1820         // end
1821         if (!fEntityScanner.skipChar('>', null)) {
1822             reportFatalError("NotationDeclUnterminated", new Object[]{name});
1823         }
1824         fMarkUpDepth--;
1825 
1826         fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId ));
1827         if (nonValidatingMode) nvGrammarInfo.notationDecl(name, fResourceIdentifier, null);
1828         // call handler
1829         if (fDTDHandler != null) {
1830             //Venu Revisit wby false has been removed.
1831             //fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
1832             fDTDHandler.notationDecl(name, fResourceIdentifier, null);
1833         }
1834         fReportEntity = true;
1835 
1836     } // scanNotationDecl()
1837 
1838     /**
1839      * Scans a conditional section. If it's a section to ignore the whole
1840      * section gets scanned through and this method only returns after the
1841      * closing bracket has been found. When it's an include section though, it
1842      * returns to let the main loop take care of scanning it. In that case the
1843      * end of the section if handled by the main loop (scanDecls).
1844      * <p>
1845      * <pre>
1846      * [61] conditionalSect   ::= includeSect | ignoreSect
1847      * [62] includeSect       ::= '&lt;![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1848      * [63] ignoreSect   ::= '&lt;![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
1849      * [64] ignoreSectContents ::= Ignore ('&lt;![' ignoreSectContents ']]>' Ignore)*
1850      * [65] Ignore            ::=    Char* - (Char* ('&lt;![' | ']]>') Char*)
1851      * </pre>
1852      * <p>
1853      * <strong>Note:</strong> Called after scanning past '&lt;![' */
scanConditionalSect(int currPEDepth)1854     private final void scanConditionalSect(int currPEDepth)
1855     throws IOException, XNIException {
1856 
1857         fReportEntity = false;
1858         skipSeparator(false, !scanningInternalSubset());
1859 
1860         if (fEntityScanner.skipString("INCLUDE")) {
1861             skipSeparator(false, !scanningInternalSubset());
1862             if(currPEDepth != fPEDepth && fValidation) {
1863                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1864                 "INVALID_PE_IN_CONDITIONAL",
1865                 new Object[]{ fEntityManager.fCurrentEntity.name},
1866                 XMLErrorReporter.SEVERITY_ERROR);
1867             }
1868             // call handler
1869             if (!fEntityScanner.skipChar('[', null)) {
1870                 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1871             }
1872 
1873             if (fDTDHandler != null) {
1874                 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE,
1875                 null);
1876             }
1877             fIncludeSectDepth++;
1878             // just stop there and go back to the main loop
1879             fReportEntity = true;
1880         }
1881         else if (fEntityScanner.skipString("IGNORE")) {
1882             skipSeparator(false, !scanningInternalSubset());
1883             if(currPEDepth != fPEDepth && fValidation) {
1884                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1885                 "INVALID_PE_IN_CONDITIONAL",
1886                 new Object[]{ fEntityManager.fCurrentEntity.name},
1887                 XMLErrorReporter.SEVERITY_ERROR);
1888             }
1889             // call handler
1890             if (fDTDHandler != null) {
1891                 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE,
1892                 null);
1893             }
1894             if (!fEntityScanner.skipChar('[', null)) {
1895                 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1896             }
1897             fReportEntity = true;
1898             int initialDepth = ++fIncludeSectDepth;
1899             if (fDTDHandler != null) {
1900                 fIgnoreConditionalBuffer.clear();
1901             }
1902             while (true) {
1903                 if (fEntityScanner.skipChar('<', null)) {
1904                     if (fDTDHandler != null) {
1905                         fIgnoreConditionalBuffer.append('<');
1906                     }
1907                     //
1908                     // These tests are split so that we handle cases like
1909                     // '<<![' and '<!<![' which we might otherwise miss.
1910                     //
1911                     if (fEntityScanner.skipChar('!', null)) {
1912                         if(fEntityScanner.skipChar('[', null)) {
1913                             if (fDTDHandler != null) {
1914                                 fIgnoreConditionalBuffer.append("![");
1915                             }
1916                             fIncludeSectDepth++;
1917                         } else {
1918                             if (fDTDHandler != null) {
1919                                 fIgnoreConditionalBuffer.append("!");
1920                             }
1921                         }
1922                     }
1923                 }
1924                 else if (fEntityScanner.skipChar(']', null)) {
1925                     if (fDTDHandler != null) {
1926                         fIgnoreConditionalBuffer.append(']');
1927                     }
1928                     //
1929                     // The same thing goes for ']<![' and '<]]>', etc.
1930                     //
1931                     if (fEntityScanner.skipChar(']', null)) {
1932                         if (fDTDHandler != null) {
1933                             fIgnoreConditionalBuffer.append(']');
1934                         }
1935                         while (fEntityScanner.skipChar(']', null)) {
1936                             /* empty loop body */
1937                             if (fDTDHandler != null) {
1938                                 fIgnoreConditionalBuffer.append(']');
1939                             }
1940                         }
1941                         if (fEntityScanner.skipChar('>', null)) {
1942                             if (fIncludeSectDepth-- == initialDepth) {
1943                                 fMarkUpDepth--;
1944                                 // call handler
1945                                 if (fDTDHandler != null) {
1946                                     fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0,
1947                                     fIgnoreConditionalBuffer.length - 2);
1948                                     fDTDHandler.ignoredCharacters(fLiteral, null);
1949                                     fDTDHandler.endConditional(null);
1950                                 }
1951                                 return;
1952                             } else if(fDTDHandler != null) {
1953                                 fIgnoreConditionalBuffer.append('>');
1954                             }
1955                         }
1956                     }
1957                 }
1958                 else {
1959                     int c = fEntityScanner.scanChar(null);
1960                     if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
1961                         reportFatalError("IgnoreSectUnterminated", null);
1962                         return;
1963                     }
1964                     if (fDTDHandler != null) {
1965                         fIgnoreConditionalBuffer.append((char)c);
1966                     }
1967                 }
1968             }
1969         }
1970         else {
1971             reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1972         }
1973 
1974     } // scanConditionalSect()
1975 
1976     /**
1977      * Dispatch an XML "event".
1978      *
1979      * @param complete True if this method is intended to scan
1980      *                 and dispatch as much as possible.
1981      *
1982      * @return True if there is more to scan.
1983      *
1984      * @throws IOException  Thrown on i/o error.
1985      * @throws XNIException Thrown on parse error.
1986      *
1987      */
scanDecls(boolean complete)1988     protected final boolean scanDecls(boolean complete)
1989     throws IOException, XNIException {
1990 
1991         skipSeparator(false, true);
1992         boolean again = true;
1993         //System.out.println("scanDecls"+fScannerState);
1994         while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
1995             again = complete;
1996             if (fEntityScanner.skipChar('<', null)) {
1997                 fMarkUpDepth++;
1998                 if (fEntityScanner.skipChar('?', null)) {
1999                     fStringBuffer.clear();
2000                     scanPI(fStringBuffer);
2001                     fMarkUpDepth--; // we're done with this decl
2002                 }
2003                 else if (fEntityScanner.skipChar('!', null)) {
2004                     if (fEntityScanner.skipChar('-', null)) {
2005                         if (!fEntityScanner.skipChar('-', null)) {
2006                             reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
2007                             null);
2008                         } else {
2009                             scanComment();
2010                         }
2011                     }
2012                     else if (fEntityScanner.skipString("ELEMENT")) {
2013                         scanElementDecl();
2014                     }
2015                     else if (fEntityScanner.skipString("ATTLIST")) {
2016                         scanAttlistDecl();
2017                     }
2018                     else if (fEntityScanner.skipString("ENTITY")) {
2019                         scanEntityDecl();
2020                     }
2021                     else if (fEntityScanner.skipString("NOTATION")) {
2022                         scanNotationDecl();
2023                     }
2024                     else if (fEntityScanner.skipChar('[', null) &&
2025                     !scanningInternalSubset()) {
2026                         scanConditionalSect(fPEDepth);
2027                     }
2028                     else {
2029                         fMarkUpDepth--;
2030                         reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
2031                         null);
2032                     }
2033                 }
2034                 else {
2035                     fMarkUpDepth--;
2036                     reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
2037                 }
2038             }
2039             else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']', null)) {
2040                 // end of conditional section?
2041                 if (!fEntityScanner.skipChar(']', null)
2042                 || !fEntityScanner.skipChar('>', null)) {
2043                     reportFatalError("IncludeSectUnterminated", null);
2044                 }
2045                 // call handler
2046                 if (fDTDHandler != null) {
2047                     fDTDHandler.endConditional(null);
2048                 }
2049                 // decreaseMarkupDepth();
2050                 fIncludeSectDepth--;
2051                 fMarkUpDepth--;
2052             }
2053             else if (scanningInternalSubset() &&
2054             fEntityScanner.peekChar() == ']') {
2055                 // this is the end of the internal subset, let's stop here
2056                 return false;
2057             }
2058             else if (fEntityScanner.skipSpaces()) {
2059                 // simply skip
2060             }
2061             else {
2062                 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
2063             }
2064             skipSeparator(false, true);
2065         }
2066         return fScannerState != SCANNER_STATE_END_OF_INPUT;
2067     }
2068 
2069     /**
2070      * Skip separator. This is typically just whitespace but it can also be one
2071      * or more parameter entity references.
2072      * <p>
2073      * If there are some it "expands them" by calling the corresponding entity
2074      * from the entity manager.
2075      * <p>
2076      * This is recursive and will process has many refs as possible.
2077      *
2078      * @param spaceRequired Specify whether some leading whitespace should be
2079      *                      found
2080      * @param lookForPERefs Specify whether parameter entity references should
2081      *                      be looked for
2082      * @return True if any leading whitespace was found or the end of a
2083      *         parameter entity was crossed.
2084      */
skipSeparator(boolean spaceRequired, boolean lookForPERefs)2085     private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs)
2086     throws IOException, XNIException {
2087         int depth = fPEDepth;
2088         boolean sawSpace = fEntityScanner.skipSpaces();
2089         if (!lookForPERefs || !fEntityScanner.skipChar('%', NameType.REFERENCE)) {
2090             return !spaceRequired || sawSpace || (depth != fPEDepth);
2091         }
2092         while (true) {
2093             String name = fEntityScanner.scanName(NameType.ENTITY);
2094             if (name == null) {
2095                 reportFatalError("NameRequiredInPEReference", null);
2096             }
2097             else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
2098                 reportFatalError("SemicolonRequiredInPEReference",
2099                 new Object[]{name});
2100             }
2101             startPE(name, false);
2102             fEntityScanner.skipSpaces();
2103             if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
2104                 return true;
2105         }
2106     }
2107 
2108 
2109     /*
2110      * Element Children Content Stack
2111      */
pushContentStack(int c)2112     private final void pushContentStack(int c) {
2113         if (fContentStack.length == fContentDepth) {
2114             int[] newStack = new int[fContentDepth * 2];
2115             System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth);
2116             fContentStack = newStack;
2117         }
2118         fContentStack[fContentDepth++] = c;
2119     }
2120 
popContentStack()2121     private final int popContentStack() {
2122         return fContentStack[--fContentDepth];
2123     }
2124 
2125 
2126     /*
2127      * Parameter Entity Stack
2128      */
pushPEStack(int depth, boolean report)2129     private final void pushPEStack(int depth, boolean report) {
2130         if (fPEStack.length == fPEDepth) {
2131             int[] newIntStack = new int[fPEDepth * 2];
2132             System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth);
2133             fPEStack = newIntStack;
2134             // report end/start calls
2135             boolean[] newBooleanStack = new boolean[fPEDepth * 2];
2136             System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth);
2137             fPEReport = newBooleanStack;
2138 
2139         }
2140         fPEReport[fPEDepth] = report;
2141         fPEStack[fPEDepth++] = depth;
2142     }
2143 
2144     /** pop the stack */
popPEStack()2145     private final int popPEStack() {
2146         return fPEStack[--fPEDepth];
2147     }
2148 
2149     /** look at the top of the stack */
peekReportEntity()2150     private final boolean peekReportEntity() {
2151         return fPEReport[fPEDepth-1];
2152     }
2153 
2154 
2155     /*
2156      * Utility method
2157      */
ensureEnumerationSize(int size)2158     private final void ensureEnumerationSize(int size) {
2159         if (fEnumeration.length == size) {
2160             String[] newEnum = new String[size * 2];
2161             System.arraycopy(fEnumeration, 0, newEnum, 0, size);
2162             fEnumeration = newEnum;
2163         }
2164     }
2165 
2166     // private methods
init()2167     private void init() {
2168         // reset state related data
2169         fStartDTDCalled = false;
2170         fExtEntityDepth = 0;
2171         fIncludeSectDepth = 0;
2172         fMarkUpDepth = 0;
2173         fPEDepth = 0;
2174 
2175         fStandalone = false;
2176         fSeenExternalDTD = false;
2177         fSeenExternalPE = false;
2178 
2179         // set starting state
2180         setScannerState(SCANNER_STATE_TEXT_DECL);
2181         //new SymbolTable());
2182 
2183         fLimitAnalyzer = fEntityManager.fLimitAnalyzer;
2184         fSecurityManager = fEntityManager.fSecurityManager;
2185     }
2186 
getGrammar()2187     public DTDGrammar getGrammar(){
2188         return nvGrammarInfo;
2189     }
2190 
2191 } // class XMLDTDScannerImpl
2192