KickJava   Java API By Example, From Geeks To Geeks.

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


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.XMLChar;
65 import com.sun.org.apache.xerces.internal.util.XMLResourceIdentifierImpl;
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.XMLResourceIdentifier;
69 import com.sun.org.apache.xerces.internal.xni.XMLString;
70 import com.sun.org.apache.xerces.internal.xni.XNIException;
71 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
72 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
73 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
74
75 /**
76  * This class is responsible for holding scanning methods common to
77  * scanning the XML document structure and content as well as the DTD
78  * structure and content. Both XMLDocumentScanner and XMLDTDScanner inherit
79  * from this base class.
80  *
81  * <p>
82  * This component requires the following features and properties from the
83  * component manager that uses it:
84  * <ul>
85  * <li>http://xml.org/sax/features/validation</li>
86  * <li>http://xml.org/sax/features/namespaces</li>
87  * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
88  * <li>http://apache.org/xml/properties/internal/symbol-table</li>
89  * <li>http://apache.org/xml/properties/internal/error-reporter</li>
90  * <li>http://apache.org/xml/properties/internal/entity-manager</li>
91  * </ul>
92  *
93  * @author Andy Clark, IBM
94  * @author Arnaud Le Hors, IBM
95  * @author Eric Ye, IBM
96  *
97  * @version $Id: XMLScanner.java,v 1.48 2004/04/25 05:05:50 mrglavas Exp $
98  */

99 public abstract class XMLScanner
100     implements XMLComponent {
101
102     //
103
// Constants
104
//
105

106     // feature identifiers
107

108     /** Feature identifier: validation. */
109     protected static final String JavaDoc VALIDATION =
110         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
111
112     /** Feature identifier: namespaces. */
113     protected static final String JavaDoc NAMESPACES =
114         Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
115
116     /** Feature identifier: notify character references. */
117     protected static final String JavaDoc NOTIFY_CHAR_REFS =
118         Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE;
119     
120     protected static final String JavaDoc PARSER_SETTINGS =
121                 Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
122
123     // property identifiers
124

125     /** Property identifier: symbol table. */
126     protected static final String JavaDoc SYMBOL_TABLE =
127         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
128
129     /** Property identifier: error reporter. */
130     protected static final String JavaDoc ERROR_REPORTER =
131         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
132
133     /** Property identifier: entity manager. */
134     protected static final String JavaDoc ENTITY_MANAGER =
135         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
136
137     // debugging
138

139     /** Debug attribute normalization. */
140     protected static final boolean DEBUG_ATTR_NORMALIZATION = false;
141
142     //
143
// Data
144
//
145

146
147     // features
148

149     /**
150      * Validation. This feature identifier is:
151      * http://xml.org/sax/features/validation
152      */

153     protected boolean fValidation = false;
154     
155     /** Namespaces. */
156     protected boolean fNamespaces;
157
158     /** Character references notification. */
159     protected boolean fNotifyCharRefs = false;
160     
161     /** Internal parser-settings feature */
162     protected boolean fParserSettings = true;
163     
164     // properties
165

166     /** Symbol table. */
167     protected SymbolTable fSymbolTable;
168
169     /** Error reporter. */
170     protected XMLErrorReporter fErrorReporter;
171
172     /** Entity manager. */
173     protected XMLEntityManager fEntityManager;
174
175     // protected data
176

177     /** Entity scanner. */
178     protected XMLEntityScanner fEntityScanner;
179
180     /** Entity depth. */
181     protected int fEntityDepth;
182
183     /** Literal value of the last character refence scanned. */
184     protected String JavaDoc fCharRefLiteral = null;
185
186     /** Scanning attribute. */
187     protected boolean fScanningAttribute;
188
189     /** Report entity boundary. */
190     protected boolean fReportEntity;
191
192     // symbols
193

194     /** Symbol: "version". */
195     protected final static String JavaDoc fVersionSymbol = "version".intern();
196
197     /** Symbol: "encoding". */
198     protected final static String JavaDoc fEncodingSymbol = "encoding".intern();
199
200     /** Symbol: "standalone". */
201     protected final static String JavaDoc fStandaloneSymbol = "standalone".intern();
202
203     /** Symbol: "amp". */
204     protected final static String JavaDoc fAmpSymbol = "amp".intern();
205
206     /** Symbol: "lt". */
207     protected final static String JavaDoc fLtSymbol = "lt".intern();
208
209     /** Symbol: "gt". */
210     protected final static String JavaDoc fGtSymbol = "gt".intern();
211
212     /** Symbol: "quot". */
213     protected final static String JavaDoc fQuotSymbol = "quot".intern();
214
215     /** Symbol: "apos". */
216     protected final static String JavaDoc fAposSymbol = "apos".intern();
217
218     // temporary variables
219

220     // NOTE: These objects are private to help prevent accidental modification
221
// of values by a subclass. If there were protected *and* the sub-
222
// modified the values, it would be difficult to track down the real
223
// cause of the bug. By making these private, we avoid this
224
// possibility.
225

226     /** String. */
227     private XMLString fString = new XMLString();
228
229     /** String buffer. */
230     private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
231
232     /** String buffer. */
233     private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
234
235     /** String buffer. */
236     private XMLStringBuffer fStringBuffer3 = new XMLStringBuffer();
237
238     // temporary location for Resource identification information.
239
protected XMLResourceIdentifierImpl fResourceIdentifier = new XMLResourceIdentifierImpl();
240
241     //
242
// XMLComponent methods
243
//
244

245     /**
246      *
247      *
248      * @param componentManager The component manager.
249      *
250      * @throws SAXException Throws exception if required features and
251      * properties cannot be found.
252      */

253     public void reset(XMLComponentManager componentManager)
254         throws XMLConfigurationException {
255
256         try {
257             fParserSettings = componentManager.getFeature(PARSER_SETTINGS);
258         } catch (XMLConfigurationException e) {
259             fParserSettings = true;
260         }
261
262         if (!fParserSettings) {
263             // parser settings have not been changed
264
init();
265             return;
266         }
267
268         // Xerces properties
269
fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE);
270         fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER);
271         fEntityManager = (XMLEntityManager)componentManager.getProperty(ENTITY_MANAGER);
272
273         // sax features
274
try {
275             fValidation = componentManager.getFeature(VALIDATION);
276         }
277         catch (XMLConfigurationException e) {
278             fValidation = false;
279         }
280         try {
281             fNamespaces = componentManager.getFeature(NAMESPACES);
282         }
283         catch (XMLConfigurationException e) {
284             fNamespaces = true;
285         }
286         try {
287             fNotifyCharRefs = componentManager.getFeature(NOTIFY_CHAR_REFS);
288         }
289         catch (XMLConfigurationException e) {
290             fNotifyCharRefs = false;
291         }
292         
293         init();
294
295     } // reset(XMLComponentManager)
296

297     /**
298      * Sets the value of a property during parsing.
299      *
300      * @param propertyId
301      * @param value
302      */

303     public void setProperty(String JavaDoc propertyId, Object JavaDoc value)
304         throws XMLConfigurationException {
305         
306         // Xerces properties
307
if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
308             final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
309             
310             if (suffixLength == Constants.SYMBOL_TABLE_PROPERTY.length() &&
311                 propertyId.endsWith(Constants.SYMBOL_TABLE_PROPERTY)) {
312                 fSymbolTable = (SymbolTable)value;
313             }
314             else if (suffixLength == Constants.ERROR_REPORTER_PROPERTY.length() &&
315                 propertyId.endsWith(Constants.ERROR_REPORTER_PROPERTY)) {
316                 fErrorReporter = (XMLErrorReporter)value;
317             }
318             else if (suffixLength == Constants.ENTITY_MANAGER_PROPERTY.length() &&
319                 propertyId.endsWith(Constants.ENTITY_MANAGER_PROPERTY)) {
320                 fEntityManager = (XMLEntityManager)value;
321             }
322         }
323
324     } // setProperty(String,Object)
325

326     /*
327      * Sets the feature of the scanner.
328      */

329     public void setFeature(String JavaDoc featureId, boolean value)
330         throws XMLConfigurationException {
331             
332         if (VALIDATION.equals(featureId)) {
333             fValidation = value;
334         } else if (NOTIFY_CHAR_REFS.equals(featureId)) {
335             fNotifyCharRefs = value;
336         }
337     }
338     
339     /*
340      * Gets the state of the feature of the scanner.
341      */

342     public boolean getFeature(String JavaDoc featureId)
343         throws XMLConfigurationException {
344             
345         if (VALIDATION.equals(featureId)) {
346             return fValidation;
347         } else if (NOTIFY_CHAR_REFS.equals(featureId)) {
348             return fNotifyCharRefs;
349         }
350         throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId);
351     }
352     
353     //
354
// Protected methods
355
//
356

357     // anybody calling this had better have set Symtoltable!
358
protected void reset() {
359         init();
360
361         // DTD preparsing defaults:
362
fValidation = true;
363         fNotifyCharRefs = false;
364
365     }
366
367     // common scanning methods
368

369     /**
370      * Scans an XML or text declaration.
371      * <p>
372      * <pre>
373      * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
374      * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
375      * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
376      * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
377      * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
378      * | ('"' ('yes' | 'no') '"'))
379      *
380      * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
381      * </pre>
382      *
383      * @param scanningTextDecl True if a text declaration is to
384      * be scanned instead of an XML
385      * declaration.
386      * @param pseudoAttributeValues An array of size 3 to return the version,
387      * encoding and standalone pseudo attribute values
388      * (in that order).
389      *
390      * <strong>Note:</strong> This method uses fString, anything in it
391      * at the time of calling is lost.
392      */

393     protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl,
394                                          String JavaDoc[] pseudoAttributeValues)
395         throws IOException JavaDoc, XNIException {
396
397         // pseudo-attribute values
398
String JavaDoc version = null;
399         String JavaDoc encoding = null;
400         String JavaDoc standalone = null;
401
402         // scan pseudo-attributes
403
final int STATE_VERSION = 0;
404         final int STATE_ENCODING = 1;
405         final int STATE_STANDALONE = 2;
406         final int STATE_DONE = 3;
407         int state = STATE_VERSION;
408
409         boolean dataFoundForTarget = false;
410         boolean sawSpace = fEntityScanner.skipDeclSpaces();
411         // since pseudoattributes are *not* attributes,
412
// their quotes don't need to be preserved in external parameter entities.
413
// the XMLEntityScanner#scanLiteral method will continue to
414
// emit -1 in such cases when it finds a quote; this is
415
// fine for other methods that parse scanned entities,
416
// but not for the scanning of pseudoattributes. So,
417
// temporarily, we must mark the current entity as not being "literal"
418
XMLEntityManager.ScannedEntity currEnt = fEntityManager.getCurrentEntity();
419         boolean currLiteral = currEnt.literal;
420         currEnt.literal = false;
421         while (fEntityScanner.peekChar() != '?') {
422             dataFoundForTarget = true;
423             String JavaDoc name = scanPseudoAttribute(scanningTextDecl, fString);
424             switch (state) {
425                 case STATE_VERSION: {
426                     if (name == fVersionSymbol) {
427                         if (!sawSpace) {
428                             reportFatalError(scanningTextDecl
429                                        ? "SpaceRequiredBeforeVersionInTextDecl"
430                                        : "SpaceRequiredBeforeVersionInXMLDecl",
431                                              null);
432                         }
433                         version = fString.toString();
434                         state = STATE_ENCODING;
435                         if (!versionSupported(version)) {
436                             reportFatalError(getVersionNotSupportedKey(),
437                                              new Object JavaDoc[]{version});
438                         }
439                     }
440                     else if (name == fEncodingSymbol) {
441                         if (!scanningTextDecl) {
442                             reportFatalError("VersionInfoRequired", null);
443                         }
444                         if (!sawSpace) {
445                             reportFatalError(scanningTextDecl
446                                       ? "SpaceRequiredBeforeEncodingInTextDecl"
447                                       : "SpaceRequiredBeforeEncodingInXMLDecl",
448                                              null);
449                         }
450                         encoding = fString.toString();
451                         state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE;
452                     }
453                     else {
454                         if (scanningTextDecl) {
455                             reportFatalError("EncodingDeclRequired", null);
456                         }
457                         else {
458                             reportFatalError("VersionInfoRequired", null);
459                         }
460                     }
461                     break;
462                 }
463                 case STATE_ENCODING: {
464                     if (name == fEncodingSymbol) {
465                         if (!sawSpace) {
466                             reportFatalError(scanningTextDecl
467                                       ? "SpaceRequiredBeforeEncodingInTextDecl"
468                                       : "SpaceRequiredBeforeEncodingInXMLDecl",
469                                              null);
470                         }
471                         encoding = fString.toString();
472                         state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE;
473                         // TODO: check encoding name; set encoding on
474
// entity scanner
475
}
476                     else if (!scanningTextDecl && name == fStandaloneSymbol) {
477                         if (!sawSpace) {
478                             reportFatalError("SpaceRequiredBeforeStandalone",
479                                              null);
480                         }
481                         standalone = fString.toString();
482                         state = STATE_DONE;
483                         if (!standalone.equals("yes") && !standalone.equals("no")) {
484                             reportFatalError("SDDeclInvalid", new Object JavaDoc[] {standalone});
485                         }
486                     }
487                     else {
488                         reportFatalError("EncodingDeclRequired", null);
489                     }
490                     break;
491                 }
492                 case STATE_STANDALONE: {
493                     if (name == fStandaloneSymbol) {
494                         if (!sawSpace) {
495                             reportFatalError("SpaceRequiredBeforeStandalone",
496                                              null);
497                         }
498                         standalone = fString.toString();
499                         state = STATE_DONE;
500                         if (!standalone.equals("yes") && !standalone.equals("no")) {
501                             reportFatalError("SDDeclInvalid", new Object JavaDoc[] {standalone});
502                         }
503                     }
504                     else {
505                         reportFatalError("EncodingDeclRequired", null);
506                     }
507                     break;
508                 }
509                 default: {
510                     reportFatalError("NoMorePseudoAttributes", null);
511                 }
512             }
513             sawSpace = fEntityScanner.skipDeclSpaces();
514         }
515         // restore original literal value
516
if(currLiteral)
517             currEnt.literal = true;
518         // REVISIT: should we remove this error reporting?
519
if (scanningTextDecl && state != STATE_DONE) {
520             reportFatalError("MorePseudoAttributes", null);
521         }
522         
523         // If there is no data in the xml or text decl then we fail to report error
524
// for version or encoding info above.
525
if (scanningTextDecl) {
526             if (!dataFoundForTarget && encoding == null) {
527                 reportFatalError("EncodingDeclRequired", null);
528             }
529         }
530         else {
531             if (!dataFoundForTarget && version == null) {
532                 reportFatalError("VersionInfoRequired", null);
533             }
534         }
535
536         // end
537
if (!fEntityScanner.skipChar('?')) {
538             reportFatalError("XMLDeclUnterminated", null);
539         }
540         if (!fEntityScanner.skipChar('>')) {
541             reportFatalError("XMLDeclUnterminated", null);
542
543         }
544         
545         // fill in return array
546
pseudoAttributeValues[0] = version;
547         pseudoAttributeValues[1] = encoding;
548         pseudoAttributeValues[2] = standalone;
549
550     } // scanXMLDeclOrTextDecl(boolean)
551

552     /**
553      * Scans a pseudo attribute.
554      *
555      * @param scanningTextDecl True if scanning this pseudo-attribute for a
556      * TextDecl; false if scanning XMLDecl. This
557      * flag is needed to report the correct type of
558      * error.
559      * @param value The string to fill in with the attribute
560      * value.
561      *
562      * @return The name of the attribute
563      *
564      * <strong>Note:</strong> This method uses fStringBuffer2, anything in it
565      * at the time of calling is lost.
566      */

567     public String JavaDoc scanPseudoAttribute(boolean scanningTextDecl,
568                                       XMLString value)
569         throws IOException JavaDoc, XNIException {
570
571         // REVISIT: This method is used for generic scanning of
572
// pseudo attributes, but since there are only three such
573
// attributes: version, encoding, and standalone there are
574
// for performant ways of scanning them. Every decl must
575
// have a version, and in TextDecls this version must
576
// be followed by an encoding declaration. Also the
577
// methods we invoke on the scanners allow non-ASCII
578
// characters to be parsed in the decls, but since
579
// we don't even know what the actual encoding of the
580
// document is until we scan the encoding declaration
581
// you cannot reliably read any characters outside
582
// of the ASCII range here. -- mrglavas
583
String JavaDoc name = fEntityScanner.scanName();
584         XMLEntityManager.print(fEntityManager.getCurrentEntity());
585         if (name == null) {
586             reportFatalError("PseudoAttrNameExpected", null);
587         }
588         fEntityScanner.skipDeclSpaces();
589         if (!fEntityScanner.skipChar('=')) {
590             reportFatalError(scanningTextDecl ? "EqRequiredInTextDecl"
591                              : "EqRequiredInXMLDecl", new Object JavaDoc[]{name});
592         }
593         fEntityScanner.skipDeclSpaces();
594         int quote = fEntityScanner.peekChar();
595         if (quote != '\'' && quote != '"') {
596             reportFatalError(scanningTextDecl ? "QuoteRequiredInTextDecl"
597                              : "QuoteRequiredInXMLDecl" , new Object JavaDoc[]{name});
598         }
599         fEntityScanner.scanChar();
600         int c = fEntityScanner.scanLiteral(quote, value);
601         if (c != quote) {
602             fStringBuffer2.clear();
603             do {
604                 fStringBuffer2.append(value);
605                 if (c != -1) {
606                     if (c == '&' || c == '%' || c == '<' || c == ']') {
607                         fStringBuffer2.append((char)fEntityScanner.scanChar());
608                     }
609                     // REVISIT: Even if you could reliably read non-ASCII chars
610
// why bother scanning for surrogates here? Only ASCII chars
611
// match the productions in XMLDecls and TextDecls. -- mrglavas
612
else if (XMLChar.isHighSurrogate(c)) {
613                         scanSurrogates(fStringBuffer2);
614                     }
615                     else if (isInvalidLiteral(c)) {
616                         String JavaDoc key = scanningTextDecl
617                             ? "InvalidCharInTextDecl" : "InvalidCharInXMLDecl";
618                         reportFatalError(key,
619                                        new Object JavaDoc[] {Integer.toString(c, 16)});
620                         fEntityScanner.scanChar();
621                     }
622                 }
623                 c = fEntityScanner.scanLiteral(quote, value);
624             } while (c != quote);
625             fStringBuffer2.append(value);
626             value.setValues(fStringBuffer2);
627         }
628         if (!fEntityScanner.skipChar(quote)) {
629             reportFatalError(scanningTextDecl ? "CloseQuoteMissingInTextDecl"
630                              : "CloseQuoteMissingInXMLDecl",
631                              new Object JavaDoc[]{name});
632         }
633
634         // return
635
return name;
636
637     } // scanPseudoAttribute(XMLString):String
638

639     /**
640      * Scans a processing instruction.
641      * <p>
642      * <pre>
643      * [16] PI ::= '&lt;?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
644      * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
645      * </pre>
646      * <strong>Note:</strong> This method uses fString, anything in it
647      * at the time of calling is lost.
648      */

649     protected void scanPI() throws IOException JavaDoc, XNIException {
650
651         // target
652
fReportEntity = false;
653         String JavaDoc target = null;
654         if(fNamespaces) {
655             target = fEntityScanner.scanNCName();
656         } else {
657             target = fEntityScanner.scanName();
658         }
659         if (target == null) {
660             reportFatalError("PITargetRequired", null);
661         }
662
663         // scan data
664
scanPIData(target, fString);
665         fReportEntity = true;
666
667     } // scanPI()
668

669     /**
670      * Scans a processing data. This is needed to handle the situation
671      * where a document starts with a processing instruction whose
672      * target name <em>starts with</em> "xml". (e.g. xmlfoo)
673      *
674      * <strong>Note:</strong> This method uses fStringBuffer, anything in it
675      * at the time of calling is lost.
676      *
677      * @param target The PI target
678      * @param data The string to fill in with the data
679      */

680     protected void scanPIData(String JavaDoc target, XMLString data)
681         throws IOException JavaDoc, XNIException {
682
683         // check target
684
if (target.length() == 3) {
685             char c0 = Character.toLowerCase(target.charAt(0));
686             char c1 = Character.toLowerCase(target.charAt(1));
687             char c2 = Character.toLowerCase(target.charAt(2));
688             if (c0 == 'x' && c1 == 'm' && c2 == 'l') {
689                 reportFatalError("ReservedPITarget", null);
690             }
691         }
692
693         // spaces
694
if (!fEntityScanner.skipSpaces()) {
695             if (fEntityScanner.skipString("?>")) {
696                 // we found the end, there is no data
697
data.clear();
698                 return;
699             }
700             else {
701                 if(fNamespaces && fEntityScanner.peekChar() == ':') {
702                     fEntityScanner.scanChar();
703                     XMLStringBuffer colonName = new XMLStringBuffer(target);
704                     colonName.append(":");
705                     String JavaDoc str = fEntityScanner.scanName();
706                     if (str != null)
707                         colonName.append(str);
708                     reportFatalError("ColonNotLegalWithNS", new Object JavaDoc[] {colonName.toString()});
709                     fEntityScanner.skipSpaces();
710                 } else {
711                     // if there is data there should be some space
712
reportFatalError("SpaceRequiredInPI", null);
713                 }
714             }
715         }
716
717         fStringBuffer.clear();
718         // data
719
if (fEntityScanner.scanData("?>", fStringBuffer)) {
720             do {
721                 int c = fEntityScanner.peekChar();
722                 if (c != -1) {
723                     if (XMLChar.isHighSurrogate(c)) {
724                         scanSurrogates(fStringBuffer);
725                     }
726                     else if (isInvalidLiteral(c)) {
727                         reportFatalError("InvalidCharInPI",
728                                          new Object JavaDoc[]{Integer.toHexString(c)});
729                         fEntityScanner.scanChar();
730                     }
731                 }
732             } while (fEntityScanner.scanData("?>", fStringBuffer));
733         }
734         data.setValues(fStringBuffer);
735
736     } // scanPIData(String,XMLString)
737

738     /**
739      * Scans a comment.
740      * <p>
741      * <pre>
742      * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
743      * </pre>
744      * <p>
745      * <strong>Note:</strong> Called after scanning past '&lt;!--'
746      * <strong>Note:</strong> This method uses fString, anything in it
747      * at the time of calling is lost.
748      *
749      * @param text The buffer to fill in with the text.
750      */

751     protected void scanComment(XMLStringBuffer text)
752         throws IOException JavaDoc, XNIException {
753
754         // text
755
// REVISIT: handle invalid character, eof
756
text.clear();
757         while (fEntityScanner.scanData("--", text)) {
758             int c = fEntityScanner.peekChar();
759             if (c != -1) {
760                 if (XMLChar.isHighSurrogate(c)) {
761                     scanSurrogates(text);
762                 }
763                 else if (isInvalidLiteral(c)) {
764                     reportFatalError("InvalidCharInComment",
765                                      new Object JavaDoc[] { Integer.toHexString(c) });
766                     fEntityScanner.scanChar();
767                 }
768             }
769         }
770         if (!fEntityScanner.skipChar('>')) {
771             reportFatalError("DashDashInComment", null);
772         }
773
774     } // scanComment()
775

776     /**
777      * Scans an attribute value and normalizes whitespace converting all
778      * whitespace characters to space characters.
779      *
780      * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'"
781      *
782      * @param value The XMLString to fill in with the value.
783      * @param nonNormalizedValue The XMLString to fill in with the
784      * non-normalized value.
785      * @param atName The name of the attribute being parsed (for error msgs).
786      * @param checkEntities true if undeclared entities should be reported as VC violation,
787      * false if undeclared entities should be reported as WFC violation.
788      * @param eleName The name of element to which this attribute belongs.
789      *
790      * <strong>Note:</strong> This method uses fStringBuffer2, anything in it
791      * at the time of calling is lost.
792      **/

793     protected void scanAttributeValue(XMLString value,
794                                       XMLString nonNormalizedValue,
795                                       String JavaDoc atName,
796                                       boolean checkEntities,String JavaDoc eleName)
797         throws IOException JavaDoc, XNIException
798     {
799         // quote
800
int quote = fEntityScanner.peekChar();
801         if (quote != '\'' && quote != '"') {
802             reportFatalError("OpenQuoteExpected", new Object JavaDoc[]{eleName,atName});
803         }
804
805         fEntityScanner.scanChar();
806         int entityDepth = fEntityDepth;
807
808         int c = fEntityScanner.scanLiteral(quote, value);
809         if (DEBUG_ATTR_NORMALIZATION) {
810             System.out.println("** scanLiteral -> \""
811                                + value.toString() + "\"");
812         }
813         fStringBuffer2.clear();
814         fStringBuffer2.append(value);
815         normalizeWhitespace(value);
816         if (DEBUG_ATTR_NORMALIZATION) {
817             System.out.println("** normalizeWhitespace -> \""
818                                + value.toString() + "\"");
819         }
820         if (c != quote) {
821             fScanningAttribute = true;
822             fStringBuffer.clear();
823             do {
824                 fStringBuffer.append(value);
825                 if (DEBUG_ATTR_NORMALIZATION) {
826                     System.out.println("** value2: \""
827                                        + fStringBuffer.toString() + "\"");
828                 }
829                 if (c == '&') {
830                     fEntityScanner.skipChar('&');
831                     if (entityDepth == fEntityDepth) {
832                         fStringBuffer2.append('&');
833                     }
834                     if (fEntityScanner.skipChar('#')) {
835                         if (entityDepth == fEntityDepth) {
836                             fStringBuffer2.append('#');
837                         }
838                         int ch = scanCharReferenceValue(fStringBuffer, fStringBuffer2);
839                         if (ch != -1) {
840                             if (DEBUG_ATTR_NORMALIZATION) {
841                                 System.out.println("** value3: \""
842                                                    + fStringBuffer.toString()
843                                                    + "\"");
844                             }
845                         }
846                     }
847                     else {
848                         String JavaDoc entityName = fEntityScanner.scanName();
849                         if (entityName == null) {
850                             reportFatalError("NameRequiredInReference", null);
851                         }
852                         else if (entityDepth == fEntityDepth) {
853                             fStringBuffer2.append(entityName);
854                         }
855                         if (!fEntityScanner.skipChar(';')) {
856                             reportFatalError("SemicolonRequiredInReference",
857                                              new Object JavaDoc []{entityName});
858                         }
859                         else if (entityDepth == fEntityDepth) {
860                             fStringBuffer2.append(';');
861                         }
862                         if (entityName == fAmpSymbol) {
863                             fStringBuffer.append('&');
864                             if (DEBUG_ATTR_NORMALIZATION) {
865                                 System.out.println("** value5: \""
866                                                    + fStringBuffer.toString()
867                                                    + "\"");
868                             }
869                         }
870                         else if (entityName == fAposSymbol) {
871                             fStringBuffer.append('\'');
872                             if (DEBUG_ATTR_NORMALIZATION) {
873                                 System.out.println("** value7: \""
874                                                    + fStringBuffer.toString()
875                                                    + "\"");
876                             }
877                         }
878                         else if (entityName == fLtSymbol) {
879                             fStringBuffer.append('<');
880                             if (DEBUG_ATTR_NORMALIZATION) {
881                                 System.out.println("** value9: \""
882                                                    + fStringBuffer.toString()
883                                                    + "\"");
884                             }
885                         }
886                         else if (entityName == fGtSymbol) {
887                             fStringBuffer.append('>');
888                             if (DEBUG_ATTR_NORMALIZATION) {
889                                 System.out.println("** valueB: \""
890                                                    + fStringBuffer.toString()
891                                                    + "\"");
892                             }
893                         }
894                         else if (entityName == fQuotSymbol) {
895                             fStringBuffer.append('"');
896                             if (DEBUG_ATTR_NORMALIZATION) {
897                                 System.out.println("** valueD: \""
898                                                    + fStringBuffer.toString()
899                                                    + "\"");
900                             }
901                         }
902                         else {
903                             if (fEntityManager.isExternalEntity(entityName)) {
904                                 reportFatalError("ReferenceToExternalEntity",
905                                                  new Object JavaDoc[] { entityName });
906                             }
907                             else {
908                                 if (!fEntityManager.isDeclaredEntity(entityName)) {
909                                     //WFC & VC: Entity Declared
910
if (checkEntities) {
911                                         if (fValidation) {
912                                             fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
913                                                                        "EntityNotDeclared",
914                                                                        new Object JavaDoc[]{entityName},
915                                                                        XMLErrorReporter.SEVERITY_ERROR);
916                                         }
917                                     }
918                                     else {
919                                         reportFatalError("EntityNotDeclared",
920                                                          new Object JavaDoc[]{entityName});
921                                     }
922                                 }
923                                 fEntityManager.startEntity(entityName, true);
924                             }
925                         }
926                     }
927                 }
928                 else if (c == '<') {
929                     reportFatalError("LessthanInAttValue",
930                                      new Object JavaDoc[] { eleName, atName });
931                     fEntityScanner.scanChar();
932                     if (entityDepth == fEntityDepth) {
933                         fStringBuffer2.append((char)c);
934                     }
935                 }
936                 else if (c == '%' || c == ']') {
937                     fEntityScanner.scanChar();
938                     fStringBuffer.append((char)c);
939                     if (entityDepth == fEntityDepth) {
940                         fStringBuffer2.append((char)c);
941                     }
942                     if (DEBUG_ATTR_NORMALIZATION) {
943                         System.out.println("** valueF: \""
944                                            + fStringBuffer.toString() + "\"");
945                     }
946                 }
947                 else if (c == '\n' || c == '\r') {
948                     fEntityScanner.scanChar();
949                     fStringBuffer.append(' ');
950                     if (entityDepth == fEntityDepth) {
951                         fStringBuffer2.append('\n');
952                     }
953                 }
954                 else if (c != -1 && XMLChar.isHighSurrogate(c)) {
955                     fStringBuffer3.clear();
956                     if (scanSurrogates(fStringBuffer3)) {
957                         fStringBuffer.append(fStringBuffer3);
958                         if (entityDepth == fEntityDepth) {
959                             fStringBuffer2.append(fStringBuffer3);
960                         }
961                         if (DEBUG_ATTR_NORMALIZATION) {
962                             System.out.println("** valueI: \""
963                                                + fStringBuffer.toString()
964                                                + "\"");
965                         }
966                     }
967                 }
968                 else if (c != -1 && isInvalidLiteral(c)) {
969                     reportFatalError("InvalidCharInAttValue",
970                     new Object JavaDoc[] {eleName, atName, Integer.toString(c, 16)});
971                     fEntityScanner.scanChar();
972                     if (entityDepth == fEntityDepth) {
973                         fStringBuffer2.append((char)c);
974                     }
975                 }
976                 c = fEntityScanner.scanLiteral(quote, value);
977                 if (entityDepth == fEntityDepth) {
978                     fStringBuffer2.append(value);
979                 }
980                 normalizeWhitespace(value);
981             } while (c != quote || entityDepth != fEntityDepth);
982             fStringBuffer.append(value);
983             if (DEBUG_ATTR_NORMALIZATION) {
984                 System.out.println("** valueN: \""
985                                    + fStringBuffer.toString() + "\"");
986             }
987             value.setValues(fStringBuffer);
988             fScanningAttribute = false;
989         }
990         nonNormalizedValue.setValues(fStringBuffer2);
991
992         // quote
993
int cquote = fEntityScanner.scanChar();
994         if (cquote != quote) {
995             reportFatalError("CloseQuoteExpected", new Object JavaDoc[]{eleName,atName});
996         }
997     } // scanAttributeValue()
998

999
1000    /**
1001     * Scans External ID and return the public and system IDs.
1002     *
1003     * @param identifiers An array of size 2 to return the system id,
1004     * and public id (in that order).
1005     * @param optionalSystemId Specifies whether the system id is optional.
1006     *
1007     * <strong>Note:</strong> This method uses fString and fStringBuffer,
1008     * anything in them at the time of calling is lost.
1009     */

1010    protected void scanExternalID(String JavaDoc[] identifiers,
1011                                  boolean optionalSystemId)
1012        throws IOException JavaDoc, XNIException {
1013
1014        String JavaDoc systemId = null;
1015        String JavaDoc publicId = null;
1016        if (fEntityScanner.skipString("PUBLIC")) {
1017            if (!fEntityScanner.skipSpaces()) {
1018                reportFatalError("SpaceRequiredAfterPUBLIC", null);
1019            }
1020            scanPubidLiteral(fString);
1021            publicId = fString.toString();
1022
1023            if (!fEntityScanner.skipSpaces() && !optionalSystemId) {
1024                reportFatalError("SpaceRequiredBetweenPublicAndSystem", null);
1025            }
1026        }
1027
1028        if (publicId != null || fEntityScanner.skipString("SYSTEM")) {
1029            if (publicId == null && !fEntityScanner.skipSpaces()) {
1030                reportFatalError("SpaceRequiredAfterSYSTEM", null);
1031            }
1032            int quote = fEntityScanner.peekChar();
1033            if (quote != '\'' && quote != '"') {
1034                if (publicId != null && optionalSystemId) {
1035                    // looks like we don't have any system id
1036
// simply return the public id
1037
identifiers[0] = null;
1038                    identifiers[1] = publicId;
1039                    return;
1040                }
1041                reportFatalError("QuoteRequiredInSystemID", null);
1042            }
1043            fEntityScanner.scanChar();
1044            XMLString ident = fString;
1045            if (fEntityScanner.scanLiteral(quote, ident) != quote) {
1046                fStringBuffer.clear();
1047                do {
1048                    fStringBuffer.append(ident);
1049                    int c = fEntityScanner.peekChar();
1050                    if (XMLChar.isMarkup(c) || c == ']') {
1051                        fStringBuffer.append((char)fEntityScanner.scanChar());
1052                    }
1053                } while (fEntityScanner.scanLiteral(quote, ident) != quote);
1054                fStringBuffer.append(ident);
1055                ident = fStringBuffer;
1056            }
1057            systemId = ident.toString();
1058            if (!fEntityScanner.skipChar(quote)) {
1059                reportFatalError("SystemIDUnterminated", null);
1060            }
1061        }
1062
1063        // store result in array
1064
identifiers[0] = systemId;
1065        identifiers[1] = publicId;
1066    }
1067
1068
1069    /**
1070     * Scans public ID literal.
1071     *
1072     * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1073     * [13] PubidChar::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
1074     *
1075     * The returned string is normalized according to the following rule,
1076     * from http://www.w3.org/TR/REC-xml#dt-pubid:
1077     *
1078     * Before a match is attempted, all strings of white space in the public
1079     * identifier must be normalized to single space characters (#x20), and
1080     * leading and trailing white space must be removed.
1081     *
1082     * @param literal The string to fill in with the public ID literal.
1083     * @return True on success.
1084     *
1085     * <strong>Note:</strong> This method uses fStringBuffer, anything in it at
1086     * the time of calling is lost.
1087     */

1088    protected boolean scanPubidLiteral(XMLString literal)
1089        throws IOException JavaDoc, XNIException
1090    {
1091        int quote = fEntityScanner.scanChar();
1092        if (quote != '\'' && quote != '"') {
1093            reportFatalError("QuoteRequiredInPublicID", null);
1094            return false;
1095        }
1096
1097        fStringBuffer.clear();
1098        // skip leading whitespace
1099
boolean skipSpace = true;
1100        boolean dataok = true;
1101        while (true) {
1102            int c = fEntityScanner.scanChar();
1103            if (c == ' ' || c == '\n' || c == '\r') {
1104                if (!skipSpace) {
1105                    // take the first whitespace as a space and skip the others
1106
fStringBuffer.append(' ');
1107                    skipSpace = true;
1108                }
1109            }
1110            else if (c == quote) {
1111                if (skipSpace) {
1112                    // if we finished on a space let's trim it
1113
fStringBuffer.length--;
1114                }
1115                literal.setValues(fStringBuffer);
1116                break;
1117            }
1118            else if (XMLChar.isPubid(c)) {
1119                fStringBuffer.append((char)c);
1120                skipSpace = false;
1121            }
1122            else if (c == -1) {
1123                reportFatalError("PublicIDUnterminated", null);
1124                return false;
1125            }
1126            else {
1127                dataok = false;
1128                reportFatalError("InvalidCharInPublicID",
1129                                 new Object JavaDoc[]{Integer.toHexString(c)});
1130            }
1131        }
1132        return dataok;
1133   }
1134
1135
1136    /**
1137     * Normalize whitespace in an XMLString converting all whitespace
1138     * characters to space characters.
1139     */

1140    protected void normalizeWhitespace(XMLString value) {
1141        int end = value.offset + value.length;
1142        for (int i = value.offset; i < end; i++) {
1143            int c = value.ch[i];
1144            // Performance: For XML 1.0 documents take advantage of
1145
// the fact that the only legal characters below 0x20
1146
// are 0x09 (TAB), 0x0A (LF) and 0x0D (CR). Since we've
1147
// already determined the well-formedness of these
1148
// characters it is sufficient (and safe) to check
1149
// against 0x20. -- mrglavas
1150
if (c < 0x20) {
1151                value.ch[i] = ' ';
1152            }
1153        }
1154    }
1155
1156    //
1157
// XMLEntityHandler methods
1158
//
1159

1160    /**
1161     * This method notifies of the start of an entity. The document entity
1162     * has the pseudo-name of "[xml]" the DTD has the pseudo-name of "[dtd]"
1163     * parameter entity names start with '%'; and general entities are just
1164     * specified by their name.
1165     *
1166     * @param name The name of the entity.
1167     * @param identifier The resource identifier.
1168     * @param encoding The auto-detected IANA encoding name of the entity
1169     * stream. This value will be null in those situations
1170     * where the entity encoding is not auto-detected (e.g.
1171     * internal entities or a document entity that is
1172     * parsed from a java.io.Reader).
1173     * @param augs Additional information that may include infoset augmentations
1174     *
1175     * @throws XNIException Thrown by handler to signal an error.
1176     */

1177    public void startEntity(String JavaDoc name,
1178                            XMLResourceIdentifier identifier,
1179                            String JavaDoc encoding, Augmentations augs) throws XNIException {
1180
1181        // keep track of the entity depth
1182
fEntityDepth++;
1183        // must reset entity scanner
1184
fEntityScanner = fEntityManager.getEntityScanner();
1185
1186    } // startEntity(String,XMLResourceIdentifier,String)
1187

1188    /**
1189     * This method notifies the end of an entity. The document entity has
1190     * the pseudo-name of "[xml]" the DTD has the pseudo-name of "[dtd]"
1191     * parameter entity names start with '%'; and general entities are just
1192     * specified by their name.
1193     *
1194     * @param name The name of the entity.
1195     * @param augs Additional information that may include infoset augmentations
1196     *
1197     * @throws XNIException Thrown by handler to signal an error.
1198     */

1199    public void endEntity(String JavaDoc name, Augmentations augs) throws XNIException {
1200
1201        // keep track of the entity depth
1202
fEntityDepth--;
1203
1204    } // endEntity(String)
1205

1206    /**
1207     * Scans a character reference and append the corresponding chars to the
1208     * specified buffer.
1209     *
1210     * <p>
1211     * <pre>
1212     * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1213     * </pre>
1214     *
1215     * <strong>Note:</strong> This method uses fStringBuffer, anything in it
1216     * at the time of calling is lost.
1217     *
1218     * @param buf the character buffer to append chars to
1219     * @param buf2 the character buffer to append non-normalized chars to
1220     *
1221     * @return the character value or (-1) on conversion failure
1222     */

1223    protected int scanCharReferenceValue(XMLStringBuffer buf, XMLStringBuffer buf2)
1224        throws IOException JavaDoc, XNIException {
1225
1226        // scan hexadecimal value
1227
boolean hex = false;
1228        if (fEntityScanner.skipChar('x')) {
1229            if (buf2 != null) { buf2.append('x'); }
1230            hex = true;
1231            fStringBuffer3.clear();
1232            boolean digit = true;
1233            
1234            int c = fEntityScanner.peekChar();
1235            digit = (c >= '0' && c <= '9') ||
1236                    (c >= 'a' && c <= 'f') ||
1237                    (c >= 'A' && c <= 'F');
1238            if (digit) {
1239                if (buf2 != null) { buf2.append((char)c); }
1240                fEntityScanner.scanChar();
1241                fStringBuffer3.append((char)c);
1242                
1243                do {
1244                    c = fEntityScanner.peekChar();
1245                    digit = (c >= '0' && c <= '9') ||
1246                            (c >= 'a' && c <= 'f') ||
1247                            (c >= 'A' && c <= 'F');
1248                    if (digit) {
1249                        if (buf2 != null) { buf2.append((char)c); }
1250                        fEntityScanner.scanChar();
1251                        fStringBuffer3.append((char)c);
1252                    }
1253                } while (digit);
1254            }
1255            else {
1256                reportFatalError("HexdigitRequiredInCharRef", null);
1257            }
1258        }
1259
1260        // scan decimal value
1261
else {
1262            fStringBuffer3.clear();
1263            boolean digit = true;
1264            
1265            int c = fEntityScanner.peekChar();
1266            digit = c >= '0' && c <= '9';
1267            if (digit) {
1268                if (buf2 != null) { buf2.append((char)c); }
1269                fEntityScanner.scanChar();
1270                fStringBuffer3.append((char)c);
1271                
1272                do {
1273                    c = fEntityScanner.peekChar();
1274                    digit = c >= '0' && c <= '9';
1275                    if (digit) {
1276                        if (buf2 != null) { buf2.append((char)c); }
1277                        fEntityScanner.scanChar();
1278                        fStringBuffer3.append((char)c);
1279                    }
1280                } while (digit);
1281            }
1282            else {
1283                reportFatalError("DigitRequiredInCharRef", null);
1284            }
1285        }
1286
1287        // end
1288
if (!fEntityScanner.skipChar(';')) {
1289            reportFatalError("SemicolonRequiredInCharRef", null);
1290        }
1291        if (buf2 != null) { buf2.append(';'); }
1292        
1293        // convert string to number
1294
int value = -1;
1295        try {
1296            value = Integer.parseInt(fStringBuffer3.toString(),
1297                                     hex ? 16 : 10);
1298            
1299            // character reference must be a valid XML character
1300
if (isInvalid(value)) {
1301                StringBuffer JavaDoc errorBuf = new StringBuffer JavaDoc(fStringBuffer3.length + 1);
1302                if (hex) errorBuf.append('x');
1303                errorBuf.append(fStringBuffer3.ch, fStringBuffer3.offset, fStringBuffer3.length);
1304                reportFatalError("InvalidCharRef",
1305                                 new Object JavaDoc[]{errorBuf.toString()});
1306            }
1307        }
1308        catch (NumberFormatException JavaDoc e) {
1309            // Conversion failed, let -1 value drop through.
1310
// If we end up here, the character reference was invalid.
1311
StringBuffer JavaDoc errorBuf = new StringBuffer JavaDoc(fStringBuffer3.length + 1);
1312            if (hex) errorBuf.append('x');
1313            errorBuf.append(fStringBuffer3.ch, fStringBuffer3.offset, fStringBuffer3.length);
1314            reportFatalError("InvalidCharRef",
1315                             new Object JavaDoc[]{errorBuf.toString()});
1316        }
1317
1318        // append corresponding chars to the given buffer
1319
if (!XMLChar.isSupplemental(value)) {
1320            buf.append((char) value);
1321        }
1322        else {
1323            // character is supplemental, split it into surrogate chars
1324
buf.append(XMLChar.highSurrogate(value));
1325            buf.append(XMLChar.lowSurrogate(value));
1326        }
1327
1328        // char refs notification code
1329
if (fNotifyCharRefs && value != -1) {
1330            String JavaDoc literal = "#" + (hex ? "x" : "") + fStringBuffer3.toString();
1331            if (!fScanningAttribute) {
1332                fCharRefLiteral = literal;
1333            }
1334        }
1335                
1336        return value;
1337    }
1338
1339    // returns true if the given character is not
1340
// valid with respect to the version of
1341
// XML understood by this scanner.
1342
protected boolean isInvalid(int value) {
1343        return (XMLChar.isInvalid(value));
1344    } // isInvalid(int): boolean
1345

1346    // returns true if the given character is not
1347
// valid or may not be used outside a character reference
1348
// with respect to the version of XML understood by this scanner.
1349
protected boolean isInvalidLiteral(int value) {
1350        return (XMLChar.isInvalid(value));
1351    } // isInvalidLiteral(int): boolean
1352

1353    // returns true if the given character is
1354
// a valid nameChar with respect to the version of
1355
// XML understood by this scanner.
1356
protected boolean isValidNameChar(int value) {
1357        return (XMLChar.isName(value));
1358    } // isValidNameChar(int): boolean
1359

1360    // returns true if the given character is
1361
// a valid nameStartChar with respect to the version of
1362
// XML understood by this scanner.
1363
protected boolean isValidNameStartChar(int value) {
1364        return (XMLChar.isNameStart(value));
1365    } // isValidNameStartChar(int): boolean
1366

1367    // returns true if the given character is
1368
// a valid NCName character with respect to the version of
1369
// XML understood by this scanner.
1370
protected boolean isValidNCName(int value) {
1371        return (XMLChar.isNCName(value));
1372    } // isValidNCName(int): boolean
1373

1374    // returns true if the given character is
1375
// a valid high surrogate for a nameStartChar
1376
// with respect to the version of XML understood
1377
// by this scanner.
1378
protected boolean isValidNameStartHighSurrogate(int value) {
1379        return false;
1380    } // isValidNameStartHighSurrogate(int): boolean
1381

1382    protected boolean versionSupported(String JavaDoc version ) {
1383        return version.equals("1.0");
1384    } // version Supported
1385

1386    // returns the error message key for unsupported
1387
// versions of XML with respect to the version of
1388
// XML understood by this scanner.
1389
protected String JavaDoc getVersionNotSupportedKey () {
1390        return "VersionNotSupported";
1391    } // getVersionNotSupportedKey: String
1392

1393    /**
1394     * Scans surrogates and append them to the specified buffer.
1395     * <p>
1396     * <strong>Note:</strong> This assumes the current char has already been
1397     * identified as a high surrogate.
1398     *
1399     * @param buf The StringBuffer to append the read surrogates to.
1400     * @return True if it succeeded.
1401     */

1402    protected boolean scanSurrogates(XMLStringBuffer buf)
1403        throws IOException JavaDoc, XNIException {
1404
1405        int high = fEntityScanner.scanChar();
1406        int low = fEntityScanner.peekChar();
1407        if (!XMLChar.isLowSurrogate(low)) {
1408            reportFatalError("InvalidCharInContent",
1409                             new Object JavaDoc[] {Integer.toString(high, 16)});
1410            return false;
1411        }
1412        fEntityScanner.scanChar();
1413
1414        // convert surrogates to supplemental character
1415
int c = XMLChar.supplemental((char)high, (char)low);
1416
1417        // supplemental character must be a valid XML character
1418
if (isInvalid(c)) {
1419            reportFatalError("InvalidCharInContent",
1420                             new Object JavaDoc[]{Integer.toString(c, 16)});
1421            return false;
1422        }
1423
1424        // fill in the buffer
1425
buf.append((char)high);
1426        buf.append((char)low);
1427
1428        return true;
1429
1430    } // scanSurrogates():boolean
1431

1432
1433    /**
1434     * Convenience function used in all XML scanners.
1435     */

1436    protected void reportFatalError(String JavaDoc msgId, Object JavaDoc[] args)
1437        throws XNIException {
1438        fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1439                                   msgId, args,
1440                                   XMLErrorReporter.SEVERITY_FATAL_ERROR);
1441    }
1442
1443    // private methods
1444
private void init() {
1445        fEntityScanner = null;
1446        // initialize vars
1447
fEntityDepth = 0;
1448        fReportEntity = true;
1449        fResourceIdentifier.clear();
1450    }
1451
1452} // class XMLScanner
1453
Popular Tags