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

Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » impl » [javadoc | source]