Refactory
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / util / Util.java
index ccfbc90..1cafdf9 100644 (file)
@@ -33,1760 +33,1905 @@ import net.sourceforge.phpdt.core.compiler.CharOperation;
 import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
 import net.sourceforge.phpdt.internal.core.Assert;
 import net.sourceforge.phpdt.internal.core.PackageFragmentRoot;
-import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+import net.sourceforge.phpdt.internal.core.util.PHPFileUtil;
 
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
+//import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.text.edits.MalformedTreeException;
-import org.eclipse.text.edits.TextEdit;
+//import org.eclipse.jface.text.BadLocationException;
+//import org.eclipse.text.edits.MalformedTreeException;
+//import org.eclipse.text.edits.TextEdit;
 
 /**
  * Provides convenient utility methods to other types in this package.
  */
 public class Util {
 
-  public interface Comparable {
-    /**
-     * Returns 0 if this and c are equal, >0 if this is greater than c, or <0 if this is less than c.
-     */
-    int compareTo(Comparable c);
-  }
-
-  public interface Comparer {
-    /**
-     * Returns 0 if a and b are equal, >0 if a is greater than b, or <0 if a is less than b.
-     */
-    int compare(Object a, Object b);
-  }
-
-  private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
-
-  /* Bundle containing messages */
-  protected static ResourceBundle bundle;
-
-  private final static String bundleName = "net.sourceforge.phpdt.internal.core.util.messages"; //$NON-NLS-1$
-
-  private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
-
-  private static final String EMPTY_ARGUMENT = "   "; //$NON-NLS-1$
-
-  public static final String[] fgEmptyStringArray = new String[0];
-
-  private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
-
-  static {
-    relocalize();
-  }
-
-  private Util() {
-    // cannot be instantiated
-  }
-
-  /**
-   * Lookup the message with the given ID in this catalog
-   */
-  public static String bind(String id) {
-    return bind(id, (String[]) null);
-  }
-
-  /**
-   * Lookup the message with the given ID in this catalog and bind its substitution locations with the given string.
-   */
-  public static String bind(String id, String binding) {
-    return bind(id, new String[] { binding });
-  }
-
-  /**
-   * Lookup the message with the given ID in this catalog and bind its substitution locations with the given strings.
-   */
-  public static String bind(String id, String binding1, String binding2) {
-    return bind(id, new String[] { binding1, binding2 });
-  }
-
-  /**
-   * Lookup the message with the given ID in this catalog and bind its substitution locations with the given string values.
-   */
-  public static String bind(String id, String[] bindings) {
-    if (id == null)
-      return "No message available"; //$NON-NLS-1$
-    String message = null;
-    try {
-      message = bundle.getString(id);
-    } catch (MissingResourceException e) {
-      // If we got an exception looking for the message, fail gracefully by just returning
-      // the id we were looking for. In most cases this is semi-informative so is not too bad.
-      return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
-    }
-    // for compatibility with MessageFormat which eliminates double quotes in original message
-    char[] messageWithNoDoubleQuotes = CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
-
-    if (bindings == null)
-      return new String(messageWithNoDoubleQuotes);
-
-    int length = messageWithNoDoubleQuotes.length;
-    int start = 0;
-    int end = length;
-    StringBuffer output = null;
-    while (true) {
-      if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start)) > -1) {
-        if (output == null)
-          output = new StringBuffer(length + bindings.length * 20);
-        output.append(messageWithNoDoubleQuotes, start, end - start);
-        if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes, end + 1)) > -1) {
-          int index = -1;
-          String argId = new String(messageWithNoDoubleQuotes, end + 1, start - end - 1);
-          try {
-            index = Integer.parseInt(argId);
-            output.append(bindings[index]);
-          } catch (NumberFormatException nfe) { // could be nested message ID {compiler.name}
-            boolean done = false;
-            if (!id.equals(argId)) {
-              String argMessage = null;
-              try {
-                argMessage = bundle.getString(argId);
-                output.append(argMessage);
-                done = true;
-              } catch (MissingResourceException e) {
-                // unable to bind argument, ignore (will leave argument in)
-              }
-            }
-            if (!done)
-              output.append(messageWithNoDoubleQuotes, end + 1, start - end);
-          } catch (ArrayIndexOutOfBoundsException e) {
-            output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
-          }
-          start++;
-        } else {
-          output.append(messageWithNoDoubleQuotes, end, length);
-          break;
-        }
-      } else {
-        if (output == null)
-          return new String(messageWithNoDoubleQuotes);
-        output.append(messageWithNoDoubleQuotes, start, length - start);
-        break;
-      }
-    }
-    return output.toString();
-  }
-
-  /**
-   * Checks the type signature in String sig, starting at start and ending before end (end is not included). Returns the index of
-   * the character immediately after the signature if valid, or -1 if not valid.
-   */
-  private static int checkTypeSignature(String sig, int start, int end, boolean allowVoid) {
-    if (start >= end)
-      return -1;
-    int i = start;
-    char c = sig.charAt(i++);
-    int nestingDepth = 0;
-    while (c == '[') {
-      ++nestingDepth;
-      if (i >= end)
-        return -1;
-      c = sig.charAt(i++);
-    }
-    switch (c) {
-    case 'B':
-    case 'C':
-    case 'D':
-    case 'F':
-    case 'I':
-    case 'J':
-    case 'S':
-    case 'Z':
-      break;
-    case 'V':
-      if (!allowVoid)
-        return -1;
-      // array of void is not allowed
-      if (nestingDepth != 0)
-        return -1;
-      break;
-    case 'L':
-      int semicolon = sig.indexOf(';', i);
-      // Must have at least one character between L and ;
-      if (semicolon <= i || semicolon >= end)
-        return -1;
-      i = semicolon + 1;
-      break;
-    default:
-      return -1;
-    }
-    return i;
-  }
-
-  /**
-   * Combines two hash codes to make a new one.
-   */
-  public static int combineHashCodes(int hashCode1, int hashCode2) {
-    return hashCode1 * 17 + hashCode2;
-  }
-
-  /**
-   * Compares two byte arrays. Returns <0 if a byte in a is less than the corresponding byte in b, or if a is shorter, or if a is
-   * null. Returns >0 if a byte in a is greater than the corresponding byte in b, or if a is longer, or if b is null. Returns 0 if
-   * they are equal or both null.
-   */
-  public static int compare(byte[] a, byte[] b) {
-    if (a == b)
-      return 0;
-    if (a == null)
-      return -1;
-    if (b == null)
-      return 1;
-    int len = Math.min(a.length, b.length);
-    for (int i = 0; i < len; ++i) {
-      int diff = a[i] - b[i];
-      if (diff != 0)
-        return diff;
-    }
-    if (a.length > len)
-      return 1;
-    if (b.length > len)
-      return -1;
-    return 0;
-  }
-
-  /**
-   * Compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings.
-   * 
-   * @return the value <code>0</code> if the str1 is equal to str2; a value less than <code>0</code> if str1 is
-   *         lexicographically less than str2; and a value greater than <code>0</code> if str1 is lexicographically greater than
-   *         str2.
-   */
-  public static int compare(char[] str1, char[] str2) {
-    int len1 = str1.length;
-    int len2 = str2.length;
-    int n = Math.min(len1, len2);
-    int i = 0;
-    while (n-- != 0) {
-      char c1 = str1[i];
-      char c2 = str2[i++];
-      if (c1 != c2) {
-        return c1 - c2;
-      }
-    }
-    return len1 - len2;
-  }
-
-  /**
-   * Concatenate two strings with a char in between.
-   * 
-   * @see #concat(String, String)
-   */
-  public static String concat(String s1, char c, String s2) {
-    if (s1 == null)
-      s1 = "null"; //$NON-NLS-1$
-    if (s2 == null)
-      s2 = "null"; //$NON-NLS-1$
-    int l1 = s1.length();
-    int l2 = s2.length();
-    char[] buf = new char[l1 + 1 + l2];
-    s1.getChars(0, l1, buf, 0);
-    buf[l1] = c;
-    s2.getChars(0, l2, buf, l1 + 1);
-    return new String(buf);
-  }
-
-  /**
-   * Concatenate two strings. Much faster than using +, which: - creates a StringBuffer, - which is synchronized, - of default size,
-   * so the resulting char array is often larger than needed. This implementation creates an extra char array, since the String
-   * constructor copies its argument, but there's no way around this.
-   */
-  public static String concat(String s1, String s2) {
-    if (s1 == null)
-      s1 = "null"; //$NON-NLS-1$
-    if (s2 == null)
-      s2 = "null"; //$NON-NLS-1$
-    int l1 = s1.length();
-    int l2 = s2.length();
-    char[] buf = new char[l1 + l2];
-    s1.getChars(0, l1, buf, 0);
-    s2.getChars(0, l2, buf, l1);
-    return new String(buf);
-  }
-
-  /**
-   * Concatenate three strings.
-   * 
-   * @see #concat(String, String)
-   */
-  public static String concat(String s1, String s2, String s3) {
-    if (s1 == null)
-      s1 = "null"; //$NON-NLS-1$
-    if (s2 == null)
-      s2 = "null"; //$NON-NLS-1$
-    if (s3 == null)
-      s3 = "null"; //$NON-NLS-1$
-    int l1 = s1.length();
-    int l2 = s2.length();
-    int l3 = s3.length();
-    char[] buf = new char[l1 + l2 + l3];
-    s1.getChars(0, l1, buf, 0);
-    s2.getChars(0, l2, buf, l1);
-    s3.getChars(0, l3, buf, l1 + l2);
-    return new String(buf);
-  }
-
-  /**
-   * Converts a type signature from the IBinaryType representation to the DC representation.
-   */
-  public static String convertTypeSignature(char[] sig) {
-    return new String(sig).replace('/', '.');
-  }
-
-  /**
-   * Apply the given edit on the given string and return the updated string. Return the given string if anything wrong happen while
-   * applying the edit.
-   * 
-   * @param original
-   *          the given string
-   * @param edit
-   *          the given edit
-   * 
-   * @return the updated string
-   */
-  public final static String editedString(String original, TextEdit edit) {
-    if (edit == null) {
-      return original;
-    }
-    SimpleDocument document = new SimpleDocument(original);
-    try {
-      edit.apply(document, TextEdit.NONE);
-      return document.get();
-    } catch (MalformedTreeException e) {
-      e.printStackTrace();
-    } catch (BadLocationException e) {
-      e.printStackTrace();
-    }
-    return original;
-  }
-
-  /**
-   * Returns true iff str.toLowerCase().endsWith(end.toLowerCase()) implementation is not creating extra strings.
-   */
-  public final static boolean endsWithIgnoreCase(String str, String end) {
-
-    int strLength = str == null ? 0 : str.length();
-    int endLength = end == null ? 0 : end.length();
-
-    // return false if the string is smaller than the end.
-    if (endLength > strLength)
-      return false;
-
-    // return false if any character of the end are
-    // not the same in lower case.
-    for (int i = 1; i <= endLength; i++) {
-      if (Character.toLowerCase(end.charAt(endLength - i)) != Character.toLowerCase(str.charAt(strLength - i)))
-        return false;
-    }
-
-    return true;
-  }
-
-  /**
-   * Compares two arrays using equals() on the elements. Either or both arrays may be null. Returns true if both are null. Returns
-   * false if only one is null. If both are arrays, returns true iff they have the same length and all elements are equal.
-   */
-  public static boolean equalArraysOrNull(int[] a, int[] b) {
-    if (a == b)
-      return true;
-    if (a == null || b == null)
-      return false;
-    int len = a.length;
-    if (len != b.length)
-      return false;
-    for (int i = 0; i < len; ++i) {
-      if (a[i] != b[i])
-        return false;
-    }
-    return true;
-  }
-
-  /**
-   * Compares two arrays using equals() on the elements. Either or both arrays may be null. Returns true if both are null. Returns
-   * false if only one is null. If both are arrays, returns true iff they have the same length and all elements compare true with
-   * equals.
-   */
-  public static boolean equalArraysOrNull(Object[] a, Object[] b) {
-    if (a == b)
-      return true;
-    if (a == null || b == null)
-      return false;
-
-    int len = a.length;
-    if (len != b.length)
-      return false;
-    for (int i = 0; i < len; ++i) {
-      if (a[i] == null) {
-        if (b[i] != null)
-          return false;
-      } else {
-        if (!a[i].equals(b[i]))
-          return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Compares two arrays using equals() on the elements. The arrays are first sorted. Either or both arrays may be null. Returns
-   * true if both are null. Returns false if only one is null. If both are arrays, returns true iff they have the same length and
-   * iff, after sorting both arrays, all elements compare true with equals. The original arrays are left untouched.
-   */
-  public static boolean equalArraysOrNullSortFirst(Comparable[] a, Comparable[] b) {
-    if (a == b)
-      return true;
-    if (a == null || b == null)
-      return false;
-    int len = a.length;
-    if (len != b.length)
-      return false;
-    if (len >= 2) { // only need to sort if more than two items
-      a = sortCopy(a);
-      b = sortCopy(b);
-    }
-    for (int i = 0; i < len; ++i) {
-      if (!a[i].equals(b[i]))
-        return false;
-    }
-    return true;
-  }
-
-  /**
-   * Compares two String arrays using equals() on the elements. The arrays are first sorted. Either or both arrays may be null.
-   * Returns true if both are null. Returns false if only one is null. If both are arrays, returns true iff they have the same
-   * length and iff, after sorting both arrays, all elements compare true with equals. The original arrays are left untouched.
-   */
-  public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
-    if (a == b)
-      return true;
-    if (a == null || b == null)
-      return false;
-    int len = a.length;
-    if (len != b.length)
-      return false;
-    if (len >= 2) { // only need to sort if more than two items
-      a = sortCopy(a);
-      b = sortCopy(b);
-    }
-    for (int i = 0; i < len; ++i) {
-      if (!a[i].equals(b[i]))
-        return false;
-    }
-    return true;
-  }
-
-  /**
-   * Compares two objects using equals(). Either or both array may be null. Returns true if both are null. Returns false if only one
-   * is null. Otherwise, return the result of comparing with equals().
-   */
-  public static boolean equalOrNull(Object a, Object b) {
-    if (a == b) {
-      return true;
-    }
-    if (a == null || b == null) {
-      return false;
-    }
-    return a.equals(b);
-  }
-
-  /**
-   * Given a qualified name, extract the last component. If the input is not qualified, the same string is answered.
-   */
-  public static String extractLastName(String qualifiedName) {
-    int i = qualifiedName.lastIndexOf('.');
-    if (i == -1)
-      return qualifiedName;
-    return qualifiedName.substring(i + 1);
-  }
-
-  /**
-   * Extracts the parameter types from a method signature.
-   */
-  public static String[] extractParameterTypes(char[] sig) {
-    int count = getParameterCount(sig);
-    String[] result = new String[count];
-    if (count == 0)
-      return result;
-    int i = CharOperation.indexOf('(', sig) + 1;
-    count = 0;
-    int len = sig.length;
-    int start = i;
-    for (;;) {
-      if (i == len)
-        break;
-      char c = sig[i];
-      if (c == ')')
-        break;
-      if (c == '[') {
-        ++i;
-      } else if (c == 'L') {
-        i = CharOperation.indexOf(';', sig, i + 1) + 1;
-        Assert.isTrue(i != 0);
-        result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
-        start = i;
-      } else {
-        ++i;
-        result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
-        start = i;
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Extracts the return type from a method signature.
-   */
-  public static String extractReturnType(String sig) {
-    int i = sig.lastIndexOf(')');
-    Assert.isTrue(i != -1);
-    return sig.substring(i + 1);
-  }
-
-  private static IFile findFirstClassFile(IFolder folder) {
-    try {
-      IResource[] members = folder.members();
-      for (int i = 0, max = members.length; i < max; i++) {
-        IResource member = members[i];
-        if (member.getType() == IResource.FOLDER) {
-          return findFirstClassFile((IFolder) member);
-//        } else if (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(member.getName())) {
-//          return (IFile) member;
-        }
-      }
-    } catch (CoreException e) {
-      // ignore
-    }
-    return null;
-  }
-
-  /**
-   * Finds the first line separator used by the given text.
-   * 
-   * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"</code>, or <code>null</code> if none found
-   */
-  public static String findLineSeparator(char[] text) {
-    // find the first line separator
-    int length = text.length;
-    if (length > 0) {
-      char nextChar = text[0];
-      for (int i = 0; i < length; i++) {
-        char currentChar = nextChar;
-        nextChar = i < length - 1 ? text[i + 1] : ' ';
-        switch (currentChar) {
-        case '\n':
-          return "\n"; //$NON-NLS-1$
-        case '\r':
-          return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
-        }
-      }
-    }
-    // not found
-    return null;
-  }
-
-  //   public static IClassFileAttribute getAttribute(IClassFileReader classFileReader, char[] attributeName) {
-  //           IClassFileAttribute[] attributes = classFileReader.getAttributes();
-  //           for (int i = 0, max = attributes.length; i < max; i++) {
-  //                   if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
-  //                           return attributes[i];
-  //                   }
-  //           }
-  //           return null;
-  //   }
-  //   
-  //   public static IClassFileAttribute getAttribute(ICodeAttribute codeAttribute, char[] attributeName) {
-  //           IClassFileAttribute[] attributes = codeAttribute.getAttributes();
-  //           for (int i = 0, max = attributes.length; i < max; i++) {
-  //                   if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
-  //                           return attributes[i];
-  //                   }
-  //           }
-  //           return null;
-  //   }
-
-  //   public static IClassFileAttribute getAttribute(IFieldInfo fieldInfo, char[] attributeName) {
-  //           IClassFileAttribute[] attributes = fieldInfo.getAttributes();
-  //           for (int i = 0, max = attributes.length; i < max; i++) {
-  //                   if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
-  //                           return attributes[i];
-  //                   }
-  //           }
-  //           return null;
-  //   }
-  //
-  //   public static IClassFileAttribute getAttribute(IMethodInfo methodInfo, char[] attributeName) {
-  //           IClassFileAttribute[] attributes = methodInfo.getAttributes();
-  //           for (int i = 0, max = attributes.length; i < max; i++) {
-  //                   if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
-  //                           return attributes[i];
-  //                   }
-  //           }
-  //           return null;
-  //   }
-  /**
-   * Get the jdk level of this root. The value can be:
-   * <ul>
-   * <li>major < <16 + minor : see predefined constants on ClassFileConstants</li>
-   * <li><code>0</null> if the root is a source package fragment root or if a Java model exception occured</li>
-   * </ul>
-   * Returns the jdk level
-   */
-  //   public static long getJdkLevel(Object targetLibrary) {
-  //           try {
-  //                           ClassFileReader reader = null;
-  //                           if (targetLibrary instanceof IFolder) {
-  //                                   IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only internal classfolders are allowed
-  //                                   if (classFile != null) {
-  //                                           byte[] bytes = Util.getResourceContentsAsByteArray(classFile);
-  //                                           IPath location = classFile.getLocation();
-  //                                           reader = new ClassFileReader(bytes, location == null ? null : location.toString().toCharArray());
-  //                                   }
-  //                           } else {
-  //                                   // root is a jar file or a zip file
-  //                                   ZipFile jar = null;
-  //                                   try {
-  //                                           IPath path = null;
-  //                                           if (targetLibrary instanceof IResource) {
-  //                                                   path = ((IResource)targetLibrary).getLocation();
-  //                                           } else if (targetLibrary instanceof File){
-  //                                                   File f = (File) targetLibrary;
-  //                                                   if (!f.isDirectory()) {
-  //                                                           path = new Path(((File)targetLibrary).getPath());
-  //                                                   }
-  //                                           }
-  //                                           if (path != null) {
-  //                                                   jar = JavaModelManager.getJavaModelManager().getZipFile(path);
-  //                                                   for (Enumeration e= jar.entries(); e.hasMoreElements();) {
-  //                                                           ZipEntry member= (ZipEntry) e.nextElement();
-  //                                                           String entryName= member.getName();
-  //                                                           if (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(entryName)) {
-  //                                                                   reader = ClassFileReader.read(jar, entryName);
-  //                                                                   break;
-  //                                                           }
-  //                                                   }
-  //                                           }
-  //                                   } catch (CoreException e) {
-  //                                           // ignore
-  //                                   } finally {
-  //                                           JavaModelManager.getJavaModelManager().closeZipFile(jar);
-  //                                   }
-  //                           }
-  //                           if (reader != null) {
-  //                                   return reader.getVersion();
-  //                           }
-  //           } catch(JavaModelException e) {
-  //                   // ignore
-  //           } catch(ClassFormatException e) {
-  //                   // ignore
-  //           } catch(IOException e) {
-  //                   // ignore
-  //           }
-  //           return 0;
-  //   }
-  /**
-   * Returns the line separator used by the given buffer. Uses the given text if none found.
-   * 
-   * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"</code>
-   */
-  private static String getLineSeparator(char[] text, char[] buffer) {
-    // search in this buffer's contents first
-    String lineSeparator = findLineSeparator(buffer);
-    if (lineSeparator == null) {
-      // search in the given text
-      lineSeparator = findLineSeparator(text);
-      if (lineSeparator == null) {
-        // default to system line separator
-        return net.sourceforge.phpdt.internal.compiler.util.Util.LINE_SEPARATOR;
-      }
-    }
-    return lineSeparator;
-  }
-
-  /**
-   * Returns the number of parameter types in a method signature.
-   */
-  public static int getParameterCount(char[] sig) {
-    int i = CharOperation.indexOf('(', sig) + 1;
-    Assert.isTrue(i != 0);
-    int count = 0;
-    int len = sig.length;
-    for (;;) {
-      if (i == len)
-        break;
-      char c = sig[i];
-      if (c == ')')
-        break;
-      if (c == '[') {
-        ++i;
-      } else if (c == 'L') {
-        ++count;
-        i = CharOperation.indexOf(';', sig, i + 1) + 1;
-        Assert.isTrue(i != 0);
-      } else {
-        ++count;
-        ++i;
-      }
-    }
-    return count;
-  }
-
-  /**
-   * Put all the arguments in one String.
-   */
-  public static String getProblemArgumentsForMarker(String[] arguments) {
-    StringBuffer args = new StringBuffer(10);
-
-    args.append(arguments.length);
-    args.append(':');
-
-    for (int j = 0; j < arguments.length; j++) {
-      if (j != 0)
-        args.append(ARGUMENTS_DELIMITER);
-
-      if (arguments[j].length() == 0) {
-        args.append(EMPTY_ARGUMENT);
-      } else {
-        args.append(arguments[j]);
-      }
-    }
-
-    return args.toString();
-  }
-
-  /**
-   * Separate all the arguments of a String made by getProblemArgumentsForMarker
-   */
-  public static String[] getProblemArgumentsFromMarker(String argumentsString) {
-    if (argumentsString == null)
-      return null;
-    int index = argumentsString.indexOf(':');
-    if (index == -1)
-      return null;
-
-    int length = argumentsString.length();
-    int numberOfArg;
-    try {
-      numberOfArg = Integer.parseInt(argumentsString.substring(0, index));
-    } catch (NumberFormatException e) {
-      return null;
-    }
-    argumentsString = argumentsString.substring(index + 1, length);
-
-    String[] args = new String[length];
-    int count = 0;
-
-    StringTokenizer tokenizer = new StringTokenizer(argumentsString, ARGUMENTS_DELIMITER);
-    while (tokenizer.hasMoreTokens()) {
-      String argument = tokenizer.nextToken();
-      if (argument.equals(EMPTY_ARGUMENT))
-        argument = ""; //$NON-NLS-1$
-      args[count++] = argument;
-    }
-
-    if (count != numberOfArg)
-      return null;
-
-    System.arraycopy(args, 0, args = new String[count], 0, count);
-    return args;
-  }
-
-  /**
-   * Returns the given file's contents as a byte array.
-   */
-  public static byte[] getResourceContentsAsByteArray(IFile file) throws JavaModelException {
-    InputStream stream = null;
-    try {
-      stream = new BufferedInputStream(file.getContents(true));
-    } catch (CoreException e) {
-      throw new JavaModelException(e);
-    }
-    try {
-      return net.sourceforge.phpdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1);
-    } catch (IOException e) {
-      throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
-    } finally {
-      try {
-        stream.close();
-      } catch (IOException e) {
-        // ignore
-      }
-    }
-  }
-
-  /**
-   * Returns the given file's contents as a character array.
-   */
-  public static char[] getResourceContentsAsCharArray(IFile file) throws JavaModelException {
-    // Get encoding from file
-    String encoding = null;
-    try {
-      encoding = file.getCharset();
-    } catch (CoreException ce) {
-      // do not use any encoding
-    }
-    return getResourceContentsAsCharArray(file, encoding);
-  }
-
-  public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException {
-    // Get resource contents
-    InputStream stream = null;
-    try {
-      stream = new BufferedInputStream(file.getContents(true));
-    } catch (CoreException e) {
-      throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
-    }
-    try {
-      return net.sourceforge.phpdt.internal.compiler.util.Util.getInputStreamAsCharArray(stream, -1, encoding);
-    } catch (IOException e) {
-      throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
-    } finally {
-      try {
-        stream.close();
-      } catch (IOException e) {
-        // ignore
-      }
-    }
-  }
-
-  /**
-   * Returns a trimmed version the simples names returned by Signature.
-   */
-  public static String[] getTrimmedSimpleNames(String name) {
-    String[] result = Signature.getSimpleNames(name);
-    if (result == null)
-      return null;
-    for (int i = 0, length = result.length; i < length; i++) {
-      result[i] = result[i].trim();
-    }
-    return result;
-  }
-
-  /*
-   * Returns the index of the most specific argument paths which is strictly enclosing the path to check
-   */
-  public static int indexOfEnclosingPath(IPath checkedPath, IPath[] paths, int pathCount) {
-
-    int bestMatch = -1, bestLength = -1;
-    for (int i = 0; i < pathCount; i++) {
-      if (paths[i].equals(checkedPath))
-        continue;
-      if (paths[i].isPrefixOf(checkedPath)) {
-        int currentLength = paths[i].segmentCount();
-        if (currentLength > bestLength) {
-          bestLength = currentLength;
-          bestMatch = i;
-        }
-      }
-    }
-    return bestMatch;
-  }
-
-  /*
-   * Returns the index of the first argument paths which is equal to the path to check
-   */
-  public static int indexOfMatchingPath(IPath checkedPath, IPath[] paths, int pathCount) {
-
-    for (int i = 0; i < pathCount; i++) {
-      if (paths[i].equals(checkedPath))
-        return i;
-    }
-    return -1;
-  }
-
-  /*
-   * Returns the index of the first argument paths which is strictly nested inside the path to check
-   */
-  public static int indexOfNestedPath(IPath checkedPath, IPath[] paths, int pathCount) {
-
-    for (int i = 0; i < pathCount; i++) {
-      if (checkedPath.equals(paths[i]))
-        continue;
-      if (checkedPath.isPrefixOf(paths[i]))
-        return i;
-    }
-    return -1;
-  }
-
-  /*
-   * Returns whether the given java element is exluded from its root's classpath. It doesn't check whether the root itself is on the
-   * classpath or not
-   */
-  public static final boolean isExcluded(IJavaElement element) {
-    int elementType = element.getElementType();
-    PackageFragmentRoot root = null;
-    IResource resource = null;
-    switch (elementType) {
-    case IJavaElement.JAVA_MODEL:
-    case IJavaElement.JAVA_PROJECT:
-    case IJavaElement.PACKAGE_FRAGMENT_ROOT:
-      return false;
-
-    //                 case IJavaElement.PACKAGE_FRAGMENT:
-    //                         PackageFragmentRoot root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
-    //                         IResource resource = element.getResource();
-    //                         return resource != null && isExcluded(resource, root.fullInclusionPatternChars(), root.fullExclusionPatternChars());
-
-    case IJavaElement.COMPILATION_UNIT:
-      root = (PackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
-      resource = element.getResource();
-      //                               if (resource != null && isExcluded(resource, root.fullInclusionPatternChars(), root.fullExclusionPatternChars()))
-      //                                       return true;
-      return isExcluded(element.getParent());
-
-    default:
-      IJavaElement cu = element.getAncestor(IJavaElement.COMPILATION_UNIT);
-      return cu != null && isExcluded(cu);
-    }
-  }
-
-  /*
-   * Returns whether the given resource path matches one of the inclusion/exclusion patterns. NOTE: should not be asked directly
-   * using pkg root pathes
-   * 
-   * @see IClasspathEntry#getInclusionPatterns
-   * @see IClasspathEntry#getExclusionPatterns
-   */
-  public final static boolean isExcluded(IPath resourcePath, char[][] inclusionPatterns, char[][] exclusionPatterns,
-      boolean isFolderPath) {
-    if (inclusionPatterns == null && exclusionPatterns == null)
-      return false;
-    char[] path = resourcePath.toString().toCharArray();
-
-    inclusionCheck: if (inclusionPatterns != null) {
-      for (int i = 0, length = inclusionPatterns.length; i < length; i++) {
-        char[] pattern = inclusionPatterns[i];
-        char[] folderPattern = pattern;
-        if (isFolderPath) {
-          int lastSlash = CharOperation.lastIndexOf('/', pattern);
-          if (lastSlash != -1 && lastSlash != pattern.length - 1) { // trailing slash -> adds '**' for free (see
-                                                                    // http://ant.apache.org/manual/dirtasks.html)
-            int star = CharOperation.indexOf('*', pattern, lastSlash);
-            if ((star == -1 || star >= pattern.length - 1 || pattern[star + 1] != '*')) {
-              folderPattern = CharOperation.subarray(pattern, 0, lastSlash);
-            }
-          }
-        }
-        if (CharOperation.pathMatch(folderPattern, path, true, '/')) {
-          break inclusionCheck;
-        }
-      }
-      return true; // never included
-    }
-    if (isFolderPath) {
-      path = CharOperation.concat(path, new char[] { '*' }, '/');
-    }
-    exclusionCheck: if (exclusionPatterns != null) {
-      for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
-        if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/')) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
-  public final static boolean isExcluded(IResource resource, char[][] exclusionPatterns) {
-    IPath path = resource.getFullPath();
-    // ensure that folders are only excluded if all of their children are excluded
-    return isExcluded(path, null, exclusionPatterns, resource.getType() == IResource.FOLDER);
-  }
-
-  /*
-   * Returns whether the given resource matches one of the exclusion patterns. NOTE: should not be asked directly using pkg root
-   * pathes
-   * 
-   * @see IClasspathEntry#getExclusionPatterns
-   */
-  public final static boolean isExcluded(IResource resource, char[][] inclusionPatterns, char[][] exclusionPatterns) {
-    IPath path = resource.getFullPath();
-    // ensure that folders are only excluded if all of their children are excluded
-    return isExcluded(path, inclusionPatterns, exclusionPatterns, resource.getType() == IResource.FOLDER);
-  }
-
-  /**
-   * Validate the given .class file name. A .class file name must obey the following rules:
-   * <ul>
-   * <li>it must not be null
-   * <li>it must include the <code>".class"</code> suffix
-   * <li>its prefix must be a valid identifier
-   * </ul>
-   * </p>
-   * 
-   * @param name
-   *          the name of a .class file
-   * @return a status object with code <code>IStatus.OK</code> if the given name is valid as a .class file name, otherwise a
-   *         status object indicating what is wrong with the name
-   */
-  //   public static boolean isValidClassFileName(String name) {
-  //           return JavaConventions.validateClassFileName(name).getSeverity() != IStatus.ERROR;
-  //   }
-  /**
-   * Validate the given compilation unit name. A compilation unit name must obey the following rules:
-   * <ul>
-   * <li>it must not be null
-   * <li>it must include the <code>".java"</code> suffix
-   * <li>its prefix must be a valid identifier
-   * </ul>
-   * </p>
-   * 
-   * @param name
-   *          the name of a compilation unit
-   * @return a status object with code <code>IStatus.OK</code> if the given name is valid as a compilation unit name, otherwise a
-   *         status object indicating what is wrong with the name
-   */
-  public static boolean isValidCompilationUnitName(String name) {
-    return PHPFileUtil.isPHPFileName(name);
-    //         return JavaConventions.validateCompilationUnitName(name).getSeverity() != IStatus.ERROR;
-  }
-
-  /**
-   * Returns true if the given folder name is valid for a package, false if it is not.
-   */
-       public static boolean isValidFolderNameForPackage(String folderName) {
-  //           return JavaConventions.validateIdentifier(folderName).getSeverity() != IStatus.ERROR;
-         return true;
-       }
-  /**
-   * Returns true if the given method signature is valid, false if it is not.
-   */
-  public static boolean isValidMethodSignature(String sig) {
-    int len = sig.length();
-    if (len == 0)
-      return false;
-    int i = 0;
-    char c = sig.charAt(i++);
-    if (c != '(')
-      return false;
-    if (i >= len)
-      return false;
-    while (sig.charAt(i) != ')') {
-      // Void is not allowed as a parameter type.
-      i = checkTypeSignature(sig, i, len, false);
-      if (i == -1)
-        return false;
-      if (i >= len)
-        return false;
-    }
-    ++i;
-    i = checkTypeSignature(sig, i, len, true);
-    return i == len;
-  }
-
-  /**
-   * Returns true if the given type signature is valid, false if it is not.
-   */
-  public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
-    int len = sig.length();
-    return checkTypeSignature(sig, 0, len, allowVoid) == len;
-  }
-
-  /*
-   * Add a log entry
-   */
-  public static void log(Throwable e, String message) {
-    Throwable nestedException;
-    if (e instanceof JavaModelException && (nestedException = ((JavaModelException) e).getException()) != null) {
-      e = nestedException;
-    }
-    IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, message, e);
-    JavaCore.getPlugin().getLog().log(status);
-  }
-
-  /**
-   * Normalizes the cariage returns in the given text. They are all changed to use the given buffer's line separator.
-   */
-  public static char[] normalizeCRs(char[] text, char[] buffer) {
-    CharArrayBuffer result = new CharArrayBuffer();
-    int lineStart = 0;
-    int length = text.length;
-    if (length == 0)
-      return text;
-    String lineSeparator = getLineSeparator(text, buffer);
-    char nextChar = text[0];
-    for (int i = 0; i < length; i++) {
-      char currentChar = nextChar;
-      nextChar = i < length - 1 ? text[i + 1] : ' ';
-      switch (currentChar) {
-      case '\n':
-        int lineLength = i - lineStart;
-        char[] line = new char[lineLength];
-        System.arraycopy(text, lineStart, line, 0, lineLength);
-        result.append(line);
-        result.append(lineSeparator);
-        lineStart = i + 1;
-        break;
-      case '\r':
-        lineLength = i - lineStart;
-        if (lineLength >= 0) {
-          line = new char[lineLength];
-          System.arraycopy(text, lineStart, line, 0, lineLength);
-          result.append(line);
-          result.append(lineSeparator);
-          if (nextChar == '\n') {
-            nextChar = ' ';
-            lineStart = i + 2;
-          } else {
-            // when line separator are mixed in the same file
-            // \r might not be followed by a \n. If not, we should increment
-            // lineStart by one and not by two.
-            lineStart = i + 1;
-          }
-        } else {
-          // when line separator are mixed in the same file
-          // we need to prevent NegativeArraySizeException
-          lineStart = i + 1;
-        }
-        break;
-      }
-    }
-    char[] lastLine;
-    if (lineStart > 0) {
-      int lastLineLength = length - lineStart;
-      if (lastLineLength > 0) {
-        lastLine = new char[lastLineLength];
-        System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
-        result.append(lastLine);
-      }
-      return result.getContents();
-    }
-    return text;
-  }
-
-  /**
-   * Normalizes the cariage returns in the given text. They are all changed to use given buffer's line sepatator.
-   */
-  public static String normalizeCRs(String text, String buffer) {
-    return new String(normalizeCRs(text.toCharArray(), buffer.toCharArray()));
-  }
-
-  /**
-   * Converts the given relative path into a package name. Returns null if the path is not a valid package name.
-   */
-  public static String packageName(IPath pkgPath) {
-    StringBuffer pkgName = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME);
-    for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
-      String segment = pkgPath.segment(j);
-      //                       if (!isValidFolderNameForPackage(segment)) {
-      //                               return null;
-      //                       }
-      pkgName.append(segment);
-      if (j < pkgPath.segmentCount() - 1) {
-        pkgName.append("."); //$NON-NLS-1$
-      }
-    }
-    return pkgName.toString();
-  }
-
-  /**
-   * Returns the length of the common prefix between s1 and s2.
-   */
-  public static int prefixLength(char[] s1, char[] s2) {
-    int len = 0;
-    int max = Math.min(s1.length, s2.length);
-    for (int i = 0; i < max && s1[i] == s2[i]; ++i)
-      ++len;
-    return len;
-  }
-
-  /**
-   * Returns the length of the common prefix between s1 and s2.
-   */
-  public static int prefixLength(String s1, String s2) {
-    int len = 0;
-    int max = Math.min(s1.length(), s2.length());
-    for (int i = 0; i < max && s1.charAt(i) == s2.charAt(i); ++i)
-      ++len;
-    return len;
-  }
-
-  private static void quickSort(char[][] list, int left, int right) {
-    int original_left = left;
-    int original_right = right;
-    char[] mid = list[(left + right) / 2];
-    do {
-      while (compare(list[left], mid) < 0) {
-        left++;
-      }
-      while (compare(mid, list[right]) < 0) {
-        right--;
-      }
-      if (left <= right) {
-        char[] tmp = list[left];
-        list[left] = list[right];
-        list[right] = tmp;
-        left++;
-        right--;
-      }
-    } while (left <= right);
-    if (original_left < right) {
-      quickSort(list, original_left, right);
-    }
-    if (left < original_right) {
-      quickSort(list, left, original_right);
-    }
-  }
-
-  /**
-   * Sort the comparable objects in the given collection.
-   */
-  private static void quickSort(Comparable[] sortedCollection, int left, int right) {
-    int original_left = left;
-    int original_right = right;
-    Comparable mid = sortedCollection[(left + right) / 2];
-    do {
-      while (sortedCollection[left].compareTo(mid) < 0) {
-        left++;
-      }
-      while (mid.compareTo(sortedCollection[right]) < 0) {
-        right--;
-      }
-      if (left <= right) {
-        Comparable tmp = sortedCollection[left];
-        sortedCollection[left] = sortedCollection[right];
-        sortedCollection[right] = tmp;
-        left++;
-        right--;
-      }
-    } while (left <= right);
-    if (original_left < right) {
-      quickSort(sortedCollection, original_left, right);
-    }
-    if (left < original_right) {
-      quickSort(sortedCollection, left, original_right);
-    }
-  }
-
-  private static void quickSort(int[] list, int left, int right) {
-    int original_left = left;
-    int original_right = right;
-    int mid = list[(left + right) / 2];
-    do {
-      while (list[left] < mid) {
-        left++;
-      }
-      while (mid < list[right]) {
-        right--;
-      }
-      if (left <= right) {
-        int tmp = list[left];
-        list[left] = list[right];
-        list[right] = tmp;
-        left++;
-        right--;
-      }
-    } while (left <= right);
-    if (original_left < right) {
-      quickSort(list, original_left, right);
-    }
-    if (left < original_right) {
-      quickSort(list, left, original_right);
-    }
-  }
-
-  /**
-   * Sort the objects in the given collection using the given comparer.
-   */
-  private static void quickSort(Object[] sortedCollection, int left, int right, Comparer comparer) {
-    int original_left = left;
-    int original_right = right;
-    Object mid = sortedCollection[(left + right) / 2];
-    do {
-      while (comparer.compare(sortedCollection[left], mid) < 0) {
-        left++;
-      }
-      while (comparer.compare(mid, sortedCollection[right]) < 0) {
-        right--;
-      }
-      if (left <= right) {
-        Object tmp = sortedCollection[left];
-        sortedCollection[left] = sortedCollection[right];
-        sortedCollection[right] = tmp;
-        left++;
-        right--;
-      }
-    } while (left <= right);
-    if (original_left < right) {
-      quickSort(sortedCollection, original_left, right, comparer);
-    }
-    if (left < original_right) {
-      quickSort(sortedCollection, left, original_right, comparer);
-    }
-  }
-
-  /**
-   * Sort the objects in the given collection using the given sort order.
-   */
-  private static void quickSort(Object[] sortedCollection, int left, int right, int[] sortOrder) {
-    int original_left = left;
-    int original_right = right;
-    int mid = sortOrder[(left + right) / 2];
-    do {
-      while (sortOrder[left] < mid) {
-        left++;
-      }
-      while (mid < sortOrder[right]) {
-        right--;
-      }
-      if (left <= right) {
-        Object tmp = sortedCollection[left];
-        sortedCollection[left] = sortedCollection[right];
-        sortedCollection[right] = tmp;
-        int tmp2 = sortOrder[left];
-        sortOrder[left] = sortOrder[right];
-        sortOrder[right] = tmp2;
-        left++;
-        right--;
-      }
-    } while (left <= right);
-    if (original_left < right) {
-      quickSort(sortedCollection, original_left, right, sortOrder);
-    }
-    if (left < original_right) {
-      quickSort(sortedCollection, left, original_right, sortOrder);
-    }
-  }
-
-  /**
-   * Sort the strings in the given collection.
-   */
-  private static void quickSort(String[] sortedCollection, int left, int right) {
-    int original_left = left;
-    int original_right = right;
-    String mid = sortedCollection[(left + right) / 2];
-    do {
-      while (sortedCollection[left].compareTo(mid) < 0) {
-        left++;
-      }
-      while (mid.compareTo(sortedCollection[right]) < 0) {
-        right--;
-      }
-      if (left <= right) {
-        String tmp = sortedCollection[left];
-        sortedCollection[left] = sortedCollection[right];
-        sortedCollection[right] = tmp;
-        left++;
-        right--;
-      }
-    } while (left <= right);
-    if (original_left < right) {
-      quickSort(sortedCollection, original_left, right);
-    }
-    if (left < original_right) {
-      quickSort(sortedCollection, left, original_right);
-    }
-  }
-
-  /**
-   * Sort the strings in the given collection in reverse alphabetical order.
-   */
-  private static void quickSortReverse(String[] sortedCollection, int left, int right) {
-    int original_left = left;
-    int original_right = right;
-    String mid = sortedCollection[(left + right) / 2];
-    do {
-      while (sortedCollection[left].compareTo(mid) > 0) {
-        left++;
-      }
-      while (mid.compareTo(sortedCollection[right]) > 0) {
-        right--;
-      }
-      if (left <= right) {
-        String tmp = sortedCollection[left];
-        sortedCollection[left] = sortedCollection[right];
-        sortedCollection[right] = tmp;
-        left++;
-        right--;
-      }
-    } while (left <= right);
-    if (original_left < right) {
-      quickSortReverse(sortedCollection, original_left, right);
-    }
-    if (left < original_right) {
-      quickSortReverse(sortedCollection, left, original_right);
-    }
-  }
-
-  /**
-   * Reads in a string from the specified data input stream. The string has been encoded using a modified UTF-8 format.
-   * <p>
-   * The first two bytes are read as if by <code>readUnsignedShort</code>. This value gives the number of following bytes that
-   * are in the encoded string, not the length of the resulting string. The following bytes are then interpreted as bytes encoding
-   * characters in the UTF-8 format and are converted into characters.
-   * <p>
-   * This method blocks until all the bytes are read, the end of the stream is detected, or an exception is thrown.
-   * 
-   * @param in
-   *          a data input stream.
-   * @return a Unicode string.
-   * @exception EOFException
-   *              if the input stream reaches the end before all the bytes.
-   * @exception IOException
-   *              if an I/O error occurs.
-   * @exception UTFDataFormatException
-   *              if the bytes do not represent a valid UTF-8 encoding of a Unicode string.
-   * @see java.io.DataInputStream#readUnsignedShort()
-   */
-  public final static char[] readUTF(DataInput in) throws IOException {
-    int utflen = in.readUnsignedShort();
-    char str[] = new char[utflen];
-    int count = 0;
-    int strlen = 0;
-    while (count < utflen) {
-      int c = in.readUnsignedByte();
-      int char2, char3;
-      switch (c >> 4) {
-      case 0:
-      case 1:
-      case 2:
-      case 3:
-      case 4:
-      case 5:
-      case 6:
-      case 7:
-        // 0xxxxxxx
-        count++;
-        str[strlen++] = (char) c;
-        break;
-      case 12:
-      case 13:
-        // 110x xxxx 10xx xxxx
-        count += 2;
-        if (count > utflen)
-          throw new UTFDataFormatException();
-        char2 = in.readUnsignedByte();
-        if ((char2 & 0xC0) != 0x80)
-          throw new UTFDataFormatException();
-        str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
-        break;
-      case 14:
-        // 1110 xxxx 10xx xxxx 10xx xxxx
-        count += 3;
-        if (count > utflen)
-          throw new UTFDataFormatException();
-        char2 = in.readUnsignedByte();
-        char3 = in.readUnsignedByte();
-        if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
-          throw new UTFDataFormatException();
-        str[strlen++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
-        break;
-      default:
-        // 10xx xxxx, 1111 xxxx
-        throw new UTFDataFormatException();
-      }
-    }
-    if (strlen < utflen) {
-      System.arraycopy(str, 0, str = new char[strlen], 0, strlen);
-    }
-    return str;
-  }
-
-  /**
-   * Creates a NLS catalog for the given locale.
-   */
-  public static void relocalize() {
-    try {
-      bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
-    } catch (MissingResourceException e) {
-      System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
-      throw e;
-    }
-  }
-
-  public static void sort(char[][] list) {
-    if (list.length > 1)
-      quickSort(list, 0, list.length - 1);
-  }
-
-  /**
-   * Sorts an array of Comparable objects in place.
-   */
-  public static void sort(Comparable[] objects) {
-    if (objects.length > 1)
-      quickSort(objects, 0, objects.length - 1);
-  }
-
-  public static void sort(int[] list) {
-    if (list.length > 1)
-      quickSort(list, 0, list.length - 1);
-  }
-
-  /**
-   * Sorts an array of objects in place. The given comparer compares pairs of items.
-   */
-  public static void sort(Object[] objects, Comparer comparer) {
-    if (objects.length > 1)
-      quickSort(objects, 0, objects.length - 1, comparer);
-  }
-
-  /**
-   * Sorts an array of objects in place, using the sort order given for each item.
-   */
-  public static void sort(Object[] objects, int[] sortOrder) {
-    if (objects.length > 1)
-      quickSort(objects, 0, objects.length - 1, sortOrder);
-  }
-
-  /**
-   * Sorts an array of strings in place using quicksort.
-   */
-  public static void sort(String[] strings) {
-    if (strings.length > 1)
-      quickSort(strings, 0, strings.length - 1);
-  }
-
-  /**
-   * Sorts an array of Comparable objects, returning a new array with the sorted items. The original array is left untouched.
-   */
-  public static Comparable[] sortCopy(Comparable[] objects) {
-    int len = objects.length;
-    Comparable[] copy = new Comparable[len];
-    System.arraycopy(objects, 0, copy, 0, len);
-    sort(copy);
-    return copy;
-  }
-
-  /**
-   * Sorts an array of Strings, returning a new array with the sorted items. The original array is left untouched.
-   */
-  public static Object[] sortCopy(Object[] objects, Comparer comparer) {
-    int len = objects.length;
-    Object[] copy = new Object[len];
-    System.arraycopy(objects, 0, copy, 0, len);
-    sort(copy, comparer);
-    return copy;
-  }
-
-  /**
-   * Sorts an array of Strings, returning a new array with the sorted items. The original array is left untouched.
-   */
-  public static String[] sortCopy(String[] objects) {
-    int len = objects.length;
-    String[] copy = new String[len];
-    System.arraycopy(objects, 0, copy, 0, len);
-    sort(copy);
-    return copy;
-  }
-
-  /**
-   * Sorts an array of strings in place using quicksort in reverse alphabetical order.
-   */
-  public static void sortReverseOrder(String[] strings) {
-    if (strings.length > 1)
-      quickSortReverse(strings, 0, strings.length - 1);
-  }
-
-  /**
-   * Converts a String[] to char[][].
-   */
-  public static char[][] toCharArrays(String[] a) {
-    int len = a.length;
-    char[][] result = new char[len][];
-    for (int i = 0; i < len; ++i) {
-      result[i] = toChars(a[i]);
-    }
-    return result;
-  }
-
-  /**
-   * Converts a String to char[].
-   */
-  public static char[] toChars(String s) {
-    int len = s.length();
-    char[] chars = new char[len];
-    s.getChars(0, len, chars, 0);
-    return chars;
-  }
-
-  /**
-   * Converts a String to char[][], where segments are separate by '.'.
-   */
-  public static char[][] toCompoundChars(String s) {
-    int len = s.length();
-    if (len == 0) {
-      return CharOperation.NO_CHAR_CHAR;
-    }
-    int segCount = 1;
-    for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
-      ++segCount;
-    }
-    char[][] segs = new char[segCount][];
-    int start = 0;
-    for (int i = 0; i < segCount; ++i) {
-      int dot = s.indexOf('.', start);
-      int end = (dot == -1 ? s.length() : dot);
-      segs[i] = new char[end - start];
-      s.getChars(start, end, segs[i], 0);
-      start = end + 1;
-    }
-    return segs;
-  }
-
-  /**
-   * Converts a char[] to String.
-   */
-  public static String toString(char[] c) {
-    return new String(c);
-  }
-
-  /**
-   * Converts a char[][] to String, where segments are separated by '.'.
-   */
-  public static String toString(char[][] c) {
-    StringBuffer sb = new StringBuffer();
-    for (int i = 0, max = c.length; i < max; ++i) {
-      if (i != 0)
-        sb.append('.');
-      sb.append(c[i]);
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Converts a char[][] and a char[] to String, where segments are separated by '.'.
-   */
-  public static String toString(char[][] c, char[] d) {
-    if (c == null)
-      return new String(d);
-    StringBuffer sb = new StringBuffer();
-    for (int i = 0, max = c.length; i < max; ++i) {
-      sb.append(c[i]);
-      sb.append('.');
-    }
-    sb.append(d);
-    return sb.toString();
-  }
-
-  /*
-   * Returns the unresolved type parameter signatures of the given method e.g. {"QString;", "[int", "[[Qjava.util.Vector;"}
-   */
-  //   public static String[] typeParameterSignatures(AbstractMethodDeclaration method) {
-  //           Argument[] args = method.arguments;
-  //           if (args != null) {
-  //                   int length = args.length;
-  //                   String[] signatures = new String[length];
-  //                   for (int i = 0; i < args.length; i++) {
-  //                           Argument arg = args[i];
-  //                           signatures[i] = typeSignature(arg.type);
-  //                   }
-  //                   return signatures;
-  //           }
-  //           return new String[0];
-  //   }
-  /*
-   * Returns the unresolved type signature of the given type reference, e.g. "QString;", "[int", "[[Qjava.util.Vector;"
-   */
-  //   public static String typeSignature(TypeReference type) {
-  //           char[][] compoundName = type.getTypeName();
-  //           char[] typeName =CharOperation.concatWith(compoundName, '.');
-  //           String signature = Signature.createTypeSignature(typeName, false/*don't resolve*/);
-  //           int dimensions = type.dimensions();
-  //           if (dimensions > 0) {
-  //                   signature = Signature.createArraySignature(signature, dimensions);
-  //           }
-  //           return signature;
-  //   }
-  /*
-        * Returns the unresolved type signature of the given type reference, 
-        * e.g. "QString;", "[int", "[[Qjava.util.Vector;"
+       public interface Comparable {
+               /**
+                * Returns 0 if this and c are equal, >0 if this is greater than c, or
+                * <0 if this is less than c.
+                */
+               int compareTo(Comparable c);
+       }
+
+       public interface Comparer {
+               /**
+                * Returns 0 if a and b are equal, >0 if a is greater than b, or <0 if a
+                * is less than b.
+                */
+               int compare(Object a, Object b);
+       }
+
+       private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
+
+       /* Bundle containing messages */
+       protected static ResourceBundle bundle;
+
+       private final static String bundleName = "net.sourceforge.phpdt.internal.core.util.messages"; //$NON-NLS-1$
+
+       private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
+
+       private static final String EMPTY_ARGUMENT = "   "; //$NON-NLS-1$
+
+       public static final String[] fgEmptyStringArray = new String[0];
+
+       private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
+
+       static {
+               relocalize();
+       }
+
+       private Util() {
+               // cannot be instantiated
+       }
+
+       /**
+        * Lookup the message with the given ID in this catalog
+        */
+       public static String bind(String id) {
+               return bind(id, (String[]) null);
+       }
+
+       /**
+        * Lookup the message with the given ID in this catalog and bind its
+        * substitution locations with the given string.
+        */
+       public static String bind(String id, String binding) {
+               return bind(id, new String[] { binding });
+       }
+
+       /**
+        * Lookup the message with the given ID in this catalog and bind its
+        * substitution locations with the given strings.
+        */
+       public static String bind(String id, String binding1, String binding2) {
+               return bind(id, new String[] { binding1, binding2 });
+       }
+
+       /**
+        * Lookup the message with the given ID in this catalog and bind its
+        * substitution locations with the given string values.
+        */
+       public static String bind(String id, String[] bindings) {
+               if (id == null)
+                       return "No message available"; //$NON-NLS-1$
+               String message = null;
+               try {
+                       message = bundle.getString(id);
+               } catch (MissingResourceException e) {
+                       // If we got an exception looking for the message, fail gracefully
+                       // by just returning
+                       // the id we were looking for. In most cases this is
+                       // semi-informative so is not too bad.
+                       return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
+               }
+               // for compatibility with MessageFormat which eliminates double quotes
+               // in original message
+               char[] messageWithNoDoubleQuotes = CharOperation.replace(message
+                               .toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
+
+               if (bindings == null)
+                       return new String(messageWithNoDoubleQuotes);
+
+               int length = messageWithNoDoubleQuotes.length;
+               int start = 0;
+               int end = length;
+               StringBuffer output = null;
+               while (true) {
+                       if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes,
+                                       start)) > -1) {
+                               if (output == null)
+                                       output = new StringBuffer(length + bindings.length * 20);
+                               output.append(messageWithNoDoubleQuotes, start, end - start);
+                               if ((start = CharOperation.indexOf('}',
+                                               messageWithNoDoubleQuotes, end + 1)) > -1) {
+                                       int index = -1;
+                                       String argId = new String(messageWithNoDoubleQuotes,
+                                                       end + 1, start - end - 1);
+                                       try {
+                                               index = Integer.parseInt(argId);
+                                               output.append(bindings[index]);
+                                       } catch (NumberFormatException nfe) { // could be nested
+                                                                                                                       // message ID
+                                                                                                                       // {compiler.name}
+                                               boolean done = false;
+                                               if (!id.equals(argId)) {
+                                                       String argMessage = null;
+                                                       try {
+                                                               argMessage = bundle.getString(argId);
+                                                               output.append(argMessage);
+                                                               done = true;
+                                                       } catch (MissingResourceException e) {
+                                                               // unable to bind argument, ignore (will leave
+                                                               // argument in)
+                                                       }
+                                               }
+                                               if (!done)
+                                                       output.append(messageWithNoDoubleQuotes, end + 1,
+                                                                       start - end);
+                                       } catch (ArrayIndexOutOfBoundsException e) {
+                                               output
+                                                               .append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
+                                       }
+                                       start++;
+                               } else {
+                                       output.append(messageWithNoDoubleQuotes, end, length);
+                                       break;
+                               }
+                       } else {
+                               if (output == null)
+                                       return new String(messageWithNoDoubleQuotes);
+                               output.append(messageWithNoDoubleQuotes, start, length - start);
+                               break;
+                       }
+               }
+               return output.toString();
+       }
+
+       /**
+        * Checks the type signature in String sig, starting at start and ending
+        * before end (end is not included). Returns the index of the character
+        * immediately after the signature if valid, or -1 if not valid.
+        */
+       private static int checkTypeSignature(String sig, int start, int end,
+                       boolean allowVoid) {
+               if (start >= end)
+                       return -1;
+               int i = start;
+               char c = sig.charAt(i++);
+               int nestingDepth = 0;
+               while (c == '[') {
+                       ++nestingDepth;
+                       if (i >= end)
+                               return -1;
+                       c = sig.charAt(i++);
+               }
+               switch (c) {
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'F':
+               case 'I':
+               case 'J':
+               case 'S':
+               case 'Z':
+                       break;
+               case 'V':
+                       if (!allowVoid)
+                               return -1;
+                       // array of void is not allowed
+                       if (nestingDepth != 0)
+                               return -1;
+                       break;
+               case 'L':
+                       int semicolon = sig.indexOf(';', i);
+                       // Must have at least one character between L and ;
+                       if (semicolon <= i || semicolon >= end)
+                               return -1;
+                       i = semicolon + 1;
+                       break;
+               default:
+                       return -1;
+               }
+               return i;
+       }
+
+       /**
+        * Combines two hash codes to make a new one.
+        */
+       public static int combineHashCodes(int hashCode1, int hashCode2) {
+               return hashCode1 * 17 + hashCode2;
+       }
+
+       /**
+        * Compares two byte arrays. Returns <0 if a byte in a is less than the
+        * corresponding byte in b, or if a is shorter, or if a is null. Returns >0
+        * if a byte in a is greater than the corresponding byte in b, or if a is
+        * longer, or if b is null. Returns 0 if they are equal or both null.
+        */
+       public static int compare(byte[] a, byte[] b) {
+               if (a == b)
+                       return 0;
+               if (a == null)
+                       return -1;
+               if (b == null)
+                       return 1;
+               int len = Math.min(a.length, b.length);
+               for (int i = 0; i < len; ++i) {
+                       int diff = a[i] - b[i];
+                       if (diff != 0)
+                               return diff;
+               }
+               if (a.length > len)
+                       return 1;
+               if (b.length > len)
+                       return -1;
+               return 0;
+       }
+
+       /**
+        * Compares two strings lexicographically. The comparison is based on the
+        * Unicode value of each character in the strings.
+        * 
+        * @return the value <code>0</code> if the str1 is equal to str2; a value
+        *         less than <code>0</code> if str1 is lexicographically less than
+        *         str2; and a value greater than <code>0</code> if str1 is
+        *         lexicographically greater than str2.
+        */
+       public static int compare(char[] str1, char[] str2) {
+               int len1 = str1.length;
+               int len2 = str2.length;
+               int n = Math.min(len1, len2);
+               int i = 0;
+               while (n-- != 0) {
+                       char c1 = str1[i];
+                       char c2 = str2[i++];
+                       if (c1 != c2) {
+                               return c1 - c2;
+                       }
+               }
+               return len1 - len2;
+       }
+
+       /**
+        * Concatenate two strings with a char in between.
+        * 
+        * @see #concat(String, String)
+        */
+       public static String concat(String s1, char c, String s2) {
+               if (s1 == null)
+                       s1 = "null"; //$NON-NLS-1$
+               if (s2 == null)
+                       s2 = "null"; //$NON-NLS-1$
+               int l1 = s1.length();
+               int l2 = s2.length();
+               char[] buf = new char[l1 + 1 + l2];
+               s1.getChars(0, l1, buf, 0);
+               buf[l1] = c;
+               s2.getChars(0, l2, buf, l1 + 1);
+               return new String(buf);
+       }
+
+       /**
+        * Concatenate two strings. Much faster than using +, which: - creates a
+        * StringBuffer, - which is synchronized, - of default size, so the
+        * resulting char array is often larger than needed. This implementation
+        * creates an extra char array, since the String constructor copies its
+        * argument, but there's no way around this.
+        */
+       public static String concat(String s1, String s2) {
+               if (s1 == null)
+                       s1 = "null"; //$NON-NLS-1$
+               if (s2 == null)
+                       s2 = "null"; //$NON-NLS-1$
+               int l1 = s1.length();
+               int l2 = s2.length();
+               char[] buf = new char[l1 + l2];
+               s1.getChars(0, l1, buf, 0);
+               s2.getChars(0, l2, buf, l1);
+               return new String(buf);
+       }
+
+       /**
+        * Concatenate three strings.
+        * 
+        * @see #concat(String, String)
+        */
+       public static String concat(String s1, String s2, String s3) {
+               if (s1 == null)
+                       s1 = "null"; //$NON-NLS-1$
+               if (s2 == null)
+                       s2 = "null"; //$NON-NLS-1$
+               if (s3 == null)
+                       s3 = "null"; //$NON-NLS-1$
+               int l1 = s1.length();
+               int l2 = s2.length();
+               int l3 = s3.length();
+               char[] buf = new char[l1 + l2 + l3];
+               s1.getChars(0, l1, buf, 0);
+               s2.getChars(0, l2, buf, l1);
+               s3.getChars(0, l3, buf, l1 + l2);
+               return new String(buf);
+       }
+
+       /**
+        * Converts a type signature from the IBinaryType representation to the DC
+        * representation.
+        */
+       public static String convertTypeSignature(char[] sig) {
+               return new String(sig).replace('/', '.');
+       }
+
+       /**
+        * Apply the given edit on the given string and return the updated string.
+        * Return the given string if anything wrong happen while applying the edit.
+        * 
+        * @param original
+        *            the given string
+        * @param edit
+        *            the given edit
+        * 
+        * @return the updated string
+        */
+//     public final static String editedString(String original, TextEdit edit) {
+//             if (edit == null) {
+//                     return original;
+//             }
+//             SimpleDocument document = new SimpleDocument(original);
+//             try {
+//                     edit.apply(document, TextEdit.NONE);
+//                     return document.get();
+//             } catch (MalformedTreeException e) {
+//                     e.printStackTrace();
+//             } catch (BadLocationException e) {
+//                     e.printStackTrace();
+//             }
+//             return original;
+//     }
+
+       /**
+        * Returns true iff str.toLowerCase().endsWith(end.toLowerCase())
+        * implementation is not creating extra strings.
+        */
+       public final static boolean endsWithIgnoreCase(String str, String end) {
+
+               int strLength = str == null ? 0 : str.length();
+               int endLength = end == null ? 0 : end.length();
+
+               // return false if the string is smaller than the end.
+               if (endLength > strLength)
+                       return false;
+
+               // return false if any character of the end are
+               // not the same in lower case.
+               for (int i = 1; i <= endLength; i++) {
+                       if (Character.toLowerCase(end.charAt(endLength - i)) != Character
+                                       .toLowerCase(str.charAt(strLength - i)))
+                               return false;
+               }
+
+               return true;
+       }
+
+       /**
+        * Compares two arrays using equals() on the elements. Either or both arrays
+        * may be null. Returns true if both are null. Returns false if only one is
+        * null. If both are arrays, returns true iff they have the same length and
+        * all elements are equal.
+        */
+       public static boolean equalArraysOrNull(int[] a, int[] b) {
+               if (a == b)
+                       return true;
+               if (a == null || b == null)
+                       return false;
+               int len = a.length;
+               if (len != b.length)
+                       return false;
+               for (int i = 0; i < len; ++i) {
+                       if (a[i] != b[i])
+                               return false;
+               }
+               return true;
+       }
+
+       /**
+        * Compares two arrays using equals() on the elements. Either or both arrays
+        * may be null. Returns true if both are null. Returns false if only one is
+        * null. If both are arrays, returns true iff they have the same length and
+        * all elements compare true with equals.
+        */
+       public static boolean equalArraysOrNull(Object[] a, Object[] b) {
+               if (a == b)
+                       return true;
+               if (a == null || b == null)
+                       return false;
+
+               int len = a.length;
+               if (len != b.length)
+                       return false;
+               for (int i = 0; i < len; ++i) {
+                       if (a[i] == null) {
+                               if (b[i] != null)
+                                       return false;
+                       } else {
+                               if (!a[i].equals(b[i]))
+                                       return false;
+                       }
+               }
+               return true;
+       }
+
+       /**
+        * Compares two arrays using equals() on the elements. The arrays are first
+        * sorted. Either or both arrays may be null. Returns true if both are null.
+        * Returns false if only one is null. If both are arrays, returns true iff
+        * they have the same length and iff, after sorting both arrays, all
+        * elements compare true with equals. The original arrays are left
+        * untouched.
+        */
+       public static boolean equalArraysOrNullSortFirst(Comparable[] a,
+                       Comparable[] b) {
+               if (a == b)
+                       return true;
+               if (a == null || b == null)
+                       return false;
+               int len = a.length;
+               if (len != b.length)
+                       return false;
+               if (len >= 2) { // only need to sort if more than two items
+                       a = sortCopy(a);
+                       b = sortCopy(b);
+               }
+               for (int i = 0; i < len; ++i) {
+                       if (!a[i].equals(b[i]))
+                               return false;
+               }
+               return true;
+       }
+
+       /**
+        * Compares two String arrays using equals() on the elements. The arrays are
+        * first sorted. Either or both arrays may be null. Returns true if both are
+        * null. Returns false if only one is null. If both are arrays, returns true
+        * iff they have the same length and iff, after sorting both arrays, all
+        * elements compare true with equals. The original arrays are left
+        * untouched.
+        */
+       public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
+               if (a == b)
+                       return true;
+               if (a == null || b == null)
+                       return false;
+               int len = a.length;
+               if (len != b.length)
+                       return false;
+               if (len >= 2) { // only need to sort if more than two items
+                       a = sortCopy(a);
+                       b = sortCopy(b);
+               }
+               for (int i = 0; i < len; ++i) {
+                       if (!a[i].equals(b[i]))
+                               return false;
+               }
+               return true;
+       }
+
+       /**
+        * Compares two objects using equals(). Either or both array may be null.
+        * Returns true if both are null. Returns false if only one is null.
+        * Otherwise, return the result of comparing with equals().
+        */
+       public static boolean equalOrNull(Object a, Object b) {
+               if (a == b) {
+                       return true;
+               }
+               if (a == null || b == null) {
+                       return false;
+               }
+               return a.equals(b);
+       }
+
+       /**
+        * Given a qualified name, extract the last component. If the input is not
+        * qualified, the same string is answered.
+        */
+       public static String extractLastName(String qualifiedName) {
+               int i = qualifiedName.lastIndexOf('.');
+               if (i == -1)
+                       return qualifiedName;
+               return qualifiedName.substring(i + 1);
+       }
+
+       /**
+        * Extracts the parameter types from a method signature.
+        */
+       public static String[] extractParameterTypes(char[] sig) {
+               int count = getParameterCount(sig);
+               String[] result = new String[count];
+               if (count == 0)
+                       return result;
+               int i = CharOperation.indexOf('(', sig) + 1;
+               count = 0;
+               int len = sig.length;
+               int start = i;
+               for (;;) {
+                       if (i == len)
+                               break;
+                       char c = sig[i];
+                       if (c == ')')
+                               break;
+                       if (c == '[') {
+                               ++i;
+                       } else if (c == 'L') {
+                               i = CharOperation.indexOf(';', sig, i + 1) + 1;
+                               Assert.isTrue(i != 0);
+                               result[count++] = convertTypeSignature(CharOperation.subarray(
+                                               sig, start, i));
+                               start = i;
+                       } else {
+                               ++i;
+                               result[count++] = convertTypeSignature(CharOperation.subarray(
+                                               sig, start, i));
+                               start = i;
+                       }
+               }
+               return result;
+       }
+
+       /**
+        * Extracts the return type from a method signature.
+        */
+       public static String extractReturnType(String sig) {
+               int i = sig.lastIndexOf(')');
+               Assert.isTrue(i != -1);
+               return sig.substring(i + 1);
+       }
+
+//     private static IFile findFirstClassFile(IFolder folder) {
+//             try {
+//                     IResource[] members = folder.members();
+//                     for (int i = 0, max = members.length; i < max; i++) {
+//                             IResource member = members[i];
+//                             if (member.getType() == IResource.FOLDER) {
+//                                     return findFirstClassFile((IFolder) member);
+//                                     // } else if
+//                                     // (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(member.getName()))
+//                                     // {
+//                                     // return (IFile) member;
+//                             }
+//                     }
+//             } catch (CoreException e) {
+//                     // ignore
+//             }
+//             return null;
+//     }
+
+       /**
+        * Finds the first line separator used by the given text.
+        * 
+        * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"</code>,
+        *         or <code>null</code> if none found
+        */
+       public static String findLineSeparator(char[] text) {
+               // find the first line separator
+               int length = text.length;
+               if (length > 0) {
+                       char nextChar = text[0];
+                       for (int i = 0; i < length; i++) {
+                               char currentChar = nextChar;
+                               nextChar = i < length - 1 ? text[i + 1] : ' ';
+                               switch (currentChar) {
+                               case '\n':
+                                       return "\n"; //$NON-NLS-1$
+                               case '\r':
+                                       return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
+                               }
+                       }
+               }
+               // not found
+               return null;
+       }
+
+       // public static IClassFileAttribute getAttribute(IClassFileReader
+       // classFileReader, char[] attributeName) {
+       // IClassFileAttribute[] attributes = classFileReader.getAttributes();
+       // for (int i = 0, max = attributes.length; i < max; i++) {
+       // if (CharOperation.equals(attributes[i].getAttributeName(),
+       // attributeName)) {
+       // return attributes[i];
+       // }
+       // }
+       // return null;
+       // }
+       //      
+       // public static IClassFileAttribute getAttribute(ICodeAttribute
+       // codeAttribute, char[] attributeName) {
+       // IClassFileAttribute[] attributes = codeAttribute.getAttributes();
+       // for (int i = 0, max = attributes.length; i < max; i++) {
+       // if (CharOperation.equals(attributes[i].getAttributeName(),
+       // attributeName)) {
+       // return attributes[i];
+       // }
+       // }
+       // return null;
+       // }
+
+       // public static IClassFileAttribute getAttribute(IFieldInfo fieldInfo,
+       // char[] attributeName) {
+       // IClassFileAttribute[] attributes = fieldInfo.getAttributes();
+       // for (int i = 0, max = attributes.length; i < max; i++) {
+       // if (CharOperation.equals(attributes[i].getAttributeName(),
+       // attributeName)) {
+       // return attributes[i];
+       // }
+       // }
+       // return null;
+       // }
+       //
+       // public static IClassFileAttribute getAttribute(IMethodInfo methodInfo,
+       // char[] attributeName) {
+       // IClassFileAttribute[] attributes = methodInfo.getAttributes();
+       // for (int i = 0, max = attributes.length; i < max; i++) {
+       // if (CharOperation.equals(attributes[i].getAttributeName(),
+       // attributeName)) {
+       // return attributes[i];
+       // }
+       // }
+       // return null;
+       // }
+       /**
+        * Get the jdk level of this root. The value can be:
+        * <ul>
+        * <li>major < <16 + minor : see predefined constants on ClassFileConstants</li>
+        * <li><code>0</null> if the root is a source package fragment root or if a Java model exception occured</li>
+        * </ul>
+        * Returns the jdk level
+        */
+       // public static long getJdkLevel(Object targetLibrary) {
+       // try {
+       // ClassFileReader reader = null;
+       // if (targetLibrary instanceof IFolder) {
+       // IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only
+       // internal classfolders are allowed
+       // if (classFile != null) {
+       // byte[] bytes = Util.getResourceContentsAsByteArray(classFile);
+       // IPath location = classFile.getLocation();
+       // reader = new ClassFileReader(bytes, location == null ? null :
+       // location.toString().toCharArray());
+       // }
+       // } else {
+       // // root is a jar file or a zip file
+       // ZipFile jar = null;
+       // try {
+       // IPath path = null;
+       // if (targetLibrary instanceof IResource) {
+       // path = ((IResource)targetLibrary).getLocation();
+       // } else if (targetLibrary instanceof File){
+       // File f = (File) targetLibrary;
+       // if (!f.isDirectory()) {
+       // path = new Path(((File)targetLibrary).getPath());
+       // }
+       // }
+       // if (path != null) {
+       // jar = JavaModelManager.getJavaModelManager().getZipFile(path);
+       // for (Enumeration e= jar.entries(); e.hasMoreElements();) {
+       // ZipEntry member= (ZipEntry) e.nextElement();
+       // String entryName= member.getName();
+       // if
+       // (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(entryName))
+       // {
+       // reader = ClassFileReader.read(jar, entryName);
+       // break;
+       // }
+       // }
+       // }
+       // } catch (CoreException e) {
+       // // ignore
+       // } finally {
+       // JavaModelManager.getJavaModelManager().closeZipFile(jar);
+       // }
+       // }
+       // if (reader != null) {
+       // return reader.getVersion();
+       // }
+       // } catch(JavaModelException e) {
+       // // ignore
+       // } catch(ClassFormatException e) {
+       // // ignore
+       // } catch(IOException e) {
+       // // ignore
+       // }
+       // return 0;
+       // }
+       /**
+        * Returns the line separator used by the given buffer. Uses the given text
+        * if none found.
+        * 
+        * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"</code>
+        */
+       private static String getLineSeparator(char[] text, char[] buffer) {
+               // search in this buffer's contents first
+               String lineSeparator = findLineSeparator(buffer);
+               if (lineSeparator == null) {
+                       // search in the given text
+                       lineSeparator = findLineSeparator(text);
+                       if (lineSeparator == null) {
+                               // default to system line separator
+                               return net.sourceforge.phpdt.internal.compiler.util.Util.LINE_SEPARATOR;
+                       }
+               }
+               return lineSeparator;
+       }
+
+       /**
+        * Returns the number of parameter types in a method signature.
+        */
+       public static int getParameterCount(char[] sig) {
+               int i = CharOperation.indexOf('(', sig) + 1;
+               Assert.isTrue(i != 0);
+               int count = 0;
+               int len = sig.length;
+               for (;;) {
+                       if (i == len)
+                               break;
+                       char c = sig[i];
+                       if (c == ')')
+                               break;
+                       if (c == '[') {
+                               ++i;
+                       } else if (c == 'L') {
+                               ++count;
+                               i = CharOperation.indexOf(';', sig, i + 1) + 1;
+                               Assert.isTrue(i != 0);
+                       } else {
+                               ++count;
+                               ++i;
+                       }
+               }
+               return count;
+       }
+
+       /**
+        * Put all the arguments in one String.
+        */
+       public static String getProblemArgumentsForMarker(String[] arguments) {
+               StringBuffer args = new StringBuffer(10);
+
+               args.append(arguments.length);
+               args.append(':');
+
+               for (int j = 0; j < arguments.length; j++) {
+                       if (j != 0)
+                               args.append(ARGUMENTS_DELIMITER);
+
+                       if (arguments[j].length() == 0) {
+                               args.append(EMPTY_ARGUMENT);
+                       } else {
+                               args.append(arguments[j]);
+                       }
+               }
+
+               return args.toString();
+       }
+
+       /**
+        * Separate all the arguments of a String made by
+        * getProblemArgumentsForMarker
+        */
+       public static String[] getProblemArgumentsFromMarker(String argumentsString) {
+               if (argumentsString == null)
+                       return null;
+               int index = argumentsString.indexOf(':');
+               if (index == -1)
+                       return null;
+
+               int length = argumentsString.length();
+               int numberOfArg;
+               try {
+                       numberOfArg = Integer.parseInt(argumentsString.substring(0, index));
+               } catch (NumberFormatException e) {
+                       return null;
+               }
+               argumentsString = argumentsString.substring(index + 1, length);
+
+               String[] args = new String[length];
+               int count = 0;
+
+               StringTokenizer tokenizer = new StringTokenizer(argumentsString,
+                               ARGUMENTS_DELIMITER);
+               while (tokenizer.hasMoreTokens()) {
+                       String argument = tokenizer.nextToken();
+                       if (argument.equals(EMPTY_ARGUMENT))
+                               argument = ""; //$NON-NLS-1$
+                       args[count++] = argument;
+               }
+
+               if (count != numberOfArg)
+                       return null;
+
+               System.arraycopy(args, 0, args = new String[count], 0, count);
+               return args;
+       }
+
+       /**
+        * Returns the given file's contents as a byte array.
+        */
+       public static byte[] getResourceContentsAsByteArray(IFile file)
+                       throws JavaModelException {
+               InputStream stream = null;
+               try {
+                       stream = new BufferedInputStream(file.getContents(true));
+               } catch (CoreException e) {
+                       throw new JavaModelException(e);
+               }
+               try {
+                       return net.sourceforge.phpdt.internal.compiler.util.Util
+                                       .getInputStreamAsByteArray(stream, -1);
+               } catch (IOException e) {
+                       throw new JavaModelException(e,
+                                       IJavaModelStatusConstants.IO_EXCEPTION);
+               } finally {
+                       try {
+                               stream.close();
+                       } catch (IOException e) {
+                               // ignore
+                       }
+               }
+       }
+
+       /**
+        * Returns the given file's contents as a character array.
+        */
+       public static char[] getResourceContentsAsCharArray(IFile file)
+                       throws JavaModelException {
+               // Get encoding from file
+               String encoding = null;
+               try {
+                       encoding = file.getCharset();
+               } catch (CoreException ce) {
+                       // do not use any encoding
+               }
+               return getResourceContentsAsCharArray(file, encoding);
+       }
+
+       public static char[] getResourceContentsAsCharArray(IFile file,
+                       String encoding) throws JavaModelException {
+               // Get resource contents
+               InputStream stream = null;
+               try {
+                       stream = new BufferedInputStream(file.getContents(true));
+               } catch (CoreException e) {
+                       throw new JavaModelException(e,
+                                       IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
+               }
+               try {
+                       return net.sourceforge.phpdt.internal.compiler.util.Util
+                                       .getInputStreamAsCharArray(stream, -1, encoding);
+               } catch (IOException e) {
+                       throw new JavaModelException(e,
+                                       IJavaModelStatusConstants.IO_EXCEPTION);
+               } finally {
+                       try {
+                               stream.close();
+                       } catch (IOException e) {
+                               // ignore
+                       }
+               }
+       }
+
+       /**
+        * Returns a trimmed version the simples names returned by Signature.
+        */
+       public static String[] getTrimmedSimpleNames(String name) {
+               String[] result = Signature.getSimpleNames(name);
+               if (result == null)
+                       return null;
+               for (int i = 0, length = result.length; i < length; i++) {
+                       result[i] = result[i].trim();
+               }
+               return result;
+       }
+
+       /*
+        * Returns the index of the most specific argument paths which is strictly
+        * enclosing the path to check
+        */
+       public static int indexOfEnclosingPath(IPath checkedPath, IPath[] paths,
+                       int pathCount) {
+
+               int bestMatch = -1, bestLength = -1;
+               for (int i = 0; i < pathCount; i++) {
+                       if (paths[i].equals(checkedPath))
+                               continue;
+                       if (paths[i].isPrefixOf(checkedPath)) {
+                               int currentLength = paths[i].segmentCount();
+                               if (currentLength > bestLength) {
+                                       bestLength = currentLength;
+                                       bestMatch = i;
+                               }
+                       }
+               }
+               return bestMatch;
+       }
+
+       /*
+        * Returns the index of the first argument paths which is equal to the path
+        * to check
+        */
+       public static int indexOfMatchingPath(IPath checkedPath, IPath[] paths,
+                       int pathCount) {
+
+               for (int i = 0; i < pathCount; i++) {
+                       if (paths[i].equals(checkedPath))
+                               return i;
+               }
+               return -1;
+       }
+
+       /*
+        * Returns the index of the first argument paths which is strictly nested
+        * inside the path to check
+        */
+       public static int indexOfNestedPath(IPath checkedPath, IPath[] paths,
+                       int pathCount) {
+
+               for (int i = 0; i < pathCount; i++) {
+                       if (checkedPath.equals(paths[i]))
+                               continue;
+                       if (checkedPath.isPrefixOf(paths[i]))
+                               return i;
+               }
+               return -1;
+       }
+
+       /*
+        * Returns whether the given java element is exluded from its root's
+        * classpath. It doesn't check whether the root itself is on the classpath
+        * or not
+        */
+       public static final boolean isExcluded(IJavaElement element) {
+               int elementType = element.getElementType();
+               PackageFragmentRoot root = null;
+               IResource resource = null;
+               switch (elementType) {
+               case IJavaElement.JAVA_MODEL:
+               case IJavaElement.JAVA_PROJECT:
+               case IJavaElement.PACKAGE_FRAGMENT_ROOT:
+                       return false;
+
+                       // case IJavaElement.PACKAGE_FRAGMENT:
+                       // PackageFragmentRoot root =
+                       // (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+                       // IResource resource = element.getResource();
+                       // return resource != null && isExcluded(resource,
+                       // root.fullInclusionPatternChars(),
+                       // root.fullExclusionPatternChars());
+
+               case IJavaElement.COMPILATION_UNIT:
+                       root = (PackageFragmentRoot) element
+                                       .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+                       resource = element.getResource();
+                       // if (resource != null && isExcluded(resource,
+                       // root.fullInclusionPatternChars(),
+                       // root.fullExclusionPatternChars()))
+                       // return true;
+                       return isExcluded(element.getParent());
+
+               default:
+                       IJavaElement cu = element
+                                       .getAncestor(IJavaElement.COMPILATION_UNIT);
+                       return cu != null && isExcluded(cu);
+               }
+       }
+
+       /*
+        * Returns whether the given resource path matches one of the
+        * inclusion/exclusion patterns. NOTE: should not be asked directly using
+        * pkg root pathes
+        * 
+        * @see IClasspathEntry#getInclusionPatterns
+        * @see IClasspathEntry#getExclusionPatterns
+        */
+       public final static boolean isExcluded(IPath resourcePath,
+                       char[][] inclusionPatterns, char[][] exclusionPatterns,
+                       boolean isFolderPath) {
+               if (inclusionPatterns == null && exclusionPatterns == null)
+                       return false;
+               char[] path = resourcePath.toString().toCharArray();
+
+               inclusionCheck: if (inclusionPatterns != null) {
+                       for (int i = 0, length = inclusionPatterns.length; i < length; i++) {
+                               char[] pattern = inclusionPatterns[i];
+                               char[] folderPattern = pattern;
+                               if (isFolderPath) {
+                                       int lastSlash = CharOperation.lastIndexOf('/', pattern);
+                                       if (lastSlash != -1 && lastSlash != pattern.length - 1) { // trailing
+                                                                                                                                                               // slash
+                                                                                                                                                               // ->
+                                                                                                                                                               // adds
+                                                                                                                                                               // '**'
+                                                                                                                                                               // for
+                                                                                                                                                               // free
+                                                                                                                                                               // (see
+                                               // http://ant.apache.org/manual/dirtasks.html)
+                                               int star = CharOperation.indexOf('*', pattern,
+                                                               lastSlash);
+                                               if ((star == -1 || star >= pattern.length - 1 || pattern[star + 1] != '*')) {
+                                                       folderPattern = CharOperation.subarray(pattern, 0,
+                                                                       lastSlash);
+                                               }
+                                       }
+                               }
+                               if (CharOperation.pathMatch(folderPattern, path, true, '/')) {
+                                       break inclusionCheck;
+                               }
+                       }
+                       return true; // never included
+               }
+               if (isFolderPath) {
+                       path = CharOperation.concat(path, new char[] { '*' }, '/');
+               }
+               exclusionCheck: if (exclusionPatterns != null) {
+                       for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
+                               if (CharOperation.pathMatch(exclusionPatterns[i], path, true,
+                                               '/')) {
+                                       return true;
+                               }
+                       }
+               }
+               return false;
+       }
+
+       public final static boolean isExcluded(IResource resource,
+                       char[][] exclusionPatterns) {
+               IPath path = resource.getFullPath();
+               // ensure that folders are only excluded if all of their children are
+               // excluded
+               return isExcluded(path, null, exclusionPatterns,
+                               resource.getType() == IResource.FOLDER);
+       }
+
+       /*
+        * Returns whether the given resource matches one of the exclusion patterns.
+        * NOTE: should not be asked directly using pkg root pathes
+        * 
+        * @see IClasspathEntry#getExclusionPatterns
+        */
+       public final static boolean isExcluded(IResource resource,
+                       char[][] inclusionPatterns, char[][] exclusionPatterns) {
+               IPath path = resource.getFullPath();
+               // ensure that folders are only excluded if all of their children are
+               // excluded
+               return isExcluded(path, inclusionPatterns, exclusionPatterns, resource
+                               .getType() == IResource.FOLDER);
+       }
+
+       /**
+        * Validate the given .class file name. A .class file name must obey the
+        * following rules:
+        * <ul>
+        * <li>it must not be null
+        * <li>it must include the <code>".class"</code> suffix
+        * <li>its prefix must be a valid identifier
+        * </ul>
+        * </p>
+        * 
+        * @param name
+        *            the name of a .class file
+        * @return a status object with code <code>IStatus.OK</code> if the given
+        *         name is valid as a .class file name, otherwise a status object
+        *         indicating what is wrong with the name
+        */
+       // public static boolean isValidClassFileName(String name) {
+       // return JavaConventions.validateClassFileName(name).getSeverity() !=
+       // IStatus.ERROR;
+       // }
+       /**
+        * Validate the given compilation unit name. A compilation unit name must
+        * obey the following rules:
+        * <ul>
+        * <li>it must not be null
+        * <li>it must include the <code>".java"</code> suffix
+        * <li>its prefix must be a valid identifier
+        * </ul>
+        * </p>
+        * 
+        * @param name
+        *            the name of a compilation unit
+        * @return a status object with code <code>IStatus.OK</code> if the given
+        *         name is valid as a compilation unit name, otherwise a status
+        *         object indicating what is wrong with the name
+        */
+       public static boolean isValidCompilationUnitName(String name) {
+               return PHPFileUtil.isPHPFileName(name);
+               // return
+               // JavaConventions.validateCompilationUnitName(name).getSeverity() !=
+               // IStatus.ERROR;
+       }
+
+       /**
+        * Returns true if the given folder name is valid for a package, false if it
+        * is not.
+        */
+       public static boolean isValidFolderNameForPackage(String folderName) {
+               // return JavaConventions.validateIdentifier(folderName).getSeverity()
+               // != IStatus.ERROR;
+               return true;
+       }
+
+       /**
+        * Returns true if the given method signature is valid, false if it is not.
+        */
+       public static boolean isValidMethodSignature(String sig) {
+               int len = sig.length();
+               if (len == 0)
+                       return false;
+               int i = 0;
+               char c = sig.charAt(i++);
+               if (c != '(')
+                       return false;
+               if (i >= len)
+                       return false;
+               while (sig.charAt(i) != ')') {
+                       // Void is not allowed as a parameter type.
+                       i = checkTypeSignature(sig, i, len, false);
+                       if (i == -1)
+                               return false;
+                       if (i >= len)
+                               return false;
+               }
+               ++i;
+               i = checkTypeSignature(sig, i, len, true);
+               return i == len;
+       }
+
+       /**
+        * Returns true if the given type signature is valid, false if it is not.
+        */
+       public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
+               int len = sig.length();
+               return checkTypeSignature(sig, 0, len, allowVoid) == len;
+       }
+
+       /*
+        * Add a log entry
+        */
+       public static void log(Throwable e, String message) {
+               Throwable nestedException;
+               if (e instanceof JavaModelException
+                               && (nestedException = ((JavaModelException) e).getException()) != null) {
+                       e = nestedException;
+               }
+               IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
+                               IStatus.ERROR, message, e);
+               JavaCore.getPlugin().getLog().log(status);
+       }
+
+       /**
+        * Normalizes the cariage returns in the given text. They are all changed to
+        * use the given buffer's line separator.
+        */
+       public static char[] normalizeCRs(char[] text, char[] buffer) {
+               CharArrayBuffer result = new CharArrayBuffer();
+               int lineStart = 0;
+               int length = text.length;
+               if (length == 0)
+                       return text;
+               String lineSeparator = getLineSeparator(text, buffer);
+               char nextChar = text[0];
+               for (int i = 0; i < length; i++) {
+                       char currentChar = nextChar;
+                       nextChar = i < length - 1 ? text[i + 1] : ' ';
+                       switch (currentChar) {
+                       case '\n':
+                               int lineLength = i - lineStart;
+                               char[] line = new char[lineLength];
+                               System.arraycopy(text, lineStart, line, 0, lineLength);
+                               result.append(line);
+                               result.append(lineSeparator);
+                               lineStart = i + 1;
+                               break;
+                       case '\r':
+                               lineLength = i - lineStart;
+                               if (lineLength >= 0) {
+                                       line = new char[lineLength];
+                                       System.arraycopy(text, lineStart, line, 0, lineLength);
+                                       result.append(line);
+                                       result.append(lineSeparator);
+                                       if (nextChar == '\n') {
+                                               nextChar = ' ';
+                                               lineStart = i + 2;
+                                       } else {
+                                               // when line separator are mixed in the same file
+                                               // \r might not be followed by a \n. If not, we should
+                                               // increment
+                                               // lineStart by one and not by two.
+                                               lineStart = i + 1;
+                                       }
+                               } else {
+                                       // when line separator are mixed in the same file
+                                       // we need to prevent NegativeArraySizeException
+                                       lineStart = i + 1;
+                               }
+                               break;
+                       }
+               }
+               char[] lastLine;
+               if (lineStart > 0) {
+                       int lastLineLength = length - lineStart;
+                       if (lastLineLength > 0) {
+                               lastLine = new char[lastLineLength];
+                               System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
+                               result.append(lastLine);
+                       }
+                       return result.getContents();
+               }
+               return text;
+       }
+
+       /**
+        * Normalizes the cariage returns in the given text. They are all changed to
+        * use given buffer's line sepatator.
+        */
+       public static String normalizeCRs(String text, String buffer) {
+               return new String(
+                               normalizeCRs(text.toCharArray(), buffer.toCharArray()));
+       }
+
+       /**
+        * Converts the given relative path into a package name. Returns null if the
+        * path is not a valid package name.
+        */
+       public static String packageName(IPath pkgPath) {
+               StringBuffer pkgName = new StringBuffer(
+                               IPackageFragment.DEFAULT_PACKAGE_NAME);
+               for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
+                       String segment = pkgPath.segment(j);
+                       // if (!isValidFolderNameForPackage(segment)) {
+                       // return null;
+                       // }
+                       pkgName.append(segment);
+                       if (j < pkgPath.segmentCount() - 1) {
+                               pkgName.append("."); //$NON-NLS-1$
+                       }
+               }
+               return pkgName.toString();
+       }
+
+       /**
+        * Returns the length of the common prefix between s1 and s2.
+        */
+       public static int prefixLength(char[] s1, char[] s2) {
+               int len = 0;
+               int max = Math.min(s1.length, s2.length);
+               for (int i = 0; i < max && s1[i] == s2[i]; ++i)
+                       ++len;
+               return len;
+       }
+
+       /**
+        * Returns the length of the common prefix between s1 and s2.
+        */
+       public static int prefixLength(String s1, String s2) {
+               int len = 0;
+               int max = Math.min(s1.length(), s2.length());
+               for (int i = 0; i < max && s1.charAt(i) == s2.charAt(i); ++i)
+                       ++len;
+               return len;
+       }
+
+       private static void quickSort(char[][] list, int left, int right) {
+               int original_left = left;
+               int original_right = right;
+               char[] mid = list[(left + right) / 2];
+               do {
+                       while (compare(list[left], mid) < 0) {
+                               left++;
+                       }
+                       while (compare(mid, list[right]) < 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               char[] tmp = list[left];
+                               list[left] = list[right];
+                               list[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(list, original_left, right);
+               }
+               if (left < original_right) {
+                       quickSort(list, left, original_right);
+               }
+       }
+
+       /**
+        * Sort the comparable objects in the given collection.
+        */
+       private static void quickSort(Comparable[] sortedCollection, int left,
+                       int right) {
+               int original_left = left;
+               int original_right = right;
+               Comparable mid = sortedCollection[(left + right) / 2];
+               do {
+                       while (sortedCollection[left].compareTo(mid) < 0) {
+                               left++;
+                       }
+                       while (mid.compareTo(sortedCollection[right]) < 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               Comparable tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(sortedCollection, original_left, right);
+               }
+               if (left < original_right) {
+                       quickSort(sortedCollection, left, original_right);
+               }
+       }
+
+       private static void quickSort(int[] list, int left, int right) {
+               int original_left = left;
+               int original_right = right;
+               int mid = list[(left + right) / 2];
+               do {
+                       while (list[left] < mid) {
+                               left++;
+                       }
+                       while (mid < list[right]) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               int tmp = list[left];
+                               list[left] = list[right];
+                               list[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(list, original_left, right);
+               }
+               if (left < original_right) {
+                       quickSort(list, left, original_right);
+               }
+       }
+
+       /**
+        * Sort the objects in the given collection using the given comparer.
+        */
+       private static void quickSort(Object[] sortedCollection, int left,
+                       int right, Comparer comparer) {
+               int original_left = left;
+               int original_right = right;
+               Object mid = sortedCollection[(left + right) / 2];
+               do {
+                       while (comparer.compare(sortedCollection[left], mid) < 0) {
+                               left++;
+                       }
+                       while (comparer.compare(mid, sortedCollection[right]) < 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               Object tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(sortedCollection, original_left, right, comparer);
+               }
+               if (left < original_right) {
+                       quickSort(sortedCollection, left, original_right, comparer);
+               }
+       }
+
+       /**
+        * Sort the objects in the given collection using the given sort order.
+        */
+       private static void quickSort(Object[] sortedCollection, int left,
+                       int right, int[] sortOrder) {
+               int original_left = left;
+               int original_right = right;
+               int mid = sortOrder[(left + right) / 2];
+               do {
+                       while (sortOrder[left] < mid) {
+                               left++;
+                       }
+                       while (mid < sortOrder[right]) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               Object tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               int tmp2 = sortOrder[left];
+                               sortOrder[left] = sortOrder[right];
+                               sortOrder[right] = tmp2;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(sortedCollection, original_left, right, sortOrder);
+               }
+               if (left < original_right) {
+                       quickSort(sortedCollection, left, original_right, sortOrder);
+               }
+       }
+
+       /**
+        * Sort the strings in the given collection.
+        */
+       private static void quickSort(String[] sortedCollection, int left, int right) {
+               int original_left = left;
+               int original_right = right;
+               String mid = sortedCollection[(left + right) / 2];
+               do {
+                       while (sortedCollection[left].compareTo(mid) < 0) {
+                               left++;
+                       }
+                       while (mid.compareTo(sortedCollection[right]) < 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               String tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSort(sortedCollection, original_left, right);
+               }
+               if (left < original_right) {
+                       quickSort(sortedCollection, left, original_right);
+               }
+       }
+
+       /**
+        * Sort the strings in the given collection in reverse alphabetical order.
+        */
+       private static void quickSortReverse(String[] sortedCollection, int left,
+                       int right) {
+               int original_left = left;
+               int original_right = right;
+               String mid = sortedCollection[(left + right) / 2];
+               do {
+                       while (sortedCollection[left].compareTo(mid) > 0) {
+                               left++;
+                       }
+                       while (mid.compareTo(sortedCollection[right]) > 0) {
+                               right--;
+                       }
+                       if (left <= right) {
+                               String tmp = sortedCollection[left];
+                               sortedCollection[left] = sortedCollection[right];
+                               sortedCollection[right] = tmp;
+                               left++;
+                               right--;
+                       }
+               } while (left <= right);
+               if (original_left < right) {
+                       quickSortReverse(sortedCollection, original_left, right);
+               }
+               if (left < original_right) {
+                       quickSortReverse(sortedCollection, left, original_right);
+               }
+       }
+
+       /**
+        * Reads in a string from the specified data input stream. The string has
+        * been encoded using a modified UTF-8 format.
+        * <p>
+        * The first two bytes are read as if by <code>readUnsignedShort</code>.
+        * This value gives the number of following bytes that are in the encoded
+        * string, not the length of the resulting string. The following bytes are
+        * then interpreted as bytes encoding characters in the UTF-8 format and are
+        * converted into characters.
+        * <p>
+        * This method blocks until all the bytes are read, the end of the stream is
+        * detected, or an exception is thrown.
+        * 
+        * @param in
+        *            a data input stream.
+        * @return a Unicode string.
+        * @exception EOFException
+        *                if the input stream reaches the end before all the bytes.
+        * @exception IOException
+        *                if an I/O error occurs.
+        * @exception UTFDataFormatException
+        *                if the bytes do not represent a valid UTF-8 encoding of a
+        *                Unicode string.
+        * @see java.io.DataInputStream#readUnsignedShort()
+        */
+       public final static char[] readUTF(DataInput in) throws IOException {
+               int utflen = in.readUnsignedShort();
+               char str[] = new char[utflen];
+               int count = 0;
+               int strlen = 0;
+               while (count < utflen) {
+                       int c = in.readUnsignedByte();
+                       int char2, char3;
+                       switch (c >> 4) {
+                       case 0:
+                       case 1:
+                       case 2:
+                       case 3:
+                       case 4:
+                       case 5:
+                       case 6:
+                       case 7:
+                               // 0xxxxxxx
+                               count++;
+                               str[strlen++] = (char) c;
+                               break;
+                       case 12:
+                       case 13:
+                               // 110x xxxx 10xx xxxx
+                               count += 2;
+                               if (count > utflen)
+                                       throw new UTFDataFormatException();
+                               char2 = in.readUnsignedByte();
+                               if ((char2 & 0xC0) != 0x80)
+                                       throw new UTFDataFormatException();
+                               str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+                               break;
+                       case 14:
+                               // 1110 xxxx 10xx xxxx 10xx xxxx
+                               count += 3;
+                               if (count > utflen)
+                                       throw new UTFDataFormatException();
+                               char2 = in.readUnsignedByte();
+                               char3 = in.readUnsignedByte();
+                               if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+                                       throw new UTFDataFormatException();
+                               str[strlen++] = (char) (((c & 0x0F) << 12)
+                                               | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+                               break;
+                       default:
+                               // 10xx xxxx, 1111 xxxx
+                               throw new UTFDataFormatException();
+                       }
+               }
+               if (strlen < utflen) {
+                       System.arraycopy(str, 0, str = new char[strlen], 0, strlen);
+               }
+               return str;
+       }
+
+       /**
+        * Creates a NLS catalog for the given locale.
+        */
+       public static void relocalize() {
+               try {
+                       bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
+               } catch (MissingResourceException e) {
+                       System.out
+                                       .println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
+                       throw e;
+               }
+       }
+
+       public static void sort(char[][] list) {
+               if (list.length > 1)
+                       quickSort(list, 0, list.length - 1);
+       }
+
+       /**
+        * Sorts an array of Comparable objects in place.
+        */
+       public static void sort(Comparable[] objects) {
+               if (objects.length > 1)
+                       quickSort(objects, 0, objects.length - 1);
+       }
+
+       public static void sort(int[] list) {
+               if (list.length > 1)
+                       quickSort(list, 0, list.length - 1);
+       }
+
+       /**
+        * Sorts an array of objects in place. The given comparer compares pairs of
+        * items.
+        */
+       public static void sort(Object[] objects, Comparer comparer) {
+               if (objects.length > 1)
+                       quickSort(objects, 0, objects.length - 1, comparer);
+       }
+
+       /**
+        * Sorts an array of objects in place, using the sort order given for each
+        * item.
+        */
+       public static void sort(Object[] objects, int[] sortOrder) {
+               if (objects.length > 1)
+                       quickSort(objects, 0, objects.length - 1, sortOrder);
+       }
+
+       /**
+        * Sorts an array of strings in place using quicksort.
+        */
+       public static void sort(String[] strings) {
+               if (strings.length > 1)
+                       quickSort(strings, 0, strings.length - 1);
+       }
+
+       /**
+        * Sorts an array of Comparable objects, returning a new array with the
+        * sorted items. The original array is left untouched.
+        */
+       public static Comparable[] sortCopy(Comparable[] objects) {
+               int len = objects.length;
+               Comparable[] copy = new Comparable[len];
+               System.arraycopy(objects, 0, copy, 0, len);
+               sort(copy);
+               return copy;
+       }
+
+       /**
+        * Sorts an array of Strings, returning a new array with the sorted items.
+        * The original array is left untouched.
+        */
+       public static Object[] sortCopy(Object[] objects, Comparer comparer) {
+               int len = objects.length;
+               Object[] copy = new Object[len];
+               System.arraycopy(objects, 0, copy, 0, len);
+               sort(copy, comparer);
+               return copy;
+       }
+
+       /**
+        * Sorts an array of Strings, returning a new array with the sorted items.
+        * The original array is left untouched.
+        */
+       public static String[] sortCopy(String[] objects) {
+               int len = objects.length;
+               String[] copy = new String[len];
+               System.arraycopy(objects, 0, copy, 0, len);
+               sort(copy);
+               return copy;
+       }
+
+       /**
+        * Sorts an array of strings in place using quicksort in reverse
+        * alphabetical order.
+        */
+       public static void sortReverseOrder(String[] strings) {
+               if (strings.length > 1)
+                       quickSortReverse(strings, 0, strings.length - 1);
+       }
+
+       /**
+        * Converts a String[] to char[][].
+        */
+       public static char[][] toCharArrays(String[] a) {
+               int len = a.length;
+               char[][] result = new char[len][];
+               for (int i = 0; i < len; ++i) {
+                       result[i] = toChars(a[i]);
+               }
+               return result;
+       }
+
+       /**
+        * Converts a String to char[].
+        */
+       public static char[] toChars(String s) {
+               int len = s.length();
+               char[] chars = new char[len];
+               s.getChars(0, len, chars, 0);
+               return chars;
+       }
+
+       /**
+        * Converts a String to char[][], where segments are separate by '.'.
+        */
+       public static char[][] toCompoundChars(String s) {
+               int len = s.length();
+               if (len == 0) {
+                       return CharOperation.NO_CHAR_CHAR;
+               }
+               int segCount = 1;
+               for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
+                       ++segCount;
+               }
+               char[][] segs = new char[segCount][];
+               int start = 0;
+               for (int i = 0; i < segCount; ++i) {
+                       int dot = s.indexOf('.', start);
+                       int end = (dot == -1 ? s.length() : dot);
+                       segs[i] = new char[end - start];
+                       s.getChars(start, end, segs[i], 0);
+                       start = end + 1;
+               }
+               return segs;
+       }
+
+       /**
+        * Converts a char[] to String.
+        */
+       public static String toString(char[] c) {
+               return new String(c);
+       }
+
+       /**
+        * Converts a char[][] to String, where segments are separated by '.'.
+        */
+       public static String toString(char[][] c) {
+               StringBuffer sb = new StringBuffer();
+               for (int i = 0, max = c.length; i < max; ++i) {
+                       if (i != 0)
+                               sb.append('.');
+                       sb.append(c[i]);
+               }
+               return sb.toString();
+       }
+
+       /**
+        * Converts a char[][] and a char[] to String, where segments are separated
+        * by '.'.
+        */
+       public static String toString(char[][] c, char[] d) {
+               if (c == null)
+                       return new String(d);
+               StringBuffer sb = new StringBuffer();
+               for (int i = 0, max = c.length; i < max; ++i) {
+                       sb.append(c[i]);
+                       sb.append('.');
+               }
+               sb.append(d);
+               return sb.toString();
+       }
+
+       /*
+        * Returns the unresolved type parameter signatures of the given method e.g.
+        * {"QString;", "[int", "[[Qjava.util.Vector;"}
+        */
+       // public static String[] typeParameterSignatures(AbstractMethodDeclaration
+       // method) {
+       // Argument[] args = method.arguments;
+       // if (args != null) {
+       // int length = args.length;
+       // String[] signatures = new String[length];
+       // for (int i = 0; i < args.length; i++) {
+       // Argument arg = args[i];
+       // signatures[i] = typeSignature(arg.type);
+       // }
+       // return signatures;
+       // }
+       // return new String[0];
+       // }
+       /*
+        * Returns the unresolved type signature of the given type reference, e.g.
+        * "QString;", "[int", "[[Qjava.util.Vector;"
+        */
+       // public static String typeSignature(TypeReference type) {
+       // char[][] compoundName = type.getTypeName();
+       // char[] typeName =CharOperation.concatWith(compoundName, '.');
+       // String signature = Signature.createTypeSignature(typeName, false/*don't
+       // resolve*/);
+       // int dimensions = type.dimensions();
+       // if (dimensions > 0) {
+       // signature = Signature.createArraySignature(signature, dimensions);
+       // }
+       // return signature;
+       // }
+       /*
+        * Returns the unresolved type signature of the given type reference, e.g.
+        * "QString;", "[int", "[[Qjava.util.Vector;"
         */
        public static String typeSignature(TypeReference type) {
                char[][] compoundName = type.getTypeName();
-               char[] typeName =CharOperation.concatWith(compoundName, '.');
-               String signature = Signature.createTypeSignature(typeName, false/*don't resolve*/);
+               char[] typeName = CharOperation.concatWith(compoundName, '.');
+               String signature = Signature
+                               .createTypeSignature(typeName, false/* don't resolve */);
                int dimensions = type.dimensions();
                if (dimensions > 0) {
-                       signature =  Signature.createArraySignature(signature, dimensions);
+                       signature = Signature.createArraySignature(signature, dimensions);
                }
                return signature;
        }
-  /**
-   * Asserts that the given method signature is valid.
-   */
-  public static void validateMethodSignature(String sig) {
-    Assert.isTrue(isValidMethodSignature(sig));
-  }
-
-  /**
-   * Asserts that the given type signature is valid.
-   */
-  public static void validateTypeSignature(String sig, boolean allowVoid) {
-    Assert.isTrue(isValidTypeSignature(sig, allowVoid));
-  }
-
-  public static void verbose(String log) {
-    verbose(log, System.out);
-  }
-
-  public static synchronized void verbose(String log, PrintStream printStream) {
-    int start = 0;
-    do {
-      int end = log.indexOf('\n', start);
-      printStream.print(Thread.currentThread());
-      printStream.print(" "); //$NON-NLS-1$
-      printStream.print(log.substring(start, end == -1 ? log.length() : end + 1));
-      start = end + 1;
-    } while (start != 0);
-    printStream.println();
-  }
-
-  /**
-   * Writes a string to the given output stream using UTF-8 encoding in a machine-independent manner.
-   * <p>
-   * First, two bytes are written to the output stream as if by the <code>writeShort</code> method giving the number of bytes to
-   * follow. This value is the number of bytes actually written out, not the length of the string. Following the length, each
-   * character of the string is output, in sequence, using the UTF-8 encoding for the character.
-   * 
-   * @param str
-   *          a string to be written.
-   * @return the number of bytes written to the stream.
-   * @exception IOException
-   *              if an I/O error occurs.
-   * @since JDK1.0
-   */
-  public static int writeUTF(OutputStream out, char[] str) throws IOException {
-    int strlen = str.length;
-    int utflen = 0;
-    for (int i = 0; i < strlen; i++) {
-      int c = str[i];
-      if ((c >= 0x0001) && (c <= 0x007F)) {
-        utflen++;
-      } else if (c > 0x07FF) {
-        utflen += 3;
-      } else {
-        utflen += 2;
-      }
-    }
-    if (utflen > 65535)
-      throw new UTFDataFormatException();
-    out.write((utflen >>> 8) & 0xFF);
-    out.write((utflen >>> 0) & 0xFF);
-    if (strlen == utflen) {
-      for (int i = 0; i < strlen; i++)
-        out.write(str[i]);
-    } else {
-      for (int i = 0; i < strlen; i++) {
-        int c = str[i];
-        if ((c >= 0x0001) && (c <= 0x007F)) {
-          out.write(c);
-        } else if (c > 0x07FF) {
-          out.write(0xE0 | ((c >> 12) & 0x0F));
-          out.write(0x80 | ((c >> 6) & 0x3F));
-          out.write(0x80 | ((c >> 0) & 0x3F));
-        } else {
-          out.write(0xC0 | ((c >> 6) & 0x1F));
-          out.write(0x80 | ((c >> 0) & 0x3F));
-        }
-      }
-    }
-    return utflen + 2; // the number of bytes written to the stream
-  }
+
+       /**
+        * Asserts that the given method signature is valid.
+        */
+       public static void validateMethodSignature(String sig) {
+               Assert.isTrue(isValidMethodSignature(sig));
+       }
+
+       /**
+        * Asserts that the given type signature is valid.
+        */
+       public static void validateTypeSignature(String sig, boolean allowVoid) {
+               Assert.isTrue(isValidTypeSignature(sig, allowVoid));
+       }
+
+       public static void verbose(String log) {
+               verbose(log, System.out);
+       }
+
+       public static synchronized void verbose(String log, PrintStream printStream) {
+               int start = 0;
+               do {
+                       int end = log.indexOf('\n', start);
+                       printStream.print(Thread.currentThread());
+                       printStream.print(" "); //$NON-NLS-1$
+                       printStream.print(log.substring(start, end == -1 ? log.length()
+                                       : end + 1));
+                       start = end + 1;
+               } while (start != 0);
+               printStream.println();
+       }
+
+       /**
+        * Writes a string to the given output stream using UTF-8 encoding in a
+        * machine-independent manner.
+        * <p>
+        * First, two bytes are written to the output stream as if by the
+        * <code>writeShort</code> method giving the number of bytes to follow.
+        * This value is the number of bytes actually written out, not the length of
+        * the string. Following the length, each character of the string is output,
+        * in sequence, using the UTF-8 encoding for the character.
+        * 
+        * @param str
+        *            a string to be written.
+        * @return the number of bytes written to the stream.
+        * @exception IOException
+        *                if an I/O error occurs.
+        * @since JDK1.0
+        */
+       public static int writeUTF(OutputStream out, char[] str) throws IOException {
+               int strlen = str.length;
+               int utflen = 0;
+               for (int i = 0; i < strlen; i++) {
+                       int c = str[i];
+                       if ((c >= 0x0001) && (c <= 0x007F)) {
+                               utflen++;
+                       } else if (c > 0x07FF) {
+                               utflen += 3;
+                       } else {
+                               utflen += 2;
+                       }
+               }
+               if (utflen > 65535)
+                       throw new UTFDataFormatException();
+               out.write((utflen >>> 8) & 0xFF);
+               out.write((utflen >>> 0) & 0xFF);
+               if (strlen == utflen) {
+                       for (int i = 0; i < strlen; i++)
+                               out.write(str[i]);
+               } else {
+                       for (int i = 0; i < strlen; i++) {
+                               int c = str[i];
+                               if ((c >= 0x0001) && (c <= 0x007F)) {
+                                       out.write(c);
+                               } else if (c > 0x07FF) {
+                                       out.write(0xE0 | ((c >> 12) & 0x0F));
+                                       out.write(0x80 | ((c >> 6) & 0x3F));
+                                       out.write(0x80 | ((c >> 0) & 0x3F));
+                               } else {
+                                       out.write(0xC0 | ((c >> 6) & 0x1F));
+                                       out.write(0x80 | ((c >> 0) & 0x3F));
+                               }
+                       }
+               }
+               return utflen + 2; // the number of bytes written to the stream
+       }
 }
\ No newline at end of file