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    import org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream;
030    import org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream;
031    
032    /**
033     * <p>Factory to create Compressor[In|Out]putStreams from names. To add other
034     * implementations you should extend CompressorStreamFactory and override the
035     * appropriate methods (and call their implementation from super of course).</p>
036     * 
037     * Example (Compressing a file):
038     * 
039     * <pre>
040     * final OutputStream out = new FileOutputStream(output); 
041     * CompressorOutputStream cos = 
042     *      new CompressorStreamFactory().createCompressorOutputStream(CompressorStreamFactory.BZIP2, out);
043     * IOUtils.copy(new FileInputStream(input), cos);
044     * cos.close();
045     * </pre>
046     * 
047     * Example (Compressing a file):
048     * <pre>
049     * final InputStream is = new FileInputStream(input); 
050     * CompressorInputStream in = 
051     *      new CompressorStreamFactory().createCompressorInputStream(CompressorStreamFactory.BZIP2, is);
052     * IOUtils.copy(in, new FileOutputStream(output));
053     * in.close();
054     * </pre>
055     * 
056     * @Immutable
057     */
058    public class CompressorStreamFactory {
059    
060        /**
061         * Constant used to identify the BZIP2 compression algorithm.
062         * @since Commons Compress 1.1
063         */
064        public static final String BZIP2 = "bzip2";
065        /**
066         * Constant used to identify the GZIP compression algorithm.
067         * @since Commons Compress 1.1
068         */
069        public static final String GZIP = "gz";
070        /**
071         * Constant used to identify the PACK200 compression algorithm.
072         * @since Commons Compress 1.3
073         */
074        public static final String PACK200 = "pack200";
075    
076        /**
077         * Create an compressor input stream from an input stream, autodetecting
078         * the compressor type from the first few bytes of the stream. The InputStream
079         * must support marks, like BufferedInputStream.
080         * 
081         * @param in the input stream
082         * @return the compressor input stream
083         * @throws CompressorException if the compressor name is not known
084         * @throws IllegalArgumentException if the stream is null or does not support mark
085         * @since Commons Compress 1.1
086         */
087        public CompressorInputStream createCompressorInputStream(final InputStream in)
088                throws CompressorException {
089            if (in == null) {
090                throw new IllegalArgumentException("Stream must not be null.");
091            }
092    
093            if (!in.markSupported()) {
094                throw new IllegalArgumentException("Mark is not supported.");
095            }
096    
097            final byte[] signature = new byte[12];
098            in.mark(signature.length);
099            try {
100                int signatureLength = in.read(signature);
101                in.reset();
102    
103                if (BZip2CompressorInputStream.matches(signature, signatureLength)) {
104                    return new BZip2CompressorInputStream(in);
105                }
106    
107                if (GzipCompressorInputStream.matches(signature, signatureLength)) {
108                    return new GzipCompressorInputStream(in);
109                }
110    
111                if (Pack200CompressorInputStream.matches(signature, signatureLength)) {
112                    return new Pack200CompressorInputStream(in);
113                }
114    
115            } catch (IOException e) {
116                throw new CompressorException("Failed to detect Compressor from InputStream.", e);
117            }
118    
119            throw new CompressorException("No Compressor found for the stream signature.");
120        }
121    
122        /**
123         * Create a compressor input stream from a compressor name and an input stream.
124         * 
125         * @param name of the compressor, i.e. "gz", "bzip2" or "pack200"
126         * @param in the input stream
127         * @return compressor input stream
128         * @throws CompressorException if the compressor name is not known
129         * @throws IllegalArgumentException if the name or input stream is null
130         */
131        public CompressorInputStream createCompressorInputStream(final String name,
132                final InputStream in) throws CompressorException {
133            if (name == null || in == null) {
134                throw new IllegalArgumentException(
135                        "Compressor name and stream must not be null.");
136            }
137    
138            try {
139    
140                if (GZIP.equalsIgnoreCase(name)) {
141                    return new GzipCompressorInputStream(in);
142                }
143    
144                if (BZIP2.equalsIgnoreCase(name)) {
145                    return new BZip2CompressorInputStream(in);
146                }
147    
148                if (PACK200.equalsIgnoreCase(name)) {
149                    return new Pack200CompressorInputStream(in);
150                }
151    
152            } catch (IOException e) {
153                throw new CompressorException(
154                        "Could not create CompressorInputStream.", e);
155            }
156            throw new CompressorException("Compressor: " + name + " not found.");
157        }
158    
159        /**
160         * Create an compressor output stream from an compressor name and an input stream.
161         * 
162         * @param name the compressor name, i.e. "gz", "bzip2" or "pack200"
163         * @param out the output stream
164         * @return the compressor output stream
165         * @throws CompressorException if the archiver name is not known
166         * @throws IllegalArgumentException if the archiver name or stream is null
167         */
168        public CompressorOutputStream createCompressorOutputStream(
169                final String name, final OutputStream out)
170                throws CompressorException {
171            if (name == null || out == null) {
172                throw new IllegalArgumentException(
173                        "Compressor name and stream must not be null.");
174            }
175    
176            try {
177    
178                if (GZIP.equalsIgnoreCase(name)) {
179                    return new GzipCompressorOutputStream(out);
180                }
181    
182                if (BZIP2.equalsIgnoreCase(name)) {
183                    return new BZip2CompressorOutputStream(out);
184                }
185    
186                if (PACK200.equalsIgnoreCase(name)) {
187                    return new Pack200CompressorOutputStream(out);
188                }
189    
190            } catch (IOException e) {
191                throw new CompressorException(
192                        "Could not create CompressorOutputStream", e);
193            }
194            throw new CompressorException("Compressor: " + name + " not found.");
195        }
196    }