aae9666ab4156d51c7afc4db3cee0bf10250f466
[simantics/platform.git] / bundles / org.simantics.utils / src / org / simantics / utils / FileUtils.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.utils;\r
13 \r
14 import java.io.BufferedReader;\r
15 import java.io.Closeable;\r
16 import java.io.File;\r
17 import java.io.FileFilter;\r
18 import java.io.FileInputStream;\r
19 import java.io.FileNotFoundException;\r
20 import java.io.FileOutputStream;\r
21 import java.io.IOException;\r
22 import java.io.InputStream;\r
23 import java.io.InputStreamReader;\r
24 import java.io.OutputStream;\r
25 import java.io.RandomAccessFile;\r
26 import java.io.UnsupportedEncodingException;\r
27 import java.net.URI;\r
28 import java.net.URL;\r
29 import java.nio.channels.FileChannel;\r
30 import java.nio.charset.Charset;\r
31 import java.nio.file.FileVisitResult;\r
32 import java.nio.file.Files;\r
33 import java.nio.file.Path;\r
34 import java.nio.file.SimpleFileVisitor;\r
35 import java.nio.file.StandardCopyOption;\r
36 import java.nio.file.attribute.BasicFileAttributes;\r
37 import java.util.ArrayList;\r
38 import java.util.Arrays;\r
39 import java.util.Deque;\r
40 import java.util.LinkedList;\r
41 import java.util.Random;\r
42 import java.util.zip.DataFormatException;\r
43 import java.util.zip.Deflater;\r
44 import java.util.zip.Inflater;\r
45 import java.util.zip.ZipEntry;\r
46 import java.util.zip.ZipException;\r
47 import java.util.zip.ZipInputStream;\r
48 import java.util.zip.ZipOutputStream;\r
49 \r
50 import org.apache.log4j.Logger;\r
51 import org.simantics.databoard.Bindings;\r
52 import org.simantics.databoard.adapter.AdaptException;\r
53 import org.simantics.databoard.adapter.Adapter;\r
54 import org.simantics.databoard.adapter.AdapterConstructionException;\r
55 import org.simantics.databoard.binding.Binding;\r
56 import org.simantics.databoard.type.Datatype;\r
57 import org.simantics.utils.bytes.LEInt;\r
58 import org.simantics.utils.strings.FileNameUtils;\r
59 \r
60 /**\r
61  * Utilities for common file operations.\r
62  *\r
63  * see StreamUtil in databoard for Input/OutputStream reading/writing utils\r
64  * @see FileNameUtils for more utils\r
65  * \r
66  * @author Toni Kalajainen\r
67  * @author Tuukka Lehtonen\r
68  */\r
69 public class FileUtils {\r
70 \r
71         /**\r
72          * Create escaped filename\r
73          * \r
74          * @param name any string\r
75          * @return file compatible string\r
76          */\r
77         public static String escapeFileName(String name) {\r
78                 try {\r
79                         return java.net.URLEncoder.encode(name, "UTF-8");\r
80                 } catch (UnsupportedEncodingException e) {\r
81                         // never expected\r
82                         throw new RuntimeException(e);\r
83                 }\r
84         }\r
85         \r
86         /**\r
87          * Unescape filename into string \r
88          * \r
89          * @param filename \r
90          * @return any string\r
91          */\r
92         public static String unescapeFileName(String filename) {\r
93                 try {\r
94                         return java.net.URLDecoder.decode(filename, "UTF-8");\r
95                 } catch (UnsupportedEncodingException e) {\r
96                         // never expected\r
97                         throw new RuntimeException(e);\r
98                 }\r
99         }\r
100 \r
101     public static File ensureParentDirectoryExists(String path) throws IOException {\r
102         return ensureParentDirectoryExists(new File(path));\r
103     }\r
104 \r
105     /**\r
106      * Ensures the parent directory pointed by the specified file path exists as a\r
107      * directory.\r
108      * \r
109      * @param path the directory whose existence is to be ensured\r
110      * @return the requested directory\r
111      * @throws IOException if the specified directory cannot be created or\r
112      *         already exists as a file\r
113      */\r
114     public static File ensureParentDirectoryExists(File path) throws IOException {\r
115         return ensureDirectoryExists(path.getParentFile());\r
116     }\r
117         \r
118         \r
119     public static File ensureDirectoryExists(String path) throws IOException {\r
120         return ensureDirectoryExists(new File(path));\r
121     }\r
122 \r
123     /**\r
124      * Ensures the directory pointed by the specified file path exists as a\r
125      * directory.\r
126      * \r
127      * @param path the directory whose existence is to be ensured\r
128      * @return the requested directory\r
129      * @throws IOException if the specified directory cannot be created or\r
130      *         already exists as a file\r
131      */\r
132     public static File ensureDirectoryExists(File path) throws IOException {\r
133         if (path.isDirectory())\r
134             // Already exists, everything OK.\r
135             return path;\r
136 \r
137         if (path.exists())\r
138             // Path is not a directory but it exists, fail!\r
139             throw new IOException("file '" + path + "', already exists but it is not a directory");\r
140 \r
141         path.mkdirs();\r
142         if (!path.exists())\r
143             // Path is not a directory but it exists, fail!\r
144             throw new IOException("could not create directory '" + path + "' for an unknown reason");\r
145 \r
146         // Directory created OK.\r
147         return path;\r
148     }\r
149 \r
150     /**\r
151      * Copies the contents of a source file to the destination file.\r
152      * \r
153      * @param sourceFile the source file descriptor\r
154      * @param destFile the destination file descriptor\r
155      * @throws IOException when anything IO-related goes wrong during the copy\r
156      */\r
157     public static void copyFile(File sourceFile, File destFile) throws IOException {\r
158         if (!destFile.exists()) {\r
159             destFile.createNewFile();\r
160         }\r
161 \r
162         FileInputStream fis = null;\r
163         FileOutputStream fos = null;\r
164         try {\r
165             fis = new FileInputStream(sourceFile);\r
166             fos = new FileOutputStream(destFile);\r
167             FileChannel source = fis.getChannel();\r
168             FileChannel destination = fos.getChannel();\r
169 \r
170             long count = 0;\r
171             long size = source.size();\r
172             while (count < size) {\r
173                 count += destination.transferFrom(source, count, size - count);\r
174             }\r
175         } finally {\r
176             if (fis != null) {\r
177                 uncheckedClose(fis);\r
178             }\r
179             if (fos != null) {\r
180                 uncheckedClose(fos);\r
181             }\r
182         }\r
183     }\r
184     \r
185     /**\r
186      * Copy file or dir recursively.\r
187      * \r
188      * @param src\r
189      * @param dst\r
190      * @throws IOException\r
191      */\r
192     public static void copy(File src, File dst) throws IOException\r
193     {\r
194         if (src.isDirectory()) {\r
195                 if(!dst.exists()) dst.mkdir();\r
196 \r
197                 for (String file : src.list()) {\r
198                         File srcFile = new File(src, file);\r
199                         File dstFile = new File(dst, file);\r
200                         copy(srcFile,dstFile);\r
201                 }\r
202         } else {\r
203                 copyFile(src, dst);\r
204         }\r
205     }\r
206     \r
207 \r
208 //    public static File createTempFileFromResource(URL sourceUrl) throws IOException {\r
209 //        sourceUrl = FileLocator.resolve(sourceUrl);\r
210 //        File sourceFile;\r
211 //        try {\r
212 //            if (sourceUrl.getProtocol().equalsIgnoreCase("file"))\r
213 //                sourceFile = new File(sourceUrl.getPath());\r
214 //            else\r
215 //                sourceFile = new File(sourceUrl.toURI());\r
216 //        } catch (URISyntaxException e) {\r
217 //            throw new RuntimeException(e);\r
218 //        }\r
219 //\r
220 //        File tempFile = File.createTempFile("tmp", ".tmp");\r
221 //        FileUtils.copyFile(sourceFile, tempFile);\r
222 //        return tempFile;\r
223 //    }\r
224 \r
225     /**\r
226      * Reads entire binary file\r
227      * @param file file\r
228      * @return contents of binary file\r
229      * @throws IOException on i/o problems\r
230      */\r
231     public static byte[] readFile(File file)\r
232     throws IOException\r
233     {\r
234         try (FileInputStream fis = new FileInputStream(file)) {\r
235             long size = file.length();\r
236             if (size>Integer.MAX_VALUE)\r
237                 throw new IOException("File too big");\r
238             int len = (int) size;\r
239             byte data [] = new byte[len];\r
240             int pos = 0;\r
241 \r
242             while (pos<size) {\r
243                 int read = fis.read(data, pos, len-pos);\r
244                 pos += read;\r
245             }\r
246             return data;\r
247         }\r
248     }\r
249 \r
250     /**\r
251      * Creates and writes a binary file\r
252      * @param file file\r
253      * @param data data\r
254      * @throws IOException on i/o problems\r
255      */\r
256     public static void writeFile(File file, byte[] data)\r
257     throws IOException\r
258     {\r
259 //        file.createNewFile();\r
260 //        file.setWritable(true);\r
261         try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {\r
262             raf.setLength(data.length);\r
263             raf.seek(0);\r
264             raf.write(data);\r
265         }\r
266     }\r
267 \r
268 \r
269     /**\r
270      * Fetch the entire contents of the input stream text file, and return it in\r
271      * a String. This style of implementation does not throw Exceptions to the\r
272      * caller.\r
273      * \r
274      * @param stream the stream to completely read in\r
275      */\r
276     public static String getContents(InputStream stream) throws IOException {\r
277         return getContents(stream, Charset.defaultCharset());\r
278     }\r
279 \r
280     /**\r
281      * Fetch the entire contents of the input stream text file, and return it in\r
282      * a String. This style of implementation does not throw Exceptions to the\r
283      * caller.\r
284      * \r
285      * @param stream the stream to completely read in\r
286      */\r
287     public static String getContents(InputStream stream, Charset charset, String lineSeparator) throws IOException {\r
288         StringBuilder contents = new StringBuilder();\r
289         BufferedReader input = null;\r
290         try {\r
291             input = new BufferedReader(new InputStreamReader(stream, charset));\r
292 \r
293             String line = null;\r
294             while ((line = input.readLine()) != null) {\r
295                 contents.append(line);\r
296                 contents.append(lineSeparator);\r
297             }\r
298         } finally {\r
299             try {\r
300                 if (input != null) {\r
301                     // flush and close both "input" and its underlying\r
302                     // FileReader\r
303                     input.close();\r
304                 }\r
305             } catch (IOException ex) {\r
306                 ex.printStackTrace();\r
307             }\r
308         }\r
309         return contents.toString();\r
310     }\r
311 \r
312     public static String getContents(File f) throws IOException {\r
313         return getContents(f, Charset.defaultCharset());\r
314     }\r
315     \r
316     public static String getContents(File f, Charset charset) throws IOException {\r
317         return getContents(new FileInputStream(f), charset);\r
318     }\r
319 \r
320     public static String getContents(InputStream stream, Charset charset) throws IOException {\r
321         return getContents(stream, charset, System.getProperty("line.separator"));\r
322     }\r
323 \r
324     public static String getContents(InputStream stream, String lineSeparator) throws IOException {\r
325         return getContents(stream, Charset.defaultCharset(), lineSeparator);\r
326     }\r
327     \r
328     /**\r
329      * Fetch the entire contents of a text file, and return it in a String. This\r
330      * style of implementation does not throw Exceptions to the caller.\r
331      * \r
332      * @param sourcePath is a file which already exists and can be read.\r
333      */\r
334     public static String getContents(String sourcePath) throws IOException {\r
335         return getContents(sourcePath, Charset.defaultCharset(), System.getProperty("line.separator"));\r
336     }\r
337 \r
338     public static String getContents(String sourcePath, String lineSeparator) throws IOException {\r
339         return getContents(sourcePath, Charset.defaultCharset(), lineSeparator);\r
340     }\r
341 \r
342     public static String getContents(String sourcePath, Charset charset) throws IOException {\r
343         return getContents(sourcePath, charset, System.getProperty("line.separator"));\r
344     }\r
345 \r
346     /**\r
347      * Fetch the entire contents of a text file, and return it in a String. This\r
348      * style of implementation does not throw Exceptions to the caller.\r
349      * \r
350      * @param sourcePath is a file which already exists and can be read.\r
351      */\r
352     public static String getContents(String sourcePath, Charset charset, String lineSeparator) throws IOException {\r
353         FileInputStream input = null;\r
354         try {\r
355             input = new FileInputStream(sourcePath);\r
356             return getContents(input, charset, lineSeparator);\r
357         } finally {\r
358             uncheckedClose(input);\r
359         }\r
360     }\r
361 \r
362     /**\r
363      * Get the contents of a file which is located inside a given bundle.\r
364      * This works regardless of whether the bundle is jarred or not.\r
365      * \r
366      * @param URL the resource to read in\r
367      * @return the contents of the resource\r
368      * @throws IOException if the file is not found or other io errors occur\r
369      */\r
370     public static String getContents(URL url) throws IOException {\r
371         if (url == null)\r
372             throw new IllegalArgumentException("null URL");\r
373         InputStream input = null;\r
374         try {\r
375             input = url.openStream();\r
376             return FileUtils.getContents(input);\r
377         } finally {\r
378             uncheckedClose(input);\r
379         }\r
380     }\r
381 \r
382         /**\r
383          * Read a binary file into a java instance. Binary file is a variant, \r
384          * there is a filetype in the header of the file. \r
385          * If requested binding is not the exact binding of the file, an adapter is tried.\r
386          * \r
387          * @param file file\r
388          * @param binding content binding\r
389          * @return instance\r
390          * @throws IOException \r
391          */\r
392         public static Object readFile(InputStream stream, Binding binding) throws IOException {\r
393                 Binding datatype_binding = Bindings.getBindingUnchecked( Datatype.class );\r
394                 Datatype type = (Datatype) Bindings.getSerializerUnchecked( datatype_binding ).deserialize( stream );\r
395 \r
396                 if (type.equals(binding.type())) {\r
397                         return Bindings.getSerializerUnchecked( binding ).deserialize(stream);\r
398                 } else {\r
399                         try {\r
400                                 Binding fileContentBinding = Bindings.getMutableBinding(type);\r
401                                 Adapter adapter = Bindings.adapterFactory.getAdapter(fileContentBinding, binding, true, false);\r
402                                 Object value = Bindings.getSerializerUnchecked( fileContentBinding ).deserialize(stream);\r
403                                 return adapter.adapt( value );\r
404                         } catch (AdapterConstructionException e) {\r
405                                 throw new IOException(e);\r
406                         } catch (AdaptException e) {\r
407                                 throw new IOException(e);\r
408                         }\r
409                 }\r
410         }\r
411     \r
412     /**\r
413      * Deletes all files and sub-directories from the specified directory. If a\r
414      * file is specified, only that fill will be deleted.\r
415      * \r
416      * @param dir\r
417      * @throws IOException\r
418      */\r
419     public static void deleteAll(File dir) throws IOException {\r
420         if (dir.isFile()) {\r
421             dir.delete();\r
422             return;\r
423         }\r
424 \r
425         if (dir.isDirectory()) {\r
426             File[] fs = dir.listFiles((FileFilter) null);\r
427             if (fs == null)\r
428                 return;\r
429 \r
430             for (File f : fs) {\r
431                 if (f.isDirectory()) {\r
432                     deleteAll(f);\r
433                 } else {\r
434                     if (!f.delete()) {\r
435                         throw new IOException("Could not delete file: " + f.getAbsolutePath());\r
436                     }\r
437                 }\r
438             }\r
439 \r
440             if (!dir.delete()) {\r
441                 throw new IOException("Could not delete directory: " + dir.getAbsolutePath());\r
442             }\r
443         } else if (dir.exists()) {\r
444             if (!dir.delete()) {\r
445                 throw new IOException("Could not delete file: " + dir.getAbsolutePath());\r
446             }\r
447         }\r
448     }\r
449 \r
450     /**\r
451      * Deletes all files and sub-directories from the specified directory. If a\r
452      * file is specified, only that fill will be deleted.\r
453      * \r
454      * If the given directory contains files listed in the filter those files are not deleted\r
455      * \r
456      * @param dir\r
457      *                          directory from where to start the deletion \r
458      * @param filter\r
459      *                          filter containing specific file paths not to delete\r
460      * @throws IOException\r
461      */\r
462     public static void deleteAllWithFilter(File dir, ArrayList<String> filter) throws IOException {\r
463         if (dir.isFile()) {\r
464                 if (!filter.contains(dir.getAbsolutePath())) {\r
465                         dir.delete();\r
466                         return;                         \r
467                 }\r
468         }\r
469 \r
470         if (dir.isDirectory()) {\r
471             File[] fs = dir.listFiles((FileFilter) null);\r
472             if (fs == null)\r
473                 return;\r
474 \r
475             for (File f : fs) {\r
476                 if (f.isDirectory()) {\r
477                     deleteAllWithFilter(f, filter);\r
478                 } else {\r
479                         if (!filter.contains(f.getAbsolutePath())) {\r
480                         if (!f.delete()) {\r
481                             throw new IOException("Could not delete file: " + f.getAbsolutePath());\r
482                         }       \r
483                         }\r
484                 }\r
485             }\r
486             if (!filter.contains(dir.getAbsolutePath())) {\r
487                 if (!dir.delete()) {\r
488                     throw new IOException("Could not delete directory: " + dir.getAbsolutePath());\r
489                 }               \r
490             }\r
491         } else if (dir.exists()) {\r
492                 if (filter.contains(dir.getAbsolutePath())) {\r
493                 if (!dir.delete()) {\r
494                     throw new IOException("Could not delete file: " + dir.getAbsolutePath());\r
495                 }\r
496                 }\r
497         }\r
498     }\r
499     \r
500     public static ArrayList<String> createFileFilter(File dir, ArrayList<String> filter) {\r
501         if (filter == null)\r
502                 filter = new ArrayList<String>();\r
503         if (dir.isFile()) {\r
504                 filter.add(dir.getAbsolutePath());\r
505                 return filter;\r
506         }\r
507         \r
508         if (dir.isDirectory()) {\r
509             File[] fs = dir.listFiles((FileFilter) null);\r
510             if (fs == null)\r
511                 return filter;\r
512 \r
513             for (File f : fs) {\r
514                 if (f.isDirectory()) {\r
515                     createFileFilter(f, filter);\r
516                 } else {\r
517                         filter.add(f.getAbsolutePath());\r
518                 }\r
519             }\r
520             filter.add(dir.getAbsolutePath());\r
521         } else if (dir.exists()) {\r
522                 filter.add(dir.getAbsolutePath());\r
523         }\r
524                 return filter;\r
525     }\r
526 \r
527 \r
528     /**\r
529      * Delete a directory incl. all files and sub-directories by best effort.\r
530      * Does not throw exceptions if deletion fails, simply tries to delete the\r
531      * provided directory to the best of Java File API's abilities.\r
532      * \r
533      * @param dir\r
534      *            directory to delete recursively\r
535      * @boolean <code>true</code> if all files were successfully deleted,\r
536      *          <code>false</code> if some or all failed to be deleted\r
537      */\r
538     public static boolean deleteDir(File dir) {\r
539         Logger myLogger = Logger.getLogger(FileUtils.class);\r
540         myLogger.debug("Deleting directory "+dir);\r
541         boolean result = true;\r
542 \r
543         if (!dir.isDirectory()) return false;\r
544         File[] fs = dir.listFiles();\r
545         if (fs != null) {\r
546             for (File f : fs) {\r
547                 if (f.isDirectory()) result &= deleteDir(f);\r
548                 if (f.isFile()) result &= f.delete();\r
549             }\r
550         }\r
551         boolean ok = dir.delete();\r
552 //              if (!ok) dir.deleteOnExit();\r
553         result &= ok;\r
554         return result;\r
555     }\r
556     \r
557     public static String deleteDirs(File dir) { \r
558         Logger myLogger = Logger.getLogger(FileUtils.class);\r
559         myLogger.debug("Deleting directory "+dir);\r
560         boolean result = true;\r
561 \r
562         if (!dir.isDirectory()) \r
563                 return dir + " is not a directory!";\r
564         File[] fs = dir.listFiles();\r
565         if (fs != null) {\r
566             for (File f : fs) {\r
567                 //System.out.println("file f :" + f);\r
568                 if (f.isDirectory()) { \r
569                         boolean a = deleteDir(f);\r
570                         result &= a;\r
571                 }\r
572                 if (f.isFile()) {\r
573                         boolean a = f.delete();\r
574                         result &= a;\r
575                 }\r
576                         \r
577             }\r
578         }\r
579         boolean ok = dir.delete();\r
580 //              if (!ok) dir.deleteOnExit();\r
581         result &= ok;\r
582         return "deleteDirs succesful for " + dir + " : " + result;\r
583     }\r
584 \r
585     /**\r
586      * Closes a stream and ignores any resulting exception. This is useful\r
587      * when doing stream cleanup in a finally block where secondary exceptions\r
588      * are not worth logging.\r
589      */\r
590     public static void uncheckedClose(Closeable closeable) {\r
591         try {\r
592             if (closeable != null)\r
593                 closeable.close();\r
594         } catch (IOException e) {\r
595             //ignore\r
596         }\r
597     }\r
598 \r
599     /**\r
600      * Extracts the specified source file in the specified bundle into the\r
601      * specified local directory.\r
602      * \r
603      * @param url the source URL to stream the resource from\r
604      * @param targetFile the target file to write the resource to\r
605      * @param deleteOnExit <code>true</code> to use {@link File#deleteOnExit()}\r
606      *        on the resulting file. Note that this does not guarantee that the\r
607      *        file is deleted when the JVM exits\r
608      * @return the resulting file\r
609      * @throws FileNotFoundException\r
610      */\r
611     public static File copyResource(URL url, File targetFile, boolean deleteOnExit) throws IOException, FileNotFoundException {\r
612         if (url == null)\r
613             throw new IllegalArgumentException("null url");\r
614 \r
615         FileOutputStream os = null;\r
616         InputStream is = null;\r
617         try {\r
618             if (targetFile.exists())\r
619                 targetFile.delete();\r
620 \r
621             is = url.openStream();\r
622             int read;\r
623             byte [] buffer = new byte [16384];\r
624             os = new FileOutputStream (targetFile);\r
625             while ((read = is.read (buffer)) != -1) {\r
626                 os.write(buffer, 0, read);\r
627             }\r
628             os.close ();\r
629             is.close ();\r
630 \r
631             // Request removal of the extracted files on JVM exit.\r
632             if (deleteOnExit)\r
633                 targetFile.deleteOnExit();\r
634             return targetFile;\r
635         } finally {\r
636             FileUtils.uncheckedClose(os);\r
637             FileUtils.uncheckedClose(is);\r
638         }\r
639     }\r
640 \r
641     /**\r
642      * Creates the requested location under the system's temporary directories\r
643      * for temporary data storage.\r
644      * \r
645      * @param pathSegments the path segments that are appended to\r
646      *        java.io.tmpdir. The path segments musn't contain path separators.\r
647      * @return the resulting temporary directory as a File object\r
648      * @throws IOException if anything goes wrong\r
649      */\r
650     public static File getOrCreateTemporaryDirectory(boolean requireEmptyDirectory, String... pathSegments) throws IOException {\r
651         String separator = System.getProperty("file.separator");\r
652         String tempDir = System.getProperty("java.io.tmpdir");\r
653         if (tempDir == null)\r
654             throw new IllegalStateException("'java.io.tmpdir' property is not defined, is the system TMP environment variable defined?");\r
655 \r
656         if (!hasTrailingSeparator(tempDir))\r
657             tempDir = tempDir + separator;\r
658 \r
659         for (int i = 0; i < pathSegments.length-1; ++i) {\r
660             if (containsSeparator(pathSegments[i]))\r
661                 throw new IllegalArgumentException("path segments contain path separators: " + Arrays.toString(pathSegments));\r
662             tempDir = pathSegments[i] + separator;\r
663         }\r
664 \r
665         // Find name for an empty or non-existing temporary directory\r
666         if (pathSegments.length > 0) {\r
667             String lastSegment = pathSegments[pathSegments.length - 1];\r
668             String suffix = "";\r
669             int counter = 0;\r
670             // This loop will not exit until it succeeds or some error occurs.\r
671             while (true) {\r
672                 File temp = new File(tempDir + lastSegment + suffix);\r
673 \r
674                 if (!temp.exists()) {\r
675                     // Found non-existent temporary directory!\r
676                     if (temp.mkdirs()) {\r
677                         // Ok, everything seems to be fine.\r
678                         return temp;\r
679                     }\r
680                     // For some reason the directory could not be created, lets\r
681                     // try another name.\r
682                 } else {\r
683                     // Found an existing temporary file.\r
684                     if (temp.isDirectory() && temp.canWrite()) {\r
685                         if (requireEmptyDirectory) {\r
686                             String[] files = temp.list();\r
687                             if (files != null) {\r
688                                 if (files.length == 0) {\r
689                                     // Ok, the directory is empty and writable.\r
690                                     return temp;\r
691                                 }\r
692                             }\r
693                         } else {\r
694                             return temp;\r
695                         }\r
696                         // Either the directory was empty or it could not be\r
697                         // checked. In any case, don't use the directory.\r
698                     }\r
699                 }\r
700 \r
701                 // Try another directory name if no success with this one.\r
702                 suffix = Integer.toHexString(counter);\r
703                 ++counter;\r
704             }\r
705         }\r
706         return new File(tempDir);\r
707     }\r
708 \r
709     private static boolean containsSeparator(String s) {\r
710         return s.contains("/") || s.contains("\\");\r
711     }\r
712 \r
713     private static boolean hasTrailingSeparator(String s) {\r
714         return s.endsWith("/") || s.endsWith("\\");\r
715     }\r
716 \r
717     /**\r
718      * Very simple compression using ZLib\r
719      * @param input the uncompressed data\r
720      * @return the compressed data\r
721      */\r
722     public static byte[] deflate(byte[] input) {\r
723         // Compress the bytes\r
724         Deflater compresser = new Deflater(Deflater.BEST_COMPRESSION);\r
725         compresser.setInput(input);\r
726         compresser.finish();\r
727 \r
728         int bufferSize = input.length<16 ? 16 : input.length;\r
729         byte buffer[] = new byte[bufferSize];\r
730         int  bufferPos = 0;\r
731         do {\r
732             int compressedDataLength = compresser.deflate(buffer, bufferPos, buffer.length-bufferPos);\r
733             bufferPos += compressedDataLength;\r
734             if (!compresser.finished())\r
735                 buffer = Arrays.copyOf(buffer, buffer.length + bufferSize);\r
736         } while (!compresser.finished());\r
737 \r
738         byte[] result = new byte[bufferPos+4];\r
739         System.arraycopy(buffer, 0, result, 4, bufferPos);\r
740         byte sizeData[] = LEInt.toBytes(input.length);\r
741         System.arraycopy(sizeData, 0, result, 0, 4);\r
742         return result;\r
743     }\r
744 \r
745     /**\r
746      * Very simple decompression using ZLib.\r
747      * @param input the compressed input\r
748      * @return the uncompressed data\r
749      * @throws DataFormatException\r
750      */\r
751     public static byte[] inflate(byte[] input) throws DataFormatException {\r
752         // Decompress the bytes\r
753         int inflatedSize = LEInt.toInt(input);\r
754         Inflater decompresser = new Inflater();\r
755         decompresser.setInput(input, 4, input.length - 4);\r
756         byte[] result = new byte[inflatedSize];\r
757         int resultLength = decompresser.inflate(result);\r
758         assert(resultLength == inflatedSize);\r
759         decompresser.end();\r
760         return result;\r
761     }\r
762 \r
763 \r
764     public static boolean isValidFileName(String name) {\r
765         File f = new File(name) ;\r
766         if (!f.exists()) {\r
767             try {\r
768                 boolean ok = f.createNewFile();\r
769                 if (ok)\r
770                     f.delete();\r
771                 return ok;\r
772             } catch (IOException ioe) {\r
773                 return false;\r
774             }\r
775         }\r
776         return true;\r
777     }\r
778 \r
779     /**\r
780      * Create a temporary directory\r
781      * \r
782      * @return temporary directory\r
783      */\r
784     public static File createTmpDir()\r
785     {\r
786         String tmp = System.getenv("tmp");\r
787         if (tmp==null) tmp = "c:/temp";\r
788         Random r = new Random();\r
789         String randomName = "simantics-tmp-"+(r.nextInt(10000)+10000);\r
790         File tmpDir = new File(tmp+"/"+randomName);\r
791         tmpDir.deleteOnExit();\r
792         Boolean ok = tmpDir.mkdirs();\r
793         if (!ok) throw new RuntimeException("tmp dir "+tmpDir+" was not created");\r
794         return tmpDir;\r
795     }\r
796     \r
797     public static void compressZip(String sourcePath, String zipDir) throws IOException {\r
798         Logger myLogger = Logger.getLogger(FileUtils.class);\r
799         myLogger.debug("Compressing file " + sourcePath + " to zip " + zipDir + ".");\r
800 \r
801         System.out.println("Compressing file " + sourcePath + " to zip " + zipDir + ".");\r
802 \r
803         File filesource = new File(sourcePath);\r
804         URI base = filesource.toURI();\r
805         Deque<File> queue = new LinkedList<File>();\r
806         queue.push(filesource);\r
807         try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zipDir))) {\r
808                 while (!queue.isEmpty()) {\r
809                         filesource = queue.pop();\r
810                         for (File child : filesource.listFiles()) {\r
811                                 String name = base.relativize(child.toURI()).getPath();\r
812                                 if (child.isDirectory()) {\r
813                                         queue.push(child);\r
814                                         name = name.endsWith("/") ? name : name + "/";\r
815                                         zout.putNextEntry(new ZipEntry(name));\r
816                                 } else {\r
817                                         zout.putNextEntry(new ZipEntry(name));\r
818                                         copy(child, zout);\r
819                                         zout.closeEntry();\r
820                                 }\r
821                         }\r
822                 }\r
823         } finally {\r
824                 myLogger.debug("Filecompression done.");\r
825                 System.out.println("Filecompression done.");\r
826         }\r
827     }\r
828 \r
829     private static void copy(File file, ZipOutputStream zout) throws IOException {\r
830         try (InputStream in = new FileInputStream(file)) {\r
831                 copy(in, zout);\r
832         }\r
833     }\r
834 \r
835         /**\r
836      * Extract a zip file into a directory\r
837      * \r
838      * @param zipFile\r
839      * @param dst\r
840      * @throws IOException\r
841      */\r
842     public static void extractZip(File zipFile, File dst) throws IOException {\r
843         Logger myLogger = Logger.getLogger(FileUtils.class);\r
844         myLogger.debug("Extracting zip "+zipFile);\r
845         try (FileInputStream fis = new FileInputStream(zipFile)) {\r
846             extractZip(fis, dst);\r
847         }\r
848     }\r
849 \r
850     /**\r
851      * Extract a zip file into a directory\r
852      * \r
853      * @param zipInput\r
854      * @param dst directory\r
855      * @throws IOException\r
856      */\r
857     public static void extractZip(InputStream zipInput, File dst) throws IOException {\r
858         Logger myLogger = Logger.getLogger(FileUtils.class);\r
859         byte[] buf = new byte[8192];\r
860         ZipInputStream zis = new ZipInputStream(zipInput);\r
861         ZipEntry entry;\r
862 \r
863         entry = zis.getNextEntry();\r
864         while (entry != null) {\r
865             // for each entry to be extracted\r
866             String name = entry.getName();\r
867             myLogger.debug("Extracting "+name);\r
868             File file = new File(dst, name);\r
869 \r
870             if (entry.isDirectory())\r
871             {\r
872                 if ( !file.exists() ) file.mkdirs();\r
873             } else {\r
874                 File parent = file.getParentFile();\r
875                 if (!parent.exists()) parent.mkdirs();\r
876                 if (!file.exists()) file.createNewFile();\r
877 \r
878                 FileOutputStream fileoutputstream = new FileOutputStream(file);\r
879                 try {\r
880                     int n = 0;\r
881                     while ((n = zis.read(buf, 0, buf.length)) > -1)\r
882                         fileoutputstream.write(buf, 0, n);\r
883                 } catch (ZipException e) {\r
884                         throw new IOException("Failed to extract '" + name + "'.", e);\r
885                 } finally {\r
886                     fileoutputstream.close();\r
887                 }\r
888             }\r
889 \r
890             zis.closeEntry();\r
891             entry = zis.getNextEntry();\r
892         }// while\r
893 \r
894         zis.close();\r
895     }\r
896 \r
897     // Test inflate & deflate\r
898     public static void main(String[] args) {\r
899         try {\r
900             // Test compression\r
901             String str = "abcdefghijklmnopqrstuvwxyz";\r
902             byte data[] = str.getBytes();\r
903             System.out.println("Data:\t"+data.length);\r
904             byte deflated[] = deflate(data);\r
905             System.out.println("Deflated:\t"+deflated.length);\r
906             byte inflated[] = inflate(deflated);\r
907             System.out.println("Inflated:\t"+inflated.length);\r
908             String str2 = new String(inflated);\r
909             System.out.println("Strings are equal: "+str.endsWith(str2));\r
910         } catch (DataFormatException e) {\r
911             e.printStackTrace();\r
912         }\r
913     }\r
914 \r
915     public static File[] listFilesByExtension(File directory, final String extension) {\r
916         return directory.listFiles(new ExtensionFilter(extension));\r
917     }\r
918     \r
919     /**\r
920      * Copy the content of the input stream into the output stream, using a temporary\r
921      * byte array buffer whose size is defined by {@link #IO_BUFFER_SIZE}.\r
922      *\r
923      * @param in The input stream to copy from.\r
924      * @param out The output stream to copy to.\r
925      *\r
926      * @throws IOException If any error occurs during the copy.\r
927      */\r
928     private static final int IO_BUFFER_SIZE = 64 * 1024;\r
929 \r
930     public static void copy(InputStream in, OutputStream out) throws IOException {\r
931         byte[] b = new byte[IO_BUFFER_SIZE];\r
932         int read;\r
933         while (true) {\r
934             read = in.read(b);\r
935             if (read < 0)\r
936                 break;\r
937             out.write(b, 0, read);\r
938         }\r
939     }\r
940 \r
941     /**\r
942      * @param in\r
943      * @param out\r
944      * @param maxBytesToCopy the maximum amount of bytes to copy\r
945      * @return the amount of bytes copied\r
946      * @throws IOException\r
947      */\r
948     public static long copy(InputStream in, OutputStream out, long maxBytesToCopy) throws IOException {\r
949         byte[] b = new byte[IO_BUFFER_SIZE];\r
950         int read = 0;\r
951         while (read < maxBytesToCopy) {\r
952             int l = (int) Math.min((long) IO_BUFFER_SIZE, maxBytesToCopy-read);\r
953             int r = in.read(b, 0, l);\r
954             if (r < 0)\r
955                 break;\r
956             out.write(b, 0, r);\r
957             read += r;\r
958         }\r
959         return read;\r
960     }\r
961 \r
962     public static void delete(Path databaseLocation) throws IOException {\r
963         Files.walkFileTree(databaseLocation, new DeleteDirectoriesVisitor());\r
964     }\r
965     \r
966     public static void copy(Path from, Path to) throws IOException {\r
967         Files.walkFileTree(from, new CopyDirectoriesVisitor(from, to));\r
968     }\r
969     \r
970     public static class DeleteDirectoriesVisitor extends SimpleFileVisitor<Path> {\r
971         \r
972         @Override\r
973         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
974             Files.delete(file);\r
975             if (Files.exists(file))\r
976                 throw new IOException("Could not delete file " + file.toAbsolutePath().toString());\r
977             return FileVisitResult.CONTINUE;\r
978         }\r
979         \r
980         @Override\r
981         public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {\r
982             if (exc != null)\r
983                 throw exc;\r
984             Files.delete(dir);\r
985             if (Files.exists(dir))\r
986                 throw new IOException("Could not delete file " + dir.toAbsolutePath().toString());\r
987             return FileVisitResult.CONTINUE;\r
988         }\r
989     }\r
990     \r
991     public static class CopyDirectoriesVisitor extends SimpleFileVisitor<Path> {\r
992         \r
993         private final Path fromPath;\r
994         private final Path toPath;\r
995         \r
996         public CopyDirectoriesVisitor(Path fromPath, Path toPath) {\r
997             this.fromPath = fromPath;\r
998             this.toPath = toPath;\r
999         }\r
1000         \r
1001         @Override\r
1002         public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\r
1003             Path targetPath = toPath.resolve(fromPath.relativize(dir));\r
1004             if(!Files.exists(targetPath)){\r
1005                 Files.createDirectory(targetPath);\r
1006             }\r
1007             return FileVisitResult.CONTINUE;\r
1008         }\r
1009 \r
1010         @Override\r
1011         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\r
1012             Files.copy(file, toPath.resolve(fromPath.relativize(file)), StandardCopyOption.REPLACE_EXISTING);\r
1013             return FileVisitResult.CONTINUE;\r
1014         }\r
1015     }\r
1016 }\r