/******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.core.util; import java.io.BufferedInputStream; import java.io.DataInput; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.UTFDataFormatException; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.StringTokenizer; import net.sourceforge.phpdt.core.IJavaElement; import net.sourceforge.phpdt.core.IJavaModelStatusConstants; import net.sourceforge.phpdt.core.IPackageFragment; import net.sourceforge.phpdt.core.JavaCore; import net.sourceforge.phpdt.core.JavaModelException; import net.sourceforge.phpdt.core.Signature; import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; import net.sourceforge.phpdt.internal.core.Assert; import net.sourceforge.phpdt.internal.core.PackageFragmentRoot; import net.sourceforge.phpdt.internal.core.util.PHPFileUtil; import org.eclipse.core.resources.IFile; //import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; //import org.eclipse.jface.text.BadLocationException; //import org.eclipse.text.edits.MalformedTreeException; //import org.eclipse.text.edits.TextEdit; /** * Provides convenient utility methods to other types in this package. */ public class Util { public interface Comparable { /** * Returns 0 if this and c are equal, >0 if this is greater than c, or * <0 if this is less than c. */ int compareTo(Comparable c); } public interface Comparer { /** * Returns 0 if a and b are equal, >0 if a is greater than b, or <0 if a * is less than b. */ int compare(Object a, Object b); } private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$ /* Bundle containing messages */ protected static ResourceBundle bundle; private final static String bundleName = "net.sourceforge.phpdt.internal.core.util.messages"; //$NON-NLS-1$ private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$ private static final String EMPTY_ARGUMENT = " "; //$NON-NLS-1$ public static final String[] fgEmptyStringArray = new String[0]; private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$ static { relocalize(); } private Util() { // cannot be instantiated } /** * Lookup the message with the given ID in this catalog */ public static String bind(String id) { return bind(id, (String[]) null); } /** * Lookup the message with the given ID in this catalog and bind its * substitution locations with the given string. */ public static String bind(String id, String binding) { return bind(id, new String[] { binding }); } /** * Lookup the message with the given ID in this catalog and bind its * substitution locations with the given strings. */ public static String bind(String id, String binding1, String binding2) { return bind(id, new String[] { binding1, binding2 }); } /** * Lookup the message with the given ID in this catalog and bind its * substitution locations with the given string values. */ public static String bind(String id, String[] bindings) { if (id == null) return "No message available"; //$NON-NLS-1$ String message = null; try { message = bundle.getString(id); } catch (MissingResourceException e) { // If we got an exception looking for the message, fail gracefully // by just returning // the id we were looking for. In most cases this is // semi-informative so is not too bad. return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$ } // for compatibility with MessageFormat which eliminates double quotes // in original message char[] messageWithNoDoubleQuotes = CharOperation.replace(message .toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE); if (bindings == null) return new String(messageWithNoDoubleQuotes); int length = messageWithNoDoubleQuotes.length; int start = 0; int end = length; StringBuffer output = null; while (true) { if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start)) > -1) { if (output == null) output = new StringBuffer(length + bindings.length * 20); output.append(messageWithNoDoubleQuotes, start, end - start); if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes, end + 1)) > -1) { int index = -1; String argId = new String(messageWithNoDoubleQuotes, end + 1, start - end - 1); try { index = Integer.parseInt(argId); output.append(bindings[index]); } catch (NumberFormatException nfe) { // could be nested // message ID // {compiler.name} boolean done = false; if (!id.equals(argId)) { String argMessage = null; try { argMessage = bundle.getString(argId); output.append(argMessage); done = true; } catch (MissingResourceException e) { // unable to bind argument, ignore (will leave // argument in) } } if (!done) output.append(messageWithNoDoubleQuotes, end + 1, start - end); } catch (ArrayIndexOutOfBoundsException e) { output .append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$ } start++; } else { output.append(messageWithNoDoubleQuotes, end, length); break; } } else { if (output == null) return new String(messageWithNoDoubleQuotes); output.append(messageWithNoDoubleQuotes, start, length - start); break; } } return output.toString(); } /** * Checks the type signature in String sig, starting at start and ending * before end (end is not included). Returns the index of the character * immediately after the signature if valid, or -1 if not valid. */ private static int checkTypeSignature(String sig, int start, int end, boolean allowVoid) { if (start >= end) return -1; int i = start; char c = sig.charAt(i++); int nestingDepth = 0; while (c == '[') { ++nestingDepth; if (i >= end) return -1; c = sig.charAt(i++); } switch (c) { case 'B': case 'C': case 'D': case 'F': case 'I': case 'J': case 'S': case 'Z': break; case 'V': if (!allowVoid) return -1; // array of void is not allowed if (nestingDepth != 0) return -1; break; case 'L': int semicolon = sig.indexOf(';', i); // Must have at least one character between L and ; if (semicolon <= i || semicolon >= end) return -1; i = semicolon + 1; break; default: return -1; } return i; } /** * Combines two hash codes to make a new one. */ public static int combineHashCodes(int hashCode1, int hashCode2) { return hashCode1 * 17 + hashCode2; } /** * Compares two byte arrays. Returns <0 if a byte in a is less than the * corresponding byte in b, or if a is shorter, or if a is null. Returns >0 * if a byte in a is greater than the corresponding byte in b, or if a is * longer, or if b is null. Returns 0 if they are equal or both null. */ public static int compare(byte[] a, byte[] b) { if (a == b) return 0; if (a == null) return -1; if (b == null) return 1; int len = Math.min(a.length, b.length); for (int i = 0; i < len; ++i) { int diff = a[i] - b[i]; if (diff != 0) return diff; } if (a.length > len) return 1; if (b.length > len) return -1; return 0; } /** * Compares two strings lexicographically. The comparison is based on the * Unicode value of each character in the strings. * * @return the value 0 if the str1 is equal to str2; a value * less than 0 if str1 is lexicographically less than * str2; and a value greater than 0 if str1 is * lexicographically greater than str2. */ public static int compare(char[] str1, char[] str2) { int len1 = str1.length; int len2 = str2.length; int n = Math.min(len1, len2); int i = 0; while (n-- != 0) { char c1 = str1[i]; char c2 = str2[i++]; if (c1 != c2) { return c1 - c2; } } return len1 - len2; } /** * Concatenate two strings with a char in between. * * @see #concat(String, String) */ public static String concat(String s1, char c, String s2) { if (s1 == null) s1 = "null"; //$NON-NLS-1$ if (s2 == null) s2 = "null"; //$NON-NLS-1$ int l1 = s1.length(); int l2 = s2.length(); char[] buf = new char[l1 + 1 + l2]; s1.getChars(0, l1, buf, 0); buf[l1] = c; s2.getChars(0, l2, buf, l1 + 1); return new String(buf); } /** * Concatenate two strings. Much faster than using +, which: - creates a * StringBuffer, - which is synchronized, - of default size, so the * resulting char array is often larger than needed. This implementation * creates an extra char array, since the String constructor copies its * argument, but there's no way around this. */ public static String concat(String s1, String s2) { if (s1 == null) s1 = "null"; //$NON-NLS-1$ if (s2 == null) s2 = "null"; //$NON-NLS-1$ int l1 = s1.length(); int l2 = s2.length(); char[] buf = new char[l1 + l2]; s1.getChars(0, l1, buf, 0); s2.getChars(0, l2, buf, l1); return new String(buf); } /** * Concatenate three strings. * * @see #concat(String, String) */ public static String concat(String s1, String s2, String s3) { if (s1 == null) s1 = "null"; //$NON-NLS-1$ if (s2 == null) s2 = "null"; //$NON-NLS-1$ if (s3 == null) s3 = "null"; //$NON-NLS-1$ int l1 = s1.length(); int l2 = s2.length(); int l3 = s3.length(); char[] buf = new char[l1 + l2 + l3]; s1.getChars(0, l1, buf, 0); s2.getChars(0, l2, buf, l1); s3.getChars(0, l3, buf, l1 + l2); return new String(buf); } /** * Converts a type signature from the IBinaryType representation to the DC * representation. */ public static String convertTypeSignature(char[] sig) { return new String(sig).replace('/', '.'); } /** * Apply the given edit on the given string and return the updated string. * Return the given string if anything wrong happen while applying the edit. * * @param original * the given string * @param edit * the given edit * * @return the updated string */ // public final static String editedString(String original, TextEdit edit) { // if (edit == null) { // return original; // } // SimpleDocument document = new SimpleDocument(original); // try { // edit.apply(document, TextEdit.NONE); // return document.get(); // } catch (MalformedTreeException e) { // e.printStackTrace(); // } catch (BadLocationException e) { // e.printStackTrace(); // } // return original; // } /** * Returns true iff str.toLowerCase().endsWith(end.toLowerCase()) * implementation is not creating extra strings. */ public final static boolean endsWithIgnoreCase(String str, String end) { int strLength = str == null ? 0 : str.length(); int endLength = end == null ? 0 : end.length(); // return false if the string is smaller than the end. if (endLength > strLength) return false; // return false if any character of the end are // not the same in lower case. for (int i = 1; i <= endLength; i++) { if (Character.toLowerCase(end.charAt(endLength - i)) != Character .toLowerCase(str.charAt(strLength - i))) return false; } return true; } /** * Compares two arrays using equals() on the elements. Either or both arrays * may be null. Returns true if both are null. Returns false if only one is * null. If both are arrays, returns true iff they have the same length and * all elements are equal. */ public static boolean equalArraysOrNull(int[] a, int[] b) { if (a == b) return true; if (a == null || b == null) return false; int len = a.length; if (len != b.length) return false; for (int i = 0; i < len; ++i) { if (a[i] != b[i]) return false; } return true; } /** * Compares two arrays using equals() on the elements. Either or both arrays * may be null. Returns true if both are null. Returns false if only one is * null. If both are arrays, returns true iff they have the same length and * all elements compare true with equals. */ public static boolean equalArraysOrNull(Object[] a, Object[] b) { if (a == b) return true; if (a == null || b == null) return false; int len = a.length; if (len != b.length) return false; for (int i = 0; i < len; ++i) { if (a[i] == null) { if (b[i] != null) return false; } else { if (!a[i].equals(b[i])) return false; } } return true; } /** * Compares two arrays using equals() on the elements. The arrays are first * sorted. Either or both arrays may be null. Returns true if both are null. * Returns false if only one is null. If both are arrays, returns true iff * they have the same length and iff, after sorting both arrays, all * elements compare true with equals. The original arrays are left * untouched. */ public static boolean equalArraysOrNullSortFirst(Comparable[] a, Comparable[] b) { if (a == b) return true; if (a == null || b == null) return false; int len = a.length; if (len != b.length) return false; if (len >= 2) { // only need to sort if more than two items a = sortCopy(a); b = sortCopy(b); } for (int i = 0; i < len; ++i) { if (!a[i].equals(b[i])) return false; } return true; } /** * Compares two String arrays using equals() on the elements. The arrays are * first sorted. Either or both arrays may be null. Returns true if both are * null. Returns false if only one is null. If both are arrays, returns true * iff they have the same length and iff, after sorting both arrays, all * elements compare true with equals. The original arrays are left * untouched. */ public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) { if (a == b) return true; if (a == null || b == null) return false; int len = a.length; if (len != b.length) return false; if (len >= 2) { // only need to sort if more than two items a = sortCopy(a); b = sortCopy(b); } for (int i = 0; i < len; ++i) { if (!a[i].equals(b[i])) return false; } return true; } /** * Compares two objects using equals(). Either or both array may be null. * Returns true if both are null. Returns false if only one is null. * Otherwise, return the result of comparing with equals(). */ public static boolean equalOrNull(Object a, Object b) { if (a == b) { return true; } if (a == null || b == null) { return false; } return a.equals(b); } /** * Given a qualified name, extract the last component. If the input is not * qualified, the same string is answered. */ public static String extractLastName(String qualifiedName) { int i = qualifiedName.lastIndexOf('.'); if (i == -1) return qualifiedName; return qualifiedName.substring(i + 1); } /** * Extracts the parameter types from a method signature. */ public static String[] extractParameterTypes(char[] sig) { int count = getParameterCount(sig); String[] result = new String[count]; if (count == 0) return result; int i = CharOperation.indexOf('(', sig) + 1; count = 0; int len = sig.length; int start = i; for (;;) { if (i == len) break; char c = sig[i]; if (c == ')') break; if (c == '[') { ++i; } else if (c == 'L') { i = CharOperation.indexOf(';', sig, i + 1) + 1; Assert.isTrue(i != 0); result[count++] = convertTypeSignature(CharOperation.subarray( sig, start, i)); start = i; } else { ++i; result[count++] = convertTypeSignature(CharOperation.subarray( sig, start, i)); start = i; } } return result; } /** * Extracts the return type from a method signature. */ public static String extractReturnType(String sig) { int i = sig.lastIndexOf(')'); Assert.isTrue(i != -1); return sig.substring(i + 1); } // private static IFile findFirstClassFile(IFolder folder) { // try { // IResource[] members = folder.members(); // for (int i = 0, max = members.length; i < max; i++) { // IResource member = members[i]; // if (member.getType() == IResource.FOLDER) { // return findFirstClassFile((IFolder) member); // // } else if // // (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(member.getName())) // // { // // return (IFile) member; // } // } // } catch (CoreException e) { // // ignore // } // return null; // } /** * Finds the first line separator used by the given text. * * @return "\n" or "\r" or "\r\n", * or null if none found */ public static String findLineSeparator(char[] text) { // find the first line separator int length = text.length; if (length > 0) { char nextChar = text[0]; for (int i = 0; i < length; i++) { char currentChar = nextChar; nextChar = i < length - 1 ? text[i + 1] : ' '; switch (currentChar) { case '\n': return "\n"; //$NON-NLS-1$ case '\r': return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$ } } } // not found return null; } // public static IClassFileAttribute getAttribute(IClassFileReader // classFileReader, char[] attributeName) { // IClassFileAttribute[] attributes = classFileReader.getAttributes(); // for (int i = 0, max = attributes.length; i < max; i++) { // if (CharOperation.equals(attributes[i].getAttributeName(), // attributeName)) { // return attributes[i]; // } // } // return null; // } // // public static IClassFileAttribute getAttribute(ICodeAttribute // codeAttribute, char[] attributeName) { // IClassFileAttribute[] attributes = codeAttribute.getAttributes(); // for (int i = 0, max = attributes.length; i < max; i++) { // if (CharOperation.equals(attributes[i].getAttributeName(), // attributeName)) { // return attributes[i]; // } // } // return null; // } // public static IClassFileAttribute getAttribute(IFieldInfo fieldInfo, // char[] attributeName) { // IClassFileAttribute[] attributes = fieldInfo.getAttributes(); // for (int i = 0, max = attributes.length; i < max; i++) { // if (CharOperation.equals(attributes[i].getAttributeName(), // attributeName)) { // return attributes[i]; // } // } // return null; // } // // public static IClassFileAttribute getAttribute(IMethodInfo methodInfo, // char[] attributeName) { // IClassFileAttribute[] attributes = methodInfo.getAttributes(); // for (int i = 0, max = attributes.length; i < max; i++) { // if (CharOperation.equals(attributes[i].getAttributeName(), // attributeName)) { // return attributes[i]; // } // } // return null; // } /** * Get the jdk level of this root. The value can be: * * Returns the jdk level */ // public static long getJdkLevel(Object targetLibrary) { // try { // ClassFileReader reader = null; // if (targetLibrary instanceof IFolder) { // IFile classFile = findFirstClassFile((IFolder) targetLibrary); // only // internal classfolders are allowed // if (classFile != null) { // byte[] bytes = Util.getResourceContentsAsByteArray(classFile); // IPath location = classFile.getLocation(); // reader = new ClassFileReader(bytes, location == null ? null : // location.toString().toCharArray()); // } // } else { // // root is a jar file or a zip file // ZipFile jar = null; // try { // IPath path = null; // if (targetLibrary instanceof IResource) { // path = ((IResource)targetLibrary).getLocation(); // } else if (targetLibrary instanceof File){ // File f = (File) targetLibrary; // if (!f.isDirectory()) { // path = new Path(((File)targetLibrary).getPath()); // } // } // if (path != null) { // jar = JavaModelManager.getJavaModelManager().getZipFile(path); // for (Enumeration e= jar.entries(); e.hasMoreElements();) { // ZipEntry member= (ZipEntry) e.nextElement(); // String entryName= member.getName(); // if // (net.sourceforge.phpdt.internal.compiler.util.Util.isClassFileName(entryName)) // { // reader = ClassFileReader.read(jar, entryName); // break; // } // } // } // } catch (CoreException e) { // // ignore // } finally { // JavaModelManager.getJavaModelManager().closeZipFile(jar); // } // } // if (reader != null) { // return reader.getVersion(); // } // } catch(JavaModelException e) { // // ignore // } catch(ClassFormatException e) { // // ignore // } catch(IOException e) { // // ignore // } // return 0; // } /** * Returns the line separator used by the given buffer. Uses the given text * if none found. * * @return "\n" or "\r" or "\r\n" */ private static String getLineSeparator(char[] text, char[] buffer) { // search in this buffer's contents first String lineSeparator = findLineSeparator(buffer); if (lineSeparator == null) { // search in the given text lineSeparator = findLineSeparator(text); if (lineSeparator == null) { // default to system line separator return net.sourceforge.phpdt.internal.compiler.util.Util.LINE_SEPARATOR; } } return lineSeparator; } /** * Returns the number of parameter types in a method signature. */ public static int getParameterCount(char[] sig) { int i = CharOperation.indexOf('(', sig) + 1; Assert.isTrue(i != 0); int count = 0; int len = sig.length; for (;;) { if (i == len) break; char c = sig[i]; if (c == ')') break; if (c == '[') { ++i; } else if (c == 'L') { ++count; i = CharOperation.indexOf(';', sig, i + 1) + 1; Assert.isTrue(i != 0); } else { ++count; ++i; } } return count; } /** * Put all the arguments in one String. */ public static String getProblemArgumentsForMarker(String[] arguments) { StringBuffer args = new StringBuffer(10); args.append(arguments.length); args.append(':'); for (int j = 0; j < arguments.length; j++) { if (j != 0) args.append(ARGUMENTS_DELIMITER); if (arguments[j].length() == 0) { args.append(EMPTY_ARGUMENT); } else { args.append(arguments[j]); } } return args.toString(); } /** * Separate all the arguments of a String made by * getProblemArgumentsForMarker */ public static String[] getProblemArgumentsFromMarker(String argumentsString) { if (argumentsString == null) return null; int index = argumentsString.indexOf(':'); if (index == -1) return null; int length = argumentsString.length(); int numberOfArg; try { numberOfArg = Integer.parseInt(argumentsString.substring(0, index)); } catch (NumberFormatException e) { return null; } argumentsString = argumentsString.substring(index + 1, length); String[] args = new String[length]; int count = 0; StringTokenizer tokenizer = new StringTokenizer(argumentsString, ARGUMENTS_DELIMITER); while (tokenizer.hasMoreTokens()) { String argument = tokenizer.nextToken(); if (argument.equals(EMPTY_ARGUMENT)) argument = ""; //$NON-NLS-1$ args[count++] = argument; } if (count != numberOfArg) return null; System.arraycopy(args, 0, args = new String[count], 0, count); return args; } /** * Returns the given file's contents as a byte array. */ public static byte[] getResourceContentsAsByteArray(IFile file) throws JavaModelException { InputStream stream = null; try { stream = new BufferedInputStream(file.getContents(true)); } catch (CoreException e) { throw new JavaModelException(e); } try { return net.sourceforge.phpdt.internal.compiler.util.Util .getInputStreamAsByteArray(stream, -1); } catch (IOException e) { throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION); } finally { try { stream.close(); } catch (IOException e) { // ignore } } } /** * Returns the given file's contents as a character array. */ public static char[] getResourceContentsAsCharArray(IFile file) throws JavaModelException { // Get encoding from file String encoding = null; try { encoding = file.getCharset(); } catch (CoreException ce) { // do not use any encoding } return getResourceContentsAsCharArray(file, encoding); } public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException { // Get resource contents InputStream stream = null; try { stream = new BufferedInputStream(file.getContents(true)); } catch (CoreException e) { throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST); } try { return net.sourceforge.phpdt.internal.compiler.util.Util .getInputStreamAsCharArray(stream, -1, encoding); } catch (IOException e) { throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION); } finally { try { stream.close(); } catch (IOException e) { // ignore } } } /** * Returns a trimmed version the simples names returned by Signature. */ public static String[] getTrimmedSimpleNames(String name) { String[] result = Signature.getSimpleNames(name); if (result == null) return null; for (int i = 0, length = result.length; i < length; i++) { result[i] = result[i].trim(); } return result; } /* * Returns the index of the most specific argument paths which is strictly * enclosing the path to check */ public static int indexOfEnclosingPath(IPath checkedPath, IPath[] paths, int pathCount) { int bestMatch = -1, bestLength = -1; for (int i = 0; i < pathCount; i++) { if (paths[i].equals(checkedPath)) continue; if (paths[i].isPrefixOf(checkedPath)) { int currentLength = paths[i].segmentCount(); if (currentLength > bestLength) { bestLength = currentLength; bestMatch = i; } } } return bestMatch; } /* * Returns the index of the first argument paths which is equal to the path * to check */ public static int indexOfMatchingPath(IPath checkedPath, IPath[] paths, int pathCount) { for (int i = 0; i < pathCount; i++) { if (paths[i].equals(checkedPath)) return i; } return -1; } /* * Returns the index of the first argument paths which is strictly nested * inside the path to check */ public static int indexOfNestedPath(IPath checkedPath, IPath[] paths, int pathCount) { for (int i = 0; i < pathCount; i++) { if (checkedPath.equals(paths[i])) continue; if (checkedPath.isPrefixOf(paths[i])) return i; } return -1; } /* * Returns whether the given java element is exluded from its root's * classpath. It doesn't check whether the root itself is on the classpath * or not */ public static final boolean isExcluded(IJavaElement element) { int elementType = element.getElementType(); PackageFragmentRoot root = null; IResource resource = null; switch (elementType) { case IJavaElement.JAVA_MODEL: case IJavaElement.JAVA_PROJECT: case IJavaElement.PACKAGE_FRAGMENT_ROOT: return false; // case IJavaElement.PACKAGE_FRAGMENT: // PackageFragmentRoot root = // (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); // IResource resource = element.getResource(); // return resource != null && isExcluded(resource, // root.fullInclusionPatternChars(), // root.fullExclusionPatternChars()); case IJavaElement.COMPILATION_UNIT: root = (PackageFragmentRoot) element .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); resource = element.getResource(); // if (resource != null && isExcluded(resource, // root.fullInclusionPatternChars(), // root.fullExclusionPatternChars())) // return true; return isExcluded(element.getParent()); default: IJavaElement cu = element .getAncestor(IJavaElement.COMPILATION_UNIT); return cu != null && isExcluded(cu); } } /* * Returns whether the given resource path matches one of the * inclusion/exclusion patterns. NOTE: should not be asked directly using * pkg root pathes * * @see IClasspathEntry#getInclusionPatterns * @see IClasspathEntry#getExclusionPatterns */ public final static boolean isExcluded(IPath resourcePath, char[][] inclusionPatterns, char[][] exclusionPatterns, boolean isFolderPath) { if (inclusionPatterns == null && exclusionPatterns == null) return false; char[] path = resourcePath.toString().toCharArray(); inclusionCheck: if (inclusionPatterns != null) { for (int i = 0, length = inclusionPatterns.length; i < length; i++) { char[] pattern = inclusionPatterns[i]; char[] folderPattern = pattern; if (isFolderPath) { int lastSlash = CharOperation.lastIndexOf('/', pattern); if (lastSlash != -1 && lastSlash != pattern.length - 1) { // trailing // slash // -> // adds // '**' // for // free // (see // http://ant.apache.org/manual/dirtasks.html) int star = CharOperation.indexOf('*', pattern, lastSlash); if ((star == -1 || star >= pattern.length - 1 || pattern[star + 1] != '*')) { folderPattern = CharOperation.subarray(pattern, 0, lastSlash); } } } if (CharOperation.pathMatch(folderPattern, path, true, '/')) { break inclusionCheck; } } return true; // never included } if (isFolderPath) { path = CharOperation.concat(path, new char[] { '*' }, '/'); } exclusionCheck: if (exclusionPatterns != null) { for (int i = 0, length = exclusionPatterns.length; i < length; i++) { if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/')) { return true; } } } return false; } public final static boolean isExcluded(IResource resource, char[][] exclusionPatterns) { IPath path = resource.getFullPath(); // ensure that folders are only excluded if all of their children are // excluded return isExcluded(path, null, exclusionPatterns, resource.getType() == IResource.FOLDER); } /* * Returns whether the given resource matches one of the exclusion patterns. * NOTE: should not be asked directly using pkg root pathes * * @see IClasspathEntry#getExclusionPatterns */ public final static boolean isExcluded(IResource resource, char[][] inclusionPatterns, char[][] exclusionPatterns) { IPath path = resource.getFullPath(); // ensure that folders are only excluded if all of their children are // excluded return isExcluded(path, inclusionPatterns, exclusionPatterns, resource .getType() == IResource.FOLDER); } /** * Validate the given .class file name. A .class file name must obey the * following rules: * *

* * @param name * the name of a .class file * @return a status object with code IStatus.OK if the given * name is valid as a .class file name, otherwise a status object * indicating what is wrong with the name */ // public static boolean isValidClassFileName(String name) { // return JavaConventions.validateClassFileName(name).getSeverity() != // IStatus.ERROR; // } /** * Validate the given compilation unit name. A compilation unit name must * obey the following rules: * *

* * @param name * the name of a compilation unit * @return a status object with code IStatus.OK if the given * name is valid as a compilation unit name, otherwise a status * object indicating what is wrong with the name */ public static boolean isValidCompilationUnitName(String name) { return PHPFileUtil.isPHPFileName(name); // return // JavaConventions.validateCompilationUnitName(name).getSeverity() != // IStatus.ERROR; } /** * Returns true if the given folder name is valid for a package, false if it * is not. */ public static boolean isValidFolderNameForPackage(String folderName) { // return JavaConventions.validateIdentifier(folderName).getSeverity() // != IStatus.ERROR; return true; } /** * Returns true if the given method signature is valid, false if it is not. */ public static boolean isValidMethodSignature(String sig) { int len = sig.length(); if (len == 0) return false; int i = 0; char c = sig.charAt(i++); if (c != '(') return false; if (i >= len) return false; while (sig.charAt(i) != ')') { // Void is not allowed as a parameter type. i = checkTypeSignature(sig, i, len, false); if (i == -1) return false; if (i >= len) return false; } ++i; i = checkTypeSignature(sig, i, len, true); return i == len; } /** * Returns true if the given type signature is valid, false if it is not. */ public static boolean isValidTypeSignature(String sig, boolean allowVoid) { int len = sig.length(); return checkTypeSignature(sig, 0, len, allowVoid) == len; } /* * Add a log entry */ public static void log(Throwable e, String message) { Throwable nestedException; if (e instanceof JavaModelException && (nestedException = ((JavaModelException) e).getException()) != null) { e = nestedException; } IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, message, e); JavaCore.getPlugin().getLog().log(status); } /** * Normalizes the cariage returns in the given text. They are all changed to * use the given buffer's line separator. */ public static char[] normalizeCRs(char[] text, char[] buffer) { CharArrayBuffer result = new CharArrayBuffer(); int lineStart = 0; int length = text.length; if (length == 0) return text; String lineSeparator = getLineSeparator(text, buffer); char nextChar = text[0]; for (int i = 0; i < length; i++) { char currentChar = nextChar; nextChar = i < length - 1 ? text[i + 1] : ' '; switch (currentChar) { case '\n': int lineLength = i - lineStart; char[] line = new char[lineLength]; System.arraycopy(text, lineStart, line, 0, lineLength); result.append(line); result.append(lineSeparator); lineStart = i + 1; break; case '\r': lineLength = i - lineStart; if (lineLength >= 0) { line = new char[lineLength]; System.arraycopy(text, lineStart, line, 0, lineLength); result.append(line); result.append(lineSeparator); if (nextChar == '\n') { nextChar = ' '; lineStart = i + 2; } else { // when line separator are mixed in the same file // \r might not be followed by a \n. If not, we should // increment // lineStart by one and not by two. lineStart = i + 1; } } else { // when line separator are mixed in the same file // we need to prevent NegativeArraySizeException lineStart = i + 1; } break; } } char[] lastLine; if (lineStart > 0) { int lastLineLength = length - lineStart; if (lastLineLength > 0) { lastLine = new char[lastLineLength]; System.arraycopy(text, lineStart, lastLine, 0, lastLineLength); result.append(lastLine); } return result.getContents(); } return text; } /** * Normalizes the cariage returns in the given text. They are all changed to * use given buffer's line sepatator. */ public static String normalizeCRs(String text, String buffer) { return new String( normalizeCRs(text.toCharArray(), buffer.toCharArray())); } /** * Converts the given relative path into a package name. Returns null if the * path is not a valid package name. */ public static String packageName(IPath pkgPath) { StringBuffer pkgName = new StringBuffer( IPackageFragment.DEFAULT_PACKAGE_NAME); for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) { String segment = pkgPath.segment(j); // if (!isValidFolderNameForPackage(segment)) { // return null; // } pkgName.append(segment); if (j < pkgPath.segmentCount() - 1) { pkgName.append("."); //$NON-NLS-1$ } } return pkgName.toString(); } /** * Returns the length of the common prefix between s1 and s2. */ public static int prefixLength(char[] s1, char[] s2) { int len = 0; int max = Math.min(s1.length, s2.length); for (int i = 0; i < max && s1[i] == s2[i]; ++i) ++len; return len; } /** * Returns the length of the common prefix between s1 and s2. */ public static int prefixLength(String s1, String s2) { int len = 0; int max = Math.min(s1.length(), s2.length()); for (int i = 0; i < max && s1.charAt(i) == s2.charAt(i); ++i) ++len; return len; } private static void quickSort(char[][] list, int left, int right) { int original_left = left; int original_right = right; char[] mid = list[(left + right) / 2]; do { while (compare(list[left], mid) < 0) { left++; } while (compare(mid, list[right]) < 0) { right--; } if (left <= right) { char[] tmp = list[left]; list[left] = list[right]; list[right] = tmp; left++; right--; } } while (left <= right); if (original_left < right) { quickSort(list, original_left, right); } if (left < original_right) { quickSort(list, left, original_right); } } /** * Sort the comparable objects in the given collection. */ private static void quickSort(Comparable[] sortedCollection, int left, int right) { int original_left = left; int original_right = right; Comparable mid = sortedCollection[(left + right) / 2]; do { while (sortedCollection[left].compareTo(mid) < 0) { left++; } while (mid.compareTo(sortedCollection[right]) < 0) { right--; } if (left <= right) { Comparable tmp = sortedCollection[left]; sortedCollection[left] = sortedCollection[right]; sortedCollection[right] = tmp; left++; right--; } } while (left <= right); if (original_left < right) { quickSort(sortedCollection, original_left, right); } if (left < original_right) { quickSort(sortedCollection, left, original_right); } } private static void quickSort(int[] list, int left, int right) { int original_left = left; int original_right = right; int mid = list[(left + right) / 2]; do { while (list[left] < mid) { left++; } while (mid < list[right]) { right--; } if (left <= right) { int tmp = list[left]; list[left] = list[right]; list[right] = tmp; left++; right--; } } while (left <= right); if (original_left < right) { quickSort(list, original_left, right); } if (left < original_right) { quickSort(list, left, original_right); } } /** * Sort the objects in the given collection using the given comparer. */ private static void quickSort(Object[] sortedCollection, int left, int right, Comparer comparer) { int original_left = left; int original_right = right; Object mid = sortedCollection[(left + right) / 2]; do { while (comparer.compare(sortedCollection[left], mid) < 0) { left++; } while (comparer.compare(mid, sortedCollection[right]) < 0) { right--; } if (left <= right) { Object tmp = sortedCollection[left]; sortedCollection[left] = sortedCollection[right]; sortedCollection[right] = tmp; left++; right--; } } while (left <= right); if (original_left < right) { quickSort(sortedCollection, original_left, right, comparer); } if (left < original_right) { quickSort(sortedCollection, left, original_right, comparer); } } /** * Sort the objects in the given collection using the given sort order. */ private static void quickSort(Object[] sortedCollection, int left, int right, int[] sortOrder) { int original_left = left; int original_right = right; int mid = sortOrder[(left + right) / 2]; do { while (sortOrder[left] < mid) { left++; } while (mid < sortOrder[right]) { right--; } if (left <= right) { Object tmp = sortedCollection[left]; sortedCollection[left] = sortedCollection[right]; sortedCollection[right] = tmp; int tmp2 = sortOrder[left]; sortOrder[left] = sortOrder[right]; sortOrder[right] = tmp2; left++; right--; } } while (left <= right); if (original_left < right) { quickSort(sortedCollection, original_left, right, sortOrder); } if (left < original_right) { quickSort(sortedCollection, left, original_right, sortOrder); } } /** * Sort the strings in the given collection. */ private static void quickSort(String[] sortedCollection, int left, int right) { int original_left = left; int original_right = right; String mid = sortedCollection[(left + right) / 2]; do { while (sortedCollection[left].compareTo(mid) < 0) { left++; } while (mid.compareTo(sortedCollection[right]) < 0) { right--; } if (left <= right) { String tmp = sortedCollection[left]; sortedCollection[left] = sortedCollection[right]; sortedCollection[right] = tmp; left++; right--; } } while (left <= right); if (original_left < right) { quickSort(sortedCollection, original_left, right); } if (left < original_right) { quickSort(sortedCollection, left, original_right); } } /** * Sort the strings in the given collection in reverse alphabetical order. */ private static void quickSortReverse(String[] sortedCollection, int left, int right) { int original_left = left; int original_right = right; String mid = sortedCollection[(left + right) / 2]; do { while (sortedCollection[left].compareTo(mid) > 0) { left++; } while (mid.compareTo(sortedCollection[right]) > 0) { right--; } if (left <= right) { String tmp = sortedCollection[left]; sortedCollection[left] = sortedCollection[right]; sortedCollection[right] = tmp; left++; right--; } } while (left <= right); if (original_left < right) { quickSortReverse(sortedCollection, original_left, right); } if (left < original_right) { quickSortReverse(sortedCollection, left, original_right); } } /** * Reads in a string from the specified data input stream. The string has * been encoded using a modified UTF-8 format. *

* The first two bytes are read as if by readUnsignedShort. * This value gives the number of following bytes that are in the encoded * string, not the length of the resulting string. The following bytes are * then interpreted as bytes encoding characters in the UTF-8 format and are * converted into characters. *

* This method blocks until all the bytes are read, the end of the stream is * detected, or an exception is thrown. * * @param in * a data input stream. * @return a Unicode string. * @exception EOFException * if the input stream reaches the end before all the bytes. * @exception IOException * if an I/O error occurs. * @exception UTFDataFormatException * if the bytes do not represent a valid UTF-8 encoding of a * Unicode string. * @see java.io.DataInputStream#readUnsignedShort() */ public final static char[] readUTF(DataInput in) throws IOException { int utflen = in.readUnsignedShort(); char str[] = new char[utflen]; int count = 0; int strlen = 0; while (count < utflen) { int c = in.readUnsignedByte(); int char2, char3; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 0xxxxxxx count++; str[strlen++] = (char) c; break; case 12: case 13: // 110x xxxx 10xx xxxx count += 2; if (count > utflen) throw new UTFDataFormatException(); char2 = in.readUnsignedByte(); if ((char2 & 0xC0) != 0x80) throw new UTFDataFormatException(); str[strlen++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); break; case 14: // 1110 xxxx 10xx xxxx 10xx xxxx count += 3; if (count > utflen) throw new UTFDataFormatException(); char2 = in.readUnsignedByte(); char3 = in.readUnsignedByte(); if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) throw new UTFDataFormatException(); str[strlen++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); break; default: // 10xx xxxx, 1111 xxxx throw new UTFDataFormatException(); } } if (strlen < utflen) { System.arraycopy(str, 0, str = new char[strlen], 0, strlen); } return str; } /** * Creates a NLS catalog for the given locale. */ public static void relocalize() { try { bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); } catch (MissingResourceException e) { System.out .println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$ throw e; } } public static void sort(char[][] list) { if (list.length > 1) quickSort(list, 0, list.length - 1); } /** * Sorts an array of Comparable objects in place. */ public static void sort(Comparable[] objects) { if (objects.length > 1) quickSort(objects, 0, objects.length - 1); } public static void sort(int[] list) { if (list.length > 1) quickSort(list, 0, list.length - 1); } /** * Sorts an array of objects in place. The given comparer compares pairs of * items. */ public static void sort(Object[] objects, Comparer comparer) { if (objects.length > 1) quickSort(objects, 0, objects.length - 1, comparer); } /** * Sorts an array of objects in place, using the sort order given for each * item. */ public static void sort(Object[] objects, int[] sortOrder) { if (objects.length > 1) quickSort(objects, 0, objects.length - 1, sortOrder); } /** * Sorts an array of strings in place using quicksort. */ public static void sort(String[] strings) { if (strings.length > 1) quickSort(strings, 0, strings.length - 1); } /** * Sorts an array of Comparable objects, returning a new array with the * sorted items. The original array is left untouched. */ public static Comparable[] sortCopy(Comparable[] objects) { int len = objects.length; Comparable[] copy = new Comparable[len]; System.arraycopy(objects, 0, copy, 0, len); sort(copy); return copy; } /** * Sorts an array of Strings, returning a new array with the sorted items. * The original array is left untouched. */ public static Object[] sortCopy(Object[] objects, Comparer comparer) { int len = objects.length; Object[] copy = new Object[len]; System.arraycopy(objects, 0, copy, 0, len); sort(copy, comparer); return copy; } /** * Sorts an array of Strings, returning a new array with the sorted items. * The original array is left untouched. */ public static String[] sortCopy(String[] objects) { int len = objects.length; String[] copy = new String[len]; System.arraycopy(objects, 0, copy, 0, len); sort(copy); return copy; } /** * Sorts an array of strings in place using quicksort in reverse * alphabetical order. */ public static void sortReverseOrder(String[] strings) { if (strings.length > 1) quickSortReverse(strings, 0, strings.length - 1); } /** * Converts a String[] to char[][]. */ public static char[][] toCharArrays(String[] a) { int len = a.length; char[][] result = new char[len][]; for (int i = 0; i < len; ++i) { result[i] = toChars(a[i]); } return result; } /** * Converts a String to char[]. */ public static char[] toChars(String s) { int len = s.length(); char[] chars = new char[len]; s.getChars(0, len, chars, 0); return chars; } /** * Converts a String to char[][], where segments are separate by '.'. */ public static char[][] toCompoundChars(String s) { int len = s.length(); if (len == 0) { return CharOperation.NO_CHAR_CHAR; } int segCount = 1; for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) { ++segCount; } char[][] segs = new char[segCount][]; int start = 0; for (int i = 0; i < segCount; ++i) { int dot = s.indexOf('.', start); int end = (dot == -1 ? s.length() : dot); segs[i] = new char[end - start]; s.getChars(start, end, segs[i], 0); start = end + 1; } return segs; } /** * Converts a char[] to String. */ public static String toString(char[] c) { return new String(c); } /** * Converts a char[][] to String, where segments are separated by '.'. */ public static String toString(char[][] c) { StringBuffer sb = new StringBuffer(); for (int i = 0, max = c.length; i < max; ++i) { if (i != 0) sb.append('.'); sb.append(c[i]); } return sb.toString(); } /** * Converts a char[][] and a char[] to String, where segments are separated * by '.'. */ public static String toString(char[][] c, char[] d) { if (c == null) return new String(d); StringBuffer sb = new StringBuffer(); for (int i = 0, max = c.length; i < max; ++i) { sb.append(c[i]); sb.append('.'); } sb.append(d); return sb.toString(); } /* * Returns the unresolved type parameter signatures of the given method e.g. * {"QString;", "[int", "[[Qjava.util.Vector;"} */ // public static String[] typeParameterSignatures(AbstractMethodDeclaration // method) { // Argument[] args = method.arguments; // if (args != null) { // int length = args.length; // String[] signatures = new String[length]; // for (int i = 0; i < args.length; i++) { // Argument arg = args[i]; // signatures[i] = typeSignature(arg.type); // } // return signatures; // } // return new String[0]; // } /* * Returns the unresolved type signature of the given type reference, e.g. * "QString;", "[int", "[[Qjava.util.Vector;" */ // public static String typeSignature(TypeReference type) { // char[][] compoundName = type.getTypeName(); // char[] typeName =CharOperation.concatWith(compoundName, '.'); // String signature = Signature.createTypeSignature(typeName, false/*don't // resolve*/); // int dimensions = type.dimensions(); // if (dimensions > 0) { // signature = Signature.createArraySignature(signature, dimensions); // } // return signature; // } /* * Returns the unresolved type signature of the given type reference, e.g. * "QString;", "[int", "[[Qjava.util.Vector;" */ public static String typeSignature(TypeReference type) { char[][] compoundName = type.getTypeName(); char[] typeName = CharOperation.concatWith(compoundName, '.'); String signature = Signature .createTypeSignature(typeName, false/* don't resolve */); int dimensions = type.dimensions(); if (dimensions > 0) { signature = Signature.createArraySignature(signature, dimensions); } return signature; } /** * Asserts that the given method signature is valid. */ public static void validateMethodSignature(String sig) { Assert.isTrue(isValidMethodSignature(sig)); } /** * Asserts that the given type signature is valid. */ public static void validateTypeSignature(String sig, boolean allowVoid) { Assert.isTrue(isValidTypeSignature(sig, allowVoid)); } public static void verbose(String log) { verbose(log, System.out); } public static synchronized void verbose(String log, PrintStream printStream) { int start = 0; do { int end = log.indexOf('\n', start); printStream.print(Thread.currentThread()); printStream.print(" "); //$NON-NLS-1$ printStream.print(log.substring(start, end == -1 ? log.length() : end + 1)); start = end + 1; } while (start != 0); printStream.println(); } /** * Writes a string to the given output stream using UTF-8 encoding in a * machine-independent manner. *

* First, two bytes are written to the output stream as if by the * writeShort method giving the number of bytes to follow. * This value is the number of bytes actually written out, not the length of * the string. Following the length, each character of the string is output, * in sequence, using the UTF-8 encoding for the character. * * @param str * a string to be written. * @return the number of bytes written to the stream. * @exception IOException * if an I/O error occurs. * @since JDK1.0 */ public static int writeUTF(OutputStream out, char[] str) throws IOException { int strlen = str.length; int utflen = 0; for (int i = 0; i < strlen; i++) { int c = str[i]; if ((c >= 0x0001) && (c <= 0x007F)) { utflen++; } else if (c > 0x07FF) { utflen += 3; } else { utflen += 2; } } if (utflen > 65535) throw new UTFDataFormatException(); out.write((utflen >>> 8) & 0xFF); out.write((utflen >>> 0) & 0xFF); if (strlen == utflen) { for (int i = 0; i < strlen; i++) out.write(str[i]); } else { for (int i = 0; i < strlen; i++) { int c = str[i]; if ((c >= 0x0001) && (c <= 0x007F)) { out.write(c); } else if (c > 0x07FF) { out.write(0xE0 | ((c >> 12) & 0x0F)); out.write(0x80 | ((c >> 6) & 0x3F)); out.write(0x80 | ((c >> 0) & 0x3F)); } else { out.write(0xC0 | ((c >> 6) & 0x1F)); out.write(0x80 | ((c >> 0) & 0x3F)); } } } return utflen + 2; // the number of bytes written to the stream } }