Refactory: remove unused classes, imports, fields and methods.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / util / Util.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.util;
12
13 import java.io.BufferedInputStream;
14 //import java.io.DataInput;
15 //import java.io.EOFException;
16 import java.io.IOException;
17 import java.io.InputStream;
18 //import java.io.OutputStream;
19 import java.io.PrintStream;
20 //import java.io.UTFDataFormatException;
21 import java.util.Locale;
22 import java.util.MissingResourceException;
23 import java.util.ResourceBundle;
24 //import java.util.StringTokenizer;
25
26 import net.sourceforge.phpdt.core.IJavaElement;
27 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
28 import net.sourceforge.phpdt.core.IPackageFragment;
29 import net.sourceforge.phpdt.core.JavaCore;
30 import net.sourceforge.phpdt.core.JavaModelException;
31 import net.sourceforge.phpdt.core.Signature;
32 import net.sourceforge.phpdt.core.compiler.CharOperation;
33 //import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
34 //incastrix
35 //import net.sourceforge.phpdt.internal.corext.Assert;
36 //import org.eclipse.core.runtime.Assert;
37 //import net.sourceforge.phpdt.internal.core.PackageFragmentRoot;
38 import net.sourceforge.phpdt.internal.core.util.PHPFileUtil;
39
40 import org.eclipse.core.resources.IFile;
41 //import org.eclipse.core.resources.IFolder;
42 import org.eclipse.core.resources.IResource;
43 import org.eclipse.core.runtime.CoreException;
44 import org.eclipse.core.runtime.IPath;
45 import org.eclipse.core.runtime.IStatus;
46 import org.eclipse.core.runtime.Status;
47 //import org.eclipse.jface.text.BadLocationException;
48 //import org.eclipse.text.edits.MalformedTreeException;
49 //import org.eclipse.text.edits.TextEdit;
50
51 /**
52  * Provides convenient utility methods to other types in this package.
53  */
54 public class Util {
55
56         public interface Comparable {
57                 /**
58                  * Returns 0 if this and c are equal, >0 if this is greater than c, or
59                  * <0 if this is less than c.
60                  */
61                 int compareTo(Comparable c);
62         }
63
64         public interface Comparer {
65                 /**
66                  * Returns 0 if a and b are equal, >0 if a is greater than b, or <0 if a
67                  * is less than b.
68                  */
69                 int compare(Object a, Object b);
70         }
71
72         private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
73
74         /* Bundle containing messages */
75         protected static ResourceBundle bundle;
76
77         private final static String bundleName = "net.sourceforge.phpdt.internal.core.util.messages"; //$NON-NLS-1$
78
79         private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
80
81         private static final String EMPTY_ARGUMENT = "   "; //$NON-NLS-1$
82
83         public static final String[] fgEmptyStringArray = new String[0];
84
85         private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
86
87         static {
88                 relocalize();
89         }
90
91         private Util() {
92                 // cannot be instantiated
93         }
94
95         /**
96          * Lookup the message with the given ID in this catalog
97          */
98         public static String bind(String id) {
99                 return bind(id, (String[]) null);
100         }
101
102         /**
103          * Lookup the message with the given ID in this catalog and bind its
104          * substitution locations with the given string.
105          */
106         public static String bind(String id, String binding) {
107                 return bind(id, new String[] { binding });
108         }
109
110         /**
111          * Lookup the message with the given ID in this catalog and bind its
112          * substitution locations with the given strings.
113          */
114         public static String bind(String id, String binding1, String binding2) {
115                 return bind(id, new String[] { binding1, binding2 });
116         }
117
118         /**
119          * Lookup the message with the given ID in this catalog and bind its
120          * substitution locations with the given string values.
121          */
122         public static String bind(String id, String[] bindings) {
123                 if (id == null)
124                         return "No message available"; //$NON-NLS-1$
125                 String message = null;
126                 try {
127                         message = bundle.getString(id);
128                 } catch (MissingResourceException e) {
129                         // If we got an exception looking for the message, fail gracefully
130                         // by just returning
131                         // the id we were looking for. In most cases this is
132                         // semi-informative so is not too bad.
133                         return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
134                 }
135                 // for compatibility with MessageFormat which eliminates double quotes
136                 // in original message
137                 char[] messageWithNoDoubleQuotes = CharOperation.replace(message
138                                 .toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
139
140                 if (bindings == null)
141                         return new String(messageWithNoDoubleQuotes);
142
143                 int length = messageWithNoDoubleQuotes.length;
144                 int start = 0;
145                 int end = length;
146                 StringBuffer output = null;
147                 while (true) {
148                         if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes,
149                                         start)) > -1) {
150                                 if (output == null)
151                                         output = new StringBuffer(length + bindings.length * 20);
152                                 output.append(messageWithNoDoubleQuotes, start, end - start);
153                                 if ((start = CharOperation.indexOf('}',
154                                                 messageWithNoDoubleQuotes, end + 1)) > -1) {
155                                         int index = -1;
156                                         String argId = new String(messageWithNoDoubleQuotes,
157                                                         end + 1, start - end - 1);
158                                         try {
159                                                 index = Integer.parseInt(argId);
160                                                 output.append(bindings[index]);
161                                         } catch (NumberFormatException nfe) { // could be nested
162                                                                                                                         // message ID
163                                                                                                                         // {compiler.name}
164                                                 boolean done = false;
165                                                 if (!id.equals(argId)) {
166                                                         String argMessage = null;
167                                                         try {
168                                                                 argMessage = bundle.getString(argId);
169                                                                 output.append(argMessage);
170                                                                 done = true;
171                                                         } catch (MissingResourceException e) {
172                                                                 // unable to bind argument, ignore (will leave
173                                                                 // argument in)
174                                                         }
175                                                 }
176                                                 if (!done)
177                                                         output.append(messageWithNoDoubleQuotes, end + 1,
178                                                                         start - end);
179                                         } catch (ArrayIndexOutOfBoundsException e) {
180                                                 output
181                                                                 .append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
182                                         }
183                                         start++;
184                                 } else {
185                                         output.append(messageWithNoDoubleQuotes, end, length);
186                                         break;
187                                 }
188                         } else {
189                                 if (output == null)
190                                         return new String(messageWithNoDoubleQuotes);
191                                 output.append(messageWithNoDoubleQuotes, start, length - start);
192                                 break;
193                         }
194                 }
195                 return output.toString();
196         }
197
198         /**
199          * Checks the type signature in String sig, starting at start and ending
200          * before end (end is not included). Returns the index of the character
201          * immediately after the signature if valid, or -1 if not valid.
202          */
203         private static int checkTypeSignature(String sig, int start, int end,
204                         boolean allowVoid) {
205                 if (start >= end)
206                         return -1;
207                 int i = start;
208                 char c = sig.charAt(i++);
209                 int nestingDepth = 0;
210                 while (c == '[') {
211                         ++nestingDepth;
212                         if (i >= end)
213                                 return -1;
214                         c = sig.charAt(i++);
215                 }
216                 switch (c) {
217                 case 'B':
218                 case 'C':
219                 case 'D':
220                 case 'F':
221                 case 'I':
222                 case 'J':
223                 case 'S':
224                 case 'Z':
225                         break;
226                 case 'V':
227                         if (!allowVoid)
228                                 return -1;
229                         // array of void is not allowed
230                         if (nestingDepth != 0)
231                                 return -1;
232                         break;
233                 case 'L':
234                         int semicolon = sig.indexOf(';', i);
235                         // Must have at least one character between L and ;
236                         if (semicolon <= i || semicolon >= end)
237                                 return -1;
238                         i = semicolon + 1;
239                         break;
240                 default:
241                         return -1;
242                 }
243                 return i;
244         }
245
246         /**
247          * Combines two hash codes to make a new one.
248          */
249         public static int combineHashCodes(int hashCode1, int hashCode2) {
250                 return hashCode1 * 17 + hashCode2;
251         }
252
253         /**
254          * Compares two byte arrays. Returns <0 if a byte in a is less than the
255          * corresponding byte in b, or if a is shorter, or if a is null. Returns >0
256          * if a byte in a is greater than the corresponding byte in b, or if a is
257          * longer, or if b is null. Returns 0 if they are equal or both null.
258          */
259         public static int compare(byte[] a, byte[] b) {
260                 if (a == b)
261                         return 0;
262                 if (a == null)
263                         return -1;
264                 if (b == null)
265                         return 1;
266                 int len = Math.min(a.length, b.length);
267                 for (int i = 0; i < len; ++i) {
268                         int diff = a[i] - b[i];
269                         if (diff != 0)
270                                 return diff;
271                 }
272                 if (a.length > len)
273                         return 1;
274                 if (b.length > len)
275                         return -1;
276                 return 0;
277         }
278
279         /**
280          * Compares two strings lexicographically. The comparison is based on the
281          * Unicode value of each character in the strings.
282          * 
283          * @return the value <code>0</code> if the str1 is equal to str2; a value
284          *         less than <code>0</code> if str1 is lexicographically less than
285          *         str2; and a value greater than <code>0</code> if str1 is
286          *         lexicographically greater than str2.
287          */
288         public static int compare(char[] str1, char[] str2) {
289                 int len1 = str1.length;
290                 int len2 = str2.length;
291                 int n = Math.min(len1, len2);
292                 int i = 0;
293                 while (n-- != 0) {
294                         char c1 = str1[i];
295                         char c2 = str2[i++];
296                         if (c1 != c2) {
297                                 return c1 - c2;
298                         }
299                 }
300                 return len1 - len2;
301         }
302
303         /**
304          * Concatenate two strings with a char in between.
305          * 
306          * @see #concat(String, String)
307          */
308 //      public static String concat(String s1, char c, String s2) {
309 //              if (s1 == null)
310 //                      s1 = "null"; //$NON-NLS-1$
311 //              if (s2 == null)
312 //                      s2 = "null"; //$NON-NLS-1$
313 //              int l1 = s1.length();
314 //              int l2 = s2.length();
315 //              char[] buf = new char[l1 + 1 + l2];
316 //              s1.getChars(0, l1, buf, 0);
317 //              buf[l1] = c;
318 //              s2.getChars(0, l2, buf, l1 + 1);
319 //              return new String(buf);
320 //      }
321
322         /**
323          * Concatenate two strings. Much faster than using +, which: - creates a
324          * StringBuffer, - which is synchronized, - of default size, so the
325          * resulting char array is often larger than needed. This implementation
326          * creates an extra char array, since the String constructor copies its
327          * argument, but there's no way around this.
328          */
329         public static String concat(String s1, String s2) {
330                 if (s1 == null)
331                         s1 = "null"; //$NON-NLS-1$
332                 if (s2 == null)
333                         s2 = "null"; //$NON-NLS-1$
334                 int l1 = s1.length();
335                 int l2 = s2.length();
336                 char[] buf = new char[l1 + l2];
337                 s1.getChars(0, l1, buf, 0);
338                 s2.getChars(0, l2, buf, l1);
339                 return new String(buf);
340         }
341
342         /**
343          * Concatenate three strings.
344          * 
345          * @see #concat(String, String)
346          */
347 //      public static String concat(String s1, String s2, String s3) {
348 //              if (s1 == null)
349 //                      s1 = "null"; //$NON-NLS-1$
350 //              if (s2 == null)
351 //                      s2 = "null"; //$NON-NLS-1$
352 //              if (s3 == null)
353 //                      s3 = "null"; //$NON-NLS-1$
354 //              int l1 = s1.length();
355 //              int l2 = s2.length();
356 //              int l3 = s3.length();
357 //              char[] buf = new char[l1 + l2 + l3];
358 //              s1.getChars(0, l1, buf, 0);
359 //              s2.getChars(0, l2, buf, l1);
360 //              s3.getChars(0, l3, buf, l1 + l2);
361 //              return new String(buf);
362 //      }
363
364         /**
365          * Converts a type signature from the IBinaryType representation to the DC
366          * representation.
367          */
368         public static String convertTypeSignature(char[] sig) {
369                 return new String(sig).replace('/', '.');
370         }
371
372         /**
373          * Apply the given edit on the given string and return the updated string.
374          * Return the given string if anything wrong happen while applying the edit.
375          * 
376          * @param original
377          *            the given string
378          * @param edit
379          *            the given edit
380          * 
381          * @return the updated string
382          */
383 //      public final static String editedString(String original, TextEdit edit) {
384 //              if (edit == null) {
385 //                      return original;
386 //              }
387 //              SimpleDocument document = new SimpleDocument(original);
388 //              try {
389 //                      edit.apply(document, TextEdit.NONE);
390 //                      return document.get();
391 //              } catch (MalformedTreeException e) {
392 //                      e.printStackTrace();
393 //              } catch (BadLocationException e) {
394 //                      e.printStackTrace();
395 //              }
396 //              return original;
397 //      }
398
399         /**
400          * Returns true iff str.toLowerCase().endsWith(end.toLowerCase())
401          * implementation is not creating extra strings.
402          */
403 //      public final static boolean endsWithIgnoreCase(String str, String end) {
404 //
405 //              int strLength = str == null ? 0 : str.length();
406 //              int endLength = end == null ? 0 : end.length();
407 //
408 //              // return false if the string is smaller than the end.
409 //              if (endLength > strLength)
410 //                      return false;
411 //
412 //              // return false if any character of the end are
413 //              // not the same in lower case.
414 //              for (int i = 1; i <= endLength; i++) {
415 //                      if (Character.toLowerCase(end.charAt(endLength - i)) != Character
416 //                                      .toLowerCase(str.charAt(strLength - i)))
417 //                              return false;
418 //              }
419 //
420 //              return true;
421 //      }
422
423         /**
424          * Compares two arrays using equals() on the elements. Either or both arrays
425          * may be null. Returns true if both are null. Returns false if only one is
426          * null. If both are arrays, returns true iff they have the same length and
427          * all elements are equal.
428          */
429 //      public static boolean equalArraysOrNull(int[] a, int[] b) {
430 //              if (a == b)
431 //                      return true;
432 //              if (a == null || b == null)
433 //                      return false;
434 //              int len = a.length;
435 //              if (len != b.length)
436 //                      return false;
437 //              for (int i = 0; i < len; ++i) {
438 //                      if (a[i] != b[i])
439 //                              return false;
440 //              }
441 //              return true;
442 //      }
443
444         /**
445          * Compares two arrays using equals() on the elements. Either or both arrays
446          * may be null. Returns true if both are null. Returns false if only one is
447          * null. If both are arrays, returns true iff they have the same length and
448          * all elements compare true with equals.
449          */
450         public static boolean equalArraysOrNull(Object[] a, Object[] b) {
451                 if (a == b)
452                         return true;
453                 if (a == null || b == null)
454                         return false;
455
456                 int len = a.length;
457                 if (len != b.length)
458                         return false;
459                 for (int i = 0; i < len; ++i) {
460                         if (a[i] == null) {
461                                 if (b[i] != null)
462                                         return false;
463                         } else {
464                                 if (!a[i].equals(b[i]))
465                                         return false;
466                         }
467                 }
468                 return true;
469         }
470
471         /**
472          * Compares two arrays using equals() on the elements. The arrays are first
473          * sorted. Either or both arrays may be null. Returns true if both are null.
474          * Returns false if only one is null. If both are arrays, returns true iff
475          * they have the same length and iff, after sorting both arrays, all
476          * elements compare true with equals. The original arrays are left
477          * untouched.
478          */
479 //      public static boolean equalArraysOrNullSortFirst(Comparable[] a,
480 //                      Comparable[] b) {
481 //              if (a == b)
482 //                      return true;
483 //              if (a == null || b == null)
484 //                      return false;
485 //              int len = a.length;
486 //              if (len != b.length)
487 //                      return false;
488 //              if (len >= 2) { // only need to sort if more than two items
489 //                      a = sortCopy(a);
490 //                      b = sortCopy(b);
491 //              }
492 //              for (int i = 0; i < len; ++i) {
493 //                      if (!a[i].equals(b[i]))
494 //                              return false;
495 //              }
496 //              return true;
497 //      }
498
499         /**
500          * Compares two String arrays using equals() on the elements. The arrays are
501          * first sorted. Either or both arrays may be null. Returns true if both are
502          * null. Returns false if only one is null. If both are arrays, returns true
503          * iff they have the same length and iff, after sorting both arrays, all
504          * elements compare true with equals. The original arrays are left
505          * untouched.
506          */
507 //      public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
508 //              if (a == b)
509 //                      return true;
510 //              if (a == null || b == null)
511 //                      return false;
512 //              int len = a.length;
513 //              if (len != b.length)
514 //                      return false;
515 //              if (len >= 2) { // only need to sort if more than two items
516 //                      a = sortCopy(a);
517 //                      b = sortCopy(b);
518 //              }
519 //              for (int i = 0; i < len; ++i) {
520 //                      if (!a[i].equals(b[i]))
521 //                              return false;
522 //              }
523 //              return true;
524 //      }
525
526         /**
527          * Compares two objects using equals(). Either or both array may be null.
528          * Returns true if both are null. Returns false if only one is null.
529          * Otherwise, return the result of comparing with equals().
530          */
531 //      public static boolean equalOrNull(Object a, Object b) {
532 //              if (a == b) {
533 //                      return true;
534 //              }
535 //              if (a == null || b == null) {
536 //                      return false;
537 //              }
538 //              return a.equals(b);
539 //      }
540
541         /**
542          * Given a qualified name, extract the last component. If the input is not
543          * qualified, the same string is answered.
544          */
545 //      public static String extractLastName(String qualifiedName) {
546 //              int i = qualifiedName.lastIndexOf('.');
547 //              if (i == -1)
548 //                      return qualifiedName;
549 //              return qualifiedName.substring(i + 1);
550 //      }
551
552         /**
553          * Extracts the parameter types from a method signature.
554          */
555 //      public static String[] extractParameterTypes(char[] sig) {
556 //              int count = getParameterCount(sig);
557 //              String[] result = new String[count];
558 //              if (count == 0)
559 //                      return result;
560 //              int i = CharOperation.indexOf('(', sig) + 1;
561 //              count = 0;
562 //              int len = sig.length;
563 //              int start = i;
564 //              for (;;) {
565 //                      if (i == len)
566 //                              break;
567 //                      char c = sig[i];
568 //                      if (c == ')')
569 //                              break;
570 //                      if (c == '[') {
571 //                              ++i;
572 //                      } else if (c == 'L') {
573 //                              i = CharOperation.indexOf(';', sig, i + 1) + 1;
574 //                              Assert.isTrue(i != 0);
575 //                              result[count++] = convertTypeSignature(CharOperation.subarray(
576 //                                              sig, start, i));
577 //                              start = i;
578 //                      } else {
579 //                              ++i;
580 //                              result[count++] = convertTypeSignature(CharOperation.subarray(
581 //                                              sig, start, i));
582 //                              start = i;
583 //                      }
584 //              }
585 //              return result;
586 //      }
587
588         /**
589          * Extracts the return type from a method signature.
590          */
591 //      public static String extractReturnType(String sig) {
592 //              int i = sig.lastIndexOf(')');
593 //              Assert.isTrue(i != -1);
594 //              return sig.substring(i + 1);
595 //      }
596
597 //      private static IFile findFirstClassFile(IFolder folder) {
598 //              try {
599 //                      IResource[] members = folder.members();
600 //                      for (int i = 0, max = members.length; i < max; i++) {
601 //                              IResource member = members[i];
602 //                              if (member.getType() == IResource.FOLDER) {
603 //                                      return findFirstClassFile((IFolder) member);
604 //                                      // } else if
605 //                                      // (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(member.getName()))
606 //                                      // {
607 //                                      // return (IFile) member;
608 //                              }
609 //                      }
610 //              } catch (CoreException e) {
611 //                      // ignore
612 //              }
613 //              return null;
614 //      }
615
616         /**
617          * Finds the first line separator used by the given text.
618          * 
619          * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"</code>,
620          *         or <code>null</code> if none found
621          */
622         public static String findLineSeparator(char[] text) {
623                 // find the first line separator
624                 int length = text.length;
625                 if (length > 0) {
626                         char nextChar = text[0];
627                         for (int i = 0; i < length; i++) {
628                                 char currentChar = nextChar;
629                                 nextChar = i < length - 1 ? text[i + 1] : ' ';
630                                 switch (currentChar) {
631                                 case '\n':
632                                         return "\n"; //$NON-NLS-1$
633                                 case '\r':
634                                         return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
635                                 }
636                         }
637                 }
638                 // not found
639                 return null;
640         }
641
642         // public static IClassFileAttribute getAttribute(IClassFileReader
643         // classFileReader, char[] attributeName) {
644         // IClassFileAttribute[] attributes = classFileReader.getAttributes();
645         // for (int i = 0, max = attributes.length; i < max; i++) {
646         // if (CharOperation.equals(attributes[i].getAttributeName(),
647         // attributeName)) {
648         // return attributes[i];
649         // }
650         // }
651         // return null;
652         // }
653         //      
654         // public static IClassFileAttribute getAttribute(ICodeAttribute
655         // codeAttribute, char[] attributeName) {
656         // IClassFileAttribute[] attributes = codeAttribute.getAttributes();
657         // for (int i = 0, max = attributes.length; i < max; i++) {
658         // if (CharOperation.equals(attributes[i].getAttributeName(),
659         // attributeName)) {
660         // return attributes[i];
661         // }
662         // }
663         // return null;
664         // }
665
666         // public static IClassFileAttribute getAttribute(IFieldInfo fieldInfo,
667         // char[] attributeName) {
668         // IClassFileAttribute[] attributes = fieldInfo.getAttributes();
669         // for (int i = 0, max = attributes.length; i < max; i++) {
670         // if (CharOperation.equals(attributes[i].getAttributeName(),
671         // attributeName)) {
672         // return attributes[i];
673         // }
674         // }
675         // return null;
676         // }
677         //
678         // public static IClassFileAttribute getAttribute(IMethodInfo methodInfo,
679         // char[] attributeName) {
680         // IClassFileAttribute[] attributes = methodInfo.getAttributes();
681         // for (int i = 0, max = attributes.length; i < max; i++) {
682         // if (CharOperation.equals(attributes[i].getAttributeName(),
683         // attributeName)) {
684         // return attributes[i];
685         // }
686         // }
687         // return null;
688         // }
689         /**
690          * Get the jdk level of this root. The value can be:
691          * <ul>
692          * <li>major < <16 + minor : see predefined constants on ClassFileConstants</li>
693          * <li><code>0</null> if the root is a source package fragment root or if a Java model exception occured</li>
694          * </ul>
695          * Returns the jdk level
696          */
697         // public static long getJdkLevel(Object targetLibrary) {
698         // try {
699         // ClassFileReader reader = null;
700         // if (targetLibrary instanceof IFolder) {
701         // IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only
702         // internal classfolders are allowed
703         // if (classFile != null) {
704         // byte[] bytes = Util.getResourceContentsAsByteArray(classFile);
705         // IPath location = classFile.getLocation();
706         // reader = new ClassFileReader(bytes, location == null ? null :
707         // location.toString().toCharArray());
708         // }
709         // } else {
710         // // root is a jar file or a zip file
711         // ZipFile jar = null;
712         // try {
713         // IPath path = null;
714         // if (targetLibrary instanceof IResource) {
715         // path = ((IResource)targetLibrary).getLocation();
716         // } else if (targetLibrary instanceof File){
717         // File f = (File) targetLibrary;
718         // if (!f.isDirectory()) {
719         // path = new Path(((File)targetLibrary).getPath());
720         // }
721         // }
722         // if (path != null) {
723         // jar = JavaModelManager.getJavaModelManager().getZipFile(path);
724         // for (Enumeration e= jar.entries(); e.hasMoreElements();) {
725         // ZipEntry member= (ZipEntry) e.nextElement();
726         // String entryName= member.getName();
727         // if
728         // (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(entryName))
729         // {
730         // reader = ClassFileReader.read(jar, entryName);
731         // break;
732         // }
733         // }
734         // }
735         // } catch (CoreException e) {
736         // // ignore
737         // } finally {
738         // JavaModelManager.getJavaModelManager().closeZipFile(jar);
739         // }
740         // }
741         // if (reader != null) {
742         // return reader.getVersion();
743         // }
744         // } catch(JavaModelException e) {
745         // // ignore
746         // } catch(ClassFormatException e) {
747         // // ignore
748         // } catch(IOException e) {
749         // // ignore
750         // }
751         // return 0;
752         // }
753         /**
754          * Returns the line separator used by the given buffer. Uses the given text
755          * if none found.
756          * 
757          * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"</code>
758          */
759         private static String getLineSeparator(char[] text, char[] buffer) {
760                 // search in this buffer's contents first
761                 String lineSeparator = findLineSeparator(buffer);
762                 if (lineSeparator == null) {
763                         // search in the given text
764                         lineSeparator = findLineSeparator(text);
765                         if (lineSeparator == null) {
766                                 // default to system line separator
767                                 return net.sourceforge.phpdt.internal.compiler.util.Util.LINE_SEPARATOR;
768                         }
769                 }
770                 return lineSeparator;
771         }
772
773         /**
774          * Returns the number of parameter types in a method signature.
775          */
776 //      public static int getParameterCount(char[] sig) {
777 //              int i = CharOperation.indexOf('(', sig) + 1;
778 //              Assert.isTrue(i != 0);
779 //              int count = 0;
780 //              int len = sig.length;
781 //              for (;;) {
782 //                      if (i == len)
783 //                              break;
784 //                      char c = sig[i];
785 //                      if (c == ')')
786 //                              break;
787 //                      if (c == '[') {
788 //                              ++i;
789 //                      } else if (c == 'L') {
790 //                              ++count;
791 //                              i = CharOperation.indexOf(';', sig, i + 1) + 1;
792 //                              Assert.isTrue(i != 0);
793 //                      } else {
794 //                              ++count;
795 //                              ++i;
796 //                      }
797 //              }
798 //              return count;
799 //      }
800
801         /**
802          * Put all the arguments in one String.
803          */
804         public static String getProblemArgumentsForMarker(String[] arguments) {
805                 StringBuffer args = new StringBuffer(10);
806
807                 args.append(arguments.length);
808                 args.append(':');
809
810                 for (int j = 0; j < arguments.length; j++) {
811                         if (j != 0)
812                                 args.append(ARGUMENTS_DELIMITER);
813
814                         if (arguments[j].length() == 0) {
815                                 args.append(EMPTY_ARGUMENT);
816                         } else {
817                                 args.append(arguments[j]);
818                         }
819                 }
820
821                 return args.toString();
822         }
823
824         /**
825          * Separate all the arguments of a String made by
826          * getProblemArgumentsForMarker
827          */
828 //      public static String[] getProblemArgumentsFromMarker(String argumentsString) {
829 //              if (argumentsString == null)
830 //                      return null;
831 //              int index = argumentsString.indexOf(':');
832 //              if (index == -1)
833 //                      return null;
834 //
835 //              int length = argumentsString.length();
836 //              int numberOfArg;
837 //              try {
838 //                      numberOfArg = Integer.parseInt(argumentsString.substring(0, index));
839 //              } catch (NumberFormatException e) {
840 //                      return null;
841 //              }
842 //              argumentsString = argumentsString.substring(index + 1, length);
843 //
844 //              String[] args = new String[length];
845 //              int count = 0;
846 //
847 //              StringTokenizer tokenizer = new StringTokenizer(argumentsString,
848 //                              ARGUMENTS_DELIMITER);
849 //              while (tokenizer.hasMoreTokens()) {
850 //                      String argument = tokenizer.nextToken();
851 //                      if (argument.equals(EMPTY_ARGUMENT))
852 //                              argument = ""; //$NON-NLS-1$
853 //                      args[count++] = argument;
854 //              }
855 //
856 //              if (count != numberOfArg)
857 //                      return null;
858 //
859 //              System.arraycopy(args, 0, args = new String[count], 0, count);
860 //              return args;
861 //      }
862
863         /**
864          * Returns the given file's contents as a byte array.
865          */
866         public static byte[] getResourceContentsAsByteArray(IFile file)
867                         throws JavaModelException {
868                 InputStream stream = null;
869                 try {
870                         stream = new BufferedInputStream(file.getContents(true));
871                 } catch (CoreException e) {
872                         throw new JavaModelException(e);
873                 }
874                 try {
875                         return net.sourceforge.phpdt.internal.compiler.util.Util
876                                         .getInputStreamAsByteArray(stream, -1);
877                 } catch (IOException e) {
878                         throw new JavaModelException(e,
879                                         IJavaModelStatusConstants.IO_EXCEPTION);
880                 } finally {
881                         try {
882                                 stream.close();
883                         } catch (IOException e) {
884                                 // ignore
885                         }
886                 }
887         }
888
889         /**
890          * Returns the given file's contents as a character array.
891          */
892         public static char[] getResourceContentsAsCharArray(IFile file)
893                         throws JavaModelException {
894                 // Get encoding from file
895                 String encoding = null;
896                 try {
897                         encoding = file.getCharset();
898                 } catch (CoreException ce) {
899                         // do not use any encoding
900                 }
901                 return getResourceContentsAsCharArray(file, encoding);
902         }
903
904         public static char[] getResourceContentsAsCharArray(IFile file,
905                         String encoding) throws JavaModelException {
906                 // Get resource contents
907                 InputStream stream = null;
908                 try {
909                         stream = new BufferedInputStream(file.getContents(true));
910                 } catch (CoreException e) {
911                         throw new JavaModelException(e,
912                                         IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
913                 }
914                 try {
915                         return net.sourceforge.phpdt.internal.compiler.util.Util
916                                         .getInputStreamAsCharArray(stream, -1, encoding);
917                 } catch (IOException e) {
918                         throw new JavaModelException(e,
919                                         IJavaModelStatusConstants.IO_EXCEPTION);
920                 } finally {
921                         try {
922                                 stream.close();
923                         } catch (IOException e) {
924                                 // ignore
925                         }
926                 }
927         }
928
929         /**
930          * Returns a trimmed version the simples names returned by Signature.
931          */
932         public static String[] getTrimmedSimpleNames(String name) {
933                 String[] result = Signature.getSimpleNames(name);
934                 if (result == null)
935                         return null;
936                 for (int i = 0, length = result.length; i < length; i++) {
937                         result[i] = result[i].trim();
938                 }
939                 return result;
940         }
941
942         /*
943          * Returns the index of the most specific argument paths which is strictly
944          * enclosing the path to check
945          */
946         public static int indexOfEnclosingPath(IPath checkedPath, IPath[] paths,
947                         int pathCount) {
948
949                 int bestMatch = -1, bestLength = -1;
950                 for (int i = 0; i < pathCount; i++) {
951                         if (paths[i].equals(checkedPath))
952                                 continue;
953                         if (paths[i].isPrefixOf(checkedPath)) {
954                                 int currentLength = paths[i].segmentCount();
955                                 if (currentLength > bestLength) {
956                                         bestLength = currentLength;
957                                         bestMatch = i;
958                                 }
959                         }
960                 }
961                 return bestMatch;
962         }
963
964         /*
965          * Returns the index of the first argument paths which is equal to the path
966          * to check
967          */
968         public static int indexOfMatchingPath(IPath checkedPath, IPath[] paths,
969                         int pathCount) {
970
971                 for (int i = 0; i < pathCount; i++) {
972                         if (paths[i].equals(checkedPath))
973                                 return i;
974                 }
975                 return -1;
976         }
977
978         /*
979          * Returns the index of the first argument paths which is strictly nested
980          * inside the path to check
981          */
982 //      public static int indexOfNestedPath(IPath checkedPath, IPath[] paths,
983 //                      int pathCount) {
984 //
985 //              for (int i = 0; i < pathCount; i++) {
986 //                      if (checkedPath.equals(paths[i]))
987 //                              continue;
988 //                      if (checkedPath.isPrefixOf(paths[i]))
989 //                              return i;
990 //              }
991 //              return -1;
992 //      }
993
994         /*
995          * Returns whether the given java element is exluded from its root's
996          * classpath. It doesn't check whether the root itself is on the classpath
997          * or not
998          */
999         public static final boolean isExcluded(IJavaElement element) {
1000                 int elementType = element.getElementType();
1001                 //PackageFragmentRoot root = null;
1002                 //IResource resource = null;
1003                 switch (elementType) {
1004                 case IJavaElement.JAVA_MODEL:
1005                 case IJavaElement.JAVA_PROJECT:
1006                 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
1007                         return false;
1008
1009                         // case IJavaElement.PACKAGE_FRAGMENT:
1010                         // PackageFragmentRoot root =
1011                         // (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
1012                         // IResource resource = element.getResource();
1013                         // return resource != null && isExcluded(resource,
1014                         // root.fullInclusionPatternChars(),
1015                         // root.fullExclusionPatternChars());
1016
1017                 case IJavaElement.COMPILATION_UNIT:
1018 //                      root = (PackageFragmentRoot) element
1019 //                                      .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
1020                         //resource = element.getResource();
1021                         // if (resource != null && isExcluded(resource,
1022                         // root.fullInclusionPatternChars(),
1023                         // root.fullExclusionPatternChars()))
1024                         // return true;
1025                         return isExcluded(element.getParent());
1026
1027                 default:
1028                         IJavaElement cu = element
1029                                         .getAncestor(IJavaElement.COMPILATION_UNIT);
1030                         return cu != null && isExcluded(cu);
1031                 }
1032         }
1033
1034         /*
1035          * Returns whether the given resource path matches one of the
1036          * inclusion/exclusion patterns. NOTE: should not be asked directly using
1037          * pkg root pathes
1038          * 
1039          * @see IClasspathEntry#getInclusionPatterns
1040          * @see IClasspathEntry#getExclusionPatterns
1041          */
1042         public final static boolean isExcluded(IPath resourcePath,
1043                         char[][] inclusionPatterns, char[][] exclusionPatterns,
1044                         boolean isFolderPath) {
1045                 if (inclusionPatterns == null && exclusionPatterns == null)
1046                         return false;
1047                 char[] path = resourcePath.toString().toCharArray();
1048
1049                 inclusionCheck: if (inclusionPatterns != null) {
1050                         for (int i = 0, length = inclusionPatterns.length; i < length; i++) {
1051                                 char[] pattern = inclusionPatterns[i];
1052                                 char[] folderPattern = pattern;
1053                                 if (isFolderPath) {
1054                                         int lastSlash = CharOperation.lastIndexOf('/', pattern);
1055                                         if (lastSlash != -1 && lastSlash != pattern.length - 1) { // trailing
1056                                                                                                                                                                 // slash
1057                                                                                                                                                                 // ->
1058                                                                                                                                                                 // adds
1059                                                                                                                                                                 // '**'
1060                                                                                                                                                                 // for
1061                                                                                                                                                                 // free
1062                                                                                                                                                                 // (see
1063                                                 // http://ant.apache.org/manual/dirtasks.html)
1064                                                 int star = CharOperation.indexOf('*', pattern,
1065                                                                 lastSlash);
1066                                                 if ((star == -1 || star >= pattern.length - 1 || pattern[star + 1] != '*')) {
1067                                                         folderPattern = CharOperation.subarray(pattern, 0,
1068                                                                         lastSlash);
1069                                                 }
1070                                         }
1071                                 }
1072                                 if (CharOperation.pathMatch(folderPattern, path, true, '/')) {
1073                                         break inclusionCheck;
1074                                 }
1075                         }
1076                         return true; // never included
1077                 }
1078                 if (isFolderPath) {
1079                         path = CharOperation.concat(path, new char[] { '*' }, '/');
1080                 }
1081                 exclusionCheck: if (exclusionPatterns != null) {
1082                         for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
1083                                 if (CharOperation.pathMatch(exclusionPatterns[i], path, true,
1084                                                 '/')) {
1085                                         return true;
1086                                 }
1087                         }
1088                 }
1089                 return false;
1090         }
1091
1092         public final static boolean isExcluded(IResource resource,
1093                         char[][] exclusionPatterns) {
1094                 IPath path = resource.getFullPath();
1095                 // ensure that folders are only excluded if all of their children are
1096                 // excluded
1097                 return isExcluded(path, null, exclusionPatterns,
1098                                 resource.getType() == IResource.FOLDER);
1099         }
1100
1101         /*
1102          * Returns whether the given resource matches one of the exclusion patterns.
1103          * NOTE: should not be asked directly using pkg root pathes
1104          * 
1105          * @see IClasspathEntry#getExclusionPatterns
1106          */
1107         public final static boolean isExcluded(IResource resource,
1108                         char[][] inclusionPatterns, char[][] exclusionPatterns) {
1109                 IPath path = resource.getFullPath();
1110                 // ensure that folders are only excluded if all of their children are
1111                 // excluded
1112                 return isExcluded(path, inclusionPatterns, exclusionPatterns, resource
1113                                 .getType() == IResource.FOLDER);
1114         }
1115
1116         /**
1117          * Validate the given .class file name. A .class file name must obey the
1118          * following rules:
1119          * <ul>
1120          * <li>it must not be null
1121          * <li>it must include the <code>".class"</code> suffix
1122          * <li>its prefix must be a valid identifier
1123          * </ul>
1124          * </p>
1125          * 
1126          * @param name
1127          *            the name of a .class file
1128          * @return a status object with code <code>IStatus.OK</code> if the given
1129          *         name is valid as a .class file name, otherwise a status object
1130          *         indicating what is wrong with the name
1131          */
1132         // public static boolean isValidClassFileName(String name) {
1133         // return JavaConventions.validateClassFileName(name).getSeverity() !=
1134         // IStatus.ERROR;
1135         // }
1136         /**
1137          * Validate the given compilation unit name. A compilation unit name must
1138          * obey the following rules:
1139          * <ul>
1140          * <li>it must not be null
1141          * <li>it must include the <code>".java"</code> suffix
1142          * <li>its prefix must be a valid identifier
1143          * </ul>
1144          * </p>
1145          * 
1146          * @param name
1147          *            the name of a compilation unit
1148          * @return a status object with code <code>IStatus.OK</code> if the given
1149          *         name is valid as a compilation unit name, otherwise a status
1150          *         object indicating what is wrong with the name
1151          */
1152         public static boolean isValidCompilationUnitName(String name) {
1153                 return PHPFileUtil.isPHPFileName(name);
1154                 // return
1155                 // JavaConventions.validateCompilationUnitName(name).getSeverity() !=
1156                 // IStatus.ERROR;
1157         }
1158
1159         /**
1160          * Returns true if the given folder name is valid for a package, false if it
1161          * is not.
1162          */
1163         public static boolean isValidFolderNameForPackage(String folderName) {
1164                 // return JavaConventions.validateIdentifier(folderName).getSeverity()
1165                 // != IStatus.ERROR;
1166                 return true;
1167         }
1168
1169         /**
1170          * Returns true if the given method signature is valid, false if it is not.
1171          */
1172         public static boolean isValidMethodSignature(String sig) {
1173                 int len = sig.length();
1174                 if (len == 0)
1175                         return false;
1176                 int i = 0;
1177                 char c = sig.charAt(i++);
1178                 if (c != '(')
1179                         return false;
1180                 if (i >= len)
1181                         return false;
1182                 while (sig.charAt(i) != ')') {
1183                         // Void is not allowed as a parameter type.
1184                         i = checkTypeSignature(sig, i, len, false);
1185                         if (i == -1)
1186                                 return false;
1187                         if (i >= len)
1188                                 return false;
1189                 }
1190                 ++i;
1191                 i = checkTypeSignature(sig, i, len, true);
1192                 return i == len;
1193         }
1194
1195         /**
1196          * Returns true if the given type signature is valid, false if it is not.
1197          */
1198         public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
1199                 int len = sig.length();
1200                 return checkTypeSignature(sig, 0, len, allowVoid) == len;
1201         }
1202
1203         /*
1204          * Add a log entry
1205          */
1206         public static void log(Throwable e, String message) {
1207                 Throwable nestedException;
1208                 if (e instanceof JavaModelException
1209                                 && (nestedException = ((JavaModelException) e).getException()) != null) {
1210                         e = nestedException;
1211                 }
1212                 IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
1213                                 IStatus.ERROR, message, e);
1214                 JavaCore.getPlugin().getLog().log(status);
1215         }
1216
1217         /**
1218          * Normalizes the cariage returns in the given text. They are all changed to
1219          * use the given buffer's line separator.
1220          */
1221         public static char[] normalizeCRs(char[] text, char[] buffer) {
1222                 CharArrayBuffer result = new CharArrayBuffer();
1223                 int lineStart = 0;
1224                 int length = text.length;
1225                 if (length == 0)
1226                         return text;
1227                 String lineSeparator = getLineSeparator(text, buffer);
1228                 char nextChar = text[0];
1229                 for (int i = 0; i < length; i++) {
1230                         char currentChar = nextChar;
1231                         nextChar = i < length - 1 ? text[i + 1] : ' ';
1232                         switch (currentChar) {
1233                         case '\n':
1234                                 int lineLength = i - lineStart;
1235                                 char[] line = new char[lineLength];
1236                                 System.arraycopy(text, lineStart, line, 0, lineLength);
1237                                 result.append(line);
1238                                 result.append(lineSeparator);
1239                                 lineStart = i + 1;
1240                                 break;
1241                         case '\r':
1242                                 lineLength = i - lineStart;
1243                                 if (lineLength >= 0) {
1244                                         line = new char[lineLength];
1245                                         System.arraycopy(text, lineStart, line, 0, lineLength);
1246                                         result.append(line);
1247                                         result.append(lineSeparator);
1248                                         if (nextChar == '\n') {
1249                                                 nextChar = ' ';
1250                                                 lineStart = i + 2;
1251                                         } else {
1252                                                 // when line separator are mixed in the same file
1253                                                 // \r might not be followed by a \n. If not, we should
1254                                                 // increment
1255                                                 // lineStart by one and not by two.
1256                                                 lineStart = i + 1;
1257                                         }
1258                                 } else {
1259                                         // when line separator are mixed in the same file
1260                                         // we need to prevent NegativeArraySizeException
1261                                         lineStart = i + 1;
1262                                 }
1263                                 break;
1264                         }
1265                 }
1266                 char[] lastLine;
1267                 if (lineStart > 0) {
1268                         int lastLineLength = length - lineStart;
1269                         if (lastLineLength > 0) {
1270                                 lastLine = new char[lastLineLength];
1271                                 System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
1272                                 result.append(lastLine);
1273                         }
1274                         return result.getContents();
1275                 }
1276                 return text;
1277         }
1278
1279         /**
1280          * Normalizes the cariage returns in the given text. They are all changed to
1281          * use given buffer's line sepatator.
1282          */
1283         public static String normalizeCRs(String text, String buffer) {
1284                 return new String(
1285                                 normalizeCRs(text.toCharArray(), buffer.toCharArray()));
1286         }
1287
1288         /**
1289          * Converts the given relative path into a package name. Returns null if the
1290          * path is not a valid package name.
1291          */
1292         public static String packageName(IPath pkgPath) {
1293                 StringBuffer pkgName = new StringBuffer(
1294                                 IPackageFragment.DEFAULT_PACKAGE_NAME);
1295                 for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
1296                         String segment = pkgPath.segment(j);
1297                         // if (!isValidFolderNameForPackage(segment)) {
1298                         // return null;
1299                         // }
1300                         pkgName.append(segment);
1301                         if (j < pkgPath.segmentCount() - 1) {
1302                                 pkgName.append("."); //$NON-NLS-1$
1303                         }
1304                 }
1305                 return pkgName.toString();
1306         }
1307
1308         /**
1309          * Returns the length of the common prefix between s1 and s2.
1310          */
1311 //      public static int prefixLength(char[] s1, char[] s2) {
1312 //              int len = 0;
1313 //              int max = Math.min(s1.length, s2.length);
1314 //              for (int i = 0; i < max && s1[i] == s2[i]; ++i)
1315 //                      ++len;
1316 //              return len;
1317 //      }
1318
1319         /**
1320          * Returns the length of the common prefix between s1 and s2.
1321          */
1322 //      public static int prefixLength(String s1, String s2) {
1323 //              int len = 0;
1324 //              int max = Math.min(s1.length(), s2.length());
1325 //              for (int i = 0; i < max && s1.charAt(i) == s2.charAt(i); ++i)
1326 //                      ++len;
1327 //              return len;
1328 //      }
1329
1330 //      private static void quickSort(char[][] list, int left, int right) {
1331 //              int original_left = left;
1332 //              int original_right = right;
1333 //              char[] mid = list[(left + right) / 2];
1334 //              do {
1335 //                      while (compare(list[left], mid) < 0) {
1336 //                              left++;
1337 //                      }
1338 //                      while (compare(mid, list[right]) < 0) {
1339 //                              right--;
1340 //                      }
1341 //                      if (left <= right) {
1342 //                              char[] tmp = list[left];
1343 //                              list[left] = list[right];
1344 //                              list[right] = tmp;
1345 //                              left++;
1346 //                              right--;
1347 //                      }
1348 //              } while (left <= right);
1349 //              if (original_left < right) {
1350 //                      quickSort(list, original_left, right);
1351 //              }
1352 //              if (left < original_right) {
1353 //                      quickSort(list, left, original_right);
1354 //              }
1355 //      }
1356
1357         /**
1358          * Sort the comparable objects in the given collection.
1359          */
1360         private static void quickSort(Comparable[] sortedCollection, int left,
1361                         int right) {
1362                 int original_left = left;
1363                 int original_right = right;
1364                 Comparable mid = sortedCollection[(left + right) / 2];
1365                 do {
1366                         while (sortedCollection[left].compareTo(mid) < 0) {
1367                                 left++;
1368                         }
1369                         while (mid.compareTo(sortedCollection[right]) < 0) {
1370                                 right--;
1371                         }
1372                         if (left <= right) {
1373                                 Comparable tmp = sortedCollection[left];
1374                                 sortedCollection[left] = sortedCollection[right];
1375                                 sortedCollection[right] = tmp;
1376                                 left++;
1377                                 right--;
1378                         }
1379                 } while (left <= right);
1380                 if (original_left < right) {
1381                         quickSort(sortedCollection, original_left, right);
1382                 }
1383                 if (left < original_right) {
1384                         quickSort(sortedCollection, left, original_right);
1385                 }
1386         }
1387
1388 //      private static void quickSort(int[] list, int left, int right) {
1389 //              int original_left = left;
1390 //              int original_right = right;
1391 //              int mid = list[(left + right) / 2];
1392 //              do {
1393 //                      while (list[left] < mid) {
1394 //                              left++;
1395 //                      }
1396 //                      while (mid < list[right]) {
1397 //                              right--;
1398 //                      }
1399 //                      if (left <= right) {
1400 //                              int tmp = list[left];
1401 //                              list[left] = list[right];
1402 //                              list[right] = tmp;
1403 //                              left++;
1404 //                              right--;
1405 //                      }
1406 //              } while (left <= right);
1407 //              if (original_left < right) {
1408 //                      quickSort(list, original_left, right);
1409 //              }
1410 //              if (left < original_right) {
1411 //                      quickSort(list, left, original_right);
1412 //              }
1413 //      }
1414
1415         /**
1416          * Sort the objects in the given collection using the given comparer.
1417          */
1418         private static void quickSort(Object[] sortedCollection, int left,
1419                         int right, Comparer comparer) {
1420                 int original_left = left;
1421                 int original_right = right;
1422                 Object mid = sortedCollection[(left + right) / 2];
1423                 do {
1424                         while (comparer.compare(sortedCollection[left], mid) < 0) {
1425                                 left++;
1426                         }
1427                         while (comparer.compare(mid, sortedCollection[right]) < 0) {
1428                                 right--;
1429                         }
1430                         if (left <= right) {
1431                                 Object tmp = sortedCollection[left];
1432                                 sortedCollection[left] = sortedCollection[right];
1433                                 sortedCollection[right] = tmp;
1434                                 left++;
1435                                 right--;
1436                         }
1437                 } while (left <= right);
1438                 if (original_left < right) {
1439                         quickSort(sortedCollection, original_left, right, comparer);
1440                 }
1441                 if (left < original_right) {
1442                         quickSort(sortedCollection, left, original_right, comparer);
1443                 }
1444         }
1445
1446         /**
1447          * Sort the objects in the given collection using the given sort order.
1448          */
1449         private static void quickSort(Object[] sortedCollection, int left,
1450                         int right, int[] sortOrder) {
1451                 int original_left = left;
1452                 int original_right = right;
1453                 int mid = sortOrder[(left + right) / 2];
1454                 do {
1455                         while (sortOrder[left] < mid) {
1456                                 left++;
1457                         }
1458                         while (mid < sortOrder[right]) {
1459                                 right--;
1460                         }
1461                         if (left <= right) {
1462                                 Object tmp = sortedCollection[left];
1463                                 sortedCollection[left] = sortedCollection[right];
1464                                 sortedCollection[right] = tmp;
1465                                 int tmp2 = sortOrder[left];
1466                                 sortOrder[left] = sortOrder[right];
1467                                 sortOrder[right] = tmp2;
1468                                 left++;
1469                                 right--;
1470                         }
1471                 } while (left <= right);
1472                 if (original_left < right) {
1473                         quickSort(sortedCollection, original_left, right, sortOrder);
1474                 }
1475                 if (left < original_right) {
1476                         quickSort(sortedCollection, left, original_right, sortOrder);
1477                 }
1478         }
1479
1480         /**
1481          * Sort the strings in the given collection.
1482          */
1483         private static void quickSort(String[] sortedCollection, int left, int right) {
1484                 int original_left = left;
1485                 int original_right = right;
1486                 String mid = sortedCollection[(left + right) / 2];
1487                 do {
1488                         while (sortedCollection[left].compareTo(mid) < 0) {
1489                                 left++;
1490                         }
1491                         while (mid.compareTo(sortedCollection[right]) < 0) {
1492                                 right--;
1493                         }
1494                         if (left <= right) {
1495                                 String tmp = sortedCollection[left];
1496                                 sortedCollection[left] = sortedCollection[right];
1497                                 sortedCollection[right] = tmp;
1498                                 left++;
1499                                 right--;
1500                         }
1501                 } while (left <= right);
1502                 if (original_left < right) {
1503                         quickSort(sortedCollection, original_left, right);
1504                 }
1505                 if (left < original_right) {
1506                         quickSort(sortedCollection, left, original_right);
1507                 }
1508         }
1509
1510         /**
1511          * Sort the strings in the given collection in reverse alphabetical order.
1512          */
1513 //      private static void quickSortReverse(String[] sortedCollection, int left,
1514 //                      int right) {
1515 //              int original_left = left;
1516 //              int original_right = right;
1517 //              String mid = sortedCollection[(left + right) / 2];
1518 //              do {
1519 //                      while (sortedCollection[left].compareTo(mid) > 0) {
1520 //                              left++;
1521 //                      }
1522 //                      while (mid.compareTo(sortedCollection[right]) > 0) {
1523 //                              right--;
1524 //                      }
1525 //                      if (left <= right) {
1526 //                              String tmp = sortedCollection[left];
1527 //                              sortedCollection[left] = sortedCollection[right];
1528 //                              sortedCollection[right] = tmp;
1529 //                              left++;
1530 //                              right--;
1531 //                      }
1532 //              } while (left <= right);
1533 //              if (original_left < right) {
1534 //                      quickSortReverse(sortedCollection, original_left, right);
1535 //              }
1536 //              if (left < original_right) {
1537 //                      quickSortReverse(sortedCollection, left, original_right);
1538 //              }
1539 //      }
1540
1541         /**
1542          * Reads in a string from the specified data input stream. The string has
1543          * been encoded using a modified UTF-8 format.
1544          * <p>
1545          * The first two bytes are read as if by <code>readUnsignedShort</code>.
1546          * This value gives the number of following bytes that are in the encoded
1547          * string, not the length of the resulting string. The following bytes are
1548          * then interpreted as bytes encoding characters in the UTF-8 format and are
1549          * converted into characters.
1550          * <p>
1551          * This method blocks until all the bytes are read, the end of the stream is
1552          * detected, or an exception is thrown.
1553          * 
1554          * @param in
1555          *            a data input stream.
1556          * @return a Unicode string.
1557          * @exception EOFException
1558          *                if the input stream reaches the end before all the bytes.
1559          * @exception IOException
1560          *                if an I/O error occurs.
1561          * @exception UTFDataFormatException
1562          *                if the bytes do not represent a valid UTF-8 encoding of a
1563          *                Unicode string.
1564          * @see java.io.DataInputStream#readUnsignedShort()
1565          */
1566 //      public final static char[] readUTF(DataInput in) throws IOException {
1567 //              int utflen = in.readUnsignedShort();
1568 //              char str[] = new char[utflen];
1569 //              int count = 0;
1570 //              int strlen = 0;
1571 //              while (count < utflen) {
1572 //                      int c = in.readUnsignedByte();
1573 //                      int char2, char3;
1574 //                      switch (c >> 4) {
1575 //                      case 0:
1576 //                      case 1:
1577 //                      case 2:
1578 //                      case 3:
1579 //                      case 4:
1580 //                      case 5:
1581 //                      case 6:
1582 //                      case 7:
1583 //                              // 0xxxxxxx
1584 //                              count++;
1585 //                              str[strlen++] = (char) c;
1586 //                              break;
1587 //                      case 12:
1588 //                      case 13:
1589 //                              // 110x xxxx 10xx xxxx
1590 //                              count += 2;
1591 //                              if (count > utflen)
1592 //                                      throw new UTFDataFormatException();
1593 //                              char2 = in.readUnsignedByte();
1594 //                              if ((char2 & 0xC0) != 0x80)
1595 //                                      throw new UTFDataFormatException();
1596 //                              str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
1597 //                              break;
1598 //                      case 14:
1599 //                              // 1110 xxxx 10xx xxxx 10xx xxxx
1600 //                              count += 3;
1601 //                              if (count > utflen)
1602 //                                      throw new UTFDataFormatException();
1603 //                              char2 = in.readUnsignedByte();
1604 //                              char3 = in.readUnsignedByte();
1605 //                              if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
1606 //                                      throw new UTFDataFormatException();
1607 //                              str[strlen++] = (char) (((c & 0x0F) << 12)
1608 //                                              | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
1609 //                              break;
1610 //                      default:
1611 //                              // 10xx xxxx, 1111 xxxx
1612 //                              throw new UTFDataFormatException();
1613 //                      }
1614 //              }
1615 //              if (strlen < utflen) {
1616 //                      System.arraycopy(str, 0, str = new char[strlen], 0, strlen);
1617 //              }
1618 //              return str;
1619 //      }
1620
1621         /**
1622          * Creates a NLS catalog for the given locale.
1623          */
1624         public static void relocalize() {
1625                 try {
1626                         bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
1627                 } catch (MissingResourceException e) {
1628                         System.out
1629                                         .println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
1630                         throw e;
1631                 }
1632         }
1633
1634 //      public static void sort(char[][] list) {
1635 //              if (list.length > 1)
1636 //                      quickSort(list, 0, list.length - 1);
1637 //      }
1638
1639         /**
1640          * Sorts an array of Comparable objects in place.
1641          */
1642         public static void sort(Comparable[] objects) {
1643                 if (objects.length > 1)
1644                         quickSort(objects, 0, objects.length - 1);
1645         }
1646
1647 //      public static void sort(int[] list) {
1648 //              if (list.length > 1)
1649 //                      quickSort(list, 0, list.length - 1);
1650 //      }
1651
1652         /**
1653          * Sorts an array of objects in place. The given comparer compares pairs of
1654          * items.
1655          */
1656         public static void sort(Object[] objects, Comparer comparer) {
1657                 if (objects.length > 1)
1658                         quickSort(objects, 0, objects.length - 1, comparer);
1659         }
1660
1661         /**
1662          * Sorts an array of objects in place, using the sort order given for each
1663          * item.
1664          */
1665         public static void sort(Object[] objects, int[] sortOrder) {
1666                 if (objects.length > 1)
1667                         quickSort(objects, 0, objects.length - 1, sortOrder);
1668         }
1669
1670         /**
1671          * Sorts an array of strings in place using quicksort.
1672          */
1673         public static void sort(String[] strings) {
1674                 if (strings.length > 1)
1675                         quickSort(strings, 0, strings.length - 1);
1676         }
1677
1678         /**
1679          * Sorts an array of Comparable objects, returning a new array with the
1680          * sorted items. The original array is left untouched.
1681          */
1682 //      public static Comparable[] sortCopy(Comparable[] objects) {
1683 //              int len = objects.length;
1684 //              Comparable[] copy = new Comparable[len];
1685 //              System.arraycopy(objects, 0, copy, 0, len);
1686 //              sort(copy);
1687 //              return copy;
1688 //      }
1689
1690         /**
1691          * Sorts an array of Strings, returning a new array with the sorted items.
1692          * The original array is left untouched.
1693          */
1694 //      public static Object[] sortCopy(Object[] objects, Comparer comparer) {
1695 //              int len = objects.length;
1696 //              Object[] copy = new Object[len];
1697 //              System.arraycopy(objects, 0, copy, 0, len);
1698 //              sort(copy, comparer);
1699 //              return copy;
1700 //      }
1701
1702         /**
1703          * Sorts an array of Strings, returning a new array with the sorted items.
1704          * The original array is left untouched.
1705          */
1706 //      public static String[] sortCopy(String[] objects) {
1707 //              int len = objects.length;
1708 //              String[] copy = new String[len];
1709 //              System.arraycopy(objects, 0, copy, 0, len);
1710 //              sort(copy);
1711 //              return copy;
1712 //      }
1713
1714         /**
1715          * Sorts an array of strings in place using quicksort in reverse
1716          * alphabetical order.
1717          */
1718 //      public static void sortReverseOrder(String[] strings) {
1719 //              if (strings.length > 1)
1720 //                      quickSortReverse(strings, 0, strings.length - 1);
1721 //      }
1722
1723         /**
1724          * Converts a String[] to char[][].
1725          */
1726 //      public static char[][] toCharArrays(String[] a) {
1727 //              int len = a.length;
1728 //              char[][] result = new char[len][];
1729 //              for (int i = 0; i < len; ++i) {
1730 //                      result[i] = toChars(a[i]);
1731 //              }
1732 //              return result;
1733 //      }
1734
1735         /**
1736          * Converts a String to char[].
1737          */
1738 //      public static char[] toChars(String s) {
1739 //              int len = s.length();
1740 //              char[] chars = new char[len];
1741 //              s.getChars(0, len, chars, 0);
1742 //              return chars;
1743 //      }
1744
1745         /**
1746          * Converts a String to char[][], where segments are separate by '.'.
1747          */
1748         public static char[][] toCompoundChars(String s) {
1749                 int len = s.length();
1750                 if (len == 0) {
1751                         return CharOperation.NO_CHAR_CHAR;
1752                 }
1753                 int segCount = 1;
1754                 for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
1755                         ++segCount;
1756                 }
1757                 char[][] segs = new char[segCount][];
1758                 int start = 0;
1759                 for (int i = 0; i < segCount; ++i) {
1760                         int dot = s.indexOf('.', start);
1761                         int end = (dot == -1 ? s.length() : dot);
1762                         segs[i] = new char[end - start];
1763                         s.getChars(start, end, segs[i], 0);
1764                         start = end + 1;
1765                 }
1766                 return segs;
1767         }
1768
1769         /**
1770          * Converts a char[] to String.
1771          */
1772         public static String toString(char[] c) {
1773                 return new String(c);
1774         }
1775
1776         /**
1777          * Converts a char[][] to String, where segments are separated by '.'.
1778          */
1779         public static String toString(char[][] c) {
1780                 StringBuffer sb = new StringBuffer();
1781                 for (int i = 0, max = c.length; i < max; ++i) {
1782                         if (i != 0)
1783                                 sb.append('.');
1784                         sb.append(c[i]);
1785                 }
1786                 return sb.toString();
1787         }
1788
1789         /**
1790          * Converts a char[][] and a char[] to String, where segments are separated
1791          * by '.'.
1792          */
1793 //      public static String toString(char[][] c, char[] d) {
1794 //              if (c == null)
1795 //                      return new String(d);
1796 //              StringBuffer sb = new StringBuffer();
1797 //              for (int i = 0, max = c.length; i < max; ++i) {
1798 //                      sb.append(c[i]);
1799 //                      sb.append('.');
1800 //              }
1801 //              sb.append(d);
1802 //              return sb.toString();
1803 //      }
1804
1805         /*
1806          * Returns the unresolved type parameter signatures of the given method e.g.
1807          * {"QString;", "[int", "[[Qjava.util.Vector;"}
1808          */
1809         // public static String[] typeParameterSignatures(AbstractMethodDeclaration
1810         // method) {
1811         // Argument[] args = method.arguments;
1812         // if (args != null) {
1813         // int length = args.length;
1814         // String[] signatures = new String[length];
1815         // for (int i = 0; i < args.length; i++) {
1816         // Argument arg = args[i];
1817         // signatures[i] = typeSignature(arg.type);
1818         // }
1819         // return signatures;
1820         // }
1821         // return new String[0];
1822         // }
1823         /*
1824          * Returns the unresolved type signature of the given type reference, e.g.
1825          * "QString;", "[int", "[[Qjava.util.Vector;"
1826          */
1827         // public static String typeSignature(TypeReference type) {
1828         // char[][] compoundName = type.getTypeName();
1829         // char[] typeName =CharOperation.concatWith(compoundName, '.');
1830         // String signature = Signature.createTypeSignature(typeName, false/*don't
1831         // resolve*/);
1832         // int dimensions = type.dimensions();
1833         // if (dimensions > 0) {
1834         // signature = Signature.createArraySignature(signature, dimensions);
1835         // }
1836         // return signature;
1837         // }
1838         /*
1839          * Returns the unresolved type signature of the given type reference, e.g.
1840          * "QString;", "[int", "[[Qjava.util.Vector;"
1841          */
1842 //      public static String typeSignature(TypeReference type) {
1843 //              char[][] compoundName = type.getTypeName();
1844 //              char[] typeName = CharOperation.concatWith(compoundName, '.');
1845 //              String signature = Signature
1846 //                              .createTypeSignature(typeName, false/* don't resolve */);
1847 //              int dimensions = type.dimensions();
1848 //              if (dimensions > 0) {
1849 //                      signature = Signature.createArraySignature(signature, dimensions);
1850 //              }
1851 //              return signature;
1852 //      }
1853
1854         /**
1855          * Asserts that the given method signature is valid.
1856          */
1857 //      public static void validateMethodSignature(String sig) {
1858 //              Assert.isTrue(isValidMethodSignature(sig));
1859 //      }
1860
1861         /**
1862          * Asserts that the given type signature is valid.
1863          */
1864 //      public static void validateTypeSignature(String sig, boolean allowVoid) {
1865 //              Assert.isTrue(isValidTypeSignature(sig, allowVoid));
1866 //      }
1867
1868         public static void verbose(String log) {
1869                 verbose(log, System.out);
1870         }
1871
1872         public static synchronized void verbose(String log, PrintStream printStream) {
1873                 int start = 0;
1874                 do {
1875                         int end = log.indexOf('\n', start);
1876                         printStream.print(Thread.currentThread());
1877                         printStream.print(" "); //$NON-NLS-1$
1878                         printStream.print(log.substring(start, end == -1 ? log.length()
1879                                         : end + 1));
1880                         start = end + 1;
1881                 } while (start != 0);
1882                 printStream.println();
1883         }
1884
1885         /**
1886          * Writes a string to the given output stream using UTF-8 encoding in a
1887          * machine-independent manner.
1888          * <p>
1889          * First, two bytes are written to the output stream as if by the
1890          * <code>writeShort</code> method giving the number of bytes to follow.
1891          * This value is the number of bytes actually written out, not the length of
1892          * the string. Following the length, each character of the string is output,
1893          * in sequence, using the UTF-8 encoding for the character.
1894          * 
1895          * @param str
1896          *            a string to be written.
1897          * @return the number of bytes written to the stream.
1898          * @exception IOException
1899          *                if an I/O error occurs.
1900          * @since JDK1.0
1901          */
1902 //      public static int writeUTF(OutputStream out, char[] str) throws IOException {
1903 //              int strlen = str.length;
1904 //              int utflen = 0;
1905 //              for (int i = 0; i < strlen; i++) {
1906 //                      int c = str[i];
1907 //                      if ((c >= 0x0001) && (c <= 0x007F)) {
1908 //                              utflen++;
1909 //                      } else if (c > 0x07FF) {
1910 //                              utflen += 3;
1911 //                      } else {
1912 //                              utflen += 2;
1913 //                      }
1914 //              }
1915 //              if (utflen > 65535)
1916 //                      throw new UTFDataFormatException();
1917 //              out.write((utflen >>> 8) & 0xFF);
1918 //              out.write((utflen >>> 0) & 0xFF);
1919 //              if (strlen == utflen) {
1920 //                      for (int i = 0; i < strlen; i++)
1921 //                              out.write(str[i]);
1922 //              } else {
1923 //                      for (int i = 0; i < strlen; i++) {
1924 //                              int c = str[i];
1925 //                              if ((c >= 0x0001) && (c <= 0x007F)) {
1926 //                                      out.write(c);
1927 //                              } else if (c > 0x07FF) {
1928 //                                      out.write(0xE0 | ((c >> 12) & 0x0F));
1929 //                                      out.write(0x80 | ((c >> 6) & 0x3F));
1930 //                                      out.write(0x80 | ((c >> 0) & 0x3F));
1931 //                              } else {
1932 //                                      out.write(0xC0 | ((c >> 6) & 0x1F));
1933 //                                      out.write(0x80 | ((c >> 0) & 0x3F));
1934 //                              }
1935 //                      }
1936 //              }
1937 //              return utflen + 2; // the number of bytes written to the stream
1938 //      }
1939 }