--- /dev/null
+/*******************************************************************************
+ * 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 getInputStreamAsCharArray(stream, (int) file.length(), encoding);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+ /*
+ * NIO support to get input stream as byte array.
+ * Not used as with JDK 1.4.2 this support is slower than standard IO one...
+ * Keep it as comment for future in case of next JDK versions improve performance
+ * in this area...
+ *
+ public static byte[] getInputStreamAsByteArray(FileInputStream stream, int length)
+ throws IOException {
+
+ FileChannel channel = stream.getChannel();
+ int size = (int)channel.size();
+ if (length >= 0 && length < size) size = length;
+ byte[] contents = new byte[size];
+ ByteBuffer buffer = ByteBuffer.wrap(contents);
+ channel.read(buffer);
+ return contents;
+ }
+ */
+ /**
+ * 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;
+ }
+ /*
+ * NIO support to get input stream as char array.
+ * Not used as with JDK 1.4.2 this support is slower than standard IO one...
+ * Keep it as comment for future in case of next JDK versions improve performance
+ * in this area...
+ public static char[] getInputStreamAsCharArray(FileInputStream stream, int length, String encoding)
+ throws IOException {
+
+ FileChannel channel = stream.getChannel();
+ int size = (int)channel.size();
+ if (length >= 0 && length < size) size = length;
+ Charset charset = encoding==null?systemCharset:Charset.forName(encoding);
+ if (charset != null) {
+ MappedByteBuffer bbuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
+ CharsetDecoder decoder = charset.newDecoder();
+ CharBuffer buffer = decoder.decode(bbuffer);
+ char[] contents = new char[buffer.limit()];
+ buffer.get(contents);
+ return contents;
+ }
+ throw new UnsupportedCharsetException(SYSTEM_FILE_ENCODING);
+ }
+ */
+ /**
+ * 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);
+
+ // Do not keep first character for UTF-8 BOM encoding
+ int start = 0;
+ if (contentsLength > 0 && "UTF-8".equals(encoding)) { //$NON-NLS-1$
+ if (contents[0] == 0xFEFF) { // if BOM char then skip
+ contentsLength--;
+ start = 1;
+ }
+ }
+ // resize contents if necessary
+ if (contentsLength < contents.length) {
+ System.arraycopy(
+ contents,
+ start,
+ 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);
+ }
+ // Do not keep first character for UTF-8 BOM encoding
+ int start = 0;
+ if (length > 0 && "UTF-8".equals(encoding)) { //$NON-NLS-1$
+ if (contents[0] == 0xFEFF) { // if BOM char then skip
+ len--;
+ start = 1;
+ }
+ }
+ // 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, start, (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;
+ }
+ }
+}