| /******************************************************************************* |
| * Copyright (c) 2000, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-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.io.UnsupportedEncodingException; |
| 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); |
| } |
| |
| 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$ |
| |
| /** |
| * 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; |
| try { |
| reader = encoding == null |
| ? new InputStreamReader(stream) |
| : new InputStreamReader(stream, encoding); |
| } catch (UnsupportedEncodingException e) { |
| // encoding is not supported |
| reader = new InputStreamReader(stream); |
| } |
| 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)) { |
| 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)) { |
| 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(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(".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; |
| } |
| /* TODO (philippe) should consider promoting it to CharOperation |
| * Returns whether the given resource path matches one of the inclusion/exclusion |
| * patterns. |
| * NOTE: should not be asked directly using pkg root pathes |
| * @see IClasspathEntry#getInclusionPatterns |
| * @see IClasspathEntry#getExclusionPatterns |
| */ |
| public final static boolean isExcluded(char[] path, char[][] inclusionPatterns, char[][] exclusionPatterns, boolean isFolderPath) { |
| if (inclusionPatterns == null && exclusionPatterns == null) return false; |
| |
| inclusionCheck: if (inclusionPatterns != null) { |
| for (int i = 0, length = inclusionPatterns.length; i < length; i++) { |
| char[] pattern = inclusionPatterns[i]; |
| char[] folderPattern = pattern; |
| if (isFolderPath) { |
| int lastSlash = CharOperation.lastIndexOf('/', pattern); |
| if (lastSlash != -1 && lastSlash != pattern.length-1){ // trailing slash -> adds '**' for free (see http://ant.apache.org/manual/dirtasks.html) |
| int star = CharOperation.indexOf('*', pattern, lastSlash); |
| if ((star == -1 |
| || star >= pattern.length-1 |
| || pattern[star+1] != '*')) { |
| folderPattern = CharOperation.subarray(pattern, 0, lastSlash); |
| } |
| } |
| } |
| if (CharOperation.pathMatch(folderPattern, path, true, '/')) { |
| break inclusionCheck; |
| } |
| } |
| return true; // never included |
| } |
| if (isFolderPath) { |
| path = CharOperation.concat(path, new char[] {'*'}, '/'); |
| } |
| if (exclusionPatterns != null) { |
| for (int i = 0, length = exclusionPatterns.length; i < length; i++) { |
| if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/')) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| /** |
| * 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; |
| } |
| /** |
| * 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; |
| } |
| |
| /** |
| * 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; |
| } |
| } |
| /** |
| * 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(); |
| } |
| } |