| /* |
| * Copyright (c) 2014, 2015 Eike Stepper (Berlin, Germany) 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: |
| * Eike Stepper - initial API and implementation |
| * Christian W. Damus (CEA LIST) - bug 418454 |
| */ |
| package org.eclipse.oomph.util; |
| |
| import org.eclipse.oomph.internal.util.UtilPlugin; |
| |
| import org.w3c.dom.Document; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.dom.DOMSource; |
| import javax.xml.transform.stream.StreamResult; |
| |
| import java.io.BufferedReader; |
| import java.io.BufferedWriter; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.Closeable; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.FilterInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.ObjectStreamClass; |
| import java.io.OutputStream; |
| import java.io.OutputStreamWriter; |
| import java.io.Reader; |
| import java.io.Serializable; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| import java.net.URL; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.StringTokenizer; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public final class IOUtil |
| { |
| private static final int MAX_FILE_NAME_LENGTH = 200; |
| |
| private static final byte[] BUFFER = new byte[8192]; |
| |
| private static final ObjectOutputStream DEV_NULL = createDevNull(); |
| |
| private static final String IMAGE_DATA_PREFIX = "imagedata:"; |
| |
| private IOUtil() |
| { |
| } |
| |
| private static ObjectOutputStream createDevNull() |
| { |
| try |
| { |
| return new ObjectOutputStream(new OutputStream() |
| { |
| @Override |
| public void write(int b) throws IOException |
| { |
| // Do nothing. |
| } |
| }); |
| } |
| catch (IOException ex) |
| { |
| // Can't happen. |
| return null; |
| } |
| } |
| |
| public static boolean isValidFolder(File folder) |
| { |
| try |
| { |
| return folder.isDirectory() && folder.getAbsoluteFile().equals(folder.getCanonicalFile()); |
| } |
| catch (IOException ex) |
| { |
| return false; |
| } |
| } |
| |
| public static File getExistingFolder(File file) |
| { |
| if (file.isDirectory()) |
| { |
| return file.getAbsoluteFile(); |
| } |
| |
| File parent = file.getParentFile(); |
| if (parent != null) |
| { |
| return getExistingFolder(parent); |
| } |
| |
| return null; |
| } |
| |
| public static File getFromPath(String command) |
| { |
| String path = System.getenv().get("PATH"); |
| |
| StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator); |
| while (tokenizer.hasMoreTokens()) |
| { |
| String folder = tokenizer.nextToken(); |
| File file = new File(folder, command); |
| if (file.isFile()) |
| { |
| return file; |
| } |
| } |
| |
| return null; |
| } |
| |
| public static boolean isSerializeable(Object object) |
| { |
| try |
| { |
| DEV_NULL.writeObject(object); |
| return true; |
| } |
| catch (Exception ex) |
| { |
| return false; |
| } |
| } |
| |
| public static byte[] serialize(Serializable object) |
| { |
| try |
| { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| |
| ObjectOutputStream stream = new ObjectOutputStream(baos); |
| stream.writeObject(object); |
| stream.flush(); |
| |
| return baos.toByteArray(); |
| } |
| catch (Exception ex) |
| { |
| UtilPlugin.INSTANCE.log(ex); |
| return null; |
| } |
| } |
| |
| public static Serializable deserialize(byte[] bytes) |
| { |
| try |
| { |
| ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(bytes)); |
| return (Serializable)stream.readObject(); |
| } |
| catch (Exception ex) |
| { |
| UtilPlugin.INSTANCE.log(ex); |
| return null; |
| } |
| } |
| |
| public static Serializable deserialize(byte[] bytes, final ClassLoader classLoader) |
| { |
| try |
| { |
| ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(bytes)) |
| { |
| @Override |
| protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException |
| { |
| if (classLoader != null) |
| { |
| String className = desc.getName(); |
| |
| try |
| { |
| Class<?> c = classLoader.loadClass(className); |
| if (c != null) |
| { |
| return c; |
| } |
| } |
| catch (ClassNotFoundException ex) |
| { |
| if (!StackTraceElement[].class.getName().equals(className)) |
| { |
| UtilPlugin.INSTANCE.log(ex); |
| } |
| } |
| } |
| |
| return super.resolveClass(desc); |
| } |
| }; |
| |
| return (Serializable)stream.readObject(); |
| } |
| catch (Exception ex) |
| { |
| UtilPlugin.INSTANCE.log(ex); |
| return null; |
| } |
| } |
| |
| public static byte[] getSHA1(String contents) throws NoSuchAlgorithmException, IOException |
| { |
| return getSHA1(new ByteArrayInputStream(contents.getBytes())); |
| } |
| |
| public static byte[] getSHA1(InputStream contents) throws NoSuchAlgorithmException, IOException |
| { |
| InputStream stream = null; |
| |
| try |
| { |
| final MessageDigest digest = MessageDigest.getInstance("SHA-1"); |
| stream = new FilterInputStream(contents) |
| { |
| @Override |
| public int read() throws IOException |
| { |
| for (;;) |
| { |
| int ch = super.read(); |
| switch (ch) |
| { |
| case -1: |
| return -1; |
| |
| case 10: |
| case 13: |
| continue; |
| } |
| |
| digest.update((byte)ch); |
| return ch; |
| } |
| } |
| |
| @Override |
| public int read(byte[] b, int off, int len) throws IOException |
| { |
| int read = super.read(b, off, len); |
| if (read == -1) |
| { |
| return -1; |
| } |
| |
| for (int i = off; i < off + read; i++) |
| { |
| byte c = b[i]; |
| if (c == 10 || c == 13) |
| { |
| if (i + 1 < off + read) |
| { |
| System.arraycopy(b, i + 1, b, i, read - i - 1); |
| --i; |
| } |
| |
| --read; |
| } |
| } |
| |
| digest.update(b, off, read); |
| return read; |
| } |
| }; |
| |
| synchronized (BUFFER) |
| { |
| while (stream.read(BUFFER) != -1) |
| { |
| // Do nothing |
| } |
| } |
| |
| return digest.digest(); |
| } |
| finally |
| { |
| close(stream); |
| } |
| } |
| |
| public static String encodeFileName(String path) |
| { |
| String result = path.replace(':', '_').replace('/', '_').replace('\\', '_').replace('?', '_'); |
| |
| int length = result.length(); |
| if (length > MAX_FILE_NAME_LENGTH) |
| { |
| String digest; |
| |
| try |
| { |
| byte[] bytes = getSHA1(result); |
| digest = "-" + HexUtil.bytesToHex(bytes) + "-"; |
| } |
| catch (Exception ex) |
| { |
| digest = "---" + result.hashCode() + "---"; |
| } |
| |
| int half = (MAX_FILE_NAME_LENGTH - digest.length() >> 1) - 1; |
| result = result.substring(0, half) + digest + result.substring(result.length() - half); |
| } |
| |
| return result; |
| } |
| |
| public static String encodeImageData(String imageURI) |
| { |
| if (!imageURI.startsWith(IMAGE_DATA_PREFIX)) |
| { |
| int lastDot = imageURI.lastIndexOf('.'); |
| if (lastDot != -1) |
| { |
| String extension = imageURI.substring(lastDot); |
| InputStream in = null; |
| |
| try |
| { |
| in = new URL(imageURI).openStream(); |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| copy(in, baos); |
| |
| String data = HexUtil.bytesToHex(baos.toByteArray()); |
| imageURI = IMAGE_DATA_PREFIX + data + extension; |
| } |
| catch (Exception ex) |
| { |
| //$FALL-THROUGH$ |
| } |
| finally |
| { |
| closeSilent(in); |
| } |
| } |
| } |
| |
| return imageURI; |
| } |
| |
| public static String decodeImageData(String imageURI) |
| { |
| if (imageURI.startsWith(IMAGE_DATA_PREFIX)) |
| { |
| String data = imageURI.substring(IMAGE_DATA_PREFIX.length()); |
| OutputStream out = null; |
| |
| try |
| { |
| byte[] digest = getSHA1(data); |
| |
| int lastDot = data.lastIndexOf('.'); |
| if (lastDot != -1) |
| { |
| String extension = data.substring(lastDot); |
| data = data.substring(0, lastDot); |
| |
| File iconFile = new File(PropertiesUtil.getProperty("java.io.tmpdir"), "icon-" + HexUtil.bytesToHex(digest) + extension); |
| if (!iconFile.exists()) |
| { |
| ByteArrayInputStream bais = new ByteArrayInputStream(HexUtil.hexToBytes(data)); |
| out = new FileOutputStream(iconFile); |
| copy(bais, out); |
| } |
| |
| imageURI = iconFile.toURI().toString(); |
| } |
| } |
| catch (Exception ex) |
| { |
| //$FALL-THROUGH$ |
| } |
| finally |
| { |
| closeSilent(out); |
| } |
| } |
| |
| return imageURI; |
| } |
| |
| public static FileInputStream openInputStream(File file) throws IORuntimeException |
| { |
| try |
| { |
| return new FileInputStream(file); |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| } |
| |
| public static FileOutputStream openOutputStream(File file) throws IORuntimeException |
| { |
| try |
| { |
| mkdirs(file.getParentFile()); |
| return new FileOutputStream(file); |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| } |
| |
| public static Exception closeSilent(Closeable closeable) |
| { |
| try |
| { |
| if (closeable != null) |
| { |
| closeable.close(); |
| } |
| |
| return null; |
| } |
| catch (Exception ex) |
| { |
| UtilPlugin.INSTANCE.log(ex); |
| return ex; |
| } |
| } |
| |
| public static Exception closeSilent(Socket socket) |
| { |
| try |
| { |
| if (socket != null) |
| { |
| socket.close(); |
| } |
| |
| return null; |
| } |
| catch (Exception ex) |
| { |
| UtilPlugin.INSTANCE.log(ex); |
| return ex; |
| } |
| } |
| |
| public static Exception closeSilent(ServerSocket socket) |
| { |
| try |
| { |
| if (socket != null) |
| { |
| socket.close(); |
| } |
| |
| return null; |
| } |
| catch (Exception ex) |
| { |
| UtilPlugin.INSTANCE.log(ex); |
| return ex; |
| } |
| } |
| |
| public static void close(Closeable closeable) throws IORuntimeException |
| { |
| try |
| { |
| if (closeable != null) |
| { |
| closeable.close(); |
| } |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| } |
| |
| public static void mkdirs(File folder) throws IORuntimeException |
| { |
| if (!folder.exists()) |
| { |
| if (!folder.mkdirs()) |
| { |
| throw new IORuntimeException("Unable to create directory " + folder.getAbsolutePath()); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| public static boolean deleteBestEffort(File file) |
| { |
| return deleteBestEffort(file, true); |
| } |
| |
| public static boolean deleteBestEffort(File file, boolean deleteOnExit) |
| { |
| boolean deleted = true; |
| if (file != null) |
| { |
| if (file.isDirectory()) |
| { |
| File[] children = file.listFiles(); |
| if (children != null) |
| { |
| for (File child : children) |
| { |
| deleted &= deleteBestEffort(child, deleteOnExit); |
| } |
| } |
| } |
| |
| if (!file.delete()) |
| { |
| deleted = false; |
| |
| if (deleteOnExit) |
| { |
| file.deleteOnExit(); |
| } |
| } |
| } |
| |
| return deleted; |
| } |
| |
| public static long copy(InputStream input, OutputStream output, byte buffer[]) throws IORuntimeException |
| { |
| try |
| { |
| long length = 0; |
| int n; |
| |
| while ((n = input.read(buffer)) != -1) |
| { |
| output.write(buffer, 0, n); |
| length += n; |
| } |
| |
| return length; |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| } |
| |
| public static long copy(InputStream input, OutputStream output, int bufferSize) throws IORuntimeException |
| { |
| if (bufferSize == BUFFER.length) |
| { |
| return copy(input, output); |
| } |
| |
| return copy(input, output, new byte[bufferSize]); |
| } |
| |
| public static long copy(InputStream input, OutputStream output) throws IORuntimeException |
| { |
| synchronized (BUFFER) |
| { |
| return copy(input, output, BUFFER); |
| } |
| } |
| |
| public static void copyTree(File source, File target, boolean bestEffort) throws IORuntimeException |
| { |
| if (source.isDirectory()) |
| { |
| mkdirs(target); |
| File[] files = source.listFiles(); |
| for (File file : files) |
| { |
| String name = file.getName(); |
| copyTree(new File(source, name), new File(target, name), bestEffort); |
| } |
| } |
| else |
| { |
| try |
| { |
| copyFile(source, target); |
| } |
| catch (RuntimeException ex) |
| { |
| if (!bestEffort) |
| { |
| throw ex; |
| } |
| } |
| } |
| } |
| |
| public static void copyTree(File source, File target) throws IORuntimeException |
| { |
| copyTree(source, target, false); |
| } |
| |
| public static void copyFile(File source, File target) throws IORuntimeException |
| { |
| mkdirs(target.getParentFile()); |
| |
| FileInputStream input = null; |
| FileOutputStream output = null; |
| |
| try |
| { |
| input = openInputStream(source); |
| output = openOutputStream(target); |
| copy(input, output); |
| } |
| finally |
| { |
| closeSilent(input); |
| closeSilent(output); |
| } |
| } |
| |
| public static byte[] readFile(File file) throws IORuntimeException |
| { |
| if (file.length() > Integer.MAX_VALUE) |
| { |
| throw new IllegalArgumentException("File too long: " + file.length()); //$NON-NLS-1$ |
| } |
| |
| int size = (int)file.length(); |
| FileInputStream input = openInputStream(file); |
| |
| try |
| { |
| ByteArrayOutputStream output = new ByteArrayOutputStream(size); |
| copy(input, output); |
| return output.toByteArray(); |
| } |
| finally |
| { |
| closeSilent(input); |
| } |
| } |
| |
| public static void writeFile(File file, byte[] bytes) throws IORuntimeException |
| { |
| FileOutputStream output = openOutputStream(file); |
| |
| try |
| { |
| ByteArrayInputStream input = new ByteArrayInputStream(bytes); |
| copy(input, output); |
| } |
| finally |
| { |
| closeSilent(output); |
| } |
| } |
| |
| public static List<String> readLines(File file, String charsetName) |
| { |
| List<String> lines = new ArrayList<String>(); |
| |
| if (file.exists()) |
| { |
| InputStream in = null; |
| Reader reader = null; |
| BufferedReader bufferedReader = null; |
| |
| try |
| { |
| in = new FileInputStream(file); |
| reader = charsetName == null ? new InputStreamReader(in) : new InputStreamReader(in, charsetName); |
| bufferedReader = new BufferedReader(reader); |
| |
| String line; |
| while ((line = bufferedReader.readLine()) != null) |
| { |
| lines.add(line); |
| } |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| finally |
| { |
| closeSilent(bufferedReader); |
| closeSilent(reader); |
| closeSilent(in); |
| } |
| } |
| |
| return lines; |
| } |
| |
| public static void writeLines(File file, String charsetName, List<String> lines) |
| { |
| mkdirs(file.getParentFile()); |
| OutputStream out = null; |
| try |
| { |
| out = new FileOutputStream(file); |
| writeLines(out, charsetName, lines); |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| finally |
| { |
| closeSilent(out); |
| } |
| } |
| |
| public static void writeLines(OutputStream out, String charsetName, List<String> lines) |
| { |
| Writer writer = null; |
| BufferedWriter bufferedWriter = null; |
| |
| try |
| { |
| writer = charsetName == null ? new OutputStreamWriter(out) : new OutputStreamWriter(out, charsetName); |
| bufferedWriter = new BufferedWriter(writer); |
| |
| for (String line : lines) |
| { |
| bufferedWriter.write(line); |
| bufferedWriter.write(StringUtil.NL); |
| } |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| finally |
| { |
| closeSilent(bufferedWriter); |
| closeSilent(writer); |
| } |
| } |
| |
| public static String readUTF8(File file) throws Exception |
| { |
| InputStream inputStream = new FileInputStream(file); |
| ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
| |
| try |
| { |
| copy(inputStream, outputStream); |
| } |
| finally |
| { |
| close(inputStream); |
| } |
| |
| return new String(outputStream.toByteArray(), "UTF-8"); |
| } |
| |
| public static void writeUTF8(File file, String contents) throws Exception |
| { |
| mkdirs(file.getParentFile()); |
| |
| InputStream inputStream = new ByteArrayInputStream(contents.getBytes("UTF-8")); |
| OutputStream outputStream = new FileOutputStream(file); |
| |
| try |
| { |
| copy(inputStream, outputStream); |
| } |
| finally |
| { |
| close(outputStream); |
| } |
| } |
| |
| public static String readXML(InputStream inputStream) throws Exception |
| { |
| try |
| { |
| DocumentBuilder documentBuilder = XMLUtil.createDocumentBuilder(); |
| Document document = documentBuilder.parse(inputStream); |
| |
| TransformerFactory transformerFactory = TransformerFactory.newInstance(); |
| Transformer transformer = transformerFactory.newTransformer(); |
| |
| StringWriter out = new StringWriter(); |
| transformer.transform(new DOMSource(document), new StreamResult(out)); |
| out.close(); |
| |
| return out.toString(); |
| } |
| finally |
| { |
| IOUtil.close(inputStream); |
| } |
| } |
| |
| public static List<File> listDepthFirst(File file) |
| { |
| FileCollector collector = new FileCollector(); |
| visitDepthFirst(file, collector); |
| return collector.getFiles(); |
| } |
| |
| public static List<File> listBreadthFirst(File file) |
| { |
| FileCollector collector = new FileCollector(); |
| visitBreadthFirst(file, collector); |
| return collector.getFiles(); |
| } |
| |
| private static void visitDepthFirst(File file, IOVisitor visitor) throws IORuntimeException |
| { |
| try |
| { |
| boolean recurse = visitor.visit(file); |
| if (recurse && file.isDirectory()) |
| { |
| visitDepthFirst(file.listFiles(), visitor); |
| } |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| } |
| |
| private static void visitDepthFirst(File[] files, IOVisitor visitor) |
| { |
| for (File file : files) |
| { |
| visitDepthFirst(file, visitor); |
| } |
| } |
| |
| private static void visitBreadthFirst(File file, IOVisitor visitor) throws IORuntimeException |
| { |
| File[] files = { file }; |
| visitBreadthFirst(files, visitor); |
| } |
| |
| private static void visitBreadthFirst(File[] files, IOVisitor visitor) throws IORuntimeException |
| { |
| try |
| { |
| boolean[] recurse = new boolean[files.length]; |
| for (int i = 0; i < files.length; i++) |
| { |
| File file = files[i]; |
| recurse[i] = visitor.visit(file); |
| } |
| |
| for (int i = 0; i < files.length; i++) |
| { |
| File file = files[i]; |
| if (file.isDirectory() && recurse[i]) |
| { |
| File[] children = file.listFiles(); |
| for (File child : children) |
| { |
| visitBreadthFirst(child, visitor); |
| } |
| } |
| } |
| } |
| catch (IOException ex) |
| { |
| throw new IORuntimeException(ex); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private interface IOVisitor |
| { |
| public boolean visit(File file) throws IOException; |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private static class FileCollector implements IOVisitor |
| { |
| private List<File> files = new ArrayList<File>(); |
| |
| public FileCollector() |
| { |
| } |
| |
| public List<File> getFiles() |
| { |
| return files; |
| } |
| |
| public boolean visit(File file) throws IOException |
| { |
| files.add(file); |
| return true; |
| } |
| } |
| } |