1 /*
2 * Portions Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
3 */
4
5 /*
6 * Copyright 2005 The Apache Software Foundation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 package com.sun.org.apache.xerces.internal.impl;
22
23
24 import com.sun.xml.internal.stream.XMLEntityStorage;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import javax.xml.stream.events.XMLEvent;
29 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
30 import com.sun.org.apache.xerces.internal.util.SymbolTable;
31 import com.sun.org.apache.xerces.internal.util.XMLChar;
32 import com.sun.org.apache.xerces.internal.util.XMLResourceIdentifierImpl;
33 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
34 import com.sun.org.apache.xerces.internal.xni.Augmentations;
35 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
36 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
37 import com.sun.org.apache.xerces.internal.xni.XMLString;
38 import com.sun.org.apache.xerces.internal.xni.XNIException;
39 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
40 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
41 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
42 import com.sun.xml.internal.stream.Entity;
43
44 //import com.sun.xml.stream.XMLEntityManager;
45 //import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
46
47 /**
48 * This class is responsible for holding scanning methods common to
49 * scanning the XML document structure and content as well as the DTD
50 * structure and content. Both XMLDocumentScanner and XMLDTDScanner inherit
51 * from this base class.
52 *
53 * <p>
54 * This component requires the following features and properties from the
55 * component manager that uses it:
56 * <ul>
57 * <li>http://xml.org/sax/features/validation</li>
58 * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
59 * <li>http://apache.org/xml/properties/internal/symbol-table</li>
60 * <li>http://apache.org/xml/properties/internal/error-reporter</li>
61 * <li>http://apache.org/xml/properties/internal/entity-manager</li>
62 * </ul>
63 *
64 * @author Andy Clark, IBM
65 * @author Arnaud Le Hors, IBM
66 * @author Eric Ye, IBM
67 * @author K.Venugopal SUN Microsystems
68 * @author Sunitha Reddy, SUN Microsystems
69 */
70 public abstract class XMLScanner
71 implements XMLComponent {
72
73 //
74 // Constants
75 //
76
77 // feature identifiers
78
79 /** Feature identifier: namespaces. */
80 protected static final String NAMESPACES =
81 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
82
83 /** Feature identifier: validation. */
84 protected static final String VALIDATION =
85 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
86
87 /** Feature identifier: notify character references. */
88 protected static final String NOTIFY_CHAR_REFS =
89 Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE;
90
91 // property identifiers
92
93 protected static final String PARSER_SETTINGS =
94 Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
95 /** Property identifier: symbol table. */
96 protected static final String SYMBOL_TABLE =
97 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
98
99 /** Property identifier: error reporter. */
100 protected static final String ERROR_REPORTER =
101 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
102
103 /** Property identifier: entity manager. */
104 protected static final String ENTITY_MANAGER =
105 Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
106
107 // debugging
108
109 /** Debug attribute normalization. */
110 protected static final boolean DEBUG_ATTR_NORMALIZATION = false;
111
112
113 //xxx: setting the default value as false, as we dont need to calculate this value
114 //we should have a feature when set to true computes this value
115 private boolean fNeedNonNormalizedValue = false;
116
117 protected ArrayList attributeValueCache = new ArrayList();
118 protected ArrayList stringBufferCache = new ArrayList();
119 protected int fStringBufferIndex = 0;
120 protected boolean fAttributeCacheInitDone = false;
121 protected int fAttributeCacheUsedCount = 0;
122
123 //
124 // Data
125 //
126
127 // features
128
129 /**
130 * Validation. This feature identifier is:
131 * http://xml.org/sax/features/validation
132 */
133 protected boolean fValidation = false;
134
135 /** Namespaces. */
136 protected boolean fNamespaces;
137
138 /** Character references notification. */
139 protected boolean fNotifyCharRefs = false;
140
141 /** Internal parser-settings feature */
142 protected boolean fParserSettings = true;
143
144 // properties
145
146 protected PropertyManager fPropertyManager = null ;
147 /** Symbol table. */
148 protected SymbolTable fSymbolTable;
149
150 /** Error reporter. */
151 protected XMLErrorReporter fErrorReporter;
152
153 /** Entity manager. */
154 //protected XMLEntityManager fEntityManager = PropertyManager.getEntityManager();
155 protected XMLEntityManager fEntityManager = null ;
156
157 /** xxx this should be available from EntityManager Entity storage */
158 protected XMLEntityStorage fEntityStore = null ;
159
160 // protected data
161
162 /** event type */
163 protected XMLEvent fEvent ;
164
165 /** Entity scanner, this alwasy works on last entity that was opened. */
166 protected XMLEntityScanner fEntityScanner = null;
167
168 /** Entity depth. */
169 protected int fEntityDepth;
170
171 /** Literal value of the last character refence scanned. */
172 protected String fCharRefLiteral = null;
173
174 /** Scanning attribute. */
175 protected boolean fScanningAttribute;
176
177 /** Report entity boundary. */
178 protected boolean fReportEntity;
179
180 // symbols
181
182 /** Symbol: "version". */
183 protected final static String fVersionSymbol = "version".intern();
184
185 /** Symbol: "encoding". */
186 protected final static String fEncodingSymbol = "encoding".intern();
187
188 /** Symbol: "standalone". */
189 protected final static String fStandaloneSymbol = "standalone".intern();
190
191 /** Symbol: "amp". */
192 protected final static String fAmpSymbol = "amp".intern();
193
194 /** Symbol: "lt". */
195 protected final static String fLtSymbol = "lt".intern();
196
197 /** Symbol: "gt". */
198 protected final static String fGtSymbol = "gt".intern();
199
200 /** Symbol: "quot". */
201 protected final static String fQuotSymbol = "quot".intern();
202
203 /** Symbol: "apos". */
204 protected final static String fAposSymbol = "apos".intern();
205
206 // temporary variables
207
208 // NOTE: These objects are private to help prevent accidental modification
209 // of values by a subclass. If there were protected *and* the sub-
210 // modified the values, it would be difficult to track down the real
211 // cause of the bug. By making these private, we avoid this
212 // possibility.
213
214 /** String. */
215 private XMLString fString = new XMLString();
216
217 /** String buffer. */
218 private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
219
220 /** String buffer. */
221 private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
222
223 /** String buffer. */
224 private XMLStringBuffer fStringBuffer3 = new XMLStringBuffer();
225
226 // temporary location for Resource identification information.
227 protected XMLResourceIdentifierImpl fResourceIdentifier = new XMLResourceIdentifierImpl();
228 int initialCacheCount = 6;
229 //
230 // XMLComponent methods
231 //
232
233 /**
234 *
235 *
236 * @param componentManager The component manager.
237 *
238 * @throws SAXException Throws exception if required features and
239 * properties cannot be found.
240 */
241 public void reset(XMLComponentManager componentManager)
242 throws XMLConfigurationException {
243
244 try {
245 fParserSettings = componentManager.getFeature(PARSER_SETTINGS);
246 } catch (XMLConfigurationException e) {
247 fParserSettings = true;
248 }
249
250 if (!fParserSettings) {
251 // parser settings have not been changed
252 init();
253 return;
254 }
255
256
257 // Xerces properties
258 fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE);
259 fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER);
260 fEntityManager = (XMLEntityManager)componentManager.getProperty(ENTITY_MANAGER);
261
262 //this step is extra because we have separated the storage of entity
263 fEntityStore = fEntityManager.getEntityStore() ;
264
265 // sax features
266 try {
267 fValidation = componentManager.getFeature(VALIDATION);
268 } catch (XMLConfigurationException e) {
269 fValidation = false;
270 }
271 try {
272 fNamespaces = componentManager.getFeature(NAMESPACES);
273 }
274 catch (XMLConfigurationException e) {
275 fNamespaces = true;
276 }
277 try {
278 fNotifyCharRefs = componentManager.getFeature(NOTIFY_CHAR_REFS);
279 } catch (XMLConfigurationException e) {
280 fNotifyCharRefs = false;
281 }
282
283 init();
284 } // reset(XMLComponentManager)
285
286 protected void setPropertyManager(PropertyManager propertyManager){
287 fPropertyManager = propertyManager ;
288 }
289
290 /**
291 * Sets the value of a property during parsing.
292 *
293 * @param propertyId
294 * @param value
295 */
296 public void setProperty(String propertyId, Object value)
297 throws XMLConfigurationException {
298
299 // Xerces properties
300 if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
301 String property =
302 propertyId.substring(Constants.XERCES_PROPERTY_PREFIX.length());
303 if (property.equals(Constants.SYMBOL_TABLE_PROPERTY)) {
304 fSymbolTable = (SymbolTable)value;
305 } else if (property.equals(Constants.ERROR_REPORTER_PROPERTY)) {
306 fErrorReporter = (XMLErrorReporter)value;
307 } else if (property.equals(Constants.ENTITY_MANAGER_PROPERTY)) {
308 fEntityManager = (XMLEntityManager)value;
309 }
310 }
311 /*else if(propertyId.equals(Constants.STAX_PROPERTIES)){
312 fStaxProperties = (HashMap)value;
313 //TODO::discuss with neeraj what are his thoughts on passing properties.
314 //For now use this
315 }*/
316
317 } // setProperty(String,Object)
318
319 /*
320 * Sets the feature of the scanner.
321 */
322 public void setFeature(String featureId, boolean value)
323 throws XMLConfigurationException {
324
325 if (VALIDATION.equals(featureId)) {
326 fValidation = value;
327 } else if (NOTIFY_CHAR_REFS.equals(featureId)) {
328 fNotifyCharRefs = value;
329 }
330 }
331
332 /*
333 * Gets the state of the feature of the scanner.
334 */
335 public boolean getFeature(String featureId)
336 throws XMLConfigurationException {
337
338 if (VALIDATION.equals(featureId)) {
339 return fValidation;
340 } else if (NOTIFY_CHAR_REFS.equals(featureId)) {
341 return fNotifyCharRefs;
342 }
343 throw new XMLConfigurationException(XMLConfigurationException.NOT_RECOGNIZED, featureId);
344 }
345
346 //
347 // Protected methods
348 //
349
350 // anybody calling this had better have set Symtoltable!
351 protected void reset() {
352 init();
353
354 // DTD preparsing defaults:
355 fValidation = true;
356 fNotifyCharRefs = false;
357
358 }
359
360 public void reset(PropertyManager propertyManager) {
361 init();
362 // Xerces properties
363 fSymbolTable = (SymbolTable)propertyManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY);
364
365 fErrorReporter = (XMLErrorReporter)propertyManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY);
366
367 fEntityManager = (XMLEntityManager)propertyManager.getProperty(ENTITY_MANAGER);
368 fEntityStore = fEntityManager.getEntityStore() ;
369 fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner() ;
370 //fEntityManager.reset();
371 // DTD preparsing defaults:
372 fValidation = false;
373 fNotifyCharRefs = false;
374
375 }
376 // common scanning methods
377
378 /**
379 * Scans an XML or text declaration.
380 * <p>
381 * <pre>
382 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
383 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
384 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" )
385 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
386 * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
387 * | ('"' ('yes' | 'no') '"'))
388 *
389 * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
390 * </pre>
391 *
392 * @param scanningTextDecl True if a text declaration is to
393 * be scanned instead of an XML
394 * declaration.
395 * @param pseudoAttributeValues An array of size 3 to return the version,
396 * encoding and standalone pseudo attribute values
397 * (in that order).
398 *
399 * <strong>Note:</strong> This method uses fString, anything in it
400 * at the time of calling is lost.
401 */
402 protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl,
403 String[] pseudoAttributeValues)
404 throws IOException, XNIException {
405
406 // pseudo-attribute values
407 String version = null;
408 String encoding = null;
409 String standalone = null;
410
411 // scan pseudo-attributes
412 final int STATE_VERSION = 0;
413 final int STATE_ENCODING = 1;
414 final int STATE_STANDALONE = 2;
415 final int STATE_DONE = 3;
416 int state = STATE_VERSION;
417
418 boolean dataFoundForTarget = false;
419 boolean sawSpace = fEntityScanner.skipSpaces();
420 while (fEntityScanner.peekChar() != '?') {
421 dataFoundForTarget = true;
422 String name = scanPseudoAttribute(scanningTextDecl, fString);
423 switch (state) {
424 case STATE_VERSION: {
425 if (name.equals(fVersionSymbol)) {
426 if (!sawSpace) {
427 reportFatalError(scanningTextDecl
428 ? "SpaceRequiredBeforeVersionInTextDecl"
429 : "SpaceRequiredBeforeVersionInXMLDecl",
430 null);
431 }
432 version = fString.toString();
433 state = STATE_ENCODING;
434 if (!versionSupported(version)) {
435 reportFatalError("VersionNotSupported",
436 new Object[]{version});
437 }
438
439 if (version.equals("1.1")) {
440 Entity.ScannedEntity top = fEntityManager.getTopLevelEntity();
441 if (top != null && (top.version == null || top.version.equals("1.0"))) {
442 reportFatalError("VersionMismatch", null);
443 }
444 fEntityManager.setScannerVersion(Constants.XML_VERSION_1_1);
445 }
446
447 } else if (name.equals(fEncodingSymbol)) {
448 if (!scanningTextDecl) {
449 reportFatalError("VersionInfoRequired", null);
450 }
451 if (!sawSpace) {
452 reportFatalError(scanningTextDecl
453 ? "SpaceRequiredBeforeEncodingInTextDecl"
454 : "SpaceRequiredBeforeEncodingInXMLDecl",
455 null);
456 }
457 encoding = fString.toString();
458 state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE;
459 } else {
460 if (scanningTextDecl) {
461 reportFatalError("EncodingDeclRequired", null);
462 } else {
463 reportFatalError("VersionInfoRequired", null);
464 }
465 }
466 break;
467 }
468 case STATE_ENCODING: {
469 if (name.equals(fEncodingSymbol)) {
470 if (!sawSpace) {
471 reportFatalError(scanningTextDecl
472 ? "SpaceRequiredBeforeEncodingInTextDecl"
473 : "SpaceRequiredBeforeEncodingInXMLDecl",
474 null);
475 }
476 encoding = fString.toString();
477 state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE;
478 // TODO: check encoding name; set encoding on
479 // entity scanner
480 } else if (!scanningTextDecl && name.equals(fStandaloneSymbol)) {
481 if (!sawSpace) {
482 reportFatalError("SpaceRequiredBeforeStandalone",
483 null);
484 }
485 standalone = fString.toString();
486 state = STATE_DONE;
487 if (!standalone.equals("yes") && !standalone.equals("no")) {
488 reportFatalError("SDDeclInvalid", null);
489 }
490 } else {
491 reportFatalError("EncodingDeclRequired", null);
492 }
493 break;
494 }
495 case STATE_STANDALONE: {
496 if (name.equals(fStandaloneSymbol)) {
497 if (!sawSpace) {
498 reportFatalError("SpaceRequiredBeforeStandalone",
499 null);
500 }
501 standalone = fString.toString();
502 state = STATE_DONE;
503 if (!standalone.equals("yes") && !standalone.equals("no")) {
504 reportFatalError("SDDeclInvalid", null);
505 }
506 } else {
507 reportFatalError("EncodingDeclRequired", null);
508 }
509 break;
510 }
511 default: {
512 reportFatalError("NoMorePseudoAttributes", null);
513 }
514 }
515 sawSpace = fEntityScanner.skipSpaces();
516 }
517 // REVISIT: should we remove this error reporting?
518 if (scanningTextDecl && state != STATE_DONE) {
519 reportFatalError("MorePseudoAttributes", null);
520 }
521
522 // If there is no data in the xml or text decl then we fail to report error
523 // for version or encoding info above.
524 if (scanningTextDecl) {
525 if (!dataFoundForTarget && encoding == null) {
526 reportFatalError("EncodingDeclRequired", null);
527 }
528 } else {
529 if (!dataFoundForTarget && version == null) {
530 reportFatalError("VersionInfoRequired", null);
531 }
532 }
533
534 // end
535 if (!fEntityScanner.skipChar('?')) {
536 reportFatalError("XMLDeclUnterminated", null);
537 }
538 if (!fEntityScanner.skipChar('>')) {
539 reportFatalError("XMLDeclUnterminated", null);
540
541 }
542
543 // fill in return array
544 pseudoAttributeValues[0] = version;
545 pseudoAttributeValues[1] = encoding;
546 pseudoAttributeValues[2] = standalone;
547
548 } // scanXMLDeclOrTextDecl(boolean)
549
550 /**
551 * Scans a pseudo attribute.
552 *
553 * @param scanningTextDecl True if scanning this pseudo-attribute for a
554 * TextDecl; false if scanning XMLDecl. This
555 * flag is needed to report the correct type of
556 * error.
557 * @param value The string to fill in with the attribute
558 * value.
559 *
560 * @return The name of the attribute
561 *
562 * <strong>Note:</strong> This method uses fStringBuffer2, anything in it
563 * at the time of calling is lost.
564 */
565 public String scanPseudoAttribute(boolean scanningTextDecl,
566 XMLString value)
567 throws IOException, XNIException {
568
569 String name = fEntityScanner.scanName();
570 // XMLEntityManager.print(fEntityManager.getCurrentEntity());
571
572 if (name == null) {
573 reportFatalError("PseudoAttrNameExpected", null);
574 }
575 fEntityScanner.skipSpaces();
576 if (!fEntityScanner.skipChar('=')) {
577 reportFatalError(scanningTextDecl ? "EqRequiredInTextDecl"
578 : "EqRequiredInXMLDecl", new Object[]{name});
579 }
580 fEntityScanner.skipSpaces();
581 int quote = fEntityScanner.peekChar();
582 if (quote != '\'' && quote != '"') {
583 reportFatalError(scanningTextDecl ? "QuoteRequiredInTextDecl"
584 : "QuoteRequiredInXMLDecl" , new Object[]{name});
585 }
586 fEntityScanner.scanChar();
587 int c = fEntityScanner.scanLiteral(quote, value);
588 if (c != quote) {
589 fStringBuffer2.clear();
590 do {
591 fStringBuffer2.append(value);
592 if (c != -1) {
593 if (c == '&' || c == '%' || c == '<' || c == ']') {
594 fStringBuffer2.append((char)fEntityScanner.scanChar());
595 } else if (XMLChar.isHighSurrogate(c)) {
596 scanSurrogates(fStringBuffer2);
597 } else if (isInvalidLiteral(c)) {
598 String key = scanningTextDecl
599 ? "InvalidCharInTextDecl" : "InvalidCharInXMLDecl";
600 reportFatalError(key,
601 new Object[] {Integer.toString(c, 16)});
602 fEntityScanner.scanChar();
603 }
604 }
605 c = fEntityScanner.scanLiteral(quote, value);
606 } while (c != quote);
607 fStringBuffer2.append(value);
608 value.setValues(fStringBuffer2);
609 }
610 if (!fEntityScanner.skipChar(quote)) {
611 reportFatalError(scanningTextDecl ? "CloseQuoteMissingInTextDecl"
612 : "CloseQuoteMissingInXMLDecl",
613 new Object[]{name});
614 }
615
616 // return
617 return name;
618
619 } // scanPseudoAttribute(XMLString):String
620
621 /**
622 * Scans a processing instruction.
623 * <p>
624 * <pre>
625 * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
626 * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
627 * </pre>
628 */
629 //CHANGED:
630 //EARLIER: scanPI()
631 //NOW: scanPI(XMLStringBuffer)
632 //it makes things more easy if XMLStringBUffer is passed. Motivation for this change is same
633 // as that for scanContent()
634
635 protected void scanPI(XMLStringBuffer data) throws IOException, XNIException {
636
637 // target
638 fReportEntity = false;
639 String target = fEntityScanner.scanName();
640 if (target == null) {
641 reportFatalError("PITargetRequired", null);
642 }
643
644 // scan data
645 scanPIData(target, data);
646 fReportEntity = true;
647
648 } // scanPI(XMLStringBuffer)
649
650 /**
651 * Scans a processing data. This is needed to handle the situation
652 * where a document starts with a processing instruction whose
653 * target name <em>starts with</em> "xml". (e.g. xmlfoo)
654 *
655 * This method would always read the whole data. We have while loop and data is buffered
656 * until delimeter is encountered.
657 *
658 * @param target The PI target
659 * @param data The string to fill in with the data
660 */
661
662 //CHANGED:
663 //Earlier:This method uses the fStringBuffer and later buffer values are set to
664 //the supplied XMLString....
665 //Now: Changed the signature of this function to pass XMLStringBuffer.. and data would
666 //be appended to that buffer
667
668 protected void scanPIData(String target, XMLStringBuffer data)
669 throws IOException, XNIException {
670
671 // check target
672 if (target.length() == 3) {
673 char c0 = Character.toLowerCase(target.charAt(0));
674 char c1 = Character.toLowerCase(target.charAt(1));
675 char c2 = Character.toLowerCase(target.charAt(2));
676 if (c0 == 'x' && c1 == 'm' && c2 == 'l') {
677 reportFatalError("ReservedPITarget", null);
678 }
679 }
680
681 // spaces
682 if (!fEntityScanner.skipSpaces()) {
683 if (fEntityScanner.skipString("?>")) {
684 // we found the end, there is no data just return
685 return;
686 } else {
687 // if there is data there should be some space
688 reportFatalError("SpaceRequiredInPI", null);
689 }
690 }
691
692 // since scanData appends the parsed data to the buffer passed
693 // a while loop would append the whole of parsed data to the buffer(data:XMLStringBuffer)
694 //until all of the data is buffered.
695 if (fEntityScanner.scanData("?>", data)) {
696 do {
697 int c = fEntityScanner.peekChar();
698 if (c != -1) {
699 if (XMLChar.isHighSurrogate(c)) {
700 scanSurrogates(data);
701 } else if (isInvalidLiteral(c)) {
702 reportFatalError("InvalidCharInPI",
703 new Object[]{Integer.toHexString(c)});
704 fEntityScanner.scanChar();
705 }
706 }
707 } while (fEntityScanner.scanData("?>", data));
708 }
709
710 } // scanPIData(String,XMLString)
711
712 /**
713 * Scans a comment.
714 * <p>
715 * <pre>
716 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
717 * </pre>
718 * <p>
719 * <strong>Note:</strong> Called after scanning past '<!--'
720 * <strong>Note:</strong> This method uses fString, anything in it
721 * at the time of calling is lost.
722 *
723 * @param text The buffer to fill in with the text.
724 */
725 protected void scanComment(XMLStringBuffer text)
726 throws IOException, XNIException {
727
728 //System.out.println( "XMLScanner#scanComment# In Scan Comment" );
729 // text
730 // REVISIT: handle invalid character, eof
731 text.clear();
732 while (fEntityScanner.scanData("--", text)) {
733 int c = fEntityScanner.peekChar();
734
735 //System.out.println( "XMLScanner#scanComment#text.toString() == " + text.toString() );
736 //System.out.println( "XMLScanner#scanComment#c == " + c );
737
738 if (c != -1) {
739 if (XMLChar.isHighSurrogate(c)) {
740 scanSurrogates(text);
741 }
742 if (isInvalidLiteral(c)) {
743 reportFatalError("InvalidCharInComment",
744 new Object[] { Integer.toHexString(c) });
745 fEntityScanner.scanChar();
746 }
747 }
748 }
749 if (!fEntityScanner.skipChar('>')) {
750 reportFatalError("DashDashInComment", null);
751 }
752
753 } // scanComment()
754
755 /**
756 * Scans an attribute value and normalizes whitespace converting all
757 * whitespace characters to space characters.
758 *
759 * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'"
760 *
761 * @param value The XMLString to fill in with the value.
762 * @param nonNormalizedValue The XMLString to fill in with the
763 * non-normalized value.
764 * @param atName The name of the attribute being parsed (for error msgs).
765 * @param attributes The attributes list for the scanned attribute.
766 * @param attrIndex The index of the attribute to use from the list.
767 * @param checkEntities true if undeclared entities should be reported as VC violation,
768 * false if undeclared entities should be reported as WFC violation.
769 *
770 * <strong>Note:</strong> This method uses fStringBuffer2, anything in it
771 * at the time of calling is lost.
772 **/
773 protected void scanAttributeValue(XMLString value,
774 XMLString nonNormalizedValue,
775 String atName,
776 XMLAttributes attributes, int attrIndex,
777 boolean checkEntities)
778 throws IOException, XNIException {
779 XMLStringBuffer stringBuffer = null;
780 // quote
781 int quote = fEntityScanner.peekChar();
782 if (quote != '\'' && quote != '"') {
783 reportFatalError("OpenQuoteExpected", new Object[]{atName});
784 }
785
786 fEntityScanner.scanChar();
787 int entityDepth = fEntityDepth;
788
789 int c = fEntityScanner.scanLiteral(quote, value);
790 if (DEBUG_ATTR_NORMALIZATION) {
791 System.out.println("** scanLiteral -> \""
792 + value.toString() + "\"");
793 }
794 if(fNeedNonNormalizedValue){
795 fStringBuffer2.clear();
796 fStringBuffer2.append(value);
797 }
798 if(fEntityScanner.whiteSpaceLen > 0)
799 normalizeWhitespace(value);
800 if (DEBUG_ATTR_NORMALIZATION) {
801 System.out.println("** normalizeWhitespace -> \""
802 + value.toString() + "\"");
803 }
804 if (c != quote) {
805 fScanningAttribute = true;
806 stringBuffer = getStringBuffer();
807 stringBuffer.clear();
808 do {
809 stringBuffer.append(value);
810 if (DEBUG_ATTR_NORMALIZATION) {
811 System.out.println("** value2: \""
812 + stringBuffer.toString() + "\"");
813 }
814 if (c == '&') {
815 fEntityScanner.skipChar('&');
816 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue ) {
817 fStringBuffer2.append('&');
818 }
819 if (fEntityScanner.skipChar('#')) {
820 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue ) {
821 fStringBuffer2.append('#');
822 }
823 int ch ;
824 if (fNeedNonNormalizedValue)
825 ch = scanCharReferenceValue(stringBuffer, fStringBuffer2);
826 else
827 ch = scanCharReferenceValue(stringBuffer, null);
828
829 if (ch != -1) {
830 if (DEBUG_ATTR_NORMALIZATION) {
831 System.out.println("** value3: \""
832 + stringBuffer.toString()
833 + "\"");
834 }
835 }
836 } else {
837 String entityName = fEntityScanner.scanName();
838 if (entityName == null) {
839 reportFatalError("NameRequiredInReference", null);
840 } else if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
841 fStringBuffer2.append(entityName);
842 }
843 if (!fEntityScanner.skipChar(';')) {
844 reportFatalError("SemicolonRequiredInReference",
845 new Object []{entityName});
846 } else if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
847 fStringBuffer2.append(';');
848 }
849 if (entityName == fAmpSymbol) {
850 stringBuffer.append('&');
851 if (DEBUG_ATTR_NORMALIZATION) {
852 System.out.println("** value5: \""
853 + stringBuffer.toString()
854 + "\"");
855 }
856 } else if (entityName == fAposSymbol) {
857 stringBuffer.append('\'');
858 if (DEBUG_ATTR_NORMALIZATION) {
859 System.out.println("** value7: \""
860 + stringBuffer.toString()
861 + "\"");
862 }
863 } else if (entityName == fLtSymbol) {
864 stringBuffer.append('<');
865 if (DEBUG_ATTR_NORMALIZATION) {
866 System.out.println("** value9: \""
867 + stringBuffer.toString()
868 + "\"");
869 }
870 } else if (entityName == fGtSymbol) {
871 stringBuffer.append('>');
872 if (DEBUG_ATTR_NORMALIZATION) {
873 System.out.println("** valueB: \""
874 + stringBuffer.toString()
875 + "\"");
876 }
877 } else if (entityName == fQuotSymbol) {
878 stringBuffer.append('"');
879 if (DEBUG_ATTR_NORMALIZATION) {
880 System.out.println("** valueD: \""
881 + stringBuffer.toString()
882 + "\"");
883 }
884 } else {
885 if (fEntityStore.isExternalEntity(entityName)) {
886 reportFatalError("ReferenceToExternalEntity",
887 new Object[] { entityName });
888 } else {
889 if (!fEntityStore.isDeclaredEntity(entityName)) {
890 //WFC & VC: Entity Declared
891 if (checkEntities) {
892 if (fValidation) {
893 fErrorReporter.reportError(fEntityScanner,XMLMessageFormatter.XML_DOMAIN,
894 "EntityNotDeclared",
895 new Object[]{entityName},
896 XMLErrorReporter.SEVERITY_ERROR);
897 }
898 } else {
899 reportFatalError("EntityNotDeclared",
900 new Object[]{entityName});
901 }
902 }
903 fEntityManager.startEntity(entityName, true);
904 }
905 }
906 }
907 } else if (c == '<') {
908 reportFatalError("LessthanInAttValue",
909 new Object[] { null, atName });
910 fEntityScanner.scanChar();
911 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
912 fStringBuffer2.append((char)c);
913 }
914 } else if (c == '%' || c == ']') {
915 fEntityScanner.scanChar();
916 stringBuffer.append((char)c);
917 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
918 fStringBuffer2.append((char)c);
919 }
920 if (DEBUG_ATTR_NORMALIZATION) {
921 System.out.println("** valueF: \""
922 + stringBuffer.toString() + "\"");
923 }
924 } else if (c == '\n' || c == '\r') {
925 fEntityScanner.scanChar();
926 stringBuffer.append(' ');
927 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
928 fStringBuffer2.append('\n');
929 }
930 } else if (c != -1 && XMLChar.isHighSurrogate(c)) {
931 if (scanSurrogates(fStringBuffer3)) {
932 stringBuffer.append(fStringBuffer3);
933 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
934 fStringBuffer2.append(fStringBuffer3);
935 }
936 if (DEBUG_ATTR_NORMALIZATION) {
937 System.out.println("** valueI: \""
938 + stringBuffer.toString()
939 + "\"");
940 }
941 }
942 } else if (c != -1 && isInvalidLiteral(c)) {
943 reportFatalError("InvalidCharInAttValue",
944 new Object[] {Integer.toString(c, 16)});
945 fEntityScanner.scanChar();
946 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
947 fStringBuffer2.append((char)c);
948 }
949 }
950 c = fEntityScanner.scanLiteral(quote, value);
951 if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
952 fStringBuffer2.append(value);
953 }
954 if(fEntityScanner.whiteSpaceLen > 0)
955 normalizeWhitespace(value);
956 //Todo ::Move this check to Attributes , do conversion
957 //only if attribute is being accessed. -Venu
958 } while (c != quote || entityDepth != fEntityDepth);
959 stringBuffer.append(value);
960 if (DEBUG_ATTR_NORMALIZATION) {
961 System.out.println("** valueN: \""
962 + stringBuffer.toString() + "\"");
963 }
964 value.setValues(stringBuffer);
965 fScanningAttribute = false;
966 }
967 if(fNeedNonNormalizedValue)
968 nonNormalizedValue.setValues(fStringBuffer2);
969
970 // quote
971 int cquote = fEntityScanner.scanChar();
972 if (cquote != quote) {
973 reportFatalError("CloseQuoteExpected", new Object[]{atName});
974 }
975 } // scanAttributeValue()
976
977
978 /**
979 * Scans External ID and return the public and system IDs.
980 *
981 * @param identifiers An array of size 2 to return the system id,
982 * and public id (in that order).
983 * @param optionalSystemId Specifies whether the system id is optional.
984 *
985 * <strong>Note:</strong> This method uses fString and fStringBuffer,
986 * anything in them at the time of calling is lost.
987 */
988 protected void scanExternalID(String[] identifiers,
989 boolean optionalSystemId)
990 throws IOException, XNIException {
991
992 String systemId = null;
993 String publicId = null;
994 if (fEntityScanner.skipString("PUBLIC")) {
995 if (!fEntityScanner.skipSpaces()) {
996 reportFatalError("SpaceRequiredAfterPUBLIC", null);
997 }
998 scanPubidLiteral(fString);
999 publicId = fString.toString();
1000
1001 if (!fEntityScanner.skipSpaces() && !optionalSystemId) {
1002 reportFatalError("SpaceRequiredBetweenPublicAndSystem", null);
1003 }
1004 }
1005
1006 if (publicId != null || fEntityScanner.skipString("SYSTEM")) {
1007 if (publicId == null && !fEntityScanner.skipSpaces()) {
1008 reportFatalError("SpaceRequiredAfterSYSTEM", null);
1009 }
1010 int quote = fEntityScanner.peekChar();
1011 if (quote != '\'' && quote != '"') {
1012 if (publicId != null && optionalSystemId) {
1013 // looks like we don't have any system id
1014 // simply return the public id
1015 identifiers[0] = null;
1016 identifiers[1] = publicId;
1017 return;
1018 }
1019 reportFatalError("QuoteRequiredInSystemID", null);
1020 }
1021 fEntityScanner.scanChar();
1022 XMLString ident = fString;
1023 if (fEntityScanner.scanLiteral(quote, ident) != quote) {
1024 fStringBuffer.clear();
1025 do {
1026 fStringBuffer.append(ident);
1027 int c = fEntityScanner.peekChar();
1028 if (XMLChar.isMarkup(c) || c == ']') {
1029 fStringBuffer.append((char)fEntityScanner.scanChar());
1030 }
1031 } while (fEntityScanner.scanLiteral(quote, ident) != quote);
1032 fStringBuffer.append(ident);
1033 ident = fStringBuffer;
1034 }
1035 systemId = ident.toString();
1036 if (!fEntityScanner.skipChar(quote)) {
1037 reportFatalError("SystemIDUnterminated", null);
1038 }
1039 }
1040
1041 // store result in array
1042 identifiers[0] = systemId;
1043 identifiers[1] = publicId;
1044 }
1045
1046
1047 /**
1048 * Scans public ID literal.
1049 *
1050 * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
1051 * [13] PubidChar::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
1052 *
1053 * The returned string is normalized according to the following rule,
1054 * from http://www.w3.org/TR/REC-xml#dt-pubid:
1055 *
1056 * Before a match is attempted, all strings of white space in the public
1057 * identifier must be normalized to single space characters (#x20), and
1058 * leading and trailing white space must be removed.
1059 *
1060 * @param literal The string to fill in with the public ID literal.
1061 * @return True on success.
1062 *
1063 * <strong>Note:</strong> This method uses fStringBuffer, anything in it at
1064 * the time of calling is lost.
1065 */
1066 protected boolean scanPubidLiteral(XMLString literal)
1067 throws IOException, XNIException {
1068 int quote = fEntityScanner.scanChar();
1069 if (quote != '\'' && quote != '"') {
1070 reportFatalError("QuoteRequiredInPublicID", null);
1071 return false;
1072 }
1073
1074 fStringBuffer.clear();
1075 // skip leading whitespace
1076 boolean skipSpace = true;
1077 boolean dataok = true;
1078 while (true) {
1079 int c = fEntityScanner.scanChar();
1080 if (c == ' ' || c == '\n' || c == '\r') {
1081 if (!skipSpace) {
1082 // take the first whitespace as a space and skip the others
1083 fStringBuffer.append(' ');
1084 skipSpace = true;
1085 }
1086 } else if (c == quote) {
1087 if (skipSpace) {
1088 // if we finished on a space let's trim it
1089 fStringBuffer.length--;
1090 }
1091 literal.setValues(fStringBuffer);
1092 break;
1093 } else if (XMLChar.isPubid(c)) {
1094 fStringBuffer.append((char)c);
1095 skipSpace = false;
1096 } else if (c == -1) {
1097 reportFatalError("PublicIDUnterminated", null);
1098 return false;
1099 } else {
1100 dataok = false;
1101 reportFatalError("InvalidCharInPublicID",
1102 new Object[]{Integer.toHexString(c)});
1103 }
1104 }
1105 return dataok;
1106 }
1107
1108
1109 /**
1110 * Normalize whitespace in an XMLString converting all whitespace
1111 * characters to space characters.
1112 */
1113 protected void normalizeWhitespace(XMLString value) {
1114 int i=0;
1115 int j=0;
1116 int [] buff = fEntityScanner.whiteSpaceLookup;
1117 int buffLen = fEntityScanner.whiteSpaceLen;
1118 int end = value.offset + value.length;
1119 while(i < buffLen){
1120 j = buff[i];
1121 if(j < end ){
1122 value.ch[j] = ' ';
1123 }
1124 i++;
1125 }
1126 }
1127
1128 //
1129 // XMLEntityHandler methods
1130 //
1131
1132 /**
1133 * This method notifies of the start of an entity. The document entity
1134 * has the pseudo-name of "[xml]" the DTD has the pseudo-name of "[dtd]"
1135 * parameter entity names start with '%'; and general entities are just
1136 * specified by their name.
1137 *
1138 * @param name The name of the entity.
1139 * @param identifier The resource identifier.
1140 * @param encoding The auto-detected IANA encoding name of the entity
1141 * stream. This value will be null in those situations
1142 * where the entity encoding is not auto-detected (e.g.
1143 * internal entities or a document entity that is
1144 * parsed from a java.io.Reader).
1145 *
1146 * @throws XNIException Thrown by handler to signal an error.
1147 */
1148 public void startEntity(String name,
1149 XMLResourceIdentifier identifier,
1150 String encoding, Augmentations augs) throws XNIException {
1151
1152 // keep track of the entity depth
1153 fEntityDepth++;
1154 // must reset entity scanner
1155 fEntityScanner = fEntityManager.getEntityScanner();
1156 fEntityStore = fEntityManager.getEntityStore() ;
1157 } // startEntity(String,XMLResourceIdentifier,String)
1158
1159 /**
1160 * This method notifies the end of an entity. The document entity has
1161 * the pseudo-name of "[xml]" the DTD has the pseudo-name of "[dtd]"
1162 * parameter entity names start with '%'; and general entities are just
1163 * specified by their name.
1164 *
1165 * @param name The name of the entity.
1166 *
1167 * @throws XNIException Thrown by handler to signal an error.
1168 */
1169 public void endEntity(String name, Augmentations augs) throws IOException, XNIException {
1170
1171 // keep track of the entity depth
1172 fEntityDepth--;
1173
1174 } // endEntity(String)
1175
1176 /**
1177 * Scans a character reference and append the corresponding chars to the
1178 * specified buffer.
1179 *
1180 * <p>
1181 * <pre>
1182 * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1183 * </pre>
1184 *
1185 * <strong>Note:</strong> This method uses fStringBuffer, anything in it
1186 * at the time of calling is lost.
1187 *
1188 * @param buf the character buffer to append chars to
1189 * @param buf2 the character buffer to append non-normalized chars to
1190 *
1191 * @return the character value or (-1) on conversion failure
1192 */
1193 protected int scanCharReferenceValue(XMLStringBuffer buf, XMLStringBuffer buf2)
1194 throws IOException, XNIException {
1195 // scan hexadecimal value
1196 boolean hex = false;
1197 if (fEntityScanner.skipChar('x')) {
1198 if (buf2 != null) { buf2.append('x'); }
1199 hex = true;
1200 fStringBuffer3.clear();
1201 boolean digit = true;
1202
1203 int c = fEntityScanner.peekChar();
1204 digit = (c >= '0' && c <= '9') ||
1205 (c >= 'a' && c <= 'f') ||
1206 (c >= 'A' && c <= 'F');
1207 if (digit) {
1208 if (buf2 != null) { buf2.append((char)c); }
1209 fEntityScanner.scanChar();
1210 fStringBuffer3.append((char)c);
1211
1212 do {
1213 c = fEntityScanner.peekChar();
1214 digit = (c >= '0' && c <= '9') ||
1215 (c >= 'a' && c <= 'f') ||
1216 (c >= 'A' && c <= 'F');
1217 if (digit) {
1218 if (buf2 != null) { buf2.append((char)c); }
1219 fEntityScanner.scanChar();
1220 fStringBuffer3.append((char)c);
1221 }
1222 } while (digit);
1223 } else {
1224 reportFatalError("HexdigitRequiredInCharRef", null);
1225 }
1226 }
1227
1228 // scan decimal value
1229 else {
1230 fStringBuffer3.clear();
1231 boolean digit = true;
1232
1233 int c = fEntityScanner.peekChar();
1234 digit = c >= '0' && c <= '9';
1235 if (digit) {
1236 if (buf2 != null) { buf2.append((char)c); }
1237 fEntityScanner.scanChar();
1238 fStringBuffer3.append((char)c);
1239
1240 do {
1241 c = fEntityScanner.peekChar();
1242 digit = c >= '0' && c <= '9';
1243 if (digit) {
1244 if (buf2 != null) { buf2.append((char)c); }
1245 fEntityScanner.scanChar();
1246 fStringBuffer3.append((char)c);
1247 }
1248 } while (digit);
1249 } else {
1250 reportFatalError("DigitRequiredInCharRef", null);
1251 }
1252 }
1253
1254 // end
1255 if (!fEntityScanner.skipChar(';')) {
1256 reportFatalError("SemicolonRequiredInCharRef", null);
1257 }
1258 if (buf2 != null) { buf2.append(';'); }
1259
1260 // convert string to number
1261 int value = -1;
1262 try {
1263 value = Integer.parseInt(fStringBuffer3.toString(),
1264 hex ? 16 : 10);
1265
1266 // character reference must be a valid XML character
1267 if (isInvalid(value)) {
1268 StringBuffer errorBuf = new StringBuffer(fStringBuffer3.length + 1);
1269 if (hex) errorBuf.append('x');
1270 errorBuf.append(fStringBuffer3.ch, fStringBuffer3.offset, fStringBuffer3.length);
1271 reportFatalError("InvalidCharRef",
1272 new Object[]{errorBuf.toString()});
1273 }
1274 } catch (NumberFormatException e) {
1275 // Conversion failed, let -1 value drop through.
1276 // If we end up here, the character reference was invalid.
1277 StringBuffer errorBuf = new StringBuffer(fStringBuffer3.length + 1);
1278 if (hex) errorBuf.append('x');
1279 errorBuf.append(fStringBuffer3.ch, fStringBuffer3.offset, fStringBuffer3.length);
1280 reportFatalError("InvalidCharRef",
1281 new Object[]{errorBuf.toString()});
1282 }
1283
1284 // append corresponding chars to the given buffer
1285 if (!XMLChar.isSupplemental(value)) {
1286 buf.append((char) value);
1287 } else {
1288 // character is supplemental, split it into surrogate chars
1289 buf.append(XMLChar.highSurrogate(value));
1290 buf.append(XMLChar.lowSurrogate(value));
1291 }
1292
1293 // char refs notification code
1294 if (fNotifyCharRefs && value != -1) {
1295 String literal = "#" + (hex ? "x" : "") + fStringBuffer3.toString();
1296 if (!fScanningAttribute) {
1297 fCharRefLiteral = literal;
1298 }
1299 }
1300
1301 return value;
1302 }
1303 // returns true if the given character is not
1304 // valid with respect to the version of
1305 // XML understood by this scanner.
1306 protected boolean isInvalid(int value) {
1307 return (XMLChar.isInvalid(value));
1308 } // isInvalid(int): boolean
1309
1310 // returns true if the given character is not
1311 // valid or may not be used outside a character reference
1312 // with respect to the version of XML understood by this scanner.
1313 protected boolean isInvalidLiteral(int value) {
1314 return (XMLChar.isInvalid(value));
1315 } // isInvalidLiteral(int): boolean
1316
1317 // returns true if the given character is
1318 // a valid nameChar with respect to the version of
1319 // XML understood by this scanner.
1320 protected boolean isValidNameChar(int value) {
1321 return (XMLChar.isName(value));
1322 } // isValidNameChar(int): boolean
1323
1324 // returns true if the given character is
1325 // a valid NCName character with respect to the version of
1326 // XML understood by this scanner.
1327 protected boolean isValidNCName(int value) {
1328 return (XMLChar.isNCName(value));
1329 } // isValidNCName(int): boolean
1330
1331 // returns true if the given character is
1332 // a valid nameStartChar with respect to the version of
1333 // XML understood by this scanner.
1334 protected boolean isValidNameStartChar(int value) {
1335 return (XMLChar.isNameStart(value));
1336 } // isValidNameStartChar(int): boolean
1337
1338 protected boolean versionSupported(String version ) {
1339 return version.equals("1.0") || version.equals("1.1");
1340 } // version Supported
1341
1342 /**
1343 * Scans surrogates and append them to the specified buffer.
1344 * <p>
1345 * <strong>Note:</strong> This assumes the current char has already been
1346 * identified as a high surrogate.
1347 *
1348 * @param buf The StringBuffer to append the read surrogates to.
1349 * @return True if it succeeded.
1350 */
1351 protected boolean scanSurrogates(XMLStringBuffer buf)
1352 throws IOException, XNIException {
1353
1354 int high = fEntityScanner.scanChar();
1355 int low = fEntityScanner.peekChar();
1356 if (!XMLChar.isLowSurrogate(low)) {
1357 reportFatalError("InvalidCharInContent",
1358 new Object[] {Integer.toString(high, 16)});
1359 return false;
1360 }
1361 fEntityScanner.scanChar();
1362
1363 // convert surrogates to supplemental character
1364 int c = XMLChar.supplemental((char)high, (char)low);
1365
1366 // supplemental character must be a valid XML character
1367 if (isInvalid(c)) {
1368 reportFatalError("InvalidCharInContent",
1369 new Object[]{Integer.toString(c, 16)});
1370 return false;
1371 }
1372
1373 // fill in the buffer
1374 buf.append((char)high);
1375 buf.append((char)low);
1376
1377 return true;
1378
1379 } // scanSurrogates():boolean
1380
1381
1382 /**
1383 * Convenience function used in all XML scanners.
1384 */
1385 protected void reportFatalError(String msgId, Object[] args)
1386 throws XNIException {
1387 fErrorReporter.reportError(fEntityScanner, XMLMessageFormatter.XML_DOMAIN,
1388 msgId, args,
1389 XMLErrorReporter.SEVERITY_FATAL_ERROR);
1390 }
1391
1392 // private methods
1393 private void init() {
1394 // initialize scanner
1395 fEntityScanner = null;
1396 // initialize vars
1397 fEntityDepth = 0;
1398 fReportEntity = true;
1399 fResourceIdentifier.clear();
1400
1401 if(!fAttributeCacheInitDone){
1402 for(int i = 0; i < initialCacheCount; i++){
1403 attributeValueCache.add(new XMLString());
1404 stringBufferCache.add(new XMLStringBuffer());
1405 }
1406 fAttributeCacheInitDone = true;
1407 }
1408 fStringBufferIndex = 0;
1409 fAttributeCacheUsedCount = 0;
1410
1411 }
1412
1413 XMLStringBuffer getStringBuffer(){
1414 if((fStringBufferIndex < initialCacheCount )|| (fStringBufferIndex < stringBufferCache.size())){
1415 return (XMLStringBuffer)stringBufferCache.get(fStringBufferIndex++);
1416 }else{
1417 XMLStringBuffer tmpObj = new XMLStringBuffer();
1418 fStringBufferIndex++;
1419 stringBufferCache.add(tmpObj);
1420 return tmpObj;
1421 }
1422 }
1423
1424
1425 } // class XMLScanner