package org.korsakow.ide.util; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.swing.filechooser.FileFilter; import org.korsakow.ide.io.AsyncStreamPipe; import org.korsakow.services.encoders.image.ImageFormat; import org.korsakow.services.encoders.sound.SoundFormat; import org.korsakow.services.encoders.video.VideoCodec; public class FileUtil { public static final String LINE_SEPARATOR = System.getProperty("line.separator"); public static final Pattern VIDEO_FILE_EXTENSION_PATTERN = Pattern.compile(ResourceBundle.getBundle("MyResources").getString("video_pattern"), Pattern.CASE_INSENSITIVE); public static final Pattern SOUND_FILE_EXTENSION_PATTERN = Pattern.compile(ResourceBundle.getBundle("MyResources").getString("sound_pattern"), Pattern.CASE_INSENSITIVE); public static final Pattern IMAGE_FILE_EXTENSION_PATTERN = Pattern.compile(ResourceBundle.getBundle("MyResources").getString("image_pattern"), Pattern.CASE_INSENSITIVE); public static final Pattern TEXT_FILE_EXTENSION_PATTERN = Pattern.compile(ResourceBundle.getBundle("MyResources").getString("text_pattern"), Pattern.CASE_INSENSITIVE); // public static final String[] VIDEO_FILE_EXTENSIONS = { // "flv", "f4v", "mp4", "m4a", "mpg", "mov", "mp4v", "m4v", "3gp", "3g2", "avi", // }; // public static final String[] SOUND_FILE_EXTENSIONS = { // "wav", // "mp3", // }; // public static final String[] IMAGE_FILE_EXTENSIONS = { // "jpg", "jpeg", "png", "bmp", "gif", // }; // public static final String[] TEXT_FILE_EXTENSIONS = { // "txt", // }; public static final FileFilter VIDEO_FILE_CHOOSER_FILTER = new FileFilter() { @Override public boolean accept(File file) { return VIDEO_FILE_EXTENSION_PATTERN.matcher(file.getName()).matches(); } @Override public String getDescription() { return "Videos"; } }; public static final FileFilter SOUND_FILE_CHOOSER_FILTER = new FileFilter() { @Override public boolean accept(File file) { return SOUND_FILE_EXTENSION_PATTERN.matcher(file.getName()).matches(); } @Override public String getDescription() { return "Sound"; } }; public static final FileFilter TEXT_FILE_CHOOSER_FILTER = new FileFilter() { @Override public boolean accept(File file) { return TEXT_FILE_EXTENSION_PATTERN.matcher(file.getName()).matches(); } @Override public String getDescription() { return "Text"; } }; public static boolean isMediaFile(String filename) { return isVideoFile(filename) || isSoundFile(filename) || isImageFile(filename) || isTextFile(filename); } public static boolean isVideoFile(String filename) { return VIDEO_FILE_EXTENSION_PATTERN.matcher(filename).matches(); } public static boolean isSoundFile(String filename) { return SOUND_FILE_EXTENSION_PATTERN.matcher(filename).matches(); } public static boolean isImageFile(String filename) { return IMAGE_FILE_EXTENSION_PATTERN.matcher(filename).matches(); } public static boolean isTextFile(String filename) { return TEXT_FILE_EXTENSION_PATTERN.matcher(filename).matches(); } public static String getFileExtension(SoundFormat format) { return format.name().toLowerCase(); } public static String getFileExtension(ImageFormat format) { return format.name().toLowerCase(); } public static String getFileExtension(VideoCodec format) { return format.name().toLowerCase(); } public static String setFileExtension(String filename, String ext) { return getFilenameWithoutExtension(filename) + "." + ext; } public static String getFileExtension(String filename) { int index = filename.lastIndexOf('.'); if (index == -1) return ""; return filename.substring(index+1); } // TODO: rename this to stripExtension since it leaves any leading path info intact public static String getFilenameWithoutExtension(String filename) { String ext = getFileExtension(filename); if (ext.length() == 0) return filename; int index = filename.lastIndexOf(ext); if (index == -1) return filename; int lastSeparator = 0; // TODO: uncomment this section // lastSeparator = filename.lastIndexOf(File.separatorChar); // if (lastSeparator == -1) // lastSeparator = 0; // else // lastSeparator += 1; return filename.substring(lastSeparator, index-1); // -1 for "." } public static boolean isProbablyADirectory( File file ) { return isProbablyADirectory(file.getPath()); } public static boolean isProbablyADirectory( String path ) { File file = new File( path ); if (file.isDirectory()) return true; if (file.isFile()) return false; return !file.getName().contains("."); } public static void copyFile(String sourceFile, String destFile) throws IOException { copyFile(new File(sourceFile), new File(destFile)); } public static void copyFile(File sourceFile, File destFile) throws IOException { if (destFile.getParentFile()!=null) destFile.getParentFile().mkdirs(); FileInputStream input = null; FileOutputStream output = null; try { input = new FileInputStream(sourceFile); output = new FileOutputStream(destFile); long offset = 0; long length = sourceFile.length(); long count = length; final FileChannel destChannel = output.getChannel(); final FileChannel srcChannel = input.getChannel(); do { long written = destChannel.transferFrom(srcChannel, offset, count); count -= written; offset += written; } while (count > 0); } finally { if (input != null) try { input.close(); } catch (IOException e) {} if (output != null) try { output.close(); } catch (IOException e) {} } } public static void copyTree(File dir, File dest) throws IOException { if (!dir.isDirectory()) { copyFile(dir, dest); return; } for (File child : dir.listFiles()) { copyTree(child, new File(dest, child.getName())); } } public static void setExecutable(File file, boolean executable) throws IOException { Process p; switch (Platform.getOS()) { case MAC: case NIX: p = Runtime.getRuntime().exec(new String[] { "chmod", "u"+(executable?'+':'-')+"x", file.getAbsolutePath(), }); try { AsyncStreamPipe<InputStream, ByteArrayOutputStream> errPipe = new AsyncStreamPipe<InputStream, ByteArrayOutputStream>(p.getErrorStream(), new ByteArrayOutputStream()); int exitcode = p.waitFor(); errPipe.join(); if (exitcode != 0) throw new IOException(errPipe.getOutputStream().toString()); } catch (InterruptedException e) { throw new IOException(e.getMessage()); } p.destroy(); break; case WIN: break; } } public static File createTempDirectory(String prefix, String suffix) throws IOException { return createTempDirectory(prefix, suffix, null); } public static File createTempDirectory(String prefix, String suffix, File directory) throws IOException { File file = File.createTempFile(prefix, suffix, directory); // technically this leaves a small window during which the file may be taken by some other process... delete(file); mkdirs(file); return file; } /** * Delete may fail... yet do we care so long as the file does not exist? * This method throws if delete fails AND the file still exists * @param file * @throws IOException */ public static void delete(File file) throws IOException { if (!file.delete()) if (file.exists()) throw new IOException("could not delete file"); } /** * Its unclear if File.mkdirs will return false if the directory could not be created but actually already exists. * This method calls mkdirs and throws if at the end the dirs dont exist. * @param file * @throws IOException */ public static void mkdirs(File file) throws IOException { if (!file.mkdirs()) if (!file.isDirectory()) throw new IOException("could not make dirs: " + file.getPath()); } public static String readFileAsString(String filename) throws IOException { return readFileAsString(new File(filename)); } public static String readFileAsString(File file) throws IOException { byte[] buffer = new byte[(int)file.length()]; DataInputStream reader = new DataInputStream(new FileInputStream(file)); try { reader.readFully(buffer); return new String(buffer, "UTF-8"); } finally { try { reader.close(); } catch (IOException e) {} } } public static List<String> readFileLines(File file) throws IOException { List<String> lines = new ArrayList<String>(); BufferedReader reader = new BufferedReader(new FileReader(file)); String line; try { while ((line=reader.readLine()) != null) lines.add(line); } finally { try { reader.close(); } catch (IOException e) {} } return lines; } public static void writeFileFromString(String filename, String content) throws IOException { File file = new File(filename); writeFileFromString(file, content); } public static void writeFileFromString(File file, String content) throws IOException { File parent = file.getParentFile(); if (parent != null) parent.mkdirs(); BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(file), "UTF-8") ); try { writer.write(content); writer.flush(); } finally { try { writer.close(); } catch (IOException e) {} } } /** * Fully writes one stream to another * @param input * @param output */ public static void writeStreamFully(InputStream input, OutputStream output) throws IOException { try { byte[] buffer = new byte[1024]; int len; while ((len = input.read(buffer)) != -1) { output.write(buffer, 0, len); } output.flush(); } finally { try { output.close(); } catch (IOException e) {} } } public static byte[] readBytesFully(InputStream input) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(input.available()); writeStreamFully(input, baos); return baos.toByteArray(); } public static String readString(InputStream input) throws IOException { return new String(readBytesFully(input), "UTF-8"); } public static void unzip(ZipInputStream zip, File parentDir) throws IOException { try { ZipEntry entry = null; while ((entry = zip.getNextEntry()) != null) { File entryFile = new File(parentDir, entry.getName()); if (entry.isDirectory()) { entryFile.mkdirs(); } else { FileOutputStream outputStream = new FileOutputStream(entryFile); FileUtil.writeStreamFully(zip, outputStream); } zip.closeEntry(); } } finally { try { zip.close(); } catch (IOException e) {} } } public static int executeProcess(Process process, OutputStream outBuff, OutputStream errBuff) throws InterruptedException { AsyncStreamPipe<InputStream, OutputStream> errPiper = new AsyncStreamPipe<InputStream, OutputStream>(process.getErrorStream(), errBuff); AsyncStreamPipe<InputStream, OutputStream> outPiper = new AsyncStreamPipe<InputStream, OutputStream>(process.getInputStream(), outBuff); errPiper.start(); outPiper.start(); // we avoid thread(process) issues by basically not doing anything until all pipers have joined. try { // it is essential that we capture stdout because sometimes if you don't, Process.waitFor won't ever return! // at least this has been observed on windows final int exitCode = process.waitFor(); // we join&destroy here as well as in finally so that if one of them throws legitimately it can propagate and we won't swallow an exception errPiper.join(); outPiper.join(); process.destroy(); return exitCode; } finally { try { process.destroy(); } catch (Throwable t) {} // this should be first to ensure the joins don't block (e.g if we are here from an InterruptedException) try { errPiper.join(); } catch (Throwable t) {} try { outPiper.join(); } catch (Throwable t) {} try { if (!System.err.equals(outBuff) && !System.out.equals(outBuff)) outBuff.close(); } catch (Throwable t) {} try { if (!System.err.equals(errBuff) && !System.out.equals(errBuff)) errBuff.close(); } catch (Throwable t) {} } } }