KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > impl > XMLDTDScannerImpl


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.impl;
18
19 import java.io.IOException JavaDoc;
20
21 import org.apache.xerces.impl.msg.XMLMessageFormatter;
22 import org.apache.xerces.util.SymbolTable;
23 import org.apache.xerces.util.XMLAttributesImpl;
24 import org.apache.xerces.util.XMLChar;
25 import org.apache.xerces.util.XMLStringBuffer;
26 import org.apache.xerces.xni.Augmentations;
27 import org.apache.xerces.xni.XMLDTDContentModelHandler;
28 import org.apache.xerces.xni.XMLDTDHandler;
29 import org.apache.xerces.xni.XMLResourceIdentifier;
30 import org.apache.xerces.xni.XMLString;
31 import org.apache.xerces.xni.XNIException;
32 import org.apache.xerces.xni.parser.XMLComponent;
33 import org.apache.xerces.xni.parser.XMLComponentManager;
34 import org.apache.xerces.xni.parser.XMLConfigurationException;
35 import org.apache.xerces.xni.parser.XMLDTDScanner;
36 import org.apache.xerces.xni.parser.XMLInputSource;
37
38 /**
39  * This class is responsible for scanning the declarations found
40  * in the internal and external subsets of a DTD in an XML document.
41  * The scanner acts as the sources for the DTD information which is
42  * communicated to the DTD handlers.
43  * <p>
44  * This component requires the following features and properties from the
45  * component manager that uses it:
46  * <ul>
47  * <li>http://xml.org/sax/features/validation</li>
48  * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
49  * <li>http://apache.org/xml/properties/internal/symbol-table</li>
50  * <li>http://apache.org/xml/properties/internal/error-reporter</li>
51  * <li>http://apache.org/xml/properties/internal/entity-manager</li>
52  * </ul>
53  *
54  * @xerces.internal
55  *
56  * @author Arnaud Le Hors, IBM
57  * @author Andy Clark, IBM
58  * @author Glenn Marcy, IBM
59  * @author Eric Ye, IBM
60  *
61  * @version $Id: XMLDTDScannerImpl.java,v 1.52 2004/10/04 21:45:49 mrglavas Exp $
62  */

63 public class XMLDTDScannerImpl
64     extends XMLScanner
65     implements XMLDTDScanner, XMLComponent, XMLEntityHandler {
66
67     //
68
// Constants
69
//
70

71     // scanner states
72

73     /** Scanner state: end of input. */
74     protected static final int SCANNER_STATE_END_OF_INPUT = 0;
75
76     /** Scanner state: text declaration. */
77     protected static final int SCANNER_STATE_TEXT_DECL = 1;
78
79     /** Scanner state: markup declaration. */
80     protected static final int SCANNER_STATE_MARKUP_DECL = 2;
81
82     // recognized features and properties
83

84     /** Recognized features. */
85     private static final String JavaDoc[] RECOGNIZED_FEATURES = {
86         VALIDATION,
87         NOTIFY_CHAR_REFS,
88     };
89
90     /** Feature defaults. */
91     private static final Boolean JavaDoc[] FEATURE_DEFAULTS = {
92         null,
93         Boolean.FALSE,
94     };
95
96     /** Recognized properties. */
97     private static final String JavaDoc[] RECOGNIZED_PROPERTIES = {
98         SYMBOL_TABLE,
99         ERROR_REPORTER,
100         ENTITY_MANAGER,
101     };
102
103     /** Property defaults. */
104     private static final Object JavaDoc[] PROPERTY_DEFAULTS = {
105         null,
106         null,
107         null,
108     };
109
110     // debugging
111

112     /** Debug scanner state. */
113     private static final boolean DEBUG_SCANNER_STATE = false;
114
115     //
116
// Data
117
//
118

119     // handlers
120

121     /** DTD handler. */
122     protected XMLDTDHandler fDTDHandler;
123
124     /** DTD content model handler. */
125     protected XMLDTDContentModelHandler fDTDContentModelHandler;
126
127     // state
128

129     /** Scanner state. */
130     protected int fScannerState;
131
132     /** Standalone. */
133     protected boolean fStandalone;
134
135     /** Seen external DTD. */
136     protected boolean fSeenExternalDTD;
137
138     /** Seen external parameter entity. */
139     protected boolean fSeenExternalPE;
140
141     // private data
142

143     /** Start DTD called. */
144     private boolean fStartDTDCalled;
145
146     /** Default attribute */
147     private XMLAttributesImpl fAttributes = new XMLAttributesImpl();
148
149     /**
150      * Stack of content operators (either '|' or ',') in children
151      * content.
152      */

153     private int[] fContentStack = new int[5];
154
155     /** Size of content stack. */
156     private int fContentDepth;
157
158     /** Parameter entity stack to check well-formedness. */
159     private int[] fPEStack = new int[5];
160
161
162     /** Parameter entity stack to report start/end entity calls. */
163     private boolean[] fPEReport = new boolean[5];
164
165     /** Number of opened parameter entities. */
166     private int fPEDepth;
167
168     /** Markup depth. */
169     private int fMarkUpDepth;
170
171     /** Number of opened external entities. */
172     private int fExtEntityDepth;
173
174     /** Number of opened include sections. */
175     private int fIncludeSectDepth;
176
177     // temporary variables
178

179     /** Array of 3 strings. */
180     private String JavaDoc[] fStrings = new String JavaDoc[3];
181
182     /** String. */
183     private XMLString fString = new XMLString();
184
185     /** String buffer. */
186     private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
187
188     /** String buffer. */
189     private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
190
191     /** Literal text. */
192     private XMLString fLiteral = new XMLString();
193
194     /** Literal text. */
195     private XMLString fLiteral2 = new XMLString();
196
197     /** Enumeration values. */
198     private String JavaDoc[] fEnumeration = new String JavaDoc[5];
199
200     /** Enumeration values count. */
201     private int fEnumerationCount;
202
203     /** Ignore conditional section buffer. */
204     private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128);
205
206     //
207
// Constructors
208
//
209

210     /** Default constructor. */
211     public XMLDTDScannerImpl() {} // <init>()
212

213     /** Constructor for he use of non-XMLComponentManagers. */
214     public XMLDTDScannerImpl(SymbolTable symbolTable,
215                 XMLErrorReporter errorReporter, XMLEntityManager entityManager) {
216         fSymbolTable = symbolTable;
217         fErrorReporter = errorReporter;
218         fEntityManager = entityManager;
219         entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
220     }
221
222     //
223
// XMLDTDScanner methods
224
//
225

226     /**
227      * Sets the input source.
228      *
229      * @param inputSource The input source or null.
230      *
231      * @throws IOException Thrown on i/o error.
232      */

233     public void setInputSource(XMLInputSource inputSource) throws IOException JavaDoc {
234         if (inputSource == null) {
235             // no system id was available
236
if (fDTDHandler != null) {
237                 fDTDHandler.startDTD(null, null);
238                 fDTDHandler.endDTD(null);
239             }
240             return;
241         }
242         fEntityManager.setEntityHandler(this);
243         fEntityManager.startDTDEntity(inputSource);
244     } // setInputSource(XMLInputSource)
245

246     /**
247      * Scans the external subset of the document.
248      *
249      * @param complete True if the scanner should scan the document
250      * completely, pushing all events to the registered
251      * document handler. A value of false indicates that
252      * that the scanner should only scan the next portion
253      * of the document and return. A scanner instance is
254      * permitted to completely scan a document if it does
255      * not support this "pull" scanning model.
256      *
257      * @return True if there is more to scan, false otherwise.
258      */

259     public boolean scanDTDExternalSubset(boolean complete)
260         throws IOException JavaDoc, XNIException {
261
262         fEntityManager.setEntityHandler(this);
263         if (fScannerState == SCANNER_STATE_TEXT_DECL) {
264             fSeenExternalDTD = true;
265             boolean textDecl = scanTextDecl();
266             if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
267                 return false;
268             }
269             else {
270                 // next state is markup decls regardless of whether there
271
// is a TextDecl or not
272
setScannerState(SCANNER_STATE_MARKUP_DECL);
273                 if (textDecl && !complete) {
274                     return true;
275                 }
276             }
277         }
278         // keep dispatching "events"
279
do {
280             if (!scanDecls(complete)) {
281                 return false;
282             }
283         } while (complete);
284
285         // return that there is more to scan
286
return true;
287
288     } // scanDTDExternalSubset(boolean):boolean
289

290     /**
291      * Scans the internal subset of the document.
292      *
293      * @param complete True if the scanner should scan the document
294      * completely, pushing all events to the registered
295      * document handler. A value of false indicates that
296      * that the scanner should only scan the next portion
297      * of the document and return. A scanner instance is
298      * permitted to completely scan a document if it does
299      * not support this "pull" scanning model.
300      * @param standalone True if the document was specified as standalone.
301      * This value is important for verifying certain
302      * well-formedness constraints.
303      * @param hasExternalDTD True if the document has an external DTD.
304      * This allows the scanner to properly notify
305      * the handler of the end of the DTD in the
306      * absence of an external subset.
307      *
308      * @return True if there is more to scan, false otherwise.
309      */

310     public boolean scanDTDInternalSubset(boolean complete, boolean standalone,
311                                          boolean hasExternalSubset)
312         throws IOException JavaDoc, XNIException {
313         // reset entity scanner
314
fEntityScanner = fEntityManager.getEntityScanner();
315         fEntityManager.setEntityHandler(this);
316         fStandalone = standalone;
317         if (fScannerState == SCANNER_STATE_TEXT_DECL) {
318             // call handler
319
if (fDTDHandler != null) {
320                 fDTDHandler.startDTD(fEntityScanner, null);
321                 fStartDTDCalled = true;
322             }
323             // set starting state for internal subset
324
setScannerState(SCANNER_STATE_MARKUP_DECL);
325         }
326         // keep dispatching "events"
327
do {
328             if (!scanDecls(complete)) {
329                 // call handler
330
if (fDTDHandler != null && hasExternalSubset == false) {
331                     fDTDHandler.endDTD(null);
332                 }
333                 // we're done, set starting state for external subset
334
setScannerState(SCANNER_STATE_TEXT_DECL);
335                 return false;
336             }
337         } while (complete);
338
339         // return that there is more to scan
340
return true;
341
342     } // scanDTDInternalSubset(boolean,boolean,boolean):boolean
343

344     //
345
// XMLComponent methods
346
//
347

348     /**
349      * reset
350      *
351      * @param componentManager
352      */

353     public void reset(XMLComponentManager componentManager)
354         throws XMLConfigurationException {
355         
356         super.reset(componentManager);
357         init();
358
359     } // reset(XMLComponentManager)
360

361     // this is made for something like XMLDTDLoader--XMLComponentManager-free operation...
362
public void reset() {
363         super.reset();
364         init();
365     }
366
367     /**
368      * Returns a list of feature identifiers that are recognized by
369      * this component. This method may return null if no features
370      * are recognized by this component.
371      */

372     public String JavaDoc[] getRecognizedFeatures() {
373         return (String JavaDoc[])(RECOGNIZED_FEATURES.clone());
374     } // getRecognizedFeatures():String[]
375

376     /**
377      * Returns a list of property identifiers that are recognized by
378      * this component. This method may return null if no properties
379      * are recognized by this component.
380      */

381     public String JavaDoc[] getRecognizedProperties() {
382         return (String JavaDoc[])(RECOGNIZED_PROPERTIES.clone());
383     } // getRecognizedProperties():String[]
384

385     /**
386      * Returns the default state for a feature, or null if this
387      * component does not want to report a default value for this
388      * feature.
389      *
390      * @param featureId The feature identifier.
391      *
392      * @since Xerces 2.2.0
393      */

394     public Boolean JavaDoc getFeatureDefault(String JavaDoc featureId) {
395         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
396             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
397                 return FEATURE_DEFAULTS[i];
398             }
399         }
400         return null;
401     } // getFeatureDefault(String):Boolean
402

403     /**
404      * Returns the default state for a property, or null if this
405      * component does not want to report a default value for this
406      * property.
407      *
408      * @param propertyId The property identifier.
409      *
410      * @since Xerces 2.2.0
411      */

412     public Object JavaDoc getPropertyDefault(String JavaDoc propertyId) {
413         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
414             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
415                 return PROPERTY_DEFAULTS[i];
416             }
417         }
418         return null;
419     } // getPropertyDefault(String):Object
420

421     //
422
// XMLDTDSource methods
423
//
424

425     /**
426      * setDTDHandler
427      *
428      * @param dtdHandler
429      */

430     public void setDTDHandler(XMLDTDHandler dtdHandler) {
431         fDTDHandler = dtdHandler;
432     } // setDTDHandler(XMLDTDHandler)
433

434     /**
435      * getDTDHandler
436      *
437      * @return the XMLDTDHandler
438      */

439     public XMLDTDHandler getDTDHandler() {
440         return fDTDHandler;
441     } // getDTDHandler(): XMLDTDHandler
442

443     //
444
// XMLDTDContentModelSource methods
445
//
446

447     /**
448      * setDTDContentModelHandler
449      *
450      * @param dtdContentModelHandler
451      */

452     public void setDTDContentModelHandler(XMLDTDContentModelHandler
453                                           dtdContentModelHandler) {
454         fDTDContentModelHandler = dtdContentModelHandler;
455     } // setDTDContentModelHandler
456

457     /**
458      * getDTDContentModelHandler
459      *
460      * @return XMLDTDContentModelHandler
461      */

462     public XMLDTDContentModelHandler getDTDContentModelHandler() {
463         return fDTDContentModelHandler ;
464     } // setDTDContentModelHandler
465

466     //
467
// XMLEntityHandler methods
468
//
469

470     /**
471      * This method notifies of the start of an entity. The DTD has the
472      * pseudo-name of "[dtd]" parameter entity names start with '%'; and
473      * general entities are just specified by their name.
474      *
475      * @param name The name of the entity.
476      * @param identifier The resource identifier.
477      * @param encoding The auto-detected IANA encoding name of the entity
478      * stream. This value will be null in those situations
479      * where the entity encoding is not auto-detected (e.g.
480      * internal entities or a document entity that is
481      * parsed from a java.io.Reader).
482      * @param augs Additional information that may include infoset augmentations
483      *
484      * @throws XNIException Thrown by handler to signal an error.
485      */

486     public void startEntity(String JavaDoc name,
487                             XMLResourceIdentifier identifier,
488                             String JavaDoc encoding, Augmentations augs) throws XNIException {
489
490         super.startEntity(name, identifier, encoding, augs);
491
492         boolean dtdEntity = name.equals("[dtd]");
493         if (dtdEntity) {
494             // call handler
495
if (fDTDHandler != null && !fStartDTDCalled ) {
496                 fDTDHandler.startDTD(fEntityScanner, null);
497             }
498             if (fDTDHandler != null) {
499                 fDTDHandler.startExternalSubset(identifier,null);
500             }
501             fEntityManager.startExternalSubset();
502             fExtEntityDepth++;
503         }
504         else if (name.charAt(0) == '%') {
505             pushPEStack(fMarkUpDepth, fReportEntity);
506             if (fEntityScanner.isExternal()) {
507                 fExtEntityDepth++;
508             }
509         }
510
511         // call handler
512
if (fDTDHandler != null && !dtdEntity && fReportEntity) {
513             fDTDHandler.startParameterEntity(name, identifier, encoding, augs);
514         }
515
516     } // startEntity(String,XMLResourceIdentifier,String)
517

518     /**
519      * This method notifies the end of an entity. The DTD has the pseudo-name
520      * of "[dtd]" parameter entity names start with '%'; and general entities
521      * are just specified by their name.
522      *
523      * @param name The name of the entity.
524      * @param augs Additional information that may include infoset augmentations
525      *
526      * @throws XNIException Thrown by handler to signal an error.
527      */

