001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.commons.compress.compressors;
020    
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.io.OutputStream;
024    
025    import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
026    import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
027    import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
028    import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
029    
030    /**
031     * <p>Factory to create Compressor[In|Out]putStreams from names. To add other
032     * implementations you should extend CompressorStreamFactory and override the
033     * appropriate methods (and call their implementation from super of course).</p>
034     * 
035     * Example (Compressing a file):
036     * 
037     * <pre>
038     * final OutputStream out = new FileOutputStream(output); 
039     * CompressorOutputStream cos = 
040     *      new CompressorStreamFactory().createCompressorOutputStream(CompressorStreamFactory.BZIP2, out);
041     * IOUtils.copy(new FileInputStream(input), cos);
042     * cos.close();
043     * </pre>    
044     * 
045     * Example (Compressing a file):
046     * <pre>
047     * final InputStream is = new FileInputStream(input); 
048     * CompressorInputStream in = 
049     *      new CompressorStreamFactory().createCompressorInputStream(CompressorStreamFactory.BZIP2, is);
050     * IOUtils.copy(in, new FileOutputStream(output));
051     * in.close();
052     * </pre>
053     * 
054     * @Immutable
055     */
056    public class CompressorStreamFactory {
057    
058        /**
059         * Constant used to identify the BZIP2 compression algorithm.
060         * @since Commons Compress 1.1
061         */
062        public static final String BZIP2 = "bzip2";
063        /**
064         * Constant used to identify the GZIP compression algorithm.
065         * @since Commons Compress 1.1
066         */
067        public static final String GZIP = "gz";
068    
069        /**
070         * Create an compressor input stream from an input stream, autodetecting
071         * the compressor type from the first few bytes of the stream. The InputStream
072         * must support marks, like BufferedInputStream.
073         * 
074         * @param in the input stream
075         * @return the compressor input stream
076         * @throws CompressorException if the compressor name is not known
077         * @throws IllegalArgumentException if the stream is null or does not support mark
078         * @since Commons Compress 1.1
079         */
080        public CompressorInputStream createCompressorInputStream(final InputStream in)
081                throws CompressorException {
082            if (in == null) {
083                throw new IllegalArgumentException("Stream must not be null.");
084            }
085    
086            if (!in.markSupported()) {
087                throw new IllegalArgumentException("Mark is not supported.");
088            }
089    
090            final byte[] signature = new byte[12];
091            in.mark(signature.length);
092            try {
093                int signatureLength = in.read(signature);
094                in.reset();
095                
096                if (BZip2CompressorInputStream.matches(signature, signatureLength)) {
097                    return new BZip2CompressorInputStream(in);
098                }
099                
100                if (GzipCompressorInputStream.matches(signature, signatureLength)) {
101                    return new GzipCompressorInputStream(in);
102                }
103    
104            } catch (IOException e) {
105                throw new CompressorException("Failed to detect Compressor from InputStream.", e);
106            }
107    
108            throw new CompressorException("No Compressor found for the stream signature.");
109        }
110        
111        /**
112         * Create a compressor input stream from a compressor name and an input stream.
113         * 
114         * @param name of the compressor, i.e. "gz" or "bzip2"
115         * @param in the input stream
116         * @return compressor input stream
117         * @throws CompressorException if the compressor name is not known
118         * @throws IllegalArgumentException if the name or input stream is null
119         */
120        public CompressorInputStream createCompressorInputStream(final String name,
121                final InputStream in) throws CompressorException {
122            if (name == null || in == null) {
123                throw new IllegalArgumentException(
124                        "Compressor name and stream must not be null.");
125            }
126    
127            try {
128                
129                if (GZIP.equalsIgnoreCase(name)) {
130                    return new GzipCompressorInputStream(in);
131                }
132                
133                if (BZIP2.equalsIgnoreCase(name)) {
134                    return new BZip2CompressorInputStream(in);
135                }
136                
137            } catch (IOException e) {
138                throw new CompressorException(
139                        "Could not create CompressorInputStream.", e);
140            }
141            throw new CompressorException("Compressor: " + name + " not found.");
142        }
143    
144        /**
145         * Create an compressor output stream from an compressor name and an input stream.
146         * 
147         * @param name the compressor name, i.e. "gz" or "bzip2"
148         * @param out the output stream
149         * @return the compressor output stream
150         * @throws CompressorException if the archiver name is not known
151         * @throws IllegalArgumentException if the archiver name or stream is null
152         */
153        public CompressorOutputStream createCompressorOutputStream(
154                final String name, final OutputStream out)
155                throws CompressorException {
156            if (name == null || out == null) {
157                throw new IllegalArgumentException(
158                        "Compressor name and stream must not be null.");
159            }
160    
161            try {
162    
163                if (GZIP.equalsIgnoreCase(name)) {
164                    return new GzipCompressorOutputStream(out);
165                }
166                
167                if (BZIP2.equalsIgnoreCase(name)) {
168                    return new BZip2CompressorOutputStream(out);
169                }
170            
171            } catch (IOException e) {
172                throw new CompressorException(
173                        "Could not create CompressorOutputStream", e);
174            }
175            throw new CompressorException("Compressor: " + name + " not found.");
176        }
177    }