]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils/src/org/simantics/utils/FileUtils.java
Worked around Windows FS problems in IndexedRelationsSearcherBase
[simantics/platform.git] / bundles / org.simantics.utils / src / org / simantics / utils / FileUtils.java
index 51449d57bf4814a03e788b66c20c9e7f66996a25..44a3dfcf5731b9ff2c9334959a66e3463416f283 100644 (file)
-/*******************************************************************************\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)) {
+        }
+    }
+}