package org.rubypeople.rdt.core.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.rubypeople.rdt.internal.core.util.CharOperation;
public abstract class Util
{
private static final String[] KEYWORDS = new String[] { "alias", "and", "BEGIN", "begin", "break", "case", "class",
"def", "defined", "do", "else", "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module",
"next", "nil", "not", "or", "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef",
"unless", "until", "when", "while", "yield" };
private static final String[] OPERATORS = new String[] { "::", ".", "[]", "**", "-", "+", "!", "~", "*", "/", "%",
"+", "-", "<<", ">>", "&", "|", "^", ">", ">=", "<", "<=", "<=>", "==", "===", "!=", "=~", "!~", "&&",
"||", "..", "...", "=", "+=", "-=", "*=", "/=", "||=" };
public interface Displayable
{
public String displayString(Object o);
}
private static final int DEFAULT_READING_SIZE = 8192;
public final static String UTF_8 = "UTF-8"; //$NON-NLS-1$
public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
public static byte[] getFileByteContent(File file) throws IOException
{
InputStream stream = null;
try
{
stream = new FileInputStream(file);
return getInputStreamAsByteArray(stream, (int) file.length());
}
finally
{
if (stream != null)
{
try
{
stream.close();
}
catch (IOException e)
{
// ignore
}
}
}
}
/**
* 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();
}
/**
* 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
{
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;
}
/**
* 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();
}
});
}
/**
* Returns the contents of the given file as a char array. When encoding is null, then the platform default one is
* used
*
* @throws IOException
* if a problem occured reading the file.
*/
public static char[] getFileCharContent(File file, String encoding) throws IOException
{
InputStream stream = null;
try
{
stream = new FileInputStream(file);
return getInputStreamAsCharArray(stream, (int) file.length(), encoding);
}
finally
{
if (stream != null)
{
try
{
stream.close();
}
catch (IOException e)
{
// ignore
}
}
}
}
/**
* Returns the given input stream's contents as a character array. If a length is specified (ie. if length != -1),
* this represents the number of bytes in the stream. Note this doesn't close the stream.
*
* @throws IOException
* if a problem occured reading the stream.
*/
public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding) throws IOException
{
InputStreamReader reader = null;
try
{
reader = encoding == null ? new InputStreamReader(stream) : new InputStreamReader(stream, encoding);
}
catch (UnsupportedEncodingException e)
{
// encoding is not supported
reader = new InputStreamReader(stream);
}
char[] contents;
int totalRead = 0;
if (length == -1)
{
contents = CharOperation.NO_CHAR;
}
else
{
// length is a good guess when the encoding produces less or the same amount of characters than the file
// length
contents = new char[length]; // best guess
}
while (true)
{
int amountRequested;
if (totalRead < length)
{
// until known length is met, reuse same array sized eagerly
amountRequested = length - totalRead;
}
else
{
// reading beyond known length
int current = reader.read();
if (current < 0)
break;
amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K
// resize contents if needed
if (totalRead + 1 + amountRequested > contents.length)
System.arraycopy(contents, 0, contents = new char[totalRead + 1 + amountRequested], 0, totalRead);
// add current character
contents[totalRead++] = (char) current; // coming from totalRead==length
}
// read as many chars as possible
int amountRead = reader.read(contents, totalRead, amountRequested);
if (amountRead < 0)
break;
totalRead += amountRead;
}
// Do not keep first character for UTF-8 BOM encoding
int start = 0;
if (totalRead > 0 && UTF_8.equals(encoding))
{
if (contents[0] == 0xFEFF)
{ // if BOM char then skip
totalRead--;
start = 1;
}
}
// resize contents if necessary
if (totalRead < contents.length)
System.arraycopy(contents, start, contents = new char[totalRead], 0, totalRead);
return contents;
}
public static String camelCaseToUnderscores(String name)
{
if (name == null)
return null;
if (name.length() == 0)
return "";
StringBuffer newName = new StringBuffer();
boolean lastWasUpper = false;
for (int i = 0; i < name.length(); i++)
{
char c = name.charAt(i);
newName.append(Character.toLowerCase(c));
if (lastWasUpper && Character.isLowerCase(c))
{
if (newName.length() > 2)
newName.insert(newName.length() - 2, "_");
lastWasUpper = false;
}
if (Character.isUpperCase(c))
{
lastWasUpper = true;
}
}
return newName.toString();
}
public static String underscoresToCamelCase(String name)
{
if (name == null)
return null;
if (name.length() == 0)
return "";
StringBuffer newName = new StringBuffer();
boolean lastWasUnderScore = false;
for (int i = 0; i < name.length(); i++)
{
char c = name.charAt(i);
if (lastWasUnderScore || i == 0)
{
newName.append(Character.toUpperCase(c));
lastWasUnderScore = false;
}
else if (c == '_')
{
lastWasUnderScore = true;
}
else
{
newName.append(c);
}
}
return newName.toString();
}
public static boolean isOperator(String word)
{
return contains(word, OPERATORS);
}
public static boolean isKeyword(String word)
{
return contains(word, KEYWORDS);
}
private static boolean contains(String word, String[] array)
{
for (int i = 0; i < array.length; i++)
{
if (array[i].equals(word))
return true;
}
return false;
}
/**
* Used to try and find executables and bin scripts that were installed with a common suffix. Typically users would
* install with something like "19", or "1.9"
*
* @param basePath
* @return null if no file with base name exists. File pointer if we find a match with a suffix appended.
*/
public static File findFileWithOptionalSuffix(String basePath)
{
File file = new File(basePath);
if (file != null && file.exists() && file.isFile())
return file;
File parentDir = file.getParentFile();
if (parentDir == null || !parentDir.exists())
return null;
IPath path = new Path(basePath);
final String extension = getExtension(path);
final String filenameWithoutExtension = path.removeFileExtension().lastSegment();
File[] children = parentDir.listFiles(new FilenameFilter()
{
public boolean accept(File dir, String name)
{
String tmpExtension = getExtension(new Path(name));
return name.startsWith(filenameWithoutExtension)
&& ((extension == null && tmpExtension == null) || (tmpExtension != null && extension != null && tmpExtension
.equals(extension)));
}
});
if (children == null || children.length == 0)
return null;
// Prefer version # suffixes, newest to oldest
String[] commonSuffixes = new String[] { "1.9", "19", "1.8", "18", "1.7", "17", "1.6", "16" };
for (File child : children)
{
for (String suffix : commonSuffixes)
{
IPath childPath = new Path(child.getName());
String childExtension = getExtension(childPath);
String baseName = childPath.lastSegment();
if (childExtension != null)
baseName = baseName.substring(0, baseName.length() - childExtension.length());
if (baseName.endsWith(suffix))
return child;
}
}
// Just return first child.
return children[0];
}
private static String getExtension(IPath path)
{
String extension = path.getFileExtension();
if (extension == null)
return null;
if (Pattern.matches("^\\d+$", extension))
return null;
return extension;
}
}