/*******************************************************************************
* Copyright © 2000, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.ide.core.internal.model;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.edt.ide.core.EDTCoreIDEPlugin;
import org.eclipse.edt.ide.core.model.EGLConventions;
import org.eclipse.edt.ide.core.model.EGLCore;
import org.eclipse.edt.ide.core.model.EGLModelException;
import org.eclipse.edt.ide.core.model.IEGLElement;
import org.eclipse.edt.ide.core.model.IEGLModelStatusConstants;
import org.eclipse.edt.ide.core.model.IEGLPathEntry;
import org.eclipse.edt.ide.core.model.IPackageFragment;
import org.eclipse.edt.ide.core.model.Signature;
import org.eclipse.edt.compiler.internal.core.utils.CharOperation;
import org.eclipse.edt.compiler.tools.IRUtils;
import com.ibm.icu.util.StringTokenizer;
/**
* Provides convenient utility methods to other types in this package.
*/
public class Util {
private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
private static final String EMPTY_ARGUMENT = " "; //$NON-NLS-1$
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);
}
public interface Displayable {
String displayString(Object o);
}
public static final String[] fgEmptyStringArray = new String[0];
/* Bundle containing messages */
protected static ResourceBundle bundle;
private final static String bundleName = "org.eclipse.edt.ide.core.internal.model.EGLModelResources"; //$NON-NLS-1$
public final static char[] SUFFIX_egl = ".egl".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_EGL = ".EGL".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_buildstate = ".bs".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_BUILDSTATE = ".BS".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_eglbld = ".eglbld".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_EGLBLD = ".EGLBLD".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_jar = ".jar".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_JAR = ".JAR".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_zip = ".zip".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_ZIP = ".ZIP".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_eglar = ".eglar".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_EGLAR = ".EGLAR".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_mofar = ".mofar".toCharArray(); //$NON-NLS-1$
public final static char[] SUFFIX_MOFAR = ".MOFAR".toCharArray(); //$NON-NLS-1$
static {
relocalize();
}
/**
* 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});
// }
/**
* 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 char arrays lexicographically.
* The comparison is based on the Unicode value of each character in
* the char arrays.
* @return the value <code>0</code> if a is equal to
* b; a value less than <code>0</code> if a
* is lexicographically less than b; and a
* value greater than <code>0</code> if a is
* lexicographically greater than b.
*/
public static int compare(char[] v1, char[] v2) {
int len1 = v1.length;
int len2 = v2.length;
int n = Math.min(len1, len2);
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i]) {
return v1[i] - v2[i];
}
++i;
}
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);
}
/**
* Returns the concatenation of the given array parts using the given separator between each part.
* <br>
* <br>
* For example:<br>
* <ol>
* <li><pre>
* array = {"a", "b"}
* separator = '.'
* => result = "a.b"
* </pre>
* </li>
* <li><pre>
* array = {}
* separator = '.'
* => result = ""
* </pre></li>
* </ol>
*
* @param array the given array
* @param separator the given separator
* @return the concatenation of the given array parts using the given separator between each part
*/
public static final String concatWith(String[] array, char separator) {
StringBuffer buffer = new StringBuffer();
for (int i = 0, length = array.length; i < length; i++) {
buffer.append(array[i]);
if (i < length - 1)
buffer.append(separator);
}
return buffer.toString();
}
/**
* 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('/', '.');
}
/**
* 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 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 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 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);
}
/**
* Finds the first line separator used by the given text.
*
* @return </code>"\n"</code> or </code>"\r"</code> or </code>"\r\n"</code>,
* or <code>null</code> if none found
*/
public static String findLineSeparator(char[] text) {
// find the first line separator
int length = text.length;
if (length > 0) {
char nextChar = text[0];
for (int i = 0; i < length; i++) {
char currentChar = nextChar;
nextChar = i < length-1 ? text[i+1] : ' ';
switch (currentChar) {
case '\n': return "\n"; //$NON-NLS-1$
case '\r': return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
// not found
return null;
}
/**
* Returns the given file's contents as a byte array.
*/
public static byte[] getResourceContentsAsByteArray(IFile file) throws EGLModelException {
InputStream stream= null;
try {
stream = new BufferedInputStream(file.getContents(true));
} catch (CoreException e) {
throw new EGLModelException(e);
}
try {
return org.eclipse.edt.ide.core.internal.model.util.Util.getInputStreamAsByteArray(stream, -1);
} catch (IOException e) {
throw new EGLModelException(e, IEGLModelStatusConstants.IO_EXCEPTION);
} finally {
try {
stream.close();
} catch (IOException e) {
}
}
}
/**
* Returns the given file's contents as a character array.
*/
public static char[] getResourceContentsAsCharArray(IFile file) throws EGLModelException {
try {
String encoding = file.getCharset();
if(encoding == null) //get the default encoding setting
encoding = EGLCore.create(file.getProject()).getOption(EGLCore.CORE_ENCODING, true);
return getResourceContentsAsCharArray(file, encoding);
} catch (CoreException e) {
throw new EGLModelException(e);
}
}
public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws EGLModelException {
InputStream stream= null;
try {
stream = new BufferedInputStream(file.getContents(true));
} catch (CoreException e) {
throw new EGLModelException(e, IEGLModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
}
try {
return org.eclipse.edt.ide.core.internal.model.util.Util.getInputStreamAsCharArray(stream, -1, encoding);
} catch (IOException e) {
throw new EGLModelException(e, IEGLModelStatusConstants.IO_EXCEPTION);
} finally {
try {
stream.close();
} catch (IOException e) {
}
}
}
/**
* 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 true iff str.toLowerCase().endsWith(".eglar" or ".mofar")
* implementation is not creating extra strings.
*/
public final static boolean isEGLARFileName(String name) {
if (name == null) {
return false;
}
return IRUtils.matchesFileName(name, SUFFIX_eglar, SUFFIX_EGLAR)
|| IRUtils.matchesFileName(name, SUFFIX_mofar, SUFFIX_MOFAR);
}
public static boolean isValidMofPackage(String fullPath) {
if(fullPath != null && fullPath.contains("eglgen")) {
return true;
} else {
return false;
}
}
/**
* Returns true iff str.toLowerCase().endsWith(".jar" or ".zip")
* implementation is not creating extra strings.
*/
public final static boolean isArchiveFileName(String name) {
int nameLength = name == null ? 0 : name.length();
int suffixLength = SUFFIX_JAR.length;
if (nameLength < suffixLength) return false;
int i, offset;
for ( i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
char c = name.charAt(offset + i);
if (c != SUFFIX_jar[i] && c != SUFFIX_JAR[i]) break;
}
if (i == suffixLength) return true;
for ( i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
char c = name.charAt(offset + i);
if (c != SUFFIX_zip[i] && c != SUFFIX_ZIP[i]) return false;
}
return true;
}
/**
* Returns true iff str.toLowerCase().endsWith(".eglbld")
* implementation is not creating extra strings.
*/
public final static boolean isEGLBLDFileName(String name) {
int nameLength = name == null ? 0 : name.length();
int suffixLength = SUFFIX_EGLBLD.length;
if (nameLength < suffixLength) return false;
for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
char c = name.charAt(offset + i);
if (c != SUFFIX_eglbld[i] && c != SUFFIX_EGLBLD[i]) return false;
}
return true;
}
/**
* Returns true iff str.toLowerCase().endsWith(".egl")
* implementation is not creating extra strings.
*/
public final static boolean isEGLFileName(String name) {
int nameLength = name == null ? 0 : name.length();
int suffixLength = SUFFIX_EGL.length;
if (nameLength < suffixLength) return false;
for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
char c = name.charAt(offset + i);
if (c != SUFFIX_egl[i] && c != SUFFIX_EGL[i]) return false;
}
return true;
}
/**
* Returns true iff str.toLowerCase().endsWith(".bs")
* implementation is not creating extra strings.
*/
public final static boolean isBuildStateFileName(String name) {
int nameLength = name == null ? 0 : name.length();
int suffixLength = SUFFIX_BUILDSTATE.length;
if (nameLength < suffixLength) return false;
for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
char c = name.charAt(offset + i);
if (c != SUFFIX_buildstate[i] && c != SUFFIX_BUILDSTATE[i]) return false;
}
return true;
}
/*
* Returns whether the given java element is exluded from its root's classpath.
*/
public static final boolean isExcluded(IEGLElement element) {
int elementType = element.getElementType();
switch (elementType) {
case IEGLElement.PACKAGE_FRAGMENT:
PackageFragmentRoot root = (PackageFragmentRoot)element.getAncestor(IEGLElement.PACKAGE_FRAGMENT_ROOT);
IResource resource = element.getResource();
return resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars());
case IEGLElement.EGL_FILE:
root = (PackageFragmentRoot)element.getAncestor(IEGLElement.PACKAGE_FRAGMENT_ROOT);
resource = element.getResource();
if (resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars()))
return true;
return isExcluded(element.getParent());
default:
IEGLElement cu = element.getAncestor(IEGLElement.EGL_FILE);
return cu != null && isExcluded(cu);
}
}
/*
* Returns whether the given resource path matches one of the exclusion
* patterns.
*
* @see IClasspathEntry#getExclusionPatterns
*/
public final static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
if (exclusionPatterns == null) return false;
char[] path = resourcePath.toString().toCharArray();
for (int i = 0, length = exclusionPatterns.length; i < length; i++)
if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
return true;
return false;
}
/*
* Returns whether the given resource matches one of the exclusion patterns.
*
* @see IClasspathEntry#getExclusionPatterns
*/
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
if (resource.getType() == IResource.FOLDER)
path = path.append("*"); //$NON-NLS-1$
return isExcluded(path, exclusionPatterns);
}
/**
* Validate the given compilation unit name.
* A compilation unit name must obey the following rules:
* <ul>
* <li> it must not be null
* <li> it must include the <code>".java"</code> suffix
* <li> its prefix must be a valid identifier
* </ul>
* </p>
* @param name the name of a compilation unit
* @return a status object with code <code>IStatus.OK</code> if
* the given name is valid as a compilation unit name, otherwise a status
* object indicating what is wrong with the name
*/
public static boolean isValidEGLFileName(String name) {
return EGLConventions.validateEGLFileName(name).getSeverity() != IStatus.ERROR;
}
/**
* Validate the given .class file name.
* A .class file name must obey the following rules:
* <ul>
* <li> it must not be null
* <li> it must include the <code>".class"</code> suffix
* <li> its prefix must be a valid identifier
* </ul>
* </p>
* @param name the name of a .class file
* @return a status object with code <code>IStatus.OK</code> if
* the given name is valid as a .class file name, otherwise a status
* object indicating what is wrong with the name
*/
public static boolean isValidClassFileName(String name) {
// TODO handle class files generated from egl resources
return false;
//return EGLConventions.validateClassFileName(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 EGLConventions.validateIdentifier(folderName).getSeverity() != IStatus.ERROR;
}
/*
* Add a log entry
*/
public static void log(Throwable e, String message) {
Throwable nestedException;
if (e instanceof EGLModelException
&& (nestedException = ((EGLModelException)e).getException()) != null) {
e = nestedException;
}
IStatus status= new Status(
IStatus.ERROR,
EDTCoreIDEPlugin.getPlugin().getDescriptor().getUniqueIdentifier(),
IStatus.ERROR,
message,
e);
EDTCoreIDEPlugin.getPlugin().getLog().log(status);
}
/**
* 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 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 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);
}
}
/**
* 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();
}
/**
* 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);
}
}
/**
* 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);
}
}
/**
* 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 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 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 in place.
*/
public static void sort(Comparable[] objects) {
if (objects.length > 1)
quickSort(objects, 0, objects.length - 1);
}
/**
* 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 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 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, 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();
}
/**
* Converts a char[] to String.
*/
public static String toString(char[] c) {
return new String(c);
}
/**
* Converts an array of Objects into String.
*/
public static String toString(Object[] objects) {
return toString(objects,
new Displayable(){
public String displayString(Object o) {
if (o == null) return "null"; //$NON-NLS-1$
return o.toString();
}
});
}
/**
* Converts an array of Objects into String.
*/
public static String toString(Object[] objects, Displayable renderer) {
if (objects == null) return ""; //$NON-NLS-1$
StringBuffer buffer = new StringBuffer(10);
for (int i = 0; i < objects.length; i++){
if (i > 0) buffer.append(", "); //$NON-NLS-1$
buffer.append(renderer.displayString(objects[i]));
}
return buffer.toString();
}
/**
* 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;
}
}
/**
* 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;
}
/*
* Converts the given URI to a local file. Use the existing file if the uri is on the local file system.
* Otherwise fetch it.
* Returns null if unable to fetch it.
*/
public static File toLocalFile(URI uri, IProgressMonitor monitor) throws CoreException {
IFileStore fileStore = EFS.getStore(uri);
File localFile = fileStore.toLocalFile(EFS.NONE, monitor);
if (localFile ==null)
// non local file system
localFile= fileStore.toLocalFile(EFS.CACHE, monitor);
return localFile;
}
/**
* Returns the contents of the given zip entry as a byte array.
* @throws IOException if a problem occured reading the zip entry.
*/
public static byte[] getZipEntryByteContent(ZipEntry ze, ZipFile zip)
throws IOException {
InputStream stream = null;
try {
InputStream inputStream = zip.getInputStream(ze);
if (inputStream == null) throw new IOException("Invalid zip entry name : " + ze.getName()); //$NON-NLS-1$
stream = new BufferedInputStream(inputStream);
return getInputStreamAsByteArray(stream, (int) ze.getSize());
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// ignore
}
}
}
}
/**
* Returns the given input stream's contents as a byte array.
* If a length is specified (ie. if length != -1), only length bytes
* are returned. Otherwise all bytes in the stream are returned.
* Note this doesn't close the stream.
* @throws IOException if a problem occured reading the stream.
*/
public static byte[] getInputStreamAsByteArray(InputStream stream, int length)
throws IOException {
final int DEFAULT_READING_SIZE = 8192;
byte[] contents;
if (length == -1) {
contents = new byte[0];
int contentsLength = 0;
int amountRead = -1;
do {
int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K
// resize contents if needed
if (contentsLength + amountRequested > contents.length) {
System.arraycopy(
contents,
0,
contents = new byte[contentsLength + amountRequested],
0,
contentsLength);
}
// read as many bytes as possible
amountRead = stream.read(contents, contentsLength, amountRequested);
if (amountRead > 0) {
// remember length of contents
contentsLength += amountRead;
}
} while (amountRead != -1);
// resize contents if necessary
if (contentsLength < contents.length) {
System.arraycopy(
contents,
0,
contents = new byte[contentsLength],
0,
contentsLength);
}
} else {
contents = new byte[length];
int len = 0;
int readSize = 0;
while ((readSize != -1) && (len != length)) {
// See PR 1FMS89U
// We record first the read size. In this case len is the actual read size.
len += readSize;
readSize = stream.read(contents, len, length - len);
}
}
return contents;
}
/**
* Return a new array which is the split of the given string using the given divider. The given end
* is exclusive and the given start is inclusive.
* <br>
* <br>
* For example:
* <ol>
* <li><pre>
* divider = 'b'
* string = "abbaba"
* start = 2
* end = 5
* result => { "", "a", "" }
* </pre>
* </li>
* </ol>
*
* @param divider the given divider
* @param string the given string
* @param start the given starting index
* @param end the given ending index
* @return a new array which is the split of the given string using the given divider
* @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length
*/
public static final String[] splitOn(
char divider,
String string,
int start,
int end) {
int length = string == null ? 0 : string.length();
if (length == 0 || start > end)
return new String[0];
int wordCount = 1;
for (int i = start; i < end; i++)
if (string.charAt(i) == divider)
wordCount++;
String[] split = new String[wordCount];
int last = start, currentWord = 0;
for (int i = start; i < end; i++) {
if (string.charAt(i) == divider) {
split[currentWord++] = string.substring(last, i);
last = i + 1;
}
}
split[currentWord] = string.substring(last, end);
return split;
}
/**
* Compares two arrays using equals() on the elements.
* Neither can be null. Only the first len elements are compared.
* Return false if either array is shorter than len.
*/
public static boolean equalArrays(Object[] a, Object[] b, int len) {
if (a == b) return true;
if (a.length < len || b.length < len) 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;
}
//Given an IEGLPathEntry for a binary project, return the project name
public static String getExternalProjectName(IEGLPathEntry entry) {
//For now, the path will look something like this: "C:\targetPlatform\project.eglar"
String fname = entry.getPath().lastSegment();
int index = fname.lastIndexOf(".");
if (index > -1) {
fname = fname.substring(0, index);
}
return fname;
}
}