aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java')
-rw-r--r--src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java797
1 files changed, 797 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java b/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
new file mode 100644
index 000000000..d730b9de4
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
@@ -0,0 +1,797 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.compressors;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.commons.compress.compressors.brotli.BrotliCompressorInputStream;
+import org.apache.commons.compress.compressors.brotli.BrotliUtils;
+import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
+import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
+import org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream;
+import org.apache.commons.compress.compressors.deflate.DeflateCompressorOutputStream;
+import org.apache.commons.compress.compressors.deflate64.Deflate64CompressorInputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
+import org.apache.commons.compress.compressors.lz4.BlockLZ4CompressorInputStream;
+import org.apache.commons.compress.compressors.lz4.BlockLZ4CompressorOutputStream;
+import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorInputStream;
+import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorOutputStream;
+import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream;
+import org.apache.commons.compress.compressors.lzma.LZMACompressorOutputStream;
+import org.apache.commons.compress.compressors.lzma.LZMAUtils;
+import org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream;
+import org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream;
+import org.apache.commons.compress.compressors.snappy.FramedSnappyCompressorInputStream;
+import org.apache.commons.compress.compressors.snappy.FramedSnappyCompressorOutputStream;
+import org.apache.commons.compress.compressors.snappy.SnappyCompressorInputStream;
+import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
+import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream;
+import org.apache.commons.compress.compressors.xz.XZUtils;
+import org.apache.commons.compress.compressors.z.ZCompressorInputStream;
+import org.apache.commons.compress.compressors.zstandard.ZstdCompressorInputStream;
+import org.apache.commons.compress.compressors.zstandard.ZstdCompressorOutputStream;
+import org.apache.commons.compress.compressors.zstandard.ZstdUtils;
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.commons.compress.utils.Lists;
+import org.apache.commons.compress.utils.ServiceLoaderIterator;
+import org.apache.commons.compress.utils.Sets;
+
+/**
+ * <p>
+ * Factory to create Compressor[In|Out]putStreams from names. To add other
+ * implementations you should extend CompressorStreamFactory and override the
+ * appropriate methods (and call their implementation from super of course).
+ * </p>
+ *
+ * Example (Compressing a file):
+ *
+ * <pre>
+ * final OutputStream out = Files.newOutputStream(output.toPath());
+ * CompressorOutputStream cos = new CompressorStreamFactory()
+ * .createCompressorOutputStream(CompressorStreamFactory.BZIP2, out);
+ * IOUtils.copy(Files.newInputStream(input.toPath()), cos);
+ * cos.close();
+ * </pre>
+ *
+ * Example (Decompressing a file):
+ *
+ * <pre>
+ * final InputStream is = Files.newInputStream(input.toPath());
+ * CompressorInputStream in = new CompressorStreamFactory().createCompressorInputStream(CompressorStreamFactory.BZIP2,
+ * is);
+ * IOUtils.copy(in, Files.newOutputStream(output.toPath()));
+ * in.close();
+ * </pre>
+ *
+ * @Immutable provided that the deprecated method setDecompressConcatenated is
+ * not used.
+ * @ThreadSafe even if the deprecated method setDecompressConcatenated is used
+ */
+public class CompressorStreamFactory implements CompressorStreamProvider {
+
+ private static final CompressorStreamFactory SINGLETON = new CompressorStreamFactory();
+
+
+
+ /**
+ * Constant (value {@value}) used to identify the BROTLI compression
+ * algorithm.
+ *
+ * @since 1.14
+ */
+ public static final String BROTLI = "br";
+
+ /**
+ * Constant (value {@value}) used to identify the BZIP2 compression
+ * algorithm.
+ *
+ * @since 1.1
+ */
+ public static final String BZIP2 = "bzip2";
+
+ /**
+ * Constant (value {@value}) used to identify the GZIP compression
+ * algorithm.
+ *
+ * @since 1.1
+ */
+ public static final String GZIP = "gz";
+
+ /**
+ * Constant (value {@value}) used to identify the PACK200 compression
+ * algorithm.
+ *
+ * @since 1.3
+ */
+ public static final String PACK200 = "pack200";
+
+ /**
+ * Constant (value {@value}) used to identify the XZ compression method.
+ *
+ * @since 1.4
+ */
+ public static final String XZ = "xz";
+
+ /**
+ * Constant (value {@value}) used to identify the LZMA compression method.
+ *
+ * @since 1.6
+ */
+ public static final String LZMA = "lzma";
+
+ /**
+ * Constant (value {@value}) used to identify the "framed" Snappy
+ * compression method.
+ *
+ * @since 1.7
+ */
+ public static final String SNAPPY_FRAMED = "snappy-framed";
+
+ /**
+ * Constant (value {@value}) used to identify the "raw" Snappy compression
+ * method. Not supported as an output stream type.
+ *
+ * @since 1.7
+ */
+ public static final String SNAPPY_RAW = "snappy-raw";
+
+ /**
+ * Constant (value {@value}) used to identify the traditional Unix compress
+ * method. Not supported as an output stream type.
+ *
+ * @since 1.7
+ */
+ public static final String Z = "z";
+
+ /**
+ * Constant (value {@value}) used to identify the Deflate compress method.
+ *
+ * @since 1.9
+ */
+ public static final String DEFLATE = "deflate";
+
+ /**
+ * Constant (value {@value}) used to identify the Deflate64 compress method.
+ *
+ * @since 1.16
+ */
+ public static final String DEFLATE64 = "deflate64";
+
+ /**
+ * Constant (value {@value}) used to identify the block LZ4
+ * compression method.
+ *
+ * @since 1.14
+ */
+ public static final String LZ4_BLOCK = "lz4-block";
+
+ /**
+ * Constant (value {@value}) used to identify the frame LZ4
+ * compression method.
+ *
+ * @since 1.14
+ */
+ public static final String LZ4_FRAMED = "lz4-framed";
+
+ /**
+ * Constant (value {@value}) used to identify the Zstandard compression
+ * algorithm. Not supported as an output stream type.
+ *
+ * @since 1.16
+ */
+ public static final String ZSTANDARD = "zstd";
+
+ private static final String YOU_NEED_BROTLI_DEC = youNeed("Google Brotli Dec", "https://github.com/google/brotli/");
+ private static final String YOU_NEED_XZ_JAVA = youNeed("XZ for Java", "https://tukaani.org/xz/java.html");
+ private static final String YOU_NEED_ZSTD_JNI = youNeed("Zstd JNI", "https://github.com/luben/zstd-jni");
+
+ private static String youNeed(String name, String url) {
+ return " In addition to Apache Commons Compress you need the " + name + " library - see " + url;
+ }
+
+ /**
+ * Constructs a new sorted map from input stream provider names to provider
+ * objects.
+ *
+ * <p>
+ * The map returned by this method will have one entry for each provider for
+ * which support is available in the current Java virtual machine. If two or
+ * more supported provider have the same name then the resulting map will
+ * contain just one of them; which one it will contain is not specified.
+ * </p>
+ *
+ * <p>
+ * The invocation of this method, and the subsequent use of the resulting
+ * map, may cause time-consuming disk or network I/O operations to occur.
+ * This method is provided for applications that need to enumerate all of
+ * the available providers, for example to allow user provider selection.
+ * </p>
+ *
+ * <p>
+ * This method may return different results at different times if new
+ * providers are dynamically made available to the current Java virtual
+ * machine.
+ * </p>
+ *
+ * @return An immutable, map from names to provider objects
+ * @since 1.13
+ */
+ public static SortedMap<String, CompressorStreamProvider> findAvailableCompressorInputStreamProviders() {
+ return AccessController.doPrivileged(new PrivilegedAction<SortedMap<String, CompressorStreamProvider>>() {
+ @Override
+ public SortedMap<String, CompressorStreamProvider> run() {
+ final TreeMap<String, CompressorStreamProvider> map = new TreeMap<>();
+ putAll(SINGLETON.getInputStreamCompressorNames(), SINGLETON, map);
+ for (final CompressorStreamProvider provider : findCompressorStreamProviders()) {
+ putAll(provider.getInputStreamCompressorNames(), provider, map);
+ }
+ return map;
+ }
+ });
+ }
+
+ /**
+ * Constructs a new sorted map from output stream provider names to provider
+ * objects.
+ *
+ * <p>
+ * The map returned by this method will have one entry for each provider for
+ * which support is available in the current Java virtual machine. If two or
+ * more supported provider have the same name then the resulting map will
+ * contain just one of them; which one it will contain is not specified.
+ * </p>
+ *
+ * <p>
+ * The invocation of this method, and the subsequent use of the resulting
+ * map, may cause time-consuming disk or network I/O operations to occur.
+ * This method is provided for applications that need to enumerate all of
+ * the available providers, for example to allow user provider selection.
+ * </p>
+ *
+ * <p>
+ * This method may return different results at different times if new
+ * providers are dynamically made available to the current Java virtual
+ * machine.
+ * </p>
+ *
+ * @return An immutable, map from names to provider objects
+ * @since 1.13
+ */
+ public static SortedMap<String, CompressorStreamProvider> findAvailableCompressorOutputStreamProviders() {
+ return AccessController.doPrivileged(new PrivilegedAction<SortedMap<String, CompressorStreamProvider>>() {
+ @Override
+ public SortedMap<String, CompressorStreamProvider> run() {
+ final TreeMap<String, CompressorStreamProvider> map = new TreeMap<>();
+ putAll(SINGLETON.getOutputStreamCompressorNames(), SINGLETON, map);
+ for (final CompressorStreamProvider provider : findCompressorStreamProviders()) {
+ putAll(provider.getOutputStreamCompressorNames(), provider, map);
+ }
+ return map;
+ }
+
+ });
+ }
+ private static ArrayList<CompressorStreamProvider> findCompressorStreamProviders() {
+ return Lists.newArrayList(serviceLoaderIterator());
+ }
+
+ public static String getBrotli() {
+ return BROTLI;
+ }
+
+ public static String getBzip2() {
+ return BZIP2;
+ }
+
+ public static String getDeflate() {
+ return DEFLATE;
+ }
+
+ /**
+ * @since 1.16
+ * @return the constant {@link #DEFLATE64}
+ */
+ public static String getDeflate64() {
+ return DEFLATE64;
+ }
+
+ public static String getGzip() {
+ return GZIP;
+ }
+
+ public static String getLzma() {
+ return LZMA;
+ }
+
+ public static String getPack200() {
+ return PACK200;
+ }
+
+ public static CompressorStreamFactory getSingleton() {
+ return SINGLETON;
+ }
+
+ public static String getSnappyFramed() {
+ return SNAPPY_FRAMED;
+ }
+
+ public static String getSnappyRaw() {
+ return SNAPPY_RAW;
+ }
+
+ public static String getXz() {
+ return XZ;
+ }
+
+ public static String getZ() {
+ return Z;
+ }
+
+ public static String getLZ4Framed() {
+ return LZ4_FRAMED;
+ }
+
+ public static String getLZ4Block() {
+ return LZ4_BLOCK;
+ }
+
+ public static String getZstandard() {
+ return ZSTANDARD;
+ }
+
+ static void putAll(final Set<String> names, final CompressorStreamProvider provider,
+ final TreeMap<String, CompressorStreamProvider> map) {
+ for (final String name : names) {
+ map.put(toKey(name), provider);
+ }
+ }
+
+ private static Iterator<CompressorStreamProvider> serviceLoaderIterator() {
+ return new ServiceLoaderIterator<>(CompressorStreamProvider.class);
+ }
+
+ private static String toKey(final String name) {
+ return name.toUpperCase(Locale.ROOT);
+ }
+
+ /**
+ * If true, decompress until the end of the input. If false, stop after the
+ * first stream and leave the input position to point to the next byte after
+ * the stream
+ */
+ private final Boolean decompressUntilEOF;
+ // This is Boolean so setDecompressConcatenated can determine whether it has
+ // been set by the ctor
+ // once the setDecompressConcatenated method has been removed, it can revert
+ // to boolean
+
+ private SortedMap<String, CompressorStreamProvider> compressorInputStreamProviders;
+
+ private SortedMap<String, CompressorStreamProvider> compressorOutputStreamProviders;
+
+ /**
+ * If true, decompress until the end of the input. If false, stop after the
+ * first stream and leave the input position to point to the next byte after
+ * the stream
+ */
+ private volatile boolean decompressConcatenated = false;
+
+ private final int memoryLimitInKb;
+ /**
+ * Create an instance with the decompress Concatenated option set to false.
+ */
+ public CompressorStreamFactory() {
+ this.decompressUntilEOF = null;
+ this.memoryLimitInKb = -1;
+ }
+
+ /**
+ * Create an instance with the provided decompress Concatenated option.
+ *
+ * @param decompressUntilEOF
+ * if true, decompress until the end of the input; if false, stop
+ * after the first stream and leave the input position to point
+ * to the next byte after the stream. This setting applies to the
+ * gzip, bzip2 and xz formats only.
+ *
+ * @param memoryLimitInKb
+ * Some streams require allocation of potentially significant
+ * byte arrays/tables, and they can offer checks to prevent OOMs
+ * on corrupt files. Set the maximum allowed memory allocation in KBs.
+ *
+ * @since 1.14
+ */
+ public CompressorStreamFactory(final boolean decompressUntilEOF, final int memoryLimitInKb) {
+ this.decompressUntilEOF = decompressUntilEOF;
+ // Also copy to existing variable so can continue to use that as the
+ // current value
+ this.decompressConcatenated = decompressUntilEOF;
+ this.memoryLimitInKb = memoryLimitInKb;
+ }
+
+
+ /**
+ * Create an instance with the provided decompress Concatenated option.
+ *
+ * @param decompressUntilEOF
+ * if true, decompress until the end of the input; if false, stop
+ * after the first stream and leave the input position to point
+ * to the next byte after the stream. This setting applies to the
+ * gzip, bzip2 and xz formats only.
+ * @since 1.10
+ */
+ public CompressorStreamFactory(final boolean decompressUntilEOF) {
+ this(decompressUntilEOF, -1);
+ }
+
+ /**
+ * Try to detect the type of compressor stream.
+ *
+ * @param in input stream
+ * @return type of compressor stream detected
+ * @throws CompressorException if no compressor stream type was detected
+ * or if something else went wrong
+ * @throws IllegalArgumentException if stream is null or does not support mark
+ *
+ * @since 1.14
+ */
+ public static String detect(final InputStream in) throws CompressorException {
+ if (in == null) {
+ throw new IllegalArgumentException("Stream must not be null.");
+ }
+
+ if (!in.markSupported()) {
+ throw new IllegalArgumentException("Mark is not supported.");
+ }
+
+ final byte[] signature = new byte[12];
+ in.mark(signature.length);
+ int signatureLength = -1;
+ try {
+ signatureLength = IOUtils.readFully(in, signature);
+ in.reset();
+ } catch (IOException e) {
+ throw new CompressorException("IOException while reading signature.", e);
+ }
+
+ if (BZip2CompressorInputStream.matches(signature, signatureLength)) {
+ return BZIP2;
+ }
+
+ if (GzipCompressorInputStream.matches(signature, signatureLength)) {
+ return GZIP;
+ }
+
+ if (Pack200CompressorInputStream.matches(signature, signatureLength)) {
+ return PACK200;
+ }
+
+ if (FramedSnappyCompressorInputStream.matches(signature, signatureLength)) {
+ return SNAPPY_FRAMED;
+ }
+
+ if (ZCompressorInputStream.matches(signature, signatureLength)) {
+ return Z;
+ }
+
+ if (DeflateCompressorInputStream.matches(signature, signatureLength)) {
+ return DEFLATE;
+ }
+
+ if (XZUtils.matches(signature, signatureLength)) {
+ return XZ;
+ }
+
+ if (LZMAUtils.matches(signature, signatureLength)) {
+ return LZMA;
+ }
+
+ if (FramedLZ4CompressorInputStream.matches(signature, signatureLength)) {
+ return LZ4_FRAMED;
+ }
+
+ if (ZstdUtils.matches(signature, signatureLength)) {
+ return ZSTANDARD;
+ }
+
+ throw new CompressorException("No Compressor found for the stream signature.");
+ }
+ /**
+ * Create an compressor input stream from an input stream, autodetecting the
+ * compressor type from the first few bytes of the stream. The InputStream
+ * must support marks, like BufferedInputStream.
+ *
+ * @param in
+ * the input stream
+ * @return the compressor input stream
+ * @throws CompressorException
+ * if the compressor name is not known
+ * @throws IllegalArgumentException
+ * if the stream is null or does not support mark
+ * @since 1.1
+ */
+ public CompressorInputStream createCompressorInputStream(final InputStream in) throws CompressorException {
+ return createCompressorInputStream(detect(in), in);
+ }
+
+ /**
+ * Creates a compressor input stream from a compressor name and an input
+ * stream.
+ *
+ * @param name
+ * of the compressor, i.e. {@value #GZIP}, {@value #BZIP2},
+ * {@value #XZ}, {@value #LZMA}, {@value #PACK200},
+ * {@value #SNAPPY_RAW}, {@value #SNAPPY_FRAMED}, {@value #Z},
+ * {@value #LZ4_BLOCK}, {@value #LZ4_FRAMED}, {@value #ZSTANDARD},
+ * {@value #DEFLATE64}
+ * or {@value #DEFLATE}
+ * @param in
+ * the input stream
+ * @return compressor input stream
+ * @throws CompressorException
+ * if the compressor name is not known or not available,
+ * or if there's an IOException or MemoryLimitException thrown
+ * during initialization
+ * @throws IllegalArgumentException
+ * if the name or input stream is null
+ */
+ public CompressorInputStream createCompressorInputStream(final String name, final InputStream in)
+ throws CompressorException {
+ return createCompressorInputStream(name, in, decompressConcatenated);
+ }
+
+ @Override
+ public CompressorInputStream createCompressorInputStream(final String name, final InputStream in,
+ final boolean actualDecompressConcatenated) throws CompressorException {
+ if (name == null || in == null) {
+ throw new IllegalArgumentException("Compressor name and stream must not be null.");
+ }
+
+ try {
+
+ if (GZIP.equalsIgnoreCase(name)) {
+ return new GzipCompressorInputStream(in, actualDecompressConcatenated);
+ }
+
+ if (BZIP2.equalsIgnoreCase(name)) {
+ return new BZip2CompressorInputStream(in, actualDecompressConcatenated);
+ }
+
+ if (BROTLI.equalsIgnoreCase(name)) {
+ if (!BrotliUtils.isBrotliCompressionAvailable()) {
+ throw new CompressorException("Brotli compression is not available." + YOU_NEED_BROTLI_DEC);
+ }
+ return new BrotliCompressorInputStream(in);
+ }
+
+ if (XZ.equalsIgnoreCase(name)) {
+ if (!XZUtils.isXZCompressionAvailable()) {
+ throw new CompressorException("XZ compression is not available." + YOU_NEED_XZ_JAVA);
+ }
+ return new XZCompressorInputStream(in, actualDecompressConcatenated, memoryLimitInKb);
+ }
+
+ if (ZSTANDARD.equalsIgnoreCase(name)) {
+ if (!ZstdUtils.isZstdCompressionAvailable()) {
+ throw new CompressorException("Zstandard compression is not available." + YOU_NEED_ZSTD_JNI);
+ }
+ return new ZstdCompressorInputStream(in);
+ }
+
+ if (LZMA.equalsIgnoreCase(name)) {
+ if (!LZMAUtils.isLZMACompressionAvailable()) {
+ throw new CompressorException("LZMA compression is not available" + YOU_NEED_XZ_JAVA);
+ }
+ return new LZMACompressorInputStream(in, memoryLimitInKb);
+ }
+
+ if (PACK200.equalsIgnoreCase(name)) {
+ return new Pack200CompressorInputStream(in);
+ }
+
+ if (SNAPPY_RAW.equalsIgnoreCase(name)) {
+ return new SnappyCompressorInputStream(in);
+ }
+
+ if (SNAPPY_FRAMED.equalsIgnoreCase(name)) {
+ return new FramedSnappyCompressorInputStream(in);
+ }
+
+ if (Z.equalsIgnoreCase(name)) {
+ return new ZCompressorInputStream(in, memoryLimitInKb);
+ }
+
+ if (DEFLATE.equalsIgnoreCase(name)) {
+ return new DeflateCompressorInputStream(in);
+ }
+
+ if (DEFLATE64.equalsIgnoreCase(name)) {
+ return new Deflate64CompressorInputStream(in);
+ }
+
+ if (LZ4_BLOCK.equalsIgnoreCase(name)) {
+ return new BlockLZ4CompressorInputStream(in);
+ }
+
+ if (LZ4_FRAMED.equalsIgnoreCase(name)) {
+ return new FramedLZ4CompressorInputStream(in, actualDecompressConcatenated);
+ }
+
+ } catch (final IOException e) {
+ throw new CompressorException("Could not create CompressorInputStream.", e);
+ }
+ final CompressorStreamProvider compressorStreamProvider = getCompressorInputStreamProviders().get(toKey(name));
+ if (compressorStreamProvider != null) {
+ return compressorStreamProvider.createCompressorInputStream(name, in, actualDecompressConcatenated);
+ }
+
+ throw new CompressorException("Compressor: " + name + " not found.");
+ }
+
+ /**
+ * Creates an compressor output stream from an compressor name and an output
+ * stream.
+ *
+ * @param name
+ * the compressor name, i.e. {@value #GZIP}, {@value #BZIP2},
+ * {@value #XZ}, {@value #PACK200}, {@value #SNAPPY_FRAMED},
+ * {@value #LZ4_BLOCK}, {@value #LZ4_FRAMED}, {@value #ZSTANDARD}
+ * or {@value #DEFLATE}
+ * @param out
+ * the output stream
+ * @return the compressor output stream
+ * @throws CompressorException
+ * if the archiver name is not known
+ * @throws IllegalArgumentException
+ * if the archiver name or stream is null
+ */
+ @Override
+ public CompressorOutputStream createCompressorOutputStream(final String name, final OutputStream out)
+ throws CompressorException {
+ if (name == null || out == null) {
+ throw new IllegalArgumentException("Compressor name and stream must not be null.");
+ }
+
+ try {
+
+ if (GZIP.equalsIgnoreCase(name)) {
+ return new GzipCompressorOutputStream(out);
+ }
+
+ if (BZIP2.equalsIgnoreCase(name)) {
+ return new BZip2CompressorOutputStream(out);
+ }
+
+ if (XZ.equalsIgnoreCase(name)) {
+ return new XZCompressorOutputStream(out);
+ }
+
+ if (PACK200.equalsIgnoreCase(name)) {
+ return new Pack200CompressorOutputStream(out);
+ }
+
+ if (LZMA.equalsIgnoreCase(name)) {
+ return new LZMACompressorOutputStream(out);
+ }
+
+ if (DEFLATE.equalsIgnoreCase(name)) {
+ return new DeflateCompressorOutputStream(out);
+ }
+
+ if (SNAPPY_FRAMED.equalsIgnoreCase(name)) {
+ return new FramedSnappyCompressorOutputStream(out);
+ }
+
+ if (LZ4_BLOCK.equalsIgnoreCase(name)) {
+ return new BlockLZ4CompressorOutputStream(out);
+ }
+
+ if (LZ4_FRAMED.equalsIgnoreCase(name)) {
+ return new FramedLZ4CompressorOutputStream(out);
+ }
+
+ if (ZSTANDARD.equalsIgnoreCase(name)) {
+ return new ZstdCompressorOutputStream(out);
+ }
+ } catch (final IOException e) {
+ throw new CompressorException("Could not create CompressorOutputStream", e);
+ }
+ final CompressorStreamProvider compressorStreamProvider = getCompressorOutputStreamProviders().get(toKey(name));
+ if (compressorStreamProvider != null) {
+ return compressorStreamProvider.createCompressorOutputStream(name, out);
+ }
+ throw new CompressorException("Compressor: " + name + " not found.");
+ }
+
+ public SortedMap<String, CompressorStreamProvider> getCompressorInputStreamProviders() {
+ if (compressorInputStreamProviders == null) {
+ compressorInputStreamProviders = Collections
+ .unmodifiableSortedMap(findAvailableCompressorInputStreamProviders());
+ }
+ return compressorInputStreamProviders;
+ }
+
+ public SortedMap<String, CompressorStreamProvider> getCompressorOutputStreamProviders() {
+ if (compressorOutputStreamProviders == null) {
+ compressorOutputStreamProviders = Collections
+ .unmodifiableSortedMap(findAvailableCompressorOutputStreamProviders());
+ }
+ return compressorOutputStreamProviders;
+ }
+
+ // For Unit tests
+ boolean getDecompressConcatenated() {
+ return decompressConcatenated;
+ }
+
+ public Boolean getDecompressUntilEOF() {
+ return decompressUntilEOF;
+ }
+
+ @Override
+ public Set<String> getInputStreamCompressorNames() {
+ return Sets.newHashSet(GZIP, BROTLI, BZIP2, XZ, LZMA, PACK200, DEFLATE, SNAPPY_RAW, SNAPPY_FRAMED, Z, LZ4_BLOCK,
+ LZ4_FRAMED, ZSTANDARD, DEFLATE64);
+ }
+
+ @Override
+ public Set<String> getOutputStreamCompressorNames() {
+ return Sets.newHashSet(GZIP, BZIP2, XZ, LZMA, PACK200, DEFLATE, SNAPPY_FRAMED, LZ4_BLOCK, LZ4_FRAMED, ZSTANDARD);
+ }
+
+ /**
+ * Whether to decompress the full input or only the first stream in formats
+ * supporting multiple concatenated input streams.
+ *
+ * <p>
+ * This setting applies to the gzip, bzip2 and xz formats only.
+ * </p>
+ *
+ * @param decompressConcatenated
+ * if true, decompress until the end of the input; if false, stop
+ * after the first stream and leave the input position to point
+ * to the next byte after the stream
+ * @since 1.5
+ * @deprecated 1.10 use the {@link #CompressorStreamFactory(boolean)}
+ * constructor instead
+ * @throws IllegalStateException
+ * if the constructor {@link #CompressorStreamFactory(boolean)}
+ * was used to create the factory
+ */
+ @Deprecated
+ public void setDecompressConcatenated(final boolean decompressConcatenated) {
+ if (this.decompressUntilEOF != null) {
+ throw new IllegalStateException("Cannot override the setting defined by the constructor");
+ }
+ this.decompressConcatenated = decompressConcatenated;
+ }
+
+}