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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.util;
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;
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 import net.sourceforge.phpdt.internal.core.Assert;
35 import net.sourceforge.phpdt.internal.core.PackageFragmentRoot;
36 import net.sourceforge.phpdt.internal.core.util.PHPFileUtil;
38 import org.eclipse.core.resources.IFile;
39 //import org.eclipse.core.resources.IFolder;
40 import org.eclipse.core.resources.IResource;
41 import org.eclipse.core.runtime.CoreException;
42 import org.eclipse.core.runtime.IPath;
43 import org.eclipse.core.runtime.IStatus;
44 import org.eclipse.core.runtime.Status;
45 import org.eclipse.jface.text.BadLocationException;
46 import org.eclipse.text.edits.MalformedTreeException;
47 import org.eclipse.text.edits.TextEdit;
50 * Provides convenient utility methods to other types in this package.
54 public interface Comparable {
56 * Returns 0 if this and c are equal, >0 if this is greater than c, or
57 * <0 if this is less than c.
59 int compareTo(Comparable c);
62 public interface Comparer {
64 * Returns 0 if a and b are equal, >0 if a is greater than b, or <0 if a
67 int compare(Object a, Object b);
70 private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
72 /* Bundle containing messages */
73 protected static ResourceBundle bundle;
75 private final static String bundleName = "net.sourceforge.phpdt.internal.core.util.messages"; //$NON-NLS-1$
77 private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
79 private static final String EMPTY_ARGUMENT = " "; //$NON-NLS-1$
81 public static final String[] fgEmptyStringArray = new String[0];
83 private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
90 // cannot be instantiated
94 * Lookup the message with the given ID in this catalog
96 public static String bind(String id) {
97 return bind(id, (String[]) null);
101 * Lookup the message with the given ID in this catalog and bind its
102 * substitution locations with the given string.
104 public static String bind(String id, String binding) {
105 return bind(id, new String[] { binding });
109 * Lookup the message with the given ID in this catalog and bind its
110 * substitution locations with the given strings.
112 public static String bind(String id, String binding1, String binding2) {
113 return bind(id, new String[] { binding1, binding2 });
117 * Lookup the message with the given ID in this catalog and bind its
118 * substitution locations with the given string values.
120 public static String bind(String id, String[] bindings) {
122 return "No message available"; //$NON-NLS-1$
123 String message = null;
125 message = bundle.getString(id);
126 } catch (MissingResourceException e) {
127 // If we got an exception looking for the message, fail gracefully
129 // the id we were looking for. In most cases this is
130 // semi-informative so is not too bad.
131 return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
133 // for compatibility with MessageFormat which eliminates double quotes
134 // in original message
135 char[] messageWithNoDoubleQuotes = CharOperation.replace(message
136 .toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
138 if (bindings == null)
139 return new String(messageWithNoDoubleQuotes);
141 int length = messageWithNoDoubleQuotes.length;
144 StringBuffer output = null;
146 if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes,
149 output = new StringBuffer(length + bindings.length * 20);
150 output.append(messageWithNoDoubleQuotes, start, end - start);
151 if ((start = CharOperation.indexOf('}',
152 messageWithNoDoubleQuotes, end + 1)) > -1) {
154 String argId = new String(messageWithNoDoubleQuotes,
155 end + 1, start - end - 1);
157 index = Integer.parseInt(argId);
158 output.append(bindings[index]);
159 } catch (NumberFormatException nfe) { // could be nested
162 boolean done = false;
163 if (!id.equals(argId)) {
164 String argMessage = null;
166 argMessage = bundle.getString(argId);
167 output.append(argMessage);
169 } catch (MissingResourceException e) {
170 // unable to bind argument, ignore (will leave
175 output.append(messageWithNoDoubleQuotes, end + 1,
177 } catch (ArrayIndexOutOfBoundsException e) {
179 .append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
183 output.append(messageWithNoDoubleQuotes, end, length);
188 return new String(messageWithNoDoubleQuotes);
189 output.append(messageWithNoDoubleQuotes, start, length - start);
193 return output.toString();
197 * Checks the type signature in String sig, starting at start and ending
198 * before end (end is not included). Returns the index of the character
199 * immediately after the signature if valid, or -1 if not valid.
201 private static int checkTypeSignature(String sig, int start, int end,
206 char c = sig.charAt(i++);
207 int nestingDepth = 0;
227 // array of void is not allowed
228 if (nestingDepth != 0)
232 int semicolon = sig.indexOf(';', i);
233 // Must have at least one character between L and ;
234 if (semicolon <= i || semicolon >= end)
245 * Combines two hash codes to make a new one.
247 public static int combineHashCodes(int hashCode1, int hashCode2) {
248 return hashCode1 * 17 + hashCode2;
252 * Compares two byte arrays. Returns <0 if a byte in a is less than the
253 * corresponding byte in b, or if a is shorter, or if a is null. Returns >0
254 * if a byte in a is greater than the corresponding byte in b, or if a is
255 * longer, or if b is null. Returns 0 if they are equal or both null.
257 public static int compare(byte[] a, byte[] b) {
264 int len = Math.min(a.length, b.length);
265 for (int i = 0; i < len; ++i) {
266 int diff = a[i] - b[i];
278 * Compares two strings lexicographically. The comparison is based on the
279 * Unicode value of each character in the strings.
281 * @return the value <code>0</code> if the str1 is equal to str2; a value
282 * less than <code>0</code> if str1 is lexicographically less than
283 * str2; and a value greater than <code>0</code> if str1 is
284 * lexicographically greater than str2.
286 public static int compare(char[] str1, char[] str2) {
287 int len1 = str1.length;
288 int len2 = str2.length;
289 int n = Math.min(len1, len2);
302 * Concatenate two strings with a char in between.
304 * @see #concat(String, String)
306 public static String concat(String s1, char c, String s2) {
308 s1 = "null"; //$NON-NLS-1$
310 s2 = "null"; //$NON-NLS-1$
311 int l1 = s1.length();
312 int l2 = s2.length();
313 char[] buf = new char[l1 + 1 + l2];
314 s1.getChars(0, l1, buf, 0);
316 s2.getChars(0, l2, buf, l1 + 1);
317 return new String(buf);
321 * Concatenate two strings. Much faster than using +, which: - creates a
322 * StringBuffer, - which is synchronized, - of default size, so the
323 * resulting char array is often larger than needed. This implementation
324 * creates an extra char array, since the String constructor copies its
325 * argument, but there's no way around this.
327 public static String concat(String s1, String s2) {
329 s1 = "null"; //$NON-NLS-1$
331 s2 = "null"; //$NON-NLS-1$
332 int l1 = s1.length();
333 int l2 = s2.length();
334 char[] buf = new char[l1 + l2];
335 s1.getChars(0, l1, buf, 0);
336 s2.getChars(0, l2, buf, l1);
337 return new String(buf);
341 * Concatenate three strings.
343 * @see #concat(String, String)
345 public static String concat(String s1, String s2, String s3) {
347 s1 = "null"; //$NON-NLS-1$
349 s2 = "null"; //$NON-NLS-1$
351 s3 = "null"; //$NON-NLS-1$
352 int l1 = s1.length();
353 int l2 = s2.length();
354 int l3 = s3.length();
355 char[] buf = new char[l1 + l2 + l3];
356 s1.getChars(0, l1, buf, 0);
357 s2.getChars(0, l2, buf, l1);
358 s3.getChars(0, l3, buf, l1 + l2);
359 return new String(buf);
363 * Converts a type signature from the IBinaryType representation to the DC
366 public static String convertTypeSignature(char[] sig) {
367 return new String(sig).replace('/', '.');
371 * Apply the given edit on the given string and return the updated string.
372 * Return the given string if anything wrong happen while applying the edit.
379 * @return the updated string
381 public final static String editedString(String original, TextEdit edit) {
385 SimpleDocument document = new SimpleDocument(original);
387 edit.apply(document, TextEdit.NONE);
388 return document.get();
389 } catch (MalformedTreeException e) {
391 } catch (BadLocationException e) {
398 * Returns true iff str.toLowerCase().endsWith(end.toLowerCase())
399 * implementation is not creating extra strings.
401 public final static boolean endsWithIgnoreCase(String str, String end) {
403 int strLength = str == null ? 0 : str.length();
404 int endLength = end == null ? 0 : end.length();
406 // return false if the string is smaller than the end.
407 if (endLength > strLength)
410 // return false if any character of the end are
411 // not the same in lower case.
412 for (int i = 1; i <= endLength; i++) {
413 if (Character.toLowerCase(end.charAt(endLength - i)) != Character
414 .toLowerCase(str.charAt(strLength - i)))
422 * Compares two arrays using equals() on the elements. Either or both arrays
423 * may be null. Returns true if both are null. Returns false if only one is
424 * null. If both are arrays, returns true iff they have the same length and
425 * all elements are equal.
427 public static boolean equalArraysOrNull(int[] a, int[] b) {
430 if (a == null || b == null)
435 for (int i = 0; i < len; ++i) {
443 * Compares two arrays using equals() on the elements. Either or both arrays
444 * may be null. Returns true if both are null. Returns false if only one is
445 * null. If both are arrays, returns true iff they have the same length and
446 * all elements compare true with equals.
448 public static boolean equalArraysOrNull(Object[] a, Object[] b) {
451 if (a == null || b == null)
457 for (int i = 0; i < len; ++i) {
462 if (!a[i].equals(b[i]))
470 * Compares two arrays using equals() on the elements. The arrays are first
471 * sorted. Either or both arrays may be null. Returns true if both are null.
472 * Returns false if only one is null. If both are arrays, returns true iff
473 * they have the same length and iff, after sorting both arrays, all
474 * elements compare true with equals. The original arrays are left
477 public static boolean equalArraysOrNullSortFirst(Comparable[] a,
481 if (a == null || b == null)
486 if (len >= 2) { // only need to sort if more than two items
490 for (int i = 0; i < len; ++i) {
491 if (!a[i].equals(b[i]))
498 * Compares two String arrays using equals() on the elements. The arrays are
499 * first sorted. Either or both arrays may be null. Returns true if both are
500 * null. Returns false if only one is null. If both are arrays, returns true
501 * iff they have the same length and iff, after sorting both arrays, all
502 * elements compare true with equals. The original arrays are left
505 public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
508 if (a == null || b == null)
513 if (len >= 2) { // only need to sort if more than two items
517 for (int i = 0; i < len; ++i) {
518 if (!a[i].equals(b[i]))
525 * Compares two objects using equals(). Either or both array may be null.
526 * Returns true if both are null. Returns false if only one is null.
527 * Otherwise, return the result of comparing with equals().
529 public static boolean equalOrNull(Object a, Object b) {
533 if (a == null || b == null) {
540 * Given a qualified name, extract the last component. If the input is not
541 * qualified, the same string is answered.
543 public static String extractLastName(String qualifiedName) {
544 int i = qualifiedName.lastIndexOf('.');
546 return qualifiedName;
547 return qualifiedName.substring(i + 1);
551 * Extracts the parameter types from a method signature.
553 public static String[] extractParameterTypes(char[] sig) {
554 int count = getParameterCount(sig);
555 String[] result = new String[count];
558 int i = CharOperation.indexOf('(', sig) + 1;
560 int len = sig.length;
570 } else if (c == 'L') {
571 i = CharOperation.indexOf(';', sig, i + 1) + 1;
572 Assert.isTrue(i != 0);
573 result[count++] = convertTypeSignature(CharOperation.subarray(
578 result[count++] = convertTypeSignature(CharOperation.subarray(
587 * Extracts the return type from a method signature.
589 public static String extractReturnType(String sig) {
590 int i = sig.lastIndexOf(')');
591 Assert.isTrue(i != -1);
592 return sig.substring(i + 1);
595 // private static IFile findFirstClassFile(IFolder folder) {
597 // IResource[] members = folder.members();
598 // for (int i = 0, max = members.length; i < max; i++) {
599 // IResource member = members[i];
600 // if (member.getType() == IResource.FOLDER) {
601 // return findFirstClassFile((IFolder) member);
603 // // (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(member.getName()))
605 // // return (IFile) member;
608 // } catch (CoreException e) {
615 * Finds the first line separator used by the given text.
617 * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"</code>,
618 * or <code>null</code> if none found
620 public static String findLineSeparator(char[] text) {
621 // find the first line separator
622 int length = text.length;
624 char nextChar = text[0];
625 for (int i = 0; i < length; i++) {
626 char currentChar = nextChar;
627 nextChar = i < length - 1 ? text[i + 1] : ' ';
628 switch (currentChar) {
630 return "\n"; //$NON-NLS-1$
632 return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
640 // public static IClassFileAttribute getAttribute(IClassFileReader
641 // classFileReader, char[] attributeName) {
642 // IClassFileAttribute[] attributes = classFileReader.getAttributes();
643 // for (int i = 0, max = attributes.length; i < max; i++) {
644 // if (CharOperation.equals(attributes[i].getAttributeName(),
646 // return attributes[i];
652 // public static IClassFileAttribute getAttribute(ICodeAttribute
653 // codeAttribute, char[] attributeName) {
654 // IClassFileAttribute[] attributes = codeAttribute.getAttributes();
655 // for (int i = 0, max = attributes.length; i < max; i++) {
656 // if (CharOperation.equals(attributes[i].getAttributeName(),
658 // return attributes[i];
664 // public static IClassFileAttribute getAttribute(IFieldInfo fieldInfo,
665 // char[] attributeName) {
666 // IClassFileAttribute[] attributes = fieldInfo.getAttributes();
667 // for (int i = 0, max = attributes.length; i < max; i++) {
668 // if (CharOperation.equals(attributes[i].getAttributeName(),
670 // return attributes[i];
676 // public static IClassFileAttribute getAttribute(IMethodInfo methodInfo,
677 // char[] attributeName) {
678 // IClassFileAttribute[] attributes = methodInfo.getAttributes();
679 // for (int i = 0, max = attributes.length; i < max; i++) {
680 // if (CharOperation.equals(attributes[i].getAttributeName(),
682 // return attributes[i];
688 * Get the jdk level of this root. The value can be:
690 * <li>major < <16 + minor : see predefined constants on ClassFileConstants</li>
691 * <li><code>0</null> if the root is a source package fragment root or if a Java model exception occured</li>
693 * Returns the jdk level
695 // public static long getJdkLevel(Object targetLibrary) {
697 // ClassFileReader reader = null;
698 // if (targetLibrary instanceof IFolder) {
699 // IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only
700 // internal classfolders are allowed
701 // if (classFile != null) {
702 // byte[] bytes = Util.getResourceContentsAsByteArray(classFile);
703 // IPath location = classFile.getLocation();
704 // reader = new ClassFileReader(bytes, location == null ? null :
705 // location.toString().toCharArray());
708 // // root is a jar file or a zip file
709 // ZipFile jar = null;
711 // IPath path = null;
712 // if (targetLibrary instanceof IResource) {
713 // path = ((IResource)targetLibrary).getLocation();
714 // } else if (targetLibrary instanceof File){
715 // File f = (File) targetLibrary;
716 // if (!f.isDirectory()) {
717 // path = new Path(((File)targetLibrary).getPath());
720 // if (path != null) {
721 // jar = JavaModelManager.getJavaModelManager().getZipFile(path);
722 // for (Enumeration e= jar.entries(); e.hasMoreElements();) {
723 // ZipEntry member= (ZipEntry) e.nextElement();
724 // String entryName= member.getName();
726 // (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(entryName))
728 // reader = ClassFileReader.read(jar, entryName);
733 // } catch (CoreException e) {
736 // JavaModelManager.getJavaModelManager().closeZipFile(jar);
739 // if (reader != null) {
740 // return reader.getVersion();
742 // } catch(JavaModelException e) {
744 // } catch(ClassFormatException e) {
746 // } catch(IOException e) {
752 * Returns the line separator used by the given buffer. Uses the given text
755 * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"</code>
757 private static String getLineSeparator(char[] text, char[] buffer) {
758 // search in this buffer's contents first
759 String lineSeparator = findLineSeparator(buffer);
760 if (lineSeparator == null) {
761 // search in the given text
762 lineSeparator = findLineSeparator(text);
763 if (lineSeparator == null) {
764 // default to system line separator
765 return net.sourceforge.phpdt.internal.compiler.util.Util.LINE_SEPARATOR;
768 return lineSeparator;
772 * Returns the number of parameter types in a method signature.
774 public static int getParameterCount(char[] sig) {
775 int i = CharOperation.indexOf('(', sig) + 1;
776 Assert.isTrue(i != 0);
778 int len = sig.length;
787 } else if (c == 'L') {
789 i = CharOperation.indexOf(';', sig, i + 1) + 1;
790 Assert.isTrue(i != 0);
800 * Put all the arguments in one String.
802 public static String getProblemArgumentsForMarker(String[] arguments) {
803 StringBuffer args = new StringBuffer(10);
805 args.append(arguments.length);
808 for (int j = 0; j < arguments.length; j++) {
810 args.append(ARGUMENTS_DELIMITER);
812 if (arguments[j].length() == 0) {
813 args.append(EMPTY_ARGUMENT);
815 args.append(arguments[j]);
819 return args.toString();
823 * Separate all the arguments of a String made by
824 * getProblemArgumentsForMarker
826 public static String[] getProblemArgumentsFromMarker(String argumentsString) {
827 if (argumentsString == null)
829 int index = argumentsString.indexOf(':');
833 int length = argumentsString.length();
836 numberOfArg = Integer.parseInt(argumentsString.substring(0, index));
837 } catch (NumberFormatException e) {
840 argumentsString = argumentsString.substring(index + 1, length);
842 String[] args = new String[length];
845 StringTokenizer tokenizer = new StringTokenizer(argumentsString,
846 ARGUMENTS_DELIMITER);
847 while (tokenizer.hasMoreTokens()) {
848 String argument = tokenizer.nextToken();
849 if (argument.equals(EMPTY_ARGUMENT))
850 argument = ""; //$NON-NLS-1$
851 args[count++] = argument;
854 if (count != numberOfArg)
857 System.arraycopy(args, 0, args = new String[count], 0, count);
862 * Returns the given file's contents as a byte array.
864 public static byte[] getResourceContentsAsByteArray(IFile file)
865 throws JavaModelException {
866 InputStream stream = null;
868 stream = new BufferedInputStream(file.getContents(true));
869 } catch (CoreException e) {
870 throw new JavaModelException(e);
873 return net.sourceforge.phpdt.internal.compiler.util.Util
874 .getInputStreamAsByteArray(stream, -1);
875 } catch (IOException e) {
876 throw new JavaModelException(e,
877 IJavaModelStatusConstants.IO_EXCEPTION);
881 } catch (IOException e) {
888 * Returns the given file's contents as a character array.
890 public static char[] getResourceContentsAsCharArray(IFile file)
891 throws JavaModelException {
892 // Get encoding from file
893 String encoding = null;
895 encoding = file.getCharset();
896 } catch (CoreException ce) {
897 // do not use any encoding
899 return getResourceContentsAsCharArray(file, encoding);
902 public static char[] getResourceContentsAsCharArray(IFile file,
903 String encoding) throws JavaModelException {
904 // Get resource contents
905 InputStream stream = null;
907 stream = new BufferedInputStream(file.getContents(true));
908 } catch (CoreException e) {
909 throw new JavaModelException(e,
910 IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
913 return net.sourceforge.phpdt.internal.compiler.util.Util
914 .getInputStreamAsCharArray(stream, -1, encoding);
915 } catch (IOException e) {
916 throw new JavaModelException(e,
917 IJavaModelStatusConstants.IO_EXCEPTION);
921 } catch (IOException e) {
928 * Returns a trimmed version the simples names returned by Signature.
930 public static String[] getTrimmedSimpleNames(String name) {
931 String[] result = Signature.getSimpleNames(name);
934 for (int i = 0, length = result.length; i < length; i++) {
935 result[i] = result[i].trim();
941 * Returns the index of the most specific argument paths which is strictly
942 * enclosing the path to check
944 public static int indexOfEnclosingPath(IPath checkedPath, IPath[] paths,
947 int bestMatch = -1, bestLength = -1;
948 for (int i = 0; i < pathCount; i++) {
949 if (paths[i].equals(checkedPath))
951 if (paths[i].isPrefixOf(checkedPath)) {
952 int currentLength = paths[i].segmentCount();
953 if (currentLength > bestLength) {
954 bestLength = currentLength;
963 * Returns the index of the first argument paths which is equal to the path
966 public static int indexOfMatchingPath(IPath checkedPath, IPath[] paths,
969 for (int i = 0; i < pathCount; i++) {
970 if (paths[i].equals(checkedPath))
977 * Returns the index of the first argument paths which is strictly nested
978 * inside the path to check
980 public static int indexOfNestedPath(IPath checkedPath, IPath[] paths,
983 for (int i = 0; i < pathCount; i++) {
984 if (checkedPath.equals(paths[i]))
986 if (checkedPath.isPrefixOf(paths[i]))
993 * Returns whether the given java element is exluded from its root's
994 * classpath. It doesn't check whether the root itself is on the classpath
997 public static final boolean isExcluded(IJavaElement element) {
998 int elementType = element.getElementType();
999 PackageFragmentRoot root = null;
1000 IResource resource = null;
1001 switch (elementType) {
1002 case IJavaElement.JAVA_MODEL:
1003 case IJavaElement.JAVA_PROJECT:
1004 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
1007 // case IJavaElement.PACKAGE_FRAGMENT:
1008 // PackageFragmentRoot root =
1009 // (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
1010 // IResource resource = element.getResource();
1011 // return resource != null && isExcluded(resource,
1012 // root.fullInclusionPatternChars(),
1013 // root.fullExclusionPatternChars());
1015 case IJavaElement.COMPILATION_UNIT:
1016 root = (PackageFragmentRoot) element
1017 .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
1018 resource = element.getResource();
1019 // if (resource != null && isExcluded(resource,
1020 // root.fullInclusionPatternChars(),
1021 // root.fullExclusionPatternChars()))
1023 return isExcluded(element.getParent());
1026 IJavaElement cu = element
1027 .getAncestor(IJavaElement.COMPILATION_UNIT);
1028 return cu != null && isExcluded(cu);
1033 * Returns whether the given resource path matches one of the
1034 * inclusion/exclusion patterns. NOTE: should not be asked directly using
1037 * @see IClasspathEntry#getInclusionPatterns
1038 * @see IClasspathEntry#getExclusionPatterns
1040 public final static boolean isExcluded(IPath resourcePath,
1041 char[][] inclusionPatterns, char[][] exclusionPatterns,
1042 boolean isFolderPath) {
1043 if (inclusionPatterns == null && exclusionPatterns == null)
1045 char[] path = resourcePath.toString().toCharArray();
1047 inclusionCheck: if (inclusionPatterns != null) {
1048 for (int i = 0, length = inclusionPatterns.length; i < length; i++) {
1049 char[] pattern = inclusionPatterns[i];
1050 char[] folderPattern = pattern;
1052 int lastSlash = CharOperation.lastIndexOf('/', pattern);
1053 if (lastSlash != -1 && lastSlash != pattern.length - 1) { // trailing
1061 // http://ant.apache.org/manual/dirtasks.html)
1062 int star = CharOperation.indexOf('*', pattern,
1064 if ((star == -1 || star >= pattern.length - 1 || pattern[star + 1] != '*')) {
1065 folderPattern = CharOperation.subarray(pattern, 0,
1070 if (CharOperation.pathMatch(folderPattern, path, true, '/')) {
1071 break inclusionCheck;
1074 return true; // never included
1077 path = CharOperation.concat(path, new char[] { '*' }, '/');
1079 exclusionCheck: if (exclusionPatterns != null) {
1080 for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
1081 if (CharOperation.pathMatch(exclusionPatterns[i], path, true,
1090 public final static boolean isExcluded(IResource resource,
1091 char[][] exclusionPatterns) {
1092 IPath path = resource.getFullPath();
1093 // ensure that folders are only excluded if all of their children are
1095 return isExcluded(path, null, exclusionPatterns,
1096 resource.getType() == IResource.FOLDER);
1100 * Returns whether the given resource matches one of the exclusion patterns.
1101 * NOTE: should not be asked directly using pkg root pathes
1103 * @see IClasspathEntry#getExclusionPatterns
1105 public final static boolean isExcluded(IResource resource,
1106 char[][] inclusionPatterns, char[][] exclusionPatterns) {
1107 IPath path = resource.getFullPath();
1108 // ensure that folders are only excluded if all of their children are
1110 return isExcluded(path, inclusionPatterns, exclusionPatterns, resource
1111 .getType() == IResource.FOLDER);
1115 * Validate the given .class file name. A .class file name must obey the
1118 * <li>it must not be null
1119 * <li>it must include the <code>".class"</code> suffix
1120 * <li>its prefix must be a valid identifier
1125 * the name of a .class file
1126 * @return a status object with code <code>IStatus.OK</code> if the given
1127 * name is valid as a .class file name, otherwise a status object
1128 * indicating what is wrong with the name
1130 // public static boolean isValidClassFileName(String name) {
1131 // return JavaConventions.validateClassFileName(name).getSeverity() !=
1135 * Validate the given compilation unit name. A compilation unit name must
1136 * obey the following rules:
1138 * <li>it must not be null
1139 * <li>it must include the <code>".java"</code> suffix
1140 * <li>its prefix must be a valid identifier
1145 * the name of a compilation unit
1146 * @return a status object with code <code>IStatus.OK</code> if the given
1147 * name is valid as a compilation unit name, otherwise a status
1148 * object indicating what is wrong with the name
1150 public static boolean isValidCompilationUnitName(String name) {
1151 return PHPFileUtil.isPHPFileName(name);
1153 // JavaConventions.validateCompilationUnitName(name).getSeverity() !=
1158 * Returns true if the given folder name is valid for a package, false if it
1161 public static boolean isValidFolderNameForPackage(String folderName) {
1162 // return JavaConventions.validateIdentifier(folderName).getSeverity()
1163 // != IStatus.ERROR;
1168 * Returns true if the given method signature is valid, false if it is not.
1170 public static boolean isValidMethodSignature(String sig) {
1171 int len = sig.length();
1175 char c = sig.charAt(i++);
1180 while (sig.charAt(i) != ')') {
1181 // Void is not allowed as a parameter type.
1182 i = checkTypeSignature(sig, i, len, false);
1189 i = checkTypeSignature(sig, i, len, true);
1194 * Returns true if the given type signature is valid, false if it is not.
1196 public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
1197 int len = sig.length();
1198 return checkTypeSignature(sig, 0, len, allowVoid) == len;
1204 public static void log(Throwable e, String message) {
1205 Throwable nestedException;
1206 if (e instanceof JavaModelException
1207 && (nestedException = ((JavaModelException) e).getException()) != null) {
1208 e = nestedException;
1210 IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
1211 IStatus.ERROR, message, e);
1212 JavaCore.getPlugin().getLog().log(status);
1216 * Normalizes the cariage returns in the given text. They are all changed to
1217 * use the given buffer's line separator.
1219 public static char[] normalizeCRs(char[] text, char[] buffer) {
1220 CharArrayBuffer result = new CharArrayBuffer();
1222 int length = text.length;
1225 String lineSeparator = getLineSeparator(text, buffer);
1226 char nextChar = text[0];
1227 for (int i = 0; i < length; i++) {
1228 char currentChar = nextChar;
1229 nextChar = i < length - 1 ? text[i + 1] : ' ';
1230 switch (currentChar) {
1232 int lineLength = i - lineStart;
1233 char[] line = new char[lineLength];
1234 System.arraycopy(text, lineStart, line, 0, lineLength);
1235 result.append(line);
1236 result.append(lineSeparator);
1240 lineLength = i - lineStart;
1241 if (lineLength >= 0) {
1242 line = new char[lineLength];
1243 System.arraycopy(text, lineStart, line, 0, lineLength);
1244 result.append(line);
1245 result.append(lineSeparator);
1246 if (nextChar == '\n') {
1250 // when line separator are mixed in the same file
1251 // \r might not be followed by a \n. If not, we should
1253 // lineStart by one and not by two.
1257 // when line separator are mixed in the same file
1258 // we need to prevent NegativeArraySizeException
1265 if (lineStart > 0) {
1266 int lastLineLength = length - lineStart;
1267 if (lastLineLength > 0) {
1268 lastLine = new char[lastLineLength];
1269 System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
1270 result.append(lastLine);
1272 return result.getContents();
1278 * Normalizes the cariage returns in the given text. They are all changed to
1279 * use given buffer's line sepatator.
1281 public static String normalizeCRs(String text, String buffer) {
1283 normalizeCRs(text.toCharArray(), buffer.toCharArray()));
1287 * Converts the given relative path into a package name. Returns null if the
1288 * path is not a valid package name.
1290 public static String packageName(IPath pkgPath) {
1291 StringBuffer pkgName = new StringBuffer(
1292 IPackageFragment.DEFAULT_PACKAGE_NAME);
1293 for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
1294 String segment = pkgPath.segment(j);
1295 // if (!isValidFolderNameForPackage(segment)) {
1298 pkgName.append(segment);
1299 if (j < pkgPath.segmentCount() - 1) {
1300 pkgName.append("."); //$NON-NLS-1$
1303 return pkgName.toString();
1307 * Returns the length of the common prefix between s1 and s2.
1309 public static int prefixLength(char[] s1, char[] s2) {
1311 int max = Math.min(s1.length, s2.length);
1312 for (int i = 0; i < max && s1[i] == s2[i]; ++i)
1318 * Returns the length of the common prefix between s1 and s2.
1320 public static int prefixLength(String s1, String s2) {
1322 int max = Math.min(s1.length(), s2.length());
1323 for (int i = 0; i < max && s1.charAt(i) == s2.charAt(i); ++i)
1328 private static void quickSort(char[][] list, int left, int right) {
1329 int original_left = left;
1330 int original_right = right;
1331 char[] mid = list[(left + right) / 2];
1333 while (compare(list[left], mid) < 0) {
1336 while (compare(mid, list[right]) < 0) {
1339 if (left <= right) {
1340 char[] tmp = list[left];
1341 list[left] = list[right];
1346 } while (left <= right);
1347 if (original_left < right) {
1348 quickSort(list, original_left, right);
1350 if (left < original_right) {
1351 quickSort(list, left, original_right);
1356 * Sort the comparable objects in the given collection.
1358 private static void quickSort(Comparable[] sortedCollection, int left,
1360 int original_left = left;
1361 int original_right = right;
1362 Comparable mid = sortedCollection[(left + right) / 2];
1364 while (sortedCollection[left].compareTo(mid) < 0) {
1367 while (mid.compareTo(sortedCollection[right]) < 0) {
1370 if (left <= right) {
1371 Comparable tmp = sortedCollection[left];
1372 sortedCollection[left] = sortedCollection[right];
1373 sortedCollection[right] = tmp;
1377 } while (left <= right);
1378 if (original_left < right) {
1379 quickSort(sortedCollection, original_left, right);
1381 if (left < original_right) {
1382 quickSort(sortedCollection, left, original_right);
1386 private static void quickSort(int[] list, int left, int right) {
1387 int original_left = left;
1388 int original_right = right;
1389 int mid = list[(left + right) / 2];
1391 while (list[left] < mid) {
1394 while (mid < list[right]) {
1397 if (left <= right) {
1398 int tmp = list[left];
1399 list[left] = list[right];
1404 } while (left <= right);
1405 if (original_left < right) {
1406 quickSort(list, original_left, right);
1408 if (left < original_right) {
1409 quickSort(list, left, original_right);
1414 * Sort the objects in the given collection using the given comparer.
1416 private static void quickSort(Object[] sortedCollection, int left,
1417 int right, Comparer comparer) {
1418 int original_left = left;
1419 int original_right = right;
1420 Object mid = sortedCollection[(left + right) / 2];
1422 while (comparer.compare(sortedCollection[left], mid) < 0) {
1425 while (comparer.compare(mid, sortedCollection[right]) < 0) {
1428 if (left <= right) {
1429 Object tmp = sortedCollection[left];
1430 sortedCollection[left] = sortedCollection[right];
1431 sortedCollection[right] = tmp;
1435 } while (left <= right);
1436 if (original_left < right) {
1437 quickSort(sortedCollection, original_left, right, comparer);
1439 if (left < original_right) {
1440 quickSort(sortedCollection, left, original_right, comparer);
1445 * Sort the objects in the given collection using the given sort order.
1447 private static void quickSort(Object[] sortedCollection, int left,
1448 int right, int[] sortOrder) {
1449 int original_left = left;
1450 int original_right = right;
1451 int mid = sortOrder[(left + right) / 2];
1453 while (sortOrder[left] < mid) {
1456 while (mid < sortOrder[right]) {
1459 if (left <= right) {
1460 Object tmp = sortedCollection[left];
1461 sortedCollection[left] = sortedCollection[right];
1462 sortedCollection[right] = tmp;
1463 int tmp2 = sortOrder[left];
1464 sortOrder[left] = sortOrder[right];
1465 sortOrder[right] = tmp2;
1469 } while (left <= right);
1470 if (original_left < right) {
1471 quickSort(sortedCollection, original_left, right, sortOrder);
1473 if (left < original_right) {
1474 quickSort(sortedCollection, left, original_right, sortOrder);
1479 * Sort the strings in the given collection.
1481 private static void quickSort(String[] sortedCollection, int left, int right) {
1482 int original_left = left;
1483 int original_right = right;
1484 String mid = sortedCollection[(left + right) / 2];
1486 while (sortedCollection[left].compareTo(mid) < 0) {
1489 while (mid.compareTo(sortedCollection[right]) < 0) {
1492 if (left <= right) {
1493 String tmp = sortedCollection[left];
1494 sortedCollection[left] = sortedCollection[right];
1495 sortedCollection[right] = tmp;
1499 } while (left <= right);
1500 if (original_left < right) {
1501 quickSort(sortedCollection, original_left, right);
1503 if (left < original_right) {
1504 quickSort(sortedCollection, left, original_right);
1509 * Sort the strings in the given collection in reverse alphabetical order.
1511 private static void quickSortReverse(String[] sortedCollection, int left,
1513 int original_left = left;
1514 int original_right = right;
1515 String mid = sortedCollection[(left + right) / 2];
1517 while (sortedCollection[left].compareTo(mid) > 0) {
1520 while (mid.compareTo(sortedCollection[right]) > 0) {
1523 if (left <= right) {
1524 String tmp = sortedCollection[left];
1525 sortedCollection[left] = sortedCollection[right];
1526 sortedCollection[right] = tmp;
1530 } while (left <= right);
1531 if (original_left < right) {
1532 quickSortReverse(sortedCollection, original_left, right);
1534 if (left < original_right) {
1535 quickSortReverse(sortedCollection, left, original_right);
1540 * Reads in a string from the specified data input stream. The string has
1541 * been encoded using a modified UTF-8 format.
1543 * The first two bytes are read as if by <code>readUnsignedShort</code>.
1544 * This value gives the number of following bytes that are in the encoded
1545 * string, not the length of the resulting string. The following bytes are
1546 * then interpreted as bytes encoding characters in the UTF-8 format and are
1547 * converted into characters.
1549 * This method blocks until all the bytes are read, the end of the stream is
1550 * detected, or an exception is thrown.
1553 * a data input stream.
1554 * @return a Unicode string.
1555 * @exception EOFException
1556 * if the input stream reaches the end before all the bytes.
1557 * @exception IOException
1558 * if an I/O error occurs.
1559 * @exception UTFDataFormatException
1560 * if the bytes do not represent a valid UTF-8 encoding of a
1562 * @see java.io.DataInputStream#readUnsignedShort()
1564 public final static char[] readUTF(DataInput in) throws IOException {
1565 int utflen = in.readUnsignedShort();
1566 char str[] = new char[utflen];
1569 while (count < utflen) {
1570 int c = in.readUnsignedByte();
1583 str[strlen++] = (char) c;
1587 // 110x xxxx 10xx xxxx
1590 throw new UTFDataFormatException();
1591 char2 = in.readUnsignedByte();
1592 if ((char2 & 0xC0) != 0x80)
1593 throw new UTFDataFormatException();
1594 str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
1597 // 1110 xxxx 10xx xxxx 10xx xxxx
1600 throw new UTFDataFormatException();
1601 char2 = in.readUnsignedByte();
1602 char3 = in.readUnsignedByte();
1603 if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
1604 throw new UTFDataFormatException();
1605 str[strlen++] = (char) (((c & 0x0F) << 12)
1606 | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
1609 // 10xx xxxx, 1111 xxxx
1610 throw new UTFDataFormatException();
1613 if (strlen < utflen) {
1614 System.arraycopy(str, 0, str = new char[strlen], 0, strlen);
1620 * Creates a NLS catalog for the given locale.
1622 public static void relocalize() {
1624 bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
1625 } catch (MissingResourceException e) {
1627 .println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
1632 public static void sort(char[][] list) {
1633 if (list.length > 1)
1634 quickSort(list, 0, list.length - 1);
1638 * Sorts an array of Comparable objects in place.
1640 public static void sort(Comparable[] objects) {
1641 if (objects.length > 1)
1642 quickSort(objects, 0, objects.length - 1);
1645 public static void sort(int[] list) {
1646 if (list.length > 1)
1647 quickSort(list, 0, list.length - 1);
1651 * Sorts an array of objects in place. The given comparer compares pairs of
1654 public static void sort(Object[] objects, Comparer comparer) {
1655 if (objects.length > 1)
1656 quickSort(objects, 0, objects.length - 1, comparer);
1660 * Sorts an array of objects in place, using the sort order given for each
1663 public static void sort(Object[] objects, int[] sortOrder) {
1664 if (objects.length > 1)
1665 quickSort(objects, 0, objects.length - 1, sortOrder);
1669 * Sorts an array of strings in place using quicksort.
1671 public static void sort(String[] strings) {
1672 if (strings.length > 1)
1673 quickSort(strings, 0, strings.length - 1);
1677 * Sorts an array of Comparable objects, returning a new array with the
1678 * sorted items. The original array is left untouched.
1680 public static Comparable[] sortCopy(Comparable[] objects) {
1681 int len = objects.length;
1682 Comparable[] copy = new Comparable[len];
1683 System.arraycopy(objects, 0, copy, 0, len);
1689 * Sorts an array of Strings, returning a new array with the sorted items.
1690 * The original array is left untouched.
1692 public static Object[] sortCopy(Object[] objects, Comparer comparer) {
1693 int len = objects.length;
1694 Object[] copy = new Object[len];
1695 System.arraycopy(objects, 0, copy, 0, len);
1696 sort(copy, comparer);
1701 * Sorts an array of Strings, returning a new array with the sorted items.
1702 * The original array is left untouched.
1704 public static String[] sortCopy(String[] objects) {
1705 int len = objects.length;
1706 String[] copy = new String[len];
1707 System.arraycopy(objects, 0, copy, 0, len);
1713 * Sorts an array of strings in place using quicksort in reverse
1714 * alphabetical order.
1716 public static void sortReverseOrder(String[] strings) {
1717 if (strings.length > 1)
1718 quickSortReverse(strings, 0, strings.length - 1);
1722 * Converts a String[] to char[][].
1724 public static char[][] toCharArrays(String[] a) {
1726 char[][] result = new char[len][];
1727 for (int i = 0; i < len; ++i) {
1728 result[i] = toChars(a[i]);
1734 * Converts a String to char[].
1736 public static char[] toChars(String s) {
1737 int len = s.length();
1738 char[] chars = new char[len];
1739 s.getChars(0, len, chars, 0);
1744 * Converts a String to char[][], where segments are separate by '.'.
1746 public static char[][] toCompoundChars(String s) {
1747 int len = s.length();
1749 return CharOperation.NO_CHAR_CHAR;
1752 for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
1755 char[][] segs = new char[segCount][];
1757 for (int i = 0; i < segCount; ++i) {
1758 int dot = s.indexOf('.', start);
1759 int end = (dot == -1 ? s.length() : dot);
1760 segs[i] = new char[end - start];
1761 s.getChars(start, end, segs[i], 0);
1768 * Converts a char[] to String.
1770 public static String toString(char[] c) {
1771 return new String(c);
1775 * Converts a char[][] to String, where segments are separated by '.'.
1777 public static String toString(char[][] c) {
1778 StringBuffer sb = new StringBuffer();
1779 for (int i = 0, max = c.length; i < max; ++i) {
1784 return sb.toString();
1788 * Converts a char[][] and a char[] to String, where segments are separated
1791 public static String toString(char[][] c, char[] d) {
1793 return new String(d);
1794 StringBuffer sb = new StringBuffer();
1795 for (int i = 0, max = c.length; i < max; ++i) {
1800 return sb.toString();
1804 * Returns the unresolved type parameter signatures of the given method e.g.
1805 * {"QString;", "[int", "[[Qjava.util.Vector;"}
1807 // public static String[] typeParameterSignatures(AbstractMethodDeclaration
1809 // Argument[] args = method.arguments;
1810 // if (args != null) {
1811 // int length = args.length;
1812 // String[] signatures = new String[length];
1813 // for (int i = 0; i < args.length; i++) {
1814 // Argument arg = args[i];
1815 // signatures[i] = typeSignature(arg.type);
1817 // return signatures;
1819 // return new String[0];
1822 * Returns the unresolved type signature of the given type reference, e.g.
1823 * "QString;", "[int", "[[Qjava.util.Vector;"
1825 // public static String typeSignature(TypeReference type) {
1826 // char[][] compoundName = type.getTypeName();
1827 // char[] typeName =CharOperation.concatWith(compoundName, '.');
1828 // String signature = Signature.createTypeSignature(typeName, false/*don't
1830 // int dimensions = type.dimensions();
1831 // if (dimensions > 0) {
1832 // signature = Signature.createArraySignature(signature, dimensions);
1834 // return signature;
1837 * Returns the unresolved type signature of the given type reference, e.g.
1838 * "QString;", "[int", "[[Qjava.util.Vector;"
1840 public static String typeSignature(TypeReference type) {
1841 char[][] compoundName = type.getTypeName();
1842 char[] typeName = CharOperation.concatWith(compoundName, '.');
1843 String signature = Signature
1844 .createTypeSignature(typeName, false/* don't resolve */);
1845 int dimensions = type.dimensions();
1846 if (dimensions > 0) {
1847 signature = Signature.createArraySignature(signature, dimensions);
1853 * Asserts that the given method signature is valid.
1855 public static void validateMethodSignature(String sig) {
1856 Assert.isTrue(isValidMethodSignature(sig));
1860 * Asserts that the given type signature is valid.
1862 public static void validateTypeSignature(String sig, boolean allowVoid) {
1863 Assert.isTrue(isValidTypeSignature(sig, allowVoid));
1866 public static void verbose(String log) {
1867 verbose(log, System.out);
1870 public static synchronized void verbose(String log, PrintStream printStream) {
1873 int end = log.indexOf('\n', start);
1874 printStream.print(Thread.currentThread());
1875 printStream.print(" "); //$NON-NLS-1$
1876 printStream.print(log.substring(start, end == -1 ? log.length()
1879 } while (start != 0);
1880 printStream.println();
1884 * Writes a string to the given output stream using UTF-8 encoding in a
1885 * machine-independent manner.
1887 * First, two bytes are written to the output stream as if by the
1888 * <code>writeShort</code> method giving the number of bytes to follow.
1889 * This value is the number of bytes actually written out, not the length of
1890 * the string. Following the length, each character of the string is output,
1891 * in sequence, using the UTF-8 encoding for the character.
1894 * a string to be written.
1895 * @return the number of bytes written to the stream.
1896 * @exception IOException
1897 * if an I/O error occurs.
1900 public static int writeUTF(OutputStream out, char[] str) throws IOException {
1901 int strlen = str.length;
1903 for (int i = 0; i < strlen; i++) {
1905 if ((c >= 0x0001) && (c <= 0x007F)) {
1907 } else if (c > 0x07FF) {
1914 throw new UTFDataFormatException();
1915 out.write((utflen >>> 8) & 0xFF);
1916 out.write((utflen >>> 0) & 0xFF);
1917 if (strlen == utflen) {
1918 for (int i = 0; i < strlen; i++)
1921 for (int i = 0; i < strlen; i++) {
1923 if ((c >= 0x0001) && (c <= 0x007F)) {
1925 } else if (c > 0x07FF) {
1926 out.write(0xE0 | ((c >> 12) & 0x0F));
1927 out.write(0x80 | ((c >> 6) & 0x3F));
1928 out.write(0x80 | ((c >> 0) & 0x3F));
1930 out.write(0xC0 | ((c >> 6) & 0x1F));
1931 out.write(0x80 | ((c >> 0) & 0x3F));
1935 return utflen + 2; // the number of bytes written to the stream