X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/Util.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/Util.java index 39b4d39..09ace1c 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/Util.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/Util.java @@ -30,1763 +30,1908 @@ 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.ui.util.PHPFileUtil; -import net.sourceforge.phpeclipse.internal.compiler.ast.TypeReference; +//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.IFolder; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.text.edits.MalformedTreeException; -import org.eclipse.text.edits.TextEdit; +//import org.eclipse.jface.text.BadLocationException; +//import org.eclipse.text.edits.MalformedTreeException; +//import org.eclipse.text.edits.TextEdit; /** * Provides convenient utility methods to other types in this package. */ public class Util { - public interface Comparable { - /** - * Returns 0 if this and c are equal, >0 if this is greater than c, or <0 if this is less than c. - */ - int compareTo(Comparable c); - } - - public interface Comparer { - /** - * Returns 0 if a and b are equal, >0 if a is greater than b, or <0 if a is less than b. - */ - int compare(Object a, Object b); - } - - private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$ - - /* Bundle containing messages */ - protected static ResourceBundle bundle; - - private final static String bundleName = "net.sourceforge.phpdt.internal.core.util.messages"; //$NON-NLS-1$ - - private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$ - - private static final String EMPTY_ARGUMENT = " "; //$NON-NLS-1$ - - public static final String[] fgEmptyStringArray = new String[0]; - - private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$ - - static { - relocalize(); - } - - private Util() { - // cannot be instantiated - } - - /** - * Lookup the message with the given ID in this catalog - */ - public static String bind(String id) { - return bind(id, (String[]) null); - } - - /** - * Lookup the message with the given ID in this catalog and bind its substitution locations with the given string. - */ - public static String bind(String id, String binding) { - return bind(id, new String[] { binding }); - } - - /** - * Lookup the message with the given ID in this catalog and bind its substitution locations with the given strings. - */ - public static String bind(String id, String binding1, String binding2) { - return bind(id, new String[] { binding1, binding2 }); - } - - /** - * Lookup the message with the given ID in this catalog and bind its substitution locations with the given string values. - */ - public static String bind(String id, String[] bindings) { - if (id == null) - return "No message available"; //$NON-NLS-1$ - String message = null; - try { - message = bundle.getString(id); - } catch (MissingResourceException e) { - // If we got an exception looking for the message, fail gracefully by just returning - // the id we were looking for. In most cases this is semi-informative so is not too bad. - return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$ - } - // for compatibility with MessageFormat which eliminates double quotes in original message - char[] messageWithNoDoubleQuotes = CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE); - - if (bindings == null) - return new String(messageWithNoDoubleQuotes); - - int length = messageWithNoDoubleQuotes.length; - int start = 0; - int end = length; - StringBuffer output = null; - while (true) { - if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start)) > -1) { - if (output == null) - output = new StringBuffer(length + bindings.length * 20); - output.append(messageWithNoDoubleQuotes, start, end - start); - if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes, end + 1)) > -1) { - int index = -1; - String argId = new String(messageWithNoDoubleQuotes, end + 1, start - end - 1); - try { - index = Integer.parseInt(argId); - output.append(bindings[index]); - } catch (NumberFormatException nfe) { // could be nested message ID {compiler.name} - boolean done = false; - if (!id.equals(argId)) { - String argMessage = null; - try { - argMessage = bundle.getString(argId); - output.append(argMessage); - done = true; - } catch (MissingResourceException e) { - // unable to bind argument, ignore (will leave argument in) - } - } - if (!done) - output.append(messageWithNoDoubleQuotes, end + 1, start - end); - } catch (ArrayIndexOutOfBoundsException e) { - output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$ - } - start++; - } else { - output.append(messageWithNoDoubleQuotes, end, length); - break; - } - } else { - if (output == null) - return new String(messageWithNoDoubleQuotes); - output.append(messageWithNoDoubleQuotes, start, length - start); - break; - } - } - return output.toString(); - } - - /** - * Checks the type signature in String sig, starting at start and ending before end (end is not included). Returns the index of - * the character immediately after the signature if valid, or -1 if not valid. - */ - private static int checkTypeSignature(String sig, int start, int end, boolean allowVoid) { - if (start >= end) - return -1; - int i = start; - char c = sig.charAt(i++); - int nestingDepth = 0; - while (c == '[') { - ++nestingDepth; - if (i >= end) - return -1; - c = sig.charAt(i++); - } - switch (c) { - case 'B': - case 'C': - case 'D': - case 'F': - case 'I': - case 'J': - case 'S': - case 'Z': - break; - case 'V': - if (!allowVoid) - return -1; - // array of void is not allowed - if (nestingDepth != 0) - return -1; - break; - case 'L': - int semicolon = sig.indexOf(';', i); - // Must have at least one character between L and ; - if (semicolon <= i || semicolon >= end) - return -1; - i = semicolon + 1; - break; - default: - return -1; - } - return i; - } - - /** - * Combines two hash codes to make a new one. - */ - public static int combineHashCodes(int hashCode1, int hashCode2) { - return hashCode1 * 17 + hashCode2; - } - - /** - * Compares two byte arrays. Returns <0 if a byte in a is less than the corresponding byte in b, or if a is shorter, or if a is - * null. Returns >0 if a byte in a is greater than the corresponding byte in b, or if a is longer, or if b is null. Returns 0 if - * they are equal or both null. - */ - public static int compare(byte[] a, byte[] b) { - if (a == b) - return 0; - if (a == null) - return -1; - if (b == null) - return 1; - int len = Math.min(a.length, b.length); - for (int i = 0; i < len; ++i) { - int diff = a[i] - b[i]; - if (diff != 0) - return diff; - } - if (a.length > len) - return 1; - if (b.length > len) - return -1; - return 0; - } - - /** - * Compares two strings lexicographically. The comparison is based on the Unicode value of each character in the strings. - * - * @return the value 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 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*/); + char[] typeName = CharOperation.concatWith(compoundName, '.'); + String signature = Signature + .createTypeSignature(typeName, false/* don't resolve */); int dimensions = type.dimensions(); if (dimensions > 0) { - signature = Signature.createArraySignature(signature, dimensions); + signature = Signature.createArraySignature(signature, dimensions); } return signature; } - /** - * Asserts that the given method signature is valid. - */ - public static void validateMethodSignature(String sig) { - Assert.isTrue(isValidMethodSignature(sig)); - } - - /** - * Asserts that the given type signature is valid. - */ - public static void validateTypeSignature(String sig, boolean allowVoid) { - Assert.isTrue(isValidTypeSignature(sig, allowVoid)); - } - - public static void verbose(String log) { - verbose(log, System.out); - } - - public static synchronized void verbose(String log, PrintStream printStream) { - int start = 0; - do { - int end = log.indexOf('\n', start); - printStream.print(Thread.currentThread()); - printStream.print(" "); //$NON-NLS-1$ - printStream.print(log.substring(start, end == -1 ? log.length() : end + 1)); - start = end + 1; - } while (start != 0); - printStream.println(); - } - - /** - * Writes a string to the given output stream using UTF-8 encoding in a machine-independent manner. - *

- * 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 - } + + /** + * 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 + } } \ No newline at end of file