528     public void endEntity(String JavaDoc name, Augmentations augs)
529         throws XNIException {
530
531         super.endEntity(name, augs);
532
533         // if there is no data after the doctype
534
//
535
if (fScannerState == SCANNER_STATE_END_OF_INPUT)
536             return;
537
538         // Handle end of PE
539
boolean reportEntity = fReportEntity;
540         if (name.startsWith("%")) {
541             reportEntity = peekReportEntity();
542             // check well-formedness of the enity
543
int startMarkUpDepth = popPEStack();
544             // throw fatalError if this entity was incomplete and
545
// was a freestanding decl
546
if(startMarkUpDepth == 0 &&
547                     startMarkUpDepth < fMarkUpDepth) {
548                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
549                                    "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL",
550                                    new Object JavaDoc[]{ fEntityManager.fCurrentEntity.name},
551                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
552             }
553             if (startMarkUpDepth != fMarkUpDepth) {
554                 reportEntity = false;
555                 if (fValidation) {
556                 // Proper nesting of parameter entities is a Validity Constraint
557
// and must not be enforced when validation is off
558
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
559                                            "ImproperDeclarationNesting",
560                                            new Object JavaDoc[]{ name },
561                                            XMLErrorReporter.SEVERITY_ERROR);
562                 }
563             }
564             if (fEntityScanner.isExternal()) {
565                 fExtEntityDepth--;
566             }
567         }
568
569         // call handler
570
boolean dtdEntity = name.equals("[dtd]");
571         if (fDTDHandler != null && !dtdEntity && reportEntity) {
572             fDTDHandler.endParameterEntity(name, augs);
573         }
574
575         // end DTD
576
if (dtdEntity) {
577             if (fIncludeSectDepth != 0) {
578                 reportFatalError("IncludeSectUnterminated", null);
579             }
580             fScannerState = SCANNER_STATE_END_OF_INPUT;
581             // call handler
582
fEntityManager.endExternalSubset();
583             if (fDTDHandler != null) {
584                 fDTDHandler.endExternalSubset(null);
585                 fDTDHandler.endDTD(null);
586             }
587             fExtEntityDepth--;
588         }
589
590     } // endEntity(String)
591

592     // helper methods
593

594     /**
595      * Sets the scanner state.
596      *
597      * @param state The new scanner state.
598      */

599     protected final void setScannerState(int state) {
600
601         fScannerState = state;
602         if (DEBUG_SCANNER_STATE) {
603             System.out.print("### setScannerState: ");
604             System.out.print(getScannerStateName(state));
605             System.out.println();
606         }
607
608     } // setScannerState(int)
609

610     //
611
// Private methods
612
//
613

614     /** Returns the scanner state name. */
615     private static String JavaDoc getScannerStateName(int state) {
616
617         if (DEBUG_SCANNER_STATE) {
618             switch (state) {
619                 case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
620                 case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
621                 case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL";
622             }
623         }
624
625         return "??? ("+state+')';
626
627     } // getScannerStateName(int):String
628

629     protected final boolean scanningInternalSubset() {
630         return fExtEntityDepth == 0;
631     }
632
633     /**
634      * start a parameter entity dealing with the textdecl if there is any
635      *
636      * @param name The name of the parameter entity to start (without the '%')
637      * @param literal Whether this is happening within a literal
638      */

639     protected void startPE(String JavaDoc name, boolean literal)
640         throws IOException JavaDoc, XNIException {
641         int depth = fPEDepth;
642         String JavaDoc pName = "%"+name;
643         if (fValidation && !fEntityManager.isDeclaredEntity(pName)) {
644             fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
645                                         new Object JavaDoc[]{name}, XMLErrorReporter.SEVERITY_ERROR);
646         }
647         fEntityManager.startEntity(fSymbolTable.addSymbol(pName),
648                                    literal);
649         // if we actually got a new entity and it's external
650
// parse text decl if there is any
651
if (depth != fPEDepth && fEntityScanner.isExternal()) {
652             scanTextDecl();
653         }
654     }
655
656     /**
657      * Dispatch an XML "event".
658      *
659      * @param complete True if this method is intended to scan
660      * and dispatch as much as possible.
661      *
662      * @return True if a TextDecl was scanned.
663      *
664      * @throws IOException Thrown on i/o error.
665      * @throws XNIException Thrown on parse error.
666      *
667      */

668     protected final boolean scanTextDecl()
669         throws IOException JavaDoc, XNIException {
670
671         // scan XMLDecl
672
boolean textDecl = false;
673         if (fEntityScanner.skipString("<?xml")) {
674             fMarkUpDepth++;
675             // NOTE: special case where document starts with a PI
676
// whose name starts with "xml" (e.g. "xmlfoo")
677
if (isValidNameChar(fEntityScanner.peekChar())) {
678                 fStringBuffer.clear();
679                 fStringBuffer.append("xml");
680                 if (fNamespaces) {
681                     while (isValidNCName(fEntityScanner.peekChar())) {
682                         fStringBuffer.append((char)fEntityScanner.scanChar());
683                     }
684                 }
685                 else {
686                     while (isValidNameChar(fEntityScanner.peekChar())) {
687                         fStringBuffer.append((char)fEntityScanner.scanChar());
688                     }
689                 }
690                 String JavaDoc target =
691                     fSymbolTable.addSymbol(fStringBuffer.ch,
692                                            fStringBuffer.offset,
693                                            fStringBuffer.length);
694                 scanPIData(target, fString);
695             }
696
697             // standard Text declaration
698
else {
699                 // pseudo-attribute values
700
String JavaDoc version = null;
701                 String JavaDoc encoding = null;
702
703                 scanXMLDeclOrTextDecl(true, fStrings);
704                 textDecl = true;
705                 fMarkUpDepth--;
706
707                 version = fStrings[0];
708                 encoding = fStrings[1];
709
710                 fEntityScanner.setXMLVersion(version);
711                 if (!fEntityScanner.fCurrentEntity.isEncodingExternallySpecified()) {
712                     fEntityScanner.setEncoding(encoding);
713                 }
714
715                 // call handler
716
if (fDTDHandler != null) {
717                     fDTDHandler.textDecl(version, encoding, null);
718                 }
719             }
720         }
721         fEntityManager.fCurrentEntity.mayReadChunks = true;
722
723         return textDecl;
724     
725     } // scanTextDecl(boolean):boolean
726

727     /**
728      * Scans a processing data. This is needed to handle the situation
729      * where a document starts with a processing instruction whose
730      * target name <em>starts with</em> "xml". (e.g. xmlfoo)
731      *
732      * @param target The PI target
733      * @param data The string to fill in with the data
734      */

735     protected final void scanPIData(String JavaDoc target, XMLString data)
736         throws IOException JavaDoc, XNIException {
737
738         super.scanPIData(target, data);
739         fMarkUpDepth--;
740
741         // call handler
742
if (fDTDHandler != null) {
743             fDTDHandler.processingInstruction(target, data, null);
744         }
745
746     } // scanPIData(String)
747

748     /**
749      * Scans a comment.
750      * <p>
751      * <pre>
752      * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
753      * </pre>
754      * <p>
755      * <strong>Note:</strong> Called after scanning past '&lt;!--'
756      */

757     protected final void scanComment() throws IOException JavaDoc, XNIException {
758
759         fReportEntity = false;
760         scanComment(fStringBuffer);
761         fMarkUpDepth--;
762
763         // call handler
764
if (fDTDHandler != null) {
765             fDTDHandler.comment(fStringBuffer, null);
766         }
767         fReportEntity = true;
768
769     } // scanComment()
770

771     /**
772      * Scans an element declaration
773      * <p>
774      * <pre>
775      * [45] elementdecl ::= '&lt;!ELEMENT' S Name S contentspec S? '>'
776      * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
777      * </pre>
778      * <p>
779      * <strong>Note:</strong> Called after scanning past '&lt;!ELEMENT'
780      */

781     protected final void scanElementDecl() throws IOException JavaDoc, XNIException {
782
783         // spaces
784
fReportEntity = false;
785         if (!skipSeparator(true, !scanningInternalSubset())) {
786             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL",
787                              null);
788         }
789
790         // element name
791
String JavaDoc name = fEntityScanner.scanName();
792         if (name == null) {
793             reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL",
794                              null);
795         }
796
797         // spaces
798
if (!skipSeparator(true, !scanningInternalSubset())) {
799             reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL",
800                              new Object JavaDoc[]{name});
801         }
802
803         // content model
804
if (fDTDContentModelHandler != null) {
805             fDTDContentModelHandler.startContentModel(name, null);
806         }
807         String JavaDoc contentModel = null;
808         fReportEntity = true;
809         if (fEntityScanner.skipString("EMPTY")) {
810             contentModel = "EMPTY";
811             // call handler
812
if (fDTDContentModelHandler != null) {
813                 fDTDContentModelHandler.empty(null);
814             }
815         }
816         else if (fEntityScanner.skipString("ANY")) {
817             contentModel = "ANY";
818             // call handler
819
if (fDTDContentModelHandler != null) {
820                 fDTDContentModelHandler.any(null);
821             }
822         }
823         else {
824             if (!fEntityScanner.skipChar('(')) {
825                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
826                                  new Object JavaDoc[]{name});
827             }
828             if (fDTDContentModelHandler != null) {
829                 fDTDContentModelHandler.startGroup(null);
830             }
831             fStringBuffer.clear();
832             fStringBuffer.append('(');
833             fMarkUpDepth++;
834             skipSeparator(false, !scanningInternalSubset());
835
836             // Mixed content model
837
if (fEntityScanner.skipString("#PCDATA")) {
838                 scanMixed(name);
839             }
840             else { // children content
841
scanChildren(name);
842             }
843             contentModel = fStringBuffer.toString();
844         }
845
846         // call handler
847
if (fDTDContentModelHandler != null) {
848             fDTDContentModelHandler.endContentModel(null);
849         }
850
851         fReportEntity = false;
852         skipSeparator(false, !scanningInternalSubset());
853         // end
854
if (!fEntityScanner.skipChar('>')) {
855             reportFatalError("ElementDeclUnterminated", new Object JavaDoc[]{name});
856         }
857         fReportEntity = true;
858         fMarkUpDepth--;
859         
860         // call handler
861
if (fDTDHandler != null) {
862             fDTDHandler.elementDecl(name, contentModel, null);
863         }
864
865     } // scanElementDecl()
866

867     /**
868      * scan Mixed content model
869      * This assumes the content model has been parsed up to #PCDATA and
870      * can simply append to fStringBuffer.
871      * <pre>
872      * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'
873      * | '(' S? '#PCDATA' S? ')'
874      * </pre>
875      *
876      * @param elName The element type name this declaration is about.
877      *
878      * <strong>Note:</strong> Called after scanning past '(#PCDATA'.
879      */

880     private final void scanMixed(String JavaDoc elName)
881         throws IOException JavaDoc, XNIException {
882
883         String JavaDoc childName = null;
884
885         fStringBuffer.append("#PCDATA");
886         // call handler
887
if (fDTDContentModelHandler != null) {
888             fDTDContentModelHandler.pcdata(null);
889         }
890         skipSeparator(false, !scanningInternalSubset());
891         while (fEntityScanner.skipChar('|')) {
892             fStringBuffer.append('|');
893             // call handler
894
if (fDTDContentModelHandler != null) {
895                 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
896                                                   null);
897             }
898             skipSeparator(false, !scanningInternalSubset());
899
900             childName = fEntityScanner.scanName();
901             if (childName == null) {
902                 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
903                                  new Object JavaDoc[]{elName});
904             }
905             fStringBuffer.append(childName);
906             // call handler
907
if (fDTDContentModelHandler != null) {
908                 fDTDContentModelHandler.element(childName, null);
909             }
910             skipSeparator(false, !scanningInternalSubset());
911         }
912         // The following check must be done in a single call (as opposed to one
913
// for ')' and then one for '*') to guarantee that callbacks are
914
// properly nested. We do not want to trigger endEntity too early in
915
// case we cross the boundary of an entity between the two characters.
916
if (fEntityScanner.skipString(")*")) {
917             fStringBuffer.append(")*");
918             // call handler
919
if (fDTDContentModelHandler != null) {
920                 fDTDContentModelHandler.endGroup(null);
921                 fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE,
922                                                    null);
923             }
924         }
925         else if (childName != null) {
926             reportFatalError("MixedContentUnterminated",
927                              new Object JavaDoc[]{elName});
928         }
929         else if (fEntityScanner.skipChar(')')){
930             fStringBuffer.append(')');
931             // call handler
932
if (fDTDContentModelHandler != null) {
933                 fDTDContentModelHandler.endGroup(null);
934             }
935         }
936         else {
937             reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
938                              new Object JavaDoc[]{elName});
939         }
940         fMarkUpDepth--;
941         // we are done
942
}
943
944     /**
945      * scan children content model
946      * This assumes it can simply append to fStringBuffer.
947      * <pre>
948      * [47] children ::= (choice | seq) ('?' | '*' | '+')?
949      * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
950      * [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
951      * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
952      * </pre>
953      *
954      * @param elName The element type name this declaration is about.
955      *
956      * <strong>Note:</strong> Called after scanning past the first open
957      * paranthesis.
958      */

959     private final void scanChildren(String JavaDoc elName)
960         throws IOException JavaDoc, XNIException {
961
962         fContentDepth = 0;
963         pushContentStack(0);
964         int currentOp = 0;
965         int c;
966         while (true) {
967             if (fEntityScanner.skipChar('(')) {
968                 fMarkUpDepth++;
969                 fStringBuffer.append('(');
970                 // call handler
971
if (fDTDContentModelHandler != null) {
972                     fDTDContentModelHandler.startGroup(null);
973                 }
974                 // push current op on stack and reset it
975
pushContentStack(currentOp);
976                 currentOp = 0;
977                 skipSeparator(false, !scanningInternalSubset());
978                 continue;
979             }
980             skipSeparator(false, !scanningInternalSubset());
981             String JavaDoc childName = fEntityScanner.scanName();
982             if (childName == null) {
983                 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
984                                  new Object JavaDoc[]{elName});
985                 return;
986             }
987             // call handler
988
if (fDTDContentModelHandler != null) {
989                 fDTDContentModelHandler.element(childName, null);
990             }
991             fStringBuffer.append(childName);
992             c = fEntityScanner.peekChar();
993             if (c == '?' || c == '*' || c == '+') {
994                 // call handler
995
if (fDTDContentModelHandler != null) {
996                     short oc;
997                     if (c == '?') {
998                         oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
999                     }
1000                    else if (c == '*') {
1001                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1002                    }
1003                    else {
1004                        oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1005                    }
1006                    fDTDContentModelHandler.occurrence(oc, null);
1007                }
1008                fEntityScanner.scanChar();
1009                fStringBuffer.append((char)c);
1010            }
1011            while (true) {
1012                skipSeparator(false, !scanningInternalSubset());
1013                c = fEntityScanner.peekChar();
1014                if (c == ',' && currentOp != '|') {
1015                    currentOp = c;
1016                    // call handler
1017
if (fDTDContentModelHandler != null) {
1018                        fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
1019                                                          null);
1020                    }
1021                    fEntityScanner.scanChar();
1022                    fStringBuffer.append(',');
1023                    break;
1024                }
1025                else if (c == '|' && currentOp != ',') {
1026                    currentOp = c;
1027                    // call handler
1028
if (fDTDContentModelHandler != null) {
1029                        fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
1030                                                          null);
1031                    }
1032                    fEntityScanner.scanChar();
1033                    fStringBuffer.append('|');
1034                    break;
1035                }
1036                else if (c != ')') {
1037                    reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1038                                     new Object JavaDoc[]{elName});
1039                }
1040                // call handler
1041
if (fDTDContentModelHandler != null) {
1042                    fDTDContentModelHandler.endGroup(null);
1043                }
1044                // restore previous op
1045
currentOp = popContentStack();
1046                short oc;
1047                // The following checks must be done in a single call (as
1048
// opposed to one for ')' and then one for '?', '*', and '+')
1049
// to guarantee that callbacks are properly nested. We do not
1050
// want to trigger endEntity too early in case we cross the
1051
// boundary of an entity between the two characters.
1052
if (fEntityScanner.skipString(")?")) {
1053                    fStringBuffer.append(")?");
1054                    // call handler
1055
if (fDTDContentModelHandler != null) {
1056                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1057                        fDTDContentModelHandler.occurrence(oc, null);
1058                    }
1059                }
1060                else if (fEntityScanner.skipString(")+")) {
1061                    fStringBuffer.append(")+");
1062                    // call handler
1063
if (fDTDContentModelHandler != null) {
1064                        oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1065                        fDTDContentModelHandler.occurrence(oc, null);
1066                    }
1067                }
1068                else if (fEntityScanner.skipString(")*")) {
1069                    fStringBuffer.append(")*");
1070                    // call handler
1071
if (fDTDContentModelHandler != null) {
1072                        oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1073                        fDTDContentModelHandler.occurrence(oc, null);
1074                    }
1075                }
1076                else {
1077                    // no occurrence specified
1078
fEntityScanner.scanChar();
1079                    fStringBuffer.append(')');
1080                }
1081                fMarkUpDepth--;
1082                if (fContentDepth == 0) {
1083                    return;
1084                }
1085            }
1086            skipSeparator(false, !scanningInternalSubset());
1087        }
1088    }
1089
1090    /**
1091     * Scans an attlist declaration
1092     * <p>
1093     * <pre>
1094     * [52] AttlistDecl ::= '&lt;!ATTLIST' S Name AttDef* S? '>'
1095     * [53] AttDef ::= S Name S AttType S DefaultDecl
1096     * </pre>
1097     * <p>
1098     * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1099     */

