content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999-2003 The Apache Software Foundation.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xerces" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 2002, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package jaxp.sun.org.apache.xerces.internal.impl;
  
  import java.io.IOException;
  
  import jaxp.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidatorFilter;
  import jaxp.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  import jaxp.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  import jaxp.sun.org.apache.xerces.internal.util.XMLSymbols;
  import jaxp.sun.org.apache.xerces.internal.xni.NamespaceContext;
  import jaxp.sun.org.apache.xerces.internal.xni.QName;
  import jaxp.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  import jaxp.sun.org.apache.xerces.internal.xni.XNIException;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  import jaxp.xml.stream.events.XMLEvent;
  
  
  /**
   * The scanner acts as the source for the document
   * information which is communicated to the document handler.
   *
   * This class scans an XML document, checks if document has a DTD, and if
   * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform
   * namespace binding.
   *
   * Note: This scanner should only be used when the namespace processing is on!
   *
   * <p>
   * This component requires the following features and properties from the
   * component manager that uses it:
   * <ul>
   *  <li>http://xml.org/sax/features/namespaces {true} -- if the value of this
   *      feature is set to false this scanner must not be used.</li>
   *  <li>http://xml.org/sax/features/validation</li>
   *  <li>http://apache.org/xml/features/nonvalidating/load-external-dtd</li>
   *  <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
   *  <li>http://apache.org/xml/features/scanner/notify-builtin-refs</li>
   *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
   *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
   *  <li>http://apache.org/xml/properties/internal/entity-manager</li>
   *  <li>http://apache.org/xml/properties/internal/dtd-scanner</li>
   * </ul>
   *
   * @xerces.internal
   *
   * @author Elena Litani, IBM
   * @author Michael Glavassevich, IBM
   * @author Sunitha Reddy, Sun Microsystems
   * @version $Id: XML11NSDocumentScannerImpl.java,v 1.6 2010-11-01 04:39:40 joehw Exp $
   */
  public class XML11NSDocumentScannerImpl extends XML11DocumentScannerImpl {
  
      /**
       * If is true, the dtd validator is no longer in the pipeline
       * and the scanner should bind namespaces
       */
      protected boolean fBindNamespaces;
  
      /**
       * If validating parser, make sure we report an error in the
       *  scanner if DTD grammar is missing.
       */
      protected boolean fPerformValidation;
  
      // private data
      //
  
      /** DTD validator */
      private XMLDTDValidatorFilter fDTDValidator;
  
      /**
       * Saw spaces after element name or between attributes.
       *
       * This is reserved for the case where scanning of a start element spans
       * several methods, as is the case when scanning the start of a root element
       * where a DTD external subset may be read after scanning the element name.
       */
      private boolean fSawSpace;
  
  
      /**
       * The scanner is responsible for removing DTD validator
       * from the pipeline if it is not needed.
       *
       * @param validator the DTD validator from the pipeline
       */
      public void setDTDValidator(XMLDTDValidatorFilter validator) {
          fDTDValidator = validator;
      }
  
      /**
       * Scans a start element. This method will handle the binding of
       * namespace information and notifying the handler of the start
       * of the element.
       * <p>
       * <pre>
       * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
       * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
       * </pre>
       * <p>
       * <strong>Note:</strong> This method assumes that the leading
       * '&lt;' character has been consumed.
       * <p>
       * <strong>Note:</strong> This method uses the fElementQName and
       * fAttributes variables. The contents of these variables will be
       * destroyed. The caller should copy important information out of
       * these variables before calling this method.
       *
       * @return True if element is empty. (i.e. It matches
       *          production [44].
       */
      protected boolean scanStartElement() throws IOException, XNIException {
  
          if (DEBUG_START_END_ELEMENT)
              System.out.println(">>> scanStartElementNS()");
                  // Note: namespace processing is on by default
          fEntityScanner.scanQName(fElementQName);
          // REVISIT - [Q] Why do we need this local variable? -- mrglavas
          String rawname = fElementQName.rawname;
          if (fBindNamespaces) {
              fNamespaceContext.pushContext();
              if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
                  if (fPerformValidation) {
                      fErrorReporter.reportError(
                          XMLMessageFormatter.XML_DOMAIN,
                          "MSG_GRAMMAR_NOT_FOUND",
                          new Object[] { rawname },
                          XMLErrorReporter.SEVERITY_ERROR);
  
                      if (fDoctypeName == null
                          || !fDoctypeName.equals(rawname)) {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XML_DOMAIN,
                              "RootElementTypeMustMatchDoctypedecl",
                              new Object[] { fDoctypeName, rawname },
                              XMLErrorReporter.SEVERITY_ERROR);
                      }
                  }
              }
          }
  
          // push element stack
          fCurrentElement = fElementStack.pushElement(fElementQName);
  
          // attributes
          boolean empty = false;
          fAttributes.removeAllAttributes();
          do {
              // spaces
              boolean sawSpace = fEntityScanner.skipSpaces();
  
              // end tag?
              int c = fEntityScanner.peekChar();
              if (c == '>') {
                  fEntityScanner.scanChar();
                  break;
              } else if (c == '/') {
                  fEntityScanner.scanChar();
                  if (!fEntityScanner.skipChar('>')) {
                      reportFatalError(
                          "ElementUnterminated",
                          new Object[] { rawname });
                  }
                  empty = true;
                  break;
              } else if (!isValidNameStartChar(c) || !sawSpace) {
                  // Second chance. Check if this character is a high
                  // surrogate of a valid name start character.
                  if (!isValidNameStartHighSurrogate(c) || !sawSpace) {
                      reportFatalError(
                          "ElementUnterminated",
                          new Object[] { rawname });
                  }
              }
  
              // attributes
              scanAttribute(fAttributes);
              if (fSecurityManager != null && (!fSecurityManager.isNoLimit(fElementAttributeLimit)) &&
                      fAttributes.getLength() > fElementAttributeLimit){
                  fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
                                               "ElementAttributeLimit",
                                               new Object[]{rawname, new Integer(fElementAttributeLimit) },
                                               XMLErrorReporter.SEVERITY_FATAL_ERROR );
              }
  
          } while (true);
  
          if (fBindNamespaces) {
              // REVISIT: is it required? forbit xmlns prefix for element
              if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
                  fErrorReporter.reportError(
                      XMLMessageFormatter.XMLNS_DOMAIN,
                      "ElementXMLNSPrefix",
                      new Object[] { fElementQName.rawname },
                      XMLErrorReporter.SEVERITY_FATAL_ERROR);
              }
  
              // bind the element
              String prefix =
                  fElementQName.prefix != null
                      ? fElementQName.prefix
                      : XMLSymbols.EMPTY_STRING;
              // assign uri to the element
              fElementQName.uri = fNamespaceContext.getURI(prefix);
              // make sure that object in the element stack is updated as well
              fCurrentElement.uri = fElementQName.uri;
  
              if (fElementQName.prefix == null && fElementQName.uri != null) {
                  fElementQName.prefix = XMLSymbols.EMPTY_STRING;
                  // making sure that the object in the element stack is updated too.
                  fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
              }
              if (fElementQName.prefix != null && fElementQName.uri == null) {
                  fErrorReporter.reportError(
                      XMLMessageFormatter.XMLNS_DOMAIN,
                      "ElementPrefixUnbound",
                      new Object[] {
                          fElementQName.prefix,
                          fElementQName.rawname },
                      XMLErrorReporter.SEVERITY_FATAL_ERROR);
              }
  
              // bind attributes (xmlns are already bound bellow)
              int length = fAttributes.getLength();
              for (int i = 0; i < length; i++) {
                  fAttributes.getName(i, fAttributeQName);
  
                  String aprefix =
                      fAttributeQName.prefix != null
                          ? fAttributeQName.prefix
                          : XMLSymbols.EMPTY_STRING;
                  String uri = fNamespaceContext.getURI(aprefix);
                  // REVISIT: try removing the first "if" and see if it is faster.
                  //
                  if (fAttributeQName.uri != null
                      && fAttributeQName.uri == uri) {
                      continue;
                  }
                  if (aprefix != XMLSymbols.EMPTY_STRING) {
                      fAttributeQName.uri = uri;
                      if (uri == null) {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XMLNS_DOMAIN,
                              "AttributePrefixUnbound",
                              new Object[] {
                                  fElementQName.rawname,
                                  fAttributeQName.rawname,
                                  aprefix },
                              XMLErrorReporter.SEVERITY_FATAL_ERROR);
                      }
                      fAttributes.setURI(i, uri);
                  }
              }
  
              if (length > 1) {
                  QName name = fAttributes.checkDuplicatesNS();
                  if (name != null) {
                      if (name.uri != null) {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XMLNS_DOMAIN,
                              "AttributeNSNotUnique",
                              new Object[] {
                                  fElementQName.rawname,
                                  name.localpart,
                                  name.uri },
                              XMLErrorReporter.SEVERITY_FATAL_ERROR);
                      } else {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XMLNS_DOMAIN,
                              "AttributeNotUnique",
                              new Object[] {
                                  fElementQName.rawname,
                                  name.rawname },
                              XMLErrorReporter.SEVERITY_FATAL_ERROR);
                      }
                  }
              }
          }
  
          // call handler
  
              if (empty) {
  
                  //decrease the markup depth..
                  fMarkupDepth--;
  
                  // check that this element was opened in the same entity
                  if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
                      reportFatalError(
                          "ElementEntityMismatch",
                          new Object[] { fCurrentElement.rawname });
                  }
  
                  fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
  
                  /*if (fBindNamespaces) {
                      fNamespaceContext.popContext();
                  }*/
                  fScanEndElement = true;
  
                  //pop the element off the stack..
                  fElementStack.popElement();
              } else {
  
                  if(dtdGrammarUtil != null)
                      dtdGrammarUtil.startElement(fElementQName, fAttributes);
  
                  if (fDocumentHandler != null)
                  fDocumentHandler.startElement(fElementQName, fAttributes, null);
              }
  
          if (DEBUG_START_END_ELEMENT)
              System.out.println("<<< scanStartElement(): " + empty);
          return empty;
  
      } // scanStartElement():boolean
  
      /**
       * Scans the name of an element in a start or empty tag.
       *
       * @see #scanStartElement()
       */
      protected void scanStartElementName ()
          throws IOException, XNIException {
          // Note: namespace processing is on by default
          fEntityScanner.scanQName(fElementQName);
          // Must skip spaces here because the DTD scanner
          // would consume them at the end of the external subset.
          fSawSpace = fEntityScanner.skipSpaces();
      } // scanStartElementName()
  
      /**
       * Scans the remainder of a start or empty tag after the element name.
       *
       * @see #scanStartElement
       * @return True if element is empty.
       */
      protected boolean scanStartElementAfterName()
          throws IOException, XNIException {
  
          // REVISIT - [Q] Why do we need this local variable? -- mrglavas
          String rawname = fElementQName.rawname;
          if (fBindNamespaces) {
              fNamespaceContext.pushContext();
              if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
                  if (fPerformValidation) {
                      fErrorReporter.reportError(
                          XMLMessageFormatter.XML_DOMAIN,
                          "MSG_GRAMMAR_NOT_FOUND",
                          new Object[] { rawname },
                          XMLErrorReporter.SEVERITY_ERROR);
  
                      if (fDoctypeName == null
                          || !fDoctypeName.equals(rawname)) {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XML_DOMAIN,
                              "RootElementTypeMustMatchDoctypedecl",
                              new Object[] { fDoctypeName, rawname },
                              XMLErrorReporter.SEVERITY_ERROR);
                      }
                  }
              }
          }
  
          // push element stack
          fCurrentElement = fElementStack.pushElement(fElementQName);
  
          // attributes
          boolean empty = false;
          fAttributes.removeAllAttributes();
          do {
  
              // end tag?
              int c = fEntityScanner.peekChar();
              if (c == '>') {
                  fEntityScanner.scanChar();
                  break;
              } else if (c == '/') {
                  fEntityScanner.scanChar();
                  if (!fEntityScanner.skipChar('>')) {
                      reportFatalError(
                          "ElementUnterminated",
                          new Object[] { rawname });
                  }
                  empty = true;
                  break;
              } else if (!isValidNameStartChar(c) || !fSawSpace) {
                  // Second chance. Check if this character is a high
                  // surrogate of a valid name start character.
                  if (!isValidNameStartHighSurrogate(c) || !fSawSpace) {
                      reportFatalError(
                          "ElementUnterminated",
                          new Object[] { rawname });
                  }
              }
  
              // attributes
              scanAttribute(fAttributes);
  
              // spaces
              fSawSpace = fEntityScanner.skipSpaces();
  
          } while (true);
  
          if (fBindNamespaces) {
              // REVISIT: is it required? forbit xmlns prefix for element
              if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
                  fErrorReporter.reportError(
                      XMLMessageFormatter.XMLNS_DOMAIN,
                      "ElementXMLNSPrefix",
                      new Object[] { fElementQName.rawname },
                      XMLErrorReporter.SEVERITY_FATAL_ERROR);
              }
  
              // bind the element
              String prefix =
                  fElementQName.prefix != null
                      ? fElementQName.prefix
                      : XMLSymbols.EMPTY_STRING;
              // assign uri to the element
              fElementQName.uri = fNamespaceContext.getURI(prefix);
              // make sure that object in the element stack is updated as well
              fCurrentElement.uri = fElementQName.uri;
  
              if (fElementQName.prefix == null && fElementQName.uri != null) {
                  fElementQName.prefix = XMLSymbols.EMPTY_STRING;
                  // making sure that the object in the element stack is updated too.
                  fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
              }
              if (fElementQName.prefix != null && fElementQName.uri == null) {
                  fErrorReporter.reportError(
                      XMLMessageFormatter.XMLNS_DOMAIN,
                      "ElementPrefixUnbound",
                      new Object[] {
                          fElementQName.prefix,
                          fElementQName.rawname },
                      XMLErrorReporter.SEVERITY_FATAL_ERROR);
              }
  
              // bind attributes (xmlns are already bound bellow)
              int length = fAttributes.getLength();
              for (int i = 0; i < length; i++) {
                  fAttributes.getName(i, fAttributeQName);
  
                  String aprefix =
                      fAttributeQName.prefix != null
                          ? fAttributeQName.prefix
                          : XMLSymbols.EMPTY_STRING;
                  String uri = fNamespaceContext.getURI(aprefix);
                  // REVISIT: try removing the first "if" and see if it is faster.
                  //
                  if (fAttributeQName.uri != null
                      && fAttributeQName.uri == uri) {
                      continue;
                  }
                  if (aprefix != XMLSymbols.EMPTY_STRING) {
                      fAttributeQName.uri = uri;
                      if (uri == null) {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XMLNS_DOMAIN,
                              "AttributePrefixUnbound",
                              new Object[] {
                                  fElementQName.rawname,
                                  fAttributeQName.rawname,
                                  aprefix },
                              XMLErrorReporter.SEVERITY_FATAL_ERROR);
                      }
                      fAttributes.setURI(i, uri);
                  }
              }
  
              if (length > 1) {
                  QName name = fAttributes.checkDuplicatesNS();
                  if (name != null) {
                      if (name.uri != null) {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XMLNS_DOMAIN,
                              "AttributeNSNotUnique",
                              new Object[] {
                                  fElementQName.rawname,
                                  name.localpart,
                                  name.uri },
                              XMLErrorReporter.SEVERITY_FATAL_ERROR);
                      } else {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XMLNS_DOMAIN,
                              "AttributeNotUnique",
                              new Object[] {
                                  fElementQName.rawname,
                                  name.rawname },
                              XMLErrorReporter.SEVERITY_FATAL_ERROR);
                      }
                  }
              }
          }
  
          // call handler
          if (fDocumentHandler != null) {
              if (empty) {
  
                  //decrease the markup depth..
                  fMarkupDepth--;
  
                  // check that this element was opened in the same entity
                  if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
                      reportFatalError(
                          "ElementEntityMismatch",
                          new Object[] { fCurrentElement.rawname });
                  }
  
                  fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
  
                  if (fBindNamespaces) {
                      fNamespaceContext.popContext();
                  }
                  //pop the element off the stack..
                  fElementStack.popElement();
              } else {
                  fDocumentHandler.startElement(fElementQName, fAttributes, null);
              }
          }
  
          if (DEBUG_START_END_ELEMENT)
              System.out.println("<<< scanStartElementAfterName(): " + empty);
          return empty;
  
      } // scanStartElementAfterName()
  
      /**
       * Scans an attribute.
       * <p>
       * <pre>
       * [41] Attribute ::= Name Eq AttValue
       * </pre>
       * <p>
       * <strong>Note:</strong> This method assumes that the next
       * character on the stream is the first character of the attribute
       * name.
       * <p>
       * <strong>Note:</strong> This method uses the fAttributeQName and
       * fQName variables. The contents of these variables will be
       * destroyed.
       *
       * @param attributes The attributes list for the scanned attribute.
       */
      protected void scanAttribute(XMLAttributesImpl attributes)
          throws IOException, XNIException {
          if (DEBUG_START_END_ELEMENT)
              System.out.println(">>> scanAttribute()");
  
          // name
          fEntityScanner.scanQName(fAttributeQName);
  
          // equals
          fEntityScanner.skipSpaces();
          if (!fEntityScanner.skipChar('=')) {
              reportFatalError(
                  "EqRequiredInAttribute",
                  new Object[] {
                      fCurrentElement.rawname,
                      fAttributeQName.rawname });
          }
          fEntityScanner.skipSpaces();
  
          // content
          int attrIndex;
  
          if (fBindNamespaces) {
              attrIndex = attributes.getLength();
              attributes.addAttributeNS(
                  fAttributeQName,
                  XMLSymbols.fCDATASymbol,
                  null);
          } else {
              int oldLen = attributes.getLength();
              attrIndex =
                  attributes.addAttribute(
                      fAttributeQName,
                      XMLSymbols.fCDATASymbol,
                      null);
  
              // WFC: Unique Att Spec
              if (oldLen == attributes.getLength()) {
                  reportFatalError(
                      "AttributeNotUnique",
                      new Object[] {
                          fCurrentElement.rawname,
                          fAttributeQName.rawname });
              }
          }
  
          //REVISIT: one more case needs to be included: external PE and standalone is no
          boolean isVC = fHasExternalDTD && !fStandalone;
  
          // REVISIT: it seems that this function should not take attributes, and length
          scanAttributeValue(
              this.fTempString,
              fTempString2,
              fAttributeQName.rawname,
              isVC,
              fCurrentElement.rawname);
          String value = fTempString.toString();
          attributes.setValue(attrIndex, value);
          attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
          attributes.setSpecified(attrIndex, true);
  
          // record namespace declarations if any.
          if (fBindNamespaces) {
  
              String localpart = fAttributeQName.localpart;
              String prefix =
                  fAttributeQName.prefix != null
                      ? fAttributeQName.prefix
                      : XMLSymbols.EMPTY_STRING;
              // when it's of form xmlns="..." or xmlns:prefix="...",
              // it's a namespace declaration. but prefix:xmlns="..." isn't.
              if (prefix == XMLSymbols.PREFIX_XMLNS
                  || prefix == XMLSymbols.EMPTY_STRING
                  && localpart == XMLSymbols.PREFIX_XMLNS) {
  
                  // get the internalized value of this attribute
                  String uri = fSymbolTable.addSymbol(value);
  
                  // 1. "xmlns" can't be bound to any namespace
                  if (prefix == XMLSymbols.PREFIX_XMLNS
                      && localpart == XMLSymbols.PREFIX_XMLNS) {
                      fErrorReporter.reportError(
                          XMLMessageFormatter.XMLNS_DOMAIN,
                          "CantBindXMLNS",
                          new Object[] { fAttributeQName },
                          XMLErrorReporter.SEVERITY_FATAL_ERROR);
                  }
  
                  // 2. the namespace for "xmlns" can't be bound to any prefix
                  if (uri == NamespaceContext.XMLNS_URI) {
                      fErrorReporter.reportError(
                          XMLMessageFormatter.XMLNS_DOMAIN,
                          "CantBindXMLNS",
                          new Object[] { fAttributeQName },
                          XMLErrorReporter.SEVERITY_FATAL_ERROR);
                  }
  
                  // 3. "xml" can't be bound to any other namespace than it's own
                  if (localpart == XMLSymbols.PREFIX_XML) {
                      if (uri != NamespaceContext.XML_URI) {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XMLNS_DOMAIN,
                              "CantBindXML",
                              new Object[] { fAttributeQName },
                              XMLErrorReporter.SEVERITY_FATAL_ERROR);
                      }
                  }
                  // 4. the namespace for "xml" can't be bound to any other prefix
                  else {
                      if (uri == NamespaceContext.XML_URI) {
                          fErrorReporter.reportError(
                              XMLMessageFormatter.XMLNS_DOMAIN,
                              "CantBindXML",
                              new Object[] { fAttributeQName },
                              XMLErrorReporter.SEVERITY_FATAL_ERROR);
                      }
                  }
  
                  prefix =
                      localpart != XMLSymbols.PREFIX_XMLNS
                          ? localpart
                          : XMLSymbols.EMPTY_STRING;
  
                  // Declare prefix in context. Removing the association between a prefix and a
                  // namespace name is permitted in XML 1.1, so if the uri value is the empty string,
                  // the prefix is being unbound. -- mrglavas
                  fNamespaceContext.declarePrefix(
                      prefix,
                      uri.length() != 0 ? uri : null);
                  // bind namespace attribute to a namespace
                  attributes.setURI(
                      attrIndex,
                      fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS));
  
              } else {
                  // attempt to bind attribute
                  if (fAttributeQName.prefix != null) {
                      attributes.setURI(
                          attrIndex,
                          fNamespaceContext.getURI(fAttributeQName.prefix));
                  }
              }
          }
  
          if (DEBUG_START_END_ELEMENT)
              System.out.println("<<< scanAttribute()");
      } // scanAttribute(XMLAttributes)
  
      /**
       * Scans an end element.
       * <p>
       * <pre>
       * [42] ETag ::= '&lt;/' Name S? '>'
       * </pre>
       * <p>
       * <strong>Note:</strong> This method uses the fElementQName variable.
       * The contents of this variable will be destroyed. The caller should
       * copy the needed information out of this variable before calling
       * this method.
       *
       * @return The element depth.
       */
      protected int scanEndElement() throws IOException, XNIException {
          if (DEBUG_START_END_ELEMENT)
              System.out.println(">>> scanEndElement()");
  
          // pop context
          QName endElementName = fElementStack.popElement();
  
          // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
          //In scanners most of the time is consumed on checks done for XML characters, we can
          // optimize on it and avoid the checks done for endElement,
          //we will also avoid symbol table lookup - neeraj.bajaj@sun.com
  
          // this should work both for namespace processing true or false...
  
          //REVISIT: if the string is not the same as expected.. we need to do better error handling..
          //We can skip this for now... In any case if the string doesn't match -- document is not well formed.
  
          if (!fEntityScanner.skipString(endElementName.rawname)) {
               reportFatalError(
                  "ETagRequired",
                  new Object[] { endElementName.rawname });
          }
  
          // end
          fEntityScanner.skipSpaces();
          if (!fEntityScanner.skipChar('>')) {
              reportFatalError(
                  "ETagUnterminated",
                  new Object[] { endElementName.rawname });
          }
          fMarkupDepth--;
  
          //we have increased the depth for two markup "<" characters
          fMarkupDepth--;
  
          // check that this element was opened in the same entity
          if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
              reportFatalError(
                  "ElementEntityMismatch",
                  new Object[] { endElementName.rawname });
          }
  
          // call handler
          if (fDocumentHandler != null) {
              fDocumentHandler.endElement(endElementName, null);
  
              /*if (fBindNamespaces) {
                  fNamespaceContext.popContext();
              }*/
  
          }
  
          if(dtdGrammarUtil != null)
              dtdGrammarUtil.endElement(endElementName);
  
          return fMarkupDepth;
  
      } // scanEndElement():int
  
      public void reset(XMLComponentManager componentManager)
          throws XMLConfigurationException {
  
          super.reset(componentManager);
          fPerformValidation = false;
          fBindNamespaces = false;
      }
  
      /** Creates a content Driver. */
      protected Driver createContentDriver() {
          return new NS11ContentDriver();
      } // createContentDriver():Driver
  
  
      /** return the next state on the input
       *
       * @return int
       */
  
      public int next() throws IOException, XNIException {
          //since namespace context should still be valid when the parser is at the end element state therefore
          //we pop the context only when next() has been called after the end element state was encountered. - nb.
  
          if((fScannerLastState == XMLEvent.END_ELEMENT) && fBindNamespaces){
              fScannerLastState = -1;
              fNamespaceContext.popContext();
          }
  
          return fScannerLastState = super.next();
      }
  
  
      /**
       * Driver to handle content scanning.
       */
      protected final class NS11ContentDriver extends ContentDriver {
          /**
           * Scan for root element hook. This method is a hook for
           * subclasses to add code that handles scanning for the root
           * element. This method will also attempt to remove DTD validator
           * from the pipeline, if there is no DTD grammar. If DTD validator
           * is no longer in the pipeline bind namespaces in the scanner.
           *
           *
           * @return True if the caller should stop and return true which
           *          allows the scanner to switch to a new scanning
           *          Driver. A return value of false indicates that
           *          the content Driver should continue as normal.
           */
          protected boolean scanRootElementHook()
              throws IOException, XNIException {
  
              if (fExternalSubsetResolver != null && !fSeenDoctypeDecl
                  && !fDisallowDoctype && (fValidation || fLoadExternalDTD)) {
                  scanStartElementName();
                  resolveExternalSubsetAndRead();
                  reconfigurePipeline();
                  if (scanStartElementAfterName()) {
                      setScannerState(SCANNER_STATE_TRAILING_MISC);
                      setDriver(fTrailingMiscDriver);
                      return true;
                  }
              }
              else {
                  reconfigurePipeline();
                  if (scanStartElement()) {
                      setScannerState(SCANNER_STATE_TRAILING_MISC);
                      setDriver(fTrailingMiscDriver);
                      return true;
                  }
              }
              return false;
  
          } // scanRootElementHook():boolean
  
          /**
           * Re-configures pipeline by removing the DTD validator
           * if no DTD grammar exists. If no validator exists in the
           * pipeline or there is no DTD grammar, namespace binding
           * is performed by the scanner in the enclosing class.
           */
          private void reconfigurePipeline() {
              if (fDTDValidator == null) {
                  fBindNamespaces = true;
              }
              else if (!fDTDValidator.hasGrammar()) {
                  fBindNamespaces = true;
                  fPerformValidation = fDTDValidator.validate();
                  // re-configure pipeline
                  XMLDocumentSource source = fDTDValidator.getDocumentSource();
                  XMLDocumentHandler handler = fDTDValidator.getDocumentHandler();
                  source.setDocumentHandler(handler);
                  if (handler != null)
                      handler.setDocumentSource(source);
                  fDTDValidator.setDocumentSource(null);
                  fDTDValidator.setDocumentHandler(null);
              }
          } // reconfigurePipeline()
      }
  }
  