1 /*
   2  * Copyright (c) 2003, 2006, Oracle and/or its affiliates. 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 
  22 package com.sun.org.apache.xerces.internal.impl;
  23 
  24 import com.sun.xml.internal.stream.XMLBufferListener;
  25 import com.sun.xml.internal.stream.XMLEntityStorage;
  26 import com.sun.xml.internal.stream.XMLInputFactoryImpl;
  27 import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
  28 
  29 import java.io.EOFException;
  30 import java.io.IOException;
  31 import javax.xml.stream.XMLInputFactory;
  32 import javax.xml.stream.events.XMLEvent;
  33 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  34 import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
  35 import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
  36 import com.sun.org.apache.xerces.internal.util.XMLChar;
  37 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
  38 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  39 import com.sun.org.apache.xerces.internal.xni.QName;
  40 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  41 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  42 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  43 import com.sun.org.apache.xerces.internal.xni.XMLString;
  44 import com.sun.org.apache.xerces.internal.xni.XNIException;
  45 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  46 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  47 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  48 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentScanner;
  49 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  50 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  51 import com.sun.org.apache.xerces.internal.impl.Constants;
  52 import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
  53 import com.sun.org.apache.xerces.internal.util.SecurityManager;
  54 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
  55 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  56 import javax.xml.stream.XMLStreamConstants;
  57 import javax.xml.stream.events.XMLEvent;
  58 
  59 /**
  60  *
  61  * This class is responsible for scanning the structure and content
  62  * of document fragments.
  63  *
  64  * This class has been modified as per the new design which is more suited to
  65  * efficiently build pull parser. Lot of improvements have been done and
  66  * the code has been added to support stax functionality/features.
  67  *
  68  * @author Neeraj Bajaj SUN Microsystems
  69  * @author K.Venugopal SUN Microsystems
  70  * @author Glenn Marcy, IBM
  71  * @author Andy Clark, IBM
  72  * @author Arnaud  Le Hors, IBM
  73  * @author Eric Ye, IBM
  74  * @author Sunitha Reddy, SUN Microsystems
  75  * @version $Id: XMLDocumentFragmentScannerImpl.java,v 1.19 2010-11-02 19:54:55 joehw Exp $
  76  *
  77  */
  78 public class XMLDocumentFragmentScannerImpl
  79         extends XMLScanner
  80         implements XMLDocumentScanner, XMLComponent, XMLEntityHandler, XMLBufferListener {
  81 
  82     //
  83     // Constants
  84     //
  85 
  86     protected int fElementAttributeLimit;
  87 
  88     /** External subset resolver. **/
  89     protected ExternalSubsetResolver fExternalSubsetResolver;
  90 
  91     // scanner states
  92 
  93     //XXX this should be divided into more states.
  94     /** Scanner state: start of markup. */
  95     protected static final int SCANNER_STATE_START_OF_MARKUP = 21;
  96 
  97     /** Scanner state: content. */
  98     protected static final int SCANNER_STATE_CONTENT = 22;
  99 
 100     /** Scanner state: processing instruction. */
 101     protected static final int SCANNER_STATE_PI = 23;
 102 
 103     /** Scanner state: DOCTYPE. */
 104     protected static final int SCANNER_STATE_DOCTYPE = 24;
 105 
 106     /** Scanner state: XML Declaration */
 107     protected static final int SCANNER_STATE_XML_DECL = 25;
 108 
 109     /** Scanner state: root element. */
 110     protected static final int SCANNER_STATE_ROOT_ELEMENT = 26;
 111 
 112     /** Scanner state: comment. */
 113     protected static final int SCANNER_STATE_COMMENT = 27;
 114 
 115     /** Scanner state: reference. */
 116     protected static final int SCANNER_STATE_REFERENCE = 28;
 117 
 118     // <book type="hard"> reading attribute name 'type'
 119     protected static final int SCANNER_STATE_ATTRIBUTE = 29;
 120 
 121     // <book type="hard"> //reading attribute value.
 122     protected static final int SCANNER_STATE_ATTRIBUTE_VALUE = 30;
 123 
 124     /** Scanner state: trailing misc. USED BY DOCUMENT_SCANNER_IMPL*/
 125     //protected static final int SCANNER_STATE_TRAILING_MISC = 32;
 126 
 127     /** Scanner state: end of input. */
 128     protected static final int SCANNER_STATE_END_OF_INPUT = 33;
 129 
 130     /** Scanner state: terminated. */
 131     protected static final int SCANNER_STATE_TERMINATED = 34;
 132 
 133     /** Scanner state: CDATA section. */
 134     protected static final int SCANNER_STATE_CDATA = 35;
 135 
 136     /** Scanner state: Text declaration. */
 137     protected static final int SCANNER_STATE_TEXT_DECL = 36;
 138 
 139     /** Scanner state: Text declaration. */
 140     protected static final int SCANNER_STATE_CHARACTER_DATA = 37;
 141 
 142     //<book type="hard">foo</book>
 143     protected static final int SCANNER_STATE_START_ELEMENT_TAG = 38;
 144 
 145     //<book type="hard">foo</book> reading </book>
 146     protected static final int SCANNER_STATE_END_ELEMENT_TAG = 39;
 147 
 148     protected static final int SCANNER_STATE_CHAR_REFERENCE = 40;
 149     protected static final int SCANNER_STATE_BUILT_IN_REFS = 41;
 150 
 151     // feature identifiers
 152 
 153 
 154     /** Feature identifier: notify built-in refereces. */
 155     protected static final String NOTIFY_BUILTIN_REFS =
 156             Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE;
 157 
 158     /** Property identifier: entity resolver. */
 159     protected static final String ENTITY_RESOLVER =
 160             Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
 161 
 162     // recognized features and properties
 163 
 164     /** Recognized features. */
 165     private static final String[] RECOGNIZED_FEATURES = {
 166                 NAMESPACES,
 167                 VALIDATION,
 168                 NOTIFY_BUILTIN_REFS,
 169                 NOTIFY_CHAR_REFS,
 170                 Constants.STAX_REPORT_CDATA_EVENT
 171     };
 172 
 173     /** Feature defaults. */
 174     private static final Boolean[] FEATURE_DEFAULTS = {
 175                 Boolean.TRUE,
 176                 null,
 177                 Boolean.FALSE,
 178                 Boolean.FALSE,
 179                 Boolean.TRUE
 180     };
 181 
 182     /** Recognized properties. */
 183     private static final String[] RECOGNIZED_PROPERTIES = {
 184         SYMBOL_TABLE,
 185                 ERROR_REPORTER,
 186                 ENTITY_MANAGER,
 187     };
 188 
 189     /** Property defaults. */
 190     private static final Object[] PROPERTY_DEFAULTS = {
 191                 null,
 192                 null,
 193                 null,
 194     };
 195 
 196     protected static final char [] cdata = {'[','C','D','A','T','A','['};
 197     protected static final char [] xmlDecl = {'<','?','x','m','l'};
 198     protected static final char [] endTag = {'<','/'};
 199     // debugging
 200 
 201     /** Debug scanner state. */
 202     private static final boolean DEBUG_SCANNER_STATE = false;
 203 
 204     /** Debug driver. */
 205     private static final boolean DEBUG_DISPATCHER = false;
 206 
 207     /** Debug content driver scanning. */
 208     protected static final boolean DEBUG_START_END_ELEMENT = false;
 209 
 210 
 211     /** Debug driver next */
 212     protected static final boolean DEBUG_NEXT = false ;
 213 
 214     /** Debug driver next */
 215     protected static final boolean DEBUG = false;
 216     protected static final boolean DEBUG_COALESCE = false;
 217     //
 218     // Data
 219     //
 220 
 221     // protected data
 222 
 223     /** Document handler. */
 224     protected XMLDocumentHandler fDocumentHandler;
 225     protected int fScannerLastState ;
 226 
 227     /** Entity Storage */
 228     protected XMLEntityStorage fEntityStore;
 229 
 230     /** Entity stack. */
 231     protected int[] fEntityStack = new int[4];
 232 
 233     /** Markup depth. */
 234     protected int fMarkupDepth;
 235 
 236     //is the element empty
 237     protected boolean fEmptyElement ;
 238 
 239     //track if we are reading attributes, this is usefule while
 240     //there is a callback
 241     protected boolean fReadingAttributes = false;
 242 
 243     /** Scanner state. */
 244     protected int fScannerState;
 245 
 246     /** SubScanner state: inside scanContent method. */
 247     protected boolean fInScanContent = false;
 248     protected boolean fLastSectionWasCData = false;
 249     protected boolean fLastSectionWasEntityReference = false;
 250     protected boolean fLastSectionWasCharacterData = false;
 251 
 252     /** has external dtd */
 253     protected boolean fHasExternalDTD;
 254 
 255     /** Standalone. */
 256     protected boolean fStandaloneSet;
 257     protected boolean fStandalone;
 258     protected String fVersion;
 259 
 260     // element information
 261 
 262     /** Current element. */
 263     protected QName fCurrentElement;
 264 
 265     /** Element stack. */
 266     protected ElementStack fElementStack = new ElementStack();
 267     protected ElementStack2 fElementStack2 = new ElementStack2();
 268 
 269     // other info
 270 
 271     /** Document system identifier.
 272      * REVISIT:  So what's this used for?  - NG
 273      * protected String fDocumentSystemId;
 274      ******/
 275 
 276     protected String fPITarget ;
 277 
 278     //xxx do we need to create an extra XMLString object... look for using fTempString for collecting all the data values
 279     protected XMLString fPIData  = new XMLString();
 280 
 281     // features
 282 
 283 
 284     /** Notify built-in references. */
 285     protected boolean fNotifyBuiltInRefs = false;
 286 
 287     //STAX related properties
 288     //defaultValues.
 289     protected boolean fSupportDTD = true;
 290     protected boolean fReplaceEntityReferences = true;
 291     protected boolean fSupportExternalEntities = false;
 292     protected boolean fReportCdataEvent = false ;
 293     protected boolean fIsCoalesce = false ;
 294     protected String fDeclaredEncoding =  null;
 295     /** Xerces Feature: Disallow doctype declaration. */
 296     protected boolean fDisallowDoctype = false;
 297 
 298     // drivers
 299 
 300     /** Active driver. */
 301     protected Driver fDriver;
 302 
 303     /** Content driver. */
 304     protected Driver fContentDriver = createContentDriver();
 305 
 306     // temporary variables
 307 
 308     /** Element QName. */
 309     protected QName fElementQName = new QName();
 310 
 311     /** Attribute QName. */
 312     protected QName fAttributeQName = new QName();
 313 
 314     /**
 315      * CHANGED: Using XMLAttributesIteratorImpl instead of XMLAttributesImpl. This class
 316      * implements Iterator interface so we can directly give Attributes in the form of
 317      * iterator.
 318      */
 319     protected XMLAttributesIteratorImpl fAttributes = new XMLAttributesIteratorImpl();
 320 
 321 
 322     /** String. */
 323     protected XMLString fTempString = new XMLString();
 324 
 325     /** String. */
 326     protected XMLString fTempString2 = new XMLString();
 327 
 328     /** Array of 3 strings. */
 329     private String[] fStrings = new String[3];
 330 
 331     /** Making the buffer accesible to derived class -- String buffer. */
 332     protected XMLStringBuffer fStringBuffer = new XMLStringBuffer();
 333 
 334     /** Making the buffer accesible to derived class -- String buffer. */
 335     protected XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
 336 
 337     /** stores character data. */
 338     /** Making the buffer accesible to derived class -- stores PI data */
 339     protected XMLStringBuffer fContentBuffer = new XMLStringBuffer();
 340 
 341     /** Single character array. */
 342     private final char[] fSingleChar = new char[1];
 343     private String fCurrentEntityName = null;
 344 
 345     // New members
 346     protected boolean fScanToEnd = false;
 347 
 348     protected DTDGrammarUtil dtdGrammarUtil= null;
 349 
 350     protected boolean fAddDefaultAttr = false;
 351 
 352     protected boolean foundBuiltInRefs = false;
 353 
 354     protected SecurityManager fSecurityManager = null;
 355 
 356     //skip element algorithm
 357     static final short MAX_DEPTH_LIMIT = 5 ;
 358     static final short ELEMENT_ARRAY_LENGTH = 200 ;
 359     static final short MAX_POINTER_AT_A_DEPTH = 4 ;
 360     static final boolean DEBUG_SKIP_ALGORITHM = false;
 361     //create a elemnet array of length equal to ELEMENT_ARRAY_LENGTH
 362     String [] fElementArray = new String[ELEMENT_ARRAY_LENGTH] ;
 363     //pointer location where last element was skipped
 364     short fLastPointerLocation = 0 ;
 365     short fElementPointer = 0 ;
 366     //2D array to store pointer info
 367     short [] [] fPointerInfo = new short[MAX_DEPTH_LIMIT] [MAX_POINTER_AT_A_DEPTH] ;
 368     protected String fElementRawname ;
 369     protected boolean fShouldSkip = false;
 370     protected boolean fAdd = false ;
 371     protected boolean fSkip = false;
 372 
 373     /** Reusable Augmentations. */
 374     private Augmentations fTempAugmentations = null;
 375     //
 376     // Constructors
 377     //
 378 
 379     /** Default constructor. */
 380     public XMLDocumentFragmentScannerImpl() {
 381     } // <init>()
 382 
 383     //
 384     // XMLDocumentScanner methods
 385     //
 386 
 387     /**
 388      * Sets the input source.
 389      *
 390      * @param inputSource The input source.
 391      *
 392      * @throws IOException Thrown on i/o error.
 393      */
 394     public void setInputSource(XMLInputSource inputSource) throws IOException {
 395         fEntityManager.setEntityHandler(this);
 396         fEntityManager.startEntity("$fragment$", inputSource, false, true);
 397         // fDocumentSystemId = fEntityManager.expandSystemId(inputSource.getSystemId());
 398     } // setInputSource(XMLInputSource)
 399 
 400     /**
 401      * Scans a document.
 402      *
 403      * @param complete True if the scanner should scan the document
 404      *                 completely, pushing all events to the registered
 405      *                 document handler. A value of false indicates that
 406      *                 that the scanner should only scan the next portion
 407      *                 of the document and return. A scanner instance is
 408      *                 permitted to completely scan a document if it does
 409      *                 not support this "pull" scanning model.
 410      *
 411      * @return True if there is more to scan, false otherwise.
 412      */
 413    /* public boolean scanDocument(boolean complete)
 414     throws IOException, XNIException {
 415 
 416         // keep dispatching "events"
 417         fEntityManager.setEntityHandler(this);
 418 
 419         return true;
 420 
 421     } // scanDocument(boolean):boolean
 422     */
 423 
 424     public boolean scanDocument(boolean complete)
 425     throws IOException, XNIException {
 426 
 427         // keep dispatching "events"
 428         fEntityManager.setEntityHandler(this);
 429         //System.out.println(" get Document Handler in NSDocumentHandler " + fDocumentHandler );
 430 
 431         int event = next();
 432         do {
 433             switch (event) {
 434                 case XMLStreamConstants.START_DOCUMENT :
 435                     //fDocumentHandler.startDocument(fEntityManager.getEntityScanner(),fEntityManager.getEntityScanner().getVersion(),fNamespaceContext,null);// not able to get
 436                     break;
 437                 case XMLStreamConstants.START_ELEMENT :
 438                     //System.out.println(" in scann element");
 439                     //fDocumentHandler.startElement(getElementQName(),fAttributes,null);
 440                     break;
 441                 case XMLStreamConstants.CHARACTERS :
 442                     fDocumentHandler.characters(getCharacterData(),null);
 443                     break;
 444                 case XMLStreamConstants.SPACE:
 445                     //check if getCharacterData() is the right function to retrieve ignorableWhitespace information.
 446                     //System.out.println("in the space");
 447                     //fDocumentHandler.ignorableWhitespace(getCharacterData(), null);
 448                     break;
 449                 case XMLStreamConstants.ENTITY_REFERENCE :
 450                     //entity reference callback are given in startEntity
 451                     break;
 452                 case XMLStreamConstants.PROCESSING_INSTRUCTION :
 453                     fDocumentHandler.processingInstruction(getPITarget(),getPIData(),null);
 454                     break;
 455                 case XMLStreamConstants.COMMENT :
 456                     //System.out.println(" in COMMENT of the XMLNSDocumentScannerImpl");
 457                     fDocumentHandler.comment(getCharacterData(),null);
 458                     break;
 459                 case XMLStreamConstants.DTD :
 460                     //all DTD related callbacks are handled in DTDScanner.
 461                     //1. Stax doesn't define DTD states as it does for XML Document.
 462                     //therefore we don't need to take care of anything here. So Just break;
 463                     break;
 464                 case XMLStreamConstants.CDATA:
 465                     fDocumentHandler.startCDATA(null);
 466                     //xxx: check if CDATA values comes from getCharacterData() function
 467                     fDocumentHandler.characters(getCharacterData(),null);
 468                     fDocumentHandler.endCDATA(null);
 469                     //System.out.println(" in CDATA of the XMLNSDocumentScannerImpl");
 470                     break;
 471                 case XMLStreamConstants.NOTATION_DECLARATION :
 472                     break;
 473                 case XMLStreamConstants.ENTITY_DECLARATION :
 474                     break;
 475                 case XMLStreamConstants.NAMESPACE :
 476                     break;
 477                 case XMLStreamConstants.ATTRIBUTE :
 478                     break;
 479                 case XMLStreamConstants.END_ELEMENT :
 480                     //do not give callback here.
 481                     //this callback is given in scanEndElement function.
 482                     //fDocumentHandler.endElement(getElementQName(),null);
 483                     break;
 484                 default :
 485                     throw new InternalError("processing event: " + event);
 486 
 487             }
 488             //System.out.println("here in before calling next");
 489             event = next();
 490             //System.out.println("here in after calling next");
 491         } while (event!=XMLStreamConstants.END_DOCUMENT && complete);
 492 
 493         if(event == XMLStreamConstants.END_DOCUMENT) {
 494             fDocumentHandler.endDocument(null);
 495             return false;
 496         }
 497 
 498         return true;
 499 
 500     } // scanDocument(boolean):boolean
 501 
 502 
 503 
 504     public com.sun.org.apache.xerces.internal.xni.QName getElementQName(){
 505         if(fScannerLastState == XMLEvent.END_ELEMENT){
 506             fElementQName.setValues(fElementStack.getLastPoppedElement());
 507         }
 508         return fElementQName ;
 509     }
 510 
 511     /** return the next state on the input
 512      * @return int
 513      */
 514 
 515     public int next() throws IOException, XNIException {
 516         return fDriver.next();
 517     }
 518 
 519     //
 520     // XMLComponent methods
 521     //
 522 
 523     /**
 524      * Resets the component. The component can query the component manager
 525      * about any features and properties that affect the operation of the
 526      * component.
 527      *
 528      * @param componentManager The component manager.
 529      *
 530      * @throws SAXException Thrown by component on initialization error.
 531      *                      For example, if a feature or property is
 532      *                      required for the operation of the component, the
 533      *                      component manager may throw a
 534      *                      SAXNotRecognizedException or a
 535      *                      SAXNotSupportedException.
 536      */
 537 
 538     public void reset(XMLComponentManager componentManager)
 539     throws XMLConfigurationException {
 540 
 541         super.reset(componentManager);
 542 
 543         // other settings
 544         // fDocumentSystemId = null;
 545 
 546         // sax features
 547         //fAttributes.setNamespaces(fNamespaces);
 548 
 549         // xerces features
 550         fReportCdataEvent = componentManager.getFeature(Constants.STAX_REPORT_CDATA_EVENT, true);
 551 
 552         fSecurityManager = (SecurityManager)componentManager.getProperty(Constants.SECURITY_MANAGER, null);
 553         fElementAttributeLimit = (fSecurityManager != null)?fSecurityManager.getElementAttrLimit():0;
 554 
 555         fNotifyBuiltInRefs = componentManager.getFeature(NOTIFY_BUILTIN_REFS, false);
 556 
 557         Object resolver = componentManager.getProperty(ENTITY_RESOLVER, null);
 558         fExternalSubsetResolver = (resolver instanceof ExternalSubsetResolver) ?
 559                 (ExternalSubsetResolver) resolver : null;
 560 
 561         // initialize vars
 562         fMarkupDepth = 0;
 563         fCurrentElement = null;
 564         fElementStack.clear();
 565         fHasExternalDTD = false;
 566         fStandaloneSet = false;
 567         fStandalone = false;
 568         fInScanContent = false;
 569         //skipping algorithm
 570         fShouldSkip = false;
 571         fAdd = false;
 572         fSkip = false;
 573 
 574         //attribute
 575         fReadingAttributes = false;
 576         //xxx: external entities are supported in Xerces
 577         // it would be good to define feature for this case
 578         fSupportExternalEntities = true;
 579         fReplaceEntityReferences = true;
 580         fIsCoalesce = false;
 581 
 582         // setup Driver
 583         setScannerState(SCANNER_STATE_CONTENT);
 584         setDriver(fContentDriver);
 585         fEntityStore = fEntityManager.getEntityStore();
 586 
 587         dtdGrammarUtil = null;
 588 
 589 
 590         //fEntityManager.test();
 591     } // reset(XMLComponentManager)
 592 
 593 
 594     public void reset(PropertyManager propertyManager){
 595 
 596         super.reset(propertyManager);
 597 
 598         // other settings
 599         // fDocumentSystemId = null;
 600         fNamespaces = ((Boolean)propertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue();
 601         fNotifyBuiltInRefs = false ;
 602 
 603         // initialize vars
 604         fMarkupDepth = 0;
 605         fCurrentElement = null;
 606         fShouldSkip = false;
 607         fAdd = false;
 608         fSkip = false;
 609         fElementStack.clear();
 610         //fElementStack2.clear();
 611         fHasExternalDTD = false;
 612         fStandaloneSet = false;
 613         fStandalone = false;
 614         //fReplaceEntityReferences = true;
 615         //fSupportExternalEntities = true;
 616         Boolean bo = (Boolean)propertyManager.getProperty(XMLInputFactoryImpl.IS_REPLACING_ENTITY_REFERENCES);
 617         fReplaceEntityReferences = bo.booleanValue();
 618         bo = (Boolean)propertyManager.getProperty(XMLInputFactoryImpl.IS_SUPPORTING_EXTERNAL_ENTITIES);
 619         fSupportExternalEntities = bo.booleanValue();
 620         Boolean cdata = (Boolean)propertyManager.getProperty(Constants.ZEPHYR_PROPERTY_PREFIX + Constants.STAX_REPORT_CDATA_EVENT) ;
 621         if(cdata != null)
 622             fReportCdataEvent = cdata.booleanValue() ;
 623         Boolean coalesce = (Boolean)propertyManager.getProperty(XMLInputFactory.IS_COALESCING) ;
 624         if(coalesce != null)
 625             fIsCoalesce = coalesce.booleanValue();
 626         fReportCdataEvent = fIsCoalesce ? false : (fReportCdataEvent && true) ;
 627         //if fIsCoalesce is set to true, set the value of fReplaceEntityReferences to true,
 628         //if fIsCoalesce is set to false, take the value of fReplaceEntityReferences as set by application
 629         fReplaceEntityReferences = fIsCoalesce ? true : fReplaceEntityReferences;
 630         // setup Driver
 631         //we dont need to do this -- nb.
 632         //setScannerState(SCANNER_STATE_CONTENT);
 633         //setDriver(fContentDriver);
 634         fEntityStore = fEntityManager.getEntityStore();
 635         //fEntityManager.test();
 636 
 637         dtdGrammarUtil = null;
 638 
 639     } // reset(XMLComponentManager)
 640 
 641     /**
 642      * Returns a list of feature identifiers that are recognized by
 643      * this component. This method may return null if no features
 644      * are recognized by this component.
 645      */
 646     public String[] getRecognizedFeatures() {
 647         return (String[])(RECOGNIZED_FEATURES.clone());
 648     } // getRecognizedFeatures():String[]
 649 
 650     /**
 651      * Sets the state of a feature. This method is called by the component
 652      * manager any time after reset when a feature changes state.
 653      * <p>
 654      * <strong>Note:</strong> Components should silently ignore features
 655      * that do not affect the operation of the component.
 656      *
 657      * @param featureId The feature identifier.
 658      * @param state     The state of the feature.
 659      *
 660      * @throws SAXNotRecognizedException The component should not throw
 661      *                                   this exception.
 662      * @throws SAXNotSupportedException The component should not throw
 663      *                                  this exception.
 664      */
 665     public void setFeature(String featureId, boolean state)
 666     throws XMLConfigurationException {
 667 
 668         super.setFeature(featureId, state);
 669 
 670         // Xerces properties
 671         if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
 672             String feature = featureId.substring(Constants.XERCES_FEATURE_PREFIX.length());
 673             if (feature.equals(Constants.NOTIFY_BUILTIN_REFS_FEATURE)) {
 674                 fNotifyBuiltInRefs = state;
 675             }
 676         }
 677 
 678     } // setFeature(String,boolean)
 679 
 680     /**
 681      * Returns a list of property identifiers that are recognized by
 682      * this component. This method may return null if no properties
 683      * are recognized by this component.
 684      */
 685     public String[] getRecognizedProperties() {
 686         return (String[])(RECOGNIZED_PROPERTIES.clone());
 687     } // getRecognizedProperties():String[]
 688 
 689     /**
 690      * Sets the value of a property. This method is called by the component
 691      * manager any time after reset when a property changes value.
 692      * <p>
 693      * <strong>Note:</strong> Components should silently ignore properties
 694      * that do not affect the operation of the component.
 695      *
 696      * @param propertyId The property identifier.
 697      * @param value      The value of the property.
 698      *
 699      * @throws SAXNotRecognizedException The component should not throw
 700      *                                   this exception.
 701      * @throws SAXNotSupportedException The component should not throw
 702      *                                  this exception.
 703      */
 704     public void setProperty(String propertyId, Object value)
 705     throws XMLConfigurationException {
 706 
 707         super.setProperty(propertyId, value);
 708 
 709         // Xerces properties
 710         if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
 711             final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
 712             if (suffixLength == Constants.ENTITY_MANAGER_PROPERTY.length() &&
 713                     propertyId.endsWith(Constants.ENTITY_MANAGER_PROPERTY)) {
 714                 fEntityManager = (XMLEntityManager)value;
 715                 return;
 716             }
 717             if (suffixLength == Constants.ENTITY_RESOLVER_PROPERTY.length() &&
 718                     propertyId.endsWith(Constants.ENTITY_RESOLVER_PROPERTY)) {
 719                 fExternalSubsetResolver = (value instanceof ExternalSubsetResolver) ?
 720                     (ExternalSubsetResolver) value : null;
 721                 return;
 722             }
 723         }
 724 
 725 
 726                 // Xerces properties
 727         if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
 728             String property = propertyId.substring(Constants.XERCES_PROPERTY_PREFIX.length());
 729             if (property.equals(Constants.ENTITY_MANAGER_PROPERTY)) {
 730                 fEntityManager = (XMLEntityManager)value;
 731             }
 732             return;
 733         }
 734 
 735     } // setProperty(String,Object)
 736 
 737     /**
 738      * Returns the default state for a feature, or null if this
 739      * component does not want to report a default value for this
 740      * feature.
 741      *
 742      * @param featureId The feature identifier.
 743      *
 744      * @since Xerces 2.2.0
 745      */
 746     public Boolean getFeatureDefault(String featureId) {
 747         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
 748             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
 749                 return FEATURE_DEFAULTS[i];
 750             }
 751         }
 752         return null;
 753     } // getFeatureDefault(String):Boolean
 754 
 755     /**
 756      * Returns the default state for a property, or null if this
 757      * component does not want to report a default value for this
 758      * property.
 759      *
 760      * @param propertyId The property identifier.
 761      *
 762      * @since Xerces 2.2.0
 763      */
 764     public Object getPropertyDefault(String propertyId) {
 765         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
 766             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
 767                 return PROPERTY_DEFAULTS[i];
 768             }
 769         }
 770         return null;
 771     } // getPropertyDefault(String):Object
 772 
 773     //
 774     // XMLDocumentSource methods
 775     //
 776 
 777     /**
 778      * setDocumentHandler
 779      *
 780      * @param documentHandler
 781      */
 782     public void setDocumentHandler(XMLDocumentHandler documentHandler) {
 783         fDocumentHandler = documentHandler;
 784         //System.out.println(" In Set DOCUMENT HANDLER" + fDocumentHandler + " scanner =" + this);
 785     } // setDocumentHandler(XMLDocumentHandler)
 786 
 787 
 788     /** Returns the document handler */
 789     public XMLDocumentHandler getDocumentHandler(){
 790         return fDocumentHandler;
 791     }
 792 
 793     //
 794     // XMLEntityHandler methods
 795     //
 796 
 797     /**
 798      * This method notifies of the start of an entity. The DTD has the
 799      * pseudo-name of "[dtd]" parameter entity names start with '%'; and
 800      * general entities are just specified by their name.
 801      *
 802      * @param name     The name of the entity.
 803      * @param identifier The resource identifier.
 804      * @param encoding The auto-detected IANA encoding name of the entity
 805      *                 stream. This value will be null in those situations
 806      *                 where the entity encoding is not auto-detected (e.g.
 807      *                 internal entities or a document entity that is
 808      *                 parsed from a java.io.Reader).
 809      *
 810      * @throws XNIException Thrown by handler to signal an error.
 811      */
 812     public void startEntity(String name,
 813             XMLResourceIdentifier identifier,
 814             String encoding, Augmentations augs) throws XNIException {
 815 
 816         // keep track of this entity before fEntityDepth is increased
 817         if (fEntityDepth == fEntityStack.length) {
 818             int[] entityarray = new int[fEntityStack.length * 2];
 819             System.arraycopy(fEntityStack, 0, entityarray, 0, fEntityStack.length);
 820             fEntityStack = entityarray;
 821         }
 822         fEntityStack[fEntityDepth] = fMarkupDepth;
 823 
 824         super.startEntity(name, identifier, encoding, augs);
 825 
 826         // WFC:  entity declared in external subset in standalone doc
 827         if(fStandalone && fEntityStore.isEntityDeclInExternalSubset(name)) {
 828             reportFatalError("MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
 829                     new Object[]{name});
 830         }
 831 
 832         /** we are not calling the handlers yet.. */
 833         // call handler
 834         if (fDocumentHandler != null && !fScanningAttribute) {
 835             if (!name.equals("[xml]")) {
 836                 fDocumentHandler.startGeneralEntity(name, identifier, encoding, null);
 837             }
 838         }
 839 
 840     } // startEntity(String,XMLResourceIdentifier,String)
 841 
 842     /**
 843      * This method notifies the end of an entity. The DTD has the pseudo-name
 844      * of "[dtd]" parameter entity names start with '%'; and general entities
 845      * are just specified by their name.
 846      *
 847      * @param name The name of the entity.
 848      *
 849      * @throws XNIException Thrown by handler to signal an error.
 850      */
 851     public void endEntity(String name, Augmentations augs) throws IOException, XNIException {
 852 
 853         /**
 854          * // flush possible pending output buffer - see scanContent
 855          * if (fInScanContent && fStringBuffer.length != 0
 856          * && fDocumentHandler != null) {
 857          * fDocumentHandler.characters(fStringBuffer, null);
 858          * fStringBuffer.length = 0; // make sure we know it's been flushed
 859          * }
 860          */
 861         super.endEntity(name, augs);
 862 
 863         // make sure markup is properly balanced
 864         if (fMarkupDepth != fEntityStack[fEntityDepth]) {
 865             reportFatalError("MarkupEntityMismatch", null);
 866         }
 867 
 868         /**/
 869         // call handler
 870         if (fDocumentHandler != null && !fScanningAttribute) {
 871             if (!name.equals("[xml]")) {
 872                 fDocumentHandler.endGeneralEntity(name, null);
 873             }
 874         }
 875 
 876 
 877     } // endEntity(String)
 878 
 879     //
 880     // Protected methods
 881     //
 882 
 883     // Driver factory methods
 884 
 885     /** Creates a content Driver. */
 886     protected Driver createContentDriver() {
 887         return new FragmentContentDriver();
 888     } // createContentDriver():Driver
 889 
 890     // scanning methods
 891 
 892     /**
 893      * Scans an XML or text declaration.
 894      * <p>
 895      * <pre>
 896      * [23] XMLDecl ::= '&lt;?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
 897      * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
 898      * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
 899      * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
 900      * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
 901      *                 | ('"' ('yes' | 'no') '"'))
 902      *
 903      * [77] TextDecl ::= '&lt;?xml' VersionInfo? EncodingDecl S? '?>'
 904      * </pre>
 905      *
 906      * @param scanningTextDecl True if a text declaration is to
 907      *                         be scanned instead of an XML
 908      *                         declaration.
 909      */
 910     protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl)
 911     throws IOException, XNIException {
 912 
 913         // scan decl
 914         super.scanXMLDeclOrTextDecl(scanningTextDecl, fStrings);
 915         fMarkupDepth--;
 916 
 917         // pseudo-attribute values
 918         String version = fStrings[0];
 919         String encoding = fStrings[1];
 920         String standalone = fStrings[2];
 921         fDeclaredEncoding = encoding;
 922         // set standalone
 923         fStandaloneSet = standalone != null;
 924         fStandalone = fStandaloneSet && standalone.equals("yes");
 925         ///xxx see where its used.. this is not used anywhere. it may be useful for entity to store this information
 926         //but this information is only related with Document Entity.
 927         fEntityManager.setStandalone(fStandalone);
 928 
 929 
 930         // call handler
 931         if (fDocumentHandler != null) {
 932             if (scanningTextDecl) {
 933                 fDocumentHandler.textDecl(version, encoding, null);
 934             } else {
 935                 fDocumentHandler.xmlDecl(version, encoding, standalone, null);
 936             }
 937         }
 938 
 939         if(version != null){
 940             fEntityScanner.setVersion(version);
 941             fEntityScanner.setXMLVersion(version);
 942         }
 943         // set encoding on reader, only if encoding was not specified by the application explicitly
 944         if (encoding != null && !fEntityScanner.getCurrentEntity().isEncodingExternallySpecified()) {
 945              fEntityScanner.setEncoding(encoding);
 946         }
 947 
 948     } // scanXMLDeclOrTextDecl(boolean)
 949 
 950     public String getPITarget(){
 951         return fPITarget ;
 952     }
 953 
 954     public XMLStringBuffer getPIData(){
 955         return fContentBuffer ;
 956     }
 957 
 958     //XXX: why not this function behave as per the state of the parser?
 959     public XMLString getCharacterData(){
 960         if(fUsebuffer){
 961             return fContentBuffer ;
 962         }else{
 963             return fTempString;
 964         }
 965 
 966     }
 967 
 968 
 969     /**
 970      * Scans a processing data. This is needed to handle the situation
 971      * where a document starts with a processing instruction whose
 972      * target name <em>starts with</em> "xml". (e.g. xmlfoo)
 973      *
 974      * @param target The PI target
 975      * @param data The XMLStringBuffer to fill in with the data
 976      */
 977     protected void scanPIData(String target, XMLStringBuffer data)
 978     throws IOException, XNIException {
 979 
 980         super.scanPIData(target, data);
 981 
 982         //set the PI target and values
 983         fPITarget = target ;
 984 
 985         fMarkupDepth--;
 986 
 987     } // scanPIData(String)
 988 
 989     /**
 990      * Scans a comment.
 991      * <p>
 992      * <pre>
 993      * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
 994      * </pre>
 995      * <p>
 996      * <strong>Note:</strong> Called after scanning past '&lt;!--'
 997      */
 998     protected void scanComment() throws IOException, XNIException {
 999         fContentBuffer.clear();
1000         scanComment(fContentBuffer);
1001         //getTextCharacters can also be called for reading comments
1002         fUsebuffer = true;
1003         fMarkupDepth--;
1004 
1005     } // scanComment()
1006 
1007     //xxx value returned by this function may not remain valid if another event is scanned.
1008     public String getComment(){
1009         return fContentBuffer.toString();
1010     }
1011 
1012     void addElement(String rawname){
1013         if(fElementPointer < ELEMENT_ARRAY_LENGTH){
1014             //storing element raw name in a linear list of array
1015             fElementArray[fElementPointer] = rawname ;
1016             //storing elemnetPointer for particular element depth
1017 
1018             if(DEBUG_SKIP_ALGORITHM){
1019                 StringBuffer sb = new StringBuffer() ;
1020                 sb.append(" Storing element information ") ;
1021                 sb.append(" fElementPointer = " + fElementPointer) ;
1022                 sb.append(" fElementRawname = " + fElementQName.rawname) ;
1023                 sb.append(" fElementStack.fDepth = " + fElementStack.fDepth);
1024                 System.out.println(sb.toString()) ;
1025             }
1026 
1027             //store pointer information only when element depth is less MAX_DEPTH_LIMIT
1028             if(fElementStack.fDepth < MAX_DEPTH_LIMIT){
1029                 short column = storePointerForADepth(fElementPointer);
1030                 if(column > 0){
1031                     short pointer = getElementPointer((short)fElementStack.fDepth, (short)(column - 1) );
1032                     //identity comparison shouldn't take much time and we can rely on this
1033                     //since its guaranteed to have same object id for same string.
1034                     if(rawname == fElementArray[pointer]){
1035                         fShouldSkip = true ;
1036                         fLastPointerLocation = pointer ;
1037                         //reset the things and return.
1038                         resetPointer((short)fElementStack.fDepth , column) ;
1039                         fElementArray[fElementPointer] = null ;
1040                         return ;
1041                     }else{
1042                         fShouldSkip = false ;
1043                     }
1044                 }
1045             }
1046             fElementPointer++ ;
1047         }
1048     }
1049 
1050 
1051     void resetPointer(short depth, short column){
1052         fPointerInfo[depth] [column] = (short)0;
1053     }
1054 
1055     //returns column information at which pointer was stored.
1056     short storePointerForADepth(short elementPointer){
1057         short depth = (short) fElementStack.fDepth ;
1058 
1059         //Stores element pointer locations at particular depth , only 4 pointer locations
1060         //are stored at particular depth for now.
1061         for(short i = 0 ; i < MAX_POINTER_AT_A_DEPTH ; i++){
1062 
1063             if(canStore(depth, i)){
1064                 fPointerInfo[depth][i] = elementPointer ;
1065                 if(DEBUG_SKIP_ALGORITHM){
1066                     StringBuffer sb = new StringBuffer() ;
1067                     sb.append(" Pointer information ") ;
1068                     sb.append(" fElementPointer = " + fElementPointer) ;
1069                     sb.append(" fElementStack.fDepth = " + fElementStack.fDepth);
1070                     sb.append(" column = " + i ) ;
1071                     System.out.println(sb.toString()) ;
1072                 }
1073                 return i;
1074             }
1075             //else
1076             //pointer was not stored because we reached the limit
1077         }
1078         return -1 ;
1079     }
1080 
1081     boolean canStore(short depth, short column){
1082         //colum = 0 , means first element at particular depth
1083         //column = 1, means second element at particular depth
1084         //        calle should make sure that it doesn't call for value outside allowed co-ordinates
1085         return fPointerInfo[depth][column] == 0 ? true : false ;
1086     }
1087 
1088 
1089     short getElementPointer(short depth, short column){
1090         //colum = 0 , means first element at particular depth
1091         //column = 1, means second element at particular depth
1092         //        calle should make sure that it doesn't call for value outside allowed co-ordinates
1093         return fPointerInfo[depth][column] ;
1094     }
1095 
1096     //this function assumes that string passed is not null and skips
1097     //the following string from the buffer this makes sure
1098     boolean skipFromTheBuffer(String rawname) throws IOException{
1099         if(fEntityScanner.skipString(rawname)){
1100             char c = (char)fEntityScanner.peekChar() ;
1101             //If the start element was completely skipped we should encounter either ' '(space),
1102             //or '/' (in case of empty element)  or '>'
1103             if( c == ' ' || c == '/' || c == '>'){
1104                 fElementRawname = rawname ;
1105                 return true ;
1106             } else{
1107                 return false;
1108             }
1109         } else
1110             return false ;
1111     }
1112 
1113     boolean skipQElement(String rawname) throws IOException{
1114 
1115         final int c = fEntityScanner.getChar(rawname.length());
1116         //if this character is still valid element name -- this means string can't match
1117         if(XMLChar.isName(c)){
1118             return false;
1119         }else{
1120             return fEntityScanner.skipString(rawname);
1121         }
1122     }
1123 
1124     protected boolean skipElement() throws IOException {
1125 
1126         if(!fShouldSkip) return false ;
1127 
1128         if(fLastPointerLocation != 0){
1129             //Look at the next element stored in the array list.. we might just get a match.
1130             String rawname = fElementArray[fLastPointerLocation + 1] ;
1131             if(rawname != null && skipFromTheBuffer(rawname)){
1132                 fLastPointerLocation++ ;
1133                 if(DEBUG_SKIP_ALGORITHM){
1134                     System.out.println("Element " + fElementRawname + " was SKIPPED at pointer location = " + fLastPointerLocation);
1135                 }
1136                 return true ;
1137             } else{
1138                 //reset it back to zero... we haven't got the correct subset yet.
1139                 fLastPointerLocation = 0 ;
1140 
1141             }
1142         }
1143         //xxx: we can put some logic here as from what column it should start looking
1144         //for now we always start at 0
1145         //fallback to tolerant algorithm, it would look for differnt element stored at different
1146         //depth and get us the pointer location.
1147         return fShouldSkip && skipElement((short)0);
1148 
1149     }
1150 
1151     //start of the column at which it should try searching
1152     boolean skipElement(short column) throws IOException {
1153         short depth = (short)fElementStack.fDepth ;
1154 
1155         if(depth > MAX_DEPTH_LIMIT){
1156             return fShouldSkip = false ;
1157         }
1158         for(short i = column ; i < MAX_POINTER_AT_A_DEPTH ; i++){
1159             short pointer = getElementPointer(depth , i ) ;
1160 
1161             if(pointer == 0){
1162                 return fShouldSkip = false ;
1163             }
1164 
1165             if(fElementArray[pointer] != null && skipFromTheBuffer(fElementArray[pointer])){
1166                 if(DEBUG_SKIP_ALGORITHM){
1167                     System.out.println();
1168                     System.out.println("Element " + fElementRawname + " was SKIPPED at depth = " + fElementStack.fDepth + " column = " + column );
1169                     System.out.println();
1170                 }
1171                 fLastPointerLocation = pointer ;
1172                 return fShouldSkip = true ;
1173             }
1174         }
1175         return fShouldSkip = false ;
1176     }
1177 
1178     /**
1179      * Scans a start element. This method will handle the binding of
1180      * namespace information and notifying the handler of the start
1181      * of the element.
1182      * <p>
1183      * <pre>
1184      * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
1185      * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
1186      * </pre>
1187      * <p>
1188      * <strong>Note:</strong> This method assumes that the leading
1189      * '&lt;' character has been consumed.
1190      * <p>
1191      * <strong>Note:</strong> This method uses the fElementQName and
1192      * fAttributes variables. The contents of these variables will be
1193      * destroyed. The caller should copy important information out of
1194      * these variables before calling this method.
1195      * NB: Content in fAttributes is valid only till the state of the parser is XMLEvent.START_ELEMENT
1196      *
1197      * @return True if element is empty. (i.e. It matches
1198      *          production [44].
1199      */
1200     // fElementQName will have the details of element just read..
1201     // fAttributes will have the details of all the attributes.
1202     protected boolean scanStartElement()
1203     throws IOException, XNIException {
1204 
1205         if (DEBUG_START_END_ELEMENT) System.out.println( this.getClass().toString() + ">>> scanStartElement()");
1206         //when skipping is true and no more elements should be added
1207         if(fSkip && !fAdd){
1208             //get the stored element -- if everything goes right this should match the
1209             //token in the buffer
1210 
1211             QName name = fElementStack.getNext();
1212 
1213             if(DEBUG_SKIP_ALGORITHM){
1214                 System.out.println("Trying to skip String = " + name.rawname);
1215             }
1216 
1217             //Be conservative -- if skipping fails -- stop.
1218             fSkip = fEntityScanner.skipString(name.rawname);
1219 
1220             if(fSkip){
1221                 if(DEBUG_SKIP_ALGORITHM){
1222                     System.out.println("Element SUCESSFULLY skipped = " + name.rawname);
1223                 }
1224                 fElementStack.push();
1225                 fElementQName = name;
1226             }else{
1227                 //if skipping fails reposition the stack or fallback to normal way of processing
1228                 fElementStack.reposition();
1229                 if(DEBUG_SKIP_ALGORITHM){
1230                     System.out.println("Element was NOT skipped, REPOSITIONING stack" );
1231                 }
1232             }
1233         }
1234 
1235         //we are still at the stage of adding elements
1236         //the elements were not matched or
1237         //fSkip is not set to true
1238         if(!fSkip || fAdd){
1239             //get the next element from the stack
1240             fElementQName = fElementStack.nextElement();
1241             // name
1242             if (fNamespaces) {
1243                 fEntityScanner.scanQName(fElementQName);
1244             } else {
1245                 String name = fEntityScanner.scanName();
1246                 fElementQName.setValues(null, name, name, null);
1247             }
1248 
1249             if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
1250             if(DEBUG_SKIP_ALGORITHM){
1251                 if(fAdd){
1252                     System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
1253                 }
1254             }
1255 
1256         }
1257 
1258         //when the elements are being added , we need to check if we are set for skipping the elements
1259         if(fAdd){
1260             //this sets the value of fAdd variable
1261             fElementStack.matchElement(fElementQName);
1262         }
1263 
1264 
1265         //xxx: We dont need another pointer, fCurrentElement, we can use fElementQName
1266         fCurrentElement = fElementQName;
1267 
1268         String rawname = fElementQName.rawname;
1269 
1270         fEmptyElement = false;
1271 
1272         fAttributes.removeAllAttributes();
1273 
1274         if(!seekCloseOfStartTag()){
1275             fReadingAttributes = true;
1276             fAttributeCacheUsedCount =0;
1277             fStringBufferIndex =0;
1278             fAddDefaultAttr = true;
1279             do {
1280                 scanAttribute(fAttributes);
1281                 if (fSecurityManager != null && fAttributes.getLength() > fElementAttributeLimit){
1282                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1283                                                  "ElementAttributeLimit",
1284                                                  new Object[]{rawname, new Integer(fAttributes.getLength()) },
1285                                                  XMLErrorReporter.SEVERITY_FATAL_ERROR );
1286                 }
1287 
1288             } while (!seekCloseOfStartTag());
1289             fReadingAttributes=false;
1290         }
1291 
1292         if (fEmptyElement) {
1293             //decrease the markup depth..
1294             fMarkupDepth--;
1295 
1296             // check that this element was opened in the same entity
1297             if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
1298                 reportFatalError("ElementEntityMismatch",
1299                         new Object[]{fCurrentElement.rawname});
1300             }
1301             // call handler
1302             if (fDocumentHandler != null) {
1303                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
1304             }
1305 
1306             //We should not be popping out the context here in endELement becaause the namespace context is still
1307             //valid when parser is at the endElement state.
1308             //if (fNamespaces) {
1309             //  fNamespaceContext.popContext();
1310             //}
1311 
1312             //pop the element off the stack..
1313             fElementStack.popElement();
1314 
1315         } else {
1316 
1317             if(dtdGrammarUtil != null)
1318                 dtdGrammarUtil.startElement(fElementQName, fAttributes);
1319             if(fDocumentHandler != null){
1320                 //complete element and attributes are traversed in this function so we can send a callback
1321                 //here.
1322                 //<strong>we shouldn't be sending callback in scanDocument()</strong>
1323                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
1324             }
1325         }
1326 
1327 
1328         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() + "<<< scanStartElement(): "+fEmptyElement);
1329         return fEmptyElement;
1330 
1331     } // scanStartElement():boolean
1332 
1333     /**
1334      * Looks for the close of start tag, i.e. if it finds '>' or '/>'
1335      * Characters are consumed.
1336      */
1337     protected boolean seekCloseOfStartTag() throws IOException, XNIException {
1338         // spaces
1339         boolean sawSpace = fEntityScanner.skipSpaces();
1340 
1341         // end tag?
1342         final int c = fEntityScanner.peekChar();
1343         if (c == '>') {
1344             fEntityScanner.scanChar();
1345             return true;
1346         } else if (c == '/') {
1347             fEntityScanner.scanChar();
1348             if (!fEntityScanner.skipChar('>')) {
1349                 reportFatalError("ElementUnterminated",
1350                         new Object[]{fElementQName.rawname});
1351             }
1352             fEmptyElement = true;
1353             return true;
1354         } else if (!isValidNameStartChar(c) || !sawSpace) {
1355             reportFatalError("ElementUnterminated", new Object[]{fElementQName.rawname});
1356         }
1357 
1358         return false;
1359     }
1360 
1361     public boolean hasAttributes(){
1362         return fAttributes.getLength() > 0 ? true : false ;
1363     }
1364 
1365 
1366     /**
1367      * Scans an attribute.
1368      * <p>
1369      * <pre>
1370      * [41] Attribute ::= Name Eq AttValue
1371      * </pre>
1372      * <p>
1373      * <strong>Note:</strong> This method assumes that the next
1374      * character on the stream is the first character of the attribute
1375      * name.
1376      * <p>
1377      * <strong>Note:</strong> This method uses the fAttributeQName and
1378      * fQName variables. The contents of these variables will be
1379      * destroyed.
1380      *
1381      * @param attributes The attributes list for the scanned attribute.
1382      */
1383 
1384     /**
1385      * protected void scanAttribute(AttributeIteratorImpl attributes)
1386      * throws IOException, XNIException {
1387      * if (DEBUG_START_END_ELEMENT) System.out.println(">>> scanAttribute()");
1388      *
1389      *
1390      * // name
1391      * if (fNamespaces) {
1392      * fEntityScanner.scanQName(fAttributeQName);
1393      * }
1394      * else {
1395      * String name = fEntityScanner.scanName();
1396      * fAttributeQName.setValues(null, name, name, null);
1397      * }
1398      *
1399      * // equals
1400      * fEntityScanner.skipSpaces();
1401      * if (!fEntityScanner.skipChar('=')) {
1402      * reportFatalError("EqRequiredInAttribute",
1403      * new Object[]{fAttributeQName.rawname});
1404      * }
1405      * fEntityScanner.skipSpaces();
1406      *
1407      *
1408      * // content
1409      * int oldLen = attributes.getLength();
1410      */
1411     /**xxx there is one check of duplicate attribute that has been removed.
1412      * attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
1413      *
1414      * // WFC: Unique Att Spec
1415      * if (oldLen == attributes.getLength()) {
1416      * reportFatalError("AttributeNotUnique",
1417      * new Object[]{fCurrentElement.rawname,
1418      * fAttributeQName.rawname});
1419      * }
1420      */
1421 
1422     /*
1423         //REVISIT: one more case needs to be included: external PE and standalone is no
1424         boolean isVC =  fHasExternalDTD && !fStandalone;
1425         scanAttributeValue(fTempString, fTempString2,
1426                            fAttributeQName.rawname, attributes,
1427                            oldLen, isVC);
1428 
1429         //attributes.setValue(oldLen, fTempString.toString());
1430         //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
1431         //attributes.setSpecified(oldLen, true);
1432 
1433         AttributeImpl attribute = new AttributeImpl(fAttributeQName.prefix,fAttributeQName.localpart,fAttributeQName.uri,fTempString.toString(),fTempString2.toString(),XMLSymbols.fCDATASymbol,true);
1434         fAttributes.addAttribute(attribute);
1435         if (DEBUG_START_END_ELEMENT) System.out.println("<<< scanAttribute()");
1436     } // scanAttribute(XMLAttributes)
1437 
1438      */
1439 
1440     /** return the attribute iterator implementation */
1441     public XMLAttributesIteratorImpl getAttributeIterator(){
1442         if(dtdGrammarUtil != null && fAddDefaultAttr){
1443             dtdGrammarUtil.addDTDDefaultAttrs(fElementQName,fAttributes);
1444             fAddDefaultAttr = false;
1445         }
1446         return fAttributes;
1447     }
1448 
1449     /** return if standalone is set */
1450     public boolean standaloneSet(){
1451         return fStandaloneSet;
1452     }
1453     /** return if the doucment is standalone */
1454     public boolean isStandAlone(){
1455         return fStandalone ;
1456     }
1457     /**
1458      * Scans an attribute name value pair.
1459      * <p>
1460      * <pre>
1461      * [41] Attribute ::= Name Eq AttValue
1462      * </pre>
1463      * <p>
1464      * <strong>Note:</strong> This method assumes that the next
1465      * character on the stream is the first character of the attribute
1466      * name.
1467      * <p>
1468      * <strong>Note:</strong> This method uses the fAttributeQName and
1469      * fQName variables. The contents of these variables will be
1470      * destroyed.
1471      *
1472      * @param attributes The attributes list for the scanned attribute.
1473      */
1474 
1475     protected void scanAttribute(XMLAttributes attributes)
1476     throws IOException, XNIException {
1477         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
1478 
1479         // name
1480         if (fNamespaces) {
1481             fEntityScanner.scanQName(fAttributeQName);
1482         } else {
1483             String name = fEntityScanner.scanName();
1484             fAttributeQName.setValues(null, name, name, null);
1485         }
1486 
1487         // equals
1488         fEntityScanner.skipSpaces();
1489         if (!fEntityScanner.skipChar('=')) {
1490             reportFatalError("EqRequiredInAttribute",
1491                 new Object[] {fCurrentElement.rawname, fAttributeQName.rawname});
1492         }
1493         fEntityScanner.skipSpaces();
1494 
1495         int attIndex = 0 ;
1496         //REVISIT: one more case needs to be included: external PE and standalone is no
1497         boolean isVC =  fHasExternalDTD && !fStandalone;
1498         //fTempString would store attribute value
1499         ///fTempString2 would store attribute non-normalized value
1500 
1501         //this function doesn't use 'attIndex'. We are adding the attribute later
1502         //after we have figured out that current attribute is not namespace declaration
1503         //since scanAttributeValue doesn't use attIndex parameter therefore we
1504         //can safely add the attribute later..
1505         XMLString tmpStr = getString();
1506 
1507         scanAttributeValue(tmpStr, fTempString2,
1508                 fAttributeQName.rawname, attributes,
1509                 attIndex, isVC);
1510 
1511         // content
1512         int oldLen = attributes.getLength();
1513         //if the attribute name already exists.. new value is replaced with old value
1514         attIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
1515 
1516         // WFC: Unique Att Spec
1517         //attributes count will be same if the current attribute  name already exists for this element name.
1518         //this means there are two duplicate attributes.
1519         if (oldLen == attributes.getLength()) {
1520             reportFatalError("AttributeNotUnique",
1521                     new Object[]{fCurrentElement.rawname,
1522                             fAttributeQName.rawname});
1523         }
1524 
1525         //tmpString contains attribute value
1526         //we are passing null as the attribute value
1527         attributes.setValue(attIndex, null, tmpStr);
1528 
1529         ///xxx: nonNormalizedValue is not being set as it is not required by SAX & DOM
1530         //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
1531         attributes.setSpecified(attIndex, true);
1532 
1533         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanAttribute()");
1534 
1535     } // scanAttribute(XMLAttributes)
1536 
1537     /**
1538      * Scans element content.
1539      *
1540      * @return Returns the next character on the stream.
1541      */
1542     //CHANGED:
1543     //EARLIER: scanContent()
1544     //NOW: scanContent(XMLStringBuffer)
1545     //It makes things easy if this functions takes XMLStringBuffer as parameter..
1546     //this function appends the data to the buffer.
1547     protected int scanContent(XMLStringBuffer content) throws IOException, XNIException {
1548         //set the fTempString length to 0 before passing it on to scanContent
1549         //scanContent sets the correct co-ordinates as per the content read
1550         fTempString.length = 0;
1551         int c = fEntityScanner.scanContent(fTempString);
1552         content.append(fTempString);
1553         fTempString.length = 0;
1554         if (c == '\r') {
1555             // happens when there is the character reference &#13;
1556             //xxx: We know the next chracter.. we should just skip it and add ']' directlry
1557             fEntityScanner.scanChar();
1558             content.append((char)c);
1559             c = -1;
1560         } else if (c == ']') {
1561             //fStringBuffer.clear();
1562             //xxx: We know the next chracter.. we should just skip it and add ']' directlry
1563             content.append((char)fEntityScanner.scanChar());
1564             // remember where we are in case we get an endEntity before we
1565             // could flush the buffer out - this happens when we're parsing an
1566             // entity which ends with a ]
1567             fInScanContent = true;
1568             //
1569             // We work on a single character basis to handle cases such as:
1570             // ']]]>' which we might otherwise miss.
1571             //
1572             if (fEntityScanner.skipChar(']')) {
1573                 content.append(']');
1574                 while (fEntityScanner.skipChar(']')) {
1575                     content.append(']');
1576                 }
1577                 if (fEntityScanner.skipChar('>')) {
1578                     reportFatalError("CDEndInContent", null);
1579                 }
1580             }
1581             fInScanContent = false;
1582             c = -1;
1583         }
1584         if (fDocumentHandler != null && content.length > 0) {
1585             //fDocumentHandler.characters(content, null);
1586         }
1587         return c;
1588 
1589     } // scanContent():int
1590 
1591 
1592     /**
1593      * Scans a CDATA section.
1594      * <p>
1595      * <strong>Note:</strong> This method uses the fTempString and
1596      * fStringBuffer variables.
1597      *
1598      * @param complete True if the CDATA section is to be scanned
1599      *                 completely.
1600      *
1601      * @return True if CDATA is completely scanned.
1602      */
1603     //CHANGED:
1604     protected boolean scanCDATASection(XMLStringBuffer contentBuffer, boolean complete)
1605     throws IOException, XNIException {
1606 
1607         // call handler
1608         if (fDocumentHandler != null) {
1609             //fDocumentHandler.startCDATA(null);
1610         }
1611 
1612         while (true) {
1613             //scanData will fill the contentBuffer
1614             if (!fEntityScanner.scanData("]]>", contentBuffer)) {
1615                 break ;
1616                 /** We dont need all this code if we pass ']]>' as delimeter..
1617                  * int brackets = 2;
1618                  * while (fEntityScanner.skipChar(']')) {
1619                  * brackets++;
1620                  * }
1621                  *
1622                  * //When we find more than 2 square brackets
1623                  * if (fDocumentHandler != null && brackets > 2) {
1624                  * //we dont need to clear the buffer..
1625                  * //contentBuffer.clear();
1626                  * for (int i = 2; i < brackets; i++) {
1627                  * contentBuffer.append(']');
1628                  * }
1629                  * fDocumentHandler.characters(contentBuffer, null);
1630                  * }
1631                  *
1632                  * if (fEntityScanner.skipChar('>')) {
1633                  * break;
1634                  * }
1635                  * if (fDocumentHandler != null) {
1636                  * //we dont need to clear the buffer now..
1637                  * //contentBuffer.clear();
1638                  * contentBuffer.append("]]");
1639                  * fDocumentHandler.characters(contentBuffer, null);
1640                  * }
1641                  **/
1642             } else {
1643                 int c = fEntityScanner.peekChar();
1644                 if (c != -1 && isInvalidLiteral(c)) {
1645                     if (XMLChar.isHighSurrogate(c)) {
1646                         //contentBuffer.clear();
1647                         //scan surrogates if any....
1648                         scanSurrogates(contentBuffer);
1649                     } else {
1650                         reportFatalError("InvalidCharInCDSect",
1651                                 new Object[]{Integer.toString(c,16)});
1652                                 fEntityScanner.scanChar();
1653                     }
1654                 }
1655                 //by this time we have also read surrogate contents if any...
1656                 if (fDocumentHandler != null) {
1657                     //fDocumentHandler.characters(contentBuffer, null);
1658                 }
1659             }
1660         }
1661         fMarkupDepth--;
1662 
1663         if (fDocumentHandler != null && contentBuffer.length > 0) {
1664             //fDocumentHandler.characters(contentBuffer, null);
1665         }
1666 
1667         // call handler
1668         if (fDocumentHandler != null) {
1669             //fDocumentHandler.endCDATA(null);
1670         }
1671 
1672         return true;
1673 
1674     } // scanCDATASection(XMLStringBuffer, boolean):boolean
1675 
1676     /**
1677      * Scans an end element.
1678      * <p>
1679      * <pre>
1680      * [42] ETag ::= '&lt;/' Name S? '>'
1681      * </pre>
1682      * <p>
1683      * <strong>Note:</strong> This method uses the fElementQName variable.
1684      * The contents of this variable will be destroyed. The caller should
1685      * copy the needed information out of this variable before calling
1686      * this method.
1687      *
1688      * @return The element depth.
1689      */
1690     protected int scanEndElement() throws IOException, XNIException {
1691         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanEndElement()");
1692 
1693         // pop context
1694         QName endElementName = fElementStack.popElement();
1695 
1696         String rawname = endElementName.rawname;
1697         if(DEBUG)System.out.println("endElementName = " + endElementName.toString());
1698         // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
1699         //In scanners most of the time is consumed on checks done for XML characters, we can
1700         // optimize on it and avoid the checks done for endElement,
1701         //we will also avoid symbol table lookup - neeraj.bajaj@sun.com
1702 
1703         // this should work both for namespace processing true or false...
1704 
1705         //REVISIT: if the string is not the same as expected.. we need to do better error handling..
1706         //We can skip this for now... In any case if the string doesn't match -- document is not well formed.
1707 
1708         if (!fEntityScanner.skipString(endElementName.rawname)) {
1709              reportFatalError("ETagRequired", new Object[]{rawname});
1710         }
1711 
1712         // end
1713         fEntityScanner.skipSpaces();
1714         if (!fEntityScanner.skipChar('>')) {
1715             reportFatalError("ETagUnterminated",
1716                     new Object[]{rawname});
1717         }
1718         fMarkupDepth--;
1719 
1720         //we have increased the depth for two markup "<" characters
1721         fMarkupDepth--;
1722 
1723         // check that this element was opened in the same entity
1724         if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
1725             reportFatalError("ElementEntityMismatch",
1726                     new Object[]{rawname});
1727         }
1728 
1729         //We should not be popping out the context here in endELement becaause the namespace context is still
1730         //valid when parser is at the endElement state.
1731 
1732         //if (fNamespaces) {
1733         //  fNamespaceContext.popContext();
1734         //}
1735 
1736         // call handler
1737         if (fDocumentHandler != null ) {
1738             //end element is scanned in this function so we can send a callback
1739             //here.
1740             //<strong>we shouldn't be sending callback in scanDocument()</strong>
1741 
1742             fDocumentHandler.endElement(endElementName, null);
1743         }
1744         if(dtdGrammarUtil != null)
1745             dtdGrammarUtil.endElement(endElementName);
1746 
1747         return fMarkupDepth;
1748 
1749     } // scanEndElement():int
1750 
1751     /**
1752      * Scans a character reference.
1753      * <p>
1754      * <pre>
1755      * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
1756      * </pre>
1757      */
1758     protected void scanCharReference()
1759     throws IOException, XNIException {
1760 
1761         fStringBuffer2.clear();
1762         int ch = scanCharReferenceValue(fStringBuffer2, null);
1763         fMarkupDepth--;
1764         if (ch != -1) {
1765             // call handler
1766 
1767             if (fDocumentHandler != null) {
1768                 if (fNotifyCharRefs) {
1769                     fDocumentHandler.startGeneralEntity(fCharRefLiteral, null, null, null);
1770                 }
1771                 Augmentations augs = null;
1772                 if (fValidation && ch <= 0x20) {
1773                     if (fTempAugmentations != null) {
1774                         fTempAugmentations.removeAllItems();
1775                     }
1776                     else {
1777                         fTempAugmentations = new AugmentationsImpl();
1778                     }
1779                     augs = fTempAugmentations;
1780                     augs.putItem(Constants.CHAR_REF_PROBABLE_WS, Boolean.TRUE);
1781                 }
1782                 //xxx: How do we deal with this - how to return charReferenceValues
1783                 //now this is being commented because this is taken care in scanDocument()
1784                 //fDocumentHandler.characters(fStringBuffer2, null);
1785                 if (fNotifyCharRefs) {
1786                     fDocumentHandler.endGeneralEntity(fCharRefLiteral, null);
1787                 }
1788             }
1789         }
1790 
1791     } // scanCharReference()
1792 
1793 
1794     /**
1795      * Scans an entity reference.
1796      *
1797      * @return returns true if the new entity is started. If it was built-in entity
1798      *         'false' is returned.
1799      * @throws IOException  Thrown if i/o error occurs.
1800      * @throws XNIException Thrown if handler throws exception upon
1801      *                      notification.
1802      */
1803     protected void scanEntityReference(XMLStringBuffer content) throws IOException, XNIException {
1804         String name = fEntityScanner.scanName();
1805         if (name == null) {
1806             reportFatalError("NameRequiredInReference", null);
1807             return;
1808         }
1809         if (!fEntityScanner.skipChar(';')) {
1810             reportFatalError("SemicolonRequiredInReference", new Object []{name});
1811         }
1812         if (fEntityStore.isUnparsedEntity(name)) {
1813             reportFatalError("ReferenceToUnparsedEntity", new Object[]{name});
1814         }
1815         fMarkupDepth--;
1816         fCurrentEntityName = name;
1817 
1818         // handle built-in entities
1819         if (name == fAmpSymbol) {
1820             handleCharacter('&', fAmpSymbol, content);
1821             fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1822             return ;
1823         } else if (name == fLtSymbol) {
1824             handleCharacter('<', fLtSymbol, content);
1825             fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1826             return ;
1827         } else if (name == fGtSymbol) {
1828             handleCharacter('>', fGtSymbol, content);
1829             fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1830             return ;
1831         } else if (name == fQuotSymbol) {
1832             handleCharacter('"', fQuotSymbol, content);
1833             fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1834             return ;
1835         } else if (name == fAposSymbol) {
1836             handleCharacter('\'', fAposSymbol, content);
1837             fScannerState = SCANNER_STATE_BUILT_IN_REFS;
1838             return ;
1839         }
1840 
1841         //1. if the entity is external and support to external entities is not required
1842         // 2. or entities should not be replaced
1843         //3. or if it is built in entity reference.
1844         if((fEntityStore.isExternalEntity(name) && !fSupportExternalEntities) || (!fEntityStore.isExternalEntity(name) && !fReplaceEntityReferences) || foundBuiltInRefs){
1845             fScannerState = SCANNER_STATE_REFERENCE;
1846             return ;
1847         }
1848         // start general entity
1849         if (!fEntityStore.isDeclaredEntity(name)) {
1850             //SUPPORT_DTD=false && ReplaceEntityReferences should throw exception
1851             if (!fSupportDTD && fReplaceEntityReferences) {
1852                 reportFatalError("EntityNotDeclared", new Object[]{name});
1853                 return;
1854             }
1855             //REVISIT: one more case needs to be included: external PE and standalone is no
1856             if ( fHasExternalDTD && !fStandalone) {
1857                 if (fValidation)
1858                     fErrorReporter.reportError(fEntityScanner, XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
1859                             new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
1860             } else
1861                 reportFatalError("EntityNotDeclared", new Object[]{name});
1862         }
1863         //we are starting the entity even if the entity was not declared
1864         //if that was the case it its taken care in XMLEntityManager.startEntity()
1865         //we immediately call the endEntity. Application gets to know if there was
1866         //any entity that was not declared.
1867         fEntityManager.startEntity(name, false);
1868         //set the scaner state to content.. parser will automatically revive itself at any point of time.
1869         //setScannerState(SCANNER_STATE_CONTENT);
1870         //return true ;
1871     } // scanEntityReference()
1872 
1873     // utility methods
1874 
1875     /**
1876      * Calls document handler with a single character resulting from
1877      * built-in entity resolution.
1878      *
1879      * @param c
1880      * @param entity built-in name
1881      * @param XMLStringBuffer append the character to buffer
1882      *
1883      * we really dont need to call this function -- this function is only required when
1884      * we integrate with rest of Xerces2. SO maintaining the current behavior and still
1885      * calling this function to hanlde built-in entity reference.
1886      *
1887      */
1888     private void handleCharacter(char c, String entity, XMLStringBuffer content) throws XNIException {
1889         foundBuiltInRefs = true;
1890         content.append(c);
1891         if (fDocumentHandler != null) {
1892             fSingleChar[0] = c;
1893             if (fNotifyBuiltInRefs) {
1894                 fDocumentHandler.startGeneralEntity(entity, null, null, null);
1895             }
1896             fTempString.setValues(fSingleChar, 0, 1);
1897             //fDocumentHandler.characters(fTempString, null);
1898 
1899             if (fNotifyBuiltInRefs) {
1900                 fDocumentHandler.endGeneralEntity(entity, null);
1901             }
1902         }
1903     } // handleCharacter(char)
1904 
1905     // helper methods
1906 
1907     /**
1908      * Sets the scanner state.
1909      *
1910      * @param state The new scanner state.
1911      */
1912     protected final void setScannerState(int state) {
1913 
1914         fScannerState = state;
1915         if (DEBUG_SCANNER_STATE) {
1916             System.out.print("### setScannerState: ");
1917             //System.out.print(fScannerState);
1918             System.out.print(getScannerStateName(state));
1919             System.out.println();
1920         }
1921 
1922     } // setScannerState(int)
1923 
1924 
1925     /**
1926      * Sets the Driver.
1927      *
1928      * @param Driver The new Driver.
1929      */
1930     protected final void setDriver(Driver driver) {
1931         fDriver = driver;
1932         if (DEBUG_DISPATCHER) {
1933             System.out.print("%%% setDriver: ");
1934             System.out.print(getDriverName(driver));
1935             System.out.println();
1936         }
1937     }
1938 
1939     //
1940     // Private methods
1941     //
1942 
1943     /** Returns the scanner state name. */
1944     protected String getScannerStateName(int state) {
1945 
1946         switch (state) {
1947             case SCANNER_STATE_DOCTYPE: return "SCANNER_STATE_DOCTYPE";
1948             case SCANNER_STATE_ROOT_ELEMENT: return "SCANNER_STATE_ROOT_ELEMENT";
1949             case SCANNER_STATE_START_OF_MARKUP: return "SCANNER_STATE_START_OF_MARKUP";
1950             case SCANNER_STATE_COMMENT: return "SCANNER_STATE_COMMENT";
1951             case SCANNER_STATE_PI: return "SCANNER_STATE_PI";
1952             case SCANNER_STATE_CONTENT: return "SCANNER_STATE_CONTENT";
1953             case SCANNER_STATE_REFERENCE: return "SCANNER_STATE_REFERENCE";
1954             case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
1955             case SCANNER_STATE_TERMINATED: return "SCANNER_STATE_TERMINATED";
1956             case SCANNER_STATE_CDATA: return "SCANNER_STATE_CDATA";
1957             case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
1958             case SCANNER_STATE_ATTRIBUTE: return "SCANNER_STATE_ATTRIBUTE";
1959             case SCANNER_STATE_ATTRIBUTE_VALUE: return "SCANNER_STATE_ATTRIBUTE_VALUE";
1960             case SCANNER_STATE_START_ELEMENT_TAG: return "SCANNER_STATE_START_ELEMENT_TAG";
1961             case SCANNER_STATE_END_ELEMENT_TAG: return "SCANNER_STATE_END_ELEMENT_TAG";
1962             case SCANNER_STATE_CHARACTER_DATA: return "SCANNER_STATE_CHARACTER_DATA" ;
1963         }
1964 
1965         return "??? ("+state+')';
1966 
1967     } // getScannerStateName(int):String
1968     public String getEntityName(){
1969         //return the cached name
1970         return fCurrentEntityName;
1971     }
1972 
1973     /** Returns the driver name. */
1974     public String getDriverName(Driver driver) {
1975 
1976         if (DEBUG_DISPATCHER) {
1977             if (driver != null) {
1978                 String name = driver.getClass().getName();
1979                 int index = name.lastIndexOf('.');
1980                 if (index != -1) {
1981                     name = name.substring(index + 1);
1982                     index = name.lastIndexOf('$');
1983                     if (index != -1) {
1984                         name = name.substring(index + 1);
1985                     }
1986                 }
1987                 return name;
1988             }
1989         }
1990         return "null";
1991 
1992     } // getDriverName():String
1993 
1994     //
1995     // Classes
1996     //
1997 
1998     /**
1999      * @author Neeraj Bajaj, Sun Microsystems.
2000      */
2001     protected static final class Element {
2002 
2003         //
2004         // Data
2005         //
2006 
2007         /** Symbol. */
2008         public QName qname;
2009 
2010         //raw name stored as characters
2011         public char[] fRawname;
2012 
2013         /** The next Element entry. */
2014         public Element next;
2015 
2016         //
2017         // Constructors
2018         //
2019 
2020         /**
2021          * Constructs a new Element from the given QName and next Element
2022          * reference.
2023          */
2024         public Element(QName qname, Element next) {
2025             this.qname.setValues(qname);
2026             this.fRawname = qname.rawname.toCharArray();
2027             this.next = next;
2028         }
2029 
2030     } // class Element
2031 
2032     /**
2033      * Element stack.
2034      *
2035      * @author Neeraj Bajaj, Sun Microsystems.
2036      */
2037     protected class ElementStack2 {
2038 
2039         //
2040         // Data
2041         //
2042 
2043         /** The stack data. */
2044         protected QName [] fQName = new QName[20];
2045 
2046         //Element depth
2047         protected int fDepth;
2048         //total number of elements
2049         protected int fCount;
2050         //current position
2051         protected int fPosition;
2052         //Mark refers to the position
2053         protected int fMark;
2054 
2055         protected int fLastDepth ;
2056 
2057         //
2058         // Constructors
2059         //
2060 
2061         /** Default constructor. */
2062         public ElementStack2() {
2063             for (int i = 0; i < fQName.length; i++) {
2064                 fQName[i] = new QName();
2065             }
2066             fMark = fPosition = 1;
2067         } // <init>()
2068 
2069         public void resize(){
2070             /**
2071              * int length = fElements.length;
2072              * Element [] temp = new Element[length * 2];
2073              * System.arraycopy(fElements, 0, temp, 0, length);
2074              * fElements = temp;
2075              */
2076             //resize QNames
2077             int oldLength = fQName.length;
2078             QName [] tmp = new QName[oldLength * 2];
2079             System.arraycopy(fQName, 0, tmp, 0, oldLength);
2080             fQName = tmp;
2081 
2082             for (int i = oldLength; i < fQName.length; i++) {
2083                 fQName[i] = new QName();
2084             }
2085 
2086         }
2087 
2088 
2089         //
2090         // Public methods
2091         //
2092 
2093         /** Check if the element scanned during the start element
2094          *matches the stored element.
2095          *
2096          *@return true if the match suceeds.
2097          */
2098         public boolean matchElement(QName element) {
2099             //last depth is the depth when last elemnt was pushed
2100             //if last depth is greater than current depth
2101             if(DEBUG_SKIP_ALGORITHM){
2102                 System.out.println("fLastDepth = " + fLastDepth);
2103                 System.out.println("fDepth = " + fDepth);
2104             }
2105             boolean match = false;
2106             if(fLastDepth > fDepth && fDepth <= 2){
2107                 if(DEBUG_SKIP_ALGORITHM){
2108                     System.out.println("Checking if the elements match " + element.rawname + " , " + fQName[fDepth].rawname);
2109                 }
2110                 if(element.rawname == fQName[fDepth].rawname){
2111                     fAdd = false;
2112                     //mark this position
2113                     //decrease the depth by 1 as arrays are 0 based
2114                     fMark = fDepth - 1;
2115                     //we found the match and from next element skipping will start, add 1
2116                     fPosition = fMark + 1 ;
2117                     match = true;
2118                     //Once we get match decrease the count -- this was increased by nextElement()
2119                     --fCount;
2120                     if(DEBUG_SKIP_ALGORITHM){
2121                         System.out.println("fAdd FALSE -- NOW ELEMENT SHOULD NOT BE ADDED");
2122                         System.out.println("fMark = " + fMark);
2123                         System.out.println("fPosition = " + fPosition);
2124                         System.out.println("fDepth = " + fDepth);
2125                         System.out.println("fCount = " + fCount);
2126                     }
2127                 }else{
2128                     fAdd = true;
2129                     if(DEBUG_SKIP_ALGORITHM)System.out.println("fAdd is " + fAdd);
2130                 }
2131             }
2132             //store the last depth
2133             fLastDepth = fDepth++;
2134             return match;
2135         } // pushElement(QName):QName
2136 
2137         /**
2138          * This function doesn't increase depth. The function in this function is
2139          *broken down into two functions for efficiency. <@see>matchElement</see>.
2140          * This function just returns the pointer to the object and its values are set.
2141          *
2142          *@return QName reference to the next element in the list
2143          */
2144         public QName nextElement() {
2145 
2146             //if number of elements becomes equal to the length of array -- stop the skipping
2147             if (fCount == fQName.length) {
2148                 fShouldSkip = false;
2149                 fAdd = false;
2150                 if(DEBUG_SKIP_ALGORITHM)System.out.println("SKIPPING STOPPED, fShouldSkip = " + fShouldSkip);
2151                 //xxx: this is not correct, we are returning the last element
2152                 //this wont make any difference since flag has been set to 'false'
2153                 return fQName[--fCount];
2154             }
2155             if(DEBUG_SKIP_ALGORITHM){
2156                 System.out.println("fCount = " + fCount);
2157             }
2158             return fQName[fCount++];
2159 
2160         }
2161 
2162         /** Note that this function is considerably different than nextElement()
2163          * This function just returns the previously stored elements
2164          */
2165         public QName getNext(){
2166             //when position reaches number of elements in the list..
2167             //set the position back to mark,  making it a circular linked list.
2168             if(fPosition == fCount){
2169                 fPosition = fMark;
2170             }
2171             return fQName[fPosition++];
2172         }
2173 
2174         /** returns the current depth
2175          */
2176         public int popElement(){
2177             return fDepth--;
2178         }
2179 
2180 
2181         /** Clears the stack without throwing away existing QName objects. */
2182         public void clear() {
2183             fLastDepth = 0;
2184             fDepth = 0;
2185             fCount = 0 ;
2186             fPosition = fMark = 1;
2187         } // clear()
2188 
2189     } // class ElementStack
2190 
2191     /**
2192      * Element stack. This stack operates without synchronization, error
2193      * checking, and it re-uses objects instead of throwing popped items
2194      * away.
2195      *
2196      * @author Andy Clark, IBM
2197      */
2198     protected class ElementStack {
2199 
2200         //
2201         // Data
2202         //
2203 
2204         /** The stack data. */
2205         protected QName[] fElements;
2206         protected int []  fInt = new int[20];
2207 
2208 
2209         //Element depth
2210         protected int fDepth;
2211         //total number of elements
2212         protected int fCount;
2213         //current position
2214         protected int fPosition;
2215         //Mark refers to the position
2216         protected int fMark;
2217 
2218         protected int fLastDepth ;
2219 
2220         //
2221         // Constructors
2222         //
2223 
2224         /** Default constructor. */
2225         public ElementStack() {
2226             fElements = new QName[20];
2227             for (int i = 0; i < fElements.length; i++) {
2228                 fElements[i] = new QName();
2229             }
2230         } // <init>()
2231 
2232         //
2233         // Public methods
2234         //
2235 
2236         /**
2237          * Pushes an element on the stack.
2238          * <p>
2239          * <strong>Note:</strong> The QName values are copied into the
2240          * stack. In other words, the caller does <em>not</em> orphan
2241          * the element to the stack. Also, the QName object returned
2242          * is <em>not</em> orphaned to the caller. It should be
2243          * considered read-only.
2244          *
2245          * @param element The element to push onto the stack.
2246          *
2247          * @return Returns the actual QName object that stores the
2248          */
2249         //XXX: THIS FUNCTION IS NOT USED
2250         public QName pushElement(QName element) {
2251             if (fDepth == fElements.length) {
2252                 QName[] array = new QName[fElements.length * 2];
2253                 System.arraycopy(fElements, 0, array, 0, fDepth);
2254                 fElements = array;
2255                 for (int i = fDepth; i < fElements.length; i++) {
2256                     fElements[i] = new QName();
2257                 }
2258             }
2259             fElements[fDepth].setValues(element);
2260             return fElements[fDepth++];
2261         } // pushElement(QName):QName
2262 
2263 
2264         /** Note that this function is considerably different than nextElement()
2265          * This function just returns the previously stored elements
2266          */
2267         public QName getNext(){
2268             //when position reaches number of elements in the list..
2269             //set the position back to mark,  making it a circular linked list.
2270             if(fPosition == fCount){
2271                 fPosition = fMark;
2272             }
2273             //store the position of last opened tag at particular depth
2274             //fInt[++fDepth] = fPosition;
2275             if(DEBUG_SKIP_ALGORITHM){
2276                 System.out.println("Element at fPosition = " + fPosition + " is " + fElements[fPosition].rawname);
2277             }
2278             //return fElements[fPosition++];
2279             return fElements[fPosition];
2280         }
2281 
2282         /** This function should be called only when element was skipped sucessfully.
2283          * 1. Increase the depth - because element was sucessfully skipped.
2284          *2. Store the position of the element token in array  "last opened tag" at depth.
2285          *3. increase the position counter so as to point to the next element in the array
2286          */
2287         public void push(){
2288 
2289             fInt[++fDepth] = fPosition++;
2290         }
2291 
2292         /** Check if the element scanned during the start element
2293          *matches the stored element.
2294          *
2295          *@return true if the match suceeds.
2296          */
2297         public boolean matchElement(QName element) {
2298             //last depth is the depth when last elemnt was pushed
2299             //if last depth is greater than current depth
2300             //if(DEBUG_SKIP_ALGORITHM){
2301             //   System.out.println("Check if the element " + element.rawname + " matches");
2302             //  System.out.println("fLastDepth = " + fLastDepth);
2303             // System.out.println("fDepth = " + fDepth);
2304             //}
2305             boolean match = false;
2306             if(fLastDepth > fDepth && fDepth <= 3){
2307                 if(DEBUG_SKIP_ALGORITHM){
2308                     System.out.println("----------ENTERED THE LOOP WHERE WE CHECK FOR MATCHING OF ELMENT-----");
2309                     System.out.println("Depth = " + fDepth + " Checking if INCOMING element " + element.rawname + " match STORED ELEMENT " + fElements[fDepth - 1].rawname);
2310                 }
2311                 if(element.rawname == fElements[fDepth - 1].rawname){
2312                     fAdd = false;
2313                     //mark this position
2314                     //decrease the depth by 1 as arrays are 0 based
2315                     fMark = fDepth - 1;
2316                     //we found the match
2317                     fPosition = fMark;
2318                     match = true;
2319                     //Once we get match decrease the count -- this was increased by nextElement()
2320                     --fCount;
2321                     if(DEBUG_SKIP_ALGORITHM){
2322                         System.out.println("NOW ELEMENT SHOULD NOT BE ADDED, fAdd is set to false");
2323                         System.out.println("fMark = " + fMark);
2324                         System.out.println("fPosition = " + fPosition);
2325                         System.out.println("fDepth = " + fDepth);
2326                         System.out.println("fCount = " + fCount);
2327                         System.out.println("---------MATCH SUCEEDED-----------------");
2328                         System.out.println("");
2329                     }
2330                 }else{
2331                     fAdd = true;
2332                     if(DEBUG_SKIP_ALGORITHM)System.out.println("fAdd is " + fAdd);
2333                 }
2334             }
2335             //store the position for the current depth
2336             //when we are adding the elements, when skipping
2337             //starts even then this should be tracked ie. when
2338             //calling getNext()
2339             if(match){
2340                 //from next element skipping will start, add 1
2341                 fInt[fDepth] = fPosition++;
2342             } else{
2343                 if(DEBUG_SKIP_ALGORITHM){
2344                     System.out.println("At depth = " + fDepth + "array position is = " + (fCount - 1));
2345                 }
2346                 //sicne fInt[fDepth] contains pointer to the element array which are 0 based.
2347                 fInt[fDepth] = fCount - 1;
2348             }
2349 
2350             //if number of elements becomes equal to the length of array -- stop the skipping
2351             //xxx: should we do "fCount == fInt.length"
2352             if (fCount == fElements.length) {
2353                 fSkip = false;
2354                 fAdd = false;
2355                 //reposition the stack -- it seems to be too complex document and there is no symmerty in structure
2356                 reposition();
2357                 if(DEBUG_SKIP_ALGORITHM){
2358                     System.out.println("ALL THE ELMENTS IN ARRAY HAVE BEEN FILLED");
2359                     System.out.println("REPOSITIONING THE STACK");
2360                     System.out.println("-----------SKIPPING STOPPED----------");
2361                     System.out.println("");
2362                 }
2363                 return false;
2364             }
2365             if(DEBUG_SKIP_ALGORITHM){
2366                 if(match){
2367                     System.out.println("Storing fPosition = " + fInt[fDepth] + " at fDepth = " + fDepth);
2368                 }else{
2369                     System.out.println("Storing fCount = " + fInt[fDepth] + " at fDepth = " + fDepth);
2370                 }
2371             }
2372             //store the last depth
2373             fLastDepth = fDepth;
2374             return match;
2375         } // matchElement(QName):QName
2376 
2377 
2378         /**
2379          * Returns the next element on the stack.
2380          *
2381          * @return Returns the actual QName object. Callee should
2382          * use this object to store the details of next element encountered.
2383          */
2384         public QName nextElement() {
2385             if(fSkip){
2386                 fDepth++;
2387                 //boundary checks are done in matchElement()
2388                 return fElements[fCount++];
2389             } else if (fDepth == fElements.length) {
2390                 QName[] array = new QName[fElements.length * 2];
2391                 System.arraycopy(fElements, 0, array, 0, fDepth);
2392                 fElements = array;
2393                 for (int i = fDepth; i < fElements.length; i++) {
2394                     fElements[i] = new QName();
2395                 }
2396             }
2397 
2398             return fElements[fDepth++];
2399 
2400         } // pushElement(QName):QName
2401 
2402 
2403         /**
2404          * Pops an element off of the stack by setting the values of
2405          * the specified QName.
2406          * <p>
2407          * <strong>Note:</strong> The object returned is <em>not</em>
2408          * orphaned to the caller. Therefore, the caller should consider
2409          * the object to be read-only.
2410          */
2411         public QName popElement() {
2412             //return the same object that was pushed -- this would avoid
2413             //setting the values for every end element.
2414             //STRONG: this object is read only -- this object reference shouldn't be stored.
2415             if(fSkip || fAdd ){
2416                 if(DEBUG_SKIP_ALGORITHM){
2417                     System.out.println("POPPING Element, at position " + fInt[fDepth] + " element at that count is = " + fElements[fInt[fDepth]].rawname);
2418                     System.out.println("");
2419                 }
2420                 return fElements[fInt[fDepth--]];
2421             } else{
2422                 if(DEBUG_SKIP_ALGORITHM){
2423                     System.out.println("Retrieveing element at depth = " + fDepth + " is " + fElements[fDepth].rawname );
2424                 }
2425                 return fElements[--fDepth] ;
2426             }
2427             //element.setValues(fElements[--fDepth]);
2428         } // popElement(QName)
2429 
2430         /** Reposition the stack. fInt [] contains all the opened tags at particular depth.
2431          * Transfer all the opened tags starting from depth '2' to the current depth and reposition them
2432          *as per the depth.
2433          */
2434         public void reposition(){
2435             for( int i = 2 ; i <= fDepth ; i++){
2436                 fElements[i-1] = fElements[fInt[i]];
2437             }
2438             if(DEBUG_SKIP_ALGORITHM){
2439                 for( int i = 0 ; i < fDepth ; i++){
2440                     System.out.println("fElements[" + i + "]" + " = " + fElements[i].rawname);
2441                 }
2442             }
2443         }
2444 
2445         /** Clears the stack without throwing away existing QName objects. */
2446         public void clear() {
2447             fDepth = 0;
2448             fLastDepth = 0;
2449             fCount = 0 ;
2450             fPosition = fMark = 1;
2451 
2452         } // clear()
2453 
2454         /**
2455          * This function is as a result of optimization done for endElement --
2456          * we dont need to set the value for every end element encouterd.
2457          * For Well formedness checks we can have the same QName object that was pushed.
2458          * the values will be set only if application need to know about the endElement
2459          * -- neeraj.bajaj@sun.com
2460          */
2461 
2462         public QName getLastPoppedElement(){
2463             return fElements[fDepth];
2464         }
2465     } // class ElementStack
2466 
2467     /**
2468      * Drives the parser to the next state/event on the input. Parser is guaranteed
2469      * to stop at the next state/event.
2470      *
2471      * Internally XML document is divided into several states. Each state represents
2472      * a sections of XML document. When this functions returns normally, it has read
2473      * the section of XML document and returns the state corresponding to section of
2474      * document which has been read. For optimizations, a particular driver
2475      * can read ahead of the section of document (state returned) just read and
2476      * can maintain a different internal state.
2477      *
2478      *
2479      * @author Neeraj Bajaj, Sun Microsystems
2480      */
2481     protected interface Driver {
2482 
2483 
2484         /**
2485          * Drives the parser to the next state/event on the input. Parser is guaranteed
2486          * to stop at the next state/event.
2487          *
2488          * Internally XML document is divided into several states. Each state represents
2489          * a sections of XML document. When this functions returns normally, it has read
2490          * the section of XML document and returns the state corresponding to section of
2491          * document which has been read. For optimizations, a particular driver
2492          * can read ahead of the section of document (state returned) just read and
2493          * can maintain a different internal state.
2494          *
2495          * @return state representing the section of document just read.
2496          *
2497          * @throws IOException  Thrown on i/o error.
2498          * @throws XNIException Thrown on parse error.
2499          */
2500 
2501         public int next() throws IOException, XNIException;
2502 
2503     } // interface Driver
2504 
2505     /**
2506      * Driver to handle content scanning. This driver is capable of reading
2507      * the fragment of XML document. When it has finished reading fragment
2508      * of XML documents, it can pass the job of reading to another driver.
2509      *
2510      * This class has been modified as per the new design which is more suited to
2511      * efficiently build pull parser. Lot of performance improvements have been done and
2512      * the code has been added to support stax functionality/features.
2513      *
2514      * @author Neeraj Bajaj, Sun Microsystems
2515      *
2516      *
2517      * @author Andy Clark, IBM
2518      * @author Eric Ye, IBM
2519      */
2520     protected class FragmentContentDriver
2521             implements Driver {
2522 
2523         //
2524         // Driver methods
2525         //
2526         private boolean fContinueDispatching = true;
2527         private boolean fScanningForMarkup = true;
2528 
2529         /**
2530          *  decides the appropriate state of the parser
2531          */
2532         private void startOfMarkup() throws IOException {
2533             fMarkupDepth++;
2534             final int ch = fEntityScanner.peekChar();
2535 
2536             switch(ch){
2537                 case '?' :{
2538                     setScannerState(SCANNER_STATE_PI);
2539                     fEntityScanner.skipChar(ch);
2540                     break;
2541                 }
2542                 case '!' :{
2543                     fEntityScanner.skipChar(ch);
2544                     if (fEntityScanner.skipChar('-')) {
2545                         if (!fEntityScanner.skipChar('-')) {
2546                             reportFatalError("InvalidCommentStart",
2547                                     null);
2548                         }
2549                         setScannerState(SCANNER_STATE_COMMENT);
2550                     } else if (fEntityScanner.skipString(cdata)) {
2551                         setScannerState(SCANNER_STATE_CDATA );
2552                     } else if (!scanForDoctypeHook()) {
2553                         reportFatalError("MarkupNotRecognizedInContent",
2554                                 null);
2555                     }
2556                     break;
2557                 }
2558                 case '/' :{
2559                     setScannerState(SCANNER_STATE_END_ELEMENT_TAG);
2560                     fEntityScanner.skipChar(ch);
2561                     break;
2562                 }
2563                 default :{
2564                     if (isValidNameStartChar(ch)) {
2565                         setScannerState(SCANNER_STATE_START_ELEMENT_TAG);
2566                     } else {
2567                         reportFatalError("MarkupNotRecognizedInContent",
2568                                 null);
2569                     }
2570                 }
2571             }
2572 
2573         }//startOfMarkup
2574 
2575         private void startOfContent() throws IOException {
2576             if (fEntityScanner.skipChar('<')) {
2577                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
2578             } else if (fEntityScanner.skipChar('&')) {
2579                 setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
2580             } else {
2581                 //element content is there..
2582                 setScannerState(SCANNER_STATE_CHARACTER_DATA);
2583             }
2584         }//startOfContent
2585 
2586 
2587         /**
2588          *
2589          * SCANNER_STATE_CONTENT and SCANNER_STATE_START_OF_MARKUP are two super states of the parser.
2590          * At any point of time when in doubt over the current state of the parser, the state should be
2591          * set to SCANNER_STATE_CONTENT. Parser will automatically revive itself and will set state of
2592          * the parser to one of its sub state.
2593          * sub states are defined in the parser on the basis of different XML component like
2594          * SCANNER_STATE_ENTITY_REFERENCE , SCANNER_STATE_START_ELEMENT, SCANNER_STATE_CDATA etc..
2595          * These sub states help the parser to have fine control over the parsing. These are the
2596          * different milepost, parser stops at each sub state (milepost). Based on this state it is
2597          * decided if paresr needs to stop at next milepost ??
2598          *
2599          */
2600         public void decideSubState() throws IOException {
2601             while( fScannerState == SCANNER_STATE_CONTENT || fScannerState == SCANNER_STATE_START_OF_MARKUP){
2602 
2603                 switch (fScannerState) {
2604 
2605                     case SCANNER_STATE_CONTENT: {
2606                         startOfContent() ;
2607                         break;
2608                     }
2609 
2610                     case SCANNER_STATE_START_OF_MARKUP: {
2611                         startOfMarkup() ;
2612                         break;
2613                     }
2614                 }
2615             }
2616         }//decideSubState
2617 
2618         /**
2619          * Drives the parser to the next state/event on the input. Parser is guaranteed
2620          * to stop at the next state/event. Internally XML document
2621          * is divided into several states. Each state represents a sections of XML
2622          * document. When this functions returns normally, it has read the section
2623          * of XML document and returns the state corresponding to section of
2624          * document which has been read. For optimizations, a particular driver
2625          * can read ahead of the section of document (state returned) just read and
2626          * can maintain a different internal state.
2627          *
2628          * State returned corresponds to Stax states.
2629          *
2630          * @return state representing the section of document just read.
2631          *
2632          * @throws IOException  Thrown on i/o error.
2633          * @throws XNIException Thrown on parse error.
2634          */
2635 
2636         public int next() throws IOException, XNIException {
2637             while (true) {
2638             try {
2639                 if(DEBUG_NEXT){
2640                     System.out.println("NOW IN FragmentContentDriver");
2641                     System.out.println("Entering the FragmentContentDriver with = " + getScannerStateName(fScannerState));
2642                 }
2643 
2644                 //decide the actual sub state of the scanner.For more information refer to the javadoc of
2645                 //decideSubState.
2646 
2647                 switch (fScannerState) {
2648                     case SCANNER_STATE_CONTENT: {
2649                         final int ch = fEntityScanner.peekChar();
2650                         if (ch == '<') {
2651                             fEntityScanner.scanChar();
2652                             setScannerState(SCANNER_STATE_START_OF_MARKUP);
2653                         } else if (ch == '&') {
2654                             fEntityScanner.scanChar();
2655                             setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
2656                             break;
2657                         } else {
2658                             //element content is there..
2659                             setScannerState(SCANNER_STATE_CHARACTER_DATA);
2660                             break;
2661                         }
2662                     }
2663 
2664                     case SCANNER_STATE_START_OF_MARKUP: {
2665                         startOfMarkup();
2666                         break;
2667                     }//case: SCANNER_STATE_START_OF_MARKUP
2668 
2669                 }//end of switch
2670                 //decideSubState() ;
2671 
2672                 //do some special handling if isCoalesce is set to true.
2673                 if(fIsCoalesce){
2674                     fUsebuffer = true ;
2675                     //if the last section was character data
2676                     if(fLastSectionWasCharacterData){
2677 
2678                         //if we dont encounter any CDATA or ENITY REFERENCE and current state is also not SCANNER_STATE_CHARACTER_DATA
2679                         //return the last scanned charactrer data.
2680                         if((fScannerState != SCANNER_STATE_CDATA) && (fScannerState != SCANNER_STATE_REFERENCE)
2681                         && (fScannerState != SCANNER_STATE_CHARACTER_DATA)){
2682                             fLastSectionWasCharacterData = false;
2683                             return XMLEvent.CHARACTERS;
2684                         }
2685                     }//if last section was CDATA or ENTITY REFERENCE
2686                     //xxx: there might be another entity reference or CDATA after this
2687                     //<foo>blah blah &amp;&lt;<![CDATA[[aa]]>blah blah</foo>
2688                     else if((fLastSectionWasCData || fLastSectionWasEntityReference)){
2689                         //and current state is not SCANNER_STATE_CHARACTER_DATA
2690                         //or SCANNER_STATE_CDATA or SCANNER_STATE_REFERENCE
2691                         //this means there is nothing more to be coalesced.
2692                         //return the CHARACTERS event.
2693                         if((fScannerState != SCANNER_STATE_CDATA) && (fScannerState != SCANNER_STATE_REFERENCE)
2694                         && (fScannerState != SCANNER_STATE_CHARACTER_DATA)){
2695 
2696                             fLastSectionWasCData = false;
2697                             fLastSectionWasEntityReference = false;
2698                             return XMLEvent.CHARACTERS;
2699                         }
2700                     }
2701                 }
2702 
2703 
2704                 if(DEBUG_NEXT){
2705                     System.out.println("Actual scanner state set by decideSubState is = " + getScannerStateName(fScannerState));
2706                 }
2707 
2708                 switch(fScannerState){
2709 
2710                     case XMLEvent.START_DOCUMENT :
2711                         return XMLEvent.START_DOCUMENT;
2712 
2713                     case SCANNER_STATE_START_ELEMENT_TAG :{
2714 
2715                         //xxx this function returns true when element is empty.. can be linked to end element event.
2716                         //returns true if the element is empty
2717                         fEmptyElement = scanStartElement() ;
2718                         //if the element is empty the next event is "end element"
2719                         if(fEmptyElement){
2720                             setScannerState(SCANNER_STATE_END_ELEMENT_TAG);
2721                         }else{
2722                             //set the next possible state
2723                             setScannerState(SCANNER_STATE_CONTENT);
2724                         }
2725                         return XMLEvent.START_ELEMENT ;
2726                     }
2727 
2728                     case SCANNER_STATE_CHARACTER_DATA: {
2729                         if(DEBUG_COALESCE){
2730                             System.out.println("fLastSectionWasCData = " + fLastSectionWasCData);
2731                             System.out.println("fIsCoalesce = " + fIsCoalesce);
2732                         }
2733                         //if last section was either entity reference or cdata or character data we should be using buffer
2734                         fUsebuffer = fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData ;
2735 
2736                         //When coalesce is set to true and last state was REFERENCE or CDATA or CHARACTER_DATA, buffer should not be cleared.
2737                         if( fIsCoalesce && (fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData) ){
2738                             fLastSectionWasEntityReference = false;
2739                             fLastSectionWasCData = false;
2740                             fLastSectionWasCharacterData = true ;
2741                             fUsebuffer = true;
2742                         }else{
2743                             //clear the buffer
2744                             fContentBuffer.clear();
2745                         }
2746 
2747                         //set the fTempString length to 0 before passing it on to scanContent
2748                         //scanContent sets the correct co-ordinates as per the content read
2749                         fTempString.length = 0;
2750                         int c = fEntityScanner.scanContent(fTempString);
2751                         if(DEBUG){
2752                             System.out.println("fTempString = " + fTempString);
2753                         }
2754                         if(fEntityScanner.skipChar('<')){
2755                             //check if we have reached end of element
2756                             if(fEntityScanner.skipChar('/')){
2757                                 //increase the mark up depth
2758                                 fMarkupDepth++;
2759                                 fLastSectionWasCharacterData = false;
2760                                 setScannerState(SCANNER_STATE_END_ELEMENT_TAG);
2761                                 //check if its start of new element
2762                             }else if(XMLChar.isNameStart(fEntityScanner.peekChar())){
2763                                 fMarkupDepth++;
2764                                 fLastSectionWasCharacterData = false;
2765                                 setScannerState(SCANNER_STATE_START_ELEMENT_TAG);
2766                             }else{
2767                                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
2768                                 //there can be cdata ahead if coalesce is true we should call again
2769                                 if(fIsCoalesce){
2770                                     fUsebuffer = true;
2771                                     fLastSectionWasCharacterData = true;
2772                                     fContentBuffer.append(fTempString);
2773                                     fTempString.length = 0;
2774                                     continue;
2775                                 }
2776                             }
2777                             //in case last section was either entity reference or cdata or character data -- we should be using buffer
2778                             if(fUsebuffer){
2779                                 fContentBuffer.append(fTempString);
2780                                 fTempString.length = 0;
2781                             }
2782                             if(DEBUG){
2783                                 System.out.println("NOT USING THE BUFFER, STRING = " + fTempString.toString());
2784                             }
2785                             if(dtdGrammarUtil!= null && dtdGrammarUtil.isIgnorableWhiteSpace(fContentBuffer)){
2786                                 if(DEBUG)System.out.println("Return SPACE EVENT");
2787                                 return XMLEvent.SPACE;
2788                             }else
2789                                 return XMLEvent.CHARACTERS;
2790 
2791                         } else{
2792                             fUsebuffer = true ;
2793                             if(DEBUG){
2794                                 System.out.println("fContentBuffer = " + fContentBuffer);
2795                                 System.out.println("fTempString = " + fTempString);
2796                             }
2797                             fContentBuffer.append(fTempString);
2798                             fTempString.length = 0;
2799                         }
2800                         if (c == '\r') {
2801                             if(DEBUG){
2802                                 System.out.println("'\r' character found");
2803                             }
2804                             // happens when there is the character reference &#13;
2805                             //xxx: We know the next chracter.. we should just skip it and add ']' directlry
2806                             fEntityScanner.scanChar();
2807                             fUsebuffer = true;
2808                             fContentBuffer.append((char)c);
2809                             c = -1 ;
2810                         } else if (c == ']') {
2811                             //fStringBuffer.clear();
2812                             //xxx: We know the next chracter.. we should just skip it and add ']' directlry
2813                             fUsebuffer = true;
2814                             fContentBuffer.append((char)fEntityScanner.scanChar());
2815                             // remember where we are in case we get an endEntity before we
2816                             // could flush the buffer out - this happens when we're parsing an
2817                             // entity which ends with a ]
2818                             fInScanContent = true;
2819 
2820                             // We work on a single character basis to handle cases such as:
2821                             // ']]]>' which we might otherwise miss.
2822                             //
2823                             if (fEntityScanner.skipChar(']')) {
2824                                 fContentBuffer.append(']');
2825                                 while (fEntityScanner.skipChar(']')) {
2826                                     fContentBuffer.append(']');
2827                                 }
2828                                 if (fEntityScanner.skipChar('>')) {
2829                                     reportFatalError("CDEndInContent", null);
2830                                 }
2831                             }
2832                             c = -1 ;
2833                             fInScanContent = false;
2834                         }
2835 
2836                         do{
2837                             //xxx: we should be using only one buffer..
2838                             // we need not to grow the buffer only when isCoalesce() is not true;
2839 
2840                             if (c == '<') {
2841                                 fEntityScanner.scanChar();
2842                                 setScannerState(SCANNER_STATE_START_OF_MARKUP);
2843                                 break;
2844                             }//xxx what should be the behavior if entity reference is present in the content ?
2845                             else if (c == '&') {
2846                                 fEntityScanner.scanChar();
2847                                 setScannerState(SCANNER_STATE_REFERENCE);
2848                                 break;
2849                             }///xxx since this part is also characters, it should be merged...
2850                             else if (c != -1 && isInvalidLiteral(c)) {
2851                                 if (XMLChar.isHighSurrogate(c)) {
2852                                     // special case: surrogates
2853                                     scanSurrogates(fContentBuffer) ;
2854                                     setScannerState(SCANNER_STATE_CONTENT);
2855                                 } else {
2856                                     reportFatalError("InvalidCharInContent",
2857                                             new Object[] {
2858                                         Integer.toString(c, 16)});
2859                                         fEntityScanner.scanChar();
2860                                 }
2861                                 break;
2862                             }
2863                             //xxx: scanContent also gives character callback.
2864                             c = scanContent(fContentBuffer) ;
2865                             //we should not be iterating again if fIsCoalesce is not set to true
2866 
2867                             if(!fIsCoalesce){
2868                                 setScannerState(SCANNER_STATE_CONTENT);
2869                                 break;
2870                             }
2871 
2872                         }while(true);
2873 
2874                         //if (fDocumentHandler != null) {
2875                         //  fDocumentHandler.characters(fContentBuffer, null);
2876                         //}
2877                         if(DEBUG)System.out.println("USING THE BUFFER, STRING START=" + fContentBuffer.toString() +"=END");
2878                         //if fIsCoalesce is true there might be more data so call fDriver.next()
2879                         if(fIsCoalesce){
2880                             fLastSectionWasCharacterData = true ;
2881                             continue;
2882                         }else{
2883                             if(dtdGrammarUtil!= null && dtdGrammarUtil.isIgnorableWhiteSpace(fContentBuffer)){
2884                                 if(DEBUG)System.out.println("Return SPACE EVENT");
2885                                 return XMLEvent.SPACE;
2886                             } else
2887                                 return XMLEvent.CHARACTERS ;
2888                         }
2889                     }
2890 
2891                     case SCANNER_STATE_END_ELEMENT_TAG :{
2892                         if(fEmptyElement){
2893                             //set it back to false.
2894                             fEmptyElement = false;
2895                             setScannerState(SCANNER_STATE_CONTENT);
2896                             //check the case when there is comment after single element document
2897                             //<foo/> and some comment after this
2898                             return (fMarkupDepth == 0 && elementDepthIsZeroHook() ) ? XMLEvent.END_ELEMENT : XMLEvent.END_ELEMENT ;
2899 
2900                         } else if(scanEndElement() == 0) {
2901                             //It is last element of the document
2902                             if (elementDepthIsZeroHook()) {
2903                                 //if element depth is zero , it indicates the end of the document
2904                                 //the state shouldn't be set, because it is set by elementDepthIsZeroHook() function
2905                                 //xxx understand this point once again..
2906                                 return XMLEvent.END_ELEMENT ;
2907                             }
2908 
2909                         }
2910                         setScannerState(SCANNER_STATE_CONTENT);
2911                         return XMLEvent.END_ELEMENT ;
2912                     }
2913 
2914                     case SCANNER_STATE_COMMENT: { //SCANNER_STATE_COMMENT:
2915                         scanComment();
2916                         setScannerState(SCANNER_STATE_CONTENT);
2917                         return XMLEvent.COMMENT;
2918                         //break;
2919                     }
2920                     case SCANNER_STATE_PI:{ //SCANNER_STATE_PI: {
2921                         //clear the buffer first
2922                         fContentBuffer.clear() ;
2923                         //xxx: which buffer should be passed. Ideally we shouldn't have
2924                         //more than two buffers --
2925                         //xxx: where should we add the switch for buffering.
2926                         scanPI(fContentBuffer);
2927                         setScannerState(SCANNER_STATE_CONTENT);
2928                         return XMLEvent.PROCESSING_INSTRUCTION;
2929                         //break;
2930                     }
2931                     case SCANNER_STATE_CDATA :{ //SCANNER_STATE_CDATA: {
2932                         //xxx: What if CDATA is the first event
2933                         //<foo><![CDATA[hello<><>]]>append</foo>
2934 
2935                         //we should not clear the buffer only when the last state was either SCANNER_STATE_REFERENCE or
2936                         //SCANNER_STATE_CHARACTER_DATA or SCANNER_STATE_REFERENCE
2937                         if(fIsCoalesce && ( fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData)){
2938                             fLastSectionWasCData = true ;
2939                             fLastSectionWasEntityReference = false;
2940                             fLastSectionWasCharacterData = false;
2941                         }//if we dont need to coalesce clear the buffer
2942                         else{
2943                             fContentBuffer.clear();
2944                         }
2945                         fUsebuffer = true;
2946                         //CDATA section is completely read in all the case.
2947                         scanCDATASection(fContentBuffer , true);
2948                         setScannerState(SCANNER_STATE_CONTENT);
2949                         //1. if fIsCoalesce is set to true we set the variable fLastSectionWasCData to true
2950                         //and just call fDispatche.next(). Since we have set the scanner state to
2951                         //SCANNER_STATE_CONTENT (super state) parser will automatically recover and
2952                         //behave appropriately. When isCoalesce is set to true we dont need to reportCDATA event
2953                         //2. Check if application has set for reporting CDATA event
2954                         //3. if the application has neither set the fIsCoalesce to true nor fReportCdataEvent
2955                         //return the cdata event as characters.
2956                         if(fIsCoalesce){
2957                             fLastSectionWasCData = true ;
2958                             //there might be more data to coalesce.
2959                             continue;
2960                         }else if(fReportCdataEvent){
2961                             return XMLEvent.CDATA;
2962                         } else{
2963                             return XMLEvent.CHARACTERS;
2964                         }
2965                     }
2966 
2967                     case SCANNER_STATE_REFERENCE :{
2968                         fMarkupDepth++;
2969                         foundBuiltInRefs = false;
2970 
2971                         //we should not clear the buffer only when the last state was either CDATA or
2972                         //SCANNER_STATE_CHARACTER_DATA or SCANNER_STATE_REFERENCE
2973                         if(fIsCoalesce && ( fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData)){
2974                             //fLastSectionWasEntityReference or fLastSectionWasCData are only
2975                             //used when fIsCoalesce is set to true.
2976                             fLastSectionWasEntityReference = true ;
2977                             fLastSectionWasCData = false;
2978                             fLastSectionWasCharacterData = false;
2979                         }//if we dont need to coalesce clear the buffer
2980                         else{
2981                             fContentBuffer.clear();
2982                         }
2983                         fUsebuffer = true ;
2984                         //take care of character reference
2985                         if (fEntityScanner.skipChar('#')) {
2986                             scanCharReferenceValue(fContentBuffer, null);
2987                             fMarkupDepth--;
2988                             if(!fIsCoalesce){
2989                                 setScannerState(SCANNER_STATE_CONTENT);
2990                                 return XMLEvent.CHARACTERS;
2991                             }
2992                         } else {
2993                             // this function also starts new entity
2994                             scanEntityReference(fContentBuffer);
2995                             //if there was built-in entity reference & coalesce is not true
2996                             //return CHARACTERS
2997                             if(fScannerState == SCANNER_STATE_BUILT_IN_REFS && !fIsCoalesce){
2998                                 setScannerState(SCANNER_STATE_CONTENT);
2999                                 return XMLEvent.CHARACTERS;
3000                             }
3001 
3002                             //if there was a text declaration, call next() it will be taken care.
3003                             if(fScannerState == SCANNER_STATE_TEXT_DECL){
3004                                 fLastSectionWasEntityReference = true ;
3005                                 continue;
3006                             }
3007 
3008                             if(fScannerState == SCANNER_STATE_REFERENCE){
3009                                 setScannerState(SCANNER_STATE_CONTENT);
3010                                 if (fReplaceEntityReferences && fEntityStore.isDeclaredEntity(fCurrentEntityName)) {
3011                                     // Skip the entity reference, we don't care
3012                                     continue;
3013                                 }
3014                                 return XMLEvent.ENTITY_REFERENCE;
3015                             }
3016                         }
3017                         //Wether it was character reference, entity reference or built-in entity
3018                         //set the next possible state to SCANNER_STATE_CONTENT
3019                         setScannerState(SCANNER_STATE_CONTENT);
3020                         fLastSectionWasEntityReference = true ;
3021                         continue;
3022                     }
3023 
3024                     case SCANNER_STATE_TEXT_DECL: {
3025                         // scan text decl
3026                         if (fEntityScanner.skipString("<?xml")) {
3027                             fMarkupDepth++;
3028                             // NOTE: special case where entity starts with a PI
3029                             //       whose name starts with "xml" (e.g. "xmlfoo")
3030                             if (isValidNameChar(fEntityScanner.peekChar())) {
3031                                 fStringBuffer.clear();
3032                                 fStringBuffer.append("xml");
3033 
3034                                 if (fNamespaces) {
3035                                     while (isValidNCName(fEntityScanner.peekChar())) {
3036                                         fStringBuffer.append((char)fEntityScanner.scanChar());
3037                                     }
3038                                 } else {
3039                                     while (isValidNameChar(fEntityScanner.peekChar())) {
3040                                         fStringBuffer.append((char)fEntityScanner.scanChar());
3041                                     }
3042                                 }
3043                                 String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
3044                                 fContentBuffer.clear();
3045                                 scanPIData(target, fContentBuffer);
3046                             }
3047 
3048                             // standard text declaration
3049                             else {
3050                                 //xxx: this function gives callback
3051                                 scanXMLDeclOrTextDecl(true);
3052                             }
3053                         }
3054                         // now that we've straightened out the readers, we can read in chunks:
3055                         fEntityManager.fCurrentEntity.mayReadChunks = true;
3056                         setScannerState(SCANNER_STATE_CONTENT);
3057                         //xxx: we don't return any state, so how do we get to know about TEXT declarations.
3058                         //it seems we have to careful when to allow function issue a callback
3059                         //and when to allow adapter issue a callback.
3060                         continue;
3061                     }
3062 
3063 
3064                     case SCANNER_STATE_ROOT_ELEMENT: {
3065                         if (scanRootElementHook()) {
3066                             fEmptyElement = true;
3067                             //rest would be taken care by fTrailingMiscDriver set by scanRootElementHook
3068                             return XMLEvent.START_ELEMENT;
3069                         }
3070                         setScannerState(SCANNER_STATE_CONTENT);
3071                         return XMLEvent.START_ELEMENT ;
3072                     }
3073                     case SCANNER_STATE_CHAR_REFERENCE : {
3074                         fContentBuffer.clear();
3075                         scanCharReferenceValue(fContentBuffer, null);
3076                         fMarkupDepth--;
3077                         setScannerState(SCANNER_STATE_CONTENT);
3078                         return XMLEvent.CHARACTERS;
3079                     }
3080                     default:
3081                         throw new XNIException("Scanner State " + fScannerState + " not Recognized ");
3082 
3083                 }//switch
3084             }
3085             // premature end of file
3086             catch (EOFException e) {
3087                 endOfFileHook(e);
3088                 return -1;
3089             }
3090             } //while loop
3091         }//next
3092 
3093 
3094         //
3095         // Protected methods
3096         //
3097 
3098         // hooks
3099 
3100         // NOTE: These hook methods are added so that the full document
3101         //       scanner can share the majority of code with this class.
3102 
3103         /**
3104          * Scan for DOCTYPE hook. This method is a hook for subclasses
3105          * to add code to handle scanning for a the "DOCTYPE" string
3106          * after the string "<!" has been scanned.
3107          *
3108          * @return True if the "DOCTYPE" was scanned; false if "DOCTYPE"
3109          *          was not scanned.
3110          */
3111         protected boolean scanForDoctypeHook()
3112         throws IOException, XNIException {
3113             return false;
3114         } // scanForDoctypeHook():boolean
3115 
3116         /**
3117          * Element depth iz zero. This methos is a hook for subclasses
3118          * to add code to handle when the element depth hits zero. When
3119          * scanning a document fragment, an element depth of zero is
3120          * normal. However, when scanning a full XML document, the
3121          * scanner must handle the trailing miscellanous section of
3122          * the document after the end of the document's root element.
3123          *
3124          * @return True if the caller should stop and return true which
3125          *          allows the scanner to switch to a new scanning
3126          *          driver. A return value of false indicates that
3127          *          the content driver should continue as normal.
3128          */
3129         protected boolean elementDepthIsZeroHook()
3130         throws IOException, XNIException {
3131             return false;
3132         } // elementDepthIsZeroHook():boolean
3133 
3134         /**
3135          * Scan for root element hook. This method is a hook for
3136          * subclasses to add code that handles scanning for the root
3137          * element. When scanning a document fragment, there is no
3138          * "root" element. However, when scanning a full XML document,
3139          * the scanner must handle the root element specially.
3140          *
3141          * @return True if the caller should stop and return true which
3142          *          allows the scanner to switch to a new scanning
3143          *          driver. A return value of false indicates that
3144          *          the content driver should continue as normal.
3145          */
3146         protected boolean scanRootElementHook()
3147         throws IOException, XNIException {
3148             return false;
3149         } // scanRootElementHook():boolean
3150 
3151         /**
3152          * End of file hook. This method is a hook for subclasses to
3153          * add code that handles the end of file. The end of file in
3154          * a document fragment is OK if the markup depth is zero.
3155          * However, when scanning a full XML document, an end of file
3156          * is always premature.
3157          */
3158         protected void endOfFileHook(EOFException e)
3159         throws IOException, XNIException {
3160 
3161             // NOTE: An end of file is only only an error if we were
3162             //       in the middle of scanning some markup. -Ac
3163             if (fMarkupDepth != 0) {
3164                 reportFatalError("PrematureEOF", null);
3165             }
3166 
3167         } // endOfFileHook()
3168 
3169     } // class FragmentContentDriver
3170 
3171     static void pr(String str) {
3172         System.out.println(str) ;
3173     }
3174 
3175     protected boolean fUsebuffer ;
3176 
3177     /** this function gets an XMLString (which is used to store the attribute value) from the special pool
3178      *  maintained for attributes.
3179      *  fAttributeCacheUsedCount tracks the number of attributes that has been consumed from the pool.
3180      *  if all the attributes has been consumed, it adds a new XMLString inthe pool and returns the same
3181      *  XMLString.
3182      *
3183      * @return XMLString XMLString used to store an attribute value.
3184      */
3185 
3186     protected XMLString getString(){
3187         if(fAttributeCacheUsedCount < initialCacheCount || fAttributeCacheUsedCount < attributeValueCache.size()){
3188             return (XMLString)attributeValueCache.get(fAttributeCacheUsedCount++);
3189         } else{
3190             XMLString str = new XMLString();
3191             fAttributeCacheUsedCount++;
3192             attributeValueCache.add(str);
3193             return str;
3194         }
3195     }
3196 
3197     /**
3198      * Implements XMLBufferListener interface.
3199      */
3200 
3201     public void refresh(){
3202         refresh(0);
3203     }
3204 
3205     /**
3206      * receives callbacks from {@link XMLEntityReader } when buffer
3207      * is being changed.
3208      * @param refreshPosition
3209      */
3210     public void refresh(int refreshPosition){
3211         //If you are reading attributes and you got a callback
3212         //cache available attributes.
3213         if(fReadingAttributes){
3214             fAttributes.refresh();
3215         }
3216         if(fScannerState == SCANNER_STATE_CHARACTER_DATA){
3217             //since fTempString directly matches to the underlying main buffer
3218             //store the data into buffer
3219             fContentBuffer.append(fTempString);
3220             //clear the XMLString so that data can't be added again.
3221             fTempString.length = 0;
3222             fUsebuffer = true;
3223         }
3224     }
3225 
3226 } // class XMLDocumentFragmentScannerImpl