content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package mf.org.apache.xerces.impl.xs.traversers;
  
  import org.xml.sax.Attributes;
  import org.xml.sax.ContentHandler;
  import org.xml.sax.Locator;
  import org.xml.sax.SAXException;
  import org.xml.sax.SAXParseException;
  import org.xml.sax.helpers.LocatorImpl;
  
  import mf.org.apache.xerces.impl.xs.opti.SchemaDOMParser;
  import mf.org.apache.xerces.util.NamespaceSupport;
  import mf.org.apache.xerces.util.SAXLocatorWrapper;
  import mf.org.apache.xerces.util.SymbolTable;
  import mf.org.apache.xerces.util.XMLAttributesImpl;
  import mf.org.apache.xerces.util.XMLStringBuffer;
  import mf.org.apache.xerces.util.XMLSymbols;
  import mf.org.apache.xerces.xni.NamespaceContext;
  import mf.org.apache.xerces.xni.QName;
  import mf.org.apache.xerces.xni.XMLString;
  import mf.org.apache.xerces.xni.XNIException;
  import mf.org.apache.xerces.xni.parser.XMLParseException;
  import mf.org.w3c.dom.Document;
  
  /**
   * <p>SchemaContentHandler converts SAX events into XNI
   * and passes them directly to the SchemaDOMParser.</p>
   *
   * @author Michael Glavassevich, IBM
   * @author Jack Z. Wang, IBM
   * @version $Id: SchemaContentHandler.java 778956 2009-05-27 01:39:26Z mrglavas $
   * @xerces.internal
   */
  final class SchemaContentHandler implements ContentHandler {
  
      /**
       * XML Locator wrapper for SAX.
       **/
      private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper();
      /**
       * Fields for start element, end element and characters.
       */
      private final QName fElementQName = new QName();
      private final QName fAttributeQName = new QName();
      private final XMLAttributesImpl fAttributes = new XMLAttributesImpl();
      private final XMLString fTempString = new XMLString();
      private final XMLStringBuffer fStringBuffer = new XMLStringBuffer();
      /**
       * Symbol table
       **/
      private SymbolTable fSymbolTable;
      /**
       * SchemaDOMParser, events will be delegated to SchemaDOMParser to pass
       */
      private SchemaDOMParser fSchemaDOMParser;
      /**
       * The namespace context of this document: stores namespaces in scope
       */
      private NamespaceSupport fNamespaceContext = new NamespaceSupport();
      /**
       * Indicate if push NamespaceContest is needed
       */
      private boolean fNeedPushNSContext;
      /**
       * Flag used to track whether namespace declarations are reported as attributes.
       */
      private boolean fNamespacePrefixes = false;
      /**
       * Flag used to track whether XML names and Namespace URIs have been internalized.
       */
      private boolean fStringsInternalized = false;
  
      /**
       * <p>Constructs an SchemaContentHandler.</p>
       */
      public SchemaContentHandler() {
      }
  
      static void convertToSAXParseException(XMLParseException e) throws SAXException {
          Exception ex = e.getException();
          if (ex == null) {
              // must be a parser exception; mine it for locator info and throw
              // a SAXParseException
              LocatorImpl locatorImpl = new LocatorImpl();
              locatorImpl.setPublicId(e.getPublicId());
              locatorImpl.setSystemId(e.getExpandedSystemId());
              locatorImpl.setLineNumber(e.getLineNumber());
              locatorImpl.setColumnNumber(e.getColumnNumber());
              throw new SAXParseException(e.getMessage(), locatorImpl);
          }
          if (ex instanceof SAXException) {
              // why did we create an XMLParseException?
              throw (SAXException) ex;
          }
          throw new SAXException(ex);
      }
  
      static void convertToSAXException(XNIException e) throws SAXException {
          Exception ex = e.getException();
          if (ex == null) {
              throw new SAXException(e.getMessage());
          }
          if (ex instanceof SAXException) {
              throw (SAXException) ex;
          }
          throw new SAXException(ex);
      }
  
      /*
       * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
       */
      public Document getDocument() {
          return fSchemaDOMParser.getDocument();
      }
  
      /*
       * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
       */
      @Override
      public void setDocumentLocator(Locator locator) {
          fSAXLocatorWrapper.setLocator(locator);
      }
  
      /*
       * @see org.xml.sax.ContentHandler#startDocument()
       */
      @Override
      public void startDocument() throws SAXException {
          fNeedPushNSContext = true;
          fNamespaceContext.reset();
          try {
              fSchemaDOMParser.startDocument(fSAXLocatorWrapper, null, fNamespaceContext, null);
          } catch (XMLParseException e) {
              convertToSAXParseException(e);
          } catch (XNIException e) {
              convertToSAXException(e);
          }
      }
  
      /*
       * @see org.xml.sax.ContentHandler#endDocument()
       */
      @Override
      public void endDocument() throws SAXException {
          fSAXLocatorWrapper.setLocator(null);
          try {
              fSchemaDOMParser.endDocument(null);
          } catch (XMLParseException e) {
              convertToSAXParseException(e);
          } catch (XNIException e) {
              convertToSAXException(e);
          }
      }
  
      /*
       * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
       */
      @Override
      public void startPrefixMapping(String prefix, String uri) throws SAXException {
          if (fNeedPushNSContext) {
              fNeedPushNSContext = false;
              fNamespaceContext.pushContext();
          }
          if (!fStringsInternalized) {
              prefix = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING;
              uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
          } else {
              if (prefix == null) {
                  prefix = XMLSymbols.EMPTY_STRING;
              }
              if (uri != null && uri.length() == 0) {
                  uri = null;
              }
          }
          fNamespaceContext.declarePrefix(prefix, uri);
      }
  
      /*
       * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
       */
      @Override
      public void endPrefixMapping(String prefix) throws SAXException {
          // do nothing
      }
  
      /*
       * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
       */
      @Override
      public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
          if (fNeedPushNSContext) {
              fNamespaceContext.pushContext();
          }
          fNeedPushNSContext = true;
  
          // Fill element QName and XMLAttributes
          fillQName(fElementQName, uri, localName, qName);
          fillXMLAttributes(atts);
  
          // Add namespace declarations if necessary
          if (!fNamespacePrefixes) {
              final int prefixCount = fNamespaceContext.getDeclaredPrefixCount();
              if (prefixCount > 0) {
                  addNamespaceDeclarations(prefixCount);
              }
          }
  
          try {
              fSchemaDOMParser.startElement(fElementQName, fAttributes, null);
          } catch (XMLParseException e) {
              convertToSAXParseException(e);
          } catch (XNIException e) {
              convertToSAXException(e);
          }
      }
  
      /*
       * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
       */
      @Override
      public void endElement(String uri, String localName, String qName) throws SAXException {
          fillQName(fElementQName, uri, localName, qName);
          try {
              fSchemaDOMParser.endElement(fElementQName, null);
          } catch (XMLParseException e) {
              convertToSAXParseException(e);
          } catch (XNIException e) {
              convertToSAXException(e);
          } finally {
              fNamespaceContext.popContext();
          }
      }
  
      /*
       * @see org.xml.sax.ContentHandler#characters(char[], int, int)
       */
      @Override
      public void characters(char[] ch, int start, int length) throws SAXException {
          try {
              fTempString.setValues(ch, start, length);
              fSchemaDOMParser.characters(fTempString, null);
          } catch (XMLParseException e) {
              convertToSAXParseException(e);
          } catch (XNIException e) {
              convertToSAXException(e);
          }
      }
  
      /*
       * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
       */
      @Override
      public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
          try {
              fTempString.setValues(ch, start, length);
              fSchemaDOMParser.ignorableWhitespace(fTempString, null);
          } catch (XMLParseException e) {
              convertToSAXParseException(e);
          } catch (XNIException e) {
              convertToSAXException(e);
          }
      }
      
      /*
       * Other methods
       */
  
      /*
       * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
       */
      @Override
      public void processingInstruction(String target, String data) throws SAXException {
          try {
              fTempString.setValues(data.toCharArray(), 0, data.length());
              fSchemaDOMParser.processingInstruction(target, fTempString, null);
          } catch (XMLParseException e) {
              convertToSAXParseException(e);
          } catch (XNIException e) {
              convertToSAXException(e);
          }
      }
  
      /*
       * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
       */
      @Override
      public void skippedEntity(String arg) throws SAXException {
          // do-nothing
      }
  
      private void fillQName(QName toFill, String uri, String localpart, String rawname) {
          if (!fStringsInternalized) {
              uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
              localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING;
              rawname = (rawname != null) ? fSymbolTable.addSymbol(rawname) : XMLSymbols.EMPTY_STRING;
          } else {
              if (uri != null && uri.length() == 0) {
                  uri = null;
              }
              if (localpart == null) {
                  localpart = XMLSymbols.EMPTY_STRING;
              }
              if (rawname == null) {
                  rawname = XMLSymbols.EMPTY_STRING;
              }
          }
          String prefix = XMLSymbols.EMPTY_STRING;
          int prefixIdx = rawname.indexOf(':');
          if (prefixIdx != -1) {
              prefix = fSymbolTable.addSymbol(rawname.substring(0, prefixIdx));
              // local part may be an empty string if this is a namespace declaration
              if (localpart == XMLSymbols.EMPTY_STRING) {
                  localpart = fSymbolTable.addSymbol(rawname.substring(prefixIdx + 1));
              }
          }
          // local part may be an empty string if this is a namespace declaration
          else if (localpart == XMLSymbols.EMPTY_STRING) {
              localpart = rawname;
          }
          toFill.setValues(prefix, localpart, rawname, uri);
      }
  
      private void fillXMLAttributes(Attributes atts) {
          fAttributes.removeAllAttributes();
          final int attrCount = atts.getLength();
          for (int i = 0; i < attrCount; ++i) {
              fillQName(fAttributeQName, atts.getURI(i), atts.getLocalName(i), atts.getQName(i));
              String type = atts.getType(i);
              fAttributes.addAttributeNS(fAttributeQName, (type != null) ? type : XMLSymbols.fCDATASymbol, atts.getValue(i));
              fAttributes.setSpecified(i, true);
          }
      }
      
      /*
       * Static methods
       */
  
      private void addNamespaceDeclarations(final int prefixCount) {
          String prefix = null;
          String localpart = null;
          String rawname = null;
          String nsPrefix = null;
          String nsURI = null;
          for (int i = 0; i < prefixCount; ++i) {
              nsPrefix = fNamespaceContext.getDeclaredPrefixAt(i);
              nsURI = fNamespaceContext.getURI(nsPrefix);
              if (nsPrefix.length() > 0) {
                  prefix = XMLSymbols.PREFIX_XMLNS;
                  localpart = nsPrefix;
                  fStringBuffer.clear();
                  fStringBuffer.append(prefix);
                  fStringBuffer.append(':');
                  fStringBuffer.append(localpart);
                  rawname = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
              } else {
                  prefix = XMLSymbols.EMPTY_STRING;
                  localpart = XMLSymbols.PREFIX_XMLNS;
                  rawname = XMLSymbols.PREFIX_XMLNS;
              }
              fAttributeQName.setValues(prefix, localpart, rawname, NamespaceContext.XMLNS_URI);
              fAttributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol,
                      (nsURI != null) ? nsURI : XMLSymbols.EMPTY_STRING);
          }
      }
  
      public void reset(SchemaDOMParser schemaDOMParser, SymbolTable symbolTable,
                        boolean namespacePrefixes, boolean stringsInternalized) {
          fSchemaDOMParser = schemaDOMParser;
          fSymbolTable = symbolTable;
          fNamespacePrefixes = namespacePrefixes;
          fStringsInternalized = stringsInternalized;
      }
  
  } // SchemaContentHandler
  