Changing existing log4j logging to use slf4j
[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.simantics.databoard.Bindings;\r
51 import org.simantics.databoard.adapter.AdaptException;\r
52 import org.simantics.databoard.adapter.Adapter;\r
53 import org.simantics.databoard.adapter.AdapterConstructionException;\r
54 import org.simantics.databoard.binding.Binding;\r
55 import org.simantics.databoard.type.Datatype;\r
56 import org.simantics.utils.bytes.LEInt;\r
57 import org.simantics.utils.strings.FileNameUtils;\r
58 import org.slf4j.Logger;\r
59 import org.slf4j.LoggerFactory;\r
60 \r
61 /**\r
62  * Utilities for common file operations.\r
63  *\r
64  * see StreamUtil in databoard for Input/OutputStream reading/writing utils\r
65  * @see FileNameUtils for more utils\r
66  * \r
67  * @author Toni Kalajainen\r
68  * @author Tuukka Lehtonen\r
69  */\r
70 public class FileUtils {\r
71 \r
72         private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);\r
73 \r
74         /**\r
75          * Create escaped filename\r
76          * \r
77          * @param name any string\r
78          * @return file compatible string\r
79          */\r
80         public static String escapeFileName(String name) {\r
81                 try {\r
82                         return java.net.URLEncoder.encode(name, "UTF-8");\r
83                 } catch (UnsupportedEncodingException e) {\r
84                         // never expected\r
85                         throw new RuntimeException(e);\r
86                 }\r
87         }\r
88         \r
89         /**\r
90          * Unescape filename into string \r
91          * \r
92          * @param filename \r
93          * @return any string\r
94          */\r
95         public static String unescapeFileName(String filename) {\r
96                 try {\r
97                         return java.net.URLDecoder.decode(filename, "UTF-8");\r
98                 } catch (UnsupportedEncodingException e) {\r
99                         // never expected\r
100                         throw new RuntimeException(e);\r
101                 }\r
102         }\r
103 \r
104     public static File ensureParentDirectoryExists(String path) throws IOException {\r
105         return ensureParentDirectoryExists(new File(path));\r
106     }\r
107 \r
108     /**\r
109      * Ensures the parent directory pointed by the specified file path exists as a\r
110      * directory.\r
111      * \r
112      * @param path the directory whose existence is to be ensured\r
113      * @return the requested directory\r
114      * @throws IOException if the specified directory cannot be created or\r
115      *         already exists as a file\r
116      */\r
117     public static File ensureParentDirectoryExists(File path) throws IOException {\r
118         return ensureDirectoryExists(path.getParentFile());\r
119     }\r
120         \r
121         \r
122     public static File ensureDirectoryExists(String path) throws IOException {\r
123         return ensureDirectoryExists(new File(path));\r
124     }\r
125 \r
126     /**\r
127      * Ensures the directory pointed by the specified file path exists as a\r
128      * directory.\r
129      * \r
130      * @param path the directory whose existence is to be ensured\r
131      * @return the requested directory\r
132      * @throws IOException if the specified directory cannot be created or\r
133      *         already exists as a file\r
134      */\r
135     public static File ensureDirectoryExists(File path) throws IOException {\r
136         if (path.isDirectory())\r
137             // Already exists, everything OK.\r
138             return path;\r
139 \r
140         if (path.exists())\r
141             // Path is not a directory but it exists, fail!\r
142             throw new IOException("file '" + path + "', already exists but it is not a directory");\r
143 \r
144         path.mkdirs();\r
145         if (!path.exists())\r
146             // Path is not a directory but it exists, fail!\r
147             throw new IOException("could not create directory '" + path + "' for an unknown reason");\r
148 \r
149         // Directory created OK.\r
150         return path;\r
151     }\r
152 \r
153     /**\r
154      * Copies the contents of a source file to the destination file.\r
155      * \r
156      * @param sourceFile the source file descriptor\r
157      * @param destFile the destination file descriptor\r
158      * @throws IOException when anything IO-related goes wrong during the copy\r
159      */\r
160     public static void copyFile(File sourceFile, File destFile) throws IOException {\r
161         if (!destFile.exists()) {\r
162             destFile.createNewFile();\r
163         }\r
164 \r
165         FileInputStream fis = null;\r
166         FileOutputStream fos = null;\r
167         try {\r
168             fis = new FileInputStream(sourceFile);\r
169             fos = new FileOutputStream(destFile);\r
170             FileChannel source = fis.getChannel();\r
171             FileChannel destination = fos.getChannel();\r
172 \r
173             long count = 0;\r
174             long size = source.size();\r
175             while (count < size) {\r
176                 count += destination.transferFrom(source, count, size - count);\r
177             }\r
178         } finally {\r
179             if (fis != null) {\r
180                 uncheckedClose(fis);\r
181             }\r
182             if (fos != null) {\r
183                 uncheckedClose(fos);\r
184             }\r
185         }\r
186     }\r
187     \r
188     /**\r
189      * Copy file or dir recursively.\r
190      * \r
191      * @param src\r
192      * @param dst\r
193      * @throws IOException\r
194      */\r
195     public static void copy(File src, File dst) throws IOException\r
196     {\r
197         if (src.isDirectory()) {\r
198                 if(!dst.exists()) dst.mkdir();\r
199 \r
200                 for (String file : src.list()) {\r
201                         File srcFile = new File(src, file);\r
202                         File dstFile = new File(dst, file);\r
203                         copy(srcFile,dstFile);\r
204                 }\r
205         } else {\r
206                 copyFile(src, dst);\r
207         }\r
208     }\r
209     \r
210 \r
211 //    public static File createTempFileFromResource(URL sourceUrl) throws IOException {\r
212 //        sourceUrl = FileLocator.resolve(sourceUrl);\r
213 //        File sourceFile;\r
214 //        try {\r
215 //            if (sourceUrl.getProtocol().equalsIgnoreCase("file"))\r
216 //                sourceFile = new File(sourceUrl.getPath());\r
217 //            else\r
218 //                sourceFile = new File(sourceUrl.toURI());\r
219 //        } catch (URISyntaxException e) {\r
220 //            throw new RuntimeException(e);\r
221 //        }\r
222 //\r
223 //        File tempFile = File.createTempFile("tmp", ".tmp");\r
224 //        FileUtils.copyFile(sourceFile, tempFile);\r
225 //        return tempFile;\r
226 //    }\r
227 \r
228     /**\r
229      * Reads entire binary file\r
230      * @param file file\r
231      * @return contents of binary file\r
232      * @throws IOException on i/o problems\r
233      */\r
234     public static byte[] readFile(File file)\r
235     throws IOException\r
236     {\r
237         try (FileInputStream fis = new FileInputStream(file)) {\r
238             long size = file.length();\r
239             if (size>Integer.MAX_VALUE)\r
240                 throw new IOException("File too big");\r
241             int len = (int) size;\r
242             byte data [] = new byte[len];\r
243             int pos = 0;\r
244 \r
245             while (pos<size) {\r
246                 int read = fis.read(data, pos, len-pos);\r
247                 pos += read;\r
248             }\r
249             return data;\r
250         }\r
251     }\r
252 \r
253     /**\r
254      * Creates and writes a binary file\r
255      * @param file file\r
256      * @param data data\r
257      * @throws IOException on i/o problems\r
258      */\r
259     public static void writeFile(File file, byte[] data)\r
260     throws IOException\r
261     {\r
262 //        file.createNewFile();\r
263 //        file.setWritable(true);\r
264         try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {\r
265             raf.setLength(data.length);\r
266             raf.seek(0);\r
267             raf.write(data);\r
268         }\r
269     }\r
270 \r
271 \r
272     /**\r
273      * Fetch the entire contents of the input stream text file, and return it in\r
274      * a String. This style of implementation does not throw Exceptions to the\r
275      * caller.\r
276      * \r
277      * @param stream the stream to completely read in\r
278      */\r
279     public static String getContents(InputStream stream) throws IOException {\r
280         return getContents(stream, Charset.defaultCharset());\r
281     }\r
282 \r
283     /**\r
284      * Fetch the entire contents of the input stream text file, and return it in\r
285      * a String. This style of implementation does not throw Exceptions to the\r
286      * caller.\r
287      * \r
288      * @param stream the stream to completely read in\r
289      */\r
290     public static String getContents(InputStream stream, Charset charset, String lineSeparator) throws IOException {\r
291         StringBuilder contents = new StringBuilder();\r
292         BufferedReader input = null;\r
293         try {\r
294             input = new BufferedReader(new InputStreamReader(stream, charset));\r
295 \r
296             String line = null;\r
297             while ((line = input.readLine()) != null) {\r
298                 contents.append(line);\r
299                 contents.append(lineSeparator);\r
300             }\r
301         } finally {\r
302             try {\r
303                 if (input != null) {\r
304                     // flush and close both "input" and its underlying\r
305                     // FileReader\r
306                     input.close();\r
307                 }\r
308             } catch (IOException ex) {\r
309                 ex.printStackTrace();\r
310             }\r
311         }\r
312         return contents.toString();\r
313     }\r
314 \r
315     public static String getContents(File f) throws IOException {\r
316         return getContents(f, Charset.defaultCharset());\r
317     }\r
318     \r
319     public static String getContents(File f, Charset charset) throws IOException {\r
320         return getContents(new FileInputStream(f), charset);\r
321     }\r
322 \r
323     public static String getContents(InputStream stream, Charset charset) throws IOException {\r
324         return getContents(stream, charset, System.getProperty("line.separator"));\r
325     }\r
326 \r
327     public static String getContents(InputStream stream, String lineSeparator) throws IOException {\r
328         return getContents(stream, Charset.defaultCharset(), lineSeparator);\r
329     }\r
330     \r
331     /**\r
332      * Fetch the entire contents of a text file, and return it in a String. This\r
333      * style of implementation does not throw Exceptions to the caller.\r
334      * \r
335      * @param sourcePath is a file which already exists and can be read.\r
336      */\r
337     public static String getContents(String sourcePath) throws IOException {\r
338         return getContents(sourcePath, Charset.defaultCharset(), System.getProperty("line.separator"));\r
339     }\r
340 \r
341     public static String getContents(String sourcePath, String lineSeparator) throws IOException {\r
342         return getContents(sourcePath, Charset.defaultCharset(), lineSeparator);\r
343     }\r
344 \r
345     public static String getContents(String sourcePath, Charset charset) throws IOException {\r
346         return getContents(sourcePath, charset, System.getProperty("line.separator"));\r
347     }\r
348 \r
349     /**\r
350      * Fetch the entire contents of a text file, and return it in a String. This\r
351      * style of implementation does not throw Exceptions to the caller.\r
352      * \r
353      * @param sourcePath is a file which already exists and can be read.\r
354      */\r
355     public static String getContents(String sourcePath, Charset charset, String lineSeparator) throws IOException {\r
356         FileInputStream input = null;\r
357         try {\r
358             input = new FileInputStream(sourcePath);\r
359             return getContents(input, charset, lineSeparator);\r
360         } finally {\r
361             uncheckedClose(input);\r
362         }\r
363     }\r
364 \r
365     /**\r
366      * Get the contents of a file which is located inside a given bundle.\r
367      * This works regardless of whether the bundle is jarred or not.\r
368      * \r
369      * @param URL the resource to read in\r
370      * @return the contents of the resource\r
371      * @throws IOException if the file is not found or other io errors occur\r
372      */\r
373     public static String getContents(URL url) throws IOException {\r
374         if (url == null)\r
375             throw new IllegalArgumentException("null URL");\r
376         InputStream input = null;\r
377         try {\r
378             input = url.openStream();\r
379             return FileUtils.getContents(input);\r
380         } finally {\r
381             uncheckedClose(input);\r
382         }\r
383     }\r
384 \r
385         /**\r
386          * Read a binary file into a java instance. Binary file is a variant, \r
387          * there is a filetype in the header of the file. \r
388          * If requested binding is not the exact binding of the file, an adapter is tried.\r
389          * \r
390          * @param file file\r
391          * @param binding content binding\r
392          * @return instance\r
393          * @throws IOException \r
394          */\r
395         public static Object readFile(InputStream stream, Binding binding) throws IOException {\r
396                 Binding datatype_binding = Bindings.getBindingUnchecked( Datatype.class );\r
397                 Datatype type = (Datatype) Bindings.getSerializerUnchecked( datatype_binding ).deserialize( stream );\r
398 \r
399                 if (type.equals(binding.type())) {\r
400                         return Bindings.getSerializerUnchecked( binding ).deserialize(stream);\r
401                 } else {\r
402                         try {\r
403                                 Binding fileContentBinding = Bindings.getMutableBinding(type);\r
404                                 Adapter adapter = Bindings.adapterFactory.getAdapter(fileContentBinding, binding, true, false);\r
405                                 Object value = Bindings.getSerializerUnchecked( fileContentBinding ).deserialize(stream);\r
406                                 return adapter.adapt( value );\r
407                         } catch (AdapterConstructionException e) {\r
408                                 throw new IOException(e);\r
409                         } catch (AdaptException e) {\r
410                                 throw new IOException(e);\r
411                         }\r
412                 }\r
413         }\r
414     \r
415     /**\r
416      * Deletes all files and sub-directories from the specified directory. If a\r
417      * file is specified, only that fill will be deleted.\r
418      * \r
419      * @param dir\r
420      * @throws IOException\r
421      */\r
422     public static void deleteAll(File dir) throws IOException {\r
423         if (dir.isFile()) {\r
424             dir.delete();\r
425             return;\r
426         }\r
427 \r
428         if (dir.isDirectory()) {\r
429             File[] fs = dir.listFiles((FileFilter) null);\r
430             if (fs == null)\r
431                 return;\r
432 \r
433             for (File f : fs) {\r
434                 if (f.isDirectory()) {\r
435                     deleteAll(f);\r
436                 } else {\r
437                     if (!f.delete()) {\r
438                         throw new IOException("Could not delete file: " + f.getAbsolutePath());\r
439                     }\r
440                 }\r
441             }\r
442 \r
443             if (!dir.delete()) {\r
444                 throw new IOException("Could not delete directory: " + dir.getAbsolutePath());\r
445             }\r
446         } else if (dir.exists()) {\r
447             if (!dir.delete()) {\r
448                 throw new IOException("Could not delete file: " + dir.getAbsolutePath());\r
449             }\r
450         }\r
451     }\r
452 \r
453     /**\r
454      * Deletes all files and sub-directories from the specified directory. If a\r
455      * file is specified, only that fill will be deleted.\r
456      * \r
457      * If the given directory contains files listed in the filter those files are not deleted\r
458      * \r
459      * @param dir\r
460      *                          directory from where to start the deletion \r
461      * @param filter\r
462      *                          filter containing specific file paths not to delete\r
463      * @throws IOException\r
464      */\r
465     public static void deleteAllWithFilter(File dir, ArrayList<String> filter) throws IOException {\r
466         if (dir.isFile()) {\r
467                 if (!filter.contains(dir.getAbsolutePath())) {\r
468                         dir.delete();\r
469                         return;                         \r
470                 }\r
471         }\r
472 \r
473         if (dir.isDirectory()) {\r
474             File[] fs = dir.listFiles((FileFilter) null);\r
475             if (fs == null)\r
476                 return;\r
477 \r
478             for (File f : fs) {\r
479                 if (f.isDirectory()) {\r
480                     deleteAllWithFilter(f, filter);\r
481                 } else {\r
482                         if (!filter.contains(f.getAbsolutePath())) {\r
483                         if (!f.delete()) {\r
484                             throw new IOException("Could not delete file: " + f.getAbsolutePath());\r
485                         }       \r
486                         }\r
487                 }\r
488             }\r
489             if (!filter.contains(dir.getAbsolutePath())) {\r
490                 if (!dir.delete()) {\r
491                     throw new IOException("Could not delete directory: " + dir.getAbsolutePath());\r
492                 }               \r
493             }\r
494         } else if (dir.exists()) {\r
495                 if (filter.contains(dir.getAbsolutePath())) {\r
496                 if (!dir.delete()) {\r
497                     throw new IOException("Could not delete file: " + dir.getAbsolutePath());\r
498                 }\r
499                 }\r
500         }\r
501     }\r
502     \r
503     public static ArrayList<String> createFileFilter(File dir, ArrayList<String> filter) {\r
504         if (filter == null)\r
505                 filter = new ArrayList<String>();\r
506         if (dir.isFile()) {\r
507                 filter.add(dir.getAbsolutePath());\r
508                 return filter;\r
509         }\r
510         \r
511         if (dir.isDirectory()) {\r
512             File[] fs = dir.listFiles((FileFilter) null);\r
513             if (fs == null)\r
514                 return filter;\r
515 \r
516             for (File f : fs) {\r
517                 if (f.isDirectory()) {\r
518                     createFileFilter(f, filter);\r
519                 } else {\r
520                         filter.add(f.getAbsolutePath());\r
521                 }\r
522             }\r
523             filter.add(dir.getAbsolutePath());\r
524         } else if (dir.exists()) {\r
525                 filter.add(dir.getAbsolutePath());\r
526         }\r
527                 return filter;\r
528     }\r
529 \r
530 \r
531     /**\r
532      * Delete a directory incl. all files and sub-directories by best effort.\r
533      * Does not throw exceptions if deletion fails, simply tries to delete the\r
534      * provided directory to the best of Java File API's abilities.\r
535      * \r
536      * @param dir\r
537      *            directory to delete recursively\r
538      * @boolean <code>true</code> if all files were successfully deleted,\r
539      *          <code>false</code> if some or all failed to be deleted\r
540      */\r
541     public static boolean deleteDir(File dir) {\r
542         if (LOGGER.isDebugEnabled())\r
543             LOGGER.debug("Deleting directory "+dir);\r
544         boolean result = true;\r
545 \r
546         if (!dir.isDirectory()) return false;\r
547         File[] fs = dir.listFiles();\r
548         if (fs != null) {\r
549             for (File f : fs) {\r
550                 if (f.isDirectory()) result &= deleteDir(f);\r
551                 if (f.isFile()) result &= f.delete();\r
552             }\r
553         }\r
554         boolean ok = dir.delete();\r
555 //              if (!ok) dir.deleteOnExit();\r
556         result &= ok;\r
557         return result;\r
558     }\r
559     \r
560     public static String deleteDirs(File dir) { \r
561         if (LOGGER.isDebugEnabled())\r
562             LOGGER.debug("Deleting directory "+dir);\r
563         boolean result = true;\r
564 \r
565         if (!dir.isDirectory()) \r
566                 return dir + " is not a directory!";\r
567         File[] fs = dir.listFiles();\r
568         if (fs != null) {\r
569             for (File f : fs) {\r
570                 //System.out.println("file f :" + f);\r
571                 if (f.isDirectory()) { \r
572                         boolean a = deleteDir(f);\r
573                         result &= a;\r
574                 }\r
575                 if (f.isFile()) {\r
576                         boolean a = f.delete();\r
577                         result &= a;\r
578                 }\r
579                         \r
580             }\r
581         }\r
582         boolean ok = dir.delete();\r
583 //              if (!ok) dir.deleteOnExit();\r
584         result &= ok;\r
585         return "deleteDirs succesful for " + dir + " : " + result;\r
586     }\r
587 \r
588     /**\r
589      * Closes a stream and ignores any resulting exception. This is useful\r
590      * when doing stream cleanup in a finally block where secondary exceptions\r
591      * are not worth logging.\r
592      */\r
593     public static void uncheckedClose(Closeable closeable) {\r
594         try {\r
595             if (closeable != null)\r
596                 closeable.close();\r
597         } catch (IOException e) {\r
598             //ignore\r
599         }\r
600     }\r
601 \r
602     /**\r
603      * Extracts the specified source file in the specified bundle into the\r
604      * specified local directory.\r
605      * \r
606      * @param url the source URL to stream the resource from\r
607      * @param targetFile the target file to write the resource to\r
608      * @param deleteOnExit <code>true</code> to use {@link File#deleteOnExit()}\r
609      *        on the resulting file. Note that this does not guarantee that the\r
610      *        file is deleted when the JVM exits\r
611      * @return the resulting file\r
612      * @throws FileNotFoundException\r
613      */\r
614     public static File copyResource(URL url, File targetFile, boolean deleteOnExit) throws IOException, FileNotFoundException {\r
615         if (url == null)\r
616             throw new IllegalArgumentException("null url");\r
617 \r
618         FileOutputStream os = null;\r
619         InputStream is = null;\r
620         try {\r
621             if (targetFile.exists())\r
622                 targetFile.delete();\r
623 \r
624             is = url.openStream();\r
625             int read;\r
626             byte [] buffer = new byte [16384];\r
627             os = new FileOutputStream (targetFile);\r
628             while ((read = is.read (buffer)) != -1) {\r
629                 os.write(buffer, 0, read);\r
630             }\r
631             os.close ();\r
632             is.close ();\r
633 \r
634             // Request removal of the extracted files on JVM exit.\r
635             if (deleteOnExit)\r
636                 targetFile.deleteOnExit();\r
637             return targetFile;\r
638         } finally {\r
639             FileUtils.uncheckedClose(os);\r
640             FileUtils.uncheckedClose(is);\r
641         }\r
642     }\r
643 \r
644     /**\r
645      * Creates the requested location under the system's temporary directories\r
646      * for temporary data storage.\r
647      * \r
648      * @param pathSegments the path segments that are appended to\r
649      *        java.io.tmpdir. The path segments musn't contain path separators.\r
650      * @return the resulting temporary directory as a File object\r
651      * @throws IOException if anything goes wrong\r
652      */\r
653     public static File getOrCreateTemporaryDirectory(boolean requireEmptyDirectory, String... pathSegments) throws IOException {\r
654         String separator = System.getProperty("file.separator");\r
655         String tempDir = System.getProperty("java.io.tmpdir");\r
656         if (tempDir == null)\r
657             throw new IllegalStateException("'java.io.tmpdir' property is not defined, is the system TMP environment variable defined?");\r
658 \r
659         if (!hasTrailingSeparator(tempDir))\r
660             tempDir = tempDir + separator;\r
661 \r
662         for (int i = 0; i < pathSegments.length-1; ++i) {\r
663             if (containsSeparator(pathSegments[i]))\r
664                 throw new IllegalArgumentException("path segments contain path separators: " + Arrays.toString(pathSegments));\r
665             tempDir = pathSegments[i] + separator;\r
666         }\r
667 \r
668         // Find name for an empty or non-existing temporary directory\r
669         if (pathSegments.length > 0) {\r
670             String lastSegment = pathSegments[pathSegments.length - 1];\r
671             String suffix = "";\r
672             int counter = 0;\r
673             // This loop will not exit until it succeeds or some error occurs.\r
674             while (true) {\r
675                 File temp = new File(tempDir + lastSegment + suffix);\r
676 \r
677                 if (!temp.exists()) {\r
678                     // Found non-existent temporary directory!\r
679                     if (temp.mkdirs()) {\r
680                         // Ok, everything seems to be fine.\r
681                         return temp;\r
682                     }\r
683                     // For some reason the directory could not be created, lets\r
684                     // try another name.\r
685                 } else {\r
686                     // Found an existing temporary file.\r
687                     if (temp.isDirectory() && temp.canWrite()) {\r
688                         if (requireEmptyDirectory) {\r
689                             String[] files = temp.list();\r
690                             if (files != null) {\r
691                                 if (files.length == 0) {\r
692                                     // Ok, the directory is empty and writable.\r
693                                     return temp;\r
694                                 }\r
695                             }\r
696                         } else {\r
697                             return temp;\r
698                         }\r
699                         // Either the directory was empty or it could not be\r
700                         // checked. In any case, don't use the directory.\r
701                     }\r
702                 }\r
703 \r
704                 // Try another directory name if no success with this one.\r
705                 suffix = Integer.toHexString(counter);\r
706                 ++counter;\r
707             }\r
708         }\r
709         return new File(tempDir);\r
710     }\r
711 \r
712     private static boolean containsSeparator(String s) {\r
713         return s.contains("/") || s.contains("\\");\r
714     }\r
715 \r
716     private static boolean hasTrailingSeparator(String s) {\r
717         return s.endsWith("/") || s.endsWith("\\");\r
718     }\r
719 \r
720     /**\r
721      * Very simple compression using ZLib\r
722      * @param input the uncompressed data\r
723      * @return the compressed data\r
724      */\r
725     public static byte[] deflate(byte[] input) {\r
726         // Compress the bytes\r
727         Deflater compresser = new Deflater(Deflater.BEST_COMPRESSION);\r
728         compresser.setInput(input);\r
729         compresser.finish();\r
730 \r
731         int bufferSize = input.length<16 ? 16 : input.length;\r
732         byte buffer[] = new byte[bufferSize];\r
733         int  bufferPos = 0;\r
734         do {\r
735             int compressedDataLength = compresser.deflate(buffer, bufferPos, buffer.length-bufferPos);\r
736             bufferPos += compressedDataLength;\r
737             if (!compresser.finished())\r
738                 buffer = Arrays.copyOf(buffer, buffer.length + bufferSize);\r
739         } while (!compresser.finished());\r
740 \r
741         byte[] result = new byte[bufferPos+4];\r
742         System.arraycopy(buffer, 0, result, 4, bufferPos);\r
743         byte sizeData[] = LEInt.toBytes(input.length);\r
744         System.arraycopy(sizeData, 0, result, 0, 4);\r
745         return result;\r
746     }\r
747 \r
748     /**\r
749      * Very simple decompression using ZLib.\r
750      * @param input the compressed input\r
751      * @return the uncompressed data\r
752      * @throws DataFormatException\r
753      */\r
754     public static byte[] inflate(byte[] input) throws DataFormatException {\r
755         // Decompress the bytes\r
756         int inflatedSize = LEInt.toInt(input);\r
757         Inflater decompresser = new Inflater();\r
758         decompresser.setInput(input, 4, input.length - 4);\r
759         byte[] result = new byte[inflatedSize];\r
760         int resultLength = decompresser.inflate(result);\r
761         assert(resultLength == inflatedSize);\r
762         decompresser.end();\r
763         return result;\r
764     }\r
765 \r
766 \r
767     public static boolean isValidFileName(String name) {\r
768         File f = new File(name) ;\r
769         if (!f.exists()) {\r
770             try {\r
771                 boolean ok = f.createNewFile();\r
772                 if (ok)\r
773                     f.delete();\r
774                 return ok;\r
775             } catch (IOException ioe) {\r
776                 return false;\r
777             }\r
778         }\r
779         return true;\r
780     }\r
781 \r
782     /**\r
783      * Create a temporary directory\r
784      * \r
785      * @return temporary directory\r
786      */\r
787     public static File createTmpDir()\r
788     {\r
789         String tmp = System.getenv("tmp");\r
790         if (tmp==null) tmp = "c:/temp";\r
791         Random r = new Random();\r
792         String randomName = "simantics-tmp-"+(r.nextInt(10000)+10000);\r
793         File tmpDir = new File(tmp+"/"+randomName);\r
794         tmpDir.deleteOnExit();\r
795         Boolean ok = tmpDir.mkdirs();\r
796         if (!ok) throw new RuntimeException("tmp dir "+tmpDir+" was not created");\r
797         return tmpDir;\r
798     }\r
799     \r
800     public static void compressZip(String sourcePath, String zipDir) throws IOException {\r
801         if (LOGGER.isDebugEnabled())\r
802             LOGGER.debug("Compressing file " + sourcePath + " to zip " + zipDir + ".");\r
803 \r
804         File filesource = new File(sourcePath);\r
805         URI base = filesource.toURI();\r
806         Deque<File> queue = new LinkedList<File>();\r
807         queue.push(filesource);\r
808         try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zipDir))) {\r
809                 while (!queue.isEmpty()) {\r
810                         filesource = queue.pop();\r
811                         for (File child : filesource.listFiles()) {\r
812                                 String name = base.relativize(child.toURI()).getPath();\r
813                                 if (child.isDirectory()) {\r
814                                         queue.push(child);\r
815                                         name = name.endsWith("/") ? name : name + "/";\r
816                                         zout.putNextEntry(new ZipEntry(name));\r
817                                 } else {\r
818                                         zout.putNextEntry(new ZipEntry(name));\r
819                                         copy(child, zout);\r
820                                         zout.closeEntry();\r
821                                 }\r
822                         }\r
823                 }\r
824         } finally {\r
825                 LOGGER.debug("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         if (LOGGER.isDebugEnabled())\r
844                 LOGGER.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         byte[] buf = new byte[8192];\r
859         ZipInputStream zis = new ZipInputStream(zipInput);\r
860         ZipEntry entry;\r
861 \r
862         entry = zis.getNextEntry();\r
863         while (entry != null) {\r
864             // for each entry to be extracted\r
865             String name = entry.getName();\r
866             if (LOGGER.isDebugEnabled())\r
867                 LOGGER.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