KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > impl > XMLDTDScannerImpl


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2004 The Apache Software Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package com.sun.org.apache.xerces.internal.impl;
59
60 import java.io.IOException JavaDoc;
61
62 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
63 import com.sun.org.apache.xerces.internal.util.SymbolTable;
64 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
65 import com.sun.org.apache.xerces.internal.util.XMLChar;
66 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
67 import com.sun.org.apache.xerces.internal.xni.Augmentations;
68 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
69 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
70 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
71 import com.sun.org.apache.xerces.internal.xni.XMLString;
72 import com.sun.org.apache.xerces.internal.xni.XNIException;
73 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
74 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
75 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
76 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner;
77 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
78
79 /**
80  * This class is responsible for scanning the declarations found
81  * in the internal and external subsets of a DTD in an XML document.
82  * The scanner acts as the sources for the DTD information which is
83  * communicated to the DTD handlers.
84  * <p>
85  * This component requires the following features and properties from the
86  * component manager that uses it:
87  * <ul>
88  * <li>http://xml.org/sax/features/validation</li>
89  * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
90  * <li>http://apache.org/xml/properties/internal/symbol-table</li>
91  * <li>http://apache.org/xml/properties/internal/error-reporter</li>
92  * <li>http://apache.org/xml/properties/internal/entity-manager</li>
93  * </ul>
94  *
95  * @author Arnaud Le Hors, IBM
96  * @author Andy Clark, IBM
97  * @author Glenn Marcy, IBM
98  * @author Eric Ye, IBM
99  *
100  * @version $Id: XMLDTDScannerImpl.java,v 1.49 2004/02/27 20:36:07 mrglavas Exp $
101  */

102 public class XMLDTDScannerImpl
103     extends XMLScanner
104     implements XMLDTDScanner, XMLComponent, XMLEntityHandler {
105
106     //
107
// Constants
108
//
109

110     // scanner states
111

112     /** Scanner state: end of input. */
113     protected static final int SCANNER_STATE_END_OF_INPUT = 0;
114
115     /** Scanner state: text declaration. */
116     protected static final int SCANNER_STATE_TEXT_DECL = 1;
117
118     /** Scanner state: markup declaration. */
119     protected static final int SCANNER_STATE_MARKUP_DECL = 2;
120
121     // recognized features and properties
122

123     /** Recognized features. */
124     private static final String JavaDoc[] RECOGNIZED_FEATURES = {
125         VALIDATION,
126         NOTIFY_CHAR_REFS,
127     };
128
129     /** Feature defaults. */
130     private static final Boolean JavaDoc[] FEATURE_DEFAULTS = {
131         null,
132         Boolean.FALSE,
133     };
134
135     /** Recognized properties. */
136     private static final String JavaDoc[] RECOGNIZED_PROPERTIES = {
137         SYMBOL_TABLE,
138         ERROR_REPORTER,
139         ENTITY_MANAGER,
140     };
141
142     /** Property defaults. */
143     private static final Object JavaDoc[] PROPERTY_DEFAULTS = {
144         null,
145         null,
146         null,
147     };
148
149     // debugging
150

151     /** Debug scanner state. */
152     private static final boolean DEBUG_SCANNER_STATE = false;
153
154     //
155
// Data
156
//
157

158     // handlers
159

160     /** DTD handler. */
161     protected XMLDTDHandler fDTDHandler;
162
163     /** DTD content model handler. */
164     protected XMLDTDContentModelHandler fDTDContentModelHandler;
165
166     // state
167

168     /** Scanner state. */
169     protected int fScannerState;
170
171     /** Standalone. */
172     protected boolean fStandalone;
173
174     /** Seen external DTD. */
175     protected boolean fSeenExternalDTD;
176
177     /** Seen external parameter entity. */
178     protected boolean fSeenExternalPE;
179
180     // private data
181

182     /** Start DTD called. */
183     private boolean fStartDTDCalled;
184
185     /** Default attribute */
186     private XMLAttributesImpl fAttributes = new XMLAttributesImpl();
187
188     /**
189      * Stack of content operators (either '|' or ',') in children
190      * content.
191      */

192     private int[] fContentStack = new int[5];
193
194     /** Size of content stack. */
195     private int fContentDepth;
196
197     /** Parameter entity stack to check well-formedness. */
198     private int[] fPEStack = new int[5];
199
200
201     /** Parameter entity stack to report start/end entity calls. */
202     private boolean[] fPEReport = new boolean[5];
203
204     /** Number of opened parameter entities. */
205     private int fPEDepth;
206
207     /** Markup depth. */
208     private int fMarkUpDepth;
209
210     /** Number of opened external entities. */
211     private int fExtEntityDepth;
212
213     /** Number of opened include sections. */
214     private int fIncludeSectDepth;
215
216     // temporary variables
217

218     /** Array of 3 strings. */
219     private String JavaDoc[] fStrings = new String JavaDoc[3];
220
221     /** String. */
222     private XMLString fString = new XMLString();
223
224     /** String buffer. */
225     private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
226
227     /** String buffer. */
228     private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
229
230     /** Literal text. */
231     private XMLString fLiteral = new XMLString();
232
233     /** Literal text. */
234     private XMLString fLiteral2 = new XMLString();
235
236     /** Enumeration values. */
237     private String JavaDoc[] fEnumeration = new String JavaDoc[5];
238
239     /** Enumeration values count. */
240     private int fEnumerationCount;
241
242     /** Ignore conditional section buffer. */
243     private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128);
244
245     //
246
// Constructors
247
//
248

249     /** Default constructor. */
250     public XMLDTDScannerImpl() {} // <init>()
251

252     /** Constructor for he use of non-XMLComponentManagers. */
253     public XMLDTDScannerImpl(SymbolTable symbolTable,
254                 XMLErrorReporter errorReporter, XMLEntityManager entityManager) {
255         fSymbolTable = symbolTable;
256         fErrorReporter = errorReporter;
257         fEntityManager = entityManager;
258         entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
259     }
260
261     //
262
// XMLDTDScanner methods
263
//
264

265     /**
266      * Sets the input source.
267      *
268      * @param inputSource The input source or null.
269      *
270      * @throws IOException Thrown on i/o error.
271      */

272     public void setInputSource(XMLInputSource inputSource) throws IOException JavaDoc {
273         if (inputSource == null) {
274             // no system id was available
275
if (fDTDHandler != null) {
276                 fDTDHandler.startDTD(null, null);
277                 fDTDHandler.endDTD(null);
278             }
279             return;
280         }
281         fEntityManager.setEntityHandler(this);
282         fEntityManager.startDTDEntity(inputSource);
283     } // setInputSource(XMLInputSource)
284

285     /**
286      * Scans the external subset of the document.
287      *
288      * @param complete True if the scanner should scan the document
289      * completely, pushing all events to the registered
290      * document handler. A value of false indicates that
291      * that the scanner should only scan the next portion
292      * of the document and return. A scanner instance is
293      * permitted to completely scan a document if it does
294      * not support this "pull" scanning model.
295      *
296      * @return True if there is more to scan, false otherwise.
297      */

298     public boolean scanDTDExternalSubset(boolean complete)
299         throws IOException JavaDoc, XNIException {
300
301         fEntityManager.setEntityHandler(this);
302         if (fScannerState == SCANNER_STATE_TEXT_DECL) {
303             fSeenExternalDTD = true;
304             boolean textDecl = scanTextDecl();
305             if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
306                 return false;
307             }
308             else {
309                 // next state is markup decls regardless of whether there
310
// is a TextDecl or not
311
setScannerState(SCANNER_STATE_MARKUP_DECL);
312                 if (textDecl && !complete) {
313                     return true;
314                 }
315             }
316         }
317         // keep dispatching "events"
318
do {
319             if (!scanDecls(complete)) {
320                 return false;
321             }
322         } while (complete);
323
324         // return that there is more to scan
325
return true;
326
327     } // scanDTDExternalSubset(boolean):boolean
328

329     /**
330      * Scans the internal subset of the document.
331      *
332      * @param complete True if the scanner should scan the document
333      * completely, pushing all events to the registered
334      * document handler. A value of false indicates that
335      * that the scanner should only scan the next portion
336      * of the document and return. A scanner instance is
337      * permitted to completely scan a document if it does
338      * not support this "pull" scanning model.
339      * @param standalone True if the document was specified as standalone.
340      * This value is important for verifying certain
341      * well-formedness constraints.
342      * @param hasExternalDTD True if the document has an external DTD.
343      * This allows the scanner to properly notify
344      * the handler of the end of the DTD in the
345      * absence of an external subset.
346      *
347      * @return True if there is more to scan, false otherwise.
348      */

349     public boolean scanDTDInternalSubset(boolean complete, boolean standalone,
350                                          boolean hasExternalSubset)
351         throws IOException JavaDoc, XNIException {
352         // reset entity scanner
353
fEntityScanner = fEntityManager.getEntityScanner();
354         fEntityManager.setEntityHandler(this);
355         fStandalone = standalone;
356         if (fScannerState == SCANNER_STATE_TEXT_DECL) {
357             // call handler
358
if (fDTDHandler != null) {
359                 fDTDHandler.startDTD(fEntityScanner, null);
360                 fStartDTDCalled = true;
361             }
362             // set starting state for internal subset
363
setScannerState(SCANNER_STATE_MARKUP_DECL);
364         }
365         // keep dispatching "events"
366
do {
367             if (!scanDecls(complete)) {
368                 // call handler
369
if (fDTDHandler != null && hasExternalSubset == false) {
370                     fDTDHandler.endDTD(null);
371                 }
372                 // we're done, set starting state for external subset
373
setScannerState(SCANNER_STATE_TEXT_DECL);
374                 return false;
375             }
376         } while (complete);
377
378         // return that there is more to scan
379
return true;
380
381     } // scanDTDInternalSubset(boolean,boolean,boolean):boolean
382

383     //
384
// XMLComponent methods
385
//
386

387     /**
388      * reset
389      *
390      * @param componentManager
391      */

392     public void reset(XMLComponentManager componentManager)
393         throws XMLConfigurationException {
394         
395         super.reset(componentManager);
396         init();
397
398     } // reset(XMLComponentManager)
399

400     // this is made for something like XMLDTDLoader--XMLComponentManager-free operation...
401
public void reset() {
402         super.reset();
403         init();
404     }
405
406     /**
407      * Returns a list of feature identifiers that are recognized by
408      * this component. This method may return null if no features
409      * are recognized by this component.
410      */

411     public String JavaDoc[] getRecognizedFeatures() {
412         return (String JavaDoc[])(RECOGNIZED_FEATURES.clone());
413     } // getRecognizedFeatures():String[]
414

415     /**
416      * Returns a list of property identifiers that are recognized by
417      * this component. This method may return null if no properties
418      * are recognized by this component.
419      */

420     public String JavaDoc[] getRecognizedProperties() {
421         return (String JavaDoc[])(RECOGNIZED_PROPERTIES.clone());
422     } // getRecognizedProperties():String[]
423

424     /**
425      * Returns the default state for a feature, or null if this
426      * component does not want to report a default value for this
427      * feature.
428      *
429      * @param featureId The feature identifier.
430      *
431      * @since Xerces 2.2.0
432      */

433     public Boolean JavaDoc getFeatureDefault(String JavaDoc featureId) {
434         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
435             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
436                 return FEATURE_DEFAULTS[i];
437             }
438         }
439         return null;
440     } // getFeatureDefault(String):Boolean
441

442     /**
443      * Returns the default state for a property, or null if this
444      * component does not want to report a default value for this
445      * property.
446      *
447      * @param propertyId The property identifier.
448      *
449      * @since Xerces 2.2.0
450      */

451     public Object JavaDoc getPropertyDefault(String JavaDoc propertyId) {
452         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
453             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
454                 return PROPERTY_DEFAULTS[i];
455             }
456         }
457         return null;
458     } // getPropertyDefault(String):Object
459

460     //
461
// XMLDTDSource methods
462
//
463

464     /**
465      * setDTDHandler
466      *
467      * @param dtdHandler
468      */

469     public void setDTDHandler(XMLDTDHandler dtdHandler) {
470         fDTDHandler = dtdHandler;
471     } // setDTDHandler(XMLDTDHandler)
472

473     /**
474      * getDTDHandler
475      *
476      * @return the XMLDTDHandler
477      */

478     public XMLDTDHandler getDTDHandler() {
479         return fDTDHandler;
480     } // getDTDHandler(): XMLDTDHandler
481

482     //
483
// XMLDTDContentModelSource methods
484
//
485

486     /**
487      * setDTDContentModelHandler
488      *
489      * @param dtdContentModelHandler
490      */

491     public void setDTDContentModelHandler(XMLDTDContentModelHandler
492                                           dtdContentModelHandler) {
493         fDTDContentModelHandler = dtdContentModelHandler;
494     } // setDTDContentModelHandler
495

496     /**
497      * getDTDContentModelHandler
498      *
499      * @return XMLDTDContentModelHandler
500      */

501     public XMLDTDContentModelHandler getDTDContentModelHandler() {
502         return fDTDContentModelHandler ;
503     } // setDTDContentModelHandler
504

505     //
506
// XMLEntityHandler methods
507
//
508

509     /**
510      * This method notifies of the start of an entity. The DTD has the
511      * pseudo-name of "[dtd]" parameter entity names start with '%'; and
512      * general entities are just specified by their name.
513      *
514      * @param name The name of the entity.
515      * @param identifier The resource identifier.
516      * @param encoding The auto-detected IANA encoding name of the entity
517      * stream. This value will be null in those situations
518      * where the entity encoding is not auto-detected (e.g.
519      * internal entities or a document entity that is
520      * parsed from a java.io.Reader).
521      * @param augs Additional information that may include infoset augmentations
522      *
523      * @throws XNIException Thrown by handler to signal an error.
524      */

525     public void startEntity(String JavaDoc name,
526                             XMLResourceIdentifier identifier,
527                             String JavaDoc encoding, Augmentations augs) throws XNIException {
528
529         super.startEntity(name, identifier, encoding, augs);
530
531         boolean dtdEntity = name.equals("[dtd]");
532         if (dtdEntity) {
533             // call handler
534
if (fDTDHandler != null && !fStartDTDCalled ) {
535                 fDTDHandler.startDTD(fEntityScanner, null);
536             }
537             if (fDTDHandler != null) {
538                 fDTDHandler.startExternalSubset(identifier,null);
539             }
540             fEntityManager.startExternalSubset();
541             fExtEntityDepth++;
542         }
543         else if (name.charAt(0) == '%') {
544             pushPEStack(fMarkUpDepth, fReportEntity);
545             if (fEntityScanner.isExternal()) {
546                 fExtEntityDepth++;
547             }
548         }
549
550         // call handler
551
if (fDTDHandler != null && !dtdEntity && fReportEntity) {
552             fDTDHandler.startParameterEntity(name, identifier, encoding, augs);
553         }
554
555     } // startEntity(String,XMLResourceIdentifier,String)
556

557     /**
558      * This method notifies the end of an entity. The DTD has the pseudo-name
559      * of "[dtd]" parameter entity names start with '%'; and general entities
560      * are just specified by their name.
561      *
562      * @param name The name of the entity.
563      * @param augs Additional information that may include infoset augmentations
564      *
565      * @throws XNIException Thrown by handler to signal an error.
566      */

567     public void endEntity(String JavaDoc name, Augmentations augs)
568         throws XNIException {
569
570         super.endEntity(name, augs);
571
572         // if there is no data after the doctype
573
//
574
if (fScannerState == SCANNER_STATE_END_OF_INPUT)
575             return;
576
577         // Handle end of PE
578
boolean reportEntity = fReportEntity;
579         if (name.startsWith("%")) {
580             reportEntity = peekReportEntity();
581             // check well-formedness of the enity
582
int startMarkUpDepth = popPEStack();
583             // throw fatalError if this entity was incomplete and
584
// was a freestanding decl
585
if(startMarkUpDepth == 0 &&
586                     startMarkUpDepth < fMarkUpDepth) {
587                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
588                                    "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL",
589                                    new Object JavaDoc[]{ fEntityManager.fCurrentEntity.name},
590                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
591             }
592             if (startMarkUpDepth != fMarkUpDepth) {
593                 reportEntity = false;
594                 if (fValidation) {
595                 // Proper nesting of parameter entities is a Validity Constraint
596
// and must not be enforced when validation is off
597
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
598                                            "ImproperDeclarationNesting",
599                                            new Object JavaDoc[]{ name },
600                                            XMLErrorReporter.SEVERITY_ERROR);
601                 }
602             }
603             if (fEntityScanner.isExternal()) {
604                 fExtEntityDepth--;
605             }
606         }
607
608         // call handler
609
boolean dtdEntity = name.equals("[dtd]");
610         if (fDTDHandler != null && !dtdEntity && reportEntity) {
611             fDTDHandler.endParameterEntity(name, augs);
612         }
613
614         // end DTD
615
if (dtdEntity) {
616             if (fIncludeSectDepth != 0) {
617                 reportFatalError("IncludeSectUnterminated", null);
618             }
619             fScannerState = SCANNER_STATE_END_OF_INPUT;
620             // call handler
621
fEntityManager.endExternalSubset();
622             if (fDTDHandler != null) {
623                 fDTDHandler.endExternalSubset(null);
624                 fDTDHandler.endDTD(null);
625             }
626             fExtEntityDepth--;
627         }
628
629     } // endEntity(String)
630

