001 /*
002 * This file is part of muCommander, http://www.mucommander.com
003 * Copyright (C) 2002-2008 Maxence Bernard
004 *
005 * muCommander is free software; you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation; either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * muCommander is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program. If not, see <http://www.gnu.org/licenses/>.
017 */
018
019 package com.mucommander.file.impl.bzip2;
020
021 import com.mucommander.file.AbstractFile;
022 import com.mucommander.file.AbstractROArchiveFile;
023 import com.mucommander.file.ArchiveEntry;
024 import org.apache.tools.bzip2.CBZip2InputStream;
025
026 import java.io.BufferedInputStream;
027 import java.io.IOException;
028 import java.io.InputStream;
029 import java.util.Vector;
030
031 /**
032 * Bzip2ArchiveFile provides read-only access to archives in the Bzip2 format.
033 *
034 * <p>The actual decompression work is performed by the <code>Apache Ant</code> library under the terms of the
035 * Apache Software License.</p>
036 *
037 * @see com.mucommander.file.impl.bzip2.Bzip2FormatProvider
038 * @author Maxence Bernard
039 */
040 public class Bzip2ArchiveFile extends AbstractROArchiveFile {
041
042 /**
043 * Creates a BzipArchiveFile on top of the given file.
044 */
045 public Bzip2ArchiveFile(AbstractFile file) {
046 super(file);
047 }
048
049
050 ////////////////////////////////////////
051 // AbstractArchiveFile implementation //
052 ////////////////////////////////////////
053
054 public Vector getEntries() throws IOException {
055 String extension = getExtension();
056 String name = getName();
057
058 if(extension!=null) {
059 extension = extension.toLowerCase();
060
061 // Remove the 'bz2' or 'tbz2' extension from the entry's name
062 if(extension.equals("tbz2"))
063 name = name.substring(0, name.length()-4)+"tar";
064 else if(extension.equals("bz2"))
065 name = name.substring(0, name.length()-4);
066 }
067
068 Vector entries = new Vector();
069 entries.add(new ArchiveEntry("/"+name, false, getDate(), -1));
070 return entries;
071 }
072
073
074 public InputStream getEntryInputStream(ArchiveEntry entry) throws IOException {
075 try {
076 InputStream in = getInputStream();
077
078 // Skips the 2 magic bytes 'BZ', as required by CBZip2InputStream. Quoted from CBZip2InputStream's Javadoc:
079 // "Although BZip2 headers are marked with the magic 'Bz'. this constructor expects the next byte in the
080 // stream to be the first one after the magic. Thus callers have to skip the first two bytes. Otherwise
081 // this constructor will throw an exception."
082 // Note: the return value of read() is unchecked. In the unlikely event that EOF is reached in the first
083 // 2 bytes, CBZip2InputStream will throw an IOException.
084 in.read();
085 in.read();
086
087 // Quoted from CBZip2InputStream's Javadoc:
088 // "CBZip2InputStream reads bytes from the compressed source stream via the single byte {@link java.io.InputStream#read()
089 // read()} method exclusively. Thus you should consider to use a buffered source stream."
090 return new CBZip2InputStream(new BufferedInputStream(in));
091 }
092 catch(Exception e) {
093 // CBZip2InputStream is known to throw NullPointerException if file is not properly Bzip2-encoded
094 // so we need to catch those and throw them as IOException
095 if(com.mucommander.Debug.ON) com.mucommander.Debug.trace("Exception caught while creating CBZip2InputStream:"+e+", throwing IOException");
096
097 throw new IOException();
098 }
099 }
100 }