content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
   */
  
  /*
   * Copyright 2005 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  package jaxp.sun.org.apache.xerces.internal.impl;
  
  import jaxp.sun.xml.internal.stream.XMLBufferListener;
  import jaxp.sun.xml.internal.stream.XMLEntityStorage;
  import jaxp.sun.xml.internal.stream.XMLInputFactoryImpl;
  import jaxp.sun.xml.internal.stream.dtd.DTDGrammarUtil;
  
  import java.io.EOFException;
  import java.io.IOException;
  import jaxp.xml.stream.XMLInputFactory;
  import jaxp.xml.stream.events.XMLEvent;
  import jaxp.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  import jaxp.sun.org.apache.xerces.internal.util.AugmentationsImpl;
  import jaxp.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
  import jaxp.sun.org.apache.xerces.internal.util.XMLChar;
  import jaxp.sun.org.apache.xerces.internal.util.XMLStringBuffer;
  import jaxp.sun.org.apache.xerces.internal.util.XMLSymbols;
  import jaxp.sun.org.apache.xerces.internal.xni.QName;
  import jaxp.sun.org.apache.xerces.internal.xni.XMLAttributes;
  import jaxp.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  import jaxp.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  import jaxp.sun.org.apache.xerces.internal.xni.XMLString;
  import jaxp.sun.org.apache.xerces.internal.xni.XNIException;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLDocumentScanner;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  import jaxp.sun.org.apache.xerces.internal.xni.Augmentations;
  import jaxp.sun.org.apache.xerces.internal.utils.SecuritySupport;
  import jaxp.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
  import jaxp.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  import jaxp.sun.org.apache.xerces.internal.utils.XMLSecurityManager.Limit;
  import jaxp.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  
  import jaxp.xml.stream.XMLStreamConstants;
  
  /**
   *
   * This class is responsible for scanning the structure and content
   * of document fragments.
   *
   * This class has been modified as per the new design which is more suited to
   * efficiently build pull parser. Lot of improvements have been done and
   * the code has been added to support stax functionality/features.
   *
   * @author Neeraj Bajaj SUN Microsystems
   * @author K.Venugopal SUN Microsystems
   * @author Glenn Marcy, IBM
   * @author Andy Clark, IBM
   * @author Arnaud  Le Hors, IBM
   * @author Eric Ye, IBM
   * @author Sunitha Reddy, SUN Microsystems
   * @version $Id: XMLDocumentFragmentScannerImpl.java,v 1.19 2010-11-02 19:54:55 joehw Exp $
   *
   */
  public class XMLDocumentFragmentScannerImpl
          extends XMLScanner
          implements XMLDocumentScanner, XMLComponent, XMLEntityHandler, XMLBufferListener {
  
      //
      // Constants
      //
  
      protected int fElementAttributeLimit;
  
      /** External subset resolver. **/
      protected ExternalSubsetResolver fExternalSubsetResolver;
  
      // scanner states
  
      //XXX this should be divided into more states.
      /** Scanner state: start of markup. */
      protected static final int SCANNER_STATE_START_OF_MARKUP = 21;
  
      /** Scanner state: content. */
      protected static final int SCANNER_STATE_CONTENT = 22;
  
      /** Scanner state: processing instruction. */
      protected static final int SCANNER_STATE_PI = 23;
  
      /** Scanner state: DOCTYPE. */
      protected static final int SCANNER_STATE_DOCTYPE = 24;
  
      /** Scanner state: XML Declaration */
      protected static final int SCANNER_STATE_XML_DECL = 25;
  
      /** Scanner state: root element. */
      protected static final int SCANNER_STATE_ROOT_ELEMENT = 26;
  
      /** Scanner state: comment. */
      protected static final int SCANNER_STATE_COMMENT = 27;
  
      /** Scanner state: reference. */
      protected static final int SCANNER_STATE_REFERENCE = 28;
  
      // <book type="hard"> reading attribute name 'type'
      protected static final int SCANNER_STATE_ATTRIBUTE = 29;
  
      // <book type="hard"> //reading attribute value.
      protected static final int SCANNER_STATE_ATTRIBUTE_VALUE = 30;
  
      /** Scanner state: trailing misc. USED BY DOCUMENT_SCANNER_IMPL*/
      //protected static final int SCANNER_STATE_TRAILING_MISC = 32;
  
      /** Scanner state: end of input. */
      protected static final int SCANNER_STATE_END_OF_INPUT = 33;
  
      /** Scanner state: terminated. */
      protected static final int SCANNER_STATE_TERMINATED = 34;
  
      /** Scanner state: CDATA section. */
      protected static final int SCANNER_STATE_CDATA = 35;
  
      /** Scanner state: Text declaration. */
      protected static final int SCANNER_STATE_TEXT_DECL = 36;
  
      /** Scanner state: Text declaration. */
      protected static final int SCANNER_STATE_CHARACTER_DATA = 37;
  
      //<book type="hard">foo</book>
      protected static final int SCANNER_STATE_START_ELEMENT_TAG = 38;
  
      //<book type="hard">foo</book> reading </book>
      protected static final int SCANNER_STATE_END_ELEMENT_TAG = 39;
  
      protected static final int SCANNER_STATE_CHAR_REFERENCE = 40;
      protected static final int SCANNER_STATE_BUILT_IN_REFS = 41;
  
      // feature identifiers
  
  
      /** Feature identifier: notify built-in refereces. */
      protected static final String NOTIFY_BUILTIN_REFS =
              Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE;
  
      /** Property identifier: entity resolver. */
      protected static final String ENTITY_RESOLVER =
              Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
  
      /** Feature identifier: standard uri conformant */
      protected static final String STANDARD_URI_CONFORMANT =
              Constants.XERCES_FEATURE_PREFIX +Constants.STANDARD_URI_CONFORMANT_FEATURE;
  
      /** Property identifier: Security property manager. */
      private static final String XML_SECURITY_PROPERTY_MANAGER =
              Constants.XML_SECURITY_PROPERTY_MANAGER;
  
      /** access external dtd: file protocol
       *  For DOM/SAX, the secure feature is set to true by default
       */
      final static String EXTERNAL_ACCESS_DEFAULT = Constants.EXTERNAL_ACCESS_DEFAULT;
  
      // recognized features and properties
  
      /** Recognized features. */
      private static final String[] RECOGNIZED_FEATURES = {
                  NAMESPACES,
                  VALIDATION,
                  NOTIFY_BUILTIN_REFS,
                  NOTIFY_CHAR_REFS,
                  Constants.STAX_REPORT_CDATA_EVENT
      };
  
      /** Feature defaults. */
      private static final Boolean[] FEATURE_DEFAULTS = {
                  Boolean.TRUE,
                  null,
                  Boolean.FALSE,
                  Boolean.FALSE,
                  Boolean.TRUE
      };
  
      /** Recognized properties. */
      private static final String[] RECOGNIZED_PROPERTIES = {
          SYMBOL_TABLE,
                  ERROR_REPORTER,
                  ENTITY_MANAGER,
                  XML_SECURITY_PROPERTY_MANAGER
      };
  
      /** Property defaults. */
      private static final Object[] PROPERTY_DEFAULTS = {
                  null,
                  null,
                  null,
                  EXTERNAL_ACCESS_DEFAULT
      };
  
      private static final char [] cdata = {'[','C','D','A','T','A','['};
      static final char [] xmlDecl = {'<','?','x','m','l'};
      private static final char [] endTag = {'<','/'};
      // debugging
  
      /** Debug scanner state. */
      private static final boolean DEBUG_SCANNER_STATE = false;
  
      /** Debug driver. */
      private static final boolean DEBUG_DISPATCHER = false;
  
      /** Debug content driver scanning. */
      protected static final boolean DEBUG_START_END_ELEMENT = false;
  
  
      /** Debug driver next */
      protected static final boolean DEBUG_NEXT = false ;
  
      /** Debug driver next */
      protected static final boolean DEBUG = false;
      protected static final boolean DEBUG_COALESCE = false;
      //
      // Data
      //
  
      // protected data
  
      /** Document handler. */
      protected XMLDocumentHandler fDocumentHandler;
      protected int fScannerLastState ;
  
      /** Entity Storage */
      protected XMLEntityStorage fEntityStore;
  
      /** Entity stack. */
      protected int[] fEntityStack = new int[4];
  
      /** Markup depth. */
      protected int fMarkupDepth;
  
      //is the element empty
      protected boolean fEmptyElement ;
  
      //track if we are reading attributes, this is usefule while
      //there is a callback
      protected boolean fReadingAttributes = false;
  
      /** Scanner state. */
      protected int fScannerState;
  
      /** SubScanner state: inside scanContent method. */
      protected boolean fInScanContent = false;
      protected boolean fLastSectionWasCData = false;
      protected boolean fLastSectionWasEntityReference = false;
      protected boolean fLastSectionWasCharacterData = false;
  
      /** has external dtd */
      protected boolean fHasExternalDTD;
  
      /** Standalone. */
      protected boolean fStandaloneSet;
      protected boolean fStandalone;
      protected String fVersion;
  
      // element information
  
      /** Current element. */
      protected QName fCurrentElement;
  
      /** Element stack. */
      protected ElementStack fElementStack = new ElementStack();
      protected ElementStack2 fElementStack2 = new ElementStack2();
  
      // other info
  
      /** Document system identifier.
       * REVISIT:  So what's this used for?  - NG
       * protected String fDocumentSystemId;
       ******/
  
      protected String fPITarget ;
  
      //xxx do we need to create an extra XMLString object... look for using fTempString for collecting all the data values
      protected XMLString fPIData  = new XMLString();
  
      // features
  
  
      /** Notify built-in references. */
      protected boolean fNotifyBuiltInRefs = false;
  
      //STAX related properties
      //defaultValues.
      protected boolean fSupportDTD = true;
      protected boolean fReplaceEntityReferences = true;
      protected boolean fSupportExternalEntities = false;
      protected boolean fReportCdataEvent = false ;
      protected boolean fIsCoalesce = false ;
      protected String fDeclaredEncoding =  null;
      /** Xerces Feature: Disallow doctype declaration. */
      protected boolean fDisallowDoctype = false;
  
      /**
       * comma-delimited list of protocols that are allowed for the purpose
       * of accessing external dtd or entity references
       */
      protected String fAccessExternalDTD = EXTERNAL_ACCESS_DEFAULT;
  
      /**
       * standard uri conformant (strict uri).
       * http://apache.org/xml/features/standard-uri-conformant
       */
      protected boolean fStrictURI;
  
      // drivers
  
      /** Active driver. */
      protected Driver fDriver;
  
      /** Content driver. */
      protected Driver fContentDriver = createContentDriver();
  
      // temporary variables
  
      /** Element QName. */
      protected QName fElementQName = new QName();
  
      /** Attribute QName. */
      protected QName fAttributeQName = new QName();
  
      /**
       * CHANGED: Using XMLAttributesIteratorImpl instead of XMLAttributesImpl. This class
       * implements Iterator interface so we can directly give Attributes in the form of
       * iterator.
       */
      protected XMLAttributesIteratorImpl fAttributes = new XMLAttributesIteratorImpl();
  
  
      /** String. */
      protected XMLString fTempString = new XMLString();
  
      /** String. */
      protected XMLString fTempString2 = new XMLString();
  
      /** Array of 3 strings. */
      private String[] fStrings = new String[3];
  
      /** Making the buffer accesible to derived class -- String buffer. */
      protected XMLStringBuffer fStringBuffer = new XMLStringBuffer();
  
      /** Making the buffer accesible to derived class -- String buffer. */
      protected XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
  
      /** stores character data. */
      /** Making the buffer accesible to derived class -- stores PI data */
      protected XMLStringBuffer fContentBuffer = new XMLStringBuffer();
  
      /** Single character array. */
      private final char[] fSingleChar = new char[1];
      private String fCurrentEntityName = null;
  
      // New members
      protected boolean fScanToEnd = false;
  
      protected DTDGrammarUtil dtdGrammarUtil= null;
  
      protected boolean fAddDefaultAttr = false;
  
      protected boolean foundBuiltInRefs = false;
  
  
      //skip element algorithm
      static final short MAX_DEPTH_LIMIT = 5 ;
      static final short ELEMENT_ARRAY_LENGTH = 200 ;
      static final short MAX_POINTER_AT_A_DEPTH = 4 ;
      static final boolean DEBUG_SKIP_ALGORITHM = false;
      //create a elemnet array of length equal to ELEMENT_ARRAY_LENGTH
      String [] fElementArray = new String[ELEMENT_ARRAY_LENGTH] ;
      //pointer location where last element was skipped
      short fLastPointerLocation = 0 ;
      short fElementPointer = 0 ;
      //2D array to store pointer info
      short [] [] fPointerInfo = new short[MAX_DEPTH_LIMIT] [MAX_POINTER_AT_A_DEPTH] ;
      protected String fElementRawname ;
      protected boolean fShouldSkip = false;
      protected boolean fAdd = false ;
      protected boolean fSkip = false;
  
      /** Reusable Augmentations. */
      private Augmentations fTempAugmentations = null;
      //
      // Constructors
      //
  
      /** Default constructor. */
      public XMLDocumentFragmentScannerImpl() {
      } // <init>()
  
      //
      // XMLDocumentScanner methods
      //
  
      /**
       * Sets the input source.
       *
       * @param inputSource The input source.
       *
       * @throws IOException Thrown on i/o error.
       */
      public void setInputSource(XMLInputSource inputSource) throws IOException {
          fEntityManager.setEntityHandler(this);
          fEntityManager.startEntity("$fragment$", inputSource, false, true);
          // fDocumentSystemId = fEntityManager.expandSystemId(inputSource.getSystemId());
      } // setInputSource(XMLInputSource)
  
      /**
       * Scans a document.
       *
       * @param complete True if the scanner should scan the document
       *                 completely, pushing all events to the registered
       *                 document handler. A value of false indicates that
       *                 that the scanner should only scan the next portion
       *                 of the document and return. A scanner instance is
       *                 permitted to completely scan a document if it does
       *                 not support this "pull" scanning model.
       *
       * @return True if there is more to scan, false otherwise.
       */
      public boolean scanDocument(boolean complete)
      throws IOException, XNIException {
  
          // keep dispatching "events"
          fEntityManager.setEntityHandler(this);
          //System.out.println(" get Document Handler in NSDocumentHandler " + fDocumentHandler );
  
          int event = next();
          do {
              switch (event) {
                  case XMLStreamConstants.START_DOCUMENT :
                      //fDocumentHandler.startDocument(fEntityManager.getEntityScanner(),fEntityManager.getEntityScanner().getVersion(),fNamespaceContext,null);// not able to get
                      break;
                  case XMLStreamConstants.START_ELEMENT :
                      //System.out.println(" in scann element");
                      //fDocumentHandler.startElement(getElementQName(),fAttributes,null);
                      break;
                  case XMLStreamConstants.CHARACTERS :
                      fDocumentHandler.characters(getCharacterData(),null);
                      break;
                  case XMLStreamConstants.SPACE:
                      //check if getCharacterData() is the right function to retrieve ignorableWhitespace information.
                      //System.out.println("in the space");
                      //fDocumentHandler.ignorableWhitespace(getCharacterData(), null);
                      break;
                  case XMLStreamConstants.ENTITY_REFERENCE :
                      //entity reference callback are given in startEntity
                      break;
                  case XMLStreamConstants.PROCESSING_INSTRUCTION :
                      fDocumentHandler.processingInstruction(getPITarget(),getPIData(),null);
                      break;
                  case XMLStreamConstants.COMMENT :
                      //System.out.println(" in COMMENT of the XMLNSDocumentScannerImpl");
                      fDocumentHandler.comment(getCharacterData(),null);
                      break;
                  case XMLStreamConstants.DTD :
                      //all DTD related callbacks are handled in DTDScanner.
                      //1. Stax doesn't define DTD states as it does for XML Document.
                      //therefore we don't need to take care of anything here. So Just break;
                      break;
                  case XMLStreamConstants.CDATA:
                      fDocumentHandler.startCDATA(null);
                      //xxx: check if CDATA values comes from getCharacterData() function
                      fDocumentHandler.characters(getCharacterData(),null);
                      fDocumentHandler.endCDATA(null);
                      //System.out.println(" in CDATA of the XMLNSDocumentScannerImpl");
                      break;
                  case XMLStreamConstants.NOTATION_DECLARATION :
                      break;
                  case XMLStreamConstants.ENTITY_DECLARATION :
                      break;
                  case XMLStreamConstants.NAMESPACE :
                      break;
                  case XMLStreamConstants.ATTRIBUTE :
                      break;
                  case XMLStreamConstants.END_ELEMENT :
                      //do not give callback here.
                      //this callback is given in scanEndElement function.
                      //fDocumentHandler.endElement(getElementQName(),null);
                      break;
                  default :
                      throw new InternalError("processing event: " + event);
  
              }
              //System.out.println("here in before calling next");
              event = next();
              //System.out.println("here in after calling next");
          } while (event!=XMLStreamConstants.END_DOCUMENT && complete);
  
          if(event == XMLStreamConstants.END_DOCUMENT) {
              fDocumentHandler.endDocument(null);
              return false;
          }
  
          return true;
  
      } // scanDocument(boolean):boolean
  
  
  
      public QName getElementQName(){
          if(fScannerLastState == XMLEvent.END_ELEMENT){
              fElementQName.setValues(fElementStack.getLastPoppedElement());
          }
          return fElementQName ;
      }
  
      /** return the next state on the input
       * @return int
       */
  
      public int next() throws IOException, XNIException {
          return fDriver.next();
      }
  
      //
      // XMLComponent methods
      //
  
      /**
       * Resets the component. The component can query the component manager
       * about any features and properties that affect the operation of the
       * component.
       *
       * @param componentManager The component manager.
       *
       * @throws SAXException Thrown by component on initialization error.
       *                      For example, if a feature or property is
       *                      required for the operation of the component, the
       *                      component manager may throw a
       *                      SAXNotRecognizedException or a
       *                      SAXNotSupportedException.
       */
  
      public void reset(XMLComponentManager componentManager)
      throws XMLConfigurationException {
  
          super.reset(componentManager);
  
          // other settings
          // fDocumentSystemId = null;
  
          // sax features
          //fAttributes.setNamespaces(fNamespaces);
  
          // xerces features
          fReportCdataEvent = componentManager.getFeature(Constants.STAX_REPORT_CDATA_EVENT, true);
          fSecurityManager = (XMLSecurityManager)componentManager.getProperty(Constants.SECURITY_MANAGER, null);
          fNotifyBuiltInRefs = componentManager.getFeature(NOTIFY_BUILTIN_REFS, false);
  
          Object resolver = componentManager.getProperty(ENTITY_RESOLVER, null);
          fExternalSubsetResolver = (resolver instanceof ExternalSubsetResolver) ?
                  (ExternalSubsetResolver) resolver : null;
  
          //attribute
          fReadingAttributes = false;
          //xxx: external entities are supported in Xerces
          // it would be good to define feature for this case
          fSupportExternalEntities = true;
          fReplaceEntityReferences = true;
          fIsCoalesce = false;
  
          // setup Driver
          setScannerState(SCANNER_STATE_CONTENT);
          setDriver(fContentDriver);
  
          // JAXP 1.5 features and properties
          XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager)
                  componentManager.getProperty(XML_SECURITY_PROPERTY_MANAGER, null);
          fAccessExternalDTD = spm.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD);
  
          fStrictURI = componentManager.getFeature(STANDARD_URI_CONFORMANT, false);
  
          resetCommon();
          //fEntityManager.test();
      } // reset(XMLComponentManager)
  
  
      public void reset(PropertyManager propertyManager){
  
          super.reset(propertyManager);
  
          // other settings
          // fDocumentSystemId = null;
          fNamespaces = ((Boolean)propertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue();
          fNotifyBuiltInRefs = false ;
  
          //fElementStack2.clear();
          //fReplaceEntityReferences = true;
          //fSupportExternalEntities = true;
          Boolean bo = (Boolean)propertyManager.getProperty(XMLInputFactoryImpl.IS_REPLACING_ENTITY_REFERENCES);
          fReplaceEntityReferences = bo.booleanValue();
          bo = (Boolean)propertyManager.getProperty(XMLInputFactoryImpl.IS_SUPPORTING_EXTERNAL_ENTITIES);
          fSupportExternalEntities = bo.booleanValue();
          Boolean cdata = (Boolean)propertyManager.getProperty(Constants.ZEPHYR_PROPERTY_PREFIX + Constants.STAX_REPORT_CDATA_EVENT) ;
          if(cdata != null)
              fReportCdataEvent = cdata.booleanValue() ;
          Boolean coalesce = (Boolean)propertyManager.getProperty(XMLInputFactory.IS_COALESCING) ;
          if(coalesce != null)
              fIsCoalesce = coalesce.booleanValue();
          fReportCdataEvent = fIsCoalesce ? false : (fReportCdataEvent && true) ;
          //if fIsCoalesce is set to true, set the value of fReplaceEntityReferences to true,
          //if fIsCoalesce is set to false, take the value of fReplaceEntityReferences as set by application
          fReplaceEntityReferences = fIsCoalesce ? true : fReplaceEntityReferences;
          // setup Driver
          //we dont need to do this -- nb.
          //setScannerState(SCANNER_STATE_CONTENT);
          //setDriver(fContentDriver);
          //fEntityManager.test();
  
           // JAXP 1.5 features and properties
          XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager)
                  propertyManager.getProperty(XML_SECURITY_PROPERTY_MANAGER);
          fAccessExternalDTD = spm.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD);
  
          fSecurityManager = (XMLSecurityManager)propertyManager.getProperty(Constants.SECURITY_MANAGER);
          resetCommon();
      } // reset(XMLComponentManager)
  
      void resetCommon() {
          // initialize vars
          fMarkupDepth = 0;
          fCurrentElement = null;
          fElementStack.clear();
          fHasExternalDTD = false;
          fStandaloneSet = false;
          fStandalone = false;
          fInScanContent = false;
          //skipping algorithm
          fShouldSkip = false;
          fAdd = false;
          fSkip = false;
  
          fEntityStore = fEntityManager.getEntityStore();
          dtdGrammarUtil = null;
  
          if (fSecurityManager != null) {
              fElementAttributeLimit = fSecurityManager.getLimit(XMLSecurityManager.Limit.ELEMENT_ATTRIBUTE_LIMIT);
          } else {
              fElementAttributeLimit = 0;
          }
          fLimitAnalyzer = new XMLLimitAnalyzer();
          fEntityManager.setLimitAnalyzer(fLimitAnalyzer);
      }
  
      /**
       * Returns a list of feature identifiers that are recognized by
       * this component. This method may return null if no features
       * are recognized by this component.
       */
      public String[] getRecognizedFeatures() {
          return (String[])(RECOGNIZED_FEATURES.clone());
      } // getRecognizedFeatures():String[]
  
      /**
       * Sets the state of a feature. This method is called by the component
       * manager any time after reset when a feature changes state.
       * <p>
       * <strong>Note:</strong> Components should silently ignore features
       * that do not affect the operation of the component.
       *
       * @param featureId The feature identifier.
       * @param state     The state of the feature.
       *
       * @throws SAXNotRecognizedException The component should not throw
       *                                   this exception.
       * @throws SAXNotSupportedException The component should not throw
       *                                  this exception.
       */
      public void setFeature(String featureId, boolean state)
      throws XMLConfigurationException {
  
          super.setFeature(featureId, state);
  
          // Xerces properties
          if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
              String feature = featureId.substring(Constants.XERCES_FEATURE_PREFIX.length());
              if (feature.equals(Constants.NOTIFY_BUILTIN_REFS_FEATURE)) {
                  fNotifyBuiltInRefs = state;
              }
          }
  
      } // setFeature(String,boolean)
  
      /**
       * Returns a list of property identifiers that are recognized by
       * this component. This method may return null if no properties
       * are recognized by this component.
       */
      public String[] getRecognizedProperties() {
          return (String[])(RECOGNIZED_PROPERTIES.clone());
      } // getRecognizedProperties():String[]
  
      /**
       * Sets the value of a property. This method is called by the component
       * manager any time after reset when a property changes value.
       * <p>
       * <strong>Note:</strong> Components should silently ignore properties
       * that do not affect the operation of the component.
       *
       * @param propertyId The property identifier.
       * @param value      The value of the property.
       *
       * @throws SAXNotRecognizedException The component should not throw
       *                                   this exception.
       * @throws SAXNotSupportedException The component should not throw
       *                                  this exception.
       */
      public void setProperty(String propertyId, Object value)
      throws XMLConfigurationException {
  
          super.setProperty(propertyId, value);
  
          // Xerces properties
          if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
              final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
              if (suffixLength == Constants.ENTITY_MANAGER_PROPERTY.length() &&
                      propertyId.endsWith(Constants.ENTITY_MANAGER_PROPERTY)) {
                  fEntityManager = (XMLEntityManager)value;
                  return;
              }
              if (suffixLength == Constants.ENTITY_RESOLVER_PROPERTY.length() &&
                      propertyId.endsWith(Constants.ENTITY_RESOLVER_PROPERTY)) {
                  fExternalSubsetResolver = (value instanceof ExternalSubsetResolver) ?
                      (ExternalSubsetResolver) value : null;
                  return;
              }
          }
  
  
                  // Xerces properties
          if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
              String property = propertyId.substring(Constants.XERCES_PROPERTY_PREFIX.length());
              if (property.equals(Constants.ENTITY_MANAGER_PROPERTY)) {
                  fEntityManager = (XMLEntityManager)value;
              }
              return;
          }
  
          //JAXP 1.5 properties
          if (propertyId.equals(XML_SECURITY_PROPERTY_MANAGER))
          {
              XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager)value;
              fAccessExternalDTD = spm.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD);
          }
  
      } // setProperty(String,Object)
  
      /**
       * Returns the default state for a feature, or null if this
       * component does not want to report a default value for this
       * feature.
       *
       * @param featureId The feature identifier.
       *
       * @since Xerces 2.2.0
       */
      public Boolean getFeatureDefault(String featureId) {
          for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
              if (RECOGNIZED_FEATURES[i].equals(featureId)) {
                  return FEATURE_DEFAULTS[i];
              }
          }
          return null;
      } // getFeatureDefault(String):Boolean
  
      /**
       * Returns the default state for a property, or null if this
       * component does not want to report a default value for this
       * property.
       *
       * @param propertyId The property identifier.
       *
       * @since Xerces 2.2.0
       */
      public Object getPropertyDefault(String propertyId) {
          for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
              if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
                  return PROPERTY_DEFAULTS[i];
              }
          }
          return null;
      } // getPropertyDefault(String):Object
  
      //
      // XMLDocumentSource methods
      //
  
      /**
       * setDocumentHandler
       *
       * @param documentHandler
       */
      public void setDocumentHandler(XMLDocumentHandler documentHandler) {
          fDocumentHandler = documentHandler;
          //System.out.println(" In Set DOCUMENT HANDLER" + fDocumentHandler + " scanner =" + this);
      } // setDocumentHandler(XMLDocumentHandler)
  
  
      /** Returns the document handler */
      public XMLDocumentHandler getDocumentHandler(){
          return fDocumentHandler;
      }
  
      //
      // XMLEntityHandler methods
      //
  
      /**
       * This method notifies of the start of an entity. The DTD has the
       * pseudo-name of "[dtd]" parameter entity names start with '%'; and
       * general entities are just specified by their name.
       *
       * @param name     The name of the entity.
       * @param identifier The resource identifier.
       * @param encoding The auto-detected IANA encoding name of the entity
       *                 stream. This value will be null in those situations
       *                 where the entity encoding is not auto-detected (e.g.
       *                 internal entities or a document entity that is
       *                 parsed from a java.io.Reader).
       * @param augs     Additional information that may include infoset augmentations
       *
       * @throws XNIException Thrown by handler to signal an error.
       */
      public void startEntity(String name,
              XMLResourceIdentifier identifier,
              String encoding, Augmentations augs) throws XNIException {
  
          // keep track of this entity before fEntityDepth is increased
          if (fEntityDepth == fEntityStack.length) {
              int[] entityarray = new int[fEntityStack.length * 2];
              System.arraycopy(fEntityStack, 0, entityarray, 0, fEntityStack.length);
              fEntityStack = entityarray;
          }
          fEntityStack[fEntityDepth] = fMarkupDepth;
  
          super.startEntity(name, identifier, encoding, augs);
  
          // WFC:  entity declared in external subset in standalone doc
          if(fStandalone && fEntityStore.isEntityDeclInExternalSubset(name)) {
              reportFatalError("MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
                      new Object[]{name});
          }
  
          /** we are not calling the handlers yet.. */
          // call handler
          if (fDocumentHandler != null && !fScanningAttribute) {
              if (!name.equals("[xml]")) {
                  fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs);
              }
          }
  
      } // startEntity(String,XMLResourceIdentifier,String)
  
      /**
       * This method notifies the end of an entity. The DTD has the pseudo-name
       * of "[dtd]" parameter entity names start with '%'; and general entities
       * are just specified by their name.
       *
       * @param name The name of the entity.
       * @param augs Additional information that may include infoset augmentations
       *
       * @throws XNIException Thrown by handler to signal an error.
       */
      public void endEntity(String name, Augmentations augs) throws IOException, XNIException {
  
          /**
           * // flush possible pending output buffer - see scanContent
           * if (fInScanContent && fStringBuffer.length != 0
           * && fDocumentHandler != null) {
           * fDocumentHandler.characters(fStringBuffer, null);
           * fStringBuffer.length = 0; // make sure we know it's been flushed
           * }
           */
          super.endEntity(name, augs);
  
          // make sure markup is properly balanced
          if (fMarkupDepth != fEntityStack[fEntityDepth]) {
              reportFatalError("MarkupEntityMismatch", null);
          }
  
          /**/
          // call handler
          if (fDocumentHandler != null && !fScanningAttribute) {
              if (!name.equals("[xml]")) {
                  fDocumentHandler.endGeneralEntity(name, augs);
              }
          }
  
  
      } // endEntity(String)
  
      //
      // Protected methods
      //
  
      // Driver factory methods
  
      /** Creates a content Driver. */
      protected Driver createContentDriver() {
          return new FragmentContentDriver();
      } // createContentDriver():Driver
  
      // scanning methods
  
      /**
       * Scans an XML or text declaration.
       * <p>
       * <pre>
       * [23] XMLDecl ::= '&lt;?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
       * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
       * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
       * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
       * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
       *                 | ('"' ('yes' | 'no') '"'))
       *
       * [77] TextDecl ::= '&lt;?xml' VersionInfo? EncodingDecl S? '?>'
       * </pre>
       *
       * @param scanningTextDecl True if a text declaration is to
       *                         be scanned instead of an XML
       *                         declaration.
       */
      protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl)
      throws IOException, XNIException {
  
          // scan decl
          super.scanXMLDeclOrTextDecl(scanningTextDecl, fStrings);
          fMarkupDepth--;
  
          // pseudo-attribute values
          String version = fStrings[0];
          String encoding = fStrings[1];
          String standalone = fStrings[2];
          fDeclaredEncoding = encoding;
          // set standalone
          fStandaloneSet = standalone != null;
          fStandalone = fStandaloneSet && standalone.equals("yes");
          ///xxx see where its used.. this is not used anywhere. it may be useful for entity to store this information
          //but this information is only related with Document Entity.
          fEntityManager.setStandalone(fStandalone);
  
  
          // call handler
          if (fDocumentHandler != null) {
              if (scanningTextDecl) {
                  fDocumentHandler.textDecl(version, encoding, null);
              } else {
                  fDocumentHandler.xmlDecl(version, encoding, standalone, null);
              }
          }
  
          if(version != null){
              fEntityScanner.setVersion(version);
              fEntityScanner.setXMLVersion(version);
          }
          // set encoding on reader, only if encoding was not specified by the application explicitly
          if (encoding != null && !fEntityScanner.getCurrentEntity().isEncodingExternallySpecified()) {
               fEntityScanner.setEncoding(encoding);
          }
  
      } // scanXMLDeclOrTextDecl(boolean)
  
      public String getPITarget(){
          return fPITarget ;
      }
  
      public XMLStringBuffer getPIData(){
          return fContentBuffer ;
      }
  
      //XXX: why not this function behave as per the state of the parser?
      public XMLString getCharacterData(){
          if(fUsebuffer){
              return fContentBuffer ;
          }else{
              return fTempString;
          }
  
      }
  
  
      /**
       * Scans a processing data. This is needed to handle the situation
       * where a document starts with a processing instruction whose
       * target name <em>starts with</em> "xml". (e.g. xmlfoo)
       *
       * @param target The PI target
       * @param data The XMLStringBuffer to fill in with the data
       */
      protected void scanPIData(String target, XMLStringBuffer data)
      throws IOException, XNIException {
  
          super.scanPIData(target, data);
  
          //set the PI target and values
          fPITarget = target ;
  
          fMarkupDepth--;
  
      } // scanPIData(String)
  
      /**
       * Scans a comment.
       * <p>
       * <pre>
       * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
       * </pre>
       * <p>
       * <strong>Note:</strong> Called after scanning past '&lt;!--'
       */
      protected void scanComment() throws IOException, XNIException {
          fContentBuffer.clear();
          scanComment(fContentBuffer);
          //getTextCharacters can also be called for reading comments
          fUsebuffer = true;
          fMarkupDepth--;
  
      } // scanComment()
  
      //xxx value returned by this function may not remain valid if another event is scanned.
      public String getComment(){
          return fContentBuffer.toString();
      }
  
      void addElement(String rawname){
          if(fElementPointer < ELEMENT_ARRAY_LENGTH){
              //storing element raw name in a linear list of array
              fElementArray[fElementPointer] = rawname ;
              //storing elemnetPointer for particular element depth
  
              if(DEBUG_SKIP_ALGORITHM){
                  StringBuffer sb = new StringBuffer() ;
                  sb.append(" Storing element information ") ;
                  sb.append(" fElementPointer = " + fElementPointer) ;
                  sb.append(" fElementRawname = " + fElementQName.rawname) ;
                  sb.append(" fElementStack.fDepth = " + fElementStack.fDepth);
                  System.out.println(sb.toString()) ;
              }
  
              //store pointer information only when element depth is less MAX_DEPTH_LIMIT
              if(fElementStack.fDepth < MAX_DEPTH_LIMIT){
                  short column = storePointerForADepth(fElementPointer);
                  if(column > 0){
                      short pointer = getElementPointer((short)fElementStack.fDepth, (short)(column - 1) );
                      //identity comparison shouldn't take much time and we can rely on this
                      //since its guaranteed to have same object id for same string.
                      if(rawname == fElementArray[pointer]){
                          fShouldSkip = true ;
                          fLastPointerLocation = pointer ;
                          //reset the things and return.
                          resetPointer((short)fElementStack.fDepth , column) ;
                          fElementArray[fElementPointer] = null ;
                          return ;
                      }else{
                          fShouldSkip = false ;
                      }
                  }
              }
              fElementPointer++ ;
          }
      }
  
  
      void resetPointer(short depth, short column){
          fPointerInfo[depth] [column] = (short)0;
      }
  
      //returns column information at which pointer was stored.
      short storePointerForADepth(short elementPointer){
          short depth = (short) fElementStack.fDepth ;
  
          //Stores element pointer locations at particular depth , only 4 pointer locations
          //are stored at particular depth for now.
          for(short i = 0 ; i < MAX_POINTER_AT_A_DEPTH ; i++){
  
              if(canStore(depth, i)){
                  fPointerInfo[depth][i] = elementPointer ;
                  if(DEBUG_SKIP_ALGORITHM){
                      StringBuffer sb = new StringBuffer() ;
                      sb.append(" Pointer information ") ;
                      sb.append(" fElementPointer = " + fElementPointer) ;
                      sb.append(" fElementStack.fDepth = " + fElementStack.fDepth);
                      sb.append(" column = " + i ) ;
                      System.out.println(sb.toString()) ;
                  }
                  return i;
              }
              //else
              //pointer was not stored because we reached the limit
          }
          return -1 ;
      }
  
      boolean canStore(short depth, short column){
          //colum = 0 , means first element at particular depth
          //column = 1, means second element at particular depth
          //        calle should make sure that it doesn't call for value outside allowed co-ordinates
          return fPointerInfo[depth][column] == 0 ? true : false ;
      }
  
  
      short getElementPointer(short depth, short column){
          //colum = 0 , means first element at particular depth
          //column = 1, means second element at particular depth
          //        calle should make sure that it doesn't call for value outside allowed co-ordinates
          return fPointerInfo[depth][column] ;
      }
  
      //this function assumes that string passed is not null and skips
      //the following string from the buffer this makes sure
      boolean skipFromTheBuffer(String rawname) throws IOException{
          if(fEntityScanner.skipString(rawname)){
              char c = (char)fEntityScanner.peekChar() ;
              //If the start element was completely skipped we should encounter either ' '(space),
              //or '/' (in case of empty element)  or '>'
              if( c == ' ' || c == '/' || c == '>'){
                  fElementRawname = rawname ;
                  return true ;
              } else{
                  return false;
              }
          } else
              return false ;
      }
  
      boolean skipQElement(String rawname) throws IOException{
  
          final int c = fEntityScanner.getChar(rawname.length());
          //if this character is still valid element name -- this means string can't match
          if(XMLChar.isName(c)){
              return false;
          }else{
              return fEntityScanner.skipString(rawname);
          }
      }
  
      protected boolean skipElement() throws IOException {
  
          if(!fShouldSkip) return false ;
  
          if(fLastPointerLocation != 0){
              //Look at the next element stored in the array list.. we might just get a match.
              String rawname = fElementArray[fLastPointerLocation + 1] ;
              if(rawname != null && skipFromTheBuffer(rawname)){
                  fLastPointerLocation++ ;
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("Element " + fElementRawname + " was SKIPPED at pointer location = " + fLastPointerLocation);
                  }
                  return true ;
              } else{
                  //reset it back to zero... we haven't got the correct subset yet.
                  fLastPointerLocation = 0 ;
  
              }
          }
          //xxx: we can put some logic here as from what column it should start looking
          //for now we always start at 0
          //fallback to tolerant algorithm, it would look for differnt element stored at different
          //depth and get us the pointer location.
          return fShouldSkip && skipElement((short)0);
  
      }
  
      //start of the column at which it should try searching
      boolean skipElement(short column) throws IOException {
          short depth = (short)fElementStack.fDepth ;
  
          if(depth > MAX_DEPTH_LIMIT){
              return fShouldSkip = false ;
          }
          for(short i = column ; i < MAX_POINTER_AT_A_DEPTH ; i++){
              short pointer = getElementPointer(depth , i ) ;
  
              if(pointer == 0){
                  return fShouldSkip = false ;
              }
  
              if(fElementArray[pointer] != null && skipFromTheBuffer(fElementArray[pointer])){
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println();
                      System.out.println("Element " + fElementRawname + " was SKIPPED at depth = " + fElementStack.fDepth + " column = " + column );
                      System.out.println();
                  }
                  fLastPointerLocation = pointer ;
                  return fShouldSkip = true ;
              }
          }
          return fShouldSkip = false ;
      }
  
      /**
       * Scans a start element. This method will handle the binding of
       * namespace information and notifying the handler of the start
       * of the element.
       * <p>
       * <pre>
       * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
       * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
       * </pre>
       * <p>
       * <strong>Note:</strong> This method assumes that the leading
       * '&lt;' character has been consumed.
       * <p>
       * <strong>Note:</strong> This method uses the fElementQName and
       * fAttributes variables. The contents of these variables will be
       * destroyed. The caller should copy important information out of
       * these variables before calling this method.
       * NB: Content in fAttributes is valid only till the state of the parser is XMLEvent.START_ELEMENT
       *
       * @return True if element is empty. (i.e. It matches
       *          production [44].
       */
      // fElementQName will have the details of element just read..
      // fAttributes will have the details of all the attributes.
      protected boolean scanStartElement()
      throws IOException, XNIException {
  
          if (DEBUG_START_END_ELEMENT) System.out.println( this.getClass().toString() + ">>> scanStartElement()");
          //when skipping is true and no more elements should be added
          if(fSkip && !fAdd){
              //get the stored element -- if everything goes right this should match the
              //token in the buffer
  
              QName name = fElementStack.getNext();
  
              if(DEBUG_SKIP_ALGORITHM){
                  System.out.println("Trying to skip String = " + name.rawname);
              }
  
              //Be conservative -- if skipping fails -- stop.
              fSkip = fEntityScanner.skipString(name.rawname);
  
              if(fSkip){
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("Element SUCESSFULLY skipped = " + name.rawname);
                  }
                  fElementStack.push();
                  fElementQName = name;
              }else{
                  //if skipping fails reposition the stack or fallback to normal way of processing
                  fElementStack.reposition();
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("Element was NOT skipped, REPOSITIONING stack" );
                  }
              }
          }
  
          //we are still at the stage of adding elements
          //the elements were not matched or
          //fSkip is not set to true
          if(!fSkip || fAdd){
              //get the next element from the stack
              fElementQName = fElementStack.nextElement();
              // name
              if (fNamespaces) {
                  fEntityScanner.scanQName(fElementQName);
              } else {
                  String name = fEntityScanner.scanName();
                  fElementQName.setValues(null, name, name, null);
              }
  
              if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
              if(DEBUG_SKIP_ALGORITHM){
                  if(fAdd){
                      System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
                  }
              }
  
          }
  
          //when the elements are being added , we need to check if we are set for skipping the elements
          if(fAdd){
              //this sets the value of fAdd variable
              fElementStack.matchElement(fElementQName);
          }
  
  
          //xxx: We dont need another pointer, fCurrentElement, we can use fElementQName
          fCurrentElement = fElementQName;
  
          String rawname = fElementQName.rawname;
  
          fEmptyElement = false;
  
          fAttributes.removeAllAttributes();
  
          if(!seekCloseOfStartTag()){
              fReadingAttributes = true;
              fAttributeCacheUsedCount =0;
              fStringBufferIndex =0;
              fAddDefaultAttr = true;
              do {
                  scanAttribute(fAttributes);
                  if (fSecurityManager != null && !fSecurityManager.isNoLimit(fElementAttributeLimit) &&
                          fAttributes.getLength() > fElementAttributeLimit){
                      fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
                                                   "ElementAttributeLimit",
                                                   new Object[]{rawname, fElementAttributeLimit },
                                                   XMLErrorReporter.SEVERITY_FATAL_ERROR );
                  }
  
              } while (!seekCloseOfStartTag());
              fReadingAttributes=false;
          }
  
          if (fEmptyElement) {
              //decrease the markup depth..
              fMarkupDepth--;
  
              // check that this element was opened in the same entity
              if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
                  reportFatalError("ElementEntityMismatch",
                          new Object[]{fCurrentElement.rawname});
              }
              // call handler
              if (fDocumentHandler != null) {
                  fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
              }
  
              //We should not be popping out the context here in endELement becaause the namespace context is still
              //valid when parser is at the endElement state.
              //if (fNamespaces) {
              //  fNamespaceContext.popContext();
              //}
  
              //pop the element off the stack..
              fElementStack.popElement();
  
          } else {
  
              if(dtdGrammarUtil != null)
                  dtdGrammarUtil.startElement(fElementQName, fAttributes);
              if(fDocumentHandler != null){
                  //complete element and attributes are traversed in this function so we can send a callback
                  //here.
                  //<strong>we shouldn't be sending callback in scanDocument()</strong>
                  fDocumentHandler.startElement(fElementQName, fAttributes, null);
              }
          }
  
  
          if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() + "<<< scanStartElement(): "+fEmptyElement);
          return fEmptyElement;
  
      } // scanStartElement():boolean
  
      /**
       * Looks for the close of start tag, i.e. if it finds '>' or '/>'
       * Characters are consumed.
       */
      protected boolean seekCloseOfStartTag() throws IOException, XNIException {
          // spaces
          boolean sawSpace = fEntityScanner.skipSpaces();
  
          // end tag?
          final int c = fEntityScanner.peekChar();
          if (c == '>') {
              fEntityScanner.scanChar();
              return true;
          } else if (c == '/') {
              fEntityScanner.scanChar();
              if (!fEntityScanner.skipChar('>')) {
                  reportFatalError("ElementUnterminated",
                          new Object[]{fElementQName.rawname});
              }
              fEmptyElement = true;
              return true;
          } else if (!isValidNameStartChar(c) || !sawSpace) {
              reportFatalError("ElementUnterminated", new Object[]{fElementQName.rawname});
          }
  
          return false;
      }
  
      public boolean hasAttributes(){
          return fAttributes.getLength() > 0 ? true : false ;
      }
  
  
      /**
       * Scans an attribute.
       * <p>
       * <pre>
       * [41] Attribute ::= Name Eq AttValue
       * </pre>
       * <p>
       * <strong>Note:</strong> This method assumes that the next
       * character on the stream is the first character of the attribute
       * name.
       * <p>
       * <strong>Note:</strong> This method uses the fAttributeQName and
       * fQName variables. The contents of these variables will be
       * destroyed.
       *
       * @param attributes The attributes list for the scanned attribute.
       */
  
      /**
       * protected void scanAttribute(AttributeIteratorImpl attributes)
       * throws IOException, XNIException {
       * if (DEBUG_START_END_ELEMENT) System.out.println(">>> scanAttribute()");
       *
       *
       * // name
       * if (fNamespaces) {
       * fEntityScanner.scanQName(fAttributeQName);
       * }
       * else {
       * String name = fEntityScanner.scanName();
       * fAttributeQName.setValues(null, name, name, null);
       * }
       *
       * // equals
       * fEntityScanner.skipSpaces();
       * if (!fEntityScanner.skipChar('=')) {
       * reportFatalError("EqRequiredInAttribute",
       * new Object[]{fAttributeQName.rawname});
       * }
       * fEntityScanner.skipSpaces();
       *
       *
       * // content
       * int oldLen = attributes.getLength();
       */
      /**xxx there is one check of duplicate attribute that has been removed.
       * attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
       *
       * // WFC: Unique Att Spec
       * if (oldLen == attributes.getLength()) {
       * reportFatalError("AttributeNotUnique",
       * new Object[]{fCurrentElement.rawname,
       * fAttributeQName.rawname});
       * }
       */
  
      /*
          //REVISIT: one more case needs to be included: external PE and standalone is no
          boolean isVC =  fHasExternalDTD && !fStandalone;
          scanAttributeValue(fTempString, fTempString2,
                             fAttributeQName.rawname, attributes,
                             oldLen, isVC);
  
          //attributes.setValue(oldLen, fTempString.toString());
          //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
          //attributes.setSpecified(oldLen, true);
  
          AttributeImpl attribute = new AttributeImpl(fAttributeQName.prefix,fAttributeQName.localpart,fAttributeQName.uri,fTempString.toString(),fTempString2.toString(),XMLSymbols.fCDATASymbol,true);
          fAttributes.addAttribute(attribute);
          if (DEBUG_START_END_ELEMENT) System.out.println("<<< scanAttribute()");
      } // scanAttribute(XMLAttributes)
  
       */
  
      /** return the attribute iterator implementation */
      public XMLAttributesIteratorImpl getAttributeIterator(){
          if(dtdGrammarUtil != null && fAddDefaultAttr){
              dtdGrammarUtil.addDTDDefaultAttrs(fElementQName,fAttributes);
              fAddDefaultAttr = false;
          }
          return fAttributes;
      }
  
      /** return if standalone is set */
      public boolean standaloneSet(){
          return fStandaloneSet;
      }
      /** return if the doucment is standalone */
      public boolean isStandAlone(){
          return fStandalone ;
      }
      /**
       * Scans an attribute name value pair.
       * <p>
       * <pre>
       * [41] Attribute ::= Name Eq AttValue
       * </pre>
       * <p>
       * <strong>Note:</strong> This method assumes that the next
       * character on the stream is the first character of the attribute
       * name.
       * <p>
       * <strong>Note:</strong> This method uses the fAttributeQName and
       * fQName variables. The contents of these variables will be
       * destroyed.
       *
       * @param attributes The attributes list for the scanned attribute.
       */
  
      protected void scanAttribute(XMLAttributes attributes)
      throws IOException, XNIException {
          if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
  
          // name
          if (fNamespaces) {
              fEntityScanner.scanQName(fAttributeQName);
          } else {
              String name = fEntityScanner.scanName();
              fAttributeQName.setValues(null, name, name, null);
          }
  
          // equals
          fEntityScanner.skipSpaces();
          if (!fEntityScanner.skipChar('=')) {
              reportFatalError("EqRequiredInAttribute",
                  new Object[] {fCurrentElement.rawname, fAttributeQName.rawname});
          }
          fEntityScanner.skipSpaces();
  
          int attIndex = 0 ;
          //REVISIT: one more case needs to be included: external PE and standalone is no
          boolean isVC =  fHasExternalDTD && !fStandalone;
          //fTempString would store attribute value
          ///fTempString2 would store attribute non-normalized value
  
          //this function doesn't use 'attIndex'. We are adding the attribute later
          //after we have figured out that current attribute is not namespace declaration
          //since scanAttributeValue doesn't use attIndex parameter therefore we
          //can safely add the attribute later..
          XMLString tmpStr = getString();
  
          scanAttributeValue(tmpStr, fTempString2,
                  fAttributeQName.rawname, attributes,
                  attIndex, isVC);
  
          // content
          int oldLen = attributes.getLength();
          //if the attribute name already exists.. new value is replaced with old value
          attIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
  
          // WFC: Unique Att Spec
          //attributes count will be same if the current attribute  name already exists for this element name.
          //this means there are two duplicate attributes.
          if (oldLen == attributes.getLength()) {
              reportFatalError("AttributeNotUnique",
                      new Object[]{fCurrentElement.rawname,
                              fAttributeQName.rawname});
          }
  
          //tmpString contains attribute value
          //we are passing null as the attribute value
          attributes.setValue(attIndex, null, tmpStr);
  
          ///xxx: nonNormalizedValue is not being set as it is not required by SAX & DOM
          //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
          attributes.setSpecified(attIndex, true);
  
          if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanAttribute()");
  
      } // scanAttribute(XMLAttributes)
  
      /**
       * Scans element content.
       *
       * @return Returns the next character on the stream.
       */
      //CHANGED:
      //EARLIER: scanContent()
      //NOW: scanContent(XMLStringBuffer)
      //It makes things easy if this functions takes XMLStringBuffer as parameter..
      //this function appends the data to the buffer.
      protected int scanContent(XMLStringBuffer content) throws IOException, XNIException {
          //set the fTempString length to 0 before passing it on to scanContent
          //scanContent sets the correct co-ordinates as per the content read
          fTempString.length = 0;
          int c = fEntityScanner.scanContent(fTempString);
          content.append(fTempString);
          fTempString.length = 0;
          if (c == '\r') {
              // happens when there is the character reference &#13;
              //xxx: We know the next chracter.. we should just skip it and add ']' directlry
              fEntityScanner.scanChar();
              content.append((char)c);
              c = -1;
          } else if (c == ']') {
              //fStringBuffer.clear();
              //xxx: We know the next chracter.. we should just skip it and add ']' directlry
              content.append((char)fEntityScanner.scanChar());
              // remember where we are in case we get an endEntity before we
              // could flush the buffer out - this happens when we're parsing an
              // entity which ends with a ]
              fInScanContent = true;
              //
              // We work on a single character basis to handle cases such as:
              // ']]]>' which we might otherwise miss.
              //
              if (fEntityScanner.skipChar(']')) {
                  content.append(']');
                  while (fEntityScanner.skipChar(']')) {
                      content.append(']');
                  }
                  if (fEntityScanner.skipChar('>')) {
                      reportFatalError("CDEndInContent", null);
                  }
              }
              fInScanContent = false;
              c = -1;
          }
          if (fDocumentHandler != null && content.length > 0) {
              //fDocumentHandler.characters(content, null);
          }
          return c;
  
      } // scanContent():int
  
  
      /**
       * Scans a CDATA section.
       * <p>
       * <strong>Note:</strong> This method uses the fTempString and
       * fStringBuffer variables.
       *
       * @param complete True if the CDATA section is to be scanned
       *                 completely.
       *
       * @return True if CDATA is completely scanned.
       */
      //CHANGED:
      protected boolean scanCDATASection(XMLStringBuffer contentBuffer, boolean complete)
      throws IOException, XNIException {
  
          // call handler
          if (fDocumentHandler != null) {
              //fDocumentHandler.startCDATA(null);
          }
  
          while (true) {
              //scanData will fill the contentBuffer
              if (!fEntityScanner.scanData("]]>", contentBuffer)) {
                  break ;
                  /** We dont need all this code if we pass ']]>' as delimeter..
                   * int brackets = 2;
                   * while (fEntityScanner.skipChar(']')) {
                   * brackets++;
                   * }
                   *
                   * //When we find more than 2 square brackets
                   * if (fDocumentHandler != null && brackets > 2) {
                   * //we dont need to clear the buffer..
                   * //contentBuffer.clear();
                   * for (int i = 2; i < brackets; i++) {
                   * contentBuffer.append(']');
                   * }
                   * fDocumentHandler.characters(contentBuffer, null);
                   * }
                   *
                   * if (fEntityScanner.skipChar('>')) {
                   * break;
                   * }
                   * if (fDocumentHandler != null) {
                   * //we dont need to clear the buffer now..
                   * //contentBuffer.clear();
                   * contentBuffer.append("]]");
                   * fDocumentHandler.characters(contentBuffer, null);
                   * }
                   **/
              } else {
                  int c = fEntityScanner.peekChar();
                  if (c != -1 && isInvalidLiteral(c)) {
                      if (XMLChar.isHighSurrogate(c)) {
                          //contentBuffer.clear();
                          //scan surrogates if any....
                          scanSurrogates(contentBuffer);
                      } else {
                          reportFatalError("InvalidCharInCDSect",
                                  new Object[]{Integer.toString(c,16)});
                                  fEntityScanner.scanChar();
                      }
                  }
                  //by this time we have also read surrogate contents if any...
                  if (fDocumentHandler != null) {
                      //fDocumentHandler.characters(contentBuffer, null);
                  }
              }
          }
          fMarkupDepth--;
  
          if (fDocumentHandler != null && contentBuffer.length > 0) {
              //fDocumentHandler.characters(contentBuffer, null);
          }
  
          // call handler
          if (fDocumentHandler != null) {
              //fDocumentHandler.endCDATA(null);
          }
  
          return true;
  
      } // scanCDATASection(XMLStringBuffer, boolean):boolean
  
      /**
       * Scans an end element.
       * <p>
       * <pre>
       * [42] ETag ::= '&lt;/' Name S? '>'
       * </pre>
       * <p>
       * <strong>Note:</strong> This method uses the fElementQName variable.
       * The contents of this variable will be destroyed. The caller should
       * copy the needed information out of this variable before calling
       * this method.
       *
       * @return The element depth.
       */
      protected int scanEndElement() throws IOException, XNIException {
          if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanEndElement()");
  
          // pop context
          QName endElementName = fElementStack.popElement();
  
          String rawname = endElementName.rawname;
          if(DEBUG)System.out.println("endElementName = " + endElementName.toString());
          // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
          //In scanners most of the time is consumed on checks done for XML characters, we can
          // optimize on it and avoid the checks done for endElement,
          //we will also avoid symbol table lookup - neeraj.bajaj@sun.com
  
          // this should work both for namespace processing true or false...
  
          //REVISIT: if the string is not the same as expected.. we need to do better error handling..
          //We can skip this for now... In any case if the string doesn't match -- document is not well formed.
  
          if (!fEntityScanner.skipString(endElementName.rawname)) {
               reportFatalError("ETagRequired", new Object[]{rawname});
          }
  
          // end
          fEntityScanner.skipSpaces();
          if (!fEntityScanner.skipChar('>')) {
              reportFatalError("ETagUnterminated",
                      new Object[]{rawname});
          }
          fMarkupDepth--;
  
          //we have increased the depth for two markup "<" characters
          fMarkupDepth--;
  
          // check that this element was opened in the same entity
          if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
              reportFatalError("ElementEntityMismatch",
                      new Object[]{rawname});
          }
  
          //We should not be popping out the context here in endELement becaause the namespace context is still
          //valid when parser is at the endElement state.
  
          //if (fNamespaces) {
          //  fNamespaceContext.popContext();
          //}
  
          // call handler
          if (fDocumentHandler != null ) {
              //end element is scanned in this function so we can send a callback
              //here.
              //<strong>we shouldn't be sending callback in scanDocument()</strong>
  
              fDocumentHandler.endElement(endElementName, null);
          }
          if(dtdGrammarUtil != null)
              dtdGrammarUtil.endElement(endElementName);
  
          return fMarkupDepth;
  
      } // scanEndElement():int
  
      /**
       * Scans a character reference.
       * <p>
       * <pre>
       * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
       * </pre>
       */
      protected void scanCharReference()
      throws IOException, XNIException {
  
          fStringBuffer2.clear();
          int ch = scanCharReferenceValue(fStringBuffer2, null);
          fMarkupDepth--;
          if (ch != -1) {
              // call handler
  
              if (fDocumentHandler != null) {
                  if (fNotifyCharRefs) {
                      fDocumentHandler.startGeneralEntity(fCharRefLiteral, null, null, null);
                  }
                  Augmentations augs = null;
                  if (fValidation && ch <= 0x20) {
                      if (fTempAugmentations != null) {
                          fTempAugmentations.removeAllItems();
                      }
                      else {
                          fTempAugmentations = new AugmentationsImpl();
                      }
                      augs = fTempAugmentations;
                      augs.putItem(Constants.CHAR_REF_PROBABLE_WS, Boolean.TRUE);
                  }
                  //xxx: How do we deal with this - how to return charReferenceValues
                  //now this is being commented because this is taken care in scanDocument()
                  //fDocumentHandler.characters(fStringBuffer2, null);
                  if (fNotifyCharRefs) {
                      fDocumentHandler.endGeneralEntity(fCharRefLiteral, null);
                  }
              }
          }
  
      } // scanCharReference()
  
  
      /**
       * Scans an entity reference.
       *
       * @return returns true if the new entity is started. If it was built-in entity
       *         'false' is returned.
       * @throws IOException  Thrown if i/o error occurs.
       * @throws XNIException Thrown if handler throws exception upon
       *                      notification.
       */
      protected void scanEntityReference(XMLStringBuffer content) throws IOException, XNIException {
          String name = fEntityScanner.scanName();
          if (name == null) {
              reportFatalError("NameRequiredInReference", null);
              return;
          }
          if (!fEntityScanner.skipChar(';')) {
              reportFatalError("SemicolonRequiredInReference", new Object []{name});
          }
          if (fEntityStore.isUnparsedEntity(name)) {
              reportFatalError("ReferenceToUnparsedEntity", new Object[]{name});
          }
          fMarkupDepth--;
          fCurrentEntityName = name;
  
          // handle built-in entities
          if (name == fAmpSymbol) {
              handleCharacter('&', fAmpSymbol, content);
              fScannerState = SCANNER_STATE_BUILT_IN_REFS;
              return ;
          } else if (name == fLtSymbol) {
              handleCharacter('<', fLtSymbol, content);
              fScannerState = SCANNER_STATE_BUILT_IN_REFS;
              return ;
          } else if (name == fGtSymbol) {
              handleCharacter('>', fGtSymbol, content);
              fScannerState = SCANNER_STATE_BUILT_IN_REFS;
              return ;
          } else if (name == fQuotSymbol) {
              handleCharacter('"', fQuotSymbol, content);
              fScannerState = SCANNER_STATE_BUILT_IN_REFS;
              return ;
          } else if (name == fAposSymbol) {
              handleCharacter('\'', fAposSymbol, content);
              fScannerState = SCANNER_STATE_BUILT_IN_REFS;
              return ;
          }
  
          //1. if the entity is external and support to external entities is not required
          // 2. or entities should not be replaced
          //3. or if it is built in entity reference.
          boolean isEE = fEntityStore.isExternalEntity(name);
          if((isEE && !fSupportExternalEntities) || (!isEE && !fReplaceEntityReferences) || foundBuiltInRefs){
              fScannerState = SCANNER_STATE_REFERENCE;
              return ;
          }
          // start general entity
          if (!fEntityStore.isDeclaredEntity(name)) {
              //SUPPORT_DTD=false && ReplaceEntityReferences should throw exception
              if (!fSupportDTD && fReplaceEntityReferences) {
                  reportFatalError("EntityNotDeclared", new Object[]{name});
                  return;
              }
              //REVISIT: one more case needs to be included: external PE and standalone is no
              if ( fHasExternalDTD && !fStandalone) {
                  if (fValidation)
                      fErrorReporter.reportError(fEntityScanner, XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
                              new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
              } else
                  reportFatalError("EntityNotDeclared", new Object[]{name});
          }
          //we are starting the entity even if the entity was not declared
          //if that was the case it its taken care in XMLEntityManager.startEntity()
          //we immediately call the endEntity. Application gets to know if there was
          //any entity that was not declared.
          fEntityManager.startEntity(name, false);
          //set the scaner state to content.. parser will automatically revive itself at any point of time.
          //setScannerState(SCANNER_STATE_CONTENT);
          //return true ;
      } // scanEntityReference()
  
      // utility methods
  
      /**
       * Calls document handler with a single character resulting from
       * built-in entity resolution.
       *
       * @param c
       * @param entity built-in name
       * @param XMLStringBuffer append the character to buffer
       *
       * we really dont need to call this function -- this function is only required when
       * we integrate with rest of Xerces2. SO maintaining the current behavior and still
       * calling this function to hanlde built-in entity reference.
       *
       */
      private void handleCharacter(char c, String entity, XMLStringBuffer content) throws XNIException {
          foundBuiltInRefs = true;
          content.append(c);
          if (fDocumentHandler != null) {
              fSingleChar[0] = c;
              if (fNotifyBuiltInRefs) {
                  fDocumentHandler.startGeneralEntity(entity, null, null, null);
              }
              fTempString.setValues(fSingleChar, 0, 1);
              //fDocumentHandler.characters(fTempString, null);
  
              if (fNotifyBuiltInRefs) {
                  fDocumentHandler.endGeneralEntity(entity, null);
              }
          }
      } // handleCharacter(char)
  
      // helper methods
  
      /**
       * Sets the scanner state.
       *
       * @param state The new scanner state.
       */
      protected final void setScannerState(int state) {
  
          fScannerState = state;
          if (DEBUG_SCANNER_STATE) {
              System.out.print("### setScannerState: ");
              //System.out.print(fScannerState);
              System.out.print(getScannerStateName(state));
              System.out.println();
          }
  
      } // setScannerState(int)
  
  
      /**
       * Sets the Driver.
       *
       * @param Driver The new Driver.
       */
      protected final void setDriver(Driver driver) {
          fDriver = driver;
          if (DEBUG_DISPATCHER) {
              System.out.print("%%% setDriver: ");
              System.out.print(getDriverName(driver));
              System.out.println();
          }
      }
  
      //
      // Private methods
      //
  
      /** Returns the scanner state name. */
      protected String getScannerStateName(int state) {
  
          switch (state) {
              case SCANNER_STATE_DOCTYPE: return "SCANNER_STATE_DOCTYPE";
              case SCANNER_STATE_ROOT_ELEMENT: return "SCANNER_STATE_ROOT_ELEMENT";
              case SCANNER_STATE_START_OF_MARKUP: return "SCANNER_STATE_START_OF_MARKUP";
              case SCANNER_STATE_COMMENT: return "SCANNER_STATE_COMMENT";
              case SCANNER_STATE_PI: return "SCANNER_STATE_PI";
              case SCANNER_STATE_CONTENT: return "SCANNER_STATE_CONTENT";
              case SCANNER_STATE_REFERENCE: return "SCANNER_STATE_REFERENCE";
              case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
              case SCANNER_STATE_TERMINATED: return "SCANNER_STATE_TERMINATED";
              case SCANNER_STATE_CDATA: return "SCANNER_STATE_CDATA";
              case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
              case SCANNER_STATE_ATTRIBUTE: return "SCANNER_STATE_ATTRIBUTE";
              case SCANNER_STATE_ATTRIBUTE_VALUE: return "SCANNER_STATE_ATTRIBUTE_VALUE";
              case SCANNER_STATE_START_ELEMENT_TAG: return "SCANNER_STATE_START_ELEMENT_TAG";
              case SCANNER_STATE_END_ELEMENT_TAG: return "SCANNER_STATE_END_ELEMENT_TAG";
              case SCANNER_STATE_CHARACTER_DATA: return "SCANNER_STATE_CHARACTER_DATA" ;
          }
  
          return "??? ("+state+')';
  
      } // getScannerStateName(int):String
      public String getEntityName(){
          //return the cached name
          return fCurrentEntityName;
      }
  
      /** Returns the driver name. */
      public String getDriverName(Driver driver) {
  
          if (DEBUG_DISPATCHER) {
              if (driver != null) {
                  String name = driver.getClass().getName();
                  int index = name.lastIndexOf('.');
                  if (index != -1) {
                      name = name.substring(index + 1);
                      index = name.lastIndexOf('$');
                      if (index != -1) {
                          name = name.substring(index + 1);
                      }
                  }
                  return name;
              }
          }
          return "null";
  
      } // getDriverName():String
  
      /**
       * Check the protocol used in the systemId against allowed protocols
       *
       * @param systemId the Id of the URI
       * @param allowedProtocols a list of allowed protocols separated by comma
       * @return the name of the protocol if rejected, null otherwise
       */
      String checkAccess(String systemId, String allowedProtocols) throws IOException {
          String baseSystemId = fEntityScanner.getBaseSystemId();
          String expandedSystemId = fEntityManager.expandSystemId(systemId, baseSystemId,fStrictURI);
          return SecuritySupport.checkAccess(expandedSystemId, allowedProtocols, Constants.ACCESS_EXTERNAL_ALL);
      }
  
      //
      // Classes
      //
  
      /**
       * @author Neeraj Bajaj, Sun Microsystems.
       */
      protected static final class Element {
  
          //
          // Data
          //
  
          /** Symbol. */
          public QName qname;
  
          //raw name stored as characters
          public char[] fRawname;
  
          /** The next Element entry. */
          public Element next;
  
          //
          // Constructors
          //
  
          /**
           * Constructs a new Element from the given QName and next Element
           * reference.
           */
          public Element(QName qname, Element next) {
              this.qname.setValues(qname);
              this.fRawname = qname.rawname.toCharArray();
              this.next = next;
          }
  
      } // class Element
  
      /**
       * Element stack.
       *
       * @author Neeraj Bajaj, Sun Microsystems.
       */
      protected class ElementStack2 {
  
          //
          // Data
          //
  
          /** The stack data. */
          protected QName [] fQName = new QName[20];
  
          //Element depth
          protected int fDepth;
          //total number of elements
          protected int fCount;
          //current position
          protected int fPosition;
          //Mark refers to the position
          protected int fMark;
  
          protected int fLastDepth ;
  
          //
          // Constructors
          //
  
          /** Default constructor. */
          public ElementStack2() {
              for (int i = 0; i < fQName.length; i++) {
                  fQName[i] = new QName();
              }
              fMark = fPosition = 1;
          } // <init>()
  
          public void resize(){
              /**
               * int length = fElements.length;
               * Element [] temp = new Element[length * 2];
               * System.arraycopy(fElements, 0, temp, 0, length);
               * fElements = temp;
               */
              //resize QNames
              int oldLength = fQName.length;
              QName [] tmp = new QName[oldLength * 2];
              System.arraycopy(fQName, 0, tmp, 0, oldLength);
              fQName = tmp;
  
              for (int i = oldLength; i < fQName.length; i++) {
                  fQName[i] = new QName();
              }
  
          }
  
  
          //
          // Public methods
          //
  
          /** Check if the element scanned during the start element
           *matches the stored element.
           *
           *@return true if the match suceeds.
           */
          public boolean matchElement(QName element) {
              //last depth is the depth when last elemnt was pushed
              //if last depth is greater than current depth
              if(DEBUG_SKIP_ALGORITHM){
                  System.out.println("fLastDepth = " + fLastDepth);
                  System.out.println("fDepth = " + fDepth);
              }
              boolean match = false;
              if(fLastDepth > fDepth && fDepth <= 2){
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("Checking if the elements match " + element.rawname + " , " + fQName[fDepth].rawname);
                  }
                  if(element.rawname == fQName[fDepth].rawname){
                      fAdd = false;
                      //mark this position
                      //decrease the depth by 1 as arrays are 0 based
                      fMark = fDepth - 1;
                      //we found the match and from next element skipping will start, add 1
                      fPosition = fMark + 1 ;
                      match = true;
                      //Once we get match decrease the count -- this was increased by nextElement()
                      --fCount;
                      if(DEBUG_SKIP_ALGORITHM){
                          System.out.println("fAdd FALSE -- NOW ELEMENT SHOULD NOT BE ADDED");
                          System.out.println("fMark = " + fMark);
                          System.out.println("fPosition = " + fPosition);
                          System.out.println("fDepth = " + fDepth);
                          System.out.println("fCount = " + fCount);
                      }
                  }else{
                      fAdd = true;
                      if(DEBUG_SKIP_ALGORITHM)System.out.println("fAdd is " + fAdd);
                  }
              }
              //store the last depth
              fLastDepth = fDepth++;
              return match;
          } // pushElement(QName):QName
  
          /**
           * This function doesn't increase depth. The function in this function is
           *broken down into two functions for efficiency. <@see>matchElement</see>.
           * This function just returns the pointer to the object and its values are set.
           *
           *@return QName reference to the next element in the list
           */
          public QName nextElement() {
  
              //if number of elements becomes equal to the length of array -- stop the skipping
              if (fCount == fQName.length) {
                  fShouldSkip = false;
                  fAdd = false;
                  if(DEBUG_SKIP_ALGORITHM)System.out.println("SKIPPING STOPPED, fShouldSkip = " + fShouldSkip);
                  //xxx: this is not correct, we are returning the last element
                  //this wont make any difference since flag has been set to 'false'
                  return fQName[--fCount];
              }
              if(DEBUG_SKIP_ALGORITHM){
                  System.out.println("fCount = " + fCount);
              }
              return fQName[fCount++];
  
          }
  
          /** Note that this function is considerably different than nextElement()
           * This function just returns the previously stored elements
           */
          public QName getNext(){
              //when position reaches number of elements in the list..
              //set the position back to mark,  making it a circular linked list.
              if(fPosition == fCount){
                  fPosition = fMark;
              }
              return fQName[fPosition++];
          }
  
          /** returns the current depth
           */
          public int popElement(){
              return fDepth--;
          }
  
  
          /** Clears the stack without throwing away existing QName objects. */
          public void clear() {
              fLastDepth = 0;
              fDepth = 0;
              fCount = 0 ;
              fPosition = fMark = 1;
          } // clear()
  
      } // class ElementStack
  
      /**
       * Element stack. This stack operates without synchronization, error
       * checking, and it re-uses objects instead of throwing popped items
       * away.
       *
       * @author Andy Clark, IBM
       */
      protected class ElementStack {
  
          //
          // Data
          //
  
          /** The stack data. */
          protected QName[] fElements;
          protected int []  fInt = new int[20];
  
  
          //Element depth
          protected int fDepth;
          //total number of elements
          protected int fCount;
          //current position
          protected int fPosition;
          //Mark refers to the position
          protected int fMark;
  
          protected int fLastDepth ;
  
          //
          // Constructors
          //
  
          /** Default constructor. */
          public ElementStack() {
              fElements = new QName[20];
              for (int i = 0; i < fElements.length; i++) {
                  fElements[i] = new QName();
              }
          } // <init>()
  
          //
          // Public methods
          //
  
          /**
           * Pushes an element on the stack.
           * <p>
           * <strong>Note:</strong> The QName values are copied into the
           * stack. In other words, the caller does <em>not</em> orphan
           * the element to the stack. Also, the QName object returned
           * is <em>not</em> orphaned to the caller. It should be
           * considered read-only.
           *
           * @param element The element to push onto the stack.
           *
           * @return Returns the actual QName object that stores the
           */
          //XXX: THIS FUNCTION IS NOT USED
          public QName pushElement(QName element) {
              if (fDepth == fElements.length) {
                  QName[] array = new QName[fElements.length * 2];
                  System.arraycopy(fElements, 0, array, 0, fDepth);
                  fElements = array;
                  for (int i = fDepth; i < fElements.length; i++) {
                      fElements[i] = new QName();
                  }
              }
              fElements[fDepth].setValues(element);
              return fElements[fDepth++];
          } // pushElement(QName):QName
  
  
          /** Note that this function is considerably different than nextElement()
           * This function just returns the previously stored elements
           */
          public QName getNext(){
              //when position reaches number of elements in the list..
              //set the position back to mark,  making it a circular linked list.
              if(fPosition == fCount){
                  fPosition = fMark;
              }
              //store the position of last opened tag at particular depth
              //fInt[++fDepth] = fPosition;
              if(DEBUG_SKIP_ALGORITHM){
                  System.out.println("Element at fPosition = " + fPosition + " is " + fElements[fPosition].rawname);
              }
              //return fElements[fPosition++];
              return fElements[fPosition];
          }
  
          /** This function should be called only when element was skipped sucessfully.
           * 1. Increase the depth - because element was sucessfully skipped.
           *2. Store the position of the element token in array  "last opened tag" at depth.
           *3. increase the position counter so as to point to the next element in the array
           */
          public void push(){
  
              fInt[++fDepth] = fPosition++;
          }
  
          /** Check if the element scanned during the start element
           *matches the stored element.
           *
           *@return true if the match suceeds.
           */
          public boolean matchElement(QName element) {
              //last depth is the depth when last elemnt was pushed
              //if last depth is greater than current depth
              //if(DEBUG_SKIP_ALGORITHM){
              //   System.out.println("Check if the element " + element.rawname + " matches");
              //  System.out.println("fLastDepth = " + fLastDepth);
              // System.out.println("fDepth = " + fDepth);
              //}
              boolean match = false;
              if(fLastDepth > fDepth && fDepth <= 3){
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("----------ENTERED THE LOOP WHERE WE CHECK FOR MATCHING OF ELMENT-----");
                      System.out.println("Depth = " + fDepth + " Checking if INCOMING element " + element.rawname + " match STORED ELEMENT " + fElements[fDepth - 1].rawname);
                  }
                  if(element.rawname == fElements[fDepth - 1].rawname){
                      fAdd = false;
                      //mark this position
                      //decrease the depth by 1 as arrays are 0 based
                      fMark = fDepth - 1;
                      //we found the match
                      fPosition = fMark;
                      match = true;
                      //Once we get match decrease the count -- this was increased by nextElement()
                      --fCount;
                      if(DEBUG_SKIP_ALGORITHM){
                          System.out.println("NOW ELEMENT SHOULD NOT BE ADDED, fAdd is set to false");
                          System.out.println("fMark = " + fMark);
                          System.out.println("fPosition = " + fPosition);
                          System.out.println("fDepth = " + fDepth);
                          System.out.println("fCount = " + fCount);
                          System.out.println("---------MATCH SUCEEDED-----------------");
                          System.out.println("");
                      }
                  }else{
                      fAdd = true;
                      if(DEBUG_SKIP_ALGORITHM)System.out.println("fAdd is " + fAdd);
                  }
              }
              //store the position for the current depth
              //when we are adding the elements, when skipping
              //starts even then this should be tracked ie. when
              //calling getNext()
              if(match){
                  //from next element skipping will start, add 1
                  fInt[fDepth] = fPosition++;
              } else{
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("At depth = " + fDepth + "array position is = " + (fCount - 1));
                  }
                  //sicne fInt[fDepth] contains pointer to the element array which are 0 based.
                  fInt[fDepth] = fCount - 1;
              }
  
              //if number of elements becomes equal to the length of array -- stop the skipping
              //xxx: should we do "fCount == fInt.length"
              if (fCount == fElements.length) {
                  fSkip = false;
                  fAdd = false;
                  //reposition the stack -- it seems to be too complex document and there is no symmerty in structure
                  reposition();
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("ALL THE ELMENTS IN ARRAY HAVE BEEN FILLED");
                      System.out.println("REPOSITIONING THE STACK");
                      System.out.println("-----------SKIPPING STOPPED----------");
                      System.out.println("");
                  }
                  return false;
              }
              if(DEBUG_SKIP_ALGORITHM){
                  if(match){
                      System.out.println("Storing fPosition = " + fInt[fDepth] + " at fDepth = " + fDepth);
                  }else{
                      System.out.println("Storing fCount = " + fInt[fDepth] + " at fDepth = " + fDepth);
                  }
              }
              //store the last depth
              fLastDepth = fDepth;
              return match;
          } // matchElement(QName):QName
  
  
          /**
           * Returns the next element on the stack.
           *
           * @return Returns the actual QName object. Callee should
           * use this object to store the details of next element encountered.
           */
          public QName nextElement() {
              if(fSkip){
                  fDepth++;
                  //boundary checks are done in matchElement()
                  return fElements[fCount++];
              } else if (fDepth == fElements.length) {
                  QName[] array = new QName[fElements.length * 2];
                  System.arraycopy(fElements, 0, array, 0, fDepth);
                  fElements = array;
                  for (int i = fDepth; i < fElements.length; i++) {
                      fElements[i] = new QName();
                  }
              }
  
              return fElements[fDepth++];
  
          } // pushElement(QName):QName
  
  
          /**
           * Pops an element off of the stack by setting the values of
           * the specified QName.
           * <p>
           * <strong>Note:</strong> The object returned is <em>not</em>
           * orphaned to the caller. Therefore, the caller should consider
           * the object to be read-only.
           */
          public QName popElement() {
              //return the same object that was pushed -- this would avoid
              //setting the values for every end element.
              //STRONG: this object is read only -- this object reference shouldn't be stored.
              if(fSkip || fAdd ){
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("POPPING Element, at position " + fInt[fDepth] + " element at that count is = " + fElements[fInt[fDepth]].rawname);
                      System.out.println("");
                  }
                  return fElements[fInt[fDepth--]];
              } else{
                  if(DEBUG_SKIP_ALGORITHM){
                      System.out.println("Retrieveing element at depth = " + fDepth + " is " + fElements[fDepth].rawname );
                  }
                  return fElements[--fDepth] ;
              }
              //element.setValues(fElements[--fDepth]);
          } // popElement(QName)
  
          /** Reposition the stack. fInt [] contains all the opened tags at particular depth.
           * Transfer all the opened tags starting from depth '2' to the current depth and reposition them
           *as per the depth.
           */
          public void reposition(){
              for( int i = 2 ; i <= fDepth ; i++){
                  fElements[i-1] = fElements[fInt[i]];
              }
              if(DEBUG_SKIP_ALGORITHM){
                  for( int i = 0 ; i < fDepth ; i++){
                      System.out.println("fElements[" + i + "]" + " = " + fElements[i].rawname);
                  }
              }
          }
  
          /** Clears the stack without throwing away existing QName objects. */
          public void clear() {
              fDepth = 0;
              fLastDepth = 0;
              fCount = 0 ;
              fPosition = fMark = 1;
  
          } // clear()
  
          /**
           * This function is as a result of optimization done for endElement --
           * we dont need to set the value for every end element encouterd.
           * For Well formedness checks we can have the same QName object that was pushed.
           * the values will be set only if application need to know about the endElement
           * -- neeraj.bajaj@sun.com
           */
  
          public QName getLastPoppedElement(){
              return fElements[fDepth];
          }
      } // class ElementStack
  
      /**
       * Drives the parser to the next state/event on the input. Parser is guaranteed
       * to stop at the next state/event.
       *
       * Internally XML document is divided into several states. Each state represents
       * a sections of XML document. When this functions returns normally, it has read
       * the section of XML document and returns the state corresponding to section of
       * document which has been read. For optimizations, a particular driver
       * can read ahead of the section of document (state returned) just read and
       * can maintain a different internal state.
       *
       *
       * @author Neeraj Bajaj, Sun Microsystems
       */
      protected interface Driver {
  
  
          /**
           * Drives the parser to the next state/event on the input. Parser is guaranteed
           * to stop at the next state/event.
           *
           * Internally XML document is divided into several states. Each state represents
           * a sections of XML document. When this functions returns normally, it has read
           * the section of XML document and returns the state corresponding to section of
           * document which has been read. For optimizations, a particular driver
           * can read ahead of the section of document (state returned) just read and
           * can maintain a different internal state.
           *
           * @return state representing the section of document just read.
           *
           * @throws IOException  Thrown on i/o error.
           * @throws XNIException Thrown on parse error.
           */
  
          public int next() throws IOException, XNIException;
  
      } // interface Driver
  
      /**
       * Driver to handle content scanning. This driver is capable of reading
       * the fragment of XML document. When it has finished reading fragment
       * of XML documents, it can pass the job of reading to another driver.
       *
       * This class has been modified as per the new design which is more suited to
       * efficiently build pull parser. Lot of performance improvements have been done and
       * the code has been added to support stax functionality/features.
       *
       * @author Neeraj Bajaj, Sun Microsystems
       *
       *
       * @author Andy Clark, IBM
       * @author Eric Ye, IBM
       */
      protected class FragmentContentDriver
              implements Driver {
  
          //
          // Driver methods
          //
          private boolean fContinueDispatching = true;
          private boolean fScanningForMarkup = true;
  
          /**
           *  decides the appropriate state of the parser
           */
          private void startOfMarkup() throws IOException {
              fMarkupDepth++;
              final int ch = fEntityScanner.peekChar();
  
              switch(ch){
                  case '?' :{
                      setScannerState(SCANNER_STATE_PI);
                      fEntityScanner.skipChar(ch);
                      break;
                  }
                  case '!' :{
                      fEntityScanner.skipChar(ch);
                      if (fEntityScanner.skipChar('-')) {
                          if (!fEntityScanner.skipChar('-')) {
                              reportFatalError("InvalidCommentStart",
                                      null);
                          }
                          setScannerState(SCANNER_STATE_COMMENT);
                      } else if (fEntityScanner.skipString(cdata)) {
                          setScannerState(SCANNER_STATE_CDATA );
                      } else if (!scanForDoctypeHook()) {
                          reportFatalError("MarkupNotRecognizedInContent",
                                  null);
                      }
                      break;
                  }
                  case '/' :{
                      setScannerState(SCANNER_STATE_END_ELEMENT_TAG);
                      fEntityScanner.skipChar(ch);
                      break;
                  }
                  default :{
                      if (isValidNameStartChar(ch)) {
                          setScannerState(SCANNER_STATE_START_ELEMENT_TAG);
                      } else {
                          reportFatalError("MarkupNotRecognizedInContent",
                                  null);
                      }
                  }
              }
  
          }//startOfMarkup
  
          private void startOfContent() throws IOException {
              if (fEntityScanner.skipChar('<')) {
                  setScannerState(SCANNER_STATE_START_OF_MARKUP);
              } else if (fEntityScanner.skipChar('&')) {
                  setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
              } else {
                  //element content is there..
                  setScannerState(SCANNER_STATE_CHARACTER_DATA);
              }
          }//startOfContent
  
  
          /**
           *
           * SCANNER_STATE_CONTENT and SCANNER_STATE_START_OF_MARKUP are two super states of the parser.
           * At any point of time when in doubt over the current state of the parser, the state should be
           * set to SCANNER_STATE_CONTENT. Parser will automatically revive itself and will set state of
           * the parser to one of its sub state.
           * sub states are defined in the parser on the basis of different XML component like
           * SCANNER_STATE_ENTITY_REFERENCE , SCANNER_STATE_START_ELEMENT, SCANNER_STATE_CDATA etc..
           * These sub states help the parser to have fine control over the parsing. These are the
           * different milepost, parser stops at each sub state (milepost). Based on this state it is
           * decided if paresr needs to stop at next milepost ??
           *
           */
          public void decideSubState() throws IOException {
              while( fScannerState == SCANNER_STATE_CONTENT || fScannerState == SCANNER_STATE_START_OF_MARKUP){
  
                  switch (fScannerState) {
  
                      case SCANNER_STATE_CONTENT: {
                          startOfContent() ;
                          break;
                      }
  
                      case SCANNER_STATE_START_OF_MARKUP: {
                          startOfMarkup() ;
                          break;
                      }
                  }
              }
          }//decideSubState
  
          /**
           * Drives the parser to the next state/event on the input. Parser is guaranteed
           * to stop at the next state/event. Internally XML document
           * is divided into several states. Each state represents a sections of XML
           * document. When this functions returns normally, it has read the section
           * of XML document and returns the state corresponding to section of
           * document which has been read. For optimizations, a particular driver
           * can read ahead of the section of document (state returned) just read and
           * can maintain a different internal state.
           *
           * State returned corresponds to Stax states.
           *
           * @return state representing the section of document just read.
           *
           * @throws IOException  Thrown on i/o error.
           * @throws XNIException Thrown on parse error.
           */
  
          public int next() throws IOException, XNIException {
              while (true) {
              try {
                  if(DEBUG_NEXT){
                      System.out.println("NOW IN FragmentContentDriver");
                      System.out.println("Entering the FragmentContentDriver with = " + getScannerStateName(fScannerState));
                  }
  
                  //decide the actual sub state of the scanner.For more information refer to the javadoc of
                  //decideSubState.
  
                  switch (fScannerState) {
                      case SCANNER_STATE_CONTENT: {
                          final int ch = fEntityScanner.peekChar();
                          if (ch == '<') {
                              fEntityScanner.scanChar();
                              setScannerState(SCANNER_STATE_START_OF_MARKUP);
                          } else if (ch == '&') {
                              fEntityScanner.scanChar();
                              setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
                              break;
                          } else {
                              //element content is there..
                              setScannerState(SCANNER_STATE_CHARACTER_DATA);
                              break;
                          }
                      }
  
                      case SCANNER_STATE_START_OF_MARKUP: {
                          startOfMarkup();
                          break;
                      }//case: SCANNER_STATE_START_OF_MARKUP
  
                  }//end of switch
                  //decideSubState() ;
  
                  //do some special handling if isCoalesce is set to true.
                  if(fIsCoalesce){
                      fUsebuffer = true ;
                      //if the last section was character data
                      if(fLastSectionWasCharacterData){
  
                          //if we dont encounter any CDATA or ENITY REFERENCE and current state is also not SCANNER_STATE_CHARACTER_DATA
                          //return the last scanned charactrer data.
                          if((fScannerState != SCANNER_STATE_CDATA) && (fScannerState != SCANNER_STATE_REFERENCE)
                          && (fScannerState != SCANNER_STATE_CHARACTER_DATA)){
                              fLastSectionWasCharacterData = false;
                              return XMLEvent.CHARACTERS;
                          }
                      }//if last section was CDATA or ENTITY REFERENCE
                      //xxx: there might be another entity reference or CDATA after this
                      //<foo>blah blah &amp;&lt;<![CDATA[[aa]]>blah blah</foo>
                      else if((fLastSectionWasCData || fLastSectionWasEntityReference)){
                          //and current state is not SCANNER_STATE_CHARACTER_DATA
                          //or SCANNER_STATE_CDATA or SCANNER_STATE_REFERENCE
                          //this means there is nothing more to be coalesced.
                          //return the CHARACTERS event.
                          if((fScannerState != SCANNER_STATE_CDATA) && (fScannerState != SCANNER_STATE_REFERENCE)
                          && (fScannerState != SCANNER_STATE_CHARACTER_DATA)){
  
                              fLastSectionWasCData = false;
                              fLastSectionWasEntityReference = false;
                              return XMLEvent.CHARACTERS;
                          }
                      }
                  }
  
  
                  if(DEBUG_NEXT){
                      System.out.println("Actual scanner state set by decideSubState is = " + getScannerStateName(fScannerState));
                  }
  
                  switch(fScannerState){
  
                      case XMLEvent.START_DOCUMENT :
                          return XMLEvent.START_DOCUMENT;
  
                      case SCANNER_STATE_START_ELEMENT_TAG :{
  
                          //xxx this function returns true when element is empty.. can be linked to end element event.
                          //returns true if the element is empty
                          fEmptyElement = scanStartElement() ;
                          //if the element is empty the next event is "end element"
                          if(fEmptyElement){
                              setScannerState(SCANNER_STATE_END_ELEMENT_TAG);
                          }else{
                              //set the next possible state
                              setScannerState(SCANNER_STATE_CONTENT);
                          }
                          return XMLEvent.START_ELEMENT ;
                      }
  
                      case SCANNER_STATE_CHARACTER_DATA: {
                          if(DEBUG_COALESCE){
                              System.out.println("fLastSectionWasCData = " + fLastSectionWasCData);
                              System.out.println("fIsCoalesce = " + fIsCoalesce);
                          }
                          //if last section was either entity reference or cdata or character data we should be using buffer
                          fUsebuffer = fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData ;
  
                          //When coalesce is set to true and last state was REFERENCE or CDATA or CHARACTER_DATA, buffer should not be cleared.
                          if( fIsCoalesce && (fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData) ){
                              fLastSectionWasEntityReference = false;
                              fLastSectionWasCData = false;
                              fLastSectionWasCharacterData = true ;
                              fUsebuffer = true;
                          }else{
                              //clear the buffer
                              fContentBuffer.clear();
                          }
  
                          //set the fTempString length to 0 before passing it on to scanContent
                          //scanContent sets the correct co-ordinates as per the content read
                          fTempString.length = 0;
                          int c = fEntityScanner.scanContent(fTempString);
                          if(DEBUG){
                              System.out.println("fTempString = " + fTempString);
                          }
                          if(fEntityScanner.skipChar('<')){
                              //check if we have reached end of element
                              if(fEntityScanner.skipChar('/')){
                                  //increase the mark up depth
                                  fMarkupDepth++;
                                  fLastSectionWasCharacterData = false;
                                  setScannerState(SCANNER_STATE_END_ELEMENT_TAG);
                                  //check if its start of new element
                              }else if(XMLChar.isNameStart(fEntityScanner.peekChar())){
                                  fMarkupDepth++;
                                  fLastSectionWasCharacterData = false;
                                  setScannerState(SCANNER_STATE_START_ELEMENT_TAG);
                              }else{
                                  setScannerState(SCANNER_STATE_START_OF_MARKUP);
                                  //there can be cdata ahead if coalesce is true we should call again
                                  if(fIsCoalesce){
                                      fUsebuffer = true;
                                      fLastSectionWasCharacterData = true;
                                      fContentBuffer.append(fTempString);
                                      fTempString.length = 0;
                                      continue;
                                  }
                              }
                              //in case last section was either entity reference or cdata or character data -- we should be using buffer
                              if(fUsebuffer){
                                  fContentBuffer.append(fTempString);
                                  fTempString.length = 0;
                              }
                              if(DEBUG){
                                  System.out.println("NOT USING THE BUFFER, STRING = " + fTempString.toString());
                              }
                              //check limit before returning event
                              checkLimit(fContentBuffer);
                              if(dtdGrammarUtil!= null && dtdGrammarUtil.isIgnorableWhiteSpace(fContentBuffer)){
                                  if(DEBUG)System.out.println("Return SPACE EVENT");
                                  return XMLEvent.SPACE;
                              }else
                                  return XMLEvent.CHARACTERS;
  
                          } else{
                              fUsebuffer = true ;
                              if(DEBUG){
                                  System.out.println("fContentBuffer = " + fContentBuffer);
                                  System.out.println("fTempString = " + fTempString);
                              }
                              fContentBuffer.append(fTempString);
                              fTempString.length = 0;
                          }
                          if (c == '\r') {
                              if(DEBUG){
                                  System.out.println("'\r' character found");
                              }
                              // happens when there is the character reference &#13;
                              //xxx: We know the next chracter.. we should just skip it and add ']' directlry
                              fEntityScanner.scanChar();
                              fUsebuffer = true;
                              fContentBuffer.append((char)c);
                              c = -1 ;
                          } else if (c == ']') {
                              //fStringBuffer.clear();
                              //xxx: We know the next chracter.. we should just skip it and add ']' directlry
                              fUsebuffer = true;
                              fContentBuffer.append((char)fEntityScanner.scanChar());
                              // remember where we are in case we get an endEntity before we
                              // could flush the buffer out - this happens when we're parsing an
                              // entity which ends with a ]
                              fInScanContent = true;
  
                              // We work on a single character basis to handle cases such as:
                              // ']]]>' which we might otherwise miss.
                              //
                              if (fEntityScanner.skipChar(']')) {
                                  fContentBuffer.append(']');
                                  while (fEntityScanner.skipChar(']')) {
                                      fContentBuffer.append(']');
                                  }
                                  if (fEntityScanner.skipChar('>')) {
                                      reportFatalError("CDEndInContent", null);
                                  }
                              }
                              c = -1 ;
                              fInScanContent = false;
                          }
  
                          do{
                              //xxx: we should be using only one buffer..
                              // we need not to grow the buffer only when isCoalesce() is not true;
  
                              if (c == '<') {
                                  fEntityScanner.scanChar();
                                  setScannerState(SCANNER_STATE_START_OF_MARKUP);
                                  break;
                              }//xxx what should be the behavior if entity reference is present in the content ?
                              else if (c == '&') {
                                  fEntityScanner.scanChar();
                                  setScannerState(SCANNER_STATE_REFERENCE);
                                  break;
                              }///xxx since this part is also characters, it should be merged...
                              else if (c != -1 && isInvalidLiteral(c)) {
                                  if (XMLChar.isHighSurrogate(c)) {
                                      // special case: surrogates
                                      scanSurrogates(fContentBuffer) ;
                                      setScannerState(SCANNER_STATE_CONTENT);
                                  } else {
                                      reportFatalError("InvalidCharInContent",
                                              new Object[] {
                                          Integer.toString(c, 16)});
                                          fEntityScanner.scanChar();
                                  }
                                  break;
                              }
                              //xxx: scanContent also gives character callback.
                              c = scanContent(fContentBuffer) ;
                              //we should not be iterating again if fIsCoalesce is not set to true
  
                              if(!fIsCoalesce){
                                  setScannerState(SCANNER_STATE_CONTENT);
                                  break;
                              }
  
                          }while(true);
  
                          //if (fDocumentHandler != null) {
                          //  fDocumentHandler.characters(fContentBuffer, null);
                          //}
                          if(DEBUG)System.out.println("USING THE BUFFER, STRING START=" + fContentBuffer.toString() +"=END");
                          //if fIsCoalesce is true there might be more data so call fDriver.next()
                          if(fIsCoalesce){
                              fLastSectionWasCharacterData = true ;
                              continue;
                          }else{
                              //check limit before returning event
                              checkLimit(fContentBuffer);
                              if(dtdGrammarUtil!= null && dtdGrammarUtil.isIgnorableWhiteSpace(fContentBuffer)){
                                  if(DEBUG)System.out.println("Return SPACE EVENT");
                                  return XMLEvent.SPACE;
                              } else
                                  return XMLEvent.CHARACTERS ;
                          }
                      }
  
                      case SCANNER_STATE_END_ELEMENT_TAG :{
                          if(fEmptyElement){
                              //set it back to false.
                              fEmptyElement = false;
                              setScannerState(SCANNER_STATE_CONTENT);
                              //check the case when there is comment after single element document
                              //<foo/> and some comment after this
                              return (fMarkupDepth == 0 && elementDepthIsZeroHook() ) ? XMLEvent.END_ELEMENT : XMLEvent.END_ELEMENT ;
  
                          } else if(scanEndElement() == 0) {
                              //It is last element of the document
                              if (elementDepthIsZeroHook()) {
                                  //if element depth is zero , it indicates the end of the document
                                  //the state shouldn't be set, because it is set by elementDepthIsZeroHook() function
                                  //xxx understand this point once again..
                                  return XMLEvent.END_ELEMENT ;
                              }
  
                          }
                          setScannerState(SCANNER_STATE_CONTENT);
                          return XMLEvent.END_ELEMENT ;
                      }
  
                      case SCANNER_STATE_COMMENT: { //SCANNER_STATE_COMMENT:
                          scanComment();
                          setScannerState(SCANNER_STATE_CONTENT);
                          return XMLEvent.COMMENT;
                          //break;
                      }
                      case SCANNER_STATE_PI:{ //SCANNER_STATE_PI: {
                          //clear the buffer first
                          fContentBuffer.clear() ;
                          //xxx: which buffer should be passed. Ideally we shouldn't have
                          //more than two buffers --
                          //xxx: where should we add the switch for buffering.
                          scanPI(fContentBuffer);
                          setScannerState(SCANNER_STATE_CONTENT);
                          return XMLEvent.PROCESSING_INSTRUCTION;
                          //break;
                      }
                      case SCANNER_STATE_CDATA :{ //SCANNER_STATE_CDATA: {
                          //xxx: What if CDATA is the first event
                          //<foo><![CDATA[hello<><>]]>append</foo>
  
                          //we should not clear the buffer only when the last state was either SCANNER_STATE_REFERENCE or
                          //SCANNER_STATE_CHARACTER_DATA or SCANNER_STATE_REFERENCE
                          if(fIsCoalesce && ( fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData)){
                              fLastSectionWasCData = true ;
                              fLastSectionWasEntityReference = false;
                              fLastSectionWasCharacterData = false;
                          }//if we dont need to coalesce clear the buffer
                          else{
                              fContentBuffer.clear();
                          }
                          fUsebuffer = true;
                          //CDATA section is completely read in all the case.
                          scanCDATASection(fContentBuffer , true);
                          setScannerState(SCANNER_STATE_CONTENT);
                          //1. if fIsCoalesce is set to true we set the variable fLastSectionWasCData to true
                          //and just call fDispatche.next(). Since we have set the scanner state to
                          //SCANNER_STATE_CONTENT (super state) parser will automatically recover and
                          //behave appropriately. When isCoalesce is set to true we dont need to reportCDATA event
                          //2. Check if application has set for reporting CDATA event
                          //3. if the application has neither set the fIsCoalesce to true nor fReportCdataEvent
                          //return the cdata event as characters.
                          if(fIsCoalesce){
                              fLastSectionWasCData = true ;
                              //there might be more data to coalesce.
                              continue;
                          }else if(fReportCdataEvent){
                              return XMLEvent.CDATA;
                          } else{
                              return XMLEvent.CHARACTERS;
                          }
                      }
  
                      case SCANNER_STATE_REFERENCE :{
                          fMarkupDepth++;
                          foundBuiltInRefs = false;
  
                          //we should not clear the buffer only when the last state was either CDATA or
                          //SCANNER_STATE_CHARACTER_DATA or SCANNER_STATE_REFERENCE
                          if(fIsCoalesce && ( fLastSectionWasEntityReference || fLastSectionWasCData || fLastSectionWasCharacterData)){
                              //fLastSectionWasEntityReference or fLastSectionWasCData are only
                              //used when fIsCoalesce is set to true.
                              fLastSectionWasEntityReference = true ;
                              fLastSectionWasCData = false;
                              fLastSectionWasCharacterData = false;
                          }//if we dont need to coalesce clear the buffer
                          else{
                              fContentBuffer.clear();
                          }
                          fUsebuffer = true ;
                          //take care of character reference
                          if (fEntityScanner.skipChar('#')) {
                              scanCharReferenceValue(fContentBuffer, null);
                              fMarkupDepth--;
                              if(!fIsCoalesce){
                                  setScannerState(SCANNER_STATE_CONTENT);
                                  return XMLEvent.CHARACTERS;
                              }
                          } else {
                              // this function also starts new entity
                              scanEntityReference(fContentBuffer);
                              //if there was built-in entity reference & coalesce is not true
                              //return CHARACTERS
                              if(fScannerState == SCANNER_STATE_BUILT_IN_REFS && !fIsCoalesce){
                                  setScannerState(SCANNER_STATE_CONTENT);
                                  return XMLEvent.CHARACTERS;
                              }
  
                              //if there was a text declaration, call next() it will be taken care.
                              if(fScannerState == SCANNER_STATE_TEXT_DECL){
                                  fLastSectionWasEntityReference = true ;
                                  continue;
                              }
  
                              if(fScannerState == SCANNER_STATE_REFERENCE){
                                  setScannerState(SCANNER_STATE_CONTENT);
                                  if (fReplaceEntityReferences && fEntityStore.isDeclaredEntity(fCurrentEntityName)) {
                                      // Skip the entity reference, we don't care
                                      continue;
                                  }
                                  return XMLEvent.ENTITY_REFERENCE;
                              }
                          }
                          //Wether it was character reference, entity reference or built-in entity
                          //set the next possible state to SCANNER_STATE_CONTENT
                          setScannerState(SCANNER_STATE_CONTENT);
                          fLastSectionWasEntityReference = true ;
                          continue;
                      }
  
                      case SCANNER_STATE_TEXT_DECL: {
                          // scan text decl
                          if (fEntityScanner.skipString("<?xml")) {
                              fMarkupDepth++;
                              // NOTE: special case where entity starts with a PI
                              //       whose name starts with "xml" (e.g. "xmlfoo")
                              if (isValidNameChar(fEntityScanner.peekChar())) {
                                  fStringBuffer.clear();
                                  fStringBuffer.append("xml");
  
                                  if (fNamespaces) {
                                      while (isValidNCName(fEntityScanner.peekChar())) {
                                          fStringBuffer.append((char)fEntityScanner.scanChar());
                                      }
                                  } else {
                                      while (isValidNameChar(fEntityScanner.peekChar())) {
                                          fStringBuffer.append((char)fEntityScanner.scanChar());
                                      }
                                  }
                                  String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
                                  fContentBuffer.clear();
                                  scanPIData(target, fContentBuffer);
                              }
  
                              // standard text declaration
                              else {
                                  //xxx: this function gives callback
                                  scanXMLDeclOrTextDecl(true);
                              }
                          }
                          // now that we've straightened out the readers, we can read in chunks:
                          fEntityManager.fCurrentEntity.mayReadChunks = true;
                          setScannerState(SCANNER_STATE_CONTENT);
                          //xxx: we don't return any state, so how do we get to know about TEXT declarations.
                          //it seems we have to careful when to allow function issue a callback
                          //and when to allow adapter issue a callback.
                          continue;
                      }
  
  
                      case SCANNER_STATE_ROOT_ELEMENT: {
                          if (scanRootElementHook()) {
                              fEmptyElement = true;
                              //rest would be taken care by fTrailingMiscDriver set by scanRootElementHook
                              return XMLEvent.START_ELEMENT;
                          }
                          setScannerState(SCANNER_STATE_CONTENT);
                          return XMLEvent.START_ELEMENT ;
                      }
                      case SCANNER_STATE_CHAR_REFERENCE : {
                          fContentBuffer.clear();
                          scanCharReferenceValue(fContentBuffer, null);
                          fMarkupDepth--;
                          setScannerState(SCANNER_STATE_CONTENT);
                          return XMLEvent.CHARACTERS;
                      }
                      default:
                          throw new XNIException("Scanner State " + fScannerState + " not Recognized ");
  
                  }//switch
              }
              // premature end of file
              catch (EOFException e) {
                  endOfFileHook(e);
                  return -1;
              }
              } //while loop
          }//next
  
          /**
           * Add the count of the content buffer and check if the accumulated
           * value exceeds the limit
           * @param buffer content buffer
           */
          protected void checkLimit(XMLStringBuffer buffer) {
              if (fLimitAnalyzer.isTracking(fCurrentEntityName)) {
                  fLimitAnalyzer.addValue(Limit.GENERAL_ENTITY_SIZE_LIMIT, fCurrentEntityName, buffer.length);
                  if (fSecurityManager.isOverLimit(Limit.GENERAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
                      fSecurityManager.debugPrint(fLimitAnalyzer);
                      reportFatalError("MaxEntitySizeLimit", new Object[]{fCurrentEntityName,
                          fLimitAnalyzer.getValue(Limit.GENERAL_ENTITY_SIZE_LIMIT),
                          fSecurityManager.getLimit(Limit.GENERAL_ENTITY_SIZE_LIMIT),
                          fSecurityManager.getStateLiteral(Limit.GENERAL_ENTITY_SIZE_LIMIT)});
                  }
                  if (fSecurityManager.isOverLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
                      fSecurityManager.debugPrint(fLimitAnalyzer);
                      reportFatalError("TotalEntitySizeLimit",
                          new Object[]{fLimitAnalyzer.getTotalValue(Limit.TOTAL_ENTITY_SIZE_LIMIT),
                          fSecurityManager.getLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT),
                          fSecurityManager.getStateLiteral(Limit.TOTAL_ENTITY_SIZE_LIMIT)});
                  }
              }
          }
  
          //
          // Protected methods
          //
  
          // hooks
  
          // NOTE: These hook methods are added so that the full document
          //       scanner can share the majority of code with this class.
  
          /**
           * Scan for DOCTYPE hook. This method is a hook for subclasses
           * to add code to handle scanning for a the "DOCTYPE" string
           * after the string "<!" has been scanned.
           *
           * @return True if the "DOCTYPE" was scanned; false if "DOCTYPE"
           *          was not scanned.
           */
          protected boolean scanForDoctypeHook()
          throws IOException, XNIException {
              return false;
          } // scanForDoctypeHook():boolean
  
          /**
           * Element depth iz zero. This methos is a hook for subclasses
           * to add code to handle when the element depth hits zero. When
           * scanning a document fragment, an element depth of zero is
           * normal. However, when scanning a full XML document, the
           * scanner must handle the trailing miscellanous section of
           * the document after the end of the document's root element.
           *
           * @return True if the caller should stop and return true which
           *          allows the scanner to switch to a new scanning
           *          driver. A return value of false indicates that
           *          the content driver should continue as normal.
           */
          protected boolean elementDepthIsZeroHook()
          throws IOException, XNIException {
              return false;
          } // elementDepthIsZeroHook():boolean
  
          /**
           * Scan for root element hook. This method is a hook for
           * subclasses to add code that handles scanning for the root
           * element. When scanning a document fragment, there is no
           * "root" element. However, when scanning a full XML document,
           * the scanner must handle the root element specially.
           *
           * @return True if the caller should stop and return true which
           *          allows the scanner to switch to a new scanning
           *          driver. A return value of false indicates that
           *          the content driver should continue as normal.
           */
          protected boolean scanRootElementHook()
          throws IOException, XNIException {
              return false;
          } // scanRootElementHook():boolean
  
          /**
           * End of file hook. This method is a hook for subclasses to
           * add code that handles the end of file. The end of file in
           * a document fragment is OK if the markup depth is zero.
           * However, when scanning a full XML document, an end of file
           * is always premature.
           */
          protected void endOfFileHook(EOFException e)
          throws IOException, XNIException {
  
              // NOTE: An end of file is only only an error if we were
              //       in the middle of scanning some markup. -Ac
              if (fMarkupDepth != 0) {
                  reportFatalError("PrematureEOF", null);
              }
  
          } // endOfFileHook()
  
      } // class FragmentContentDriver
  
      static void pr(String str) {
          System.out.println(str) ;
      }
  
      protected boolean fUsebuffer ;
  
      /** this function gets an XMLString (which is used to store the attribute value) from the special pool
       *  maintained for attributes.
       *  fAttributeCacheUsedCount tracks the number of attributes that has been consumed from the pool.
       *  if all the attributes has been consumed, it adds a new XMLString inthe pool and returns the same
       *  XMLString.
       *
       * @return XMLString XMLString used to store an attribute value.
       */
  
      protected XMLString getString(){
          if(fAttributeCacheUsedCount < initialCacheCount || fAttributeCacheUsedCount < attributeValueCache.size()){
              return (XMLString)attributeValueCache.get(fAttributeCacheUsedCount++);
          } else{
              XMLString str = new XMLString();
              fAttributeCacheUsedCount++;
              attributeValueCache.add(str);
              return str;
          }
      }
  
      /**
       * Implements XMLBufferListener interface.
       */
  
      public void refresh(){
          refresh(0);
      }
  
      /**
       * receives callbacks from {@link XMLEntityReader } when buffer
       * is being changed.
       * @param refreshPosition
       */
      public void refresh(int refreshPosition){
          //If you are reading attributes and you got a callback
          //cache available attributes.
          if(fReadingAttributes){
              fAttributes.refresh();
          }
          if(fScannerState == SCANNER_STATE_CHARACTER_DATA){
              //since fTempString directly matches to the underlying main buffer
              //store the data into buffer
              fContentBuffer.append(fTempString);
              //clear the XMLString so that data can't be added again.
              fTempString.length = 0;
              fUsebuffer = true;
          }
      }
  
  } // class XMLDocumentFragmentScannerImpl
  