Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » impl » [javadoc | source]
    1   /*
    2    * Portions Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    */
    4   
    5   /*
    6    * Copyright 2005 The Apache Software Foundation.
    7    *
    8    * Licensed under the Apache License, Version 2.0 (the "License");
    9    * you may not use this file except in compliance with the License.
   10    * You may obtain a copy of the License at
   11    *
   12    *      http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing, software
   15    * distributed under the License is distributed on an "AS IS" BASIS,
   16    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   17    * See the License for the specific language governing permissions and
   18    * limitations under the License.
   19    */
   20   
   21   
   22   package com.sun.org.apache.xerces.internal.impl;
   23   
   24   import com.sun.xml.internal.stream.XMLBufferListener;
   25   import com.sun.xml.internal.stream.XMLEntityStorage;
   26   import com.sun.xml.internal.stream.XMLInputFactoryImpl;
   27   import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
   28   
   29   import java.io.EOFException;
   30   import java.io.IOException;
   31   import javax.xml.stream.XMLInputFactory;
   32   import javax.xml.stream.events.XMLEvent;
   33   import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
   34   import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
   35   import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
   36   import com.sun.org.apache.xerces.internal.util.XMLChar;
   37   import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
   38   import com.sun.org.apache.xerces.internal.util.XMLSymbols;
   39   import com.sun.org.apache.xerces.internal.xni.QName;
   40   import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
   41   import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
   42   import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
   43   import com.sun.org.apache.xerces.internal.xni.XMLString;
   44   import com.sun.org.apache.xerces.internal.xni.XNIException;
   45   import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
   46   import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
   47   import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
   48   import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentScanner;
   49   import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
   50   import com.sun.org.apache.xerces.internal.xni.Augmentations;
   51   import com.sun.org.apache.xerces.internal.impl.Constants;
   52   import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
   53   import com.sun.org.apache.xerces.internal.util.SecurityManager;
   54   import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
   55   import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
   56   import javax.xml.stream.XMLStreamConstants;
   57   import javax.xml.stream.events.XMLEvent;
   58   
   59   /**
   60    *
   61    * This class is responsible for scanning the structure and content
   62    * of document fragments.
   63    *
   64    * This class has been modified as per the new design which is more suited to
   65    * efficiently build pull parser. Lot of improvements have been done and
   66    * the code has been added to support stax functionality/features.
   67    *
   68    * @author Neeraj Bajaj SUN Microsystems
   69    * @author K.Venugopal SUN Microsystems
   70    * @author Glenn Marcy, IBM
   71    * @author Andy Clark, IBM
   72    * @author Arnaud  Le Hors, IBM
   73    * @author Eric Ye, IBM
   74    * @author Sunitha Reddy, SUN Microsystems
   75    *
   76    */
   77   public class XMLDocumentFragmentScannerImpl
   78           extends XMLScanner
   79           implements XMLDocumentScanner, XMLComponent, XMLEntityHandler, XMLBufferListener {
   80   
   81       //
   82       // Constants
   83       //
   84   
   85       protected int fElementAttributeLimit;
   86   
   87       /** External subset resolver. **/
   88       protected ExternalSubsetResolver fExternalSubsetResolver;
   89   
   90       // scanner states
   91   
   92       //XXX this should be divided into more states.
   93       /** Scanner state: start of markup. */
   94       protected static final int SCANNER_STATE_START_OF_MARKUP = 21;
   95   
   96       /** Scanner state: content. */
   97       protected static final int SCANNER_STATE_CONTENT = 22;
   98   
   99       /** Scanner state: processing instruction. */
  100       protected static final int SCANNER_STATE_PI = 23;
  101   
  102       /** Scanner state: DOCTYPE. */
  103       protected static final int SCANNER_STATE_DOCTYPE = 24;
  104   
  105       /** Scanner state: XML Declaration */
  106       protected static final int SCANNER_STATE_XML_DECL = 25;
  107   
  108       /** Scanner state: root element. */
  109       protected static final int SCANNER_STATE_ROOT_ELEMENT = 26;
  110   
  111       /** Scanner state: comment. */
  112       protected static final int SCANNER_STATE_COMMENT = 27;
  113   
  114       /** Scanner state: reference. */
  115       protected static final int SCANNER_STATE_REFERENCE = 28;
  116   
  117       // <book type="hard"> reading attribute name 'type'
  118       protected static final int SCANNER_STATE_ATTRIBUTE = 29;
  119   
  120       // <book type="hard"> //reading attribute value.
  121       protected static final int SCANNER_STATE_ATTRIBUTE_VALUE = 30;
  122   
  123       /** Scanner state: trailing misc. USED BY DOCUMENT_SCANNER_IMPL*/
  124       //protected static final int SCANNER_STATE_TRAILING_MISC = 32;
  125   
  126       /** Scanner state: end of input. */
  127       protected static final int SCANNER_STATE_END_OF_INPUT = 33;
  128   
  129       /** Scanner state: terminated. */
  130       protected static final int SCANNER_STATE_TERMINATED = 34;
  131   
  132       /** Scanner state: CDATA section. */
  133       protected static final int SCANNER_STATE_CDATA = 35;
  134   
  135       /** Scanner state: Text declaration. */
  136       protected static final int SCANNER_STATE_TEXT_DECL = 36;
  137   
  138       /** Scanner state: Text declaration. */
  139       protected static final int SCANNER_STATE_CHARACTER_DATA = 37;
  140   
  141       //<book type="hard">foo</book>
  142       protected static final int SCANNER_STATE_START_ELEMENT_TAG = 38;
  143   
  144       //<book type="hard">foo</book> reading </book>
  145       protected static final int SCANNER_STATE_END_ELEMENT_TAG = 39;
  146   
  147       protected static final int SCANNER_STATE_CHAR_REFERENCE = 40;
  148       protected static final int SCANNER_STATE_BUILT_IN_REFS = 41;
  149   
  150       // feature identifiers
  151   
  152   
  153       /** Feature identifier: notify built-in refereces. */
  154       protected static final String NOTIFY_BUILTIN_REFS =
  155               Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE;
  156   
  157       /** Property identifier: entity resolver. */
  158       protected static final String ENTITY_RESOLVER =
  159               Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
  160   
  161       // recognized features and properties
  162   
  163       /** Recognized features. */
  164       private static final String[] RECOGNIZED_FEATURES = {
  165                   NAMESPACES,
  166                   VALIDATION,
  167                   NOTIFY_BUILTIN_REFS,
  168                   NOTIFY_CHAR_REFS,
  169                   Constants.STAX_REPORT_CDATA_EVENT
  170       };
  171   
  172       /** Feature defaults. */
  173       private static final Boolean[] FEATURE_DEFAULTS = {
  174                   Boolean.TRUE,
  175                   null,
  176                   Boolean.FALSE,
  177                   Boolean.FALSE,
  178                   Boolean.TRUE
  179       };
  180   
  181       /** Recognized properties. */
  182       private static final String[] RECOGNIZED_PROPERTIES = {
  183           SYMBOL_TABLE,
  184                   ERROR_REPORTER,
  185                   ENTITY_MANAGER,
  186       };
  187   
  188       /** Property defaults. */
  189       private static final Object[] PROPERTY_DEFAULTS = {
  190                   null,
  191                   null,
  192                   null,
  193       };
  194   
  195       protected static final char [] cdata = {'[','C','D','A','T','A','['};
  196       protected static final char [] xmlDecl = {'<','?','x','m','l'};
  197       protected static final char [] endTag = {'<','/'};
  198       // debugging
  199   
  200       /** Debug scanner state. */
  201       private static final boolean DEBUG_SCANNER_STATE = false;
  202   
  203       /** Debug driver. */
  204       private static final boolean DEBUG_DISPATCHER = false;
  205   
  206       /** Debug content driver scanning. */
  207       protected static final boolean DEBUG_START_END_ELEMENT = false;
  208   
  209   
  210       /** Debug driver next */
  211       protected static final boolean DEBUG_NEXT = false ;
  212   
  213       /** Debug driver next */
  214       protected static final boolean DEBUG = false;
  215       protected static final boolean DEBUG_COALESCE = false;
  216       //
  217       // Data
  218       //
  219   
  220       // protected data
  221   
  222       /** Document handler. */
  223       protected XMLDocumentHandler fDocumentHandler;
  224       protected int fScannerLastState ;
  225   
  226       /** Entity Storage */
  227       protected XMLEntityStorage fEntityStore;
  228   
  229       /** Entity stack. */
  230       protected int[] fEntityStack = new int[4];
  231   
  232       /** Markup depth. */
  233       protected int fMarkupDepth;
  234   
  235       //is the element empty
  236       protected boolean fEmptyElement ;
  237   
  238       //track if we are reading attributes, this is usefule while
  239       //there is a callback
  240       protected boolean fReadingAttributes = false;
  241   
  242       /** Scanner state. */
  243       protected int fScannerState;
  244   
  245       /** SubScanner state: inside scanContent method. */
  246       protected boolean fInScanContent = false;
  247       protected boolean fLastSectionWasCData = false;
  248       protected boolean fLastSectionWasEntityReference = false;
  249       protected boolean fLastSectionWasCharacterData = false;
  250   
  251       /** has external dtd */
  252       protected boolean fHasExternalDTD;
  253   
  254       /** Standalone. */
  255       protected boolean fStandalone;
  256       protected String fVersion;
  257   
  258       // element information
  259   
  260       /** Current element. */
  261       protected QName fCurrentElement;
  262   
  263       /** Element stack. */
  264       protected ElementStack fElementStack = new ElementStack();
  265       protected ElementStack2 fElementStack2 = new ElementStack2();
  266   
  267       // other info
  268   
  269       /** Document system identifier.
  270        * REVISIT:  So what's this used for?  - NG
  271        * protected String fDocumentSystemId;
  272        ******/
  273   
  274       protected String fPITarget ;
  275   
  276       //xxx do we need to create an extra XMLString object... look for using fTempString for collecting all the data values
  277       protected XMLString fPIData  = new XMLString();
  278   
  279       // features
  280   
  281   
  282       /** Notify built-in references. */
  283       protected boolean fNotifyBuiltInRefs = false;
  284   
  285       //STAX related properties
  286       //defaultValues.
  287       protected boolean fReplaceEntityReferences = true;
  288       protected boolean fSupportExternalEntities = false;
  289       protected boolean fReportCdataEvent = false ;
  290       protected boolean fIsCoalesce = false ;
  291       protected String fDeclaredEncoding =  null;
  292   
  293       // drivers
  294   
  295       /** Active driver. */
  296       protected Driver fDriver;
  297   
  298       /** Content driver. */
  299       protected Driver fContentDriver = createContentDriver();
  300   
  301       // temporary variables
  302   
  303       /** Element QName. */
  304       protected QName fElementQName = new QName();
  305   
  306       /** Attribute QName. */
  307       protected QName fAttributeQName = new QName();
  308   
  309       /**
  310        * CHANGED: Using XMLAttributesIteratorImpl instead of XMLAttributesImpl. This class
  311        * implements Iterator interface so we can directly give Attributes in the form of
  312        * iterator.
  313        */
  314       protected XMLAttributesIteratorImpl fAttributes = new XMLAttributesIteratorImpl();
  315   
  316   
  317       /** String. */
  318       protected XMLString fTempString = new XMLString();
  319   
  320       /** String. */
  321       protected XMLString fTempString2 = new XMLString();
  322   
  323       /** Array of 3 strings. */
  324       private String[] fStrings = new String[3];
  325   
  326       /** Making the buffer accesible to derived class -- String buffer. */
  327       protected XMLStringBuffer fStringBuffer = new XMLStringBuffer();
  328   
  329       /** Making the buffer accesible to derived class -- String buffer. */
  330       protected XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
  331   
  332       /** stores character data. */
  333       /** Making the buffer accesible to derived class -- stores PI data */
  334       protected XMLStringBuffer fContentBuffer = new XMLStringBuffer();
  335   
  336       /** Single character array. */
  337       private final char[] fSingleChar = new char[1];
  338       private String fCurrentEntityName = null;
  339   
  340       // New members
  341       protected boolean fScanToEnd = false;
  342   
  343       protected DTDGrammarUtil dtdGrammarUtil= null;
  344   
  345       protected boolean fAddDefaultAttr = false;
  346   
  347       protected boolean foundBuiltInRefs = false;
  348   
  349       protected SecurityManager fSecurityManager = null;
  350   
  351       //skip element algorithm
  352       static final short MAX_DEPTH_LIMIT = 5 ;
  353       static final short ELEMENT_ARRAY_LENGTH = 200 ;
  354       static final short MAX_POINTER_AT_A_DEPTH = 4 ;
  355       static final boolean DEBUG_SKIP_ALGORITHM = false;
  356       //create a elemnet array of length equal to ELEMENT_ARRAY_LENGTH
  357       String [] fElementArray = new String[ELEMENT_ARRAY_LENGTH] ;
  358       //pointer location where last element was skipped
  359       short fLastPointerLocation = 0 ;
  360       short fElementPointer = 0 ;
  361       //2D array to store pointer info
  362       short [] [] fPointerInfo = new short[MAX_DEPTH_LIMIT] [MAX_POINTER_AT_A_DEPTH] ;
  363       protected String fElementRawname ;
  364       protected boolean fShouldSkip = false;
  365       protected boolean fAdd = false ;
  366       protected boolean fSkip = false;
  367   
  368       /** Reusable Augmentations. */
  369       private Augmentations fTempAugmentations = null;
  370       //
  371       // Constructors
  372       //
  373   
  374       /** Default constructor. */
  375       public XMLDocumentFragmentScannerImpl() {
  376       } // <init>()
  377   
  378       //
  379       // XMLDocumentScanner methods
  380       //
  381   
  382       /**
  383        * Sets the input source.
  384        *
  385        * @param inputSource The input source.
  386        *
  387        * @throws IOException Thrown on i/o error.
  388        */
  389       public void setInputSource(XMLInputSource inputSource) throws IOException {
  390           fEntityManager.setEntityHandler(this);
  391           fEntityManager.startEntity("$fragment$", inputSource, false, true);
  392           // fDocumentSystemId = fEntityManager.expandSystemId(inputSource.getSystemId());
  393       } // setInputSource(XMLInputSource)
  394   
  395       /**
  396        * Scans a document.
  397        *
  398        * @param complete True if the scanner should scan the document
  399        *                 completely, pushing all events to the registered
  400        *                 document handler. A value of false indicates that
  401        *                 that the scanner should only scan the next portion
  402        *                 of the document and return. A scanner instance is
  403        *                 permitted to completely scan a document if it does
  404        *                 not support this "pull" scanning model.
  405        *
  406        * @return True if there is more to scan, false otherwise.
  407        */
  408      /* public boolean scanDocument(boolean complete)
  409       throws IOException, XNIException {
  410   
  411           // keep dispatching "events"
  412           fEntityManager.setEntityHandler(this);
  413   
  414           return true;
  415   
  416       } // scanDocument(boolean):boolean
  417       */
  418   
  419       public boolean scanDocument(boolean complete)
  420       throws IOException, XNIException {
  421   
  422           // keep dispatching "events"
  423           fEntityManager.setEntityHandler(this);
  424           //System.out.println(" get Document Handler in NSDocumentHandler " + fDocumentHandler );
  425   
  426           int event = next();
  427           do {
  428               switch (event) {
  429                   case XMLStreamConstants.START_DOCUMENT :
  430                       //fDocumentHandler.startDocument(fEntityManager.getEntityScanner(),fEntityManager.getEntityScanner().getVersion(),fNamespaceContext,null);// not able to get
  431                       break;
  432                   case XMLStreamConstants.START_ELEMENT :
  433                       //System.out.println(" in scann element");
  434                       //fDocumentHandler.startElement(getElementQName(),fAttributes,null);
  435                       break;
  436                   case XMLStreamConstants.CHARACTERS :
  437                       fDocumentHandler.characters(getCharacterData(),null);
  438                       break;
  439                   case XMLStreamConstants.SPACE:
  440                       //check if getCharacterData() is the right function to retrieve ignorableWhitespace information.
  441                       //System.out.println("in the space");
  442                       //fDocumentHandler.ignorableWhitespace(getCharacterData(), null);
  443                       break;
  444                   case XMLStreamConstants.ENTITY_REFERENCE :
  445                       //entity reference callback are given in startEntity
  446                       break;
  447                   case XMLStreamConstants.PROCESSING_INSTRUCTION :
  448                       fDocumentHandler.processingInstruction(getPITarget(),getPIData(),null);
  449                       break;
  450                   case XMLStreamConstants.COMMENT :
  451                       //System.out.println(" in COMMENT of the XMLNSDocumentScannerImpl");
  452                       fDocumentHandler.comment(getCharacterData(),null);
  453                       break;
  454                   case XMLStreamConstants.DTD :
  455                       //all DTD related callbacks are handled in DTDScanner.
  456                       //1. Stax doesn't define DTD states as it does for XML Document.
  457                       //therefore we don't need to take care of anything here. So Just break;
  458                       break;
  459                   case XMLStreamConstants.CDATA:
  460                       fDocumentHandler.startCDATA(null);
  461                       //xxx: check if CDATA values comes from getCharacterData() function
  462                       fDocumentHandler.characters(getCharacterData(),null);
  463                       fDocumentHandler.endCDATA(null);
  464                       //System.out.println(" in CDATA of the XMLNSDocumentScannerImpl");
  465                       break;
  466                   case XMLStreamConstants.NOTATION_DECLARATION :
  467                       break;
  468                   case XMLStreamConstants.ENTITY_DECLARATION :
  469                       break;
  470                   case XMLStreamConstants.NAMESPACE :
  471                       break;
  472                   case XMLStreamConstants.ATTRIBUTE :
  473                       break;
  474                   case XMLStreamConstants.END_ELEMENT :
  475                       //do not give callback here.
  476                       //this callback is given in scanEndElement function.
  477                       //fDocumentHandler.endElement(getElementQName(),null);
  478                       break;
  479                   default :
  480                       throw new InternalError("processing event: " + event);
  481   
  482               }
  483               //System.out.println("here in before calling next");
  484               event = next();
  485               //System.out.println("here in after calling next");
  486           } while (event!=XMLStreamConstants.END_DOCUMENT && complete);
  487   
  488           if(event == XMLStreamConstants.END_DOCUMENT) {
  489               fDocumentHandler.endDocument(null);
  490               return false;
  491           }
  492   
  493           return true;
  494   
  495       } // scanDocument(boolean):boolean
  496   
  497   
  498   
  499       public com.sun.org.apache.xerces.internal.xni.QName getElementQName(){
  500           if(fScannerLastState == XMLEvent.END_ELEMENT){
  501               fElementQName.setValues(fElementStack.getLastPoppedElement());
  502           }
  503           return fElementQName ;
  504       }
  505   
  506       /** return the next state on the input
  507        * @return int
  508        */
  509   
  510       public int next() throws IOException, XNIException {
  511           return fDriver.next();
  512       }
  513   
  514       //
  515       // XMLComponent methods
  516       //
  517   
  518       /**
  519        * Resets the component. The component can query the component manager
  520        * about any features and properties that affect the operation of the
  521        * component.
  522        *
  523        * @param componentManager The component manager.
  524        *
  525        * @throws SAXException Thrown by component on initialization error.
  526        *                      For example, if a feature or property is
  527        *                      required for the operation of the component, the
  528        *                      component manager may throw a
  529        *                      SAXNotRecognizedException or a
  530        *                      SAXNotSupportedException.
  531        */
  532   
  533       public void reset(XMLComponentManager componentManager)
  534       throws XMLConfigurationException {
  535   
  536           super.reset(componentManager);
  537   
  538           // other settings
  539           // fDocumentSystemId = null;
  540   
  541           // sax features
  542           //fAttributes.setNamespaces(fNamespaces);
  543   
  544           // xerces features
  545           try{
  546               fReportCdataEvent = componentManager.getFeature(Constants.STAX_REPORT_CDATA_EVENT);
  547           } catch (XMLConfigurationException e) {
  548               e.printStackTrace();
  549               //note that default value of this feature is true in stax configuration
  550               fReportCdataEvent = true;
  551           }
  552   
  553           try {
  554               fSecurityManager = (SecurityManager)componentManager.getProperty(Constants.SECURITY_MANAGER);
  555           } catch (XMLConfigurationException e) {
  556               fSecurityManager = null;
  557           }
  558           fElementAttributeLimit = (fSecurityManager != null)?fSecurityManager.getElementAttrLimit():0;
  559   
  560           try {
  561               fNotifyBuiltInRefs = componentManager.getFeature(NOTIFY_BUILTIN_REFS);
  562           } catch (XMLConfigurationException e) {
  563               fNotifyBuiltInRefs = false;
  564           }
  565   
  566           try {
  567               Object resolver = componentManager.getProperty(ENTITY_RESOLVER);
  568               fExternalSubsetResolver = (resolver instanceof ExternalSubsetResolver) ?
  569                   (ExternalSubsetResolver) resolver : null;
  570           } catch (XMLConfigurationException e) {
  571               fExternalSubsetResolver = null;
  572           }
  573   
  574           // initialize vars
  575           fMarkupDepth = 0;
  576           fCurrentElement = null;
  577           fElementStack.clear();
  578           fHasExternalDTD = false;
  579           fStandalone = false;
  580           fInScanContent = false;
  581           //skipping algorithm
  582           fShouldSkip = false;
  583           fAdd = false;
  584           fSkip = false;
  585   
  586           //attribute
  587           fReadingAttributes = false;
  588           //xxx: external entities are supported in Xerces
  589           // it would be good to define feature for this case
  590           fSupportExternalEntities = true;
  591           fReplaceEntityReferences = true;
  592           fIsCoalesce = false;
  593   
  594           // setup Driver
  595           setScannerState(SCANNER_STATE_CONTENT);
  596           setDriver(fContentDriver);
  597           fEntityStore = fEntityManager.getEntityStore();
  598   
  599           dtdGrammarUtil = null;
  600   
  601   
  602           //fEntityManager.test();
  603       } // reset(XMLComponentManager)
  604   
  605   
  606       public void reset(PropertyManager propertyManager){
  607   
  608           super.reset(propertyManager);
  609   
  610           // other settings
  611           // fDocumentSystemId = null;
  612           fNamespaces = ((Boolean)propertyManager.getProperty(XMLInputFactory.IS_NAMESPACE_AWARE)).booleanValue();
  613           fNotifyBuiltInRefs = false ;
  614   
  615           // initialize vars
  616           fMarkupDepth = 0;
  617           fCurrentElement = null;
  618           fShouldSkip = false;
  619           fAdd = false;
  620           fSkip = false;
  621           fElementStack.clear();
  622           //fElementStack2.clear();
  623           fHasExternalDTD = false;
  624           fStandalone = false;
  625           //fReplaceEntityReferences = true;
  626           //fSupportExternalEntities = true;
  627           Boolean bo = (Boolean)propertyManager.getProperty(XMLInputFactoryImpl.IS_REPLACING_ENTITY_REFERENCES);
  628           fReplaceEntityReferences = bo.booleanValue();
  629           bo = (Boolean)propertyManager.getProperty(XMLInputFactoryImpl.IS_SUPPORTING_EXTERNAL_ENTITIES);
  630           fSupportExternalEntities = bo.booleanValue();
  631           Boolean cdata = (Boolean)propertyManager.getProperty(Constants.ZEPHYR_PROPERTY_PREFIX + Constants.STAX_REPORT_CDATA_EVENT) ;
  632           if(cdata != null)
  633               fReportCdataEvent = cdata.booleanValue() ;
  634           Boolean coalesce = (Boolean)propertyManager.getProperty(XMLInputFactory.IS_COALESCING) ;
  635           if(coalesce != null)
  636               fIsCoalesce = coalesce.booleanValue();
  637           fReportCdataEvent = fIsCoalesce ? false : (fReportCdataEvent && true) ;
  638           //if fIsCoalesce is set to true, set the value of fReplaceEntityReferences to true,
  639           //if fIsCoalesce is set to false, take the value of fReplaceEntityReferences as set by application
  640           fReplaceEntityReferences = fIsCoalesce ? true : fReplaceEntityReferences;
  641           // setup Driver
  642           //we dont need to do this -- nb.
  643           //setScannerState(SCANNER_STATE_CONTENT);
  644           //setDriver(fContentDriver);
  645           fEntityStore = fEntityManager.getEntityStore();
  646           //fEntityManager.test();
  647   
  648           dtdGrammarUtil = null;
  649   
  650       } // reset(XMLComponentManager)
  651   
  652       /**
  653        * Returns a list of feature identifiers that are recognized by
  654        * this component. This method may return null if no features
  655        * are recognized by this component.
  656        */
  657       public String[] getRecognizedFeatures() {
  658           return (String[])(RECOGNIZED_FEATURES.clone());
  659       } // getRecognizedFeatures():String[]
  660   
  661       /**
  662        * Sets the state of a feature. This method is called by the component
  663        * manager any time after reset when a feature changes state.
  664        * <p>
  665        * <strong>Note:</strong> Components should silently ignore features
  666        * that do not affect the operation of the component.
  667        *
  668        * @param featureId The feature identifier.
  669        * @param state     The state of the feature.
  670        *
  671        * @throws SAXNotRecognizedException The component should not throw
  672        *                                   this exception.
  673        * @throws SAXNotSupportedException The component should not throw
  674        *                                  this exception.
  675        */
  676       public void setFeature(String featureId, boolean state)
  677       throws XMLConfigurationException {
  678   
  679           super.setFeature(featureId, state);
  680   
  681           // Xerces properties
  682           if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
  683               String feature = featureId.substring(Constants.XERCES_FEATURE_PREFIX.length());
  684               if (feature.equals(Constants.NOTIFY_BUILTIN_REFS_FEATURE)) {
  685                   fNotifyBuiltInRefs = state;
  686               }
  687           }
  688   
  689       } // setFeature(String,boolean)
  690   
  691       /**
  692        * Returns a list of property identifiers that are recognized by
  693        * this component. This method may return null if no properties
  694        * are recognized by this component.
  695        */
  696       public String[] getRecognizedProperties() {
  697           return (String[])(RECOGNIZED_PROPERTIES.clone());
  698       } // getRecognizedProperties():String[]
  699   
  700       /**
  701        * Sets the value of a property. This method is called by the component
  702        * manager any time after reset when a property changes value.
  703        * <p>
  704        * <strong>Note:</strong> Components should silently ignore properties
  705        * that do not affect the operation of the component.
  706        *
  707        * @param propertyId The property identifier.
  708        * @param value      The value of the property.
  709        *
  710        * @throws SAXNotRecognizedException The component should not throw
  711        *                                   this exception.
  712        * @throws SAXNotSupportedException The component should not throw
  713        *                                  this exception.
  714        */
  715       public void setProperty(String propertyId, Object value)
  716       throws XMLConfigurationException {
  717   
  718           super.setProperty(propertyId, value);
  719   
  720           // Xerces properties
  721           if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
  722               final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
  723               if (suffixLength == Constants.ENTITY_MANAGER_PROPERTY.length() &&
  724                       propertyId.endsWith(Constants.ENTITY_MANAGER_PROPERTY)) {
  725                   fEntityManager = (XMLEntityManager)value;
  726                   return;
  727               }
  728               if (suffixLength == Constants.ENTITY_RESOLVER_PROPERTY.length() &&
  729                       propertyId.endsWith(Constants.ENTITY_RESOLVER_PROPERTY)) {
  730                   fExternalSubsetResolver = (value instanceof ExternalSubsetResolver) ?
  731                       (ExternalSubsetResolver) value : null;
  732                   return;
  733               }
  734           }
  735   
  736   
  737                   // Xerces properties
  738           if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
  739               String property = propertyId.substring(Constants.XERCES_PROPERTY_PREFIX.length());
  740               if (property.equals(Constants.ENTITY_MANAGER_PROPERTY)) {
  741                   fEntityManager = (XMLEntityManager)value;
  742               }
  743               return;
  744           }
  745   
  746       } // setProperty(String,Object)
  747   
  748       /**
  749        * Returns the default state for a feature, or null if this
  750        * component does not want to report a default value for this
  751        * feature.
  752        *
  753        * @param featureId The feature identifier.
  754        *
  755        * @since Xerces 2.2.0
  756        */
  757       public Boolean getFeatureDefault(String featureId) {
  758           for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
  759               if (RECOGNIZED_FEATURES[i].equals(featureId)) {
  760                   return FEATURE_DEFAULTS[i];
  761               }
  762           }
  763           return null;
  764       } // getFeatureDefault(String):Boolean
  765   
  766       /**
  767        * Returns the default state for a property, or null if this
  768        * component does not want to report a default value for this
  769        * property.
  770        *
  771        * @param propertyId The property identifier.
  772        *
  773        * @since Xerces 2.2.0
  774        */
  775       public Object getPropertyDefault(String propertyId) {
  776           for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
  777               if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
  778                   return PROPERTY_DEFAULTS[i];
  779               }
  780           }
  781           return null;
  782       } // getPropertyDefault(String):Object
  783   
  784       //
  785       // XMLDocumentSource methods
  786       //
  787   
  788       /**
  789        * setDocumentHandler
  790        *
  791        * @param documentHandler
  792        */
  793       public void setDocumentHandler(XMLDocumentHandler documentHandler) {
  794           fDocumentHandler = documentHandler;
  795           //System.out.println(" In Set DOCUMENT HANDLER" + fDocumentHandler + " scanner =" + this);
  796       } // setDocumentHandler(XMLDocumentHandler)
  797   
  798   
  799       /** Returns the document handler */
  800       public XMLDocumentHandler getDocumentHandler(){
  801           return fDocumentHandler;
  802       }
  803   
  804       //
  805       // XMLEntityHandler methods
  806       //
  807   
  808       /**
  809        * This method notifies of the start of an entity. The DTD has the
  810        * pseudo-name of "[dtd]" parameter entity names start with '%'; and
  811        * general entities are just specified by their name.
  812        *
  813        * @param name     The name of the entity.
  814        * @param identifier The resource identifier.
  815        * @param encoding The auto-detected IANA encoding name of the entity
  816        *                 stream. This value will be null in those situations
  817        *                 where the entity encoding is not auto-detected (e.g.
  818        *                 internal entities or a document entity that is
  819        *                 parsed from a java.io.Reader).
  820        *
  821        * @throws XNIException Thrown by handler to signal an error.
  822        */
  823       public void startEntity(String name,
  824               XMLResourceIdentifier identifier,
  825               String encoding, Augmentations augs) throws XNIException {
  826   
  827           // keep track of this entity before fEntityDepth is increased
  828           if (fEntityDepth == fEntityStack.length) {
  829               int[] entityarray = new int[fEntityStack.length * 2];
  830               System.arraycopy(fEntityStack, 0, entityarray, 0, fEntityStack.length);
  831               fEntityStack = entityarray;
  832           }
  833           fEntityStack[fEntityDepth] = fMarkupDepth;
  834   
  835           super.startEntity(name, identifier, encoding, augs);
  836   
  837           // WFC:  entity declared in external subset in standalone doc
  838           if(fStandalone && fEntityStore.isEntityDeclInExternalSubset(name)) {
  839               reportFatalError("MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
  840                       new Object[]{name});
  841           }
  842   
  843           /** we are not calling the handlers yet.. */
  844           // call handler
  845           if (fDocumentHandler != null && !fScanningAttribute) {
  846               if (!name.equals("[xml]")) {
  847                   fDocumentHandler.startGeneralEntity(name, identifier, encoding, null);
  848               }
  849           }
  850   
  851       } // startEntity(String,XMLResourceIdentifier,String)
  852   
  853       /**
  854        * This method notifies the end of an entity. The DTD has the pseudo-name
  855        * of "[dtd]" parameter entity names start with '%'; and general entities
  856        * are just specified by their name.
  857        *
  858        * @param name The name of the entity.
  859        *
  860        * @throws XNIException Thrown by handler to signal an error.
  861        */
  862       public void endEntity(String name, Augmentations augs) throws IOException, XNIException {
  863   
  864           /**
  865            * // flush possible pending output buffer - see scanContent
  866            * if (fInScanContent && fStringBuffer.length != 0
  867            * && fDocumentHandler != null) {
  868            * fDocumentHandler.characters(fStringBuffer, null);
  869            * fStringBuffer.length = 0; // make sure we know it's been flushed
  870            * }
  871            */
  872           super.endEntity(name, augs);
  873   
  874           // make sure markup is properly balanced
  875           if (fMarkupDepth != fEntityStack[fEntityDepth]) {
  876               reportFatalError("MarkupEntityMismatch", null);
  877           }
  878   
  879           /**/
  880           // call handler
  881           if (fDocumentHandler != null && !fScanningAttribute) {
  882               if (!name.equals("[xml]")) {
  883                   fDocumentHandler.endGeneralEntity(name, null);
  884               }
  885           }
  886   
  887   
  888       } // endEntity(String)
  889   
  890       //
  891       // Protected methods
  892       //
  893   
  894       // Driver factory methods
  895   
  896       /** Creates a content Driver. */
  897       protected Driver createContentDriver() {
  898           return new FragmentContentDriver();
  899       } // createContentDriver():Driver
  900   
  901       // scanning methods
  902   
  903       /**
  904        * Scans an XML or text declaration.
  905        * <p>
  906        * <pre>
  907        * [23] XMLDecl ::= '&lt;?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  908        * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
  909        * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
  910        * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
  911        * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
  912        *                 | ('"' ('yes' | 'no') '"'))
  913        *
  914        * [77] TextDecl ::= '&lt;?xml' VersionInfo? EncodingDecl S? '?>'
  915        * </pre>
  916        *
  917        * @param scanningTextDecl True if a text declaration is to
  918        *                         be scanned instead of an XML
  919        *                         declaration.
  920        */
  921       protected void scanXMLDeclOrTextDecl(boolean scanningTextDecl)
  922       throws IOException, XNIException {
  923   
  924           // scan decl
  925           super.scanXMLDeclOrTextDecl(scanningTextDecl, fStrings);
  926           fMarkupDepth--;
  927   
  928           // pseudo-attribute values
  929           String version = fStrings[0];
  930           String encoding = fStrings[1];
  931           String standalone = fStrings[2];
  932           fDeclaredEncoding = encoding;
  933           // set standalone
  934           fStandalone = standalone != null && standalone.equals("yes");
  935           ///xxx see where its used.. this is not used anywhere. it may be useful for entity to store this information
  936           //but this information is only related with Document Entity.
  937           fEntityManager.setStandalone(fStandalone);
  938   
  939   
  940           // call handler
  941           if (fDocumentHandler != null) {
  942               if (scanningTextDecl) {
  943                   fDocumentHandler.textDecl(version, encoding, null);
  944               } else {
  945                   fDocumentHandler.xmlDecl(version, encoding, standalone, null);
  946               }
  947           }
  948   
  949           if(version != null){
  950               fEntityScanner.setVersion(version);
  951               fEntityScanner.setXMLVersion(version);
  952           }
  953           // set encoding on reader, only if encoding was not specified by the application explicitly
  954           if (encoding != null && !fEntityScanner.getCurrentEntity().isEncodingExternallySpecified()) {
  955                fEntityScanner.setEncoding(encoding);
  956           }
  957   
  958       } // scanXMLDeclOrTextDecl(boolean)
  959   
  960       public String getPITarget(){
  961           return fPITarget ;
  962       }
  963   
  964       public XMLStringBuffer getPIData(){
  965           return fContentBuffer ;
  966       }
  967   
  968       //XXX: why not this function behave as per the state of the parser?
  969       public XMLString getCharacterData(){
  970           if(fUsebuffer){
  971               return fContentBuffer ;
  972           }else{
  973               return fTempString;
  974           }
  975   
  976       }
  977   
  978   
  979       /**
  980        * Scans a processing data. This is needed to handle the situation
  981        * where a document starts with a processing instruction whose
  982        * target name <em>starts with</em> "xml". (e.g. xmlfoo)
  983        *
  984        * @param target The PI target
  985        * @param data The XMLStringBuffer to fill in with the data
  986        */
  987       protected void scanPIData(String target, XMLStringBuffer data)
  988       throws IOException, XNIException {
  989   
  990           super.scanPIData(target, data);
  991   
  992           //set the PI target and values
  993           fPITarget = target ;
  994   
  995           fMarkupDepth--;
  996   
  997       } // scanPIData(String)
  998   
  999       /**
 1000        * Scans a comment.
 1001        * <p>
 1002        * <pre>
 1003        * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
 1004        * </pre>
 1005        * <p>
 1006        * <strong>Note:</strong> Called after scanning past '&lt;!--'
 1007        */
 1008       protected void scanComment() throws IOException, XNIException {
 1009           fContentBuffer.clear();
 1010           scanComment(fContentBuffer);
 1011           //getTextCharacters can also be called for reading comments
 1012           fUsebuffer = true;
 1013           fMarkupDepth--;
 1014   
 1015       } // scanComment()
 1016   
 1017       //xxx value returned by this function may not remain valid if another event is scanned.
 1018       public String getComment(){
 1019           return fContentBuffer.toString();
 1020       }
 1021   
 1022       void addElement(String rawname){
 1023           if(fElementPointer < ELEMENT_ARRAY_LENGTH){
 1024               //storing element raw name in a linear list of array
 1025               fElementArray[fElementPointer] = rawname ;
 1026               //storing elemnetPointer for particular element depth
 1027   
 1028               if(DEBUG_SKIP_ALGORITHM){
 1029                   StringBuffer sb = new StringBuffer() ;
 1030                   sb.append(" Storing element information ") ;
 1031                   sb.append(" fElementPointer = " + fElementPointer) ;
 1032                   sb.append(" fElementRawname = " + fElementQName.rawname) ;
 1033                   sb.append(" fElementStack.fDepth = " + fElementStack.fDepth);
 1034                   System.out.println(sb.toString()) ;
 1035               }
 1036   
 1037               //store pointer information only when element depth is less MAX_DEPTH_LIMIT
 1038               if(fElementStack.fDepth < MAX_DEPTH_LIMIT){
 1039                   short column = storePointerForADepth(fElementPointer);
 1040                   if(column > 0){
 1041                       short pointer = getElementPointer((short)fElementStack.fDepth, (short)(column - 1) );
 1042                       //identity comparison shouldn't take much time and we can rely on this
 1043                       //since its guaranteed to have same object id for same string.
 1044                       if(rawname == fElementArray[pointer]){
 1045                           fShouldSkip = true ;
 1046                           fLastPointerLocation = pointer ;
 1047                           //reset the things and return.
 1048                           resetPointer((short)fElementStack.fDepth , column) ;
 1049                           fElementArray[fElementPointer] = null ;
 1050                           return ;
 1051                       }else{
 1052                           fShouldSkip = false ;
 1053                       }
 1054                   }
 1055               }
 1056               fElementPointer++ ;
 1057           }
 1058       }
 1059   
 1060   
 1061       void resetPointer(short depth, short column){
 1062           fPointerInfo[depth] [column] = (short)0;
 1063       }
 1064   
 1065       //returns column information at which pointer was stored.
 1066       short storePointerForADepth(short elementPointer){
 1067           short depth = (short) fElementStack.fDepth ;
 1068   
 1069           //Stores element pointer locations at particular depth , only 4 pointer locations
 1070           //are stored at particular depth for now.
 1071           for(short i = 0 ; i < MAX_POINTER_AT_A_DEPTH ; i++){
 1072   
 1073               if(canStore(depth, i)){
 1074                   fPointerInfo[depth][i] = elementPointer ;
 1075                   if(DEBUG_SKIP_ALGORITHM){
 1076                       StringBuffer sb = new StringBuffer() ;
 1077                       sb.append(" Pointer information ") ;
 1078                       sb.append(" fElementPointer = " + fElementPointer) ;
 1079                       sb.append(" fElementStack.fDepth = " + fElementStack.fDepth);
 1080                       sb.append(" column = " + i ) ;
 1081                       System.out.println(sb.toString()) ;
 1082                   }
 1083                   return i;
 1084               }
 1085               //else
 1086               //pointer was not stored because we reached the limit
 1087           }
 1088           return -1 ;
 1089       }
 1090   
 1091       boolean canStore(short depth, short column){
 1092           //colum = 0 , means first element at particular depth
 1093           //column = 1, means second element at particular depth
 1094           //        calle should make sure that it doesn't call for value outside allowed co-ordinates
 1095           return fPointerInfo[depth][column] == 0 ? true : false ;
 1096       }
 1097   
 1098   
 1099       short getElementPointer(short depth, short column){
 1100           //colum = 0 , means first element at particular depth
 1101           //column = 1, means second element at particular depth
 1102           //        calle should make sure that it doesn't call for value outside allowed co-ordinates
 1103           return fPointerInfo[depth][column] ;
 1104       }
 1105   
 1106       //this function assumes that string passed is not null and skips
 1107       //the following string from the buffer this makes sure
 1108       boolean skipFromTheBuffer(String rawname) throws IOException{
 1109           if(fEntityScanner.skipString(rawname)){
 1110               char c = (char)fEntityScanner.peekChar() ;
 1111               //If the start element was completely skipped we should encounter either ' '(space),
 1112               //or '/' (in case of empty element)  or '>'
 1113               if( c == ' ' || c == '/' || c == '>'){
 1114                   fElementRawname = rawname ;
 1115                   return true ;
 1116               } else{
 1117                   return false;
 1118               }
 1119           } else
 1120               return false ;
 1121       }
 1122   
 1123       boolean skipQElement(String rawname) throws IOException{
 1124   
 1125           final int c = fEntityScanner.getChar(rawname.length());
 1126           //if this character is still valid element name -- this means string can't match
 1127           if(XMLChar.isName(c)){
 1128               return false;
 1129           }else{
 1130               return fEntityScanner.skipString(rawname);
 1131           }
 1132       }
 1133   
 1134       protected boolean skipElement() throws IOException {
 1135   
 1136           if(!fShouldSkip) return false ;
 1137   
 1138           if(fLastPointerLocation != 0){
 1139               //Look at the next element stored in the array list.. we might just get a match.
 1140               String rawname = fElementArray[fLastPointerLocation + 1] ;
 1141               if(rawname != null && skipFromTheBuffer(rawname)){
 1142                   fLastPointerLocation++ ;
 1143                   if(DEBUG_SKIP_ALGORITHM){
 1144                       System.out.println("Element " + fElementRawname + " was SKIPPED at pointer location = " + fLastPointerLocation);
 1145                   }
 1146                   return true ;
 1147               } else{
 1148                   //reset it back to zero... we haven't got the correct subset yet.
 1149                   fLastPointerLocation = 0 ;
 1150   
 1151               }
 1152           }
 1153           //xxx: we can put some logic here as from what column it should start looking
 1154           //for now we always start at 0
 1155           //fallback to tolerant algorithm, it would look for differnt element stored at different
 1156           //depth and get us the pointer location.
 1157           return fShouldSkip && skipElement((short)0);
 1158   
 1159       }
 1160   
 1161       //start of the column at which it should try searching
 1162       boolean skipElement(short column) throws IOException {
 1163           short depth = (short)fElementStack.fDepth ;
 1164   
 1165           if(depth > MAX_DEPTH_LIMIT){
 1166               return fShouldSkip = false ;
 1167           }
 1168           for(short i = column ; i < MAX_POINTER_AT_A_DEPTH ; i++){
 1169               short pointer = getElementPointer(depth , i ) ;
 1170   
 1171               if(pointer == 0){
 1172                   return fShouldSkip = false ;
 1173               }
 1174   
 1175               if(fElementArray[pointer] != null && skipFromTheBuffer(fElementArray[pointer])){
 1176                   if(DEBUG_SKIP_ALGORITHM){
 1177                       System.out.println();
 1178                       System.out.println("Element " + fElementRawname + " was SKIPPED at depth = " + fElementStack.fDepth + " column = " + column );
 1179                       System.out.println();
 1180                   }
 1181                   fLastPointerLocation = pointer ;
 1182                   return fShouldSkip = true ;
 1183               }
 1184           }
 1185           return fShouldSkip = false ;
 1186       }
 1187   
 1188       /**
 1189        * Scans a start element. This method will handle the binding of
 1190        * namespace information and notifying the handler of the start
 1191        * of the element.
 1192        * <p>
 1193        * <pre>
 1194        * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
 1195        * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
 1196        * </pre>
 1197        * <p>
 1198        * <strong>Note:</strong> This method assumes that the leading
 1199        * '&lt;' character has been consumed.
 1200        * <p>
 1201        * <strong>Note:</strong> This method uses the fElementQName and
 1202        * fAttributes variables. The contents of these variables will be
 1203        * destroyed. The caller should copy important information out of
 1204        * these variables before calling this method.
 1205        * NB: Content in fAttributes is valid only till the state of the parser is XMLEvent.START_ELEMENT
 1206        *
 1207        * @return True if element is empty. (i.e. It matches
 1208        *          production [44].
 1209        */
 1210       // fElementQName will have the details of element just read..
 1211       // fAttributes will have the details of all the attributes.
 1212       protected boolean scanStartElement()
 1213       throws IOException, XNIException {
 1214   
 1215           if (DEBUG_START_END_ELEMENT) System.out.println( this.getClass().toString() + ">>> scanStartElement()");
 1216           //when skipping is true and no more elements should be added
 1217           if(fSkip && !fAdd){
 1218               //get the stored element -- if everything goes right this should match the
 1219               //token in the buffer
 1220   
 1221               QName name = fElementStack.getNext();
 1222   
 1223               if(DEBUG_SKIP_ALGORITHM){
 1224                   System.out.println("Trying to skip String = " + name.rawname);
 1225               }
 1226   
 1227               //Be conservative -- if skipping fails -- stop.
 1228               fSkip = fEntityScanner.skipString(name.rawname);
 1229   
 1230               if(fSkip){
 1231                   if(DEBUG_SKIP_ALGORITHM){
 1232                       System.out.println("Element SUCESSFULLY skipped = " + name.rawname);
 1233                   }
 1234                   fElementStack.push();
 1235                   fElementQName = name;
 1236               }else{
 1237                   //if skipping fails reposition the stack or fallback to normal way of processing
 1238                   fElementStack.reposition();
 1239                   if(DEBUG_SKIP_ALGORITHM){
 1240                       System.out.println("Element was NOT skipped, REPOSITIONING stack" );
 1241                   }
 1242               }
 1243           }
 1244   
 1245           //we are still at the stage of adding elements
 1246           //the elements were not matched or
 1247           //fSkip is not set to true
 1248           if(!fSkip || fAdd){
 1249               //get the next element from the stack
 1250               fElementQName = fElementStack.nextElement();
 1251               // name
 1252               if (fNamespaces) {
 1253                   fEntityScanner.scanQName(fElementQName);
 1254               } else {
 1255                   String name = fEntityScanner.scanName();
 1256                   fElementQName.setValues(null, name, name, null);
 1257               }
 1258   
 1259               if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
 1260               if(DEBUG_SKIP_ALGORITHM){
 1261                   if(fAdd){
 1262                       System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
 1263                   }
 1264               }
 1265   
 1266           }
 1267   
 1268           //when the elements are being added , we need to check if we are set for skipping the elements
 1269           if(fAdd){
 1270               //this sets the value of fAdd variable
 1271               fElementStack.matchElement(fElementQName);
 1272           }
 1273   
 1274   
 1275           //xxx: We dont need another pointer, fCurrentElement, we can use fElementQName
 1276           fCurrentElement = fElementQName;
 1277   
 1278           String rawname = fElementQName.rawname;
 1279   
 1280           fEmptyElement = false;
 1281   
 1282           fAttributes.removeAllAttributes();
 1283   
 1284           if(!seekCloseOfStartTag()){
 1285               fReadingAttributes = true;
 1286               fAttributeCacheUsedCount =0;
 1287               fStringBufferIndex =0;
 1288               fAddDefaultAttr = true;
 1289               do {
 1290                   scanAttribute(fAttributes);
 1291                   if (fSecurityManager != null && fAttributes.getLength() > fElementAttributeLimit){
 1292                       fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 1293                                                    "ElementAttributeLimit",
 1294                                                    new Object[]{rawname, new Integer(fAttributes.getLength()) },
 1295                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR );
 1296                   }
 1297   
 1298               } while (!seekCloseOfStartTag());
 1299               fReadingAttributes=false;
 1300           }
 1301   
 1302           if (fEmptyElement) {
 1303               //decrease the markup depth..
 1304               fMarkupDepth--;
 1305   
 1306               // check that this element was opened in the same entity
 1307               if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
 1308                   reportFatalError("ElementEntityMismatch",
 1309                           new Object[]{fCurrentElement.rawname});
 1310               }
 1311               // call handler
 1312               if (fDocumentHandler != null) {
 1313                   fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
 1314               }
 1315   
 1316               //We should not be popping out the context here in endELement becaause the namespace context is still
 1317               //valid when parser is at the endElement state.
 1318               //if (fNamespaces) {
 1319               //  fNamespaceContext.popContext();
 1320               //}
 1321   
 1322               //pop the element off the stack..
 1323               fElementStack.popElement();
 1324   
 1325           } else {
 1326   
 1327               if(dtdGrammarUtil != null)
 1328                   dtdGrammarUtil.startElement(fElementQName, fAttributes);
 1329               if(fDocumentHandler != null){
 1330                   //complete element and attributes are traversed in this function so we can send a callback
 1331                   //here.
 1332                   //<strong>we shouldn't be sending callback in scanDocument()</strong>
 1333                   fDocumentHandler.startElement(fElementQName, fAttributes, null);
 1334               }
 1335           }
 1336   
 1337   
 1338           if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() + "<<< scanStartElement(): "+fEmptyElement);
 1339           return fEmptyElement;
 1340   
 1341       } // scanStartElement():boolean
 1342   
 1343       /**
 1344        * Looks for the close of start tag, i.e. if it finds '>' or '/>'
 1345        * Characters are consumed.
 1346        */
 1347       protected boolean seekCloseOfStartTag() throws IOException, XNIException {
 1348           // spaces
 1349           boolean sawSpace = fEntityScanner.skipSpaces();
 1350   
 1351           // end tag?
 1352           final int c = fEntityScanner.peekChar();
 1353           if (c == '>') {
 1354               fEntityScanner.scanChar();
 1355               return true;
 1356           } else if (c == '/') {
 1357               fEntityScanner.scanChar();
 1358               if (!fEntityScanner.skipChar('>')) {
 1359                   reportFatalError("ElementUnterminated",
 1360                           new Object[]{fElementQName.rawname});
 1361               }
 1362               fEmptyElement = true;
 1363               return true;
 1364           } else if (!isValidNameStartChar(c) || !sawSpace) {
 1365               reportFatalError("ElementUnterminated", new Object[]{fElementQName.rawname});
 1366           }
 1367   
 1368           return false;
 1369       }
 1370   
 1371       public boolean hasAttributes(){
 1372           return fAttributes.getLength() > 0 ? true : false ;
 1373       }
 1374   
 1375   
 1376       /**
 1377        * Scans an attribute.
 1378        * <p>
 1379        * <pre>
 1380        * [41] Attribute ::= Name Eq AttValue
 1381        * </pre>
 1382        * <p>
 1383        * <strong>Note:</strong> This method assumes that the next
 1384        * character on the stream is the first character of the attribute
 1385        * name.
 1386        * <p>
 1387        * <strong>Note:</strong> This method uses the fAttributeQName and
 1388        * fQName variables. The contents of these variables will be
 1389        * destroyed.
 1390        *
 1391        * @param attributes The attributes list for the scanned attribute.
 1392        */
 1393   
 1394       /**
 1395        * protected void scanAttribute(AttributeIteratorImpl attributes)
 1396        * throws IOException, XNIException {
 1397        * if (DEBUG_START_END_ELEMENT) System.out.println(">>> scanAttribute()");
 1398        *
 1399        *
 1400        * // name
 1401        * if (fNamespaces) {
 1402        * fEntityScanner.scanQName(fAttributeQName);
 1403        * }
 1404        * else {
 1405        * String name = fEntityScanner.scanName();
 1406        * fAttributeQName.setValues(null, name, name, null);
 1407        * }
 1408        *
 1409        * // equals
 1410        * fEntityScanner.skipSpaces();
 1411        * if (!fEntityScanner.skipChar('=')) {
 1412        * reportFatalError("EqRequiredInAttribute",
 1413        * new Object[]{fAttributeQName.rawname});
 1414        * }
 1415        * fEntityScanner.skipSpaces();
 1416        *
 1417        *
 1418        * // content
 1419        * int oldLen = attributes.getLength();
 1420        */
 1421       /**xxx there is one check of duplicate attribute that has been removed.
 1422        * attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
 1423        *
 1424        * // WFC: Unique Att Spec
 1425        * if (oldLen == attributes.getLength()) {
 1426        * reportFatalError("AttributeNotUnique",
 1427        * new Object[]{fCurrentElement.rawname,
 1428        * fAttributeQName.rawname});
 1429        * }
 1430        */
 1431   
 1432       /*
 1433           //REVISIT: one more case needs to be included: external PE and standalone is no
 1434           boolean isVC =  fHasExternalDTD && !fStandalone;
 1435           scanAttributeValue(fTempString, fTempString2,
 1436                              fAttributeQName.rawname, attributes,
 1437                              oldLen, isVC);
 1438   
 1439           //attributes.setValue(oldLen, fTempString.toString());
 1440           //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
 1441           //attributes.setSpecified(oldLen, true);
 1442   
 1443           AttributeImpl attribute = new AttributeImpl(fAttributeQName.prefix,fAttributeQName.localpart,fAttributeQName.uri,fTempString.toString(),fTempString2.toString(),XMLSymbols.fCDATASymbol,true);
 1444           fAttributes.addAttribute(attribute);
 1445           if (DEBUG_START_END_ELEMENT) System.out.println("<<< scanAttribute()");
 1446       } // scanAttribute(XMLAttributes)
 1447   
 1448        */
 1449   
 1450       /** return the attribute iterator implementation */
 1451       public XMLAttributesIteratorImpl getAttributeIterator(){
 1452           if(dtdGrammarUtil != null && fAddDefaultAttr){
 1453               dtdGrammarUtil.addDTDDefaultAttrs(fElementQName,fAttributes);
 1454               fAddDefaultAttr = false;
 1455           }
 1456           return fAttributes;
 1457       }
 1458   
 1459       /** return if the doucment is standalone */
 1460       public boolean isStandAlone(){
 1461           return fStandalone ;
 1462       }
 1463       /**
 1464        * Scans an attribute name value pair.
 1465        * <p>
 1466        * <pre>
 1467        * [41] Attribute ::= Name Eq AttValue
 1468        * </pre>
 1469        * <p>
 1470        * <strong>Note:</strong> This method assumes that the next
 1471        * character on the stream is the first character of the attribute
 1472        * name.
 1473        * <p>
 1474        * <strong>Note:</strong> This method uses the fAttributeQName and
 1475        * fQName variables. The contents of these variables will be
 1476        * destroyed.
 1477        *
 1478        * @param attributes The attributes list for the scanned attribute.
 1479        */
 1480   
 1481       protected void scanAttribute(XMLAttributes attributes)
 1482       throws IOException, XNIException {
 1483           if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
 1484   
 1485           // name
 1486           if (fNamespaces) {
 1487               fEntityScanner.scanQName(fAttributeQName);
 1488           } else {
 1489               String name = fEntityScanner.scanName();
 1490               fAttributeQName.setValues(null, name, name, null);
 1491           }
 1492   
 1493           // equals
 1494           fEntityScanner.skipSpaces();
 1495           if (!fEntityScanner.skipChar('=')) {
 1496               reportFatalError("EqRequiredInAttribute",
 1497                   new Object[] {fCurrentElement.rawname, fAttributeQName.rawname});
 1498           }
 1499           fEntityScanner.skipSpaces();
 1500   
 1501           int attIndex = 0 ;
 1502           //REVISIT: one more case needs to be included: external PE and standalone is no
 1503           boolean isVC =  fHasExternalDTD && !fStandalone;
 1504           //fTempString would store attribute value
 1505           ///fTempString2 would store attribute non-normalized value
 1506   
 1507           //this function doesn't use 'attIndex'. We are adding the attribute later
 1508           //after we have figured out that current attribute is not namespace declaration
 1509           //since scanAttributeValue doesn't use attIndex parameter therefore we
 1510           //can safely add the attribute later..
 1511           XMLString tmpStr = getString();
 1512   
 1513           scanAttributeValue(tmpStr, fTempString2,
 1514                   fAttributeQName.rawname, attributes,
 1515                   attIndex, isVC);
 1516   
 1517           // content
 1518           int oldLen = attributes.getLength();
 1519           //if the attribute name already exists.. new value is replaced with old value
 1520           attIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
 1521   
 1522           // WFC: Unique Att Spec
 1523           //attributes count will be same if the current attribute  name already exists for this element name.
 1524           //this means there are two duplicate attributes.
 1525           if (oldLen == attributes.getLength()) {
 1526               reportFatalError("AttributeNotUnique",
 1527                       new Object[]{fCurrentElement.rawname,
 1528                               fAttributeQName.rawname});
 1529           }
 1530   
 1531           //tmpString contains attribute value
 1532           //we are passing null as the attribute value
 1533           attributes.setValue(attIndex, null, tmpStr);
 1534   
 1535           ///xxx: nonNormalizedValue is not being set as it is not required by SAX & DOM
 1536           //attributes.setNonNormalizedValue(oldLen, fTempString2.toString());
 1537           attributes.setSpecified(attIndex, true);
 1538   
 1539           if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanAttribute()");
 1540   
 1541       } // scanAttribute(XMLAttributes)
 1542   
 1543       /**
 1544        * Scans element content.
 1545        *
 1546        * @return Returns the next character on the stream.
 1547        */
 1548       //CHANGED:
 1549       //EARLIER: scanContent()
 1550       //NOW: scanContent(XMLStringBuffer)
 1551       //It makes things easy if this functions takes XMLStringBuffer as parameter..
 1552       //this function appends the data to the buffer.
 1553       protected int scanContent(XMLStringBuffer content) throws IOException, XNIException {
 1554           //set the fTempString length to 0 before passing it on to scanContent
 1555           //scanContent sets the correct co-ordinates as per the content read
 1556           fTempString.length = 0;
 1557           int c = fEntityScanner.scanContent(fTempString);
 1558           content.append(fTempString);
 1559           fTempString.length = 0;
 1560           if (c == '\r') {
 1561               // happens when there is the character reference &#13;
 1562               //xxx: We know the next chracter.. we should just skip it and add ']' directlry
 1563               fEntityScanner.scanChar();
 1564               content.append((char)c);
 1565               c = -1;
 1566           } else if (c == ']') {
 1567               //fStringBuffer.clear();
 1568               //xxx: We know the next chracter.. we should just skip it and add ']' directlry
 1569               content.append((char)fEntityScanner.scanChar());
 1570               // remember where we are in case we get an endEntity before we
 1571               // could flush the buffer out - this happens when we're parsing an
 1572               // entity which ends with a ]
 1573               fInScanContent = true;
 1574               //
 1575               // We work on a single character basis to handle cases such as:
 1576               // ']]]>' which we might otherwise miss.
 1577               //
 1578               if (fEntityScanner.skipChar(']')) {
 1579                   content.append(']');
 1580                   while (fEntityScanner.skipChar(']')) {
 1581                       content.append(']');
 1582                   }
 1583                   if (fEntityScanner.skipChar('>')) {
 1584                       reportFatalError("CDEndInContent", null);
 1585                   }
 1586               }
 1587               fInScanContent = false;
 1588               c = -1;
 1589           }
 1590           if (fDocumentHandler != null && content.length > 0) {
 1591               //fDocumentHandler.characters(content, null);
 1592           }
 1593           return c;
 1594   
 1595       } // scanContent():int
 1596   
 1597   
 1598       /**
 1599        * Scans a CDATA section.
 1600        * <p>
 1601        * <strong>Note:</strong> This method uses the fTempString and
 1602        * fStringBuffer variables.
 1603        *
 1604        * @param complete True if the CDATA section is to be scanned
 1605        *                 completely.
 1606        *
 1607        * @return True if CDATA is completely scanned.
 1608        */
 1609       //CHANGED:
 1610       protected boolean scanCDATASection(XMLStringBuffer contentBuffer, boolean complete)
 1611       throws IOException, XNIException {
 1612   
 1613           // call handler
 1614           if (fDocumentHandler != null) {
 1615               //fDocumentHandler.startCDATA(null);
 1616           }
 1617   
 1618           while (true) {
 1619               //scanData will fill the contentBuffer
 1620               if (!fEntityScanner.scanData("]]>", contentBuffer)) {
 1621                   break ;
 1622                   /** We dont need all this code if we pass ']]>' as delimeter..
 1623                    * int brackets = 2;
 1624                    * while (fEntityScanner.skipChar(']')) {
 1625                    * brackets++;
 1626                    * }
 1627                    *
 1628                    * //When we find more than 2 square brackets
 1629                    * if (fDocumentHandler != null && brackets > 2) {
 1630                    * //we dont need to clear the buffer..
 1631                    * //contentBuffer.clear();
 1632                    * for (int i = 2; i < brackets; i++) {
 1633                    * contentBuffer.append(']');
 1634                    * }
 1635                    * fDocumentHandler.characters(contentBuffer, null);
 1636                    * }
 1637                    *
 1638                    * if (fEntityScanner.skipChar('>')) {
 1639                    * break;
 1640                    * }
 1641                    * if (fDocumentHandler != null) {
 1642                    * //we dont need to clear the buffer now..
 1643                    * //contentBuffer.clear();
 1644                    * contentBuffer.append("]]");
 1645                    * fDocumentHandler.characters(contentBuffer, null);
 1646                    * }
 1647                    **/
 1648               } else {
 1649                   int c = fEntityScanner.peekChar();
 1650                   if (c != -1 && isInvalidLiteral(c)) {
 1651                       if (XMLChar.isHighSurrogate(c)) {
 1652                           //contentBuffer.clear();
 1653                           //scan surrogates if any....
 1654                           scanSurrogates(contentBuffer);
 1655                       } else {
 1656                           reportFatalError("InvalidCharInCDSect",
 1657                                   new Object[]{Integer.toString(c,16)});
 1658                                   fEntityScanner.scanChar();
 1659                       }
 1660                   }
 1661                   //by this time we have also read surrogate contents if any...
 1662                   if (fDocumentHandler != null) {
 1663                       //fDocumentHandler.characters(contentBuffer, null);
 1664                   }
 1665               }
 1666           }
 1667           fMarkupDepth--;
 1668   
 1669           if (fDocumentHandler != null && contentBuffer.length > 0) {
 1670               //fDocumentHandler.characters(contentBuffer, null);
 1671           }
 1672   
 1673           // call handler
 1674           if (fDocumentHandler != null) {
 1675               //fDocumentHandler.endCDATA(null);
 1676           }
 1677   
 1678           return true;
 1679   
 1680       } // scanCDATASection(XMLStringBuffer, boolean):boolean
 1681   
 1682       /**
 1683        * Scans an end element.
 1684        * <p>
 1685        * <pre>
 1686        * [42] ETag ::= '&lt;/' Name S? '>'
 1687        * </pre>
 1688        * <p>
 1689        * <strong>Note:</strong> This method uses the fElementQName variable.
 1690        * The contents of this variable will be destroyed. The caller should
 1691        * copy the needed information out of this variable before calling
 1692        * this method.
 1693        *
 1694        * @return The element depth.
 1695        */
 1696       protected int scanEndElement() throws IOException, XNIException {
 1697           if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanEndElement()");
 1698   
 1699           // pop context
 1700           QName endElementName = fElementStack.popElement();
 1701   
 1702           String rawname = endElementName.rawname;
 1703           if(DEBUG)System.out.println("endElementName = " + endElementName.toString());
 1704           // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
 1705           //In scanners most of the time is consumed on checks done for XML characters, we can
 1706           // optimize on it and avoid the checks done for endElement,
 1707           //we will also avoid symbol table lookup - neeraj.bajaj@sun.com
 1708   
 1709           // this should work both for namespace processing true or false...
 1710   
 1711           //REVISIT: if the string is not the same as expected.. we need to do better error handling..
 1712           //We can skip this for now... In any case if the string doesn't match -- document is not well formed.
 1713   
 1714           if (!fEntityScanner.skipString(endElementName.rawname)) {
 1715                reportFatalError("ETagRequired", new Object[]{rawname});
 1716           }
 1717   
 1718           // end
 1719           fEntityScanner.skipSpaces();
 1720           if (!fEntityScanner.skipChar('>')) {
 1721               reportFatalError("ETagUnterminated",
 1722                       new Object[]{rawname});
 1723           }
 1724           fMarkupDepth--;
 1725   
 1726           //we have increased the depth for two markup "<" characters
 1727           fMarkupDepth--;
 1728   
 1729           // check that this element was opened in the same entity
 1730           if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
 1731               reportFatalError("ElementEntityMismatch",
 1732                       new Object[]{rawname});
 1733           }
 1734   
 1735           //We should not be popping out the context here in endELement becaause the namespace context is still
 1736           //valid when parser is at the endElement state.
 1737   
 1738           //if (fNamespaces) {
 1739           //  fNamespaceContext.popContext();
 1740           //}
 1741   
 1742           // call handler
 1743           if (fDocumentHandler != null ) {
 1744               //end element is scanned in this function so we can send a callback
 1745               //here.
 1746               //<strong>we shouldn't be sending callback in scanDocument()</strong>
 1747   
 1748               fDocumentHandler.endElement(endElementName, null);
 1749           }
 1750           if(dtdGrammarUtil != null)
 1751               dtdGrammarUtil.endElement(endElementName);
 1752   
 1753           return fMarkupDepth;
 1754   
 1755       } // scanEndElement():int
 1756   
 1757       /**
 1758        * Scans a character reference.
 1759        * <p>
 1760        * <pre>
 1761        * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
 1762        * </pre>
 1763        */
 1764       protected void scanCharReference()
 1765       throws IOException, XNIException {
 1766   
 1767           fStringBuffer2.clear();
 1768           int ch = scanCharReferenceValue(fStringBuffer2, null);
 1769           fMarkupDepth--;
 1770           if (ch != -1) {
 1771               // call handler
 1772   
 1773               if (fDocumentHandler != null) {
 1774                   if (fNotifyCharRefs) {
 1775                       fDocumentHandler.startGeneralEntity(fCharRefLiteral, null, null, null);
 1776                   }
 1777                   Augmentations augs = null;
 1778                   if (fValidation && ch <= 0x20) {
 1779                       if (fTempAugmentations != null) {
 1780                           fTempAugmentations.removeAllItems();
 1781                       }
 1782                       else {
 1783                           fTempAugmentations = new AugmentationsImpl();
 1784                       }
 1785                       augs = fTempAugmentations;
 1786                       augs.putItem(Constants.CHAR_REF_PROBABLE_WS, Boolean.TRUE);
 1787                   }
 1788                   //xxx: How do we deal with this - how to return charReferenceValues
 1789                   //now this is being commented because this is taken care in scanDocument()
 1790                   //fDocumentHandler.characters(fStringBuffer2, null);
 1791                   if (fNotifyCharRefs) {
 1792                       fDocumentHandler.endGeneralEntity(fCharRefLiteral, null);
 1793                   }
 1794               }
 1795           }
 1796   
 1797       } // scanCharReference()
 1798   
 1799   
 1800       /**
 1801        * Scans an entity reference.
 1802        *
 1803        * @return returns true if the new entity is started. If it was built-in entity
 1804        *         'false' is returned.
 1805        * @throws IOException  Thrown if i/o error occurs.
 1806        * @throws XNIException Thrown if handler throws exception upon
 1807        *                      notification.
 1808        */
 1809       protected void scanEntityReference(XMLStringBuffer content) throws IOException, XNIException {
 1810           String name = fEntityScanner.scanName();
 1811           if (name == null) {
 1812               reportFatalError("NameRequiredInReference", null);
 1813           }
 1814           if (!fEntityScanner.skipChar(';')) {
 1815               reportFatalError("SemicolonRequiredInReference", new Object []{name});
 1816           }
 1817           if (fEntityStore.isUnparsedEntity(name)) {
 1818               reportFatalError("ReferenceToUnparsedEntity", new Object[]{name});
 1819           }
 1820           fMarkupDepth--;
 1821           fCurrentEntityName = name;
 1822   
 1823           // handle built-in entities
 1824           if (name == fAmpSymbol) {
 1825               handleCharacter('&', fAmpSymbol, content);
 1826               fScannerState = SCANNER_STATE_BUILT_IN_REFS;
 1827               return ;
 1828           } else if (name == fLtSymbol) {
 1829               handleCharacter('<', fLtSymbol, content);
 1830               fScannerState = SCANNER_STATE_BUILT_IN_REFS;
 1831               return ;
 1832           } else if (name == fGtSymbol) {
 1833               handleCharacter('>', fGtSymbol, content);
 1834               fScannerState = SCANNER_STATE_BUILT_IN_REFS;
 1835               return ;
 1836           } else if (name == fQuotSymbol) {
 1837               handleCharacter('"', fQuotSymbol, content);
 1838               fScannerState = SCANNER_STATE_BUILT_IN_REFS;
 1839               return ;
 1840           } else if (name == fAposSymbol) {
 1841               handleCharacter('\'', fAposSymbol, content);
 1842               fScannerState = SCANNER_STATE_BUILT_IN_REFS;
 1843               return ;
 1844           }
 1845   
 1846           //1. if the entity is external and support to external entities is not required
 1847           // 2. or entities should not be replaced
 1848           //3. or if it is built in entity reference.
 1849           if((fEntityStore.isExternalEntity(name) && !fSupportExternalEntities) || (!fEntityStore.isExternalEntity(name) && !fReplaceEntityReferences) || foundBuiltInRefs){
 1850               fScannerState = SCANNER_STATE_REFERENCE;
 1851               return ;
 1852           }
 1853           // start general entity
 1854           if (!fEntityStore.isDeclaredEntity(name)) {
 1855               //REVISIT: one more case needs to be included: external PE and standalone is no
 1856               if ( fHasExternalDTD && !fStandalone) {
 1857                   if (fValidation)
 1858                       fErrorReporter.reportError(fEntityScanner, XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared",
 1859                               new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR);
 1860               } else
 1861                   reportFatalError("EntityNotDeclared", new Object[]{name});
 1862           }
 1863           //we are starting the entity even if the entity was not declared
 1864           //if that was the case it its taken care in XMLEntityManager.startEntity()
 1865           //we immediately call the endEntity. Application gets to know if there was
 1866           //any entity that was not declared.
 1867           fEntityManager.startEntity(name, false);
 1868           //set the scaner state to content.. parser will automatically revive itself at any point of time.
 1869           //setScannerState(SCANNER_STATE_CONTENT);
 1870           //return true ;
 1871       } // scanEntityReference()
 1872   
 1873       // utility methods
 1874   
 1875       /**
 1876        * Calls document handler with a single character resulting from
 1877        * built-in entity resolution.
 1878        *
 1879        * @param c
 1880        * @param entity built-in name
 1881        * @param XMLStringBuffer append the character to buffer
 1882        *
 1883        * we really dont need to call this function -- this function is only required when
 1884        * we integrate with rest of Xerces2. SO maintaining the current behavior and still
 1885        * calling this function to hanlde built-in entity reference.
 1886        *
 1887        */
 1888       private void handleCharacter(char c, String entity, XMLStringBuffer content) throws XNIException {
 1889           foundBuiltInRefs = true;
 1890           content.append(c);
 1891           if (fDocumentHandler != null) {
 1892               fSingleChar[0] = c;
 1893               if (fNotifyBuiltInRefs) {
 1894                   fDocumentHandler.startGeneralEntity(entity, null, null, null);
 1895               }
 1896               fTempString.setValues(fSingleChar, 0, 1);
 1897               //fDocumentHandler.characters(fTempString, null);
 1898   
 1899               if (fNotifyBuiltInRefs) {
 1900                   fDocumentHandler.endGeneralEntity(entity, null);
 1901               }
 1902           }
 1903       } // handleCharacter(char)
 1904   
 1905       // helper methods
 1906   
 1907       /**
 1908        * Sets the scanner state.
 1909        *
 1910        * @param state The new scanner state.
 1911        */
 1912       protected final void setScannerState(int state) {
 1913   
 1914           fScannerState = state;
 1915           if (DEBUG_SCANNER_STATE) {
 1916               System.out.print("### setScannerState: ");
 1917               //System.out.print(fScannerState);
 1918               System.out.print(getScannerStateName(state));
 1919               System.out.println();
 1920           }
 1921   
 1922       } // setScannerState(int)
 1923   
 1924   
 1925       /**
 1926        * Sets the Driver.
 1927        *
 1928        * @param Driver The new Driver.
 1929        */
 1930       protected final void setDriver(Driver driver) {
 1931           fDriver = driver;
 1932           if (DEBUG_DISPATCHER) {
 1933               System.out.print("%%% setDriver: ");
 1934               System.out.print(getDriverName(driver));
 1935               System.out.println();
 1936           }
 1937       }
 1938   
 1939       //
 1940       // Private methods
 1941       //
 1942   
 1943       /** Returns the scanner state name. */
 1944       protected String getScannerStateName(int state) {
 1945   
 1946           switch (state) {
 1947               case SCANNER_STATE_DOCTYPE: return "SCANNER_STATE_DOCTYPE";
 1948               case SCANNER_STATE_ROOT_ELEMENT: return "SCANNER_STATE_ROOT_ELEMENT";
 1949               case SCANNER_STATE_START_OF_MARKUP: return "SCANNER_STATE_START_OF_MARKUP";
 1950               case SCANNER_STATE_COMMENT: return "SCANNER_STATE_COMMENT";
 1951               case SCANNER_STATE_PI: return "SCANNER_STATE_PI";
 1952               case SCANNER_STATE_CONTENT: return "SCANNER_STATE_CONTENT";
 1953               case SCANNER_STATE_REFERENCE: return "SCANNER_STATE_REFERENCE";
 1954               case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT";
 1955               case SCANNER_STATE_TERMINATED: return "SCANNER_STATE_TERMINATED";
 1956               case SCANNER_STATE_CDATA: return "SCANNER_STATE_CDATA";
 1957               case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL";
 1958               case SCANNER_STATE_ATTRIBUTE: return "SCANNER_STATE_ATTRIBUTE";
 1959               case SCANNER_STATE_ATTRIBUTE_VALUE: return "SCANNER_STATE_ATTRIBUTE_VALUE";
 1960               case SCANNER_STATE_START_ELEMENT_TAG: return "SCANNER_STATE_START_ELEMENT_TAG";
 1961               case SCANNER_STATE_END_ELEMENT_TAG: return "SCANNER_STATE_END_ELEMENT_TAG";
 1962               case SCANNER_STATE_CHARACTER_DATA: return "SCANNER_STATE_CHARACTER_DATA" ;
 1963           }
 1964   
 1965           return "??? ("+state+')';
 1966   
 1967       } // getScannerStateName(int):String
 1968       public String getEntityName(){
 1969           //return the cached name
 1970           return fCurrentEntityName;
 1971       }
 1972   
 1973       /** Returns the driver name. */
 1974       public String getDriverName(Driver driver) {
 1975   
 1976           if (DEBUG_DISPATCHER) {
 1977               if (driver != null) {
 1978                   String name = driver.getClass().getName();
 1979                   int index = name.lastIndexOf('.');
 1980                   if (index != -1) {
 1981                       name = name.substring(index + 1);
 1982                       index = name.lastIndexOf('$');
 1983                       if (index != -1) {
 1984                           name = name.substring(index + 1);
 1985                       }
 1986                   }
 1987                   return name;
 1988               }
 1989           }
 1990           return "null";
 1991   
 1992       } // getDriverName():String
 1993   
 1994       //
 1995       // Classes
 1996       //
 1997   
 1998       /**
 1999        * @author Neeraj Bajaj, Sun Microsystems.
 2000        */
 2001       protected static final class Element {
 2002   
 2003           //
 2004           // Data
 2005           //
 2006   
 2007           /** Symbol. */
 2008           public QName qname;
 2009   
 2010           //raw name stored as characters
 2011           public char[] fRawname;
 2012   
 2013           /** The next Element entry. */
 2014           public Element next;
 2015   
 2016           //
 2017           // Constructors
 2018           //
 2019   
 2020           /**
 2021            * Constructs a new Element from the given QName and next Element
 2022            * reference.
 2023            */
 2024           public Element(QName qname, Element next) {
 2025               this.qname.setValues(qname);
 2026               this.fRawname = qname.rawname.toCharArray();
 2027               this.next = next;
 2028           }
 2029   
 2030       } // class Element
 2031   
 2032       /**
 2033        * Element stack.
 2034        *
 2035        * @author Neeraj Bajaj, Sun Microsystems.
 2036        */
 2037       protected class ElementStack2 {
 2038   
 2039           //
 2040           // Data
 2041           //
 2042   
 2043           /** The stack data. */
 2044           protected QName [] fQName = new QName[20];
 2045   
 2046           //Element depth
 2047           protected int fDepth;
 2048           //total number of elements
 2049           protected int fCount;
 2050           //current position
 2051           protected int fPosition;
 2052           //Mark refers to the position
 2053           protected int fMark;
 2054   
 2055           protected int fLastDepth ;
 2056   
 2057           //
 2058           // Constructors
 2059           //
 2060   
 2061           /** Default constructor. */
 2062           public ElementStack2() {
 2063               for (int i = 0; i < fQName.length; i++) {
 2064                   fQName[i] = new QName();
 2065               }
 2066               fMark = fPosition = 1;
 2067           } // <init>()
 2068   
 2069           public void resize(){
 2070               /**
 2071                * int length = fElements.length;
 2072                * Element [] temp = new Element[length * 2];
 2073                * System.arraycopy(fElements, 0, temp, 0, length);
 2074                * fElements = temp;
 2075                */
 2076               //resize QNames
 2077               int oldLength = fQName.length;
 2078               QName [] tmp = new QName[oldLength * 2];
 2079               System.arraycopy(fQName, 0, tmp, 0, oldLength);
 2080               fQName = tmp;
 2081   
 2082               for (int i = oldLength; i < fQName.length; i++) {
 2083                   fQName[i] = new QName();
 2084               }
 2085   
 2086           }
 2087   
 2088   
 2089           //
 2090           // Public methods
 2091           //
 2092   
 2093           /** Check if the element scanned during the start element
 2094            *matches the stored element.
 2095            *
 2096            *@return true if the match suceeds.
 2097            */
 2098           public boolean matchElement(QName element) {
 2099               //last depth is the depth when last elemnt was pushed
 2100               //if last depth is greater than current depth
 2101               if(DEBUG_SKIP_ALGORITHM){
 2102                   System.out.println("fLastDepth = " + fLastDepth);
 2103                   System.out.println("fDepth = " + fDepth);
 2104               }
 2105               boolean match = false;
 2106               if(fLastDepth > fDepth && fDepth <= 2){
 2107                   if(DEBUG_SKIP_ALGORITHM){
 2108                       System.out.println("Checking if the elements match " + element.rawname + " , " + fQName[fDepth].rawname);
 2109                   }
 2110                   if(element.rawname == fQName[fDepth].rawname){
 2111                       fAdd = false;
 2112                       //mark this position
 2113                       //decrease the depth by 1 as arrays are 0 based
 2114                       fMark = fDepth - 1;
 2115                       //we found the match and from next element skipping will start, add 1
 2116                       fPosition = fMark + 1 ;
 2117                       match = true;
 2118                       //Once we get match decrease the count -- this was increased by nextElement()
 2119                       --fCount;
 2120                       if(DEBUG_SKIP_ALGORITHM){
 2121                           System.out.println("fAdd FALSE -- NOW ELEMENT SHOULD NOT BE ADDED");
 2122                           System.out.println("fMark = " + fMark);
 2123                           System.out.println("fPosition = " + fPosition);
 2124                           System.out.println("fDepth = " + fDepth);
 2125                           System.out.println("fCount = " + fCount);
 2126                       }
 2127                   }else{
 2128                       fAdd = true;
 2129                       if(DEBUG_SKIP_ALGORITHM)System.out.println("fAdd is " + fAdd);
 2130                   }
 2131               }
 2132               //store the last depth
 2133               fLastDepth = fDepth++;
 2134               return match;
 2135           } // pushElement(QName):QName
 2136   
 2137           /**
 2138            * This function doesn't increase depth. The function in this function is
 2139            *broken down into two functions for efficiency. <@see>matchElement</see>.
 2140            * This function just returns the pointer to the object and its values are set.
 2141            *
 2142            *@return QName reference to the next element in the list
 2143            */
 2144           public QName nextElement() {
 2145   
 2146               //if number of elements becomes equal to the length of array -- stop the skipping
 2147               if (fCount == fQName.length) {
 2148                   fShouldSkip = false;
 2149                   fAdd = false;
 2150                   if(DEBUG_SKIP_ALGORITHM)System.out.println("SKIPPING STOPPED, fShouldSkip = " + fShouldSkip);
 2151                   //xxx: this is not correct, we are returning the last element
 2152                   //this wont make any difference since flag has been set to 'false'
 2153                   return fQName[--fCount];
 2154               }
 2155               if(DEBUG_SKIP_ALGORITHM){
 2156                   System.out.println("fCount = " + fCount);
 2157               }
 2158               return fQName[fCount++];
 2159   
 2160           }
 2161   
 2162           /** Note that this function is considerably different than nextElement()
 2163            * This function just returns the previously stored elements
 2164            */
 2165           public QName getNext(){
 2166               //when position reaches number of elements in the list..
 2167               //set the position back to mark,  making it a circular linked list.
 2168               if(fPosition == fCount){
 2169                   fPosition = fMark;
 2170               }
 2171               return fQName[fPosition++];
 2172           }
 2173   
 2174           /** returns the current depth
 2175            */
 2176           public int popElement(){
 2177               return fDepth--;
 2178           }
 2179   
 2180   
 2181           /** Clears the stack without throwing away existing QName objects. */
 2182           public void clear() {
 2183               fLastDepth = 0;
 2184               fDepth = 0;
 2185               fCount = 0 ;
 2186               fPosition = fMark = 1;
 2187           } // clear()
 2188   
 2189       } // class ElementStack
 2190   
 2191       /**
 2192        * Element stack. This stack operates without synchronization, error
 2193        * checking, and it re-uses objects instead of throwing popped items
 2194        * away.
 2195        *
 2196        * @author Andy Clark, IBM
 2197        */
 2198       protected class ElementStack {
 2199   
 2200           //
 2201           // Data
 2202           //
 2203   
 2204           /** The stack data. */
 2205           protected QName[] fElements;
 2206           protected int []  fInt = new int[20];
 2207   
 2208   
 2209           //Element depth
 2210           protected int fDepth;
 2211           //total number of elements
 2212           protected int fCount;
 2213           //current position
 2214           protected int fPosition;
 2215           //Mark refers to the position
 2216           protected int fMark;
 2217   
 2218           protected int fLastDepth ;
 2219   
 2220           //
 2221           // Constructors
 2222           //
 2223   
 2224           /** Default constructor. */
 2225           public ElementStack() {
 2226               fElements = new QName[20];
 2227               for (int i = 0; i < fElements.length; i++) {
 2228                   fElements[i] = new QName();
 2229               }
 2230           } // <init>()
 2231   
 2232           //
 2233           // Public methods
 2234           //
 2235   
 2236           /**
 2237            * Pushes an element on the stack.
 2238            * <p>
 2239            * <strong>Note:</strong> The QName values are copied into the
 2240            * stack. In other words, the caller does <em>not</em> orphan
 2241            * the element to the stack. Also, the QName object returned
 2242            * is <em>not</em> orphaned to the caller. It should be
 2243            * considered read-only.
 2244            *
 2245            * @param element The element to push onto the stack.
 2246            *
 2247            * @return Returns the actual QName object that stores the
 2248            */
 2249           //XXX: THIS FUNCTION IS NOT USED
 2250           public QName pushElement(QName element) {
 2251               if (fDepth == fElements.length) {
 2252                   QName[] array = new QName[fElements.length * 2];
 2253                   System.arraycopy(fElements, 0, array, 0, fDepth);
 2254                   fElements = array;
 2255                   for (int i = fDepth; i < fElements.length; i++) {
 2256                       fElements[i] = new QName();
 2257                   }
 2258               }
 2259               fElements[fDepth].setValues(element);
 2260               return fElements[fDepth++];
 2261           } // pushElement(QName):QName
 2262   
 2263   
 2264           /** Note that this function is considerably different than nextElement()
 2265            * This function just returns the previously stored elements
 2266            */
 2267           public QName getNext(){
 2268               //when position reaches number of elements in the list..
 2269               //set the position back to mark,  making it a circular linked list.
 2270               if(fPosition == fCount){
 2271                   fPosition = fMark;
 2272               }
 2273               //store the position of last opened tag at particular depth
 2274               //fInt[++fDepth] = fPosition;
 2275               if(DEBUG_SKIP_ALGORITHM){
 2276                   System.out.println("Element at fPosition = " + fPosition + " is " + fElements[fPosition].rawname);
 2277               }
 2278               //return fElements[fPosition++];
 2279               return fElements[fPosition];
 2280           }
 2281   
 2282           /** This function should be called only when element was skipped sucessfully.
 2283            * 1. Increase the depth - because element was sucessfully skipped.
 2284            *2. Store the position of the element token in array  "last opened tag" at depth.
 2285            *3. increase the position counter so as to point to the next element in the array
 2286            */
 2287           public void push(){
 2288   
 2289               fInt[++fDepth] = fPosition++;
 2290           }
 2291   
 2292           /** Check if the element scanned during the start element
 2293            *matches the stored element.
 2294            *
 2295            *@return true if the match suceeds.
 2296            */
 2297           public boolean matchElement(QName element) {
 2298               //last depth is the depth when last elemnt was pushed
 2299               //if last depth is greater than current depth
 2300               //if(DEBUG_SKIP_ALGORITHM){
 2301               //   System.out.println("Check if the element " + element.rawname + " matches");
 2302               //  System.out.println("fLastDepth = " + fLastDepth);
 2303               // System.out.println("fDepth = " + fDepth);
 2304               //}
 2305               boolean match = false;
 2306               if(fLastDepth > fDepth && fDepth <= 3){
 2307                   if(DEBUG_SKIP_ALGORITHM){
 2308                       System.out.println("----------ENTERED THE LOOP WHERE WE CHECK FOR MATCHING OF ELMENT-----");
 2309                       System.out.println("Depth = " + fDepth + " Checking if INCOMING element " + element.rawname + " match STORED ELEMENT " + fElements[fDepth - 1].rawname);
 2310                   }
 2311                   if(element.rawname == fElements[fDepth - 1].rawname){
 2312                       fAdd = false;
 2313                       //mark this position
 2314                       //decrease the depth by 1 as arrays are 0 based
 2315                       fMark = fDepth - 1;
 2316                       //we found the match
 2317                       fPosition = fMark;
 2318                       match = true;
 2319                       //Once we get match decrease the count -- this was increased by nextElement()
 2320                       --fCount;
 2321                       if(DEBUG_SKIP_ALGORITHM){
 2322                           System.out.println("NOW ELEMENT SHOULD NOT BE ADDED, fAdd is set to false");
 2323                           System.out.println("fMark = " + fMark);
 2324                           System.out.println("fPosition = " + fPosition);
 2325                           System.out.println("fDepth = " + fDepth);
 2326                           System.out.println("fCount = " + fCount);
 2327                           System.out.println("---------MATCH SUCEEDED-----------------");
 2328                           System.out.println("");
 2329                       }
 2330                   }else{
 2331                       fAdd = true;
 2332                       if(DEBUG_SKIP_ALGORITHM)System.out.println("fAdd is " + fAdd);
 2333                   }
 2334               }
 2335               //store the position for the current depth
 2336               //when we are adding the elements, when skipping
 2337               //starts even then this should be tracked ie. when
 2338               //calling getNext()
 2339               if(match){
 2340                   //from next element skipping will start, add 1
 2341                   fInt[fDepth] = fPosition++;
 2342               } else{
 2343                   if(DEBUG_SKIP_ALGORITHM){
 2344                       System.out.println("At depth = " + fDepth + "array position is = " + (fCount - 1));
 2345                   }
 2346                   //sicne fInt[fDepth] contains pointer to the element array which are 0 based.
 2347                   fInt[fDepth] = fCount - 1;
 2348               }
 2349   
 2350               //if number of elements becomes equal to the length of array -- stop the skipping
 2351               //xxx: should we do "fCount == fInt.length"
 2352               if (fCount == fElements.length) {
 2353                   fSkip = false;
 2354                   fAdd = false;
 2355                   //reposition the stack -- it seems to be too complex document and there is no symmerty in structure
 2356                   reposition();
 2357                   if(DEBUG_SKIP_ALGORITHM){
 2358                       System.out.println("ALL THE ELMENTS IN ARRAY HAVE BEEN FILLED");
 2359                       System.out.println("REPOSITIONING THE STACK");
 2360                       System.out.println("-----------SKIPPING STOPPED----------");
 2361                       System.out.println("");
 2362                   }
 2363                   return false;
 2364               }
 2365               if(DEBUG_SKIP_ALGORITHM){
 2366                   if(match){
 2367                       System.out.println("Storing fPosition = " + fInt[fDepth] + " at fDepth = " + fDepth);
 2368                   }else{
 2369                       System.out.println("Storing fCount = " + fInt[fDepth] + " at fDepth = " + fDepth);
 2370                   }
 2371               }
 2372               //store the last depth
 2373               fLastDepth = fDepth;
 2374               return match;
 2375           } // matchElement(QName):QName
 2376   
 2377   
 2378           /**
 2379            * Returns the next element on the stack.
 2380            *
 2381            * @return Returns the actual QName object. Callee should
 2382            * use this object to store the details of next element encountered.
 2383            */
 2384           public QName nextElement() {
 2385               if(fSkip){
 2386                   fDepth++;
 2387                   //boundary checks are done in matchElement()
 2388