blob: eef5cbdcc78b8bca29342bc0a2c93009fa8ed384 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.util;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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.jdt.core.compiler.CharOperation;
public class Util implements SuffixConstants {
public interface Displayable {
String displayString(Object o);
}
public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
public static char[] LINE_SEPARATOR_CHARS = LINE_SEPARATOR.toCharArray();
private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
private static final int DEFAULT_READING_SIZE = 8192;
/* Bundle containing messages */
protected static ResourceBundle bundle;
private final static String bundleName =
"org.eclipse.jdt.internal.compiler.util.messages"; //$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 });
}
/**
* 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 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();
}
/**
* Lookup the message with the given ID in this catalog
*/
public static String bind(String id) {
return bind(id, (String[]) null);
}
/**
* 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;
}
}
/**
* Returns the given bytes as a char array using a given encoding (null means platform default).
*/
public static char[] bytesToChar(byte[] bytes, String encoding) throws IOException {
return getInputStreamAsCharArray(new ByteArrayInputStream(bytes), bytes.length, encoding);
}
/**
* Returns the contents of the given file as a byte array.
* @throws IOException if a problem occured reading the file.
*/
public static byte[] getFileByteContent(File file) throws IOException {
InputStream stream = null;
try {
stream = new BufferedInputStream(new FileInputStream(file));
return getInputStreamAsByteArray(stream, (int) file.length());
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// ignore
}
}
}
}
/**
* 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 BufferedInputStream(new FileInputStream(file));
return Util.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 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;
}
/**
* Returns the given input stream's contents as a character array.
* If a length is specified (ie. if length != -1), only length chars
* are returned. Otherwise all chars in the stream are returned.
* 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;
reader = encoding == null
? new InputStreamReader(stream)
: new InputStreamReader(stream, encoding);
char[] contents;
if (length == -1) {
contents = CharOperation.NO_CHAR;
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 char[contentsLength + amountRequested],
0,
contentsLength);
}
// read as many chars as possible
amountRead = reader.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 char[contentsLength],
0,
contentsLength);
}
} else {
contents = new char[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 = reader.read(contents, len, length - len);
}
// See PR 1FMS89U
// Now we need to resize in case the default encoding used more than one byte for each
// character
if (len != length)
System.arraycopy(contents, 0, (contents = new char[len]), 0, len);
}
return contents;
}
/**
* 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 {
stream = new BufferedInputStream(zip.getInputStream(ze));
return getInputStreamAsByteArray(stream, (int) ze.getSize());
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
// ignore
}
}
}
}
/**
* Returns true iff str.toLowerCase().endsWith(".jar") || str.toLowerCase().endsWith(".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;
// try to match as JAR file
for (int i = 0; i < suffixLength; i++) {
char c = name.charAt(nameLength - i - 1);
int suffixIndex = suffixLength - i - 1;
if (c != SUFFIX_jar[suffixIndex] && c != SUFFIX_JAR[suffixIndex]) {
// try to match as ZIP file
suffixLength = SUFFIX_ZIP.length;
if (nameLength < suffixLength) return false;
for (int j = 0; j < suffixLength; j++) {
c = name.charAt(nameLength - j - 1);
suffixIndex = suffixLength - j - 1;
if (c != SUFFIX_zip[suffixIndex] && c != SUFFIX_ZIP[suffixIndex]) return false;
}
return true;
}
}
return true;
}
/**
* Returns true iff str.toLowerCase().endsWith(".class")
* implementation is not creating extra strings.
*/
public final static boolean isClassFileName(String name) {
int nameLength = name == null ? 0 : name.length();
int suffixLength = SUFFIX_CLASS.length;
if (nameLength < suffixLength) return false;
for (int i = 0; i < suffixLength; i++) {
char c = name.charAt(nameLength - i - 1);
int suffixIndex = suffixLength - i - 1;
if (c != SUFFIX_class[suffixIndex] && c != SUFFIX_CLASS[suffixIndex]) return false;
}
return true;
}
/**
* Returns true iff str.toLowerCase().endsWith(".class")
* implementation is not creating extra strings.
*/
public final static boolean isClassFileName(char[] name) {
int nameLength = name == null ? 0 : name.length;
int suffixLength = SUFFIX_CLASS.length;
if (nameLength < suffixLength) return false;
for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
char c = name[offset + i];
if (c != SUFFIX_class[i] && c != SUFFIX_CLASS[i]) return false;
}
return true;
}
/**
* Returns true iff str.toLowerCase().endsWith(".java")
* implementation is not creating extra strings.
*/
public final static boolean isJavaFileName(String name) {
int nameLength = name == null ? 0 : name.length();
int suffixLength = SUFFIX_JAVA.length;
if (nameLength < suffixLength) return false;
for (int i = 0; i < suffixLength; i++) {
char c = name.charAt(nameLength - i - 1);
int suffixIndex = suffixLength - i - 1;
if (c != SUFFIX_java[suffixIndex] && c != SUFFIX_JAVA[suffixIndex]) return false;
}
return true;
}
/**
* Returns true iff str.toLowerCase().endsWith(".java")
* implementation is not creating extra strings.
*/
public final static boolean isJavaFileName(char[] name) {
int nameLength = name == null ? 0 : name.length;
int suffixLength = SUFFIX_JAVA.length;
if (nameLength < suffixLength) return false;
for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
char c = name[offset + i];
if (c != SUFFIX_java[i] && c != SUFFIX_JAVA[i]) return false;
}
return true;
}
/**
* 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();
}
/**
* Converts a boolean value into Boolean.
* @param bool The boolean to convert
* @return The corresponding Boolean object (TRUE or FALSE).
*/
public static Boolean toBoolean(boolean bool) {
if (bool) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
}
}