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 2001-2004 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.
   */
  /*
   * $Id: BasisLibrary.java,v 1.6 2006/06/20 21:51:58 spericas Exp $
   */
  
  package jaxp.sun.org.apache.xalan.internal.xsltc.runtime;
  
  import jaxp.sun.org.apache.xalan.internal.utils.SecuritySupport;
  import java.text.DecimalFormat;
  import java.text.DecimalFormatSymbols;
  import java.text.FieldPosition;
  import java.text.MessageFormat;
  import java.text.NumberFormat;
  import java.util.Locale;
  import java.util.ResourceBundle;
  
  import jaxp.xml.parsers.ParserConfigurationException;
  import jaxp.xml.transform.dom.DOMSource;
  
  import jaxp.sun.org.apache.xalan.internal.xsltc.DOM;
  import jaxp.sun.org.apache.xalan.internal.xsltc.Translet;
  import jaxp.sun.org.apache.xalan.internal.xsltc.dom.AbsoluteIterator;
  import jaxp.sun.org.apache.xml.internal.dtm.Axis;
  import jaxp.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
  import jaxp.sun.org.apache.xalan.internal.xsltc.dom.MultiDOM;
  import jaxp.sun.org.apache.xalan.internal.xsltc.dom.SingletonIterator;
  import jaxp.sun.org.apache.xalan.internal.xsltc.dom.StepIterator;
  import jaxp.sun.org.apache.xalan.internal.xsltc.dom.ArrayNodeListIterator;
  import jaxp.sun.org.apache.xml.internal.dtm.DTM;
  import jaxp.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  import jaxp.sun.org.apache.xml.internal.dtm.DTMManager;
  import jaxp.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
  import jaxp.sun.org.apache.xml.internal.dtm.ref.DTMNodeProxy;
  
  import org.w3c.dom.Attr;
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  import org.w3c.dom.NodeList;
  import org.xml.sax.SAXException;
  import jaxp.sun.org.apache.xml.internal.serializer.NamespaceMappings;
  import jaxp.sun.org.apache.xml.internal.serializer.SerializationHandler;
  import jaxp.sun.org.apache.xml.internal.utils.XML11Char;
  
  /**
   * Standard XSLT functions. All standard functions expect the current node
   * and the DOM as their last two arguments.
   */
  public final class BasisLibrary {
  
      private final static String EMPTYSTRING = "";
  
      /**
       * Re-use a single instance of StringBuffer (per thread) in the basis library.
       * StringBuilder is better, however, DecimalFormat only accept StringBuffer
       */
      private static final ThreadLocal<StringBuilder> threadLocalStringBuilder =
          new ThreadLocal<StringBuilder> () {
              @Override protected StringBuilder initialValue() {
                  return new StringBuilder();
              }
      };
  
      /**
       * ThreadLocal for StringBuffer used
       */
      private static final ThreadLocal<StringBuffer> threadLocalStringBuffer =
          new ThreadLocal<StringBuffer> () {
              @Override protected StringBuffer initialValue() {
                  return new StringBuffer();
              }
      };
  
      /**
       * Standard function count(node-set)
       */
      public static int countF(DTMAxisIterator iterator) {
          return(iterator.getLast());
      }
  
      /**
       * Standard function position()
       * @deprecated This method exists only for backwards compatibility with old
       *             translets.  New code should not reference it.
       */
      public static int positionF(DTMAxisIterator iterator) {
          return iterator.isReverse()
                       ? iterator.getLast() - iterator.getPosition() + 1
                       : iterator.getPosition();
      }
  
      /**
       * XSLT Standard function sum(node-set).
       * stringToDouble is inlined
       */
      public static double sumF(DTMAxisIterator iterator, DOM dom) {
          try {
              double result = 0.0;
              int node;
              while ((node = iterator.next()) != DTMAxisIterator.END) {
                  result += Double.parseDouble(dom.getStringValueX(node));
              }
              return result;
          }
          catch (NumberFormatException e) {
              return Double.NaN;
          }
      }
  
      /**
       * XSLT Standard function string()
       */
      public static String stringF(int node, DOM dom) {
          return dom.getStringValueX(node);
      }
  
      /**
       * XSLT Standard function string(value)
       */
      public static String stringF(Object obj, DOM dom) {
          if (obj instanceof DTMAxisIterator) {
              return dom.getStringValueX(((DTMAxisIterator)obj).reset().next());
          }
          else if (obj instanceof Node) {
              return dom.getStringValueX(((Node)obj).node);
          }
          else if (obj instanceof DOM) {
              return ((DOM)obj).getStringValue();
          }
          else {
              return obj.toString();
          }
      }
  
      /**
       * XSLT Standard function string(value)
       */
      public static String stringF(Object obj, int node, DOM dom) {
          if (obj instanceof DTMAxisIterator) {
              return dom.getStringValueX(((DTMAxisIterator)obj).reset().next());
          }
          else if (obj instanceof Node) {
              return dom.getStringValueX(((Node)obj).node);
          }
          else if (obj instanceof DOM) {
              // When the first argument is a DOM we want the whole
              // DOM and not just a single node - that would not make sense.
              //return ((DOM)obj).getStringValueX(node);
              return ((DOM)obj).getStringValue();
          }
          else if (obj instanceof Double) {
              Double d = (Double)obj;
              final String result = d.toString();
              final int length = result.length();
              if ((result.charAt(length-2)=='.') &&
                  (result.charAt(length-1) == '0'))
                  return result.substring(0, length-2);
              else
                  return result;
          }
          else {
              return obj != null ? obj.toString() : "";
          }
      }
  
      /**
       * XSLT Standard function number()
       */
      public static double numberF(int node, DOM dom) {
          return stringToReal(dom.getStringValueX(node));
      }
  
      /**
       * XSLT Standard function number(value)
       */
      public static double numberF(Object obj, DOM dom) {
          if (obj instanceof Double) {
              return ((Double) obj).doubleValue();
          }
          else if (obj instanceof Integer) {
              return ((Integer) obj).doubleValue();
          }
          else if (obj instanceof Boolean) {
              return  ((Boolean) obj).booleanValue() ? 1.0 : 0.0;
          }
          else if (obj instanceof String) {
              return stringToReal((String) obj);
          }
          else if (obj instanceof DTMAxisIterator) {
              DTMAxisIterator iter = (DTMAxisIterator) obj;
              return stringToReal(dom.getStringValueX(iter.reset().next()));
          }
          else if (obj instanceof Node) {
              return stringToReal(dom.getStringValueX(((Node) obj).node));
          }
          else if (obj instanceof DOM) {
              return stringToReal(((DOM) obj).getStringValue());
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(INVALID_ARGUMENT_ERR, className, "number()");
              return 0.0;
          }
      }
  
      /**
       * XSLT Standard function round()
       */
      public static double roundF(double d) {
              return (d<-0.5 || d>0.0)?Math.floor(d+0.5):((d==0.0)?
                          d:(Double.isNaN(d)?Double.NaN:-0.0));
      }
  
      /**
       * XSLT Standard function boolean()
       */
      public static boolean booleanF(Object obj) {
          if (obj instanceof Double) {
              final double temp = ((Double) obj).doubleValue();
              return temp != 0.0 && !Double.isNaN(temp);
          }
          else if (obj instanceof Integer) {
              return ((Integer) obj).doubleValue() != 0;
          }
          else if (obj instanceof Boolean) {
              return  ((Boolean) obj).booleanValue();
          }
          else if (obj instanceof String) {
              return !((String) obj).equals(EMPTYSTRING);
          }
          else if (obj instanceof DTMAxisIterator) {
              DTMAxisIterator iter = (DTMAxisIterator) obj;
              return iter.reset().next() != DTMAxisIterator.END;
          }
          else if (obj instanceof Node) {
              return true;
          }
          else if (obj instanceof DOM) {
              String temp = ((DOM) obj).getStringValue();
              return !temp.equals(EMPTYSTRING);
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(INVALID_ARGUMENT_ERR, className, "boolean()");
          }
          return false;
      }
  
      /**
       * XSLT Standard function substring(). Must take a double because of
       * conversions resulting into NaNs and rounding.
       */
      public static String substringF(String value, double start) {
          if (Double.isNaN(start))
              return(EMPTYSTRING);
  
              final int strlen = value.length();
              int istart = (int)Math.round(start) - 1;
  
          if (istart > strlen)
              return(EMPTYSTRING);
          if (istart < 1)
              istart = 0;
          try {
              return value.substring(istart);
          } catch (IndexOutOfBoundsException e) {
              runTimeError(RUN_TIME_INTERNAL_ERR, "substring()");
              return null;
          }
      }
  
      /**
       * XSLT Standard function substring(). Must take a double because of
       * conversions resulting into NaNs and rounding.
       */
      public static String substringF(String value, double start, double length) {
          if (Double.isInfinite(start) ||
              Double.isNaN(start) ||
              Double.isNaN(length))
              return(EMPTYSTRING);
  
              int istart = (int)Math.round(start) - 1;
          final int isum;
          if (Double.isInfinite(length))
              isum = Integer.MAX_VALUE;
          else
              isum = istart + (int)Math.round(length);
  
          final int strlen = value.length();
          if (isum < 0 || istart > strlen)
                  return(EMPTYSTRING);
  
          if (istart < 0)
              istart = 0;
  
          try {
              if (isum > strlen)
                  return value.substring(istart);
              else
                  return value.substring(istart, isum);
          } catch (IndexOutOfBoundsException e) {
              runTimeError(RUN_TIME_INTERNAL_ERR, "substring()");
              return null;
          }
      }
  
      /**
       * XSLT Standard function substring-after().
       */
      public static String substring_afterF(String value, String substring) {
          final int index = value.indexOf(substring);
          if (index >= 0)
              return value.substring(index + substring.length());
          else
              return EMPTYSTRING;
      }
  
      /**
       * XSLT Standard function substring-before().
       */
      public static String substring_beforeF(String value, String substring) {
          final int index = value.indexOf(substring);
          if (index >= 0)
              return value.substring(0, index);
          else
              return EMPTYSTRING;
      }
  
      /**
       * XSLT Standard function translate().
       */
      public static String translateF(String value, String from, String to) {
          final int tol = to.length();
          final int froml = from.length();
          final int valuel = value.length();
  
          final StringBuilder result = threadLocalStringBuilder.get();
      result.setLength(0);
          for (int j, i = 0; i < valuel; i++) {
              final char ch = value.charAt(i);
              for (j = 0; j < froml; j++) {
                  if (ch == from.charAt(j)) {
                      if (j < tol)
                          result.append(to.charAt(j));
                      break;
                  }
              }
              if (j == froml)
                  result.append(ch);
          }
          return result.toString();
      }
  
      /**
       * XSLT Standard function normalize-space().
       */
      public static String normalize_spaceF(int node, DOM dom) {
          return normalize_spaceF(dom.getStringValueX(node));
      }
  
      /**
       * XSLT Standard function normalize-space(string).
       */
      public static String normalize_spaceF(String value) {
          int i = 0, n = value.length();
          StringBuilder result = threadLocalStringBuilder.get();
      result.setLength(0);
  
          while (i < n && isWhiteSpace(value.charAt(i)))
              i++;
  
          while (true) {
              while (i < n && !isWhiteSpace(value.charAt(i))) {
                  result.append(value.charAt(i++));
              }
              if (i == n)
                  break;
              while (i < n && isWhiteSpace(value.charAt(i))) {
                  i++;
              }
              if (i < n)
                  result.append(' ');
          }
          return result.toString();
      }
  
      /**
       * XSLT Standard function generate-id().
       */
      public static String generate_idF(int node) {
          if (node > 0)
              // Only generate ID if node exists
              return "N" + node;
          else
              // Otherwise return an empty string
              return EMPTYSTRING;
      }
  
      /**
       * utility function for calls to local-name().
       */
      public static String getLocalName(String value) {
          int idx = value.lastIndexOf(':');
          if (idx >= 0) value = value.substring(idx + 1);
          idx = value.lastIndexOf('@');
          if (idx >= 0) value = value.substring(idx + 1);
          return(value);
      }
  
      /**
       * External functions that cannot be resolved are replaced with a call
       * to this method. This method will generate a runtime errors. A good
       * stylesheet checks whether the function exists using conditional
       * constructs, and never really tries to call it if it doesn't exist.
       * But simple stylesheets may result in a call to this method.
       * The compiler should generate a warning if it encounters a call to
       * an unresolved external function.
       */
      public static void unresolved_externalF(String name) {
          runTimeError(EXTERNAL_FUNC_ERR, name);
      }
  
      /**
       * Utility function to throw a runtime error on the use of an extension
       * function when the secure processing feature is set to true.
       */
      public static void unallowed_extension_functionF(String name) {
          runTimeError(UNALLOWED_EXTENSION_FUNCTION_ERR, name);
      }
  
      /**
       * Utility function to throw a runtime error on the use of an extension
       * element when the secure processing feature is set to true.
       */
      public static void unallowed_extension_elementF(String name) {
          runTimeError(UNALLOWED_EXTENSION_ELEMENT_ERR, name);
      }
  
      /**
       * Utility function to throw a runtime error for an unsupported element.
       *
       * This is only used in forward-compatibility mode, when the control flow
       * cannot be determined. In 1.0 mode, the error message is emitted at
       * compile time.
       */
      public static void unsupported_ElementF(String qname, boolean isExtension) {
          if (isExtension)
              runTimeError(UNSUPPORTED_EXT_ERR, qname);
          else
              runTimeError(UNSUPPORTED_XSL_ERR, qname);
      }
  
      /**
       * XSLT Standard function namespace-uri(node-set).
       */
      public static String namespace_uriF(DTMAxisIterator iter, DOM dom) {
          return namespace_uriF(iter.next(), dom);
      }
  
      /**
       * XSLT Standard function system-property(name)
       */
      public static String system_propertyF(String name) {
          if (name.equals("xsl:version"))
              return("1.0");
          if (name.equals("xsl:vendor"))
              return("Apache Software Foundation (Xalan XSLTC)");
          if (name.equals("xsl:vendor-url"))
              return("http://xml.apache.org/xalan-j");
  
          runTimeError(INVALID_ARGUMENT_ERR, name, "system-property()");
          return(EMPTYSTRING);
      }
  
      /**
       * XSLT Standard function namespace-uri().
       */
      public static String namespace_uriF(int node, DOM dom) {
          final String value = dom.getNodeName(node);
          final int colon = value.lastIndexOf(':');
          if (colon >= 0)
              return value.substring(0, colon);
          else
              return EMPTYSTRING;
      }
  
      /**
       * Implements the object-type() extension function.
       *
       * @see <a href="http://www.exslt.org/">EXSLT</a>
       */
      public static String objectTypeF(Object obj)
      {
        if (obj instanceof String)
          return "string";
        else if (obj instanceof Boolean)
          return "boolean";
        else if (obj instanceof Number)
          return "number";
        else if (obj instanceof DOM)
          return "RTF";
        else if (obj instanceof DTMAxisIterator)
          return "node-set";
        else
          return "unknown";
      }
  
      /**
       * Implements the nodeset() extension function.
       */
      public static DTMAxisIterator nodesetF(Object obj) {
          if (obj instanceof DOM) {
             //final DOMAdapter adapter = (DOMAdapter) obj;
             final DOM dom = (DOM)obj;
             return new SingletonIterator(dom.getDocument(), true);
          }
          else if (obj instanceof DTMAxisIterator) {
             return (DTMAxisIterator) obj;
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, "node-set", className);
              return null;
          }
      }
  
      //-- Begin utility functions
  
      private static boolean isWhiteSpace(char ch) {
          return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
      }
  
      private static boolean compareStrings(String lstring, String rstring,
                                            int op, DOM dom) {
          switch (op) {
      case Operators.EQ:
              return lstring.equals(rstring);
  
      case Operators.NE:
              return !lstring.equals(rstring);
  
      case Operators.GT:
              return numberF(lstring, dom) > numberF(rstring, dom);
  
      case Operators.LT:
              return numberF(lstring, dom) < numberF(rstring, dom);
  
      case Operators.GE:
              return numberF(lstring, dom) >= numberF(rstring, dom);
  
      case Operators.LE:
              return numberF(lstring, dom) <= numberF(rstring, dom);
  
          default:
              runTimeError(RUN_TIME_INTERNAL_ERR, "compare()");
              return false;
          }
      }
  
      /**
       * Utility function: node-set/node-set compare.
       */
      public static boolean compare(DTMAxisIterator left, DTMAxisIterator right,
                                    int op, DOM dom) {
          int lnode;
          left.reset();
  
          while ((lnode = left.next()) != DTMAxisIterator.END) {
              final String lvalue = dom.getStringValueX(lnode);
  
              int rnode;
              right.reset();
              while ((rnode = right.next()) != DTMAxisIterator.END) {
                  // String value must be the same if both nodes are the same
                  if (lnode == rnode) {
                      if (op == Operators.EQ) {
                          return true;
                      } else if (op == Operators.NE) {
                          continue;
                      }
                  }
                  if (compareStrings(lvalue, dom.getStringValueX(rnode), op,
                                     dom)) {
                      return true;
                  }
              }
          }
          return false;
      }
  
      public static boolean compare(int node, DTMAxisIterator iterator,
                                    int op, DOM dom) {
          //iterator.reset();
  
          int rnode;
          String value;
  
          switch(op) {
      case Operators.EQ:
              rnode = iterator.next();
              if (rnode != DTMAxisIterator.END) {
                  value = dom.getStringValueX(node);
                  do {
                      if (node == rnode
                            || value.equals(dom.getStringValueX(rnode))) {
                         return true;
                      }
                  } while ((rnode = iterator.next()) != DTMAxisIterator.END);
              }
              break;
      case Operators.NE:
              rnode = iterator.next();
              if (rnode != DTMAxisIterator.END) {
                  value = dom.getStringValueX(node);
                  do {
                      if (node != rnode
                            && !value.equals(dom.getStringValueX(rnode))) {
                          return true;
                      }
                  } while ((rnode = iterator.next()) != DTMAxisIterator.END);
              }
              break;
      case Operators.LT:
              // Assume we're comparing document order here
              while ((rnode = iterator.next()) != DTMAxisIterator.END) {
                  if (rnode > node) return true;
              }
              break;
      case Operators.GT:
              // Assume we're comparing document order here
              while ((rnode = iterator.next()) != DTMAxisIterator.END) {
                  if (rnode < node) return true;
              }
              break;
          }
          return(false);
      }
  
      /**
       * Utility function: node-set/number compare.
       */
      public static boolean compare(DTMAxisIterator left, final double rnumber,
                                    final int op, DOM dom) {
          int node;
          //left.reset();
  
          switch (op) {
      case Operators.EQ:
              while ((node = left.next()) != DTMAxisIterator.END) {
                  if (numberF(dom.getStringValueX(node), dom) == rnumber)
                      return true;
              }
              break;
  
      case Operators.NE:
              while ((node = left.next()) != DTMAxisIterator.END) {
                  if (numberF(dom.getStringValueX(node), dom) != rnumber)
                      return true;
              }
              break;
  
      case Operators.GT:
              while ((node = left.next()) != DTMAxisIterator.END) {
                  if (numberF(dom.getStringValueX(node), dom) > rnumber)
                      return true;
              }
              break;
  
      case Operators.LT:
              while ((node = left.next()) != DTMAxisIterator.END) {
                  if (numberF(dom.getStringValueX(node), dom) < rnumber)
                      return true;
              }
              break;
  
      case Operators.GE:
              while ((node = left.next()) != DTMAxisIterator.END) {
                  if (numberF(dom.getStringValueX(node), dom) >= rnumber)
                      return true;
              }
              break;
  
      case Operators.LE:
              while ((node = left.next()) != DTMAxisIterator.END) {
                  if (numberF(dom.getStringValueX(node), dom) <= rnumber)
                      return true;
              }
              break;
  
          default:
              runTimeError(RUN_TIME_INTERNAL_ERR, "compare()");
          }
  
          return false;
      }
  
      /**
       * Utility function: node-set/string comparison.
       */
      public static boolean compare(DTMAxisIterator left, final String rstring,
                                    int op, DOM dom) {
          int node;
          //left.reset();
          while ((node = left.next()) != DTMAxisIterator.END) {
              if (compareStrings(dom.getStringValueX(node), rstring, op, dom)) {
                  return true;
              }
          }
          return false;
      }
  
  
      public static boolean compare(Object left, Object right,
                                    int op, DOM dom)
      {
          boolean result = false;
          boolean hasSimpleArgs = hasSimpleType(left) && hasSimpleType(right);
  
      if (op != Operators.EQ && op != Operators.NE) {
              // If node-boolean comparison -> convert node to boolean
              if (left instanceof Node || right instanceof Node) {
                  if (left instanceof Boolean) {
                      right = new Boolean(booleanF(right));
                      hasSimpleArgs = true;
                  }
                  if (right instanceof Boolean) {
                      left = new Boolean(booleanF(left));
                      hasSimpleArgs = true;
                  }
              }
  
              if (hasSimpleArgs) {
                  switch (op) {
          case Operators.GT:
                      return numberF(left, dom) > numberF(right, dom);
  
          case Operators.LT:
                      return numberF(left, dom) < numberF(right, dom);
  
          case Operators.GE:
                      return numberF(left, dom) >= numberF(right, dom);
  
          case Operators.LE:
                      return numberF(left, dom) <= numberF(right, dom);
  
          default:
                      runTimeError(RUN_TIME_INTERNAL_ERR, "compare()");
                  }
              }
              // falls through
          }
  
          if (hasSimpleArgs) {
              if (left instanceof Boolean || right instanceof Boolean) {
                  result = booleanF(left) == booleanF(right);
              }
              else if (left instanceof Double || right instanceof Double ||
                       left instanceof Integer || right instanceof Integer) {
                  result = numberF(left, dom) == numberF(right, dom);
              }
              else { // compare them as strings
                  result = stringF(left, dom).equals(stringF(right, dom));
              }
  
              if (op == Operators.NE) {
                  result = !result;
              }
          }
          else {
              if (left instanceof Node) {
                  left = new SingletonIterator(((Node)left).node);
              }
              if (right instanceof Node) {
                  right = new SingletonIterator(((Node)right).node);
              }
  
              if (hasSimpleType(left) ||
                  left instanceof DOM && right instanceof DTMAxisIterator) {
                  // swap operands and operator
                  final Object temp = right; right = left; left = temp;
                  op = Operators.swapOp(op);
              }
  
              if (left instanceof DOM) {
                  if (right instanceof Boolean) {
                      result = ((Boolean)right).booleanValue();
                      return result == (op == Operators.EQ);
                  }
  
                  final String sleft = ((DOM)left).getStringValue();
  
                  if (right instanceof Number) {
                      result = ((Number)right).doubleValue() ==
                          stringToReal(sleft);
                  }
                  else if (right instanceof String) {
                      result = sleft.equals((String)right);
                  }
                  else if (right instanceof DOM) {
                      result = sleft.equals(((DOM)right).getStringValue());
                  }
  
                  if (op == Operators.NE) {
                      result = !result;
                  }
                  return result;
              }
  
              // Next, node-set/t for t in {real, string, node-set, result-tree}
  
              DTMAxisIterator iter = ((DTMAxisIterator)left).reset();
  
              if (right instanceof DTMAxisIterator) {
                  result = compare(iter, (DTMAxisIterator)right, op, dom);
              }
              else if (right instanceof String) {
                  result = compare(iter, (String)right, op, dom);
              }
              else if (right instanceof Number) {
                  final double temp = ((Number)right).doubleValue();
                  result = compare(iter, temp, op, dom);
              }
              else if (right instanceof Boolean) {
                  boolean temp = ((Boolean)right).booleanValue();
                  result = (iter.reset().next() != DTMAxisIterator.END) == temp;
              }
              else if (right instanceof DOM) {
                  result = compare(iter, ((DOM)right).getStringValue(),
                                   op, dom);
              }
              else if (right == null) {
                  return(false);
              }
              else {
                  final String className = right.getClass().getName();
                  runTimeError(INVALID_ARGUMENT_ERR, className, "compare()");
              }
          }
          return result;
      }
  
      /**
       * Utility function: used to test context node's language
       */
      public static boolean testLanguage(String testLang, DOM dom, int node) {
          // language for context node (if any)
          String nodeLang = dom.getLanguage(node);
          if (nodeLang == null)
              return(false);
          else
              nodeLang = nodeLang.toLowerCase();
  
          // compare context node's language agains test language
          testLang = testLang.toLowerCase();
          if (testLang.length() == 2) {
              return(nodeLang.startsWith(testLang));
          }
          else {
              return(nodeLang.equals(testLang));
          }
      }
  
      private static boolean hasSimpleType(Object obj) {
          return obj instanceof Boolean || obj instanceof Double ||
              obj instanceof Integer || obj instanceof String ||
              obj instanceof Node || obj instanceof DOM;
      }
  
      /**
       * Utility function: used in StringType to convert a string to a real.
       */
      public static double stringToReal(String s) {
          try {
              return Double.valueOf(s).doubleValue();
          }
          catch (NumberFormatException e) {
              return Double.NaN;
          }
      }
  
      /**
       * Utility function: used in StringType to convert a string to an int.
       */
      public static int stringToInt(String s) {
          try {
              return Integer.parseInt(s);
          }
          catch (NumberFormatException e) {
              return(-1); // ???
          }
      }
  
      private static final int DOUBLE_FRACTION_DIGITS = 340;
      private static final double lowerBounds = 0.001;
      private static final double upperBounds = 10000000;
      private static DecimalFormat defaultFormatter, xpathFormatter;
      private static String defaultPattern = "";
  
      static {
          NumberFormat f = NumberFormat.getInstance(Locale.getDefault());
          defaultFormatter = (f instanceof DecimalFormat) ?
              (DecimalFormat) f : new DecimalFormat();
          // Set max fraction digits so that truncation does not occur. Setting
          // the max to Integer.MAX_VALUE may cause problems with some JDK's.
          defaultFormatter.setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
          defaultFormatter.setMinimumFractionDigits(0);
          defaultFormatter.setMinimumIntegerDigits(1);
          defaultFormatter.setGroupingUsed(false);
  
          // This formatter is used to convert numbers according to the XPath
          // 1.0 syntax which ignores locales (http://www.w3.org/TR/xpath#NT-Number)
          xpathFormatter = new DecimalFormat("",
              new DecimalFormatSymbols(Locale.US));
          xpathFormatter.setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
          xpathFormatter.setMinimumFractionDigits(0);
          xpathFormatter.setMinimumIntegerDigits(1);
          xpathFormatter.setGroupingUsed(false);
      }
  
      /**
       * Utility function: used in RealType to convert a real to a string.
       * Removes the decimal if null. Uses a specialized formatter object
       * for very large and very small numbers that ignores locales, thus
       * using always using "." as a decimal separator.
       */
      public static String realToString(double d) {
          final double m = Math.abs(d);
          if ((m >= lowerBounds) && (m < upperBounds)) {
              final String result = Double.toString(d);
              final int length = result.length();
              // Remove leading zeros.
              if ((result.charAt(length-2) == '.') &&
                  (result.charAt(length-1) == '0'))
                  return result.substring(0, length-2);
              else
                  return result;
          }
          else {
              if (Double.isNaN(d) || Double.isInfinite(d))
                  return(Double.toString(d));
  
              //Convert -0.0 to +0.0 other values remains the same
              d = d + 0.0;
  
              // Use the XPath formatter to ignore locales
              StringBuffer result = threadLocalStringBuffer.get();
              result.setLength(0);
              xpathFormatter.format(d, result, _fieldPosition);
              return result.toString();
          }
      }
  
      /**
       * Utility function: used in RealType to convert a real to an integer
       */
      public static int realToInt(double d) {
          return (int)d;
      }
  
      /**
       * Utility function: used to format/adjust  a double to a string. The
       * DecimalFormat object comes from the 'formatSymbols' hashtable in
       * AbstractTranslet.
       */
      private static FieldPosition _fieldPosition = new FieldPosition(0);
  
      public static String formatNumber(double number, String pattern,
                                        DecimalFormat formatter) {
          // bugzilla fix 12813
          if (formatter == null) {
              formatter = defaultFormatter;
          }
          try {
              StringBuffer result = threadLocalStringBuffer.get();
          result.setLength(0);
              if (pattern != defaultPattern) {
                  formatter.applyLocalizedPattern(pattern);
              }
          formatter.format(number, result, _fieldPosition);
              return result.toString();
          }
          catch (IllegalArgumentException e) {
              runTimeError(FORMAT_NUMBER_ERR, Double.toString(number), pattern);
              return(EMPTYSTRING);
          }
      }
  
      /**
       * Utility function: used to convert references to node-sets. If the
       * obj is an instanceof Node then create a singleton iterator.
       */
      public static DTMAxisIterator referenceToNodeSet(Object obj) {
          // Convert var/param -> node
          if (obj instanceof Node) {
              return(new SingletonIterator(((Node)obj).node));
          }
          // Convert var/param -> node-set
          else if (obj instanceof DTMAxisIterator) {
              return(((DTMAxisIterator)obj).cloneIterator().reset());
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, className, "node-set");
              return null;
          }
      }
  
      /**
       * Utility function: used to convert reference to org.w3c.dom.NodeList.
       */
      public static NodeList referenceToNodeList(Object obj, DOM dom) {
          if (obj instanceof Node || obj instanceof DTMAxisIterator) {
              DTMAxisIterator iter = referenceToNodeSet(obj);
              return dom.makeNodeList(iter);
          }
          else if (obj instanceof DOM) {
            dom = (DOM)obj;
            return dom.makeNodeList(DTMDefaultBase.ROOTNODE);
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, className,
                  "org.w3c.dom.NodeList");
              return null;
          }
      }
  
      /**
       * Utility function: used to convert reference to org.w3c.dom.Node.
       */
      public static org.w3c.dom.Node referenceToNode(Object obj, DOM dom) {
          if (obj instanceof Node || obj instanceof DTMAxisIterator) {
              DTMAxisIterator iter = referenceToNodeSet(obj);
              return dom.makeNode(iter);
          }
          else if (obj instanceof DOM) {
            dom = (DOM)obj;
            DTMAxisIterator iter = dom.getChildren(DTMDefaultBase.ROOTNODE);
            return dom.makeNode(iter);
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, className, "org.w3c.dom.Node");
              return null;
          }
      }
  
      /**
       * Utility function: used to convert reference to long.
       */
      public static long referenceToLong(Object obj) {
          if (obj instanceof Number) {
              return ((Number) obj).longValue();    // handles Integer and Double
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, className, Long.TYPE);
              return 0;
          }
      }
  
      /**
       * Utility function: used to convert reference to double.
       */
      public static double referenceToDouble(Object obj) {
          if (obj instanceof Number) {
              return ((Number) obj).doubleValue();   // handles Integer and Double
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, className, Double.TYPE);
              return 0;
          }
      }
  
      /**
       * Utility function: used to convert reference to boolean.
       */
      public static boolean referenceToBoolean(Object obj) {
          if (obj instanceof Boolean) {
              return ((Boolean) obj).booleanValue();
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, className, Boolean.TYPE);
              return false;
          }
      }
  
      /**
       * Utility function: used to convert reference to String.
       */
      public static String referenceToString(Object obj, DOM dom) {
          if (obj instanceof String) {
              return (String) obj;
          }
          else if (obj instanceof DTMAxisIterator) {
              return dom.getStringValueX(((DTMAxisIterator)obj).reset().next());
          }
          else if (obj instanceof Node) {
              return dom.getStringValueX(((Node)obj).node);
          }
          else if (obj instanceof DOM) {
              return ((DOM) obj).getStringValue();
          }
          else {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, className, String.class);
              return null;
          }
      }
  
      /**
       * Utility function used to convert a w3c Node into an internal DOM iterator.
       */
      public static DTMAxisIterator node2Iterator(org.w3c.dom.Node node,
                                                  Translet translet, DOM dom)
      {
          final org.w3c.dom.Node inNode = node;
          // Create a dummy NodeList which only contains the given node to make
          // use of the nodeList2Iterator() interface.
          org.w3c.dom.NodeList nodelist = new org.w3c.dom.NodeList() {
              public int getLength() {
                  return 1;
              }
  
              public org.w3c.dom.Node item(int index) {
                  if (index == 0)
                      return inNode;
                  else
                      return null;
              }
          };
  
          return nodeList2Iterator(nodelist, translet, dom);
      }
  
      /**
       * In a perfect world, this would be the implementation for
       * nodeList2Iterator. In reality, though, this causes a
       * ClassCastException in getDTMHandleFromNode because SAXImpl is
       * not an instance of DOM2DTM. So we use the more lengthy
       * implementation below until this issue has been addressed.
       *
       * @see org.apache.xml.dtm.ref.DTMManagerDefault#getDTMHandleFromNode
       */
      private static DTMAxisIterator nodeList2IteratorUsingHandleFromNode(
                                          org.w3c.dom.NodeList nodeList,
                                          Translet translet, DOM dom)
      {
          final int n = nodeList.getLength();
          final int[] dtmHandles = new int[n];
          DTMManager dtmManager = null;
          if (dom instanceof MultiDOM)
              dtmManager = ((MultiDOM) dom).getDTMManager();
          for (int i = 0; i < n; ++i) {
              org.w3c.dom.Node node = nodeList.item(i);
              int handle;
              if (dtmManager != null) {
                  handle = dtmManager.getDTMHandleFromNode(node);
              }
              else if (node instanceof DTMNodeProxy
                       && ((DTMNodeProxy) node).getDTM() == dom) {
                  handle = ((DTMNodeProxy) node).getDTMNodeNumber();
              }
              else {
                  runTimeError(RUN_TIME_INTERNAL_ERR, "need MultiDOM");
                  return null;
              }
              dtmHandles[i] = handle;
              System.out.println("Node " + i + " has handle 0x" +
                                 Integer.toString(handle, 16));
          }
          return new ArrayNodeListIterator(dtmHandles);
      }
  
      /**
       * Utility function used to convert a w3c NodeList into a internal
       * DOM iterator.
       */
      public static DTMAxisIterator nodeList2Iterator(
                                          org.w3c.dom.NodeList nodeList,
                                          Translet translet, DOM dom)
      {
          // First pass: build w3c DOM for all nodes not proxied from our DOM.
          //
          // Notice: this looses some (esp. parent) context for these nodes,
          // so some way to wrap the original nodes inside a DTMAxisIterator
          // might be preferable in the long run.
          int n = 0; // allow for change in list length, just in case.
          Document doc = null;
          DTMManager dtmManager = null;
          int[] proxyNodes = new int[nodeList.getLength()];
          if (dom instanceof MultiDOM)
              dtmManager = ((MultiDOM) dom).getDTMManager();
          for (int i = 0; i < nodeList.getLength(); ++i) {
              org.w3c.dom.Node node = nodeList.item(i);
              if (node instanceof DTMNodeProxy) {
                  DTMNodeProxy proxy = (DTMNodeProxy)node;
                  DTM nodeDTM = proxy.getDTM();
                  int handle = proxy.getDTMNodeNumber();
                  boolean isOurDOM = (nodeDTM == dom);
                  if (!isOurDOM && dtmManager != null) {
                      try {
                          isOurDOM = (nodeDTM == dtmManager.getDTM(handle));
                      }
                      catch (ArrayIndexOutOfBoundsException e) {
                          // invalid node handle, so definitely not our doc
                      }
                  }
                  if (isOurDOM) {
                      proxyNodes[i] = handle;
                      ++n;
                      continue;
                  }
              }
              proxyNodes[i] = DTM.NULL;
              int nodeType = node.getNodeType();
              if (doc == null) {
                  if (dom instanceof MultiDOM == false) {
                      runTimeError(RUN_TIME_INTERNAL_ERR, "need MultiDOM");
                      return null;
                  }
                  try {
                      AbstractTranslet at = (AbstractTranslet) translet;
                      doc = at.newDocument("", "__top__");
                  }
                  catch (ParserConfigurationException e) {
                      runTimeError(RUN_TIME_INTERNAL_ERR, e.getMessage());
                      return null;
                  }
              }
              // Use one dummy element as container for each node of the
              // list. That way, it is easier to detect resp. avoid
              // funny things which change the number of nodes,
              // e.g. auto-concatenation of text nodes.
              Element mid;
              switch (nodeType) {
                  case org.w3c.dom.Node.ELEMENT_NODE:
                  case org.w3c.dom.Node.TEXT_NODE:
                  case org.w3c.dom.Node.CDATA_SECTION_NODE:
                  case org.w3c.dom.Node.COMMENT_NODE:
                  case org.w3c.dom.Node.ENTITY_REFERENCE_NODE:
                  case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE:
                      mid = doc.createElementNS(null, "__dummy__");
                      mid.appendChild(doc.importNode(node, true));
                      doc.getDocumentElement().appendChild(mid);
                      ++n;
                      break;
                  case org.w3c.dom.Node.ATTRIBUTE_NODE:
                      // The mid element also serves as a container for
                      // attributes, avoiding problems with conflicting
                      // attributes or node order.
                      mid = doc.createElementNS(null, "__dummy__");
                      mid.setAttributeNodeNS((Attr)doc.importNode(node, true));
                      doc.getDocumentElement().appendChild(mid);
                      ++n;
                      break;
                  default:
                      // Better play it safe for all types we aren't sure we know
                      // how to deal with.
                      runTimeError(RUN_TIME_INTERNAL_ERR,
                                   "Don't know how to convert node type "
                                   + nodeType);
              }
          }
  
          // w3cDOM -> DTM -> DOMImpl
          DTMAxisIterator iter = null, childIter = null, attrIter = null;
          if (doc != null) {
              final MultiDOM multiDOM = (MultiDOM) dom;
              DOM idom = (DOM)dtmManager.getDTM(new DOMSource(doc), false,
                                                null, true, false);
              // Create DOMAdapter and register with MultiDOM
              DOMAdapter domAdapter = new DOMAdapter(idom,
                  translet.getNamesArray(),
                  translet.getUrisArray(),
                  translet.getTypesArray(),
                  translet.getNamespaceArray());
              multiDOM.addDOMAdapter(domAdapter);
  
              DTMAxisIterator iter1 = idom.getAxisIterator(Axis.CHILD);
              DTMAxisIterator iter2 = idom.getAxisIterator(Axis.CHILD);
              iter = new AbsoluteIterator(
                  new StepIterator(iter1, iter2));
  
              iter.setStartNode(DTMDefaultBase.ROOTNODE);
  
              childIter = idom.getAxisIterator(Axis.CHILD);
              attrIter = idom.getAxisIterator(Axis.ATTRIBUTE);
          }
  
          // Second pass: find DTM handles for every node in the list.
          int[] dtmHandles = new int[n];
          n = 0;
          for (int i = 0; i < nodeList.getLength(); ++i) {
              if (proxyNodes[i] != DTM.NULL) {
                  dtmHandles[n++] = proxyNodes[i];
                  continue;
              }
              org.w3c.dom.Node node = nodeList.item(i);
              DTMAxisIterator iter3 = null;
              int nodeType = node.getNodeType();
              switch (nodeType) {
                  case org.w3c.dom.Node.ELEMENT_NODE:
                  case org.w3c.dom.Node.TEXT_NODE:
                  case org.w3c.dom.Node.CDATA_SECTION_NODE:
                  case org.w3c.dom.Node.COMMENT_NODE:
                  case org.w3c.dom.Node.ENTITY_REFERENCE_NODE:
                  case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE:
                      iter3 = childIter;
                      break;
                  case org.w3c.dom.Node.ATTRIBUTE_NODE:
                      iter3 = attrIter;
                      break;
                  default:
                      // Should not happen, as first run should have got all these
                      throw new InternalRuntimeError("Mismatched cases");
              }
              if (iter3 != null) {
                  iter3.setStartNode(iter.next());
                  dtmHandles[n] = iter3.next();
                  // For now, play it self and perform extra checks:
                  if (dtmHandles[n] == DTMAxisIterator.END)
                      throw new InternalRuntimeError("Expected element missing at " + i);
                  if (iter3.next() != DTMAxisIterator.END)
                      throw new InternalRuntimeError("Too many elements at " + i);
                  ++n;
              }
          }
          if (n != dtmHandles.length)
              throw new InternalRuntimeError("Nodes lost in second pass");
  
          return new ArrayNodeListIterator(dtmHandles);
      }
  
      /**
       * Utility function used to convert references to DOMs.
       */
      public static DOM referenceToResultTree(Object obj) {
          try {
              return ((DOM) obj);
          }
          catch (IllegalArgumentException e) {
              final String className = obj.getClass().getName();
              runTimeError(DATA_CONVERSION_ERR, "reference", className);
              return null;
          }
      }
  
      /**
       * Utility function: used with nth position filters to convert a sequence
       * of nodes to just one single node (the one at position n).
       */
      public static DTMAxisIterator getSingleNode(DTMAxisIterator iterator) {
          int node = iterator.next();
          return(new SingletonIterator(node));
      }
  
      /**
       * Utility function: used in xsl:copy.
       */
      private static char[] _characterArray = new char[32];
  
      public static void copy(Object obj,
                              SerializationHandler handler,
                              int node,
                              DOM dom) {
          try {
              if (obj instanceof DTMAxisIterator)
        {
                  DTMAxisIterator iter = (DTMAxisIterator) obj;
                  dom.copy(iter.reset(), handler);
              }
              else if (obj instanceof Node) {
                  dom.copy(((Node) obj).node, handler);
              }
              else if (obj instanceof DOM) {
                  //((DOM)obj).copy(((com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase)((DOMAdapter)obj).getDOMImpl()).getDocument(), handler);
                  DOM newDom = (DOM)obj;
                  newDom.copy(newDom.getDocument(), handler);
              }
              else {
                  String string = obj.toString();         // or call stringF()
                  final int length = string.length();
                  if (length > _characterArray.length)
                      _characterArray = new char[length];
                  string.getChars(0, length, _characterArray, 0);
                  handler.characters(_characterArray, 0, length);
              }
          }
          catch (SAXException e) {
              runTimeError(RUN_TIME_COPY_ERR);
          }
      }
  
      /**
       * Utility function to check if xsl:attribute has a valid qname
       * This method should only be invoked if the name attribute is an AVT
       */
      public static void checkAttribQName(String name) {
          final int firstOccur = name.indexOf(":");
          final int lastOccur = name.lastIndexOf(":");
          final String localName = name.substring(lastOccur + 1);
  
          if (firstOccur > 0) {
              final String newPrefix = name.substring(0, firstOccur);
  
              if (firstOccur != lastOccur) {
                 final String oriPrefix = name.substring(firstOccur+1, lastOccur);
                  if (!XML11Char.isXML11ValidNCName(oriPrefix)) {
                      // even though the orignal prefix is ignored, it should still get checked for valid NCName
                      runTimeError(INVALID_QNAME_ERR,oriPrefix+":"+localName);
                  }
              }
  
              // prefix must be a valid NCName
              if (!XML11Char.isXML11ValidNCName(newPrefix)) {
                  runTimeError(INVALID_QNAME_ERR,newPrefix+":"+localName);
              }
          }
  
          // local name must be a valid NCName and must not be XMLNS
          if ((!XML11Char.isXML11ValidNCName(localName))||(localName.equals(Constants.XMLNS_PREFIX))) {
              runTimeError(INVALID_QNAME_ERR,localName);
          }
      }
  
      /**
       * Utility function to check if a name is a valid ncname
       * This method should only be invoked if the attribute value is an AVT
       */
      public static void checkNCName(String name) {
          if (!XML11Char.isXML11ValidNCName(name)) {
              runTimeError(INVALID_NCNAME_ERR,name);
          }
      }
  
      /**
       * Utility function to check if a name is a valid qname
       * This method should only be invoked if the attribute value is an AVT
       */
      public static void checkQName(String name) {
          if (!XML11Char.isXML11ValidQName(name)) {
              runTimeError(INVALID_QNAME_ERR,name);
          }
      }
  
      /**
       * Utility function for the implementation of xsl:element.
       */
      public static String startXslElement(String qname, String namespace,
          SerializationHandler handler, DOM dom, int node)
      {
          try {
              // Get prefix from qname
              String prefix;
              final int index = qname.indexOf(':');
  
              if (index > 0) {
                  prefix = qname.substring(0, index);
  
                  // Handle case when prefix is not known at compile time
                  if (namespace == null || namespace.length() == 0) {
                      try {
                          // not sure if this line of code ever works
                          namespace = dom.lookupNamespace(node, prefix);
                      }
                      catch(RuntimeException e) {
                          handler.flushPending();  // need to flush or else can't get namespacemappings
                          NamespaceMappings nm = handler.getNamespaceMappings();
                          namespace = nm.lookupNamespace(prefix);
                          if (namespace == null) {
                              runTimeError(NAMESPACE_PREFIX_ERR,prefix);
                          }
                      }
                  }
  
                  handler.startElement(namespace, qname.substring(index+1),
                                           qname);
                  handler.namespaceAfterStartElement(prefix, namespace);
              }
              else {
                  // Need to generate a prefix?
                  if (namespace != null && namespace.length() > 0) {
                      prefix = generatePrefix();
                      qname = prefix + ':' + qname;
                      handler.startElement(namespace, qname, qname);
                      handler.namespaceAfterStartElement(prefix, namespace);
                  }
                  else {
                      handler.startElement(null, null, qname);
                  }
              }
          }
          catch (SAXException e) {
              throw new RuntimeException(e.getMessage());
          }
  
          return qname;
      }
  
      /**
       * This function is used in the execution of xsl:element
       */
      public static String getPrefix(String qname) {
          final int index = qname.indexOf(':');
          return (index > 0) ? qname.substring(0, index) : null;
      }
  
      /**
       * This function is used in the execution of xsl:element
       */
      private static int prefixIndex = 0;
  
      public static String generatePrefix() {
          synchronized (BasisLibrary.class) {
              return ("ns" + prefixIndex++);
          }
      }
  
      public static final String RUN_TIME_INTERNAL_ERR =
                                             "RUN_TIME_INTERNAL_ERR";
      public static final String RUN_TIME_COPY_ERR =
                                             "RUN_TIME_COPY_ERR";
      public static final String DATA_CONVERSION_ERR =
                                             "DATA_CONVERSION_ERR";
      public static final String EXTERNAL_FUNC_ERR =
                                             "EXTERNAL_FUNC_ERR";
      public static final String EQUALITY_EXPR_ERR =
                                             "EQUALITY_EXPR_ERR";
      public static final String INVALID_ARGUMENT_ERR =
                                             "INVALID_ARGUMENT_ERR";
      public static final String FORMAT_NUMBER_ERR =
                                             "FORMAT_NUMBER_ERR";
      public static final String ITERATOR_CLONE_ERR =
                                             "ITERATOR_CLONE_ERR";
      public static final String AXIS_SUPPORT_ERR =
                                             "AXIS_SUPPORT_ERR";
      public static final String TYPED_AXIS_SUPPORT_ERR =
                                             "TYPED_AXIS_SUPPORT_ERR";
      public static final String STRAY_ATTRIBUTE_ERR =
                                             "STRAY_ATTRIBUTE_ERR";
      public static final String STRAY_NAMESPACE_ERR =
                                             "STRAY_NAMESPACE_ERR";
      public static final String NAMESPACE_PREFIX_ERR =
                                             "NAMESPACE_PREFIX_ERR";
      public static final String DOM_ADAPTER_INIT_ERR =
                                             "DOM_ADAPTER_INIT_ERR";
      public static final String PARSER_DTD_SUPPORT_ERR =
                                             "PARSER_DTD_SUPPORT_ERR";
      public static final String NAMESPACES_SUPPORT_ERR =
                                             "NAMESPACES_SUPPORT_ERR";
      public static final String CANT_RESOLVE_RELATIVE_URI_ERR =
                                             "CANT_RESOLVE_RELATIVE_URI_ERR";
      public static final String UNSUPPORTED_XSL_ERR =
                                             "UNSUPPORTED_XSL_ERR";
      public static final String UNSUPPORTED_EXT_ERR =
                                             "UNSUPPORTED_EXT_ERR";
      public static final String UNKNOWN_TRANSLET_VERSION_ERR =
                                             "UNKNOWN_TRANSLET_VERSION_ERR";
      public static final String INVALID_QNAME_ERR = "INVALID_QNAME_ERR";
      public static final String INVALID_NCNAME_ERR = "INVALID_NCNAME_ERR";
      public static final String UNALLOWED_EXTENSION_FUNCTION_ERR = "UNALLOWED_EXTENSION_FUNCTION_ERR";
      public static final String UNALLOWED_EXTENSION_ELEMENT_ERR = "UNALLOWED_EXTENSION_ELEMENT_ERR";
  
      // All error messages are localized and are stored in resource bundles.
      private static ResourceBundle m_bundle;
  
      public final static String ERROR_MESSAGES_KEY = "error-messages";
  
      static {
          String resource = "jaxp.sun.org.apache.xalan.internal.xsltc.runtime.ErrorMessages";
          m_bundle = SecuritySupport.getResourceBundle(resource);
      }
  
      /**
       * Print a run-time error message.
       */
      public static void runTimeError(String code) {
          throw new RuntimeException(m_bundle.getString(code));
      }
  
      public static void runTimeError(String code, Object[] args) {
          final String message = MessageFormat.format(m_bundle.getString(code),
                                                      args);
          throw new RuntimeException(message);
      }
  
      public static void runTimeError(String code, Object arg0) {
          runTimeError(code, new Object[]{ arg0 } );
      }
  
      public static void runTimeError(String code, Object arg0, Object arg1) {
          runTimeError(code, new Object[]{ arg0, arg1 } );
      }
  
      public static void consoleOutput(String msg) {
          System.out.println(msg);
      }
  
      /**
       * Replace a certain character in a string with a new substring.
       */
      public static String replace(String base, char ch, String str) {
          return (base.indexOf(ch) < 0) ? base :
              replace(base, String.valueOf(ch), new String[] { str });
      }
  
      public static String replace(String base, String delim, String[] str) {
          final int len = base.length();
          final StringBuilder result = threadLocalStringBuilder.get();
          result.setLength(0);
  
          for (int i = 0; i < len; i++) {
              final char ch = base.charAt(i);
              final int k = delim.indexOf(ch);
  
              if (k >= 0) {
                  result.append(str[k]);
              }
              else {
                  result.append(ch);
              }
          }
          return result.toString();
      }
  
  
      /**
       * Utility method to allow setting parameters of the form
       * {namespaceuri}localName
       * which get mapped to an instance variable in the class
       * Hence  a parameter of the form "{http://foo.bar}xyz"
       * will be replaced with the corresponding values
       * by the BasisLibrary's utility method mapQNametoJavaName
       * and thus get mapped to legal java variable names
       */
      public static String mapQNameToJavaName (String base ) {
         return replace(base, ".-:/{}?#%*",
                        new String[] { "$dot$", "$dash$" ,"$colon$", "$slash$",
                                       "","$colon$","$ques$","$hash$","$per$",
                                       "$aster$"});
  
      }
  
      //-- End utility functions
  }
  