1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.util;
13 import java.io.BufferedInputStream;
14 import java.io.ByteArrayInputStream;
16 import java.io.FileInputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.InputStreamReader;
20 import java.util.Locale;
21 import java.util.MissingResourceException;
22 import java.util.ResourceBundle;
23 import java.util.zip.ZipEntry;
24 import java.util.zip.ZipFile;
25 import org.eclipse.jdt.core.compiler.CharOperation;
27 public class Util implements SuffixConstants {
29 public interface Displayable {
30 String displayString(Object o);
33 public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
34 public static char[] LINE_SEPARATOR_CHARS = LINE_SEPARATOR.toCharArray();
36 private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
37 private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
38 private static final int DEFAULT_READING_SIZE = 8192;
40 /* Bundle containing messages */
41 protected static ResourceBundle bundle;
42 private final static String bundleName =
43 "org.eclipse.jdt.internal.compiler.util.messages"; //$NON-NLS-1$
48 * Lookup the message with the given ID in this catalog and bind its
49 * substitution locations with the given strings.
51 public static String bind(String id, String binding1, String binding2) {
52 return bind(id, new String[] { binding1, binding2 });
55 * Lookup the message with the given ID in this catalog and bind its
56 * substitution locations with the given string.
58 public static String bind(String id, String binding) {
59 return bind(id, new String[] { binding });
62 * Lookup the message with the given ID in this catalog and bind its
63 * substitution locations with the given string values.
65 public static String bind(String id, String[] bindings) {
67 return "No message available"; //$NON-NLS-1$
68 String message = null;
70 message = bundle.getString(id);
71 } catch (MissingResourceException e) {
72 // If we got an exception looking for the message, fail gracefully by just returning
73 // the id we were looking for. In most cases this is semi-informative so is not too bad.
74 return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
76 // for compatibility with MessageFormat which eliminates double quotes in original message
77 char[] messageWithNoDoubleQuotes =
78 CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
80 if (bindings == null) return new String(messageWithNoDoubleQuotes);
82 int length = messageWithNoDoubleQuotes.length;
85 StringBuffer output = null;
87 if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start)) > -1) {
88 if (output == null) output = new StringBuffer(length+bindings.length*20);
89 output.append(messageWithNoDoubleQuotes, start, end - start);
90 if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes, end + 1)) > -1) {
92 String argId = new String(messageWithNoDoubleQuotes, end + 1, start - end - 1);
94 index = Integer.parseInt(argId);
95 output.append(bindings[index]);
96 } catch (NumberFormatException nfe) { // could be nested message ID {compiler.name}
98 if (!id.equals(argId)) {
99 String argMessage = null;
101 argMessage = bundle.getString(argId);
102 output.append(argMessage);
104 } catch (MissingResourceException e) {
105 // unable to bind argument, ignore (will leave argument in)
108 if (!done) output.append(messageWithNoDoubleQuotes, end + 1, start - end);
109 } catch (ArrayIndexOutOfBoundsException e) {
110 output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
114 output.append(messageWithNoDoubleQuotes, end, length);
118 if (output == null) return new String(messageWithNoDoubleQuotes);
119 output.append(messageWithNoDoubleQuotes, start, length - start);
123 return output.toString();
126 * Lookup the message with the given ID in this catalog
128 public static String bind(String id) {
129 return bind(id, (String[]) null);
132 * Creates a NLS catalog for the given locale.
134 public static void relocalize() {
136 bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
137 } catch(MissingResourceException e) {
138 System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
143 * Returns the given bytes as a char array using a given encoding (null means platform default).
145 public static char[] bytesToChar(byte[] bytes, String encoding) throws IOException {
147 return getInputStreamAsCharArray(new ByteArrayInputStream(bytes), bytes.length, encoding);
151 * Returns the contents of the given file as a byte array.
152 * @throws IOException if a problem occured reading the file.
154 public static byte[] getFileByteContent(File file) throws IOException {
155 InputStream stream = null;
157 stream = new BufferedInputStream(new FileInputStream(file));
158 return getInputStreamAsByteArray(stream, (int) file.length());
160 if (stream != null) {
163 } catch (IOException e) {
170 * Returns the contents of the given file as a char array.
171 * When encoding is null, then the platform default one is used
172 * @throws IOException if a problem occured reading the file.
174 public static char[] getFileCharContent(File file, String encoding) throws IOException {
175 InputStream stream = null;
177 stream = new BufferedInputStream(new FileInputStream(file));
178 return getInputStreamAsCharArray(stream, (int) file.length(), encoding);
180 if (stream != null) {
183 } catch (IOException e) {
190 * NIO support to get input stream as byte array.
191 * Not used as with JDK 1.4.2 this support is slower than standard IO one...
192 * Keep it as comment for future in case of next JDK versions improve performance
195 public static byte[] getInputStreamAsByteArray(FileInputStream stream, int length)
198 FileChannel channel = stream.getChannel();
199 int size = (int)channel.size();
200 if (length >= 0 && length < size) size = length;
201 byte[] contents = new byte[size];
202 ByteBuffer buffer = ByteBuffer.wrap(contents);
203 channel.read(buffer);
208 * Returns the given input stream's contents as a byte array.
209 * If a length is specified (ie. if length != -1), only length bytes
210 * are returned. Otherwise all bytes in the stream are returned.
211 * Note this doesn't close the stream.
212 * @throws IOException if a problem occured reading the stream.
214 public static byte[] getInputStreamAsByteArray(InputStream stream, int length)
218 contents = new byte[0];
219 int contentsLength = 0;
222 int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K
224 // resize contents if needed
225 if (contentsLength + amountRequested > contents.length) {
229 contents = new byte[contentsLength + amountRequested],
234 // read as many bytes as possible
235 amountRead = stream.read(contents, contentsLength, amountRequested);
237 if (amountRead > 0) {
238 // remember length of contents
239 contentsLength += amountRead;
241 } while (amountRead != -1);
243 // resize contents if necessary
244 if (contentsLength < contents.length) {
248 contents = new byte[contentsLength],
253 contents = new byte[length];
256 while ((readSize != -1) && (len != length)) {
258 // We record first the read size. In this case len is the actual read size.
260 readSize = stream.read(contents, len, length - len);
267 * NIO support to get input stream as char array.
268 * Not used as with JDK 1.4.2 this support is slower than standard IO one...
269 * Keep it as comment for future in case of next JDK versions improve performance
271 public static char[] getInputStreamAsCharArray(FileInputStream stream, int length, String encoding)
274 FileChannel channel = stream.getChannel();
275 int size = (int)channel.size();
276 if (length >= 0 && length < size) size = length;
277 Charset charset = encoding==null?systemCharset:Charset.forName(encoding);
278 if (charset != null) {
279 MappedByteBuffer bbuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
280 CharsetDecoder decoder = charset.newDecoder();
281 CharBuffer buffer = decoder.decode(bbuffer);
282 char[] contents = new char[buffer.limit()];
283 buffer.get(contents);
286 throw new UnsupportedCharsetException(SYSTEM_FILE_ENCODING);
290 * Returns the given input stream's contents as a character array.
291 * If a length is specified (ie. if length != -1), only length chars
292 * are returned. Otherwise all chars in the stream are returned.
293 * Note this doesn't close the stream.
294 * @throws IOException if a problem occured reading the stream.
296 public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding)
298 InputStreamReader reader = null;
299 reader = encoding == null
300 ? new InputStreamReader(stream)
301 : new InputStreamReader(stream, encoding);
304 contents = CharOperation.NO_CHAR;
305 int contentsLength = 0;
308 int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K
310 // resize contents if needed
311 if (contentsLength + amountRequested > contents.length) {
315 contents = new char[contentsLength + amountRequested],
320 // read as many chars as possible
321 amountRead = reader.read(contents, contentsLength, amountRequested);
323 if (amountRead > 0) {
324 // remember length of contents
325 contentsLength += amountRead;
327 } while (amountRead != -1);
329 // Do not keep first character for UTF-8 BOM encoding
331 if (contentsLength > 0 && "UTF-8".equals(encoding)) { //$NON-NLS-1$
332 if (contents[0] == 0xFEFF) { // if BOM char then skip
337 // resize contents if necessary
338 if (contentsLength < contents.length) {
342 contents = new char[contentsLength],
347 contents = new char[length];
350 while ((readSize != -1) && (len != length)) {
352 // We record first the read size. In this case len is the actual read size.
354 readSize = reader.read(contents, len, length - len);
356 // Do not keep first character for UTF-8 BOM encoding
358 if (length > 0 && "UTF-8".equals(encoding)) { //$NON-NLS-1$
359 if (contents[0] == 0xFEFF) { // if BOM char then skip
365 // Now we need to resize in case the default encoding used more than one byte for each
368 System.arraycopy(contents, start, (contents = new char[len]), 0, len);
375 * Returns the contents of the given zip entry as a byte array.
376 * @throws IOException if a problem occured reading the zip entry.
378 public static byte[] getZipEntryByteContent(ZipEntry ze, ZipFile zip)
381 InputStream stream = null;
383 stream = new BufferedInputStream(zip.getInputStream(ze));
384 return getInputStreamAsByteArray(stream, (int) ze.getSize());
386 if (stream != null) {
389 } catch (IOException e) {
396 * Returns true iff str.toLowerCase().endsWith(".jar") || str.toLowerCase().endsWith(".zip")
397 * implementation is not creating extra strings.
399 public final static boolean isArchiveFileName(String name) {
400 int nameLength = name == null ? 0 : name.length();
401 int suffixLength = SUFFIX_JAR.length;
402 if (nameLength < suffixLength) return false;
404 // try to match as JAR file
405 for (int i = 0; i < suffixLength; i++) {
406 char c = name.charAt(nameLength - i - 1);
407 int suffixIndex = suffixLength - i - 1;
408 if (c != SUFFIX_jar[suffixIndex] && c != SUFFIX_JAR[suffixIndex]) {
410 // try to match as ZIP file
411 suffixLength = SUFFIX_ZIP.length;
412 if (nameLength < suffixLength) return false;
413 for (int j = 0; j < suffixLength; j++) {
414 c = name.charAt(nameLength - j - 1);
415 suffixIndex = suffixLength - j - 1;
416 if (c != SUFFIX_zip[suffixIndex] && c != SUFFIX_ZIP[suffixIndex]) return false;
424 * Returns true iff str.toLowerCase().endsWith(".class")
425 * implementation is not creating extra strings.
427 public final static boolean isClassFileName(String name) {
428 int nameLength = name == null ? 0 : name.length();
429 int suffixLength = SUFFIX_CLASS.length;
430 if (nameLength < suffixLength) return false;
432 for (int i = 0; i < suffixLength; i++) {
433 char c = name.charAt(nameLength - i - 1);
434 int suffixIndex = suffixLength - i - 1;
435 if (c != SUFFIX_class[suffixIndex] && c != SUFFIX_CLASS[suffixIndex]) return false;
440 * Returns true iff str.toLowerCase().endsWith(".class")
441 * implementation is not creating extra strings.
443 public final static boolean isClassFileName(char[] name) {
444 int nameLength = name == null ? 0 : name.length;
445 int suffixLength = SUFFIX_CLASS.length;
446 if (nameLength < suffixLength) return false;
448 for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
449 char c = name[offset + i];
450 if (c != SUFFIX_class[i] && c != SUFFIX_CLASS[i]) return false;
455 * Returns true iff str.toLowerCase().endsWith(".java")
456 * implementation is not creating extra strings.
458 public final static boolean isJavaFileName(String name) {
459 int nameLength = name == null ? 0 : name.length();
460 int suffixLength = SUFFIX_JAVA.length;
461 if (nameLength < suffixLength) return false;
463 for (int i = 0; i < suffixLength; i++) {
464 char c = name.charAt(nameLength - i - 1);
465 int suffixIndex = suffixLength - i - 1;
466 if (c != SUFFIX_java[suffixIndex] && c != SUFFIX_JAVA[suffixIndex]) return false;
471 * Returns true iff str.toLowerCase().endsWith(".java")
472 * implementation is not creating extra strings.
474 public final static boolean isJavaFileName(char[] name) {
475 int nameLength = name == null ? 0 : name.length;
476 int suffixLength = SUFFIX_JAVA.length;
477 if (nameLength < suffixLength) return false;
479 for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
480 char c = name[offset + i];
481 if (c != SUFFIX_java[i] && c != SUFFIX_JAVA[i]) return false;
486 * Converts an array of Objects into String.
488 public static String toString(Object[] objects) {
489 return toString(objects,
491 public String displayString(Object o) {
492 if (o == null) return "null"; //$NON-NLS-1$
499 * Converts an array of Objects into String.
501 public static String toString(Object[] objects, Displayable renderer) {
502 if (objects == null) return ""; //$NON-NLS-1$
503 StringBuffer buffer = new StringBuffer(10);
504 for (int i = 0; i < objects.length; i++){
505 if (i > 0) buffer.append(", "); //$NON-NLS-1$
506 buffer.append(renderer.displayString(objects[i]));
508 return buffer.toString();
512 * Converts a boolean value into Boolean.
513 * @param bool The boolean to convert
514 * @return The corresponding Boolean object (TRUE or FALSE).
516 public static Boolean toBoolean(boolean bool) {
520 return Boolean.FALSE;