/* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.install; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class Util { /** * @see Util#copyDirectory(ProgressMonitor, File, File, String) */ public static final boolean copyDirectory(File source, File target) { return copyDirectory(null, source, target, null); } /** * @see Util#copyDirectory(ProgressMonitor, File, File, String) */ public static final boolean copyDirectory(ProgressMonitor progress, File source, File target) { return copyDirectory(progress, source, target, null); } /** * @see Util#copyDirectory(ProgressMonitor, File, File, String) */ public static final boolean copyDirectory(File source, File target, String saveSuffix) { return copyDirectory(null, source, target, saveSuffix); } /** * Copy files under the <i>source</i> directory to the <i>target</i> * directory. If necessary, <i>target</i> directory is created.<br> * <br> * For example, if this method is called with a <i>source</i> of * <tt>/foo</tt> (which contains <tt>/foo/a</tt> and <tt>/foo/b</tt>) * and a <i>target</i> of <tt>/bar</tt>, when this method exits * <tt>/bar</tt> will contain <tt>/bar/a</tt> and <tt>/bar/b</tt>. * Note that <tt>foo</tt> itself is not copied. * * @param progress if non-null, this progress monitor is updated * with the name of each file as it is copied. * @param source source directory * @param target directory * @param saveSuffix if non-null, pre-existing files under <i>target</i> * whose paths match files to be copied from * <i>source</i> will be renamed to * <tt>name + saveSuffix</tt>. * * @return false if any problems were encountered. */ public static final boolean copyDirectory(ProgressMonitor progress, File source, File target, String saveSuffix) { // source must be a directory if (!source.isDirectory() || (target.exists() && !target.isDirectory())) { return false; } // if source and target are the same, we're done if (getPath(source).equals(getPath(target))) { return false; } // if the target doesn't exist yet, create it if (!target.exists()) { target.mkdirs(); } boolean result = true; String[] list = source.list(); for (int i = 0; i < list.length; i++) { File srcFile = new File(source, list[i]); File tgtFile = new File(target, list[i]); if (srcFile.isDirectory()) { result |= copyDirectory(progress, srcFile, tgtFile, saveSuffix); } else { result |= copyFile(progress, srcFile, tgtFile, saveSuffix); } } // if source was read-only, the target should be as well if (!source.canWrite()) { target.setReadOnly(); } // sync up last-modified time target.setLastModified(source.lastModified()); return result; } /** * @see Util#copyFile(ProgressMonitor, File, File, String) */ public static final boolean copyFile(File source, File target) { return copyFile(null, source, target, null); } /** * @see Util#copyFile(ProgressMonitor, File, File, String) */ public static final boolean copyFile(ProgressMonitor progress, File source, File target) { return copyFile(progress, source, target, null); } /** * @see Util#copyFile(ProgressMonitor, File, File, String) */ public static final boolean copyFile(File source, File target, String saveSuffix) { return copyFile(null, source, target, saveSuffix); } /** * Copy the <i>source</i> file to <i>target</i>. If <i>target</i> * does not exist, it is assumed to be the name of the copied file. * If <i>target</i> is a directory, the file will be copied * into that directory. * * @param progress if non-null, this progress monitor is updated * with the name of each file as it is copied. * @param source source directory * @param target target file/directory * @param saveSuffix if non-null and <i>target</i> exists, * <i>target</i> will be renamed to * <tt>name + saveSuffix</tt>. * * @return false if any problems were encountered. */ public static final boolean copyFile(ProgressMonitor progress, File source, File target, String saveSuffix) { // don't copy directories if (source.isDirectory()) { return false; } // if source and target are the same, we're done if (getPath(source).equals(getPath(target))) { return false; } if (target.isDirectory()) { target = new File(target, source.getName()); } FileInputStream in; try { in = new FileInputStream(source); } catch (IOException ioe) { System.err.println("Couldn't open source file " + source); return false; } copyStreamToFile(progress, in, target, saveSuffix); try { in.close(); } catch (Exception e) { ; } // if source was read-only, the target should be as well if (!source.canWrite()) { target.setReadOnly(); } // sync up last-modified time target.setLastModified(source.lastModified()); return true; } /** * @see Util#copyJar(ProgressMonitor, File, File, String) */ public static final boolean copyJar(File source, File target) { return copyJar(null, source, target, null); } /** * @see Util#copyJar(ProgressMonitor, File, File, String) */ public static final boolean copyJar(ProgressMonitor progress, File source, File target) { return copyJar(progress, source, target, null); } /** * @see Util#copyJar(ProgressMonitor, File, File, String) */ public static final boolean copyJar(File source, File target, String saveSuffix) { return copyJar(null, source, target, saveSuffix); } /** * Extract files from the <i>source</i> jar file to the <i>target</i> * directory. If necessary, the <i>target</i> directory is created.<br> * <br> * For example, if this method is called with a <i>source</i> of * <tt>foo.jar</tt> (which contains <tt>a</tt> and <tt>b</tt>) * and a <i>target</i> of <tt>/bar</tt>, when this method exits * <tt>/bar</tt> will contain <tt>/bar/a</tt> and <tt>/bar/b</tt>. * * @param progress if non-null, this progress monitor is updated * with the name of each file as it is copied. * @param source source jar file * @param target directory * @param saveSuffix if non-null, pre-existing files in <i>target</i> * whose paths match files to be copied from * <i>source</i> will be renamed to * <tt>name + saveSuffix</tt>. * * @return false if any problems were encountered. */ public static final boolean copyJar(ProgressMonitor progress, File source, File target, String saveSuffix) { // if target exists, it must be a directory if (target.exists() && !target.isDirectory()) { return false; } // if the target doesn't exist yet, create it if (!target.exists()) { target.mkdirs(); } // try to open the jar file JarFile jar; try { jar = new JarFile(source); } catch (IOException ioe) { return false; } boolean result = true; Enumeration en = jar.entries(); while (en.hasMoreElements()) { JarEntry entry = (JarEntry )en.nextElement(); final String entryName = entry.getName(); // skip manifest files if (JarFile.MANIFEST_NAME.startsWith(entryName)) { continue; } File newFile = new File(target, entryName); newFile.mkdirs(); if (!entry.isDirectory()) { InputStream in; try { in = jar.getInputStream(entry); } catch (IOException ioe) { System.err.println("Couldn't copy entry " + entryName); continue; } copyStreamToFile(progress, in, newFile, saveSuffix); try { in.close(); } catch (Exception e) { ; } } newFile.setLastModified(entry.getTime()); } return result; } private static final boolean copyStreamToFile(ProgressMonitor progress, InputStream in, File target, String saveSuffix) { // if the target already exists and we need to save the existing file... if (target.exists()) { if (saveSuffix == null) { if (progress != null) { progress.setDetail("Deleting existing " + target); } // out with the old... target.delete(); } else { if (progress != null) { progress.setDetail("Backing up existing " + target); } File saveFile = new File(target.getPath() + saveSuffix); // delete the old savefile if (saveFile.exists()) { saveFile.delete(); } // save the existing target file target.renameTo(saveFile); } } if (progress != null) { progress.setDetail("Installing " + target); } FileOutputStream out; try { out = new FileOutputStream(target); } catch (IOException ioe) { System.err.println("Couldn't open output file " + target); return false; } byte buffer[] = new byte[1024]; try { while (true) { int n = in.read(buffer); if (n < 0) { break; } out.write(buffer, 0, n); } } catch (IOException ioe) { ioe.printStackTrace(); return false; } finally { try { out.close(); } catch (Exception e) { ; } } return true; } /** * @return either the canonical path or, if that is not * available, the absolute path. */ public static final String getPath(File f) { try { return f.getCanonicalPath(); } catch (IOException ioe) { return f.getAbsolutePath(); } } }