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!
   */
  /*
   * Copyright 1999-2005 The Apache Software Foundation.
   *
   * Licensed 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 jaxp.sun.org.apache.xerces.internal.dom;
  
  import jaxp.sun.org.apache.xerces.internal.impl.RevalidationHandler;
  import jaxp.sun.org.apache.xerces.internal.parsers.DOMParserImpl;
  import jaxp.sun.org.apache.xerces.internal.parsers.DTDConfiguration;
  import jaxp.sun.org.apache.xerces.internal.parsers.XIncludeAwareParserConfiguration;
  import jaxp.sun.org.apache.xerces.internal.util.XMLChar;
  import jaxp.sun.org.apache.xerces.internal.utils.ObjectFactory;
  import jaxp.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  import jaxp.sun.org.apache.xml.internal.serialize.DOMSerializerImpl;
  import org.w3c.dom.DOMException;
  import org.w3c.dom.DOMImplementation;
  import org.w3c.dom.Document;
  import org.w3c.dom.DocumentType;
  import org.w3c.dom.Element;
  import org.w3c.dom.ls.LSParser;
  import org.w3c.dom.ls.DOMImplementationLS;
  import org.w3c.dom.ls.LSInput;
  import org.w3c.dom.ls.LSOutput;
  import org.w3c.dom.ls.LSSerializer;
  
  /**
   * The DOMImplementation class is description of a particular
   * implementation of the Document Object Model. As such its data is
   * static, shared by all instances of this implementation.
   * <P>
   * The DOM API requires that it be a real object rather than static
   * methods. However, there's nothing that says it can't be a singleton,
   * so that's how I've implemented it.
   * <P>
   * This particular class, along with CoreDocumentImpl, supports the DOM
   * Core and Load/Save (Experimental). Optional modules are supported by
   * the more complete DOMImplementation class along with DocumentImpl.
   *
   * @xerces.internal
   *
   * @version $Id: CoreDOMImplementationImpl.java,v 1.6 2010-11-01 04:39:37 joehw Exp $
   * @since PR-DOM-Level-1-19980818.
   */
  public class CoreDOMImplementationImpl
          implements DOMImplementation, DOMImplementationLS {
          //
          // Data
          //
  
      // validators pool
      private static final int SIZE = 2;
      private RevalidationHandler validators[] = new RevalidationHandler[SIZE];
  
      private RevalidationHandler dtdValidators[] = new RevalidationHandler[SIZE];
      private int freeValidatorIndex = -1;
      private int freeDTDValidatorIndex = -1;
      private int currentSize = SIZE;
  
      // Document and doctype counter.  Used to assign order to documents and
      // doctypes without owners, on an demand basis.   Used for
      // compareDocumentPosition
      private int docAndDoctypeCounter = 0;
  
          // static
          /** Dom implementation singleton. */
          static CoreDOMImplementationImpl singleton =
                  new CoreDOMImplementationImpl();
          //
          // Public methods
          //
          /** NON-DOM: Obtain and return the single shared object */
          public static DOMImplementation getDOMImplementation() {
                  return singleton;
          }
          //
          // DOMImplementation methods
          //
          /**
           * Test if the DOM implementation supports a specific "feature" --
           * currently meaning language and level thereof.
           *
           * @param feature The package name of the feature to test.
           * In Level 1, supported values are "HTML" and "XML" (case-insensitive).
           * At this writing, com.sun.org.apache.xerces.internal.dom supports only XML.
           *
           * @param version The version number of the feature being tested.
           * This is interpreted as "Version of the DOM API supported for the
           * specified Feature", and in Level 1 should be "1.0"
           *
           * @return true iff this implementation is compatable with the specified
           * feature and version.
           */
          public boolean hasFeature(String feature, String version) {
  
              boolean anyVersion = version == null || version.length() == 0;
  
              // check if Xalan implementation is around and if yes report true for supporting
              // XPath API
              // if a plus sign "+" is prepended to any feature name, implementations
              // are considered in which the specified feature may not be directly
              // castable DOMImplementation.getFeature(feature, version). Without a
              // plus, only features whose interfaces are directly castable are considered.
              if ((feature.equalsIgnoreCase("+XPath"))
                  && (anyVersion || version.equals("3.0"))) {
                  try {
                      Class xpathClass = ObjectFactory.findProviderClass(
                          "jaxp.sun.org.apache.xpath.internal.domapi.XPathEvaluatorImpl", true);
  
                  // Check if the DOM XPath implementation implements
                  // the interface org.w3c.dom.XPathEvaluator
                  Class interfaces[] = xpathClass.getInterfaces();
                  for (int i = 0; i < interfaces.length; i++) {
                      if (interfaces[i].getName().equals(
                          "org.w3c.dom.xpath.XPathEvaluator")) {
                          return true;
                      }
                  }
                  } catch (Exception e) {
                      return false;
                  }
                  return true;
              }
              if (feature.startsWith("+")) {
                  feature = feature.substring(1);
              }
              return (
                  feature.equalsIgnoreCase("Core")
                      && (anyVersion
                          || version.equals("1.0")
                          || version.equals("2.0")
                          || version.equals("3.0")))
                          || (feature.equalsIgnoreCase("XML")
                      && (anyVersion
                          || version.equals("1.0")
                          || version.equals("2.0")
                          || version.equals("3.0")))
                          || (feature.equalsIgnoreCase("LS")
                      && (anyVersion || version.equals("3.0")));
          } // hasFeature(String,String):boolean
  
  
          /**
           * Introduced in DOM Level 2. <p>
           *
           * Creates an empty DocumentType node.
           *
           * @param qualifiedName The qualified name of the document type to be created.
           * @param publicID The document type public identifier.
           * @param systemID The document type system identifier.
           * @since WD-DOM-Level-2-19990923
           */
          public DocumentType createDocumentType( String qualifiedName,
                                      String publicID, String systemID) {
                  // REVISIT: this might allow creation of invalid name for DOCTYPE
                  //          xmlns prefix.
                  //          also there is no way for a user to turn off error checking.
                  checkQName(qualifiedName);
                  return new DocumentTypeImpl(null, qualifiedName, publicID, systemID);
          }
  
      final void checkQName(String qname){
          int index = qname.indexOf(':');
          int lastIndex = qname.lastIndexOf(':');
          int length = qname.length();
  
          // it is an error for NCName to have more than one ':'
          // check if it is valid QName [Namespace in XML production 6]
          if (index == 0 || index == length - 1 || lastIndex != index) {
              String msg =
                  DOMMessageFormatter.formatMessage(
                      DOMMessageFormatter.DOM_DOMAIN,
                      "NAMESPACE_ERR",
                      null);
              throw new DOMException(DOMException.NAMESPACE_ERR, msg);
          }
          int start = 0;
          // Namespace in XML production [6]
          if (index > 0) {
              // check that prefix is NCName
              if (!XMLChar.isNCNameStart(qname.charAt(start))) {
                  String msg =
                      DOMMessageFormatter.formatMessage(
                          DOMMessageFormatter.DOM_DOMAIN,
                          "INVALID_CHARACTER_ERR",
                          null);
                  throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
              }
              for (int i = 1; i < index; i++) {
                  if (!XMLChar.isNCName(qname.charAt(i))) {
                      String msg =
                          DOMMessageFormatter.formatMessage(
                              DOMMessageFormatter.DOM_DOMAIN,
                              "INVALID_CHARACTER_ERR",
                              null);
                      throw new DOMException(
                          DOMException.INVALID_CHARACTER_ERR,
                          msg);
                  }
              }
              start = index + 1;
          }
  
          // check local part
          if (!XMLChar.isNCNameStart(qname.charAt(start))) {
              // REVISIT: add qname parameter to the message
              String msg =
                  DOMMessageFormatter.formatMessage(
                      DOMMessageFormatter.DOM_DOMAIN,
                      "INVALID_CHARACTER_ERR",
                      null);
              throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
          }
          for (int i = start + 1; i < length; i++) {
              if (!XMLChar.isNCName(qname.charAt(i))) {
                  String msg =
                      DOMMessageFormatter.formatMessage(
                          DOMMessageFormatter.DOM_DOMAIN,
                          "INVALID_CHARACTER_ERR",
                          null);
                  throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
              }
          }
      }
  
  
          /**
           * Introduced in DOM Level 2. <p>
           *
           * Creates an XML Document object of the specified type with its document
           * element.
           *
           * @param namespaceURI     The namespace URI of the document
           *                         element to create, or null.
           * @param qualifiedName    The qualified name of the document
           *                         element to create.
           * @param doctype          The type of document to be created or null.<p>
           *
           *                         When doctype is not null, its
           *                         Node.ownerDocument attribute is set to
           *                         the document being created.
           * @return Document        A new Document object.
           * @throws DOMException    WRONG_DOCUMENT_ERR: Raised if doctype has
           *                         already been used with a different document.
           * @since WD-DOM-Level-2-19990923
           */
          public Document createDocument(
                  String namespaceURI,
                  String qualifiedName,
                  DocumentType doctype)
                  throws DOMException {
                  if (doctype != null && doctype.getOwnerDocument() != null) {
                          String msg =
                                  DOMMessageFormatter.formatMessage(
                                          DOMMessageFormatter.DOM_DOMAIN,
                                          "WRONG_DOCUMENT_ERR",
                                          null);
                          throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
                  }
                  CoreDocumentImpl doc = new CoreDocumentImpl(doctype);
                  Element e = doc.createElementNS(namespaceURI, qualifiedName);
                  doc.appendChild(e);
                  return doc;
          }
  
          /**
           * DOM Level 3 WD - Experimental.
           */
          public Object getFeature(String feature, String version) {
              if (singleton.hasFeature(feature, version)) {
                  if ((feature.equalsIgnoreCase("+XPath"))) {
                      try {
                          Class xpathClass = ObjectFactory.findProviderClass(
                              "jaxp.sun.org.apache.xpath.internal.domapi.XPathEvaluatorImpl", true);
                          // Check if the DOM XPath implementation implements
                          // the interface org.w3c.dom.XPathEvaluator
                          Class interfaces[] = xpathClass.getInterfaces();
                          for (int i = 0; i < interfaces.length; i++) {
                              if (interfaces[i].getName().equals(
                                  "org.w3c.dom.xpath.XPathEvaluator")) {
                                  return xpathClass.newInstance();
                              }
                          }
                      } catch (Exception e) {
                          return null;
                      }
                  } else {
                      return singleton;
                  }
              }
              return null;
          }
  
          // DOM L3 LS
  
          /**
           * DOM Level 3 LS CR - Experimental.
       * Create a new <code>LSParser</code>. The newly constructed parser may
       * then be configured by means of its <code>DOMConfiguration</code>
       * object, and used to parse documents by means of its <code>parse</code>
       *  method.
       * @param mode  The <code>mode</code> argument is either
       *   <code>MODE_SYNCHRONOUS</code> or <code>MODE_ASYNCHRONOUS</code>, if
       *   <code>mode</code> is <code>MODE_SYNCHRONOUS</code> then the
       *   <code>LSParser</code> that is created will operate in synchronous
       *   mode, if it's <code>MODE_ASYNCHRONOUS</code> then the
       *   <code>LSParser</code> that is created will operate in asynchronous
       *   mode.
       * @param schemaType  An absolute URI representing the type of the schema
       *   language used during the load of a <code>Document</code> using the
       *   newly created <code>LSParser</code>. Note that no lexical checking
       *   is done on the absolute URI. In order to create a
       *   <code>LSParser</code> for any kind of schema types (i.e. the
       *   LSParser will be free to use any schema found), use the value
       *   <code>null</code>.
       * <p ><b>Note:</b>    For W3C XML Schema [<a href='http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/'>XML Schema Part 1</a>]
       *   , applications must use the value
       *   <code>"http://www.w3.org/2001/XMLSchema"</code>. For XML DTD [<a href='http://www.w3.org/TR/2000/REC-xml-20001006'>XML 1.0</a>],
       *   applications must use the value
       *   <code>"http://www.w3.org/TR/REC-xml"</code>. Other Schema languages
       *   are outside the scope of the W3C and therefore should recommend an
       *   absolute URI in order to use this method.
       * @return  The newly created <code>LSParser</code> object. This
       *   <code>LSParser</code> is either synchronous or asynchronous
       *   depending on the value of the <code>mode</code> argument.
       * <p ><b>Note:</b>    By default, the newly created <code>LSParser</code>
       *    does not contain a <code>DOMErrorHandler</code>, i.e. the value of
       *   the "<a href='http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030609/core.html#parameter-error-handler'>
       *   error-handler</a>" configuration parameter is <code>null</code>. However, implementations
       *   may provide a default error handler at creation time. In that case,
       *   the initial value of the <code>"error-handler"</code> configuration
       *   parameter on the new created <code>LSParser</code> contains a
       *   reference to the default error handler.
       * @exception DOMException
       *    NOT_SUPPORTED_ERR: Raised if the requested mode or schema type is
       *   not supported.
           */
          public LSParser createLSParser(short mode, String schemaType)
                  throws DOMException {
                  if (mode != DOMImplementationLS.MODE_SYNCHRONOUS || (schemaType !=null &&
                     !"http://www.w3.org/2001/XMLSchema".equals(schemaType) &&
                          !"http://www.w3.org/TR/REC-xml".equals(schemaType))) {
                          String msg =
                                  DOMMessageFormatter.formatMessage(
                                          DOMMessageFormatter.DOM_DOMAIN,
                                          "NOT_SUPPORTED_ERR",
                                          null);
                          throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
                  }
                  if (schemaType != null
                          && schemaType.equals("http://www.w3.org/TR/REC-xml")) {
                          return new DOMParserImpl(new DTDConfiguration(),
                                  schemaType);
                  }
                  else {
                          // create default parser configuration validating against XMLSchemas
                          return new DOMParserImpl(new XIncludeAwareParserConfiguration(),
                                  schemaType);
                  }
          }
  
          /**
           * DOM Level 3 LS CR - Experimental.
           * Create a new <code>LSSerializer</code> object.
           * @return The newly created <code>LSSerializer</code> object.
           * <p ><b>Note:</b>    By default, the newly created
           * <code>LSSerializer</code> has no <code>DOMErrorHandler</code>,
           * i.e. the value of the <code>"error-handler"</code> configuration
           * parameter is <code>null</code>. However, implementations may
           * provide a default error handler at creation time. In that case, the
           * initial value of the <code>"error-handler"</code> configuration
           * parameter on the new created <code>LSSerializer</code> contains a
           * reference to the default error handler.
           */
          public LSSerializer createLSSerializer() {
          return new DOMSerializerImpl();
      }
          /**
           * DOM Level 3 LS CR - Experimental.
           * Create a new empty input source.
           * @return  The newly created input object.
           */
          public LSInput createLSInput() {
                  return new DOMInputImpl();
          }
  
          //
          // Protected methods
          //
          /** NON-DOM: retrieve validator. */
          synchronized RevalidationHandler getValidator(String schemaType) {
                  // REVISIT: implement retrieving DTD validator
          if (schemaType == XMLGrammarDescription.XML_SCHEMA) {
              // create new validator - we should not attempt
              // to restrict the number of validation handlers being
              // requested
              if(freeValidatorIndex < 0) {
                  return (RevalidationHandler) (ObjectFactory
                              .newInstance(
                                  "jaxp.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator",
                                  ObjectFactory.findClassLoader(),
                                  true));
              }
              // return first available validator
              RevalidationHandler val = validators[freeValidatorIndex];
              validators[freeValidatorIndex--] = null;
              return val;
          }
          else if(schemaType == XMLGrammarDescription.XML_DTD) {
              if(freeDTDValidatorIndex < 0) {
                  return (RevalidationHandler) (ObjectFactory
                              .newInstance(
                                  "jaxp.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator",
                                  ObjectFactory.findClassLoader(),
                                  true));
              }
              // return first available validator
              RevalidationHandler val = dtdValidators[freeDTDValidatorIndex];
              dtdValidators[freeDTDValidatorIndex--] = null;
              return val;
          }
          return null;
          }
  
          /** NON-DOM: release validator */
          synchronized void releaseValidator(String schemaType,
                                           RevalidationHandler validator) {
         // REVISIT: implement support for DTD validators as well
         if(schemaType == XMLGrammarDescription.XML_SCHEMA) {
             ++freeValidatorIndex;
             if (validators.length == freeValidatorIndex ){
                  // resize size of the validators
                  currentSize+=SIZE;
                  RevalidationHandler newarray[] =  new RevalidationHandler[currentSize];
                  System.arraycopy(validators, 0, newarray, 0, validators.length);
                  validators = newarray;
             }
             validators[freeValidatorIndex]=validator;
         }
         else if(schemaType == XMLGrammarDescription.XML_DTD) {
             ++freeDTDValidatorIndex;
             if (dtdValidators.length == freeDTDValidatorIndex ){
                  // resize size of the validators
                  currentSize+=SIZE;
                  RevalidationHandler newarray[] =  new RevalidationHandler[currentSize];
                  System.arraycopy(dtdValidators, 0, newarray, 0, dtdValidators.length);
                  dtdValidators = newarray;
             }
             dtdValidators[freeDTDValidatorIndex]=validator;
         }
          }
  
         /** NON-DOM:  increment document/doctype counter */
         protected synchronized int assignDocumentNumber() {
              return ++docAndDoctypeCounter;
         }
         /** NON-DOM:  increment document/doctype counter */
         protected synchronized int assignDocTypeNumber() {
              return ++docAndDoctypeCounter;
         }
  
      /* DOM Level 3 LS CR - Experimental.
       *
       * Create a new empty output destination object where
       * <code>LSOutput.characterStream</code>,
       * <code>LSOutput.byteStream</code>, <code>LSOutput.systemId</code>,
       * <code>LSOutput.encoding</code> are null.
  
       * @return  The newly created output object.
       */
         public LSOutput createLSOutput() {
             return new DOMOutputImpl();
         }
  
  } // class DOMImplementationImpl
  