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);
36 /* Bundle containing messages */
37 protected static ResourceBundle bundle;
38 private final static String bundleName =
39 "org.eclipse.jdt.internal.compiler.util.messages"; //$NON-NLS-1$
40 private static final int DEFAULT_READING_SIZE = 8192;
42 private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
44 public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
45 public static char[] LINE_SEPARATOR_CHARS = LINE_SEPARATOR.toCharArray();
46 private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
49 * Lookup the message with the given ID in this catalog
51 public static String bind(String id) {
52 return bind(id, (String[]) null);
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 argument) {
59 return bind(id, new String[] { argument });
62 * Lookup the message with the given ID in this catalog and bind its
63 * substitution locations with the given strings.
65 public static String bind(String id, String argument1, String argument2) {
66 return bind(id, new String[] { argument1, argument2 });
69 * Lookup the message with the given ID in this catalog and bind its
70 * substitution locations with the given string values.
72 public static String bind(String id, String[] arguments) {
74 return "No message available"; //$NON-NLS-1$
75 String message = null;
77 message = bundle.getString(id);
78 } catch (MissingResourceException e) {
79 // If we got an exception looking for the message, fail gracefully by just returning
80 // the id we were looking for. In most cases this is semi-informative so is not too bad.
81 return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
83 return bindMessage(message, arguments);
86 * Bind some message with given string values.
88 public static String bindMessage(String message, String[] arguments) {
89 // for compatibility with MessageFormat which eliminates double quotes in original message
90 char[] messageWithNoDoubleQuotes =
91 CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
93 if (arguments == null) return new String(messageWithNoDoubleQuotes);
95 int length = messageWithNoDoubleQuotes.length;
98 StringBuffer output = null;
100 if ((end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start)) > -1) {
101 if (output == null) output = new StringBuffer(length+arguments.length*20);
102 output.append(messageWithNoDoubleQuotes, start, end - start);
103 if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes, end + 1)) > -1) {
105 String argId = new String(messageWithNoDoubleQuotes, end + 1, start - end - 1);
107 index = Integer.parseInt(argId);
108 if (arguments[index] == null) {
109 output.append('{').append(argId).append('}'); // leave parameter in since no better arg '{0}'
111 output.append(arguments[index]);
113 } catch (NumberFormatException nfe) { // could be nested message ID {compiler.name}
114 boolean done = false;
115 String argMessage = null;
117 argMessage = bundle.getString(argId);
118 output.append(argMessage);
120 } catch (MissingResourceException e) {
121 // unable to bind argument, ignore (will leave argument in)
123 if (!done) output.append(messageWithNoDoubleQuotes, end + 1, start - end);
124 } catch (ArrayIndexOutOfBoundsException e) {
125 output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
129 output.append(messageWithNoDoubleQuotes, end, length);
133 if (output == null) return new String(messageWithNoDoubleQuotes);
134 output.append(messageWithNoDoubleQuotes, start, length - start);
138 return output.toString();
141 * Returns the given bytes as a char array using a given encoding (null means platform default).
143 public static char[] bytesToChar(byte[] bytes, String encoding) throws IOException {
145 return getInputStreamAsCharArray(new ByteArrayInputStream(bytes), bytes.length, encoding);
149 * Returns the contents of the given file as a byte array.
150 * @throws IOException if a problem occured reading the file.
152 public static byte[] getFileByteContent(File file) throws IOException {
153 InputStream stream = null;
155 stream = new BufferedInputStream(new FileInputStream(file));
156 return getInputStreamAsByteArray(stream, (int) file.length());
158 if (stream != null) {
161 } catch (IOException e) {
168 * Returns the contents of the given file as a char array.
169 * When encoding is null, then the platform default one is used
170 * @throws IOException if a problem occured reading the file.
172 public static char[] getFileCharContent(File file, String encoding) throws IOException {
173 InputStream stream = null;
175 stream = new BufferedInputStream(new FileInputStream(file));
176 return getInputStreamAsCharArray(stream, (int) file.length(), encoding);
178 if (stream != null) {
181 } catch (IOException e) {
188 * NIO support to get input stream as byte array.
189 * Not used as with JDK 1.4.2 this support is slower than standard IO one...
190 * Keep it as comment for future in case of next JDK versions improve performance
193 public static byte[] getInputStreamAsByteArray(FileInputStream stream, int length)
196 FileChannel channel = stream.getChannel();
197 int size = (int)channel.size();
198 if (length >= 0 && length < size) size = length;
199 byte[] contents = new byte[size];
200 ByteBuffer buffer = ByteBuffer.wrap(contents);
201 channel.read(buffer);
206 * Returns the given input stream's contents as a byte array.
207 * If a length is specified (ie. if length != -1), only length bytes
208 * are returned. Otherwise all bytes in the stream are returned.
209 * Note this doesn't close the stream.
210 * @throws IOException if a problem occured reading the stream.
212 public static byte[] getInputStreamAsByteArray(InputStream stream, int length)
216 contents = new byte[0];
217 int contentsLength = 0;
220 int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K
222 // resize contents if needed
223 if (contentsLength + amountRequested > contents.length) {
227 contents = new byte[contentsLength + amountRequested],
232 // read as many bytes as possible
233 amountRead = stream.read(contents, contentsLength, amountRequested);
235 if (amountRead > 0) {
236 // remember length of contents
237 contentsLength += amountRead;
239 } while (amountRead != -1);
241 // resize contents if necessary
242 if (contentsLength < contents.length) {
246 contents = new byte[contentsLength],
251 contents = new byte[length];
254 while ((readSize != -1) && (len != length)) {
256 // We record first the read size. In this case len is the actual read size.
258 readSize = stream.read(contents, len, length - len);
265 * NIO support to get input stream as char array.
266 * Not used as with JDK 1.4.2 this support is slower than standard IO one...
267 * Keep it as comment for future in case of next JDK versions improve performance
269 public static char[] getInputStreamAsCharArray(FileInputStream stream, int length, String encoding)
272 FileChannel channel = stream.getChannel();
273 int size = (int)channel.size();
274 if (length >= 0 && length < size) size = length;
275 Charset charset = encoding==null?systemCharset:Charset.forName(encoding);
276 if (charset != null) {
277 MappedByteBuffer bbuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
278 CharsetDecoder decoder = charset.newDecoder();
279 CharBuffer buffer = decoder.decode(bbuffer);
280 char[] contents = new char[buffer.limit()];
281 buffer.get(contents);
284 throw new UnsupportedCharsetException(SYSTEM_FILE_ENCODING);
288 * Returns the given input stream's contents as a character array.
289 * If a length is specified (ie. if length != -1), only length chars
290 * are returned. Otherwise all chars in the stream are returned.
291 * Note this doesn't close the stream.
292 * @throws IOException if a problem occured reading the stream.
294 public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding)
296 InputStreamReader reader = null;
297 reader = encoding == null
298 ? new InputStreamReader(stream)
299 : new InputStreamReader(stream, encoding);
302 contents = CharOperation.NO_CHAR;
303 int contentsLength = 0;
306 int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K
308 // resize contents if needed
309 if (contentsLength + amountRequested > contents.length) {
313 contents = new char[contentsLength + amountRequested],
318 // read as many chars as possible
319 amountRead = reader.read(contents, contentsLength, amountRequested);
321 if (amountRead > 0) {
322 // remember length of contents
323 contentsLength += amountRead;
325 } while (amountRead != -1);
327 // Do not keep first character for UTF-8 BOM encoding
329 if (contentsLength > 0 && "UTF-8".equals(encoding)) { //$NON-NLS-1$
330 if (contents[0] == 0xFEFF) { // if BOM char then skip
335 // resize contents if necessary
336 if (contentsLength < contents.length) {
340 contents = new char[contentsLength],
345 contents = new char[length];
348 while ((readSize != -1) && (len != length)) {
350 // We record first the read size. In this case len is the actual read size.
352 readSize = reader.read(contents, len, length - len);
354 // Do not keep first character for UTF-8 BOM encoding
356 if (length > 0 && "UTF-8".equals(encoding)) { //$NON-NLS-1$
357 if (contents[0] == 0xFEFF) { // if BOM char then skip
363 // Now we need to resize in case the default encoding used more than one byte for each
366 System.arraycopy(contents, start, (contents = new char[len]), 0, len);
373 * Returns the contents of the given zip entry as a byte array.
374 * @throws IOException if a problem occured reading the zip entry.
376 public static byte[] getZipEntryByteContent(ZipEntry ze, ZipFile zip)
379 InputStream stream = null;
381 stream = new BufferedInputStream(zip.getInputStream(ze));
382 return getInputStreamAsByteArray(stream, (int) ze.getSize());
384 if (stream != null) {
387 } catch (IOException e) {
394 * Returns true iff str.toLowerCase().endsWith(".jar") || str.toLowerCase().endsWith(".zip")
395 * implementation is not creating extra strings.
397 public final static boolean isArchiveFileName(String name) {
398 int nameLength = name == null ? 0 : name.length();
399 int suffixLength = SUFFIX_JAR.length;
400 if (nameLength < suffixLength) return false;
402 // try to match as JAR file
403 for (int i = 0; i < suffixLength; i++) {
404 char c = name.charAt(nameLength - i - 1);
405 int suffixIndex = suffixLength - i - 1;
406 if (c != SUFFIX_jar[suffixIndex] && c != SUFFIX_JAR[suffixIndex]) {
408 // try to match as ZIP file
409 suffixLength = SUFFIX_ZIP.length;
410 if (nameLength < suffixLength) return false;
411 for (int j = 0; j < suffixLength; j++) {
412 c = name.charAt(nameLength - j - 1);
413 suffixIndex = suffixLength - j - 1;
414 if (c != SUFFIX_zip[suffixIndex] && c != SUFFIX_ZIP[suffixIndex]) return false;
422 * Returns true iff str.toLowerCase().endsWith(".class")
423 * implementation is not creating extra strings.
425 public final static boolean isClassFileName(char[] name) {
426 int nameLength = name == null ? 0 : name.length;
427 int suffixLength = SUFFIX_CLASS.length;
428 if (nameLength < suffixLength) return false;
430 for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
431 char c = name[offset + i];
432 if (c != SUFFIX_class[i] && c != SUFFIX_CLASS[i]) return false;
437 * Returns true iff str.toLowerCase().endsWith(".class")
438 * implementation is not creating extra strings.
440 public final static boolean isClassFileName(String name) {
441 int nameLength = name == null ? 0 : name.length();
442 int suffixLength = SUFFIX_CLASS.length;
443 if (nameLength < suffixLength) return false;
445 for (int i = 0; i < suffixLength; i++) {
446 char c = name.charAt(nameLength - i - 1);
447 int suffixIndex = suffixLength - i - 1;
448 if (c != SUFFIX_class[suffixIndex] && c != SUFFIX_CLASS[suffixIndex]) return false;
452 /* TODO (philippe) should consider promoting it to CharOperation
453 * Returns whether the given resource path matches one of the inclusion/exclusion
455 * NOTE: should not be asked directly using pkg root pathes
456 * @see IClasspathEntry#getInclusionPatterns
457 * @see IClasspathEntry#getExclusionPatterns
459 public final static boolean isExcluded(char[] path, char[][] inclusionPatterns, char[][] exclusionPatterns, boolean isFolderPath) {
460 if (inclusionPatterns == null && exclusionPatterns == null) return false;
462 inclusionCheck: if (inclusionPatterns != null) {
463 for (int i = 0, length = inclusionPatterns.length; i < length; i++) {
464 char[] pattern = inclusionPatterns[i];
465 char[] folderPattern = pattern;
467 int lastSlash = CharOperation.lastIndexOf('/', pattern);
468 if (lastSlash != -1 && lastSlash != pattern.length-1){ // trailing slash -> adds '**' for free (see http://ant.apache.org/manual/dirtasks.html)
469 int star = CharOperation.indexOf('*', pattern, lastSlash);
471 || star >= pattern.length-1
472 || pattern[star+1] != '*')) {
473 folderPattern = CharOperation.subarray(pattern, 0, lastSlash);
477 if (CharOperation.pathMatch(folderPattern, path, true, '/')) {
478 break inclusionCheck;
481 return true; // never included
484 path = CharOperation.concat(path, new char[] {'*'}, '/');
486 exclusionCheck: if (exclusionPatterns != null) {
487 for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
488 if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/')) {
496 * Returns true iff str.toLowerCase().endsWith(".java")
497 * implementation is not creating extra strings.
499 public final static boolean isJavaFileName(char[] name) {
500 int nameLength = name == null ? 0 : name.length;
501 int suffixLength = SUFFIX_JAVA.length;
502 if (nameLength < suffixLength) return false;
504 for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
505 char c = name[offset + i];
506 if (c != SUFFIX_java[i] && c != SUFFIX_JAVA[i]) return false;
511 * Returns true iff str.toLowerCase().endsWith(".java")
512 * implementation is not creating extra strings.
514 public final static boolean isJavaFileName(String name) {
515 int nameLength = name == null ? 0 : name.length();
516 int suffixLength = SUFFIX_JAVA.length;
517 if (nameLength < suffixLength) return false;
519 for (int i = 0; i < suffixLength; i++) {
520 char c = name.charAt(nameLength - i - 1);
521 int suffixIndex = suffixLength - i - 1;
522 if (c != SUFFIX_java[suffixIndex] && c != SUFFIX_JAVA[suffixIndex]) return false;
527 * Creates a NLS catalog for the given locale.
529 public static void relocalize() {
531 bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
532 } catch(MissingResourceException e) {
533 System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
539 * Converts a boolean value into Boolean.
540 * @param bool The boolean to convert
541 * @return The corresponding Boolean object (TRUE or FALSE).
543 public static Boolean toBoolean(boolean bool) {
547 return Boolean.FALSE;
551 * Converts an array of Objects into String.
553 public static String toString(Object[] objects) {
554 return toString(objects,
556 public String displayString(Object o) {
557 if (o == null) return "null"; //$NON-NLS-1$
564 * Converts an array of Objects into String.
566 public static String toString(Object[] objects, Displayable renderer) {
567 if (objects == null) return ""; //$NON-NLS-1$
568 StringBuffer buffer = new StringBuffer(10);
569 for (int i = 0; i < objects.length; i++){
570 if (i > 0) buffer.append(", "); //$NON-NLS-1$
571 buffer.append(renderer.displayString(objects[i]));
573 return buffer.toString();