631     // helper methods
632

633     /**
634      * Sets the scanner state.
635      *
636      * @param state The new scanner state.
637      */

638     protected final void setScannerState(int state) {
639
640         fScannerState = state;
641         if (DEBUG_SCANNER_STATE) {
642             System.out.print("### setScannerState: ");
643             System.out.print(getScannerStateName(state));
644             System.out.println();
645         }
646
647     } // setScannerState(int)
648

649     //
650
// Private methods
651
//
652

653     /** Returns the scanner state name. */
654     private static String JavaDoc getScannerStateName(int state) {
655
656         if (DEBUG_SCANNER_STATE) {
657             switch (state) {
658                 case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
659                 case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
660                 case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL";
661             }
662         }
663
664         return "??? ("+state+')';
665
666     } // getScannerStateName(int):String
667

668     protected final boolean scanningInternalSubset() {
669         return fExtEntityDepth == 0;
670     }
671
672     /**
673      * start a parameter entity dealing with the textdecl if there is any
674      *
675      * @param name The name of the parameter entity to start (without the '%')
676      * @param literal Whether this is happening within a literal
677      */

678     protected void startPE(String JavaDoc name, boolean literal)
679         throws IOException JavaDoc, XNIException {
680         int depth = fPEDepth;
681         String JavaDoc pName = "%"+name;
682         if (fValidation && !fEntityManager.isDeclaredEntity(pName)) {
683             fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
684                                         new Object JavaDoc[]{name}, XMLErrorReporter.SEVERITY_ERROR);
685         }
686         fEntityManager.startEntity(fSymbolTable.addSymbol(pName),
687                                    literal);
688         // if we actually got a new entity and it's external
689
// parse text decl if there is any
690
if (depth != fPEDepth && fEntityScanner.isExternal()) {
691             scanTextDecl();
692         }
693     }
694
695     /**
696      * Dispatch an XML "event".
697      *
698      * @param complete True if this method is intended to scan
699      * and dispatch as much as possible.
700      *
701      * @return True if a TextDecl was scanned.
702      *
703      * @throws IOException Thrown on i/o error.
704      * @throws XNIException Thrown on parse error.
705      *
706      */

707     protected final boolean scanTextDecl()
708         throws IOException JavaDoc, XNIException {
709
710         // scan XMLDecl
711
boolean textDecl = false;
712         if (fEntityScanner.skipString("<?xml")) {
713             fMarkUpDepth++;
714             // NOTE: special case where document starts with a PI
715
// whose name starts with "xml" (e.g. "xmlfoo")
716
if (isValidNameChar(fEntityScanner.peekChar())) {
717                 fStringBuffer.clear();
718                 fStringBuffer.append("xml");
719                 if (fNamespaces) {
720                     while (isValidNCName(fEntityScanner.peekChar())) {
721                         fStringBuffer.append((char)fEntityScanner.scanChar());
722                     }
723                 }
724                 else {
725                     while (isValidNameChar(fEntityScanner.peekChar())) {
726                         fStringBuffer.append((char)fEntityScanner.scanChar());
727                     }
728                 }
729                 String JavaDoc target =
730                     fSymbolTable.addSymbol(fStringBuffer.ch,
731                                            fStringBuffer.offset,
732                                            fStringBuffer.length);
733                 scanPIData(target, fString);
734             }
735
736             // standard Text declaration
737
else {
738                 // pseudo-attribute values
739
String JavaDoc version = null;
740                 String JavaDoc encoding = null;
741
742                 scanXMLDeclOrTextDecl(true, fStrings);
743                 textDecl = true;
744                 fMarkUpDepth--;
745
746                 version = fStrings[0];
747                 encoding = fStrings[1];
748
749                 fEntityScanner.setEncoding(encoding);
750
751                 // call handler
752
if (fDTDHandler != null) {
753                     fDTDHandler.textDecl(version, encoding, null);
754                 }
755             }
756         }
757         fEntityManager.fCurrentEntity.mayReadChunks = true;
758
759         return textDecl;
760     
761     } // scanTextDecl(boolean):boolean
762

763     /**
764      * Scans a processing data. This is needed to handle the situation
765      * where a document starts with a processing instruction whose
766      * target name <em>starts with</em> "xml". (e.g. xmlfoo)
767      *
768      * @param target The PI target
769      * @param data The string to fill in with the data
770      */

771     protected final void scanPIData(String JavaDoc target, XMLString data)
772         throws IOException JavaDoc, XNIException {
773
774         super.scanPIData(target, data);
775         fMarkUpDepth--;
776
777         // call handler
778
if (fDTDHandler != null) {
779             fDTDHandler.processingInstruction(target, data, null);
780         }
781
782     } // scanPIData(String)
783

784     /**
785      * Scans a comment.
786      * <p>
787      * <pre>
788      * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
789      * </pre>
790      * <p>
791      * <strong>Note:</strong> Called after scanning past '&lt;!--'
792      */

793     protected final void scanComment() throws IOException JavaDoc, XNIException {
794
795         fReportEntity = false;
796         scanComment(fStringBuffer);
797         fMarkUpDepth--;
798
799         // call handler
800
if (fDTDHandler != null) {
801             fDTDHandler.comment(fStringBuffer, null);
802         }
803         fReportEntity = true;
804
805     } // scanComment()
806

807     /**
808      * Scans an element declaration
809      * <p>
810      * <pre>
811      * [45] elementdecl ::= '&lt;!ELEMENT' S Name S contentspec S? '>'
812      * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
813      * </pre>
814      * <p>
815      * <strong>Note:</strong> Called after scanning past '&lt;!ELEMENT'
816      */

817     protected final void scanElementDecl() throws IOException JavaDoc, XNIException {
818
819         // spaces
820
fReportEntity = false;
821         if (!skipSeparator(true, !scanningInternalSubset())) {
822             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL",
823                              null);
824         }
825
826         // element name
827
String JavaDoc name = fEntityScanner.scanName();
828         if (name == null) {
829             reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL",
830                              null);
831         }
832
833         // spaces
834
if (!skipSeparator(true, !scanningInternalSubset())) {
835             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL",
836                              new Object JavaDoc[]{name});
837         }
838
839         // content model
840
if (fDTDContentModelHandler != null) {
841             fDTDContentModelHandler.startContentModel(name, null);
842         }
843         String JavaDoc contentModel = null;
844         fReportEntity = true;
845         if (fEntityScanner.skipString("EMPTY")) {
846             contentModel = "EMPTY";
847             // call handler
848
if (fDTDContentModelHandler != null) {
849                 fDTDContentModelHandler.empty(null);
850             }
851         }
852         else if (fEntityScanner.skipString("ANY")) {
853             contentModel = "ANY";
854             // call handler
855
if (fDTDContentModelHandler != null) {
856                 fDTDContentModelHandler.any(null);
857             }
858         }
859         else {
860             if (!fEntityScanner.skipChar('(')) {
861                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
862                                  new Object JavaDoc[]{name});
863             }
864             if (fDTDContentModelHandler != null) {
865                 fDTDContentModelHandler.startGroup(null);
866             }
867             fStringBuffer.clear();
868             fStringBuffer.append('(');
869             fMarkUpDepth++;
870             skipSeparator(false, !scanningInternalSubset());
871
872             // Mixed content model
873
if (fEntityScanner.skipString("#PCDATA")) {
874                 scanMixed(name);
875             }
876             else { // children content
877
scanChildren(name);
878             }
879             contentModel = fStringBuffer.toString();
880         }
881
882         // call handler
883
if (fDTDContentModelHandler != null) {
884             fDTDContentModelHandler.endContentModel(null);
885         }
886
887         fReportEntity = false;
888         skipSeparator(false, !scanningInternalSubset());
889         // end
890
if (!fEntityScanner.skipChar('>')) {
891             reportFatalError("ElementDeclUnterminated", new Object JavaDoc[]{name});
892         }
893         fReportEntity = true;
894         fMarkUpDepth--;
895         
896         // call handler
897
if (fDTDHandler != null) {
898             fDTDHandler.elementDecl(name, contentModel, null);
899         }
900
901     } // scanElementDecl()
902

903     /**
904      * scan Mixed content model
905      * This assumes the content model has been parsed up to #PCDATA and
906      * can simply append to fStringBuffer.
907      * <pre>
908      * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
909      * | '(' S? '#PCDATA' S? ')'
910      * </pre>
911      *
912      * @param elName The element type name this declaration is about.
913      *
914      * <strong>Note:</strong> Called after scanning past '(#PCDATA'.
915      */