1100    protected final void scanAttlistDecl() throws IOException JavaDoc, XNIException {
1101
1102        // spaces
1103
fReportEntity = false;
1104        if (!skipSeparator(true, !scanningInternalSubset())) {
1105            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL",
1106                             null);
1107        }
1108
1109        // element name
1110
String JavaDoc elName = fEntityScanner.scanName();
1111        if (elName == null) {
1112            reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL",
1113                             null);
1114        }
1115
1116        // call handler
1117
if (fDTDHandler != null) {
1118            fDTDHandler.startAttlist(elName, null);
1119        }
1120
1121        // spaces
1122
if (!skipSeparator(true, !scanningInternalSubset())) {
1123            // no space, is it the end yet?
1124
if (fEntityScanner.skipChar('>')) {
1125                // yes, stop here
1126
// call handler
1127
if (fDTDHandler != null) {
1128                    fDTDHandler.endAttlist(null);
1129                }
1130                fMarkUpDepth--;
1131                return;
1132            }
1133            else {
1134                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF",
1135                                 new Object JavaDoc[]{elName});
1136            }
1137        }
1138
1139        // definitions
1140
while (!fEntityScanner.skipChar('>')) {
1141            String JavaDoc name = fEntityScanner.scanName();
1142            if (name == null) {
1143                reportFatalError("AttNameRequiredInAttDef",
1144                                 new Object JavaDoc[]{elName});
1145            }
1146            // spaces
1147
if (!skipSeparator(true, !scanningInternalSubset())) {
1148                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF",
1149                                 new Object JavaDoc[]{elName, name});
1150            }
1151            // type
1152
String JavaDoc type = scanAttType(elName, name);
1153
1154            // spaces
1155
if (!skipSeparator(true, !scanningInternalSubset())) {
1156                reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF",
1157                                 new Object JavaDoc[]{elName, name});
1158            }
1159
1160            // default decl
1161
String JavaDoc defaultType = scanAttDefaultDecl(elName, name,
1162                                                    type,
1163                                                    fLiteral, fLiteral2);
1164            // REVISIT: Should we do anything with the non-normalized
1165
// default attribute value? -Ac
1166
// yes--according to bug 5073. - neilg
1167

1168            // call handler
1169
if (fDTDHandler != null) {
1170                String JavaDoc[] enumeration = null;
1171                if (fEnumerationCount != 0) {
1172                    enumeration = new String JavaDoc[fEnumerationCount];
1173                    System.arraycopy(fEnumeration, 0, enumeration,
1174                                     0, fEnumerationCount);
1175                }
1176                // Determine whether the default value to be passed should be null.
1177
// REVISIT: should probably check whether fLiteral.ch is null instead. LM.
1178
if (defaultType!=null && (defaultType.equals("#REQUIRED") ||
1179                                          defaultType.equals("#IMPLIED"))) {
1180                    fDTDHandler.attributeDecl(elName, name, type, enumeration,
1181                                              defaultType, null, null, null);
1182                }
1183                else {
1184                    fDTDHandler.attributeDecl(elName, name, type, enumeration,
1185                                              defaultType, fLiteral, fLiteral2, null);
1186                }
1187            }
1188            skipSeparator(false, !scanningInternalSubset());
1189        }
1190
1191        // call handler
1192
if (fDTDHandler != null) {
1193            fDTDHandler.endAttlist(null);
1194        }
1195        fMarkUpDepth--;
1196        fReportEntity = true;
1197
1198    } // scanAttlistDecl()
1199

1200    /**
1201     * Scans an attribute type definition
1202     * <p>
1203     * <pre>
1204     * [54] AttType ::= StringType | TokenizedType | EnumeratedType
1205     * [55] StringType ::= 'CDATA'
1206     * [56] TokenizedType ::= 'ID'
1207     * | 'IDREF'
1208     * | 'IDREFS'
1209     * | 'ENTITY'
1210     * | 'ENTITIES'
1211     * | 'NMTOKEN'
1212     * | 'NMTOKENS'
1213     * [57] EnumeratedType ::= NotationType | Enumeration
1214     * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
1215     * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
1216     * </pre>
1217     * <p>
1218     * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1219     *
1220     * @param elName The element type name this declaration is about.
1221     * @param atName The attribute name this declaration is about.
1222     */

1223    private final String JavaDoc scanAttType(String JavaDoc elName, String JavaDoc atName)
1224        throws IOException JavaDoc, XNIException {
1225
1226        String JavaDoc type = null;
1227        fEnumerationCount = 0;
1228        /*
1229         * Watchout: the order here is important: when a string happens to
1230         * be a substring of another string, the longer one needs to be
1231         * looked for first!!
1232         */

1233        if (fEntityScanner.skipString("CDATA")) {
1234            type = "CDATA";
1235        }
1236        else if (fEntityScanner.skipString("IDREFS")) {
1237            type = "IDREFS";
1238        }
1239        else if (fEntityScanner.skipString("IDREF")) {
1240            type = "IDREF";
1241        }
1242        else if (fEntityScanner.skipString("ID")) {
1243            type = "ID";
1244        }
1245        else if (fEntityScanner.skipString("ENTITY")) {
1246            type = "ENTITY";
1247        }
1248        else if (fEntityScanner.skipString("ENTITIES")) {
1249            type = "ENTITIES";
1250        }
1251        else if (fEntityScanner.skipString("NMTOKENS")) {
1252            type = "NMTOKENS";
1253        }
1254        else if (fEntityScanner.skipString("NMTOKEN")) {
1255            type = "NMTOKEN";
1256        }
1257        else if (fEntityScanner.skipString("NOTATION")) {
1258            type = "NOTATION";
1259            // spaces
1260
if (!skipSeparator(true, !scanningInternalSubset())) {
1261                reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE",
1262                                 new Object JavaDoc[]{elName, atName});
1263            }
1264            // open paren
1265
int c = fEntityScanner.scanChar();
1266            if (c != '(') {
1267                reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
1268                                 new Object JavaDoc[]{elName, atName});
1269            }
1270            fMarkUpDepth++;
1271            do {
1272                skipSeparator(false, !scanningInternalSubset());
1273                String JavaDoc aName = fEntityScanner.scanName();
1274                if (aName == null) {
1275                    reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
1276                                     new Object JavaDoc[]{elName, atName});
1277                }
1278                ensureEnumerationSize(fEnumerationCount + 1);
1279                fEnumeration[fEnumerationCount++] = aName;
1280                skipSeparator(false, !scanningInternalSubset());
1281                c = fEntityScanner.scanChar();
1282            } while (c == '|');
1283            if (c != ')') {
1284                reportFatalError("NotationTypeUnterminated",
1285                                 new Object JavaDoc[]{elName, atName});
1286            }
1287            fMarkUpDepth--;
1288        }
1289        else { // Enumeration
1290
type = "ENUMERATION";
1291            // open paren
1292
int c = fEntityScanner.scanChar();
1293            if (c != '(') {
1294// "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
1295
reportFatalError("AttTypeRequiredInAttDef",
1296                                 new Object JavaDoc[]{elName, atName});
1297            }
1298            fMarkUpDepth++;
1299            do {
1300                skipSeparator(false, !scanningInternalSubset());
1301                String JavaDoc token = fEntityScanner.scanNmtoken();
1302                if (token == null) {
1303                    reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION",
1304                                     new Object JavaDoc[]{elName, atName});
1305                }
1306                ensureEnumerationSize(fEnumerationCount + 1);
1307                fEnumeration[fEnumerationCount++] = token;
1308                skipSeparator(false, !scanningInternalSubset());
1309                c = fEntityScanner.scanChar();
1310            } while (c == '|');
1311            if (c != ')') {
1312                reportFatalError("EnumerationUnterminated",
1313                                 new Object JavaDoc[]{elName, atName});
1314            }
1315            fMarkUpDepth--;
1316        }
1317        return type;
1318
1319    } // scanAttType():String
1320

1321
1322    /**
1323     * Scans an attribute default declaration
1324     * <p>
1325     * <pre>
1326     * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
1327     * </pre>
1328     *
1329     * @param name The name of the attribute being scanned.
1330     * @param defaultVal The string to fill in with the default value.
1331     */

1332    protected final String JavaDoc scanAttDefaultDecl(String JavaDoc elName, String JavaDoc atName,
1333                                              String JavaDoc type,
1334                                              XMLString defaultVal,
1335                                              XMLString nonNormalizedDefaultVal)
1336        throws IOException JavaDoc, XNIException {
1337
1338        String JavaDoc defaultType = null;
1339        fString.clear();
1340        defaultVal.clear();
1341        if (fEntityScanner.skipString("#REQUIRED")) {
1342            defaultType = "#REQUIRED";
1343        }
1344        else if (fEntityScanner.skipString("#IMPLIED")) {
1345            defaultType = "#IMPLIED";
1346        }
1347        else {
1348            if (fEntityScanner.skipString("#FIXED")) {
1349                defaultType = "#FIXED";
1350                // spaces
1351
if (!skipSeparator(true, !scanningInternalSubset())) {
1352                    reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL",
1353                                     new Object JavaDoc[]{elName, atName});
1354                }
1355            }
1356            // AttValue
1357
boolean isVC = !fStandalone && (fSeenExternalDTD || fSeenExternalPE) ;
1358            scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName, isVC, elName);
1359        }
1360        return defaultType;
1361
1362    } // ScanAttDefaultDecl
1363

1364    /**
1365     * Scans an entity declaration
1366     * <p>
1367     * <pre>
1368     * [70] EntityDecl ::= GEDecl | PEDecl
1369     * [71] GEDecl ::= '&lt;!ENTITY' S Name S EntityDef S? '>'
1370     * [72] PEDecl ::= '&lt;!ENTITY' S '%' S Name S PEDef S? '>'
1371     * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
1372     * [74] PEDef ::= EntityValue | ExternalID
1373     * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1374     * | 'PUBLIC' S PubidLiteral S SystemLiteral
1375     * [76] NDataDecl ::= S 'NDATA' S Name
1376     * </pre>
1377     * <p>
1378     * <strong>Note:</strong> Called after scanning past '&lt;!ENTITY'
1379     */

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

1563    /**
1564     * Scans an entity value.
1565     *
1566     * @param value The string to fill in with the value.
1567     * @param nonNormalizedValue The string to fill in with the
1568     * non-normalized value.
1569     *
1570     * <strong>Note:</strong> This method uses fString, fStringBuffer (through
1571     * the use of scanCharReferenceValue), and fStringBuffer2, anything in them
1572     * at the time of calling is lost.
1573     */

1574    protected final void scanEntityValue(XMLString value,
1575                                         XMLString nonNormalizedValue)
1576        throws IOException JavaDoc, XNIException
1577    {
1578        int quote = fEntityScanner.scanChar();
1579        if (quote != '\'' && quote != '"') {
1580            reportFatalError("OpenQuoteMissingInDecl", null);
1581        }
1582        // store at which depth of entities we start
1583
int entityDepth = fEntityDepth;
1584
1585        XMLString literal = fString;
1586        XMLString literal2 = fString;
1587        if (fEntityScanner.scanLiteral(quote, fString) != quote) {
1588            fStringBuffer.clear();
1589            fStringBuffer2.clear();
1590            do {
1591                fStringBuffer.append(fString);
1592                fStringBuffer2.append(fString);
1593                if (fEntityScanner.skipChar('&')) {
1594                    if (fEntityScanner.skipChar('#')) {
1595                        fStringBuffer2.append("&#");
1596                        scanCharReferenceValue(fStringBuffer, fStringBuffer2);
1597                    }
1598                    else {
1599                        fStringBuffer.append('&');
1600                        fStringBuffer2.append('&');
1601                        String JavaDoc eName = fEntityScanner.scanName();
1602                        if (eName == null) {
1603                            reportFatalError("NameRequiredInReference",
1604                                             null);
1605                        }
1606                        else {
1607                            fStringBuffer.append(eName);
1608                            fStringBuffer2.append(eName);
1609                        }
1610                        if (!fEntityScanner.skipChar(';')) {
1611                            reportFatalError("SemicolonRequiredInReference",
1612                                             new Object JavaDoc[]{eName});
1613                        }
1614                        else {
1615                            fStringBuffer.append(';');
1616                            fStringBuffer2.append(';');
1617                        }
1618                    }
1619                }
1620                else if (fEntityScanner.skipChar('%')) {
1621                    while (true) {
1622                        fStringBuffer2.append('%');
1623                        String JavaDoc peName = fEntityScanner.scanName();
1624                        if (peName == null) {
1625                            reportFatalError("NameRequiredInPEReference",
1626                                             null);
1627                        }
1628                        else if (!fEntityScanner.skipChar(';')) {
1629                            reportFatalError("SemicolonRequiredInPEReference",
1630                                             new Object JavaDoc[]{peName});
1631                        }
1632                        else {
1633                            if (scanningInternalSubset()) {
1634                                reportFatalError("PEReferenceWithinMarkup",
1635                                                 new Object JavaDoc[]{peName});
1636                            }
1637                            fStringBuffer2.append(peName);
1638                            fStringBuffer2.append(';');
1639                        }
1640                        startPE(peName, true);
1641                        // REVISIT: [Q] Why do we skip spaces here? -Ac
1642
// REVISIT: This will make returning the non-
1643
// normalized value harder. -Ac
1644
fEntityScanner.skipSpaces();
1645                        if (!fEntityScanner.skipChar('%'))
1646                            break;
1647                    }
1648                }
1649                else {
1650                    int c = fEntityScanner.peekChar();
1651                    if (XMLChar.isHighSurrogate(c)) {
1652                        scanSurrogates(fStringBuffer2);
1653                    }
1654                    else if (isInvalidLiteral(c)) {
1655                        reportFatalError("InvalidCharInLiteral",
1656                                         new Object JavaDoc[]{Integer.toHexString(c)});
1657                        fEntityScanner.scanChar();
1658                    }
1659                    // if it's not the delimiting quote or if it is but from a
1660
// different entity than the one this literal started from,
1661
// simply append the character to our buffer
1662
else if (c != quote || entityDepth != fEntityDepth) {
1663                        fStringBuffer.append((char)c);
1664                        fStringBuffer2.append((char)c);
1665                        fEntityScanner.scanChar();
1666                    }
1667                }
1668            } while (fEntityScanner.scanLiteral(quote, fString) != quote);
1669            fStringBuffer.append(fString);
1670            fStringBuffer2.append(fString);
1671            literal = fStringBuffer;
1672            literal2 = fStringBuffer2;
1673        }
1674        value.setValues(literal);
1675        nonNormalizedValue.setValues(literal2);
1676        if (!fEntityScanner.skipChar(quote)) {
1677            reportFatalError("CloseQuoteMissingInDecl", null);
1678        }
1679    } // scanEntityValue(XMLString,XMLString):void
1680

1681    /**
1682     * Scans a notation declaration
1683     * <p>
1684     * <pre>
1685     * [82] NotationDecl ::= '&lt;!NOTATION' S Name S (ExternalID|PublicID) S? '>'
1686     * [83] PublicID ::= 'PUBLIC' S PubidLiteral
1687     * </pre>
1688     * <p>
1689     * <strong>Note:</strong> Called after scanning past '&lt;!NOTATION'
1690     */

1691    private final void scanNotationDecl() throws IOException JavaDoc, XNIException {
1692
1693        // spaces
1694
fReportEntity = false;
1695        if (!skipSeparator(true, !scanningInternalSubset())) {
1696            reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL",
1697                             null);
1698        }
1699
1700        // notation name
1701
String JavaDoc name = null;
1702        if(fNamespaces) {
1703            name = fEntityScanner.scanNCName();
1704        } else {
1705            name = fEntityScanner.scanName();
1706        }
1707        if (name == null) {
1708            reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
1709                             null);
1710        }
1711
1712        // spaces
1713
if (!skipSeparator(true, !scanningInternalSubset())) {
1714            // check for invalid ":"
1715
if(fNamespaces && fEntityScanner.peekChar() == ':') {
1716                fEntityScanner.scanChar();
1717                XMLStringBuffer colonName = new XMLStringBuffer(name);
1718                colonName.append(":");
1719                colonName.append(fEntityScanner.scanName());
1720                reportFatalError("ColonNotLegalWithNS", new Object JavaDoc[] {colonName.toString()});
1721                skipSeparator(true, !scanningInternalSubset());
1722            } else {
1723                reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL",
1724                                new Object JavaDoc[]{name});
1725            }
1726        }
1727
1728        // external id
1729
scanExternalID(fStrings, true);
1730        String JavaDoc systemId = fStrings[0];
1731        String JavaDoc publicId = fStrings[1];
1732        String JavaDoc baseSystemId = fEntityScanner.getBaseSystemId();
1733
1734        if (systemId == null && publicId == null) {
1735            reportFatalError("ExternalIDorPublicIDRequired",
1736                             new Object JavaDoc[]{name});
1737       }
1738
1739        // skip possible trailing space
1740
skipSeparator(false, !scanningInternalSubset());
1741
1742        // end
1743
if (!fEntityScanner.skipChar('>')) {
1744            reportFatalError("NotationDeclUnterminated", new Object JavaDoc[]{name});
1745        }
1746        fMarkUpDepth--;
1747
1748        // call handler
1749
if (fDTDHandler != null) {
1750            fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false));
1751            fDTDHandler.notationDecl(name, fResourceIdentifier, null);
1752        }
1753        fReportEntity = true;
1754
1755    } // scanNotationDecl()
1756

1757    /**
1758     * Scans a conditional section. If it's a section to ignore the whole
1759     * section gets scanned through and this method only returns after the
1760     * closing bracket has been found. When it's an include section though, it
1761     * returns to let the main loop take care of scanning it. In that case the
1762     * end of the section if handled by the main loop (scanDecls).
1763     * <p>
1764     * <pre>
1765     * [61] conditionalSect ::= includeSect | ignoreSect
1766     * [62] includeSect ::= '&lt;![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1767     * [63] ignoreSect ::= '&lt;![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
1768     * [64] ignoreSectContents ::= Ignore ('&lt;![' ignoreSectContents ']]>' Ignore)*
1769     * [65] Ignore ::= Char* - (Char* ('&lt;![' | ']]>') Char*)
1770     * </pre>
1771     * <p>
1772     * <strong>Note:</strong> Called after scanning past '&lt;![' */

1773    private final void scanConditionalSect(int currPEDepth)
1774        throws IOException JavaDoc, XNIException {
1775
1776        fReportEntity = false;
1777        skipSeparator(false, !scanningInternalSubset());
1778
1779        if (fEntityScanner.skipString("INCLUDE")) {
1780            skipSeparator(false, !scanningInternalSubset());
1781            if(currPEDepth != fPEDepth && fValidation) {
1782                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1783                                           "INVALID_PE_IN_CONDITIONAL",
1784                                           new Object JavaDoc[]{ fEntityManager.fCurrentEntity.name},
1785                                           XMLErrorReporter.SEVERITY_ERROR);
1786            }
1787            // call handler
1788
if (!fEntityScanner.skipChar('[')) {
1789                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1790            }
1791
1792            if (fDTDHandler != null) {
1793                fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE,
1794                                             null);
1795            }
1796            fIncludeSectDepth++;
1797            // just stop there and go back to the main loop
1798
fReportEntity = true;
1799        }
1800        else if (fEntityScanner.skipString("IGNORE")) {
1801            skipSeparator(false, !scanningInternalSubset());
1802            if(currPEDepth != fPEDepth && fValidation) {
1803                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1804                                           "INVALID_PE_IN_CONDITIONAL",
1805                                           new Object JavaDoc[]{ fEntityManager.fCurrentEntity.name},
1806                                           XMLErrorReporter.SEVERITY_ERROR);
1807            }
1808            // call handler
1809
if (fDTDHandler != null) {
1810                fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE,
1811                                             null);
1812            }
1813            if (!fEntityScanner.skipChar('[')) {
1814                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1815            }
1816            fReportEntity = true;
1817            int initialDepth = ++fIncludeSectDepth;
1818            if (fDTDHandler != null) {
1819                fIgnoreConditionalBuffer.clear();
1820            }
1821            while (true) {
1822                if (fEntityScanner.skipChar('<')) {
1823                    if (fDTDHandler != null) {
1824                        fIgnoreConditionalBuffer.append('<');
1825                    }
1826                    //
1827
// These tests are split so that we handle cases like
1828
// '<<![' and '<!<![' which we might otherwise miss.
1829
//
1830
if (fEntityScanner.skipChar('!')) {
1831                        if(fEntityScanner.skipChar('[')) {
1832                            if (fDTDHandler != null) {
1833                                fIgnoreConditionalBuffer.append("![");
1834                            }
1835                            fIncludeSectDepth++;
1836                        } else {
1837                            if (fDTDHandler != null) {
1838                                fIgnoreConditionalBuffer.append("!");
1839                            }
1840                        }
1841                    }
1842                }
1843                else if (fEntityScanner.skipChar(']')) {
1844                    if (fDTDHandler != null) {
1845                        fIgnoreConditionalBuffer.append(']');
1846                    }
1847                    //
1848
// The same thing goes for ']<![' and '<]]>', etc.
1849
//
1850
if (fEntityScanner.skipChar(']')) {
1851                        if (fDTDHandler != null) {
1852                            fIgnoreConditionalBuffer.append(']');
1853                        }
1854                        while (fEntityScanner.skipChar(']')) {
1855                            /* empty loop body */
1856                            if (fDTDHandler != null) {
1857                                fIgnoreConditionalBuffer.append(']');
1858                            }
1859                        }
1860                        if (fEntityScanner.skipChar('>')) {
1861                            if (fIncludeSectDepth-- == initialDepth) {
1862                                fMarkUpDepth--;
1863                                // call handler
1864
if (fDTDHandler != null) {
1865                                    fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0,
1866                                                       fIgnoreConditionalBuffer.length - 2);
1867                                    fDTDHandler.ignoredCharacters(fLiteral, null);
1868                                    fDTDHandler.endConditional(null);
1869                                }
1870                                return;
1871                            } else if(fDTDHandler != null) {
1872                                fIgnoreConditionalBuffer.append('>');
1873                            }
1874                        }
1875                    }
1876                }
1877                else {
1878                    int c = fEntityScanner.scanChar();
1879                    if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
1880                        reportFatalError("IgnoreSectUnterminated", null);
1881                        return;
1882                    }
1883                    if (fDTDHandler != null) {
1884                        fIgnoreConditionalBuffer.append((char)c);
1885                    }
1886                }
1887            }
1888        }
1889        else {
1890            reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1891        }
1892
1893    } // scanConditionalSect()
1894

1895    /**
1896     * Dispatch an XML "event".
1897     *
1898     * @param complete True if this method is intended to scan
1899     * and dispatch as much as possible.
1900     *
1901     * @return True if there is more to scan.
1902     *
1903     * @throws IOException Thrown on i/o error.
1904     * @throws XNIException Thrown on parse error.
1905     *
1906     */

1907    protected final boolean scanDecls(boolean complete)
1908            throws IOException JavaDoc, XNIException {
1909        
1910        skipSeparator(false, true);
1911        boolean again = true;
1912        while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
1913            again = complete;
1914            if (fEntityScanner.skipChar('<')) {
1915                fMarkUpDepth++;
1916                if (fEntityScanner.skipChar('?')) {
1917                    scanPI();
1918                }
1919                else if (fEntityScanner.skipChar('!')) {
1920                    if (fEntityScanner.skipChar('-')) {
1921                        if (!fEntityScanner.skipChar('-')) {
1922                            reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1923                                             null);
1924                        } else {
1925                            scanComment();
1926                        }
1927                    }
1928                    else if (fEntityScanner.skipString("ELEMENT")) {
1929                        scanElementDecl();
1930                    }
1931                    else if (fEntityScanner.skipString("ATTLIST")) {
1932                        scanAttlistDecl();
1933                    }
1934                    else if (fEntityScanner.skipString("ENTITY")) {
1935                        scanEntityDecl();
1936                    }
1937                    else if (fEntityScanner.skipString("NOTATION")) {
1938                        scanNotationDecl();
1939                    }
1940                    else if (fEntityScanner.skipChar('[') &&
1941                             !scanningInternalSubset()) {
1942                        scanConditionalSect(fPEDepth);
1943                    }
1944                    else {
1945                        fMarkUpDepth--;
1946                        reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1947                                         null);
1948                    }
1949                }
1950                else {
1951                    fMarkUpDepth--;
1952                    reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1953                }
1954            }
1955            else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) {
1956                // end of conditional section?
1957
if (!fEntityScanner.skipChar(']')
1958                    || !fEntityScanner.skipChar('>')) {
1959                    reportFatalError("IncludeSectUnterminated", null);
1960                }
1961                // call handler
1962
if (fDTDHandler != null) {
1963                    fDTDHandler.endConditional(null);
1964                }
1965                // decreaseMarkupDepth();
1966
fIncludeSectDepth--;
1967                fMarkUpDepth--;
1968            }
1969            else if (scanningInternalSubset() &&
1970                     fEntityScanner.peekChar() == ']') {
1971                // this is the end of the internal subset, let's stop here
1972
return false;
1973            }
1974            else if (fEntityScanner.skipSpaces()) {
1975                // simply skip
1976
}
1977            else {
1978                reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1979                // Skip the part in error
1980
int ch;
1981                do {
1982                    // Ignore the current character
1983
fEntityScanner.scanChar();
1984                    // Skip any separators
1985
skipSeparator(false, true);
1986                    // Keeping getting the next character,
1987
// until it's one of the expected ones
1988
ch = fEntityScanner.peekChar();
1989                } while (ch != '<' && ch != ']' && !XMLChar.isSpace(ch));
1990            }
1991            skipSeparator(false, true);
1992        }
1993        return fScannerState != SCANNER_STATE_END_OF_INPUT;
1994    }
1995
1996    /**
1997     * Skip separator. This is typically just whitespace but it can also be one
1998     * or more parameter entity references.
1999     * <p>
2000     * If there are some it "expands them" by calling the corresponding entity
2001     * from the entity manager.
2002     * <p>
2003     * This is recursive and will process has many refs as possible.
2004     *
2005     * @param spaceRequired Specify whether some leading whitespace should be
2006     * found
2007     * @param lookForPERefs Specify whether parameter entity references should
2008     * be looked for
2009     * @return True if any leading whitespace was found or the end of a
2010     * parameter entity was crossed.
2011     */

2012    private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs)
2013        throws IOException JavaDoc, XNIException
2014    {
2015        int depth = fPEDepth;
2016        boolean sawSpace = fEntityScanner.skipSpaces();
2017        if (!lookForPERefs || !fEntityScanner.skipChar('%')) {
2018            return !spaceRequired || sawSpace || (depth != fPEDepth);
2019        }
2020        while (true) {
2021            String JavaDoc name = fEntityScanner.scanName();
2022            if (name == null) {
2023                reportFatalError("NameRequiredInPEReference", null);
2024            }
2025            else if (!fEntityScanner.skipChar(';')) {
2026                reportFatalError("SemicolonRequiredInPEReference",
2027                                 new Object JavaDoc[]{name});
2028            }
2029            startPE(name, false);
2030            fEntityScanner.skipSpaces();
2031            if (!fEntityScanner.skipChar('%'))
2032                return true;
2033        }
2034    }
2035
2036
2037    /*
2038     * Element Children Content Stack
2039     */

2040    private final void pushContentStack(int c) {
2041        if (fContentStack.length == fContentDepth) {
2042            int[] newStack = new int[fContentDepth * 2];
2043            System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth);
2044            fContentStack = newStack;
2045        }
2046        fContentStack[fContentDepth++] = c;
2047    }
2048
2049    private final int popContentStack() {
2050        return fContentStack[--fContentDepth];
2051    }
2052
2053
2054    /*
2055     * Parameter Entity Stack
2056     */

2057    private final void pushPEStack(int depth, boolean report) {
2058        if (fPEStack.length == fPEDepth) {
2059            int[] newIntStack = new int[fPEDepth * 2];
2060            System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth);
2061            fPEStack = newIntStack;
2062            // report end/start calls
2063
boolean[] newBooleanStack = new boolean[fPEDepth * 2];
2064            System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth);
2065            fPEReport = newBooleanStack;
2066
2067        }
2068        fPEReport[fPEDepth] = report;
2069        fPEStack[fPEDepth++] = depth;
2070    }
2071
2072    /** pop the stack */
2073    private final int popPEStack() {
2074        return fPEStack[--fPEDepth];
2075    }
2076
2077    /** look at the top of the stack */
2078    private final boolean peekReportEntity() {
2079        return fPEReport[fPEDepth-1];
2080    }
2081
2082
2083    /*
2084     * Utility method
2085     */

2086    private final void ensureEnumerationSize(int size) {
2087        if (fEnumeration.length == size) {
2088            String JavaDoc[] newEnum = new String JavaDoc[size * 2];
2089            System.arraycopy(fEnumeration, 0, newEnum, 0, size);
2090            fEnumeration = newEnum;
2091        }
2092    }
2093
2094    // private methods
2095
private void init() {
2096        // reset state related data
2097
fStartDTDCalled = false;
2098        fExtEntityDepth = 0;
2099        fIncludeSectDepth = 0;
2100        fMarkUpDepth = 0;
2101        fPEDepth = 0;
2102
2103        fStandalone = false;
2104        fSeenExternalDTD = false;
2105        fSeenExternalPE = false;
2106
2107        // set starting state
2108
setScannerState(SCANNER_STATE_TEXT_DECL);
2109    }
2110
2111} // class XMLDTDScannerImpl
2112
Popular Tags