/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.command.archive;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.tools.bzip2.CBZip2InputStream;
import org.apache.tools.bzip2.CBZip2OutputStream;
import org.jnode.shell.syntax.Argument;
import org.jnode.shell.syntax.FileArgument;
import org.jnode.shell.syntax.FlagArgument;
/**
* BZip is the backing class for handling compression and decompression
* of bzip files.
*
* @author chris boertien
*/
public class BZip extends ArchiveCommand {
@SuppressWarnings("unused")
private static final boolean DEBUG = false;
private static final String help_compress = "forces compression; regardless of invocation name";
private static final String help_files = "space seperated list of files to compress";
private static final String help_keep = "Keep input files";
private static final String help_small = "(ignored)";
private static final String help_test = "test the file integrity";
private static final String fmt_suffix_bad = "Can't guess original name for %s -- using %s.out";
protected final FlagArgument Compress;
protected final FlagArgument Decompress;
protected final FileArgument Files;
protected final FlagArgument Keep;
protected final FlagArgument Small;
protected final FlagArgument Test;
private List<File> files;
private int rc = 1;
protected int clevel;
protected boolean keep;
protected boolean small;
public BZip(String s) {
super(s);
Compress = new FlagArgument("compress", Argument.OPTIONAL, help_compress);
Decompress = new FlagArgument("decompress", Argument.OPTIONAL, help_decompress);
int flags = Argument.OPTIONAL | Argument.MULTIPLE | Argument.EXISTING | FileArgument.HYPHEN_IS_SPECIAL;
Files = new FileArgument("files", flags, help_files);
Keep = new FlagArgument("keep", Argument.OPTIONAL, help_keep);
Small = new FlagArgument("small", Argument.OPTIONAL, help_small);
Test = new FlagArgument("test", Argument.OPTIONAL, help_test);
createStreamBuffer(4096);
}
public void execute(String command) {
super.execute(command);
parseOptions(command);
try {
if (compress) {
compress();
} else {
decompress();
}
rc = 0;
} catch (IOException e) {
error(err_exception_uncaught);
rc = 1;
} finally {
exit(rc);
}
}
private void compress() throws IOException {
InputStream in = null;
OutputStream out = null;
CBZip2OutputStream bzout = null;
if (use_stdout) {
bzout = new CBZip2OutputStream(stdout, clevel);
}
for (File file : files) {
if (file.getName().equals("-")) {
processStream(stdin, bzout);
continue;
}
try {
if (use_stdout) {
if ((in = openFileRead(file)) == null) {
rc = 1;
continue;
}
processStream(in, bzout);
continue;
}
try {
File bzfile = new File(file.getAbsolutePath() + ".bz2");
if ((out = openFileWrite(bzfile, true, force)) == null) {
rc = 1;
continue;
}
bzout = new CBZip2OutputStream(out, clevel);
if ((in = openFileRead(file)) == null) {
rc = 1;
continue;
}
processStream(in, bzout);
float sizeDiff = ((float) bzfile.length() / (float) file.length()) * 100;
notice(String.format(fmt_size_diff, file, sizeDiff, bzfile));
if (!keep) file.delete();
} finally {
close(bzout);
}
} finally {
close(in);
}
}
// TEST need to see if this is even necessary, and if it is
// should it be within a finally block
if (use_stdout) {
bzout.close();
}
}
private void decompress() throws IOException {
InputStream in = null;
OutputStream out = stdout;
for (File bzfile : files) {
if (bzfile.getName().equals("-")) {
processStream(new CBZip2InputStream(stdin), out);
continue;
}
try {
if (use_stdout) {
if ((in = new CBZip2InputStream(openFileRead(bzfile))) == null) {
rc = 1;
continue;
}
processStream(in, out);
continue;
}
try {
File file = stripSuffix(bzfile);
if ((out = openFileWrite(file, true, force)) == null) {
rc = 1;
continue;
}
if ((in = new CBZip2InputStream(openFileRead(bzfile))) == null) {
rc = 1;
continue;
}
processStream(in, out);
float sizeDiff = ((float) bzfile.length() / (float) file.length()) * 100;
notice(String.format(fmt_size_diff, bzfile, sizeDiff, file));
if (!keep) bzfile.delete();
} finally {
close(out);
}
} finally {
close(in);
}
}
}
@SuppressWarnings("unused")
private void test(File[] files) {
// TODO
// requires patch to apache ant to have CBZip2InputStream fail with an
// exception, instead it just prints to stderr and doesn't tell us if
// it failed.
//
// Otherwise we would have to read and compute the crc ourself.
}
/**
* Strips .bz and .bz2 suffixes from the file. Will also replace
* .tbz and .tbz2 files with .tar suffix. If the suffix doesn't match
* any of these, the suffix .out will be appended to the file name
*/
private File stripSuffix(File bzfile) {
String name = bzfile.getName();
int len = 0;
String newSuffix = null;
if (name.endsWith(".bz")) {
len = 3;
} else if (name.endsWith(".bz2")) {
len = 4;
} else if (name.endsWith(".tbz")) {
len = 4;
newSuffix = ".tar";
} else if (name.endsWith(".tbz2")) {
len = 5;
newSuffix = ".tar";
} else {
notice(String.format(fmt_suffix_bad, bzfile.getPath(), bzfile.getPath()));
return new File(bzfile.getPath() + ".out");
}
if (len > 0) {
name = name.substring(0, name.length() - len);
}
if (newSuffix != null) {
name = name + newSuffix;
}
return new File(name);
}
private void parseOptions(String command) {
small = Small.isSet();
if (!command.equals("bzcat")) {
if (compress && Decompress.isSet()) {
compress = false;
}
if (!compress && Compress.isSet()) {
compress = true;
}
keep = use_stdout || Keep.isSet();
}
files = new ArrayList<File>();
for (File file : Files.getValues()) {
if (file.isDirectory()) {
for (File f : file.listFiles()) {
if (!f.isDirectory()) {
files.add(f);
}
}
} else {
if (file.getName().equals("-")) {
use_stdout = true;
}
files.add(file);
}
}
if (files.size() == 0) {
files.add(new File("-"));
use_stdout = true;
}
}
}