916     private final void scanMixed(String JavaDoc elName)
917         throws IOException JavaDoc, XNIException {
918
919         String JavaDoc childName = null;
920
921         fStringBuffer.append("#PCDATA");
922         // call handler
923
if (fDTDContentModelHandler != null) {
924             fDTDContentModelHandler.pcdata(null);
925         }
926         skipSeparator(false, !scanningInternalSubset());
927         while (fEntityScanner.skipChar('|')) {
928             fStringBuffer.append('|');
929             // call handler
930
if (fDTDContentModelHandler != null) {
931                 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
932                                                   null);
933             }
934             skipSeparator(false, !scanningInternalSubset());
935
936             childName = fEntityScanner.scanName();
937             if (childName == null) {
938                 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
939                                  new Object JavaDoc[]{elName});
940             }
941             fStringBuffer.append(childName);
942             // call handler
943
if (fDTDContentModelHandler != null) {
944                 fDTDContentModelHandler.element(childName, null);
945             }
946             skipSeparator(false, !scanningInternalSubset());
947         }
948         // The following check must be done in a single call (as opposed to one
949
// for ')' and then one for '*') to guarantee that callbacks are
950
// properly nested. We do not want to trigger endEntity too early in
951
// case we cross the boundary of an entity between the two characters.
952
if (fEntityScanner.skipString(")*")) {
953             fStringBuffer.append(")*");
954             // call handler
955
if (fDTDContentModelHandler != null) {
956                 fDTDContentModelHandler.endGroup(null);
957                 fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE,
958                                                    null);
959             }
960         }
961         else if (childName != null) {
962             reportFatalError("MixedContentUnterminated",
963                              new Object JavaDoc[]{elName});
964         }
965         else if (fEntityScanner.skipChar(')')){
966             fStringBuffer.append(')');
967             // call handler
968
if (fDTDContentModelHandler != null) {
969                 fDTDContentModelHandler.endGroup(null);
970             }
971         }
972         else {
973             reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
974                              new Object JavaDoc[]{elName});
975         }
976         fMarkUpDepth--;
977         // we are done
978
}
979
980     /**
981      * scan children content model
982      * This assumes it can simply append to fStringBuffer.
983      * <pre>
984      * [47] children ::= (choice | seq) ('?' | '*' | '+')?
985      * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
986      * [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
987      * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
988      * </pre>
989      *
990      * @param elName The element type name this declaration is about.
991      *
992      * <strong>Note:</strong> Called after scanning past the first open
993      * paranthesis.
994      */

995     private final void scanChildren(String JavaDoc elName)
996         throws IOException JavaDoc, XNIException {
997
998         fContentDepth = 0;
999         pushContentStack(0);
1000        int currentOp = 0;
1001        int c;
1002        while (true) {
1003            if (fEntityScanner.skipChar('(')) {
1004                fMarkUpDepth++;
1005                fStringBuffer.append('(');
1006                // call handler
1007
if (fDTDContentModelHandler != null) {
1008                    fDTDContentModelHandler.startGroup(null);
1009                }
1010                // push current op on stack and reset it
1011
pushContentStack(currentOp);
1012                currentOp = 0;
1013                skipSeparator(false, !scanningInternalSubset());
1014                continue;
1015            }
1016            skipSeparator(false, !scanningInternalSubset());
1017            String JavaDoc childName = fEntityScanner.scanName();
1018            if (childName == null) {
1019                reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
1020                                 new Object JavaDoc[]{elName});
1021                return;
1022            }
1023            // call handler
1024
if (fDTDContentModelHandler != null) {
1025                fDTDContentModelHandler.element(childName, null);
1026            }
1027            fStringBuffer.append(childName);
1028            c = fEntityScanner.peekChar();
1029            if (c == '?' || c == '*' || c == '+') {
1030                // call handler
1031
if (fDTDContentModelHandler != null) {
1032                    short oc;
1033                    if (c == '?') {
1034                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1035                    }
1036                    else if (c == '*') {
1037                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1038                    }
1039                    else {
1040                        oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1041                    }
1042                    fDTDContentModelHandler.occurrence(oc, null);
1043                }
1044                fEntityScanner.scanChar();
1045                fStringBuffer.append((char)c);
1046            }
1047            while (true) {
1048                skipSeparator(false, !scanningInternalSubset());
1049                c = fEntityScanner.peekChar();
1050                if (c == ',' && currentOp != '|') {
1051                    currentOp = c;
1052                    // call handler
1053
if (fDTDContentModelHandler != null) {
1054                        fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
1055                                                          null);
1056                    }
1057                    fEntityScanner.scanChar();
1058                    fStringBuffer.append(',');
1059                    break;
1060                }
1061                else if (c == '|' && currentOp != ',') {
1062                    currentOp = c;
1063                    // call handler
1064
if (fDTDContentModelHandler != null) {
1065                        fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
1066                                                          null);
1067                    }
1068                    fEntityScanner.scanChar();
1069                    fStringBuffer.append('|');
1070                    break;
1071                }
1072                else if (c != ')') {
1073                    reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1074                                     new Object JavaDoc[]{elName});
1075                }
1076                // call handler
1077
if (fDTDContentModelHandler != null) {
1078                    fDTDContentModelHandler.endGroup(null);
1079                }
1080                // restore previous op
1081
currentOp = popContentStack();
1082                short oc;
1083                // The following checks must be done in a single call (as
1084
// opposed to one for ')' and then one for '?', '*', and '+')
1085
// to guarantee that callbacks are properly nested. We do not
1086
// want to trigger endEntity too early in case we cross the
1087
// boundary of an entity between the two characters.
1088
if (fEntityScanner.skipString(")?")) {
1089                    fStringBuffer.append(")?");
1090                    // call handler
1091
if (fDTDContentModelHandler != null) {
1092                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1093                        fDTDContentModelHandler.occurrence(oc, null);
1094                    }
1095                }
1096                else if (fEntityScanner.skipString(")+")) {
1097                    fStringBuffer.append(")+");
1098                    // call handler
1099
if (fDTDContentModelHandler != null) {
1100                        oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1101                        fDTDContentModelHandler.occurrence(oc, null);
1102                    }
1103                }
1104                else if (fEntityScanner.skipString(")*")) {
1105                    fStringBuffer.append(")*");
1106                    // call handler
1107
if (fDTDContentModelHandler != null) {
1108                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1109                        fDTDContentModelHandler.occurrence(oc, null);
1110                    }
1111                }
1112                else {
1113                    // no occurrence specified
1114
fEntityScanner.scanChar();
1115                    fStringBuffer.append(')');
1116                }
1117                fMarkUpDepth--;
1118                if (fContentDepth == 0) {
1119                    return;
1120                }
1121            }
1122            skipSeparator(false, !scanningInternalSubset());
1123        }
1124    }
1125
1126    /**
1127     * Scans an attlist declaration
1128     * <p>
1129     * <pre>
1130     * [52] AttlistDecl ::= '&lt;!ATTLIST' S Name AttDef* S? '>'
1131     * [53] AttDef ::= S Name S AttType S DefaultDecl
1132     * </pre>
1133     * <p>
1134     * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1135     */

1136    protected final void scanAttlistDecl() throws IOException JavaDoc, XNIException {
1137
1138        // spaces
1139
fReportEntity = false;
1140        if (!skipSeparator(true, !scanningInternalSubset())) {
1141            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL",
1142                             null);
1143        }
1144
1145        // element name
1146
String JavaDoc elName = fEntityScanner.scanName();
1147        if (elName == null) {
1148            reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL",
1149                             null);
1150        }
1151
1152        // call handler
1153
if (fDTDHandler != null) {
1154            fDTDHandler.startAttlist(elName, null);
1155        }
1156
1157        // spaces
1158
if (!skipSeparator(true, !scanningInternalSubset())) {
1159            // no space, is it the end yet?
1160
if (fEntityScanner.skipChar('>')) {
1161                // yes, stop here
1162
// call handler
1163
if (fDTDHandler != null) {
1164                    fDTDHandler.endAttlist(null);
1165                }
1166                fMarkUpDepth--;
1167                return;
1168            }
1169            else {
1170                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF",
1171                                 new Object JavaDoc[]{elName});
1172            }
1173        }
1174
1175        // definitions
1176
while (!fEntityScanner.skipChar('>')) {
1177            String JavaDoc name = fEntityScanner.scanName();
1178            if (name == null) {
1179                reportFatalError("AttNameRequiredInAttDef",
1180                                 new Object JavaDoc[]{elName});
1181            }
1182            // spaces
1183
if (!skipSeparator(true, !scanningInternalSubset())) {
1184                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF",
1185                                 new Object JavaDoc[]{elName, name});
1186            }
1187            // type
1188
String JavaDoc type = scanAttType(elName, name);
1189
1190            // spaces
1191
if (!skipSeparator(true, !scanningInternalSubset())) {
1192                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF",
1193                                 new Object JavaDoc[]{elName, name});
1194            }
1195
1196            // default decl
1197
String JavaDoc defaultType = scanAttDefaultDecl(elName, name,
1198                                                    type,
1199                                                    fLiteral, fLiteral2);
1200            // REVISIT: Should we do anything with the non-normalized
1201
// default attribute value? -Ac
1202
// yes--according to bug 5073. - neilg
1203

1204            // call handler
1205
if (fDTDHandler != null) {
1206                String JavaDoc[] enumeration = null;
1207                if (fEnumerationCount != 0) {
1208                    enumeration = new String JavaDoc[fEnumerationCount];
1209                    System.arraycopy(fEnumeration, 0, enumeration,
1210                                     0, fEnumerationCount);
1211                }
1212                // Determine whether the default value to be passed should be null.
1213
// REVISIT: should probably check whether fLiteral.ch is null instead. LM.
1214
if (defaultType!=null && (defaultType.equals("#REQUIRED") ||
1215                                          defaultType.equals("#IMPLIED"))) {
1216                    fDTDHandler.attributeDecl(elName, name, type, enumeration,
1217                                              defaultType, null, null, null);
1218                }
1219                else {
1220                    fDTDHandler.attributeDecl(elName, name, type, enumeration,
1221                                              defaultType, fLiteral, fLiteral2, null);
1222                }
1223            }
1224            skipSeparator(false, !scanningInternalSubset());
1225        }
1226
1227        // call handler
1228
if (fDTDHandler != null) {
1229            fDTDHandler.endAttlist(null);
1230        }
1231        fMarkUpDepth--;
1232        fReportEntity = true;
1233
1234    } // scanAttlistDecl()
1235

1236    /**
1237     * Scans an attribute type definition
1238     * <p>
1239     * <pre>
1240     * [54] AttType ::= StringType | TokenizedType | EnumeratedType
1241     * [55] StringType ::= 'CDATA'
1242     * [56] TokenizedType ::= 'ID'
1243     * | 'IDREF'
1244     * | 'IDREFS'
1245     * | 'ENTITY'
1246     * | 'ENTITIES'
1247     * | 'NMTOKEN'
1248     * | 'NMTOKENS'
1249     * [57] EnumeratedType ::= NotationType | Enumeration
1250     * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
1251     * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
1252     * </pre>
1253     * <p>
1254     * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1255     *
1256     * @param elName The element type name this declaration is about.
1257     * @param atName The attribute name this declaration is about.
1258     */

1259    private final String JavaDoc scanAttType(String JavaDoc elName, String JavaDoc atName)
1260        throws IOException JavaDoc, XNIException {
1261
1262        String JavaDoc type = null;
1263        fEnumerationCount = 0;
1264        /*
1265         * Watchout: the order here is important: when a string happens to
1266         * be a substring of another string, the longer one needs to be
1267         * looked for first!!
1268         */

1269        if (fEntityScanner.skipString("CDATA")) {
1270            type = "CDATA";
1271        }
1272        else if (fEntityScanner.skipString("IDREFS")) {
1273            type = "IDREFS";
1274        }
1275        else if (fEntityScanner.skipString("IDREF")) {
1276            type = "IDREF";
1277        }
1278        else if (fEntityScanner.skipString("ID")) {
1279            type = "ID";
1280        }
1281        else if (fEntityScanner.skipString("ENTITY")) {
1282            type = "ENTITY";
1283        }
1284        else if (fEntityScanner.skipString("ENTITIES")) {
1285            type = "ENTITIES";
1286        }
1287        else if (fEntityScanner.skipString("NMTOKENS")) {
1288            type = "NMTOKENS";
1289        }
1290        else if (fEntityScanner.skipString("NMTOKEN")) {
1291            type = "NMTOKEN";
1292        }
1293        else if (fEntityScanner.skipString("NOTATION")) {
1294            type = "NOTATION";
1295            // spaces
1296
if (!skipSeparator(true, !scanningInternalSubset())) {
1297                reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE",
1298                                 new Object JavaDoc[]{elName, atName});
1299            }
1300            // open paren
1301
int c = fEntityScanner.scanChar();
1302            if (c != '(') {
1303                reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
1304                                 new Object JavaDoc[]{elName, atName});
1305            }
1306            fMarkUpDepth++;
1307            do {
1308                skipSeparator(false, !scanningInternalSubset());
1309                String JavaDoc aName = fEntityScanner.scanName();
1310                if (aName == null) {
1311                    reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
1312                                     new Object JavaDoc[]{elName, atName});
1313                }
1314                ensureEnumerationSize(fEnumerationCount + 1);
1315                fEnumeration[fEnumerationCount++] = aName;
1316                skipSeparator(false, !scanningInternalSubset());
1317                c = fEntityScanner.scanChar();
1318            } while (c == '|');
1319            if (c != ')') {
1320                reportFatalError("NotationTypeUnterminated",
1321                                 new Object JavaDoc[]{elName, atName});
1322            }
1323            fMarkUpDepth--;
1324        }
1325        else { // Enumeration
1326
type = "ENUMERATION";
1327            // open paren
1328
int c = fEntityScanner.scanChar();
1329            if (c != '(') {
1330// "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
1331
reportFatalError("AttTypeRequiredInAttDef",
1332                                 new Object JavaDoc[]{elName, atName});
1333            }
1334            fMarkUpDepth++;
1335            do {
1336                skipSeparator(false, !scanningInternalSubset());
1337                String JavaDoc token = fEntityScanner.scanNmtoken();
1338                if (token == null) {
1339                    reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION",
1340                                     new Object JavaDoc[]{elName, atName});
1341                }
1342                ensureEnumerationSize(fEnumerationCount + 1);
1343                fEnumeration[fEnumerationCount++] = token;
1344                skipSeparator(false, !scanningInternalSubset());
1345                c = fEntityScanner.scanChar();
1346            } while (c == '|');
1347            if (c != ')') {
1348                reportFatalError("EnumerationUnterminated",
1349                                 new Object JavaDoc[]{elName, atName});
1350            }
1351            fMarkUpDepth--;
1352        }
1353        return type;
1354
1355    } // scanAttType():String
1356

1357
1358    /**
1359     * Scans an attribute default declaration
1360     * <p>
1361     * <pre>
1362     * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
1363     * </pre>
1364     *
1365     * @param name The name of the attribute being scanned.
1366     * @param defaultVal The string to fill in with the default value.
1367     */

1368    protected final String JavaDoc scanAttDefaultDecl(String JavaDoc elName, String JavaDoc atName,
1369                                              String JavaDoc type,
1370                                              XMLString defaultVal,
1371                                              XMLString nonNormalizedDefaultVal)
1372        throws IOException JavaDoc, XNIException {
1373
1374        String JavaDoc defaultType = null;
1375        fString.clear();
1376        defaultVal.clear();
1377        if (fEntityScanner.skipString("#REQUIRED")) {
1378            defaultType = "#REQUIRED";
1379        }
1380        else if (fEntityScanner.skipString("#IMPLIED")) {
1381            defaultType = "#IMPLIED";
1382        }
1383        else {
1384            if (fEntityScanner.skipString("#FIXED")) {
1385                defaultType = "#FIXED";
1386                // spaces
1387
if (!skipSeparator(true, !scanningInternalSubset())) {
1388                    reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL",
1389                                     new Object JavaDoc[]{elName, atName});
1390                }
1391            }
1392            // AttValue
1393
boolean isVC = !fStandalone && (fSeenExternalDTD || fSeenExternalPE) ;
1394            scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName, isVC, elName);
1395        }
1396        return defaultType;
1397
1398    } // ScanAttDefaultDecl
1399

1400    /**
1401     * Scans an entity declaration
1402     * <p>
1403     * <pre>
1404     * [70] EntityDecl ::= GEDecl | PEDecl
1405     * [71] GEDecl ::= '&lt;!ENTITY' S Name S EntityDef S? '>'
1406     * [72] PEDecl ::= '&lt;!ENTITY' S '%' S Name S PEDef S? '>'
1407     * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
1408     * [74] PEDef ::= EntityValue | ExternalID
1409     * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1410     * | 'PUBLIC' S PubidLiteral S SystemLiteral
1411     * [76] NDataDecl ::= S 'NDATA' S Name
1412     * </pre>
1413     * <p>
1414     * <strong>Note:</strong> Called after scanning past '&lt;!ENTITY'
1415     */

1416    private final void scanEntityDecl() throws IOException JavaDoc, XNIException {
1417
1418        boolean isPEDecl = false;
1419        boolean sawPERef = false;
1420        fReportEntity = false;
1421        if (fEntityScanner.skipSpaces()) {
1422            if (!fEntityScanner.skipChar('%')) {
1423                isPEDecl = false; // <!ENTITY x "x">
1424
}
1425            else if (skipSeparator(true, !scanningInternalSubset())) {
1426                // <!ENTITY % x "x">
1427
isPEDecl = true;
1428            }
1429            else if (scanningInternalSubset()) {
1430                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1431                                 null);
1432                isPEDecl = true;
1433            }
1434            else if (fEntityScanner.peekChar() == '%') {
1435                // <!ENTITY %%x; "x"> is legal
1436
skipSeparator(false, !scanningInternalSubset());
1437                isPEDecl = true;
1438            }
1439            else {
1440                sawPERef = true;
1441            }
1442        }
1443        else if (scanningInternalSubset() || !fEntityScanner.skipChar('%')) {
1444            // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
1445
reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1446                             null);
1447            isPEDecl = false;
1448        }
1449        else if (fEntityScanner.skipSpaces()) {
1450            // <!ENTITY% ...>
1451
reportFatalError("MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL",
1452                             null);
1453            isPEDecl = false;
1454        }
1455        else {
1456            sawPERef = true;
1457        }
1458        if (sawPERef) {
1459            while (true) {
1460                String JavaDoc peName = fEntityScanner.scanName();
1461                if (peName == null) {
1462                    reportFatalError("NameRequiredInPEReference", null);
1463                }
1464                else if (!fEntityScanner.skipChar(';')) {
1465                    reportFatalError("SemicolonRequiredInPEReference",
1466                                     new Object JavaDoc[]{peName});
1467                }
1468                else {
1469                    startPE(peName, false);
1470                }
1471                fEntityScanner.skipSpaces();
1472                if (!fEntityScanner.skipChar('%'))
1473                    break;
1474                if (!isPEDecl) {
1475                    if (skipSeparator(true, !scanningInternalSubset())) {
1476                        isPEDecl = true;
1477                        break;
1478                    }
1479                    isPEDecl = fEntityScanner.skipChar('%');
1480                }
1481            }
1482        }
1483
1484        // name
1485
String JavaDoc name = null;
1486        if(fNamespaces) {
1487            name = fEntityScanner.scanNCName();
1488        } else {
1489            name = fEntityScanner.scanName();
1490        }
1491        if (name == null) {
1492            reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null);
1493        }
1494        // spaces
1495
if (!skipSeparator(true, !scanningInternalSubset())) {
1496            if(fNamespaces && fEntityScanner.peekChar() == ':') {
1497                fEntityScanner.scanChar();
1498                XMLStringBuffer colonName = new XMLStringBuffer(name);
1499                colonName.append(":");
1500                String JavaDoc str = fEntityScanner.scanName();
1501                if (str != null)
1502                    colonName.append(str);
1503                reportFatalError("ColonNotLegalWithNS", new Object JavaDoc[] {colonName.toString()});
1504                if (!skipSeparator(true, !scanningInternalSubset())) {
1505                    reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
1506                             new Object JavaDoc[]{name});
1507                }
1508            } else {
1509                reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
1510                             new Object JavaDoc[]{name});
1511            }
1512        }
1513
1514        // external id
1515
scanExternalID(fStrings, false);
1516        String JavaDoc systemId = fStrings[0];
1517        String JavaDoc publicId = fStrings[1];
1518
1519        if (isPEDecl && systemId != null) {
1520            fSeenExternalPE = true;
1521        }
1522
1523        String JavaDoc notation = null;
1524        // NDATA
1525
boolean sawSpace = skipSeparator(true, !scanningInternalSubset());
1526        if (!isPEDecl && fEntityScanner.skipString("NDATA")) {
1527            // check whether there was space before NDATA
1528
if (!sawSpace) {
1529                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL",
1530                                 new Object JavaDoc[]{name});
1531            }
1532
1533            // spaces
1534
if (!skipSeparator(true, !scanningInternalSubset())) {
1535                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
1536                                 new Object JavaDoc[]{name});
1537            }
1538            notation = fEntityScanner.scanName();
1539            if (notation == null) {
1540                reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
1541                                 new Object JavaDoc[]{name});
1542            }
1543        }
1544
1545        // internal entity
1546
if (systemId == null) {
1547            scanEntityValue(fLiteral, fLiteral2);
1548            // since we need it's value anyway, let's snag it so it doesn't get corrupted
1549
// if a new load takes place before we store the entity values
1550
fStringBuffer.clear();
1551            fStringBuffer2.clear();
1552            fStringBuffer.append(fLiteral.ch, fLiteral.offset, fLiteral.length);
1553            fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset, fLiteral2.length);
1554        }
1555
1556        // skip possible trailing space
1557
skipSeparator(false, !scanningInternalSubset());
1558
1559        // end
1560
if (!fEntityScanner.skipChar('>')) {
1561            reportFatalError("EntityDeclUnterminated", new Object JavaDoc[]{name});
1562        }
1563        fMarkUpDepth--;
1564
1565        // register entity and make callback
1566
if (isPEDecl) {
1567            name = "%" + name;
1568        }
1569        if (systemId != null) {
1570            String JavaDoc baseSystemId = fEntityScanner.getBaseSystemId();
1571            if (notation != null) {
1572                fEntityManager.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation);
1573            }
1574            else {
1575                fEntityManager.addExternalEntity(name, publicId, systemId,
1576                                                 baseSystemId);
1577            }
1578            if (fDTDHandler != null) {
1579                fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
1580                if (notation != null) {
1581                    fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier,
1582                                                   notation, null);
1583                }
1584                else {
1585                    fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null);
1586                }
1587            }
1588        }
1589        else {
1590            fEntityManager.addInternalEntity(name, fStringBuffer.toString());
1591            if (fDTDHandler != null) {
1592                fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null);
1593            }
1594        }
1595        fReportEntity = true;
1596
1597    } // scanEntityDecl()
1598

1599    /**
1600     * Scans an entity value.
1601     *
1602     * @param value The string to fill in with the value.
1603     * @param nonNormalizedValue The string to fill in with the
1604     * non-normalized value.
1605     *
1606     * <strong>Note:</strong> This method uses fString, fStringBuffer (through
1607     * the use of scanCharReferenceValue), and fStringBuffer2, anything in them
1608     * at the time of calling is lost.
1609     */

1610    protected final void scanEntityValue(XMLString value,
1611                                         XMLString nonNormalizedValue)
1612        throws IOException JavaDoc, XNIException
1613    {
1614        int quote = fEntityScanner.scanChar();
1615        if (quote != '\'' && quote != '"') {
1616            reportFatalError("OpenQuoteMissingInDecl", null);
1617        }
1618        // store at which depth of entities we start
1619
int entityDepth = fEntityDepth;
1620
1621        XMLString literal = fString;
1622        XMLString literal2 = fString;
1623        if (fEntityScanner.scanLiteral(quote, fString) != quote) {
1624            fStringBuffer.clear();
1625            fStringBuffer2.clear();
1626            do {
1627                fStringBuffer.append(fString);
1628                fStringBuffer2.append(fString);
1629                if (fEntityScanner.skipChar('&')) {
1630                    if (fEntityScanner.skipChar('#')) {
1631                        fStringBuffer2.append("&#");
1632                        scanCharReferenceValue(fStringBuffer, fStringBuffer2);
1633                    }
1634                    else {
1635                        fStringBuffer.append('&');
1636                        fStringBuffer2.append('&');
1637                        String JavaDoc eName = fEntityScanner.scanName();
1638                        if (eName == null) {
1639                            reportFatalError("NameRequiredInReference",
1640                                             null);
1641                        }
1642                        else {
1643                            fStringBuffer.append(eName);
1644                            fStringBuffer2.append(eName);
1645                        }
1646                        if (!fEntityScanner.skipChar(';')) {
1647                            reportFatalError("SemicolonRequiredInReference",
1648                                             new Object JavaDoc[]{eName});
1649                        }
1650                        else {
1651                            fStringBuffer.append(';');
1652                            fStringBuffer2.append(';');
1653                        }
1654                    }
1655                }
1656                else if (fEntityScanner.skipChar('%')) {
1657                    while (true) {
1658                        fStringBuffer2.append('%');
1659                        String JavaDoc peName = fEntityScanner.scanName();
1660                        if (peName == null) {
1661                            reportFatalError("NameRequiredInPEReference",
1662                                             null);
1663                        }
1664                        else if (!fEntityScanner.skipChar(';')) {
1665                            reportFatalError("SemicolonRequiredInPEReference",
1666                                             new Object JavaDoc[]{peName});
1667                        }
1668                        else {
1669                            if (scanningInternalSubset()) {
1670                                reportFatalError("PEReferenceWithinMarkup",
1671                                                 new Object JavaDoc[]{peName});
1672                            }
1673                            fStringBuffer2.append(peName);
1674                            fStringBuffer2.append(';');
1675                        }
1676                        startPE(peName, true);
1677                        // REVISIT: [Q] Why do we skip spaces here? -Ac
1678
// REVISIT: This will make returning the non-
1679
// normalized value harder. -Ac
1680
fEntityScanner.skipSpaces();
1681                        if (!fEntityScanner.skipChar('%'))
1682                            break;
1683                    }
1684                }
1685                else {
1686                    int c = fEntityScanner.peekChar();
1687                    if (XMLChar.isHighSurrogate(c)) {
1688                        scanSurrogates(fStringBuffer2);
1689                    }
1690                    else if (isInvalidLiteral(c)) {
1691                        reportFatalError("InvalidCharInLiteral",
1692                                         new Object JavaDoc[]{Integer.toHexString(c)});
1693                        fEntityScanner.scanChar();
1694                    }
1695                    // if it's not the delimiting quote or if it is but from a
1696
// different entity than the one this literal started from,
1697
// simply append the character to our buffer
1698
else if (c != quote || entityDepth != fEntityDepth) {
1699                        fStringBuffer.append((char)c);
1700                        fStringBuffer2.append((char)c);
1701                        fEntityScanner.scanChar();
1702                    }
1703                }
1704            } while (fEntityScanner.scanLiteral(quote, fString) != quote);
1705            fStringBuffer.append(fString);
1706            fStringBuffer2.append(fString);
1707            literal = fStringBuffer;
1708            literal2 = fStringBuffer2;
1709        }
1710        value.setValues(literal);
1711        nonNormalizedValue.setValues(literal2);
1712        if (!fEntityScanner.skipChar(quote)) {
1713            reportFatalError("CloseQuoteMissingInDecl", null);
1714        }
1715    } // scanEntityValue(XMLString,XMLString):void
1716

1717    /**
1718     * Scans a notation declaration
1719     * <p>
1720     * <pre>
1721     * [82] NotationDecl ::= '&lt;!NOTATION' S Name S (ExternalID|PublicID) S? '>'
1722     * [83] PublicID ::= 'PUBLIC' S PubidLiteral
1723     * </pre>
1724     * <p>
1725     * <strong>Note:</strong> Called after scanning past '&lt;!NOTATION'
1726     */

1727    private final void scanNotationDecl() throws IOException JavaDoc, XNIException {
1728
1729        // spaces
1730
fReportEntity = false;
1731        if (!skipSeparator(true, !scanningInternalSubset())) {
1732            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL",
1733                             null);
1734        }
1735
1736        // notation name
1737
String JavaDoc name = null;
1738        if(fNamespaces) {
1739            name = fEntityScanner.scanNCName();
1740        } else {
1741            name = fEntityScanner.scanName();
1742        }
1743        if (name == null) {
1744            reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
1745                             null);
1746        }
1747
1748        // spaces
1749
if (!skipSeparator(true, !scanningInternalSubset())) {
1750            // check for invalid ":"
1751
if(fNamespaces && fEntityScanner.peekChar() == ':') {
1752                fEntityScanner.scanChar();
1753                XMLStringBuffer colonName = new XMLStringBuffer(name);
1754                colonName.append(":");
1755                colonName.append(fEntityScanner.scanName());
1756                reportFatalError("ColonNotLegalWithNS", new Object JavaDoc[] {colonName.toString()});
1757                skipSeparator(true, !scanningInternalSubset());
1758            } else {
1759                reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL",
1760                                new Object JavaDoc[]{name});
1761            }
1762        }
1763
1764        // external id
1765
scanExternalID(fStrings, true);
1766        String JavaDoc systemId = fStrings[0];
1767        String JavaDoc publicId = fStrings[1];
1768        String JavaDoc baseSystemId = fEntityScanner.getBaseSystemId();
1769
1770        if (systemId == null && publicId == null) {
1771            reportFatalError("ExternalIDorPublicIDRequired",
1772                             new Object JavaDoc[]{name});
1773       }
1774
1775        // skip possible trailing space
1776
skipSeparator(false, !scanningInternalSubset());
1777
1778        // end
1779
if (!fEntityScanner.skipChar('>')) {
1780            reportFatalError("NotationDeclUnterminated", new Object JavaDoc[]{name});
1781        }
1782        fMarkUpDepth--;
1783
1784        // call handler
1785
if (fDTDHandler != null) {
1786            fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
1787            fDTDHandler.notationDecl(name, fResourceIdentifier, null);
1788        }
1789        fReportEntity = true;
1790
1791    } // scanNotationDecl()
1792

1793    /**
1794     * Scans a conditional section. If it's a section to ignore the whole
1795     * section gets scanned through and this method only returns after the
1796     * closing bracket has been found. When it's an include section though, it
1797     * returns to let the main loop take care of scanning it. In that case the
1798     * end of the section if handled by the main loop (scanDecls).
1799     * <p>
1800     * <pre>
1801     * [61] conditionalSect ::= includeSect | ignoreSect
1802     * [62] includeSect ::= '&lt;![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1803     * [63] ignoreSect ::= '&lt;![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
1804     * [64] ignoreSectContents ::= Ignore ('&lt;![' ignoreSectContents ']]>' Ignore)*
1805     * [65] Ignore ::= Char* - (Char* ('&lt;![' | ']]>') Char*)
1806     * </pre>
1807     * <p>
1808     * <strong>Note:</strong> Called after scanning past '&lt;![' */

1809    private final void scanConditionalSect(int currPEDepth)
1810        throws IOException JavaDoc, XNIException {
1811
1812        fReportEntity = false;
1813        skipSeparator(false, !scanningInternalSubset());
1814
1815        if (fEntityScanner.skipString("INCLUDE")) {
1816            skipSeparator(false, !scanningInternalSubset());
1817            if(currPEDepth != fPEDepth && fValidation) {
1818                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1819                                           "INVALID_PE_IN_CONDITIONAL",
1820                                           new Object JavaDoc[]{ fEntityManager.fCurrentEntity.name},
1821                                           XMLErrorReporter.SEVERITY_ERROR);
1822            }
1823            // call handler
1824
if (!fEntityScanner.skipChar('[')) {
1825                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1826            }
1827
1828            if (fDTDHandler != null) {
1829                fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE,
1830                                             null);
1831            }
1832            fIncludeSectDepth++;
1833            // just stop there and go back to the main loop
1834
fReportEntity = true;
1835        }
1836        else if (fEntityScanner.skipString("IGNORE")) {
1837            skipSeparator(false, !scanningInternalSubset());
1838            if(currPEDepth != fPEDepth && fValidation) {
1839                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1840                                           "INVALID_PE_IN_CONDITIONAL",
1841                                           new Object JavaDoc[]{ fEntityManager.fCurrentEntity.name},
1842                                           XMLErrorReporter.SEVERITY_ERROR);
1843            }
1844            // call handler
1845
if (fDTDHandler != null) {
1846                fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE,
1847                                             null);
1848            }
1849            if (!fEntityScanner.skipChar('[')) {
1850                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1851            }
1852            fReportEntity = true;
1853            int initialDepth = ++fIncludeSectDepth;
1854            if (fDTDHandler != null) {
1855                fIgnoreConditionalBuffer.clear();
1856            }
1857            while (true) {
1858                if (fEntityScanner.skipChar('<')) {
1859                    if (fDTDHandler != null) {
1860                        fIgnoreConditionalBuffer.append('<');
1861                    }
1862                    //
1863
// These tests are split so that we handle cases like
1864
// '<<![' and '<!<![' which we might otherwise miss.
1865
//
1866
if (fEntityScanner.skipChar('!')) {
1867                        if(fEntityScanner.skipChar('[')) {
1868                            if (fDTDHandler != null) {
1869                                fIgnoreConditionalBuffer.append("![");
1870                            }
1871                            fIncludeSectDepth++;
1872                        } else {
1873                            if (fDTDHandler != null) {
1874                                fIgnoreConditionalBuffer.append("!");
1875                            }
1876                        }
1877                    }
1878                }
1879                else if (fEntityScanner.skipChar(']')) {
1880                    if (fDTDHandler != null) {
1881                        fIgnoreConditionalBuffer.append(']');
1882                    }
1883                    //
1884
// The same thing goes for ']<![' and '<]]>', etc.
1885
//
1886
if (fEntityScanner.skipChar(']')) {
1887                        if (fDTDHandler != null) {
1888                            fIgnoreConditionalBuffer.append(']');
1889                        }
1890                        while (fEntityScanner.skipChar(']')) {
1891                            /* empty loop body */
1892                            if (fDTDHandler != null) {
1893                                fIgnoreConditionalBuffer.append(']');
1894                            }
1895                        }
1896                        if (fEntityScanner.skipChar('>')) {
1897                            if (fIncludeSectDepth-- == initialDepth) {
1898                                fMarkUpDepth--;
1899                                // call handler
1900
if (fDTDHandler != null) {
1901                                    fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0,
1902                                                       fIgnoreConditionalBuffer.length - 2);
1903                                    fDTDHandler.ignoredCharacters(fLiteral, null);
1904                                    fDTDHandler.endConditional(null);
1905                                }
1906                                return;
1907                            } else if(fDTDHandler != null) {
1908                                fIgnoreConditionalBuffer.append('>');
1909                            }
1910                        }
1911                    }
1912                }
1913                else {
1914                    int c = fEntityScanner.scanChar();
1915                    if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
1916                        reportFatalError("IgnoreSectUnterminated", null);
1917                        return;
1918                    }
1919                    if (fDTDHandler != null) {
1920                        fIgnoreConditionalBuffer.append((char)c);
1921                    }
1922                }
1923            }
1924        }
1925        else {
1926            reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1927        }
1928
1929    } // scanConditionalSect()
1930

1931    /**
1932     * Dispatch an XML "event".
1933     *
1934     * @param complete True if this method is intended to scan
1935     * and dispatch as much as possible.
1936     *
1937     * @return True if there is more to scan.
1938     *
1939     * @throws IOException Thrown on i/o error.
1940     * @throws XNIException Thrown on parse error.
1941     *
1942     */

1943    protected final boolean scanDecls(boolean complete)
1944            throws IOException JavaDoc, XNIException {
1945        
1946        skipSeparator(false, true);
1947        boolean again = true;
1948        while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
1949            again = complete;
1950            if (fEntityScanner.skipChar('<')) {
1951                fMarkUpDepth++;
1952                if (fEntityScanner.skipChar('?')) {
1953                    scanPI();
1954                }
1955                else if (fEntityScanner.skipChar('!')) {
1956                    if (fEntityScanner.skipChar('-')) {
1957                        if (!fEntityScanner.skipChar('-')) {
1958                            reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1959                                             null);
1960                        } else {
1961                            scanComment();
1962                        }
1963                    }
1964                    else if (fEntityScanner.skipString("ELEMENT")) {
1965                        scanElementDecl();
1966                    }
1967                    else if (fEntityScanner.skipString("ATTLIST")) {
1968                        scanAttlistDecl();
1969                    }
1970                    else if (fEntityScanner.skipString("ENTITY")) {
1971                        scanEntityDecl();
1972                    }
1973                    else if (fEntityScanner.skipString("NOTATION")) {
1974                        scanNotationDecl();
1975                    }
1976                    else if (fEntityScanner.skipChar('[') &&
1977                             !scanningInternalSubset()) {
1978                        scanConditionalSect(fPEDepth);
1979                    }
1980                    else {
1981                        fMarkUpDepth--;
1982                        reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1983                                         null);
1984                    }
1985                }
1986                else {
1987                    fMarkUpDepth--;
1988                    reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1989                }
1990            }
1991            else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) {
1992                // end of conditional section?
1993
if (!fEntityScanner.skipChar(']')
1994                    || !fEntityScanner.skipChar('>')) {
1995                    reportFatalError("IncludeSectUnterminated", null);
1996                }
1997                // call handler
1998
if (fDTDHandler != null) {
1999                    fDTDHandler.endConditional(null);
2000                }
2001                // decreaseMarkupDepth();
2002
fIncludeSectDepth--;
2003                fMarkUpDepth--;
2004            }
2005            else if (scanningInternalSubset() &&
2006                     fEntityScanner.peekChar() == ']') {
2007                // this is the end of the internal subset, let's stop here
2008
return false;
2009            }
2010            else if (fEntityScanner.skipSpaces()) {
2011                // simply skip
2012
}
2013            else {
2014                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
2015                // Skip the part in error
2016
int ch;
2017                do {
2018                    // Ignore the current character
2019
fEntityScanner.scanChar();
2020                    // Skip any separators
2021
skipSeparator(false, true);
2022                    // Keeping getting the next character,
2023
// until it's one of the expected ones
2024
ch = fEntityScanner.peekChar();
2025                } while (ch != '<' && ch != ']' && !XMLChar.isSpace(ch));
2026            }
2027            skipSeparator(false, true);
2028        }
2029        return fScannerState != SCANNER_STATE_END_OF_INPUT;
2030    }
2031
2032    /**
2033     * Skip separator. This is typically just whitespace but it can also be one
2034     * or more parameter entity references.
2035     * <p>
2036     * If there are some it "expands them" by calling the corresponding entity
2037     * from the entity manager.
2038     * <p>
2039     * This is recursive and will process has many refs as possible.
2040     *
2041     * @param spaceRequired Specify whether some leading whitespace should be
2042     * found
2043     * @param lookForPERefs Specify whether parameter entity references should
2044     * be looked for
2045     * @return True if any leading whitespace was found or the end of a
2046     * parameter entity was crossed.
2047     */

2048    private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs)
2049        throws IOException JavaDoc, XNIException
2050    {
2051        int depth = fPEDepth;
2052        boolean sawSpace = fEntityScanner.skipSpaces();
2053        if (!lookForPERefs || !fEntityScanner.skipChar('%')) {
2054            return !spaceRequired || sawSpace || (depth != fPEDepth);
2055        }
2056        while (true) {
2057            String JavaDoc name = fEntityScanner.scanName();
2058            if (name == null) {
2059                reportFatalError("NameRequiredInPEReference", null);
2060            }
2061            else if (!fEntityScanner.skipChar(';')) {
2062                reportFatalError("SemicolonRequiredInPEReference",
2063                                 new Object JavaDoc[]{name});
2064            }
2065            startPE(name, false);
2066            fEntityScanner.skipSpaces();
2067            if (!fEntityScanner.skipChar('%'))
2068                return true;
2069        }
2070    }
2071
2072
2073    /*
2074     * Element Children Content Stack
2075     */

2076    private final void pushContentStack(int c) {
2077        if (fContentStack.length == fContentDepth) {
2078            int[] newStack = new int[fContentDepth * 2];
2079            System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth);
2080            fContentStack = newStack;
2081        }
2082        fContentStack[fContentDepth++] = c;
2083    }
2084
2085    private final int popContentStack() {
2086        return fContentStack[--fContentDepth];
2087    }
2088
2089
2090    /*
2091     * Parameter Entity Stack
2092     */

2093    private final void pushPEStack(int depth, boolean report) {
2094        if (fPEStack.length == fPEDepth) {
2095            int[] newIntStack = new int[fPEDepth * 2];
2096            System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth);
2097            fPEStack = newIntStack;
2098            // report end/start calls
2099
boolean[] newBooleanStack = new boolean[fPEDepth * 2];
2100            System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth);
2101            fPEReport = newBooleanStack;
2102
2103        }
2104        fPEReport[fPEDepth] = report;
2105        fPEStack[fPEDepth++] = depth;
2106    }
2107
2108    /** pop the stack */
2109    private final int popPEStack() {
2110        return fPEStack[--fPEDepth];
2111    }
2112
2113    /** look at the top of the stack */
2114    private final boolean peekReportEntity() {
2115        return fPEReport[fPEDepth-1];
2116    }
2117
2118
2119    /*
2120     * Utility method
2121     */

2122    private final void ensureEnumerationSize(int size) {
2123        if (fEnumeration.length == size) {
2124            String JavaDoc[] newEnum = new String JavaDoc[size * 2];
2125            System.arraycopy(fEnumeration, 0, newEnum, 0, size);
2126            fEnumeration = newEnum;
2127        }
2128    }
2129
2130    // private methods
2131
private void init() {
2132        // reset state related data
2133
fStartDTDCalled = false;
2134        fExtEntityDepth = 0;
2135        fIncludeSectDepth = 0;
2136        fMarkUpDepth = 0;
2137        fPEDepth = 0;
2138
2139        fStandalone = false;
2140        fSeenExternalDTD = false;
2141        fSeenExternalPE = false;
2142
2143        // set starting state
2144
setScannerState(SCANNER_STATE_TEXT_DECL);
2145    }
2146
2147} // class XMLDTDScannerImpl
2148
Popular Tags