-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.utils;\r
-\r
-import java.io.BufferedReader;\r
-import java.io.Closeable;\r
-import java.io.File;\r
-import java.io.FileFilter;\r
-import java.io.FileInputStream;\r
-import java.io.FileNotFoundException;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.InputStreamReader;\r
-import java.io.OutputStream;\r
-import java.io.RandomAccessFile;\r
-import java.io.UnsupportedEncodingException;\r
-import java.net.URI;\r
-import java.net.URL;\r
-import java.nio.channels.FileChannel;\r
-import java.nio.charset.Charset;\r
-import java.nio.file.FileVisitResult;\r
-import java.nio.file.Files;\r
-import java.nio.file.Path;\r
-import java.nio.file.SimpleFileVisitor;\r
-import java.nio.file.StandardCopyOption;\r
-import java.nio.file.attribute.BasicFileAttributes;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-import java.util.Deque;\r
-import java.util.LinkedList;\r
-import java.util.Random;\r
-import java.util.zip.DataFormatException;\r
-import java.util.zip.Deflater;\r
-import java.util.zip.Inflater;\r
-import java.util.zip.ZipEntry;\r
-import java.util.zip.ZipException;\r
-import java.util.zip.ZipInputStream;\r
-import java.util.zip.ZipOutputStream;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.adapter.AdaptException;\r
-import org.simantics.databoard.adapter.Adapter;\r
-import org.simantics.databoard.adapter.AdapterConstructionException;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.utils.bytes.LEInt;\r
-import org.simantics.utils.strings.FileNameUtils;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-/**\r
- * Utilities for common file operations.\r
- *\r
- * see StreamUtil in databoard for Input/OutputStream reading/writing utils\r
- * @see FileNameUtils for more utils\r
- * \r
- * @author Toni Kalajainen\r
- * @author Tuukka Lehtonen\r
- */\r
-public class FileUtils {\r
-\r
- private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);\r
-\r
- /**\r
- * Create escaped filename\r
- * \r
- * @param name any string\r
- * @return file compatible string\r
- */\r
- public static String escapeFileName(String name) {\r
- try {\r
- return java.net.URLEncoder.encode(name, "UTF-8");\r
- } catch (UnsupportedEncodingException e) {\r
- // never expected\r
- throw new RuntimeException(e);\r
- }\r
- }\r
- \r
- /**\r
- * Unescape filename into string \r
- * \r
- * @param filename \r
- * @return any string\r
- */\r
- public static String unescapeFileName(String filename) {\r
- try {\r
- return java.net.URLDecoder.decode(filename, "UTF-8");\r
- } catch (UnsupportedEncodingException e) {\r
- // never expected\r
- throw new RuntimeException(e);\r
- }\r
- }\r
-\r
- public static File ensureParentDirectoryExists(String path) throws IOException {\r
- return ensureParentDirectoryExists(new File(path));\r
- }\r
-\r
- /**\r
- * Ensures the parent directory pointed by the specified file path exists as a\r
- * directory.\r
- * \r
- * @param path the directory whose existence is to be ensured\r
- * @return the requested directory\r
- * @throws IOException if the specified directory cannot be created or\r
- * already exists as a file\r
- */\r
- public static File ensureParentDirectoryExists(File path) throws IOException {\r
- return ensureDirectoryExists(path.getParentFile());\r
- }\r
- \r
- \r
- public static File ensureDirectoryExists(String path) throws IOException {\r
- return ensureDirectoryExists(new File(path));\r
- }\r
-\r
- /**\r
- * Ensures the directory pointed by the specified file path exists as a\r
- * directory.\r
- * \r
- * @param path the directory whose existence is to be ensured\r
- * @return the requested directory\r
- * @throws IOException if the specified directory cannot be created or\r
- * already exists as a file\r
- */\r
- public static File ensureDirectoryExists(File path) throws IOException {\r
- if (path.isDirectory())\r
- // Already exists, everything OK.\r
- return path;\r
-\r
- if (path.exists())\r
- // Path is not a directory but it exists, fail!\r
- throw new IOException("file '" + path + "', already exists but it is not a directory");\r
-\r
- path.mkdirs();\r
- if (!path.exists())\r
- // Path is not a directory but it exists, fail!\r
- throw new IOException("could not create directory '" + path + "' for an unknown reason");\r
-\r
- // Directory created OK.\r
- return path;\r
- }\r
-\r
- /**\r
- * Copies the contents of a source file to the destination file.\r
- * \r
- * @param sourceFile the source file descriptor\r
- * @param destFile the destination file descriptor\r
- * @throws IOException when anything IO-related goes wrong during the copy\r
- */\r
- public static void copyFile(File sourceFile, File destFile) throws IOException {\r
- if (!destFile.exists()) {\r
- destFile.createNewFile();\r
- }\r
-\r
- FileInputStream fis = null;\r
- FileOutputStream fos = null;\r
- try {\r
- fis = new FileInputStream(sourceFile);\r
- fos = new FileOutputStream(destFile);\r
- FileChannel source = fis.getChannel();\r
- FileChannel destination = fos.getChannel();\r
-\r
- long count = 0;\r
- long size = source.size();\r
- while (count < size) {\r
- count += destination.transferFrom(source, count, size - count);\r
- }\r
- } finally {\r
- if (fis != null) {\r
- uncheckedClose(fis);\r
- }\r
- if (fos != null) {\r
- uncheckedClose(fos);\r
- }\r
- }\r
- }\r
- \r
- /**\r
- * Copy file or dir recursively.\r
- * \r
- * @param src\r
- * @param dst\r
- * @throws IOException\r
- */\r
- public static void copy(File src, File dst) throws IOException\r
- {\r
- if (src.isDirectory()) {\r
- if(!dst.exists()) dst.mkdir();\r
-\r
- for (String file : src.list()) {\r
- File srcFile = new File(src, file);\r
- File dstFile = new File(dst, file);\r
- copy(srcFile,dstFile);\r
- }\r
- } else {\r
- copyFile(src, dst);\r
- }\r
- }\r
- \r
-\r
-// public static File createTempFileFromResource(URL sourceUrl) throws IOException {\r
-// sourceUrl = FileLocator.resolve(sourceUrl);\r
-// File sourceFile;\r
-// try {\r
-// if (sourceUrl.getProtocol().equalsIgnoreCase("file"))\r
-// sourceFile = new File(sourceUrl.getPath());\r
-// else\r
-// sourceFile = new File(sourceUrl.toURI());\r
-// } catch (URISyntaxException e) {\r
-// throw new RuntimeException(e);\r
-// }\r
-//\r
-// File tempFile = File.createTempFile("tmp", ".tmp");\r
-// FileUtils.copyFile(sourceFile, tempFile);\r
-// return tempFile;\r
-// }\r
-\r
- /**\r
- * Reads entire binary file\r
- * @param file file\r
- * @return contents of binary file\r
- * @throws IOException on i/o problems\r
- */\r
- public static byte[] readFile(File file)\r
- throws IOException\r
- {\r
- try (FileInputStream fis = new FileInputStream(file)) {\r
- long size = file.length();\r
- if (size>Integer.MAX_VALUE)\r
- throw new IOException("File too big");\r
- int len = (int) size;\r
- byte data [] = new byte[len];\r
- int pos = 0;\r
-\r
- while (pos<size) {\r
- int read = fis.read(data, pos, len-pos);\r
- pos += read;\r
- }\r
- return data;\r
- }\r
- }\r
-\r
- /**\r
- * Creates and writes a binary file\r
- * @param file file\r
- * @param data data\r
- * @throws IOException on i/o problems\r
- */\r
- public static void writeFile(File file, byte[] data)\r
- throws IOException\r
- {\r
-// file.createNewFile();\r
-// file.setWritable(true);\r
- try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {\r
- raf.setLength(data.length);\r
- raf.seek(0);\r
- raf.write(data);\r
- }\r
- }\r
-\r
-\r
- /**\r
- * Fetch the entire contents of the input stream text file, and return it in\r
- * a String. This style of implementation does not throw Exceptions to the\r
- * caller.\r
- * \r
- * @param stream the stream to completely read in\r
- */\r
- public static String getContents(InputStream stream) throws IOException {\r
- return getContents(stream, Charset.defaultCharset());\r
- }\r
-\r
- /**\r
- * Fetch the entire contents of the input stream text file, and return it in\r
- * a String. This style of implementation does not throw Exceptions to the\r
- * caller.\r
- * \r
- * @param stream the stream to completely read in\r
- */\r
- public static String getContents(InputStream stream, Charset charset, String lineSeparator) throws IOException {\r
- StringBuilder contents = new StringBuilder();\r
- BufferedReader input = null;\r
- try {\r
- input = new BufferedReader(new InputStreamReader(stream, charset));\r
-\r
- String line = null;\r
- while ((line = input.readLine()) != null) {\r
- contents.append(line);\r
- contents.append(lineSeparator);\r
- }\r
- } finally {\r
- try {\r
- if (input != null) {\r
- // flush and close both "input" and its underlying\r
- // FileReader\r
- input.close();\r
- }\r
- } catch (IOException ex) {\r
- ex.printStackTrace();\r
- }\r
- }\r
- return contents.toString();\r
- }\r
-\r
- public static String getContents(File f) throws IOException {\r
- return getContents(f, Charset.defaultCharset());\r
- }\r
- \r
- public static String getContents(File f, Charset charset) throws IOException {\r
- return getContents(new FileInputStream(f), charset);\r
- }\r
-\r
- public static String getContents(InputStream stream, Charset charset) throws IOException {\r
- return getContents(stream, charset, System.getProperty("line.separator"));\r
- }\r
-\r
- public static String getContents(InputStream stream, String lineSeparator) throws IOException {\r
- return getContents(stream, Charset.defaultCharset(), lineSeparator);\r
- }\r
- \r
- /**\r
- * Fetch the entire contents of a text file, and return it in a String. This\r
- * style of implementation does not throw Exceptions to the caller.\r
- * \r
- * @param sourcePath is a file which already exists and can be read.\r
- */\r
- public static String getContents(String sourcePath) throws IOException {\r
- return getContents(sourcePath, Charset.defaultCharset(), System.getProperty("line.separator"));\r
- }\r
-\r
- public static String getContents(String sourcePath, String lineSeparator) throws IOException {\r
- return getContents(sourcePath, Charset.defaultCharset(), lineSeparator);\r
- }\r
-\r
- public static String getContents(String sourcePath, Charset charset) throws IOException {\r
- return getContents(sourcePath, charset, System.getProperty("line.separator"));\r
- }\r
-\r
- /**\r
- * Fetch the entire contents of a text file, and return it in a String. This\r
- * style of implementation does not throw Exceptions to the caller.\r
- * \r
- * @param sourcePath is a file which already exists and can be read.\r
- */\r
- public static String getContents(String sourcePath, Charset charset, String lineSeparator) throws IOException {\r
- FileInputStream input = null;\r
- try {\r
- input = new FileInputStream(sourcePath);\r
- return getContents(input, charset, lineSeparator);\r
- } finally {\r
- uncheckedClose(input);\r
- }\r
- }\r
-\r
- /**\r
- * Get the contents of a file which is located inside a given bundle.\r
- * This works regardless of whether the bundle is jarred or not.\r
- * \r
- * @param URL the resource to read in\r
- * @return the contents of the resource\r
- * @throws IOException if the file is not found or other io errors occur\r
- */\r
- public static String getContents(URL url) throws IOException {\r
- if (url == null)\r
- throw new IllegalArgumentException("null URL");\r
- InputStream input = null;\r
- try {\r
- input = url.openStream();\r
- return FileUtils.getContents(input);\r
- } finally {\r
- uncheckedClose(input);\r
- }\r
- }\r
-\r
- /**\r
- * Read a binary file into a java instance. Binary file is a variant, \r
- * there is a filetype in the header of the file. \r
- * If requested binding is not the exact binding of the file, an adapter is tried.\r
- * \r
- * @param file file\r
- * @param binding content binding\r
- * @return instance\r
- * @throws IOException \r
- */\r
- public static Object readFile(InputStream stream, Binding binding) throws IOException {\r
- Binding datatype_binding = Bindings.getBindingUnchecked( Datatype.class );\r
- Datatype type = (Datatype) Bindings.getSerializerUnchecked( datatype_binding ).deserialize( stream );\r
-\r
- if (type.equals(binding.type())) {\r
- return Bindings.getSerializerUnchecked( binding ).deserialize(stream);\r
- } else {\r
- try {\r
- Binding fileContentBinding = Bindings.getMutableBinding(type);\r
- Adapter adapter = Bindings.adapterFactory.getAdapter(fileContentBinding, binding, true, false);\r
- Object value = Bindings.getSerializerUnchecked( fileContentBinding ).deserialize(stream);\r
- return adapter.adapt( value );\r
- } catch (AdapterConstructionException e) {\r
- throw new IOException(e);\r
- } catch (AdaptException e) {\r
- throw new IOException(e);\r
- }\r
- }\r
- }\r
- \r
- /**\r
- * Deletes all files and sub-directories from the specified directory. If a\r
- * file is specified, only that fill will be deleted.\r
- * \r
- * @param dir\r
- * @throws IOException\r
- */\r
- public static void deleteAll(File dir) throws IOException {\r
- if (dir.isFile()) {\r
- dir.delete();\r
- return;\r
- }\r
-\r
- if (dir.isDirectory()) {\r
- File[] fs = dir.listFiles((FileFilter) null);\r
- if (fs == null)\r
- return;\r
-\r
- for (File f : fs) {\r
- if (f.isDirectory()) {\r
- deleteAll(f);\r
- } else {\r
- if (!f.delete()) {\r
- throw new IOException("Could not delete file: " + f.getAbsolutePath());\r
- }\r
- }\r
- }\r
-\r
- if (!dir.delete()) {\r
- throw new IOException("Could not delete directory: " + dir.getAbsolutePath());\r
- }\r
- } else if (dir.exists()) {\r
- if (!dir.delete()) {\r
- throw new IOException("Could not delete file: " + dir.getAbsolutePath());\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * Deletes all files and sub-directories from the specified directory. If a\r
- * file is specified, only that fill will be deleted.\r
- * \r
- * If the given directory contains files listed in the filter those files are not deleted\r
- * \r
- * @param dir\r
- * directory from where to start the deletion \r
- * @param filter\r
- * filter containing specific file paths not to delete\r
- * @throws IOException\r
- */\r
- public static void deleteAllWithFilter(File dir, ArrayList<String> filter) throws IOException {\r
- if (dir.isFile()) {\r
- if (!filter.contains(dir.getAbsolutePath())) {\r
- dir.delete();\r
- return; \r
- }\r
- }\r
-\r
- if (dir.isDirectory()) {\r
- File[] fs = dir.listFiles((FileFilter) null);\r
- if (fs == null)\r
- return;\r
-\r
- for (File f : fs) {\r
- if (f.isDirectory()) {\r
- deleteAllWithFilter(f, filter);\r
- } else {\r
- if (!filter.contains(f.getAbsolutePath())) {\r
- if (!f.delete()) {\r
- throw new IOException("Could not delete file: " + f.getAbsolutePath());\r
- } \r
- }\r
- }\r
- }\r
- if (!filter.contains(dir.getAbsolutePath())) {\r
- if (!dir.delete()) {\r
- throw new IOException("Could not delete directory: " + dir.getAbsolutePath());\r
- } \r
- }\r
- } else if (dir.exists()) {\r
- if (filter.contains(dir.getAbsolutePath())) {\r
- if (!dir.delete()) {\r
- throw new IOException("Could not delete file: " + dir.getAbsolutePath());\r
- }\r
- }\r
- }\r
- }\r
- \r
- public static ArrayList<String> createFileFilter(File dir, ArrayList<String> filter) {\r
- if (filter == null)\r
- filter = new ArrayList<String>();\r
- if (dir.isFile()) {\r
- filter.add(dir.getAbsolutePath());\r
- return filter;\r
- }\r
- \r
- if (dir.isDirectory()) {\r
- File[] fs = dir.listFiles((FileFilter) null);\r
- if (fs == null)\r
- return filter;\r
-\r
- for (File f : fs) {\r
- if (f.isDirectory()) {\r
- createFileFilter(f, filter);\r
- } else {\r
- filter.add(f.getAbsolutePath());\r
- }\r
- }\r
- filter.add(dir.getAbsolutePath());\r
- } else if (dir.exists()) {\r
- filter.add(dir.getAbsolutePath());\r
- }\r
- return filter;\r
- }\r
-\r
-\r
- /**\r
- * Delete a directory incl. all files and sub-directories by best effort.\r
- * Does not throw exceptions if deletion fails, simply tries to delete the\r
- * provided directory to the best of Java File API's abilities.\r
- * \r
- * @param dir\r
- * directory to delete recursively\r
- * @boolean <code>true</code> if all files were successfully deleted,\r
- * <code>false</code> if some or all failed to be deleted\r
- */\r
- public static boolean deleteDir(File dir) {\r
- if (LOGGER.isDebugEnabled())\r
- LOGGER.debug("Deleting directory "+dir);\r
- boolean result = true;\r
-\r
- if (!dir.isDirectory()) return false;\r
- File[] fs = dir.listFiles();\r
- if (fs != null) {\r
- for (File f : fs) {\r
- if (f.isDirectory()) result &= deleteDir(f);\r
- if (f.isFile()) result &= f.delete();\r
- }\r
- }\r
- boolean ok = dir.delete();\r
-// if (!ok) dir.deleteOnExit();\r
- result &= ok;\r
- return result;\r
- }\r
- \r
- public static String deleteDirs(File dir) { \r
- if (LOGGER.isDebugEnabled())\r
- LOGGER.debug("Deleting directory "+dir);\r
- boolean result = true;\r
-\r
- if (!dir.isDirectory()) \r
- return dir + " is not a directory!";\r
- File[] fs = dir.listFiles();\r
- if (fs != null) {\r
- for (File f : fs) {\r
- //System.out.println("file f :" + f);\r
- if (f.isDirectory()) { \r
- boolean a = deleteDir(f);\r
- result &= a;\r
- }\r
- if (f.isFile()) {\r
- boolean a = f.delete();\r
- result &= a;\r
- }\r
- \r
- }\r
- }\r
- boolean ok = dir.delete();\r
-// if (!ok) dir.deleteOnExit();\r
- result &= ok;\r
- return "deleteDirs succesful for " + dir + " : " + result;\r
- }\r
-\r
- /**\r
- * Closes a stream and ignores any resulting exception. This is useful\r
- * when doing stream cleanup in a finally block where secondary exceptions\r
- * are not worth logging.\r
- */\r
- public static void uncheckedClose(Closeable closeable) {\r
- try {\r
- if (closeable != null)\r
- closeable.close();\r
- } catch (IOException e) {\r
- //ignore\r
- }\r
- }\r
-\r
- /**\r
- * Extracts the specified source file in the specified bundle into the\r
- * specified local directory.\r
- * \r
- * @param url the source URL to stream the resource from\r
- * @param targetFile the target file to write the resource to\r
- * @param deleteOnExit <code>true</code> to use {@link File#deleteOnExit()}\r
- * on the resulting file. Note that this does not guarantee that the\r
- * file is deleted when the JVM exits\r
- * @return the resulting file\r
- * @throws FileNotFoundException\r
- */\r
- public static File copyResource(URL url, File targetFile, boolean deleteOnExit) throws IOException, FileNotFoundException {\r
- if (url == null)\r
- throw new IllegalArgumentException("null url");\r
-\r
- FileOutputStream os = null;\r
- InputStream is = null;\r
- try {\r
- if (targetFile.exists())\r
- targetFile.delete();\r
-\r
- is = url.openStream();\r
- int read;\r
- byte [] buffer = new byte [16384];\r
- os = new FileOutputStream (targetFile);\r
- while ((read = is.read (buffer)) != -1) {\r
- os.write(buffer, 0, read);\r
- }\r
- os.close ();\r
- is.close ();\r
-\r
- // Request removal of the extracted files on JVM exit.\r
- if (deleteOnExit)\r
- targetFile.deleteOnExit();\r
- return targetFile;\r
- } finally {\r
- FileUtils.uncheckedClose(os);\r
- FileUtils.uncheckedClose(is);\r
- }\r
- }\r
-\r
- /**\r
- * Creates the requested location under the system's temporary directories\r
- * for temporary data storage.\r
- * \r
- * @param pathSegments the path segments that are appended to\r
- * java.io.tmpdir. The path segments musn't contain path separators.\r
- * @return the resulting temporary directory as a File object\r
- * @throws IOException if anything goes wrong\r
- */\r
- public static File getOrCreateTemporaryDirectory(boolean requireEmptyDirectory, String... pathSegments) throws IOException {\r
- String separator = System.getProperty("file.separator");\r
- String tempDir = System.getProperty("java.io.tmpdir");\r
- if (tempDir == null)\r
- throw new IllegalStateException("'java.io.tmpdir' property is not defined, is the system TMP environment variable defined?");\r
-\r
- if (!hasTrailingSeparator(tempDir))\r
- tempDir = tempDir + separator;\r
-\r
- for (int i = 0; i < pathSegments.length-1; ++i) {\r
- if (containsSeparator(pathSegments[i]))\r
- throw new IllegalArgumentException("path segments contain path separators: " + Arrays.toString(pathSegments));\r
- tempDir = pathSegments[i] + separator;\r
- }\r
-\r
- // Find name for an empty or non-existing temporary directory\r
- if (pathSegments.length > 0) {\r
- String lastSegment = pathSegments[pathSegments.length - 1];\r
- String suffix = "";\r
- int counter = 0;\r
- // This loop will not exit until it succeeds or some error occurs.\r
- while (true) {\r
- File temp = new File(tempDir + lastSegment + suffix);\r
-\r
- if (!temp.exists()) {\r
- // Found non-existent temporary directory!\r
- if (temp.mkdirs()) {\r
- // Ok, everything seems to be fine.\r
- return temp;\r
- }\r
- // For some reason the directory could not be created, lets\r
- // try another name.\r
- } else {\r
- // Found an existing temporary file.\r
- if (temp.isDirectory() && temp.canWrite()) {\r
- if (requireEmptyDirectory) {\r
- String[] files = temp.list();\r
- if (files != null) {\r
- if (files.length == 0) {\r
- // Ok, the directory is empty and writable.\r
- return temp;\r
- }\r
- }\r
- } else {\r
- return temp;\r
- }\r
- // Either the directory was empty or it could not be\r
- // checked. In any case, don't use the directory.\r
- }\r
- }\r
-\r
- // Try another directory name if no success with this one.\r
- suffix = Integer.toHexString(counter);\r
- ++counter;\r
- }\r
- }\r
- return new File(tempDir);\r
- }\r
-\r
- private static boolean containsSeparator(String s) {\r
- return s.contains("/") || s.contains("\\");\r
- }\r
-\r
- private static boolean hasTrailingSeparator(String s) {\r
- return s.endsWith("/") || s.endsWith("\\");\r
- }\r
-\r
- /**\r
- * Very simple compression using ZLib\r
- * @param input the uncompressed data\r
- * @return the compressed data\r
- */\r
- public static byte[] deflate(byte[] input) {\r
- // Compress the bytes\r
- Deflater compresser = new Deflater(Deflater.BEST_COMPRESSION);\r
- compresser.setInput(input);\r
- compresser.finish();\r
-\r
- int bufferSize = input.length<16 ? 16 : input.length;\r
- byte buffer[] = new byte[bufferSize];\r
- int bufferPos = 0;\r
- do {\r
- int compressedDataLength = compresser.deflate(buffer, bufferPos, buffer.length-bufferPos);\r
- bufferPos += compressedDataLength;\r
- if (!compresser.finished())\r
- buffer = Arrays.copyOf(buffer, buffer.length + bufferSize);\r
- } while (!compresser.finished());\r
-\r
- byte[] result = new byte[bufferPos+4];\r
- System.arraycopy(buffer, 0, result, 4, bufferPos);\r
- byte sizeData[] = LEInt.toBytes(input.length);\r
- System.arraycopy(sizeData, 0, result, 0, 4);\r
- return result;\r
- }\r
-\r
- /**\r
- * Very simple decompression using ZLib.\r
- * @param input the compressed input\r
- * @return the uncompressed data\r
- * @throws DataFormatException\r
- */\r
- public static byte[] inflate(byte[] input) throws DataFormatException {\r
- // Decompress the bytes\r
- int inflatedSize = LEInt.toInt(input);\r
- Inflater decompresser = new Inflater();\r
- decompresser.setInput(input, 4, input.length - 4);\r
- byte[] result = new byte[inflatedSize];\r
- int resultLength = decompresser.inflate(result);\r
- assert(resultLength == inflatedSize);\r
- decompresser.end();\r
- return result;\r
- }\r
-\r
-\r
- public static boolean isValidFileName(String name) {\r
- File f = new File(name) ;\r
- if (!f.exists()) {\r
- try {\r
- boolean ok = f.createNewFile();\r
- if (ok)\r
- f.delete();\r
- return ok;\r
- } catch (IOException ioe) {\r
- return false;\r
- }\r
- }\r
- return true;\r
- }\r
-\r
- /**\r
- * Create a temporary directory\r
- * \r
- * @return temporary directory\r
- */\r
- public static File createTmpDir()\r
- {\r
- String tmp = System.getenv("tmp");\r
- if (tmp==null) tmp = "c:/temp";\r
- Random r = new Random();\r
- String randomName = "simantics-tmp-"+(r.nextInt(10000)+10000);\r
- File tmpDir = new File(tmp+"/"+randomName);\r
- tmpDir.deleteOnExit();\r
- Boolean ok = tmpDir.mkdirs();\r
- if (!ok) throw new RuntimeException("tmp dir "+tmpDir+" was not created");\r
- return tmpDir;\r
- }\r
- \r
- public static void compressZip(String sourcePath, String zipDir) throws IOException {\r
- if (LOGGER.isDebugEnabled())\r
- LOGGER.debug("Compressing file " + sourcePath + " to zip " + zipDir + ".");\r
-\r
- File filesource = new File(sourcePath);\r
- URI base = filesource.toURI();\r
- Deque<File> queue = new LinkedList<File>();\r
- queue.push(filesource);\r
- try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zipDir))) {\r
- while (!queue.isEmpty()) {\r
- filesource = queue.pop();\r
- for (File child : filesource.listFiles()) {\r
- String name = base.relativize(child.toURI()).getPath();\r
- if (child.isDirectory()) {\r
- queue.push(child);\r
- name = name.endsWith("/") ? name : name + "/";\r
- zout.putNextEntry(new ZipEntry(name));\r
- } else {\r
- zout.putNextEntry(new ZipEntry(name));\r
- copy(child, zout);\r
- zout.closeEntry();\r
- }\r
- }\r
- }\r
- } finally {\r
- LOGGER.debug("Filecompression done.");\r
- }\r
- }\r
-\r
- private static void copy(File file, ZipOutputStream zout) throws IOException {\r
- try (InputStream in = new FileInputStream(file)) {\r
- copy(in, zout);\r
- }\r
- }\r
-\r
- /**\r
- * Extract a zip file into a directory\r
- * \r
- * @param zipFile\r
- * @param dst\r
- * @throws IOException\r
- */\r
- public static void extractZip(File zipFile, File dst) throws IOException {\r
- if (LOGGER.isDebugEnabled())\r
- LOGGER.debug("Extracting zip "+zipFile);\r
- try (FileInputStream fis = new FileInputStream(zipFile)) {\r
- extractZip(fis, dst);\r
- }\r
- }\r
-\r
- /**\r
- * Extract a zip file into a directory\r
- * \r
- * @param zipInput\r
- * @param dst directory\r
- * @throws IOException\r
- */\r
- public static void extractZip(InputStream zipInput, File dst) throws IOException {\r
- byte[] buf = new byte[8192];\r
- ZipInputStream zis = new ZipInputStream(zipInput);\r
- ZipEntry entry;\r
-\r
- entry = zis.getNextEntry();\r
- while (entry != null) {\r
- // for each entry to be extracted\r
- String name = entry.getName();\r
- if (LOGGER.isDebugEnabled())\r
- LOGGER.debug("Extracting "+name);\r
- File file = new File(dst, name);\r
-\r
- if (entry.isDirectory())\r
- {\r
- if ( !file.exists() ) file.mkdirs();\r
- } else {\r
- File parent = file.getParentFile();\r
- if (!parent.exists()) parent.mkdirs();\r
- if (!file.exists()) file.createNewFile();\r
-\r
- FileOutputStream fileoutputstream = new FileOutputStream(file);\r
- try {\r
- int n = 0;\r
- while ((n = zis.read(buf, 0, buf.length)) > -1)\r
- fileoutputstream.write(buf, 0, n);\r
- } catch (ZipException e) {\r
- throw new IOException("Failed to extract '" + name + "'.", e);\r
- } finally {\r
- fileoutputstream.close();\r
- }\r
- }\r
-\r
- zis.closeEntry();\r
- entry = zis.getNextEntry();\r
- }// while\r
-\r
- zis.close();\r
- }\r
-\r
- // Test inflate & deflate\r
- public static void main(String[] args) {\r
- try {\r
- // Test compression\r
- String str = "abcdefghijklmnopqrstuvwxyz";\r
- byte data[] = str.getBytes();\r
- System.out.println("Data:\t"+data.length);\r
- byte deflated[] = deflate(data);\r
- System.out.println("Deflated:\t"+deflated.length);\r
- byte inflated[] = inflate(deflated);\r
- System.out.println("Inflated:\t"+inflated.length);\r
- String str2 = new String(inflated);\r
- System.out.println("Strings are equal: "+str.endsWith(str2));\r
- } catch (DataFormatException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- public static File[] listFilesByExtension(File directory, final String extension) {\r
- return directory.listFiles(new ExtensionFilter(extension));\r
- }\r
- \r
- /**\r
- * Copy the content of the input stream into the output stream, using a temporary\r
- * byte array buffer whose size is defined by {@link #IO_BUFFER_SIZE}.\r
- *\r
- * @param in The input stream to copy from.\r
- * @param out The output stream to copy to.\r
- *\r
- * @throws IOException If any error occurs during the copy.\r
- */\r
- private static final int IO_BUFFER_SIZE = 64 * 1024;\r
-\r
- public static void copy(InputStream in, OutputStream out) throws IOException {\r
- byte[] b = new byte[IO_BUFFER_SIZE];\r
- int read;\r
- while (true) {\r
- read = in.read(b);\r
- if (read < 0)\r
- break;\r
- out.write(b, 0, read);\r
- }\r
- }\r
-\r
- /**\r
- * @param in\r
- * @param out\r
- * @param maxBytesToCopy the maximum amount of bytes to copy\r
- * @return the amount of bytes copied\r
- * @throws IOException\r
- */\r
- public static long copy(InputStream in, OutputStream out, long maxBytesToCopy) throws IOException {\r
- byte[] b = new byte[IO_BUFFER_SIZE];\r
- int read = 0;\r
- while (read < maxBytesToCopy) {\r
- int l = (int) Math.min((long) IO_BUFFER_SIZE, maxBytesToCopy-read);\r
- int r = in.read(b, 0, l);\r
- if (r < 0)\r
- break;\r
- out.write(b, 0, r);\r
- read += r;\r
- }\r
- return read;\r
- }\r
-\r
- public static void delete(Path databaseLocation) throws IOException {\r
- Files.walkFileTree(databaseLocation, new DeleteDirectoriesVisitor());\r
- }\r
- \r
- public static void copy(Path from, Path to) throws IOException {\r
- Files.walkFileTree(from, new CopyDirectoriesVisitor(from, to));\r
- }\r
- \r
- public static class DeleteDirectoriesVisitor extends SimpleFileVisitor<Path> {\r
- \r
- @Override\r
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
- Files.delete(file);\r
- if (Files.exists(file))\r
- throw new IOException("Could not delete file " + file.toAbsolutePath().toString());\r
- return FileVisitResult.CONTINUE;\r
- }\r
- \r
- @Override\r
- public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {\r
- if (exc != null)\r
- throw exc;\r
- Files.delete(dir);\r
- if (Files.exists(dir))\r
- throw new IOException("Could not delete file " + dir.toAbsolutePath().toString());\r
- return FileVisitResult.CONTINUE;\r
- }\r
- }\r
- \r
- public static class CopyDirectoriesVisitor extends SimpleFileVisitor<Path> {\r
- \r
- private final Path fromPath;\r
- private final Path toPath;\r
- \r
- public CopyDirectoriesVisitor(Path fromPath, Path toPath) {\r
- this.fromPath = fromPath;\r
- this.toPath = toPath;\r
- }\r
- \r
- @Override\r
- public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\r
- Path targetPath = toPath.resolve(fromPath.relativize(dir));\r
- if(!Files.exists(targetPath)){\r
- Files.createDirectory(targetPath);\r
- }\r
- return FileVisitResult.CONTINUE;\r
- }\r
-\r
- @Override\r
- public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
- Files.copy(file, toPath.resolve(fromPath.relativize(file)), StandardCopyOption.REPLACE_EXISTING);\r
- return FileVisitResult.CONTINUE;\r
- }\r
- }\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * 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:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.utils;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.Random;
+import java.util.function.Predicate;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.adapter.AdaptException;
+import org.simantics.databoard.adapter.Adapter;
+import org.simantics.databoard.adapter.AdapterConstructionException;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.utils.bytes.LEInt;
+import org.simantics.utils.strings.FileNameUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utilities for common file operations.
+ *
+ * see StreamUtil in databoard for Input/OutputStream reading/writing utils
+ * @see FileNameUtils for more utils
+ *
+ * @author Toni Kalajainen
+ * @author Tuukka Lehtonen
+ */
+public class FileUtils {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);
+
+ /**
+ * Create escaped filename
+ *
+ * @param name any string
+ * @return file compatible string
+ */
+ public static String escapeFileName(String name) {
+ try {
+ return java.net.URLEncoder.encode(name, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // never expected
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Unescape filename into string
+ *
+ * @param filename
+ * @return any string
+ */
+ public static String unescapeFileName(String filename) {
+ try {
+ return java.net.URLDecoder.decode(filename, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // never expected
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static File ensureParentDirectoryExists(String path) throws IOException {
+ return ensureParentDirectoryExists(new File(path));
+ }
+
+ /**
+ * Ensures the parent directory pointed by the specified file path exists as a
+ * directory.
+ *
+ * @param path the directory whose existence is to be ensured
+ * @return the requested directory
+ * @throws IOException if the specified directory cannot be created or
+ * already exists as a file
+ */
+ public static File ensureParentDirectoryExists(File path) throws IOException {
+ return ensureDirectoryExists(path.getParentFile());
+ }
+
+
+ public static File ensureDirectoryExists(String path) throws IOException {
+ return ensureDirectoryExists(new File(path));
+ }
+
+ /**
+ * Ensures the directory pointed by the specified file path exists as a
+ * directory.
+ *
+ * @param path the directory whose existence is to be ensured
+ * @return the requested directory
+ * @throws IOException if the specified directory cannot be created or
+ * already exists as a file
+ */
+ public static File ensureDirectoryExists(File path) throws IOException {
+ if (path.isDirectory())
+ // Already exists, everything OK.
+ return path;
+
+ if (path.exists())
+ // Path is not a directory but it exists, fail!
+ throw new IOException("file '" + path + "', already exists but it is not a directory");
+
+ path.mkdirs();
+ if (!path.exists())
+ // Path is not a directory but it exists, fail!
+ throw new IOException("could not create directory '" + path + "' for an unknown reason");
+
+ // Directory created OK.
+ return path;
+ }
+
+ /**
+ * Copies the contents of a source file to the destination file.
+ *
+ * @param sourceFile the source file descriptor
+ * @param destFile the destination file descriptor
+ * @throws IOException when anything IO-related goes wrong during the copy
+ */
+ public static void copyFile(File sourceFile, File destFile) throws IOException {
+ if (!destFile.exists()) {
+ destFile.createNewFile();
+ }
+
+ FileInputStream fis = null;
+ FileOutputStream fos = null;
+ try {
+ fis = new FileInputStream(sourceFile);
+ fos = new FileOutputStream(destFile);
+ FileChannel source = fis.getChannel();
+ FileChannel destination = fos.getChannel();
+
+ long count = 0;
+ long size = source.size();
+ while (count < size) {
+ count += destination.transferFrom(source, count, size - count);
+ }
+ } finally {
+ if (fis != null) {
+ uncheckedClose(fis);
+ }
+ if (fos != null) {
+ uncheckedClose(fos);
+ }
+ }
+ }
+
+ /**
+ * Copy file or dir recursively.
+ *
+ * @param src
+ * @param dst
+ * @throws IOException
+ */
+ public static void copy(File src, File dst) throws IOException
+ {
+ if (src.isDirectory()) {
+ if(!dst.exists()) dst.mkdir();
+
+ for (String file : src.list()) {
+ File srcFile = new File(src, file);
+ File dstFile = new File(dst, file);
+ copy(srcFile,dstFile);
+ }
+ } else {
+ copyFile(src, dst);
+ }
+ }
+
+
+// public static File createTempFileFromResource(URL sourceUrl) throws IOException {
+// sourceUrl = FileLocator.resolve(sourceUrl);
+// File sourceFile;
+// try {
+// if (sourceUrl.getProtocol().equalsIgnoreCase("file"))
+// sourceFile = new File(sourceUrl.getPath());
+// else
+// sourceFile = new File(sourceUrl.toURI());
+// } catch (URISyntaxException e) {
+// throw new RuntimeException(e);
+// }
+//
+// File tempFile = File.createTempFile("tmp", ".tmp");
+// FileUtils.copyFile(sourceFile, tempFile);
+// return tempFile;
+// }
+
+ /**
+ * Reads entire binary file
+ * @param file file
+ * @return contents of binary file
+ * @throws IOException on i/o problems
+ */
+ public static byte[] readFile(File file)
+ throws IOException
+ {
+ try (FileInputStream fis = new FileInputStream(file)) {
+ long size = file.length();
+ if (size>Integer.MAX_VALUE)
+ throw new IOException("File too big");
+ int len = (int) size;
+ byte data [] = new byte[len];
+ int pos = 0;
+
+ while (pos<size) {
+ int read = fis.read(data, pos, len-pos);
+ pos += read;
+ }
+ return data;
+ }
+ }
+
+ /**
+ * Creates and writes a binary file
+ * @param file file
+ * @param data data
+ * @throws IOException on i/o problems
+ */
+ public static void writeFile(File file, byte[] data)
+ throws IOException
+ {
+// file.createNewFile();
+// file.setWritable(true);
+ try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
+ raf.setLength(data.length);
+ raf.seek(0);
+ raf.write(data);
+ }
+ }
+
+
+ /**
+ * Fetch the entire contents of the input stream text file, and return it in
+ * a String. This style of implementation does not throw Exceptions to the
+ * caller.
+ *
+ * @param stream the stream to completely read in
+ */
+ public static String getContents(InputStream stream) throws IOException {
+ return getContents(stream, Charset.defaultCharset());
+ }
+
+ /**
+ * Fetch the entire contents of the input stream text file, and return it in
+ * a String. This style of implementation does not throw Exceptions to the
+ * caller.
+ *
+ * @param stream the stream to completely read in
+ */
+ public static String getContents(InputStream stream, Charset charset, String lineSeparator) throws IOException {
+ StringBuilder contents = new StringBuilder();
+ BufferedReader input = null;
+ try {
+ input = new BufferedReader(new InputStreamReader(stream, charset));
+
+ String line = null;
+ while ((line = input.readLine()) != null) {
+ contents.append(line);
+ contents.append(lineSeparator);
+ }
+ } finally {
+ try {
+ if (input != null) {
+ // flush and close both "input" and its underlying
+ // FileReader
+ input.close();
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+ return contents.toString();
+ }
+
+ public static String getContents(File f) throws IOException {
+ return getContents(f, Charset.defaultCharset());
+ }
+
+ public static String getContents(File f, Charset charset) throws IOException {
+ return getContents(new FileInputStream(f), charset);
+ }
+
+ public static String getContents(InputStream stream, Charset charset) throws IOException {
+ return getContents(stream, charset, System.getProperty("line.separator"));
+ }
+
+ public static String getContents(InputStream stream, String lineSeparator) throws IOException {
+ return getContents(stream, Charset.defaultCharset(), lineSeparator);
+ }
+
+ /**
+ * Fetch the entire contents of a text file, and return it in a String. This
+ * style of implementation does not throw Exceptions to the caller.
+ *
+ * @param sourcePath is a file which already exists and can be read.
+ */
+ public static String getContents(String sourcePath) throws IOException {
+ return getContents(sourcePath, Charset.defaultCharset(), System.getProperty("line.separator"));
+ }
+
+ public static String getContents(String sourcePath, String lineSeparator) throws IOException {
+ return getContents(sourcePath, Charset.defaultCharset(), lineSeparator);
+ }
+
+ public static String getContents(String sourcePath, Charset charset) throws IOException {
+ return getContents(sourcePath, charset, System.getProperty("line.separator"));
+ }
+
+ /**
+ * Fetch the entire contents of a text file, and return it in a String. This
+ * style of implementation does not throw Exceptions to the caller.
+ *
+ * @param sourcePath is a file which already exists and can be read.
+ */
+ public static String getContents(String sourcePath, Charset charset, String lineSeparator) throws IOException {
+ FileInputStream input = null;
+ try {
+ input = new FileInputStream(sourcePath);
+ return getContents(input, charset, lineSeparator);
+ } finally {
+ uncheckedClose(input);
+ }
+ }
+
+ /**
+ * Get the contents of a file which is located inside a given bundle.
+ * This works regardless of whether the bundle is jarred or not.
+ *
+ * @param URL the resource to read in
+ * @return the contents of the resource
+ * @throws IOException if the file is not found or other io errors occur
+ */
+ public static String getContents(URL url) throws IOException {
+ if (url == null)
+ throw new IllegalArgumentException("null URL");
+ InputStream input = null;
+ try {
+ input = url.openStream();
+ return FileUtils.getContents(input);
+ } finally {
+ uncheckedClose(input);
+ }
+ }
+
+ /**
+ * Read a binary file into a java instance. Binary file is a variant,
+ * there is a filetype in the header of the file.
+ * If requested binding is not the exact binding of the file, an adapter is tried.
+ *
+ * @param file file
+ * @param binding content binding
+ * @return instance
+ * @throws IOException
+ */
+ public static Object readFile(InputStream stream, Binding binding) throws IOException {
+ Binding datatype_binding = Bindings.getBindingUnchecked( Datatype.class );
+ Datatype type = (Datatype) Bindings.getSerializerUnchecked( datatype_binding ).deserialize( stream );
+
+ if (type.equals(binding.type())) {
+ return Bindings.getSerializerUnchecked( binding ).deserialize(stream);
+ } else {
+ try {
+ Binding fileContentBinding = Bindings.getMutableBinding(type);
+ Adapter adapter = Bindings.adapterFactory.getAdapter(fileContentBinding, binding, true, false);
+ Object value = Bindings.getSerializerUnchecked( fileContentBinding ).deserialize(stream);
+ return adapter.adapt( value );
+ } catch (AdapterConstructionException e) {
+ throw new IOException(e);
+ } catch (AdaptException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+
+ /**
+ * Deletes all files and sub-directories from the specified directory. If a
+ * file is specified, only that fill will be deleted.
+ *
+ * @param dir
+ * @throws IOException
+ */
+ public static void deleteAll(File dir) throws IOException {
+ if (dir.isFile()) {
+ dir.delete();
+ return;
+ }
+
+ if (dir.isDirectory()) {
+ File[] fs = dir.listFiles((FileFilter) null);
+ if (fs == null)
+ return;
+
+ for (File f : fs) {
+ if (f.isDirectory()) {
+ deleteAll(f);
+ } else {
+ if (!f.delete()) {
+ throw new IOException("Could not delete file: " + f.getAbsolutePath());
+ }
+ }
+ }
+
+ if (!dir.delete()) {
+ throw new IOException("Could not delete directory: " + dir.getAbsolutePath());
+ }
+ } else if (dir.exists()) {
+ if (!dir.delete()) {
+ throw new IOException("Could not delete file: " + dir.getAbsolutePath());
+ }
+ }
+ }
+
+ /**
+ * Deletes all files and sub-directories from the specified directory. If a
+ * file is specified, only that fill will be deleted.
+ *
+ * If the given directory contains files listed in the filter those files are not deleted
+ *
+ * @param dir
+ * directory from where to start the deletion
+ * @param filter
+ * filter containing specific file paths not to delete
+ * @throws IOException
+ */
+ public static void deleteAllWithFilter(File dir, ArrayList<String> filter) throws IOException {
+ if (dir.isFile()) {
+ if (!filter.contains(dir.getAbsolutePath())) {
+ dir.delete();
+ return;
+ }
+ }
+
+ if (dir.isDirectory()) {
+ File[] fs = dir.listFiles((FileFilter) null);
+ if (fs == null)
+ return;
+
+ for (File f : fs) {
+ if (f.isDirectory()) {
+ deleteAllWithFilter(f, filter);
+ } else {
+ if (!filter.contains(f.getAbsolutePath())) {
+ if (!f.delete()) {
+ throw new IOException("Could not delete file: " + f.getAbsolutePath());
+ }
+ }
+ }
+ }
+ if (!filter.contains(dir.getAbsolutePath())) {
+ if (!dir.delete()) {
+ throw new IOException("Could not delete directory: " + dir.getAbsolutePath());
+ }
+ }
+ } else if (dir.exists()) {
+ if (!filter.contains(dir.getAbsolutePath())) {
+ if (!dir.delete()) {
+ throw new IOException("Could not delete file: " + dir.getAbsolutePath());
+ }
+ }
+ }
+ }
+
+ public static ArrayList<String> createFileFilter(File dir, ArrayList<String> filter) {
+ if (filter == null)
+ filter = new ArrayList<String>();
+ if (dir.isFile()) {
+ filter.add(dir.getAbsolutePath());
+ return filter;
+ }
+
+ if (dir.isDirectory()) {
+ File[] fs = dir.listFiles((FileFilter) null);
+ if (fs == null)
+ return filter;
+
+ for (File f : fs) {
+ if (f.isDirectory()) {
+ createFileFilter(f, filter);
+ } else {
+ filter.add(f.getAbsolutePath());
+ }
+ }
+ filter.add(dir.getAbsolutePath());
+ } else if (dir.exists()) {
+ filter.add(dir.getAbsolutePath());
+ }
+ return filter;
+ }
+
+
+ /**
+ * Delete a directory incl. all files and sub-directories by best effort.
+ * Does not throw exceptions if deletion fails, simply tries to delete the
+ * provided directory to the best of Java File API's abilities.
+ *
+ * @param dir
+ * directory to delete recursively
+ * @boolean <code>true</code> if all files were successfully deleted,
+ * <code>false</code> if some or all failed to be deleted
+ */
+ public static boolean deleteDir(File dir) {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Deleting directory "+dir);
+ boolean result = true;
+
+ if (!dir.isDirectory()) return false;
+ File[] fs = dir.listFiles();
+ if (fs != null) {
+ for (File f : fs) {
+ if (f.isDirectory()) result &= deleteDir(f);
+ if (f.isFile()) result &= f.delete();
+ }
+ }
+ boolean ok = dir.delete();
+// if (!ok) dir.deleteOnExit();
+ result &= ok;
+ return result;
+ }
+
+ public static String deleteDirs(File dir) {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Deleting directory "+dir);
+ boolean result = true;
+
+ if (!dir.isDirectory())
+ return dir + " is not a directory!";
+ File[] fs = dir.listFiles();
+ if (fs != null) {
+ for (File f : fs) {
+ //System.out.println("file f :" + f);
+ if (f.isDirectory()) {
+ boolean a = deleteDir(f);
+ result &= a;
+ }
+ if (f.isFile()) {
+ boolean a = f.delete();
+ result &= a;
+ }
+
+ }
+ }
+ boolean ok = dir.delete();
+// if (!ok) dir.deleteOnExit();
+ result &= ok;
+ return "deleteDirs succesful for " + dir + " : " + result;
+ }
+
+ /**
+ * Closes a stream and ignores any resulting exception. This is useful
+ * when doing stream cleanup in a finally block where secondary exceptions
+ * are not worth logging.
+ */
+ public static void uncheckedClose(Closeable closeable) {
+ try {
+ if (closeable != null)
+ closeable.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+
+ /**
+ * Extracts the specified source file in the specified bundle into the
+ * specified local directory.
+ *
+ * @param url the source URL to stream the resource from
+ * @param targetFile the target file to write the resource to
+ * @param deleteOnExit <code>true</code> to use {@link File#deleteOnExit()}
+ * on the resulting file. Note that this does not guarantee that the
+ * file is deleted when the JVM exits
+ * @return the resulting file
+ * @throws FileNotFoundException
+ */
+ public static File copyResource(URL url, File targetFile, boolean deleteOnExit) throws IOException, FileNotFoundException {
+ if (url == null)
+ throw new IllegalArgumentException("null url");
+
+ FileOutputStream os = null;
+ InputStream is = null;
+ try {
+ if (targetFile.exists())
+ targetFile.delete();
+
+ is = url.openStream();
+ int read;
+ byte [] buffer = new byte [16384];
+ os = new FileOutputStream (targetFile);
+ while ((read = is.read (buffer)) != -1) {
+ os.write(buffer, 0, read);
+ }
+ os.close ();
+ is.close ();
+
+ // Request removal of the extracted files on JVM exit.
+ if (deleteOnExit)
+ targetFile.deleteOnExit();
+ return targetFile;
+ } finally {
+ FileUtils.uncheckedClose(os);
+ FileUtils.uncheckedClose(is);
+ }
+ }
+
+ /**
+ * Creates the requested location under the system's temporary directories
+ * for temporary data storage.
+ *
+ * @param pathSegments the path segments that are appended to
+ * java.io.tmpdir. The path segments musn't contain path separators.
+ * @return the resulting temporary directory as a File object
+ * @throws IOException if anything goes wrong
+ */
+ public static File getOrCreateTemporaryDirectory(boolean requireEmptyDirectory, String... pathSegments) throws IOException {
+ String separator = System.getProperty("file.separator");
+ String tempDir = System.getProperty("java.io.tmpdir");
+ if (tempDir == null)
+ throw new IllegalStateException("'java.io.tmpdir' property is not defined, is the system TMP environment variable defined?");
+
+ if (!hasTrailingSeparator(tempDir))
+ tempDir = tempDir + separator;
+
+ for (int i = 0; i < pathSegments.length-1; ++i) {
+ if (containsSeparator(pathSegments[i]))
+ throw new IllegalArgumentException("path segments contain path separators: " + Arrays.toString(pathSegments));
+ tempDir = pathSegments[i] + separator;
+ }
+
+ // Find name for an empty or non-existing temporary directory
+ if (pathSegments.length > 0) {
+ String lastSegment = pathSegments[pathSegments.length - 1];
+ String suffix = "";
+ int counter = 0;
+ // This loop will not exit until it succeeds or some error occurs.
+ while (true) {
+ File temp = new File(tempDir + lastSegment + suffix);
+
+ if (!temp.exists()) {
+ // Found non-existent temporary directory!
+ if (temp.mkdirs()) {
+ // Ok, everything seems to be fine.
+ return temp;
+ }
+ // For some reason the directory could not be created, lets
+ // try another name.
+ } else {
+ // Found an existing temporary file.
+ if (temp.isDirectory() && temp.canWrite()) {
+ if (requireEmptyDirectory) {
+ String[] files = temp.list();
+ if (files != null) {
+ if (files.length == 0) {
+ // Ok, the directory is empty and writable.
+ return temp;
+ }
+ }
+ } else {
+ return temp;
+ }
+ // Either the directory was empty or it could not be
+ // checked. In any case, don't use the directory.
+ }
+ }
+
+ // Try another directory name if no success with this one.
+ suffix = Integer.toHexString(counter);
+ ++counter;
+ }
+ }
+ return new File(tempDir);
+ }
+
+ private static boolean containsSeparator(String s) {
+ return s.contains("/") || s.contains("\\");
+ }
+
+ private static boolean hasTrailingSeparator(String s) {
+ return s.endsWith("/") || s.endsWith("\\");
+ }
+
+ /**
+ * Very simple compression using ZLib
+ * @param input the uncompressed data
+ * @return the compressed data
+ */
+ public static byte[] deflate(byte[] input) {
+ // Compress the bytes
+ Deflater compresser = new Deflater(Deflater.BEST_COMPRESSION);
+ compresser.setInput(input);
+ compresser.finish();
+
+ int bufferSize = input.length<16 ? 16 : input.length;
+ byte buffer[] = new byte[bufferSize];
+ int bufferPos = 0;
+ do {
+ int compressedDataLength = compresser.deflate(buffer, bufferPos, buffer.length-bufferPos);
+ bufferPos += compressedDataLength;
+ if (!compresser.finished())
+ buffer = Arrays.copyOf(buffer, buffer.length + bufferSize);
+ } while (!compresser.finished());
+
+ byte[] result = new byte[bufferPos+4];
+ System.arraycopy(buffer, 0, result, 4, bufferPos);
+ byte sizeData[] = LEInt.toBytes(input.length);
+ System.arraycopy(sizeData, 0, result, 0, 4);
+ return result;
+ }
+
+ /**
+ * Very simple decompression using ZLib.
+ * @param input the compressed input
+ * @return the uncompressed data
+ * @throws DataFormatException
+ */
+ public static byte[] inflate(byte[] input) throws DataFormatException {
+ // Decompress the bytes
+ int inflatedSize = LEInt.toInt(input);
+ Inflater decompresser = new Inflater();
+ decompresser.setInput(input, 4, input.length - 4);
+ byte[] result = new byte[inflatedSize];
+ int resultLength = decompresser.inflate(result);
+ assert(resultLength == inflatedSize);
+ decompresser.end();
+ return result;
+ }
+
+
+ public static boolean isValidFileName(String name) {
+ File f = new File(name) ;
+ if (!f.exists()) {
+ try {
+ boolean ok = f.createNewFile();
+ if (ok)
+ f.delete();
+ return ok;
+ } catch (IOException ioe) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Create a temporary directory
+ *
+ * @return temporary directory
+ */
+ public static File createTmpDir()
+ {
+ String tmp = System.getenv("tmp");
+ if (tmp==null) tmp = "c:/temp";
+ Random r = new Random();
+ String randomName = "simantics-tmp-"+(r.nextInt(10000)+10000);
+ File tmpDir = new File(tmp+"/"+randomName);
+ tmpDir.deleteOnExit();
+ Boolean ok = tmpDir.mkdirs();
+ if (!ok) throw new RuntimeException("tmp dir "+tmpDir+" was not created");
+ return tmpDir;
+ }
+
+ public static void compressZip(String sourcePath, String zipDir) throws IOException {
+ if (LOGGER.isDebugEnabled())
+ LOGGER.debug("Compressing file " + sourcePath + " to zip " + zipDir + ".");
+
+ File filesource = new File(sourcePath);
+ URI base = filesource.toURI();
+ Deque<File> queue = new LinkedList<File>();
+ queue.push(filesource);
+ try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zipDir))) {
+ while (!queue.isEmpty()) {
+ filesource = queue.pop();
+ for (File child : filesource.listFiles()) {
+ String name = base.relativize(child.toURI()).getPath();
+ if (child.isDirectory()) {
+ queue.push(child);
+ name = name.endsWith("/") ? name : name + "/";
+ zout.putNextEntry(new ZipEntry(name));
+ } else {
+ zout.putNextEntry(new ZipEntry(name));
+ copy(child, zout);
+ zout.closeEntry();
+ }
+ }
+ }
+ } finally {
+ LOGGER.debug("Filecompression done.");
+ }
+ }
+
+ public static void copy(File file, OutputStream out) throws IOException {
+ try (InputStream in = new FileInputStream(file)) {
+ copy(in, out);
+ }
+ }
+
+ /**
+ * Extract a zip file into a directory
+ *
+ * @param zipFile
+ * @param dst
+ * @throws IOException
+ */
+ public static void extractZip(File zipFile, File dst) throws IOException {
+ if (LOGGER.isTraceEnabled())
+ LOGGER.trace("Extracting zip "+zipFile);
+ try (FileInputStream fis = new FileInputStream(zipFile)) {
+ extractZip(fis, dst);
+ }
+ }
+
+ /**
+ * Extract a zip file into a directory
+ *
+ * @param zipInput
+ * @param dst directory
+ * @throws IOException
+ */
+ public static void extractZip(InputStream zipInput, File dst) throws IOException {
+ byte[] buf = new byte[8192];
+ ZipInputStream zis = new ZipInputStream(zipInput);
+ ZipEntry entry;
+
+ entry = zis.getNextEntry();
+ while (entry != null) {
+ // for each entry to be extracted
+ String name = entry.getName();
+ if (LOGGER.isTraceEnabled())
+ LOGGER.trace("Extracting "+name);
+ File file = new File(dst, name);
+
+ if (entry.isDirectory())
+ {
+ if ( !file.exists() ) file.mkdirs();
+ } else {
+ File parent = file.getParentFile();
+ if (!parent.exists()) parent.mkdirs();
+ if (!file.exists()) file.createNewFile();
+
+ FileOutputStream fileoutputstream = new FileOutputStream(file);
+ try {
+ int n = 0;
+ while ((n = zis.read(buf, 0, buf.length)) > -1)
+ fileoutputstream.write(buf, 0, n);
+ } catch (ZipException e) {
+ throw new IOException("Failed to extract '" + name + "'.", e);
+ } finally {
+ fileoutputstream.close();
+ }
+ }
+
+ zis.closeEntry();
+ entry = zis.getNextEntry();
+ }// while
+
+ zis.close();
+ }
+
+ // Test inflate & deflate
+ public static void main(String[] args) {
+ try {
+ // Test compression
+ String str = "abcdefghijklmnopqrstuvwxyz";
+ byte data[] = str.getBytes();
+ System.out.println("Data:\t"+data.length);
+ byte deflated[] = deflate(data);
+ System.out.println("Deflated:\t"+deflated.length);
+ byte inflated[] = inflate(deflated);
+ System.out.println("Inflated:\t"+inflated.length);
+ String str2 = new String(inflated);
+ System.out.println("Strings are equal: "+str.endsWith(str2));
+ } catch (DataFormatException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static File[] listFilesByExtension(File directory, final String extension) {
+ return directory.listFiles(new ExtensionFilter(extension));
+ }
+
+ /**
+ * Copy the content of the input stream into the output stream, using a temporary
+ * byte array buffer whose size is defined by {@link #IO_BUFFER_SIZE}.
+ *
+ * @param in The input stream to copy from.
+ * @param out The output stream to copy to.
+ *
+ * @throws IOException If any error occurs during the copy.
+ */
+ private static final int IO_BUFFER_SIZE = 64 * 1024;
+
+ public static void copy(InputStream in, OutputStream out) throws IOException {
+ byte[] b = new byte[IO_BUFFER_SIZE];
+ int read;
+ while (true) {
+ read = in.read(b);
+ if (read < 0)
+ break;
+ out.write(b, 0, read);
+ }
+ }
+
+ /**
+ * @param in
+ * @param out
+ * @param maxBytesToCopy the maximum amount of bytes to copy
+ * @return the amount of bytes copied
+ * @throws IOException
+ */
+ public static long copy(InputStream in, OutputStream out, long maxBytesToCopy) throws IOException {
+ byte[] b = new byte[IO_BUFFER_SIZE];
+ int read = 0;
+ while (read < maxBytesToCopy) {
+ int l = (int) Math.min((long) IO_BUFFER_SIZE, maxBytesToCopy-read);
+ int r = in.read(b, 0, l);
+ if (r < 0)
+ break;
+ out.write(b, 0, r);
+ read += r;
+ }
+ return read;
+ }
+
+ public static void deleteWithFilter(Path path, Predicate<Path> filter) throws IOException {
+ if (Files.exists(path))
+ Files.walkFileTree(path, new DeleteDirectoriesVisitor(filter));
+ }
+
+ public static void delete(Path path) throws IOException {
+ deleteWithFilter(path, null);
+ }
+
+ /**
+ * Empties the specified directory but does not delete the directory itself.
+ * If a non-directory path is given, it is simply deleted.
+ *
+ * @param path
+ * @throws IOException
+ */
+ public static void emptyDirectory(Path path) throws IOException {
+ if (Files.isDirectory(path))
+ Files.walkFileTree(path, new EmptyDirectoryVisitor());
+ else
+ Files.deleteIfExists(path);
+ }
+
+ public static void copy(Path from, Path to) throws IOException {
+ Files.walkFileTree(from, new CopyDirectoriesVisitor(from, to));
+ }
+
+ public static class DeleteDirectoriesVisitor extends SimpleFileVisitor<Path> {
+
+ private Predicate<Path> filter;
+
+ public DeleteDirectoriesVisitor(Predicate<Path> filter) {
+ this.filter = filter;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ if (filter != null && !filter.test(file)) {
+ return FileVisitResult.CONTINUE;
+ }
+ Files.deleteIfExists(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ if (exc != null)
+ throw exc;
+ if (filter != null && !filter.test(dir)) {
+ return FileVisitResult.CONTINUE;
+ }
+ Files.deleteIfExists(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ }
+
+ private static class EmptyDirectoryVisitor extends SimpleFileVisitor<Path> {
+ int depth = 0;
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.deleteIfExists(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ ++depth;
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ if (exc != null)
+ throw exc;
+ if (--depth > 0)
+ Files.deleteIfExists(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ }
+
+ public static class CopyDirectoriesVisitor extends SimpleFileVisitor<Path> {
+
+ private final Path fromPath;
+ private final Path toPath;
+
+ public CopyDirectoriesVisitor(Path fromPath, Path toPath) {
+ this.fromPath = fromPath;
+ this.toPath = toPath;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ Path targetPath = toPath.resolve(fromPath.relativize(dir));
+ if(!Files.exists(targetPath)){
+ Files.createDirectory(targetPath);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.copy(file, toPath.resolve(fromPath.relativize(file)), StandardCopyOption.REPLACE_EXISTING);
+ return FileVisitResult.CONTINUE;
+ }
+ }
+
+ public static void syncFile(File file) throws IOException {
+ try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
+ raf.getFD().sync();
+ }
+ }
+
+ public static void sync(Path path) throws IOException {
+ try (InputStream stream = Files.newInputStream(path, StandardOpenOption.SYNC)) {
+ }
+ }
+}