blob: b0d6027c9d9afe2f4adb73ba2c60ba649e80f1f7 [file] [log] [blame]
/*
* 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;
}
}
}