    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    }