All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.schlichtherle.io.samples.NZip Maven / Gradle / Ivy

/*
 * Copyright (C) 2007-2010 Schlichtherle IT Services
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.schlichtherle.io.samples;

import de.schlichtherle.io.ArchiveDetector;
import de.schlichtherle.io.DefaultArchiveDetector;
import de.schlichtherle.io.File;
import de.schlichtherle.io.FileInputStream;
import de.schlichtherle.io.archive.tar.TarBZip2Driver;
import de.schlichtherle.io.archive.tar.TarDriver;
import de.schlichtherle.io.archive.tar.TarGZipDriver;
import de.schlichtherle.io.archive.zip.CheckedJarDriver;
import de.schlichtherle.io.archive.zip.CheckedReadOnlySfxDriver;
import de.schlichtherle.io.archive.zip.CheckedZipDriver;
import de.schlichtherle.io.swing.tree.FileTreeModel;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;

/**
 * A comprehensive command line utility which allows you to work
 * with entries in all supported archive files using Unix like commands
 * ({@code cat}, {@code cp}, {@code rm}, {@code mkdir},
 * {@code rmdir}, {@code ls} etc.).
 * 

* Please note that TrueZIP is designed for optimum performance. * However, this utility features some optional archive drivers which * provide additional safety or otherwise unavailable features. * Some of these drivers are not used in their default configuration - * see {@link de.schlichtherle.io.DefaultArchiveDetector} for more * information. * For example, the ZIP drivers used in this utility always check * the CRC-32 values provided in the ZIP file. * In addition, the SFX driver is used which allows you to browse * {@code .exe} files if they happen to be SelF eXtracting archives (SFX). * If they are not however, TrueZIP may spend some considerable amount of * time searching for the Central Directory required to be present in ZIP * (and hence SFX) files. * As a conclusion, this utility should not serve as a performance benchmark. *

* This class is not thread safe. * * @author Christian Schlichtherle * @version $Id: NZip.java,v 1.4 2010/08/20 13:09:44 christian_schlichtherle Exp $ * @since TrueZIP 6.5 */ public class NZip extends CommandLineUtility { private static final String CLASS_NAME = "de.schlichtherle.io.samples.NZip"; private static final ResourceBundle resources = ResourceBundle.getBundle(CLASS_NAME); private final NumberFormat numberFormat = NumberFormat.getNumberInstance(); private final DateFormat dateFormat = DateFormat.getDateTimeInstance(); private final FieldPosition fpos = new FieldPosition(NumberFormat.INTEGER_FIELD); public NZip() { } public NZip(OutputStream out, OutputStream err, boolean autoFlush) { super(out, err, autoFlush); } /** * May be overridden by subclasses to create the {@link ArchiveDetector} * which shall be used as the * {@link File#getDefaultArchiveDetector default archive detector} while * a command is running. * The {@link de.schlichtherle.io.archive.spi.ArchiveDriver}s returned * by the archive detector should use their default charsets. *

* Note that the archive detector which is returned by the implementation * in this class uses some archive drivers which may be pretty slow due to * some extra compatibility tests which they perform on every archive. */ protected DefaultArchiveDetector createDefaultArchiveDetector() { return new DefaultArchiveDetector(ArchiveDetector.ALL, new Object[] { "ear|jar|war", new CheckedJarDriver(), // check CRC-32 "zip", new CheckedZipDriver(), // check CRC-32 "exe", new CheckedReadOnlySfxDriver(), // check CRC-32 }); } /** * May be overridden by subclasses to create the {@link ArchiveDetector} * which returns {@link de.schlichtherle.io.archive.spi.ArchiveDriver}s * which should use the specified charset if supported. * This is used by selected commands in this class. *

* Note that the archive detector which is returned by the implementation * in this class uses some archive drivers which may be pretty slow due to * some extra compatibility tests which they perform on every archive. */ protected DefaultArchiveDetector createDefaultArchiveDetector( final String charset) { assert charset != null; return new DefaultArchiveDetector(ArchiveDetector.ALL, new Object[] { "ear|jar|war|zip", new CheckedZipDriver(charset), // check CRC-32 "exe", new CheckedReadOnlySfxDriver(charset), // check CRC-32 "tar", new TarDriver(charset), "tgz|tar.gz", new TarGZipDriver(charset), "tbz|tar.bz2", new TarBZip2Driver(charset), }); } /** Equivalent to {@code System.exit(new NZip().run(args));}. */ public static void main(final String[] args) { System.exit(new NZip().run(args)); } /** * Runs this command line utility. * Throws an exception if an error occurs. * * @param args A non-empty array of Unix-like commands and optional * parameters. * @return {@code false} iff the command is a test which fails, * {@code true} otherwise. * @throws IllegalUsageException If {@code args} does not contain * correct commands or parameters. * @throws IOException On any I/O related exception. */ public boolean runWithException(String[] args) throws IllegalUsageException, IOException { if (args.length < 1) throw new IllegalUsageException(); final String cmd = args[0].toLowerCase(Locale.ENGLISH); args = lshift(args); final ArchiveDetector oldDetector = File.getDefaultArchiveDetector(); try { // Let this utility recognize all archive types for which an // archive driver is installed. // Note that this may be pretty slow if there are SFX EXE files or // TAR(.GZ|.BZ2) archives to ls. // In addition, for access to RAES encrypted ZIP archives (".tzp", // ".zip.rae", ".zip.raes" suffix) Bouncy Castle's Lightweight // Crypto API for JDK 1.4, version 1.30 or higher needs to be on // the run time class path. // Furthermore, for access to TAR, TAR.GZ and TAR.BZ2 archives, // "ant.jar" from Apache's Ant, version 1.6.5 or higher needs to // be on the run time class path (version 1.7 or higher is // recommended). // Finally, for regular ZIP files we want to check the CRC32 value // when an entry input stream is closed. File.setDefaultArchiveDetector(createDefaultArchiveDetector()); if ("ls".equals(cmd)) { ls(args, false, false); } else if ("ll".equals(cmd)) { ls(args, true, false); } else if ("llr".equals(cmd)) { ls(args, true, true); } else if ("cat".equals(cmd)) { cat(args); } else if ("cp".equals(cmd)) { cpOrMv(args, false); } else if ("mv".equals(cmd)) { cpOrMv(args, true); } else if ("touch".equals(cmd)) { touch(args); } else if ("mkdir".equals(cmd)) { mkdir(args, false); } else if ("mkdirs".equals(cmd)) { mkdir(args, true); } else if ("rm".equals(cmd)) { rm(args, false); } else if ("rmr".equals(cmd)) { rm(args, true); } else if ("isarchive".equals(cmd)) { return isArchive(args); } else if ("isdirectory".equals(cmd)) { return isDirectory(args); } else if ("isfile".equals(cmd)) { return isFile(args); } else if ("exists".equals(cmd)) { return exists(args); } else if ("length".equals(cmd)) { return length(args); } else { throw new IllegalUsageException(); } } finally { File.setDefaultArchiveDetector(oldDetector); } return true; } private static final String[] lshift(final String[] args) { return lshift(args, 1); } private static String[] lshift(final String[] args, final int num) { final int rem = args.length - num; if (rem < 0) throw new IllegalArgumentException(); final String[] ret = new String[rem]; System.arraycopy(args, num, ret, 0, rem); return ret; } private void ls( String[] args, final boolean detailed, final boolean recursive) throws IOException { if (args.length <= 0) args = new String[] { "." }; for (int i = 0; i < args.length; i++) { final File file = new File(args[i]); if (args.length > 1) out.println(args[i] + ":"); if (file.isDirectory()) ls(file, "", detailed, recursive); else ls(file, file.getPath(), detailed, recursive); } } /** * Lists the given file with the given display path. */ private void ls( final java.io.File file, final String path, final boolean detailed, final boolean recursive) throws IOException { if (file.isDirectory()) { final java.io.File[] entries = file.listFiles(); if (entries == null) throw new IOException(path + " (" + resources.getString("ls.dia") + ")"); // Sort directories to the start. Arrays.sort(entries, FileTreeModel.FILE_NAME_COMPARATOR); for (int i = 0; i < entries.length; i++) { final java.io.File entry = entries[i]; final String entryPath = path.length() > 0 ? path + File.separator + entry.getName() : entry.getName(); ls(entry, entryPath, detailed); if (recursive && entry.isDirectory()) ls(entries[i], entryPath, detailed, true); } } else if (file.exists()) { ls(file, path, detailed); } else { throw new IOException(path + " (" + resources.getString("ls.nsfod") + ")"); } } private void ls( final java.io.File file, final String path, final boolean detailed) { StringBuffer buf = new StringBuffer(); if (detailed) { align(buf, file.length(), 11); buf.append(' '); buf.append(dateFormat.format(new Date(file.lastModified()))); buf.append(' '); } buf.append(path); if (detailed) buf.append(file.isDirectory() ? File.separator : (file.isFile() ? "" : "?")); out.println(buf.toString()); } private void align(StringBuffer buf, long number, int spacing) { final int length = buf.length(); numberFormat.format(number, buf, fpos); for (int i = spacing - fpos.getEndIndex(); --i >= 0; ) buf.insert(length, ' '); } private void cat(final String[] args) throws IOException { if (args.length < 1) throw new IllegalUsageException(); for (int i = 0; i < args.length; i++) { final InputStream in = new FileInputStream(args[i]); try { File.cat(in, out); } finally { in.close(); } } } private void cpOrMv(final String[] args, final boolean mv) throws IOException { if (args.length < 2) throw new IllegalUsageException(); int srcI = 0; boolean unzip = false; boolean cp437out = false; boolean utf8out = false; boolean cp437in = false; boolean utf8in = false; int in = 0, out = 0; for (; srcI < args.length && args[srcI].charAt(0) == '-'; srcI++) { if (mv) // mv throw new IllegalUsageException(); final String opt = args[srcI].toLowerCase(Locale.ENGLISH); if ("-unzip".equals(opt)) { unzip = true; out++; } else if ("-cp437out".equals(opt)) { cp437out = true; out++; } else if ("-utf8out".equals(opt)) { utf8out = true; out++; } else if ("-cp437in".equals(opt)) { cp437in = true; in++; } else if ("-utf8in".equals(opt)) { utf8in = true; in++; } else { throw new IllegalUsageException(); } } if (in > 1 || out > 1) throw new IllegalUsageException(); final ArchiveDetector srcDetector; if (cp437in) srcDetector = createDefaultArchiveDetector("IBM437"); else if (utf8in) srcDetector = createDefaultArchiveDetector("UTF-8"); else srcDetector = File.getDefaultArchiveDetector(); final ArchiveDetector dstDetector; if (unzip) dstDetector = ArchiveDetector.NULL; else if (cp437out) dstDetector = createDefaultArchiveDetector("IBM437"); else if (utf8out) dstDetector = createDefaultArchiveDetector("UTF-8"); else dstDetector = File.getDefaultArchiveDetector(); final int dstI = args.length - 1; final File dst = new File(args[dstI], dstDetector); if (dstI - srcI < 1 || (dstI - srcI > 1 && !dst.isArchive() && !dst.isDirectory())) throw new IllegalUsageException(); if (dst.isArchive() || dst.isEntry()) progressMonitor.start(); for (int i = srcI; i < dstI; i++) { final File src = new File(args[i], srcDetector); final File tmp; if (dstI - srcI > 1 || dst.isDirectory()) tmp = new File(dst, src.getName(), dstDetector); else tmp = dst; final boolean ok; if (mv) { if ((tmp.isFile() && !tmp.delete()) || !src.renameTo(tmp)) throw new IOException(src + ": " + resources.getString("cpOrMv.cmt") + ": " + tmp); } else { // cp if (!src.archiveCopyAllTo(tmp, srcDetector, dstDetector)) throw new IOException(src + ": " + resources.getString("cpOrMv.cct") + ": " + tmp + " (" + resources.getString("cpOrMv.co") + ")"); } } } private void touch(final String[] args) throws IOException { if (args.length < 1) throw new IllegalUsageException(); for (int i = 0; i < args.length; i++) { final File file = new File(args[i]); final boolean ok; if (!file.exists()) ok = file.createNewFile(); else ok = file.setLastModified(System.currentTimeMillis()); if (!ok) { final String msg; if (!file.exists()) msg = resources.getString("touch.ccf"); else if (file.isDirectory()) msg = resources.getString("touch.culmtod"); else if (file.isFile()) msg = resources.getString("touch.culmtof"); else msg = resources.getString("touch.culmtosfod"); throw new IOException(file.getPath() + " (" + msg + ")"); } } } private void mkdir(final String[] args, final boolean recursive) throws IOException { if (args.length < 1) throw new IllegalUsageException(); for (int i = 0; i < args.length; i++) { final File file = new File(args[i]); final boolean ok = recursive ? file.mkdirs() : file.mkdir(); if (!ok) { final String msg; if (!file.exists()) msg = resources.getString("mkdir.ccd"); else if (file.isDirectory()) msg = resources.getString("mkdir.dea"); else if (file.isFile()) msg = resources.getString("mkdir.fea"); else msg = resources.getString("mkdir.sfodea"); throw new IOException(file.getPath() + " (" + msg + ")"); } } } private void rm(final String[] args, final boolean recursive) throws IOException { if (args.length < 1) throw new IllegalUsageException(); for (int i = 0; i < args.length; i++) { final File file = new File(args[i]); final boolean ok = recursive ? file.deleteAll() : file.delete(); if (!ok) { final String msg; if (!file.exists()) msg = resources.getString("rm.nsfod"); else if (file.isDirectory()) if (file.list().length > 0) msg = resources.getString("rm.dne"); else msg = resources.getString("rm.crd"); else if (file.isFile()) msg = resources.getString("rm.crf"); else msg = resources.getString("rm.crsfod"); throw new IOException(file.getPath() + " (" + msg + ")"); } } } private boolean isArchive(final String[] args) { if (args.length != 1) throw new IllegalUsageException(); final boolean success = new File(args[0]).isArchive(); out.println(success); return success; } private boolean isDirectory(final String[] args) { if (args.length != 1) throw new IllegalUsageException(); final boolean success = new File(args[0]).isDirectory(); out.println(success); return success; } private boolean isFile(final String[] args) { if (args.length != 1) throw new IllegalUsageException(); final boolean success = new File(args[0]).isFile(); out.println(success); return success; } private boolean exists(final String[] args) { if (args.length != 1) throw new IllegalUsageException(); final boolean success = new File(args[0]).exists(); out.println(success); return success; } private boolean length(final String[] args) { if (args.length != 1) throw new IllegalUsageException(); final long length = new File(args[0]).length(); out.println(length); return true; } public class IllegalUsageException extends CommandLineUtility.IllegalUsageException { private IllegalUsageException() { super(resources.getString("usage")); // use Resource Bundle } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy