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