/******************************************************************************* * Copyright (c) 2005, 2007 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 * *******************************************************************************/ package org.eclipse.dltk.compiler.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.dltk.compiler.CharOperation; import org.eclipse.dltk.core.IDLTKLanguageToolkit; import org.eclipse.dltk.core.IDLTKLanguageToolkitExtension; import org.eclipse.dltk.core.RuntimePerformanceMonitor; import org.eclipse.dltk.core.RuntimePerformanceMonitor.PerformanceNode; import org.eclipse.emf.common.util.URI; import org.eclipse.osgi.util.NLS; public class Util { /** * Some input streams return available() as zero, so we need this value. */ 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$ public static final String EMPTY_STRING = ""; //$NON-NLS-1$ /** * @since 2.0 */ public static final Object[] EMPTY_ARRAY = new Object[0]; /** * 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 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; PerformanceNode p = RuntimePerformanceMonitor.begin(); try { stream = new FileInputStream(file); byte[] data = getInputStreamAsByteArray(stream, (int) file.length()); p.done("#", RuntimePerformanceMonitor.IOREAD, data.length); return data; } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // ignore } } } } /** * @since 2.0 */ public static byte[] getFileByteContent(IFileStore file) throws CoreException, IOException { InputStream stream = null; PerformanceNode p = RuntimePerformanceMonitor.begin(); try { stream = file.openInputStream(EFS.NONE, new NullProgressMonitor()); IFileInfo info = file.fetchInfo(); byte[] data = getInputStreamAsByteArray(stream, (int) info.getLength()); p.done("#", RuntimePerformanceMonitor.IOREAD, data.length); return data; } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // ignore } } } } /* * a character array. If a length is specified (ie. if length != -1), this * represents the number of bytes in the stream. 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 { try { reader = encoding == null ? new InputStreamReader( toBufferedInputStream(stream)) : new InputStreamReader( stream, encoding); } catch (UnsupportedEncodingException e) { // encoding is not supported reader = new InputStreamReader(toBufferedInputStream(stream)); } char[] contents; int totalRead = 0; if (length == -1) { contents = CharOperation.NO_CHAR; } else { // length is a good guess when the encoding produces less or the // same amount of characters than the file length contents = new char[length]; // best guess } while (true) { int amountRequested; if (totalRead < length) { // until known length is met, reuse same array sized eagerly amountRequested = length - totalRead; } else { // reading beyond known length int current = reader.read(); if (current < 0) break; amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K // resize contents if needed if (totalRead + 1 + amountRequested > contents.length) System.arraycopy(contents, 0, contents = new char[totalRead + 1 + amountRequested], 0, totalRead); // add current character contents[totalRead++] = (char) current; // coming from // totalRead==length } // read as many chars as possible int amountRead = reader.read(contents, totalRead, amountRequested); if (amountRead < 0) break; totalRead += amountRead; } // Do not keep first character for UTF-8 BOM encoding int start = 0; if (totalRead > 0 && UTF_8.equals(encoding)) { if (contents[0] == 0xFEFF) { // if BOM char then skip totalRead--; start = 1; } } // resize contents if necessary if (totalRead < contents.length) System.arraycopy(contents, start, contents = new char[totalRead], 0, totalRead); return contents; } finally { if (reader != null) { reader.close(); } } } private static InputStream toBufferedInputStream(InputStream stream) { if (stream instanceof BufferedInputStream) { return stream; } else { return new BufferedInputStream(stream, DEFAULT_READING_SIZE); } } private final static char[] SUFFIX_zip = new char[] { '.', 'z', 'i', 'p' }; private final static char[] SUFFIX_ZIP = new char[] { '.', 'Z', 'I', 'P' }; /** * Returns <code>true</code> if str.toLowerCase().endsWith(".zip") * implementation is not creating extra strings. */ public final static boolean isArchiveFileName(String name) { if (name == null) { return false; } final int nameLength = name.length(); final int suffixLength = SUFFIX_ZIP.length; if (nameLength < suffixLength) return false; for (int i = 0; i < suffixLength; i++) { final char c = name.charAt(nameLength - i - 1); final int suffixIndex = suffixLength - i - 1; if (c != SUFFIX_zip[suffixIndex] && c != SUFFIX_ZIP[suffixIndex]) { return false; } } return true; } public final static boolean isArchiveFileName(IDLTKLanguageToolkit toolkit, String name) { if (name == null) { return false; } if (toolkit instanceof IDLTKLanguageToolkitExtension) { IDLTKLanguageToolkitExtension ext = (IDLTKLanguageToolkitExtension) toolkit; if (ext.isArchiveFileName(name)) { return true; } } final int nameLength = name.length(); final int suffixLength = SUFFIX_ZIP.length; if (nameLength < suffixLength) return false; for (int i = 0; i < suffixLength; i++) { final char c = name.charAt(nameLength - i - 1); final int suffixIndex = suffixLength - i - 1; if (c != SUFFIX_zip[suffixIndex] && c != SUFFIX_ZIP[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 */ 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 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; PerformanceNode p = RuntimePerformanceMonitor.begin(); try { stream = new FileInputStream(file); char[] data = getInputStreamAsCharArray(stream, (int) file.length(), encoding); p.done("#", RuntimePerformanceMonitor.IOREAD, data.length); return data; } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // ignore } } } } public static void copy(File file, InputStream input) throws IOException { PerformanceNode p = RuntimePerformanceMonitor.begin(); OutputStream fos = new BufferedOutputStream(new FileOutputStream(file)); try { copy(input, fos); } finally { try { fos.close(); } catch (IOException e) { // ignore } } p.done("#", RuntimePerformanceMonitor.IOWRITE, file.length()); } public static void copy(InputStream input, OutputStream fos) throws IOException { byte[] buf = new byte[8192]; int n = 0; while ((n = input.read(buf)) >= 0) { fos.write(buf, 0, n); } } /** * @since 2.0 */ public static File toFile(URL url) throws IOException { final URL local = FileLocator.toFileURL(url); if (!"file".equalsIgnoreCase(local.getProtocol())) { //$NON-NLS-1$ throw new IllegalArgumentException(NLS.bind( "Can't convert {0} to file", url)); //$NON-NLS-1$ } return new File(URI.decode(local.getFile())); } }