1 /*
   2  * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 /*
   6  * Copyright 2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xerces.internal.impl;
  22 
  23 import java.io.IOException;
  24 import com.sun.org.apache.xerces.internal.xni.XMLString;
  25 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidatorFilter;
  26 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  27 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  28 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  29 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  30 import com.sun.org.apache.xerces.internal.xni.QName;
  31 import com.sun.org.apache.xerces.internal.xni.XNIException;
  32 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  33 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  34 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  35 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  36 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  37 
  38 import javax.xml.stream.events.XMLEvent;
  39 
  40 /**
  41  * This class adds the functionality of namespace processing.
  42  *
  43  * This class has been modified as per the new design which is more suited to
  44  * efficiently build pull parser. Lot of improvements have been done and
  45  * the code has been added to support stax functionality/features.
  46  *
  47  *
  48  * This class scans an XML document, checks if document has a DTD, and if
  49  * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform
  50  * namespace binding.
  51  *
  52  *
  53  * @author Neeraj Bajaj, Sun Microsystems
  54  * @author Venugopal Rao K, Sun Microsystems
  55  * @author Elena Litani, IBM
  56  */
  57 public class XMLNSDocumentScannerImpl
  58         extends XMLDocumentScannerImpl {
  59 
  60     /**
  61      * If is true, the dtd validator is no longer in the pipeline
  62      * and the scanner should bind namespaces
  63      */
  64     protected boolean fBindNamespaces;
  65 
  66     /** If validating parser, make sure we report an error in the
  67      *   scanner if DTD grammar is missing.*/
  68     protected boolean fPerformValidation;
  69 
  70 
  71     /** Default value of this feature is false, when in Stax mode this should be true */
  72     protected boolean fNotAddNSDeclAsAttribute = false;
  73 
  74     /** DTD validator */
  75      private XMLDTDValidatorFilter fDTDValidator;
  76 
  77      /** xmlns, default Namespace, declared */
  78      private boolean fXmlnsDeclared = false;
  79 
  80     /** Resets the fields of this scanner.
  81      */
  82     public void reset(PropertyManager propertyManager) {
  83         setPropertyManager(propertyManager);
  84         super.reset(propertyManager);
  85         fBindNamespaces = false;
  86         fNotAddNSDeclAsAttribute = !((Boolean)propertyManager.getProperty(Constants.ADD_NAMESPACE_DECL_AS_ATTRIBUTE)).booleanValue();
  87     }
  88 
  89     public void reset(XMLComponentManager componentManager)
  90     throws XMLConfigurationException {
  91         super.reset(componentManager);
  92         fNotAddNSDeclAsAttribute = false ;
  93         fPerformValidation = false;
  94         fBindNamespaces = false;
  95     }
  96 
  97     /** return the next state on the input
  98      *
  99      * @return int
 100      */
 101 
 102     public int next() throws IOException, XNIException {
 103         //since namespace context should still be valid when the parser is at the end element state therefore
 104         //we pop the context only when next() has been called after the end element state was encountered. - nb.
 105 
 106         if((fScannerLastState == XMLEvent.END_ELEMENT) && fBindNamespaces){
 107             fScannerLastState = -1;
 108             fNamespaceContext.popContext();
 109         }
 110 
 111         return fScannerLastState = super.next();
 112     }
 113 
 114     /**
 115      * The scanner is responsible for removing DTD validator
 116      * from the pipeline if it is not needed.
 117      *
 118      * @param previous The filter component before DTDValidator
 119      * @param dtdValidator
 120      *                 The DTDValidator
 121      * @param next     The documentHandler after the DTDValidator
 122      */
 123     public void setDTDValidator(XMLDTDValidatorFilter dtd){
 124         fDTDValidator = dtd;
 125     }
 126 
 127 
 128 
 129     /**
 130      * Scans a start element. This method will handle the binding of
 131      * namespace information and notifying the handler of the start
 132      * of the element.
 133      * <p>
 134      * <pre>
 135      * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
 136      * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
 137      * </pre>
 138      * <p>
 139      * <strong>Note:</strong> This method assumes that the leading
 140      * '&lt;' character has been consumed.
 141      * <p>
 142      * <strong>Note:</strong> This method uses the fElementQName and
 143      * fAttributes variables. The contents of these variables will be
 144      * destroyed. The caller should copy important information out of
 145      * these variables before calling this method.
 146      *
 147      * @return True if element is empty. (i.e. It matches
 148      *          production [44].
 149      */
 150     protected boolean scanStartElement()
 151     throws IOException, XNIException {
 152 
 153         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanStartElement()");
 154         //when skipping is true and no more elements should be added
 155         if(fSkip && !fAdd){
 156             //get the stored element -- if everything goes right this should match the
 157             //token in the buffer
 158 
 159             QName name = fElementStack.getNext();
 160 
 161             if(DEBUG_SKIP_ALGORITHM){
 162                 System.out.println("Trying to skip String = " + name.rawname);
 163             }
 164 
 165             //Be conservative -- if skipping fails -- stop.
 166             fSkip = fEntityScanner.skipString(name.rawname); // skipQElement(name);
 167 
 168             if(fSkip){
 169                 if(DEBUG_SKIP_ALGORITHM){
 170                     System.out.println("Element SUCESSFULLY skipped = " + name.rawname);
 171                 }
 172                 fElementStack.push();
 173                 fElementQName = name;
 174             }else{
 175                 //if skipping fails reposition the stack or fallback to normal way of processing
 176                 fElementStack.reposition();
 177                 if(DEBUG_SKIP_ALGORITHM){
 178                     System.out.println("Element was NOT skipped, REPOSITIONING stack" );
 179                 }
 180             }
 181         }
 182 
 183         //we are still at the stage of adding elements
 184         //the elements were not matched or
 185         //fSkip is not set to true
 186         if(!fSkip || fAdd){
 187             //get the next element from the stack
 188             fElementQName = fElementStack.nextElement();
 189             // There are two variables,fNamespaces and fBindNamespaces
 190             //StAX uses XMLNSDocumentScannerImpl so this distinction needs to be maintained
 191             if (fNamespaces) {
 192                 fEntityScanner.scanQName(fElementQName, NameType.ELEMENTSTART);
 193             } else {
 194                 String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
 195                 fElementQName.setValues(null, name, name, null);
 196             }
 197 
 198             if(DEBUG)System.out.println("Element scanned in start element is " + fElementQName.toString());
 199             if(DEBUG_SKIP_ALGORITHM){
 200                 if(fAdd){
 201                     System.out.println("Elements are being ADDED -- elemet added is = " + fElementQName.rawname + " at count = " + fElementStack.fCount);
 202                 }
 203             }
 204 
 205         }
 206 
 207         //when the elements are being added , we need to check if we are set for skipping the elements
 208         if(fAdd){
 209             //this sets the value of fAdd variable
 210             fElementStack.matchElement(fElementQName);
 211         }
 212 
 213         //xxx: We dont need another pointer, fCurrentElement, we can use fElementQName
 214         fCurrentElement = fElementQName;
 215 
 216         String rawname = fElementQName.rawname;
 217         checkDepth(rawname);
 218         if (fBindNamespaces) {
 219             fNamespaceContext.pushContext();
 220             if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
 221                 if (fPerformValidation) {
 222                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 223                             "MSG_GRAMMAR_NOT_FOUND",
 224                             new Object[]{ rawname},
 225                             XMLErrorReporter.SEVERITY_ERROR);
 226 
 227                             if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
 228                                 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
 229                                         "RootElementTypeMustMatchDoctypedecl",
 230                                         new Object[]{fDoctypeName, rawname},
 231                                         XMLErrorReporter.SEVERITY_ERROR);
 232                             }
 233                 }
 234             }
 235         }
 236 
 237 
 238         fEmptyElement = false;
 239         fAttributes.removeAllAttributes();
 240 
 241         if(!seekCloseOfStartTag()){
 242             fReadingAttributes = true;
 243             fAttributeCacheUsedCount =0;
 244             fStringBufferIndex =0;
 245             fAddDefaultAttr = true;
 246             fXmlnsDeclared = false;
 247 
 248             do {
 249                 scanAttribute(fAttributes);
 250                 if (fSecurityManager != null && (!fSecurityManager.isNoLimit(fElementAttributeLimit)) &&
 251                         fAttributes.getLength() > fElementAttributeLimit){
 252                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 253                                                  "ElementAttributeLimit",
 254                                                  new Object[]{rawname, fElementAttributeLimit },
 255                                                  XMLErrorReporter.SEVERITY_FATAL_ERROR );
 256                 }
 257 
 258             } while (!seekCloseOfStartTag());
 259             fReadingAttributes=false;
 260         }
 261 
 262         if (fBindNamespaces) {
 263             // REVISIT: is it required? forbit xmlns prefix for element
 264             if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
 265                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 266                         "ElementXMLNSPrefix",
 267                         new Object[]{fElementQName.rawname},
 268                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
 269             }
 270 
 271             // bind the element
 272             String prefix = fElementQName.prefix != null
 273                     ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
 274             // assign uri to the element
 275             fElementQName.uri = fNamespaceContext.getURI(prefix);
 276             // make sure that object in the element stack is updated as well
 277             fCurrentElement.uri = fElementQName.uri;
 278 
 279             if (fElementQName.prefix == null && fElementQName.uri != null) {
 280                 fElementQName.prefix = XMLSymbols.EMPTY_STRING;
 281             }
 282             if (fElementQName.prefix != null && fElementQName.uri == null) {
 283                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 284                         "ElementPrefixUnbound",
 285                         new Object[]{fElementQName.prefix, fElementQName.rawname},
 286                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
 287             }
 288 
 289             // bind attributes (xmlns are already bound bellow)
 290             int length = fAttributes.getLength();
 291             // fLength = 0; //initialize structure
 292             for (int i = 0; i < length; i++) {
 293                 fAttributes.getName(i, fAttributeQName);
 294 
 295                 String aprefix = fAttributeQName.prefix != null
 296                         ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
 297                 String uri = fNamespaceContext.getURI(aprefix);
 298                 // REVISIT: try removing the first "if" and see if it is faster.
 299                 //
 300                 if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
 301                     // checkDuplicates(fAttributeQName, fAttributes);
 302                     continue;
 303                 }
 304                 if (aprefix != XMLSymbols.EMPTY_STRING) {
 305                     fAttributeQName.uri = uri;
 306                     if (uri == null) {
 307                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 308                                 "AttributePrefixUnbound",
 309                                 new Object[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
 310                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 311                     }
 312                     fAttributes.setURI(i, uri);
 313                     // checkDuplicates(fAttributeQName, fAttributes);
 314                 }
 315             }
 316 
 317             if (length > 1) {
 318                 QName name = fAttributes.checkDuplicatesNS();
 319                 if (name != null) {
 320                     if (name.uri != null) {
 321                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 322                                 "AttributeNSNotUnique",
 323                                 new Object[]{fElementQName.rawname, name.localpart, name.uri},
 324                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 325                     } else {
 326                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 327                                 "AttributeNotUnique",
 328                                 new Object[]{fElementQName.rawname, name.rawname},
 329                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 330                     }
 331                 }
 332             }
 333         }
 334 
 335 
 336         if (fEmptyElement) {
 337             //decrease the markup depth..
 338             fMarkupDepth--;
 339 
 340             // check that this element was opened in the same entity
 341             if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
 342                 reportFatalError("ElementEntityMismatch",
 343                         new Object[]{fCurrentElement.rawname});
 344             }
 345             // call handler
 346             if (fDocumentHandler != null) {
 347                 if(DEBUG)
 348                     System.out.println("emptyElement = " + fElementQName);
 349 
 350                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
 351             }
 352 
 353             //We should not be popping out the context here in endELement becaause the namespace context is still
 354             //valid when parser is at the endElement state.
 355             fScanEndElement = true;
 356             //if (fBindNamespaces) {
 357             //  fNamespaceContext.popContext();
 358             //}
 359 
 360             //pop the element off the stack..
 361             fElementStack.popElement();
 362 
 363         } else {
 364 
 365             if(dtdGrammarUtil != null)
 366                 dtdGrammarUtil.startElement(fElementQName,fAttributes);
 367             if(fDocumentHandler != null){
 368                 //complete element and attributes are traversed in this function so we can send a callback
 369                 //here.
 370                 //<strong>we shouldn't be sending callback in scanDocument()</strong>
 371                 if(DEBUG)
 372                     System.out.println("startElement = " + fElementQName);
 373                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
 374             }
 375         }
 376 
 377 
 378         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanStartElement(): "+fEmptyElement);
 379         return fEmptyElement;
 380 
 381     } // scanStartElement():boolean
 382 
 383 
 384 
 385     /**
 386      * Scans an attribute.
 387      * <p>
 388      * <pre>
 389      * [41] Attribute ::= Name Eq AttValue
 390      * </pre>
 391      * <p>
 392      * <strong>Note:</strong> This method assumes that the next
 393      * character on the stream is the first character of the attribute
 394      * name.
 395      * <p>
 396      * <strong>Note:</strong> This method uses the fAttributeQName and
 397      * fQName variables. The contents of these variables will be
 398      * destroyed.
 399      *
 400      * @param attributes The attributes list for the scanned attribute.
 401      */
 402     protected void scanAttribute(XMLAttributesImpl attributes)
 403     throws IOException, XNIException {
 404         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
 405 
 406         // name
 407         fEntityScanner.scanQName(fAttributeQName, NameType.ATTRIBUTENAME);
 408 
 409         // equals
 410         fEntityScanner.skipSpaces();
 411         if (!fEntityScanner.skipChar('=', NameType.ATTRIBUTE)) {
 412             reportFatalError("EqRequiredInAttribute",
 413                     new Object[]{fCurrentElement.rawname,fAttributeQName.rawname});
 414         }
 415         fEntityScanner.skipSpaces();
 416 
 417         // content
 418         int attrIndex = 0 ;
 419 
 420 
 421         //REVISIT: one more case needs to be included: external PE and standalone is no
 422         boolean isVC =  fHasExternalDTD && !fStandalone;
 423 
 424         // REVISIT: it seems that this function should not take attributes, and length
 425         //fTempString would store attribute value
 426         ///fTempString2 would store attribute non-normalized value
 427 
 428         //this function doesn't use 'attIndex'. We are adding the attribute later
 429         //after we have figured out that current attribute is not namespace declaration
 430         //since scanAttributeValue doesn't use attIndex parameter therefore we
 431         //can safely add the attribute later..
 432         XMLString tmpStr = getString();
 433 
 434         /**
 435          * Determine whether this is a namespace declaration that will be subject
 436          * to the name limit check in the scanAttributeValue operation.
 437          * Namespace declaration format: xmlns="..." or xmlns:prefix="..."
 438          * Note that prefix:xmlns="..." isn't a namespace.
 439          */
 440         String localpart = fAttributeQName.localpart;
 441         String prefix = fAttributeQName.prefix != null
 442                 ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
 443         boolean isNSDecl = fBindNamespaces & (prefix == XMLSymbols.PREFIX_XMLNS ||
 444                     prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS);
 445 
 446         scanAttributeValue(tmpStr, fTempString2, fAttributeQName.rawname, attributes,
 447                 attrIndex, isVC, fCurrentElement.rawname, isNSDecl);
 448 
 449         String value = null;
 450         //fTempString.toString();
 451 
 452         // record namespace declarations if any.
 453         if (fBindNamespaces) {
 454             if (isNSDecl) {
 455                 //check the length of URI
 456                 if (tmpStr.length > fXMLNameLimit) {
 457                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
 458                             "MaxXMLNameLimit",
 459                             new Object[]{new String(tmpStr.ch,tmpStr.offset,tmpStr.length),
 460                             tmpStr.length, fXMLNameLimit,
 461                             fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.MAX_NAME_LIMIT)},
 462                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 463                 }
 464                 // get the internalized value of this attribute
 465                 String uri = fSymbolTable.addSymbol(tmpStr.ch,tmpStr.offset,tmpStr.length);
 466                 value = uri;
 467                 // 1. "xmlns" can't be bound to any namespace
 468                 if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) {
 469                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 470                             "CantBindXMLNS",
 471                             new Object[]{fAttributeQName},
 472                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 473                 }
 474 
 475                 // 2. the namespace for "xmlns" can't be bound to any prefix
 476                 if (uri == NamespaceContext.XMLNS_URI) {
 477                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 478                             "CantBindXMLNS",
 479                             new Object[]{fAttributeQName},
 480                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 481                 }
 482 
 483                 // 3. "xml" can't be bound to any other namespace than it's own
 484                 if (localpart == XMLSymbols.PREFIX_XML) {
 485                     if (uri != NamespaceContext.XML_URI) {
 486                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 487                                 "CantBindXML",
 488                                 new Object[]{fAttributeQName},
 489                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 490                     }
 491                 }
 492                 // 4. the namespace for "xml" can't be bound to any other prefix
 493                 else {
 494                     if (uri ==NamespaceContext.XML_URI) {
 495                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 496                                 "CantBindXML",
 497                                 new Object[]{fAttributeQName},
 498                                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 499                     }
 500                 }
 501                 prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING;
 502                 //set it equal to XMLSymbols.PREFIX_XMLNS when namespace declaration
 503                 // is of type xmlns = "..", in this case prefix = "" and localname = XMLSymbols.PREFIX_XMLNS
 504                 //this special behavior is because of dependency on this behavior in DOM components
 505                 if(prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS){
 506                     fAttributeQName.prefix = XMLSymbols.PREFIX_XMLNS;
 507                 }
 508                 // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
 509                 // We should only report an error if there is a prefix,
 510                 // that is, the local part is not "xmlns". -SG
 511                 if (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS) {
 512                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
 513                             "EmptyPrefixedAttName",
 514                             new Object[]{fAttributeQName},
 515                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 516                 }
 517 
 518                 // check for duplicate prefix bindings
 519                 if (((com.sun.org.apache.xerces.internal.util.NamespaceSupport) fNamespaceContext).containsPrefixInCurrentContext(prefix)) {
 520                     reportFatalError("AttributeNotUnique",
 521                             new Object[]{fCurrentElement.rawname,
 522                             fAttributeQName.rawname});
 523                 }
 524 
 525                 // declare prefix in context
 526                 boolean declared = fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null);
 527 
 528                 // check for duplicate xmlns declarations
 529                 if (!declared) { // by convention, prefix == "xmlns" | "xml"
 530                     // error if duplicate declaration
 531                     if (fXmlnsDeclared) {
 532                         reportFatalError("AttributeNotUnique",
 533                                 new Object[]{fCurrentElement.rawname,
 534                                 fAttributeQName.rawname});
 535                     }
 536 
 537                     // xmlns declared
 538                     fXmlnsDeclared = true;
 539                 }
 540 
 541                 //xerces internals (XSAttributeChecker) has dependency on namespace declaration returned
 542                 //as part of XMLAttributes.
 543                 //addition of namespace declaration to the attribute list is controlled by fNotAddNSDeclAsAttribute
 544                 //feature. This is required in Stax where namespace declarations are not considered as attribute
 545 
 546                 if(fNotAddNSDeclAsAttribute){
 547                     return ;
 548                 }
 549             }
 550         }
 551 
 552         //add the attributes to the list of attributes
 553         if (fBindNamespaces) {
 554             attrIndex = attributes.getLength();
 555             attributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, null);
 556         } else {
 557             int oldLen = attributes.getLength();
 558             attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
 559 
 560             // WFC: Unique Att Spec
 561             if (oldLen == attributes.getLength()) {
 562                 reportFatalError("AttributeNotUnique",
 563                         new Object[]{fCurrentElement.rawname,
 564                                 fAttributeQName.rawname});
 565             }
 566         }
 567 
 568         attributes.setValue(attrIndex, value,tmpStr);
 569         //attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
 570         //removing  as we are not using non-normalized values . -Venu
 571         attributes.setSpecified(attrIndex, true);
 572 
 573         // attempt to bind attribute
 574         if (fAttributeQName.prefix != null) {
 575             attributes.setURI(attrIndex, fNamespaceContext.getURI(fAttributeQName.prefix));
 576         }
 577 
 578         if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +"<<< scanAttribute()");
 579     } // scanAttribute(XMLAttributes)
 580 
 581 
 582 
 583 
 584 
 585     /** Creates a content driver. */
 586     protected Driver createContentDriver() {
 587         return new NSContentDriver();
 588     } // createContentDriver():Driver
 589 
 590     /**
 591      * Driver to handle content scanning.
 592      */
 593     protected final class NSContentDriver
 594             extends ContentDriver {
 595         /**
 596          * Scan for root element hook. This method is a hook for
 597          * subclasses to add code that handles scanning for the root
 598          * element. This method will also attempt to remove DTD validator
 599          * from the pipeline, if there is no DTD grammar. If DTD validator
 600          * is no longer in the pipeline bind namespaces in the scanner.
 601          *
 602          *
 603          * @return True if the caller should stop and return true which
 604          *          allows the scanner to switch to a new scanning
 605          *          driver. A return value of false indicates that
 606          *          the content driver should continue as normal.
 607          */
 608         protected boolean scanRootElementHook()
 609         throws IOException, XNIException {
 610 
 611             reconfigurePipeline();
 612             if (scanStartElement()) {
 613                 setScannerState(SCANNER_STATE_TRAILING_MISC);
 614                 setDriver(fTrailingMiscDriver);
 615                 return true;
 616             }
 617             return false;
 618 
 619         } // scanRootElementHook():boolean
 620 
 621         /**
 622          * Re-configures pipeline by removing the DTD validator
 623          * if no DTD grammar exists. If no validator exists in the
 624          * pipeline or there is no DTD grammar, namespace binding
 625          * is performed by the scanner in the enclosing class.
 626          */
 627         private void reconfigurePipeline() {
 628             //fDTDValidator will be null in Stax mode
 629             if (fNamespaces && fDTDValidator == null) {
 630                 fBindNamespaces = true;
 631             }
 632             else if (fNamespaces && !fDTDValidator.hasGrammar() ) {
 633                 fBindNamespaces = true;
 634                 fPerformValidation = fDTDValidator.validate();
 635                 // re-configure pipeline by removing DTDValidator
 636                 XMLDocumentSource source = fDTDValidator.getDocumentSource();
 637                 XMLDocumentHandler handler = fDTDValidator.getDocumentHandler();
 638                 source.setDocumentHandler(handler);
 639                 if (handler != null)
 640                     handler.setDocumentSource(source);
 641                 fDTDValidator.setDocumentSource(null);
 642                 fDTDValidator.setDocumentHandler(null);
 643             }
 644         } // reconfigurePipeline()
 645     }
 646 
 647 } // class XMLNSDocumentScannerImpl