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 */ 019package org.apache.commons.compress.compressors; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.OutputStream; 024import java.security.AccessController; 025import java.security.PrivilegedAction; 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.Iterator; 029import java.util.Locale; 030import java.util.Set; 031import java.util.SortedMap; 032import java.util.TreeMap; 033 034import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; 035import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; 036import org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream; 037import org.apache.commons.compress.compressors.deflate.DeflateCompressorOutputStream; 038import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; 039import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; 040import org.apache.commons.compress.compressors.lz4.BlockLZ4CompressorInputStream; 041import org.apache.commons.compress.compressors.lz4.BlockLZ4CompressorOutputStream; 042import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorInputStream; 043import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorOutputStream; 044import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream; 045import org.apache.commons.compress.compressors.lzma.LZMACompressorOutputStream; 046import org.apache.commons.compress.compressors.lzma.LZMAUtils; 047import org.apache.commons.compress.compressors.pack200.Pack200CompressorInputStream; 048import org.apache.commons.compress.compressors.pack200.Pack200CompressorOutputStream; 049import org.apache.commons.compress.compressors.snappy.FramedSnappyCompressorInputStream; 050import org.apache.commons.compress.compressors.snappy.FramedSnappyCompressorOutputStream; 051import org.apache.commons.compress.compressors.snappy.SnappyCompressorInputStream; 052import org.apache.commons.compress.compressors.xz.XZCompressorInputStream; 053import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream; 054import org.apache.commons.compress.compressors.xz.XZUtils; 055import org.apache.commons.compress.compressors.z.ZCompressorInputStream; 056import org.apache.commons.compress.utils.IOUtils; 057import org.apache.commons.compress.utils.Lists; 058import org.apache.commons.compress.utils.ServiceLoaderIterator; 059import org.apache.commons.compress.utils.Sets; 060 061/** 062 * <p> 063 * Factory to create Compressor[In|Out]putStreams from names. To add other 064 * implementations you should extend CompressorStreamFactory and override the 065 * appropriate methods (and call their implementation from super of course). 066 * </p> 067 * 068 * Example (Compressing a file): 069 * 070 * <pre> 071 * final OutputStream out = Files.newOutputStream(output.toPath()); 072 * CompressorOutputStream cos = new CompressorStreamFactory() 073 * .createCompressorOutputStream(CompressorStreamFactory.BZIP2, out); 074 * IOUtils.copy(Files.newInputStream(input.toPath()), cos); 075 * cos.close(); 076 * </pre> 077 * 078 * Example (Decompressing a file): 079 * 080 * <pre> 081 * final InputStream is = Files.newInputStream(input.toPath()); 082 * CompressorInputStream in = new CompressorStreamFactory().createCompressorInputStream(CompressorStreamFactory.BZIP2, 083 * is); 084 * IOUtils.copy(in, Files.newOutputStream(output.toPath())); 085 * in.close(); 086 * </pre> 087 * 088 * @Immutable provided that the deprecated method setDecompressConcatenated is 089 * not used. 090 * @ThreadSafe even if the deprecated method setDecompressConcatenated is used 091 */ 092public class CompressorStreamFactory implements CompressorStreamProvider { 093 094 private static final CompressorStreamFactory SINGLETON = new CompressorStreamFactory(); 095 096 097 098 /** 099 * Constant (value {@value}) used to identify the BROTLI compression 100 * algorithm. 101 * 102 * @since 1.14 103 */ 104 public static final String BROTLI = "br"; 105 106 /** 107 * Constant (value {@value}) used to identify the BZIP2 compression 108 * algorithm. 109 * 110 * @since 1.1 111 */ 112 public static final String BZIP2 = "bzip2"; 113 114 /** 115 * Constant (value {@value}) used to identify the GZIP compression 116 * algorithm. 117 * 118 * @since 1.1 119 */ 120 public static final String GZIP = "gz"; 121 122 /** 123 * Constant (value {@value}) used to identify the PACK200 compression 124 * algorithm. 125 * 126 * @since 1.3 127 */ 128 public static final String PACK200 = "pack200"; 129 130 /** 131 * Constant (value {@value}) used to identify the XZ compression method. 132 * 133 * @since 1.4 134 */ 135 public static final String XZ = "xz"; 136 137 /** 138 * Constant (value {@value}) used to identify the LZMA compression method. 139 * 140 * @since 1.6 141 */ 142 public static final String LZMA = "lzma"; 143 144 /** 145 * Constant (value {@value}) used to identify the "framed" Snappy 146 * compression method. 147 * 148 * @since 1.7 149 */ 150 public static final String SNAPPY_FRAMED = "snappy-framed"; 151 152 /** 153 * Constant (value {@value}) used to identify the "raw" Snappy compression 154 * method. Not supported as an output stream type. 155 * 156 * @since 1.7 157 */ 158 public static final String SNAPPY_RAW = "snappy-raw"; 159 160 /** 161 * Constant (value {@value}) used to identify the traditional Unix compress 162 * method. Not supported as an output stream type. 163 * 164 * @since 1.7 165 */ 166 public static final String Z = "z"; 167 168 /** 169 * Constant (value {@value}) used to identify the Deflate compress method. 170 * 171 * @since 1.9 172 */ 173 public static final String DEFLATE = "deflate"; 174 175 /** 176 * Constant (value {@value}) used to identify the block LZ4 177 * compression method. 178 * 179 * @since 1.14 180 */ 181 public static final String LZ4_BLOCK = "lz4-block"; 182 183 /** 184 * Constant (value {@value}) used to identify the frame LZ4 185 * compression method. 186 * 187 * @since 1.14 188 */ 189 public static final String LZ4_FRAMED = "lz4-framed"; 190 191 /** 192 * Constructs a new sorted map from input stream provider names to provider 193 * objects. 194 * 195 * <p> 196 * The map returned by this method will have one entry for each provider for 197 * which support is available in the current Java virtual machine. If two or 198 * more supported provider have the same name then the resulting map will 199 * contain just one of them; which one it will contain is not specified. 200 * </p> 201 * 202 * <p> 203 * The invocation of this method, and the subsequent use of the resulting 204 * map, may cause time-consuming disk or network I/O operations to occur. 205 * This method is provided for applications that need to enumerate all of 206 * the available providers, for example to allow user provider selection. 207 * </p> 208 * 209 * <p> 210 * This method may return different results at different times if new 211 * providers are dynamically made available to the current Java virtual 212 * machine. 213 * </p> 214 * 215 * @return An immutable, map from names to provider objects 216 * @since 1.13 217 */ 218 public static SortedMap<String, CompressorStreamProvider> findAvailableCompressorInputStreamProviders() { 219 return AccessController.doPrivileged(new PrivilegedAction<SortedMap<String, CompressorStreamProvider>>() { 220 @Override 221 public SortedMap<String, CompressorStreamProvider> run() { 222 final TreeMap<String, CompressorStreamProvider> map = new TreeMap<>(); 223 putAll(SINGLETON.getInputStreamCompressorNames(), SINGLETON, map); 224 for (final CompressorStreamProvider provider : findCompressorStreamProviders()) { 225 putAll(provider.getInputStreamCompressorNames(), provider, map); 226 } 227 return map; 228 } 229 }); 230 } 231 232 /** 233 * Constructs a new sorted map from output stream provider names to provider 234 * objects. 235 * 236 * <p> 237 * The map returned by this method will have one entry for each provider for 238 * which support is available in the current Java virtual machine. If two or 239 * more supported provider have the same name then the resulting map will 240 * contain just one of them; which one it will contain is not specified. 241 * </p> 242 * 243 * <p> 244 * The invocation of this method, and the subsequent use of the resulting 245 * map, may cause time-consuming disk or network I/O operations to occur. 246 * This method is provided for applications that need to enumerate all of 247 * the available providers, for example to allow user provider selection. 248 * </p> 249 * 250 * <p> 251 * This method may return different results at different times if new 252 * providers are dynamically made available to the current Java virtual 253 * machine. 254 * </p> 255 * 256 * @return An immutable, map from names to provider objects 257 * @since 1.13 258 */ 259 public static SortedMap<String, CompressorStreamProvider> findAvailableCompressorOutputStreamProviders() { 260 return AccessController.doPrivileged(new PrivilegedAction<SortedMap<String, CompressorStreamProvider>>() { 261 @Override 262 public SortedMap<String, CompressorStreamProvider> run() { 263 final TreeMap<String, CompressorStreamProvider> map = new TreeMap<>(); 264 putAll(SINGLETON.getOutputStreamCompressorNames(), SINGLETON, map); 265 for (final CompressorStreamProvider provider : findCompressorStreamProviders()) { 266 putAll(provider.getOutputStreamCompressorNames(), provider, map); 267 } 268 return map; 269 } 270 271 }); 272 } 273 private static ArrayList<CompressorStreamProvider> findCompressorStreamProviders() { 274 return Lists.newArrayList(serviceLoaderIterator()); 275 } 276 277 public static String getBrotli() { 278 return BROTLI; 279 } 280 281 public static String getBzip2() { 282 return BZIP2; 283 } 284 285 public static String getDeflate() { 286 return DEFLATE; 287 } 288 289 public static String getGzip() { 290 return GZIP; 291 } 292 293 public static String getLzma() { 294 return LZMA; 295 } 296 297 public static String getPack200() { 298 return PACK200; 299 } 300 301 public static CompressorStreamFactory getSingleton() { 302 return SINGLETON; 303 } 304 305 public static String getSnappyFramed() { 306 return SNAPPY_FRAMED; 307 } 308 309 public static String getSnappyRaw() { 310 return SNAPPY_RAW; 311 } 312 313 public static String getXz() { 314 return XZ; 315 } 316 317 public static String getZ() { 318 return Z; 319 } 320 321 public static String getLZ4Framed() { 322 return LZ4_FRAMED; 323 } 324 325 public static String getLZ4Block() { 326 return LZ4_BLOCK; 327 } 328 329 static void putAll(final Set<String> names, final CompressorStreamProvider provider, 330 final TreeMap<String, CompressorStreamProvider> map) { 331 for (final String name : names) { 332 map.put(toKey(name), provider); 333 } 334 } 335 336 private static Iterator<CompressorStreamProvider> serviceLoaderIterator() { 337 return new ServiceLoaderIterator<>(CompressorStreamProvider.class); 338 } 339 340 private static String toKey(final String name) { 341 return name.toUpperCase(Locale.ROOT); 342 } 343 344 /** 345 * If true, decompress until the end of the input. If false, stop after the 346 * first stream and leave the input position to point to the next byte after 347 * the stream 348 */ 349 private final Boolean decompressUntilEOF; 350 // This is Boolean so setDecompressConcatenated can determine whether it has 351 // been set by the ctor 352 // once the setDecompressConcatenated method has been removed, it can revert 353 // to boolean 354 355 private SortedMap<String, CompressorStreamProvider> compressorInputStreamProviders; 356 357 private SortedMap<String, CompressorStreamProvider> compressorOutputStreamProviders; 358 359 /** 360 * If true, decompress until the end of the input. If false, stop after the 361 * first stream and leave the input position to point to the next byte after 362 * the stream 363 */ 364 private volatile boolean decompressConcatenated = false; 365 366 private final int memoryLimitInKb; 367 /** 368 * Create an instance with the decompress Concatenated option set to false. 369 */ 370 public CompressorStreamFactory() { 371 this.decompressUntilEOF = null; 372 this.memoryLimitInKb = -1; 373 } 374 375 /** 376 * Create an instance with the provided decompress Concatenated option. 377 * 378 * @param decompressUntilEOF 379 * if true, decompress until the end of the input; if false, stop 380 * after the first stream and leave the input position to point 381 * to the next byte after the stream. This setting applies to the 382 * gzip, bzip2 and xz formats only. 383 * 384 * @param memoryLimitInKb 385 * Some streams require allocation of potentially significant 386 * byte arrays/tables, and they can offer checks to prevent OOMs 387 * on corrupt files. Set the maximum allowed memory allocation in KBs. 388 * 389 * @since 1.14 390 */ 391 public CompressorStreamFactory(final boolean decompressUntilEOF, final int memoryLimitInKb) { 392 this.decompressUntilEOF = Boolean.valueOf(decompressUntilEOF); 393 // Also copy to existing variable so can continue to use that as the 394 // current value 395 this.decompressConcatenated = decompressUntilEOF; 396 this.memoryLimitInKb = memoryLimitInKb; 397 } 398 399 400 /** 401 * Create an instance with the provided decompress Concatenated option. 402 * 403 * @param decompressUntilEOF 404 * if true, decompress until the end of the input; if false, stop 405 * after the first stream and leave the input position to point 406 * to the next byte after the stream. This setting applies to the 407 * gzip, bzip2 and xz formats only. 408 * @since 1.10 409 */ 410 public CompressorStreamFactory(final boolean decompressUntilEOF) { 411 this(decompressUntilEOF, -1); 412 } 413 414 /** 415 * Try to detect the type of compressor stream. 416 * 417 * @param in input stream 418 * @return type of compressor stream detected 419 * @throws CompressorException if no compressor stream type was detected 420 * or if something else went wrong 421 * @throws IllegalArgumentException if stream is null or does not support mark 422 * 423 * @since 1.14 424 */ 425 public static String detect(final InputStream in) throws CompressorException { 426 if (in == null) { 427 throw new IllegalArgumentException("Stream must not be null."); 428 } 429 430 if (!in.markSupported()) { 431 throw new IllegalArgumentException("Mark is not supported."); 432 } 433 434 final byte[] signature = new byte[12]; 435 in.mark(signature.length); 436 int signatureLength = -1; 437 try { 438 signatureLength = IOUtils.readFully(in, signature); 439 in.reset(); 440 } catch (IOException e) { 441 throw new CompressorException("IOException while reading signature.", e); 442 } 443 444 if (BZip2CompressorInputStream.matches(signature, signatureLength)) { 445 return BZIP2; 446 } 447 448 if (GzipCompressorInputStream.matches(signature, signatureLength)) { 449 return GZIP; 450 } 451 452 if (Pack200CompressorInputStream.matches(signature, signatureLength)) { 453 return PACK200; 454 } 455 456 if (FramedSnappyCompressorInputStream.matches(signature, signatureLength)) { 457 return SNAPPY_FRAMED; 458 } 459 460 if (ZCompressorInputStream.matches(signature, signatureLength)) { 461 return Z; 462 } 463 464 if (DeflateCompressorInputStream.matches(signature, signatureLength)) { 465 return DEFLATE; 466 } 467 468 if (XZUtils.matches(signature, signatureLength)) { 469 return XZ; 470 } 471 472 if (LZMAUtils.matches(signature, signatureLength)) { 473 return LZMA; 474 } 475 476 if (FramedLZ4CompressorInputStream.matches(signature, signatureLength)) { 477 return LZ4_FRAMED; 478 } 479 480 throw new CompressorException("No Compressor found for the stream signature."); 481 } 482 /** 483 * Create an compressor input stream from an input stream, autodetecting the 484 * compressor type from the first few bytes of the stream. The InputStream 485 * must support marks, like BufferedInputStream. 486 * 487 * @param in 488 * the input stream 489 * @return the compressor input stream 490 * @throws CompressorException 491 * if the compressor name is not known 492 * @throws IllegalArgumentException 493 * if the stream is null or does not support mark 494 * @since 1.1 495 */ 496 public CompressorInputStream createCompressorInputStream(final InputStream in) throws CompressorException { 497 return createCompressorInputStream(detect(in), in); 498 } 499 500 /** 501 * Creates a compressor input stream from a compressor name and an input 502 * stream. 503 * 504 * @param name 505 * of the compressor, i.e. {@value #GZIP}, {@value #BZIP2}, 506 * {@value #XZ}, {@value #LZMA}, {@value #PACK200}, 507 * {@value #SNAPPY_RAW}, {@value #SNAPPY_FRAMED}, {@value #Z}, 508 * {@value #LZ4_BLOCK}, {@value #LZ4_FRAMED} 509 * or {@value #DEFLATE} 510 * @param in 511 * the input stream 512 * @return compressor input stream 513 * @throws CompressorException 514 * if the compressor name is not known or not available, 515 * or if there's an IOException or MemoryLimitException thrown 516 * during initialization 517 * @throws IllegalArgumentException 518 * if the name or input stream is null 519 */ 520 public CompressorInputStream createCompressorInputStream(final String name, final InputStream in) 521 throws CompressorException { 522 return createCompressorInputStream(name, in, decompressConcatenated); 523 } 524 525 @Override 526 public CompressorInputStream createCompressorInputStream(final String name, final InputStream in, 527 final boolean actualDecompressConcatenated) throws CompressorException { 528 if (name == null || in == null) { 529 throw new IllegalArgumentException("Compressor name and stream must not be null."); 530 } 531 532 try { 533 534 if (GZIP.equalsIgnoreCase(name)) { 535 return new GzipCompressorInputStream(in, actualDecompressConcatenated); 536 } 537 538 if (BZIP2.equalsIgnoreCase(name)) { 539 return new BZip2CompressorInputStream(in, actualDecompressConcatenated); 540 } 541 542 if (XZ.equalsIgnoreCase(name)) { 543 if (!XZUtils.isXZCompressionAvailable()) { 544 throw new CompressorException("XZ compression is not available."); 545 } 546 return new XZCompressorInputStream(in, actualDecompressConcatenated, memoryLimitInKb); 547 } 548 549 if (LZMA.equalsIgnoreCase(name)) { 550 if (!LZMAUtils.isLZMACompressionAvailable()) { 551 throw new CompressorException("LZMA compression is not available"); 552 } 553 return new LZMACompressorInputStream(in, memoryLimitInKb); 554 } 555 556 if (PACK200.equalsIgnoreCase(name)) { 557 return new Pack200CompressorInputStream(in); 558 } 559 560 if (SNAPPY_RAW.equalsIgnoreCase(name)) { 561 return new SnappyCompressorInputStream(in); 562 } 563 564 if (SNAPPY_FRAMED.equalsIgnoreCase(name)) { 565 return new FramedSnappyCompressorInputStream(in); 566 } 567 568 if (Z.equalsIgnoreCase(name)) { 569 return new ZCompressorInputStream(in, memoryLimitInKb); 570 } 571 572 if (DEFLATE.equalsIgnoreCase(name)) { 573 return new DeflateCompressorInputStream(in); 574 } 575 576 if (LZ4_BLOCK.equalsIgnoreCase(name)) { 577 return new BlockLZ4CompressorInputStream(in); 578 } 579 580 if (LZ4_FRAMED.equalsIgnoreCase(name)) { 581 return new FramedLZ4CompressorInputStream(in, actualDecompressConcatenated); 582 } 583 584 } catch (final IOException e) { 585 throw new CompressorException("Could not create CompressorInputStream.", e); 586 } 587 final CompressorStreamProvider compressorStreamProvider = getCompressorInputStreamProviders().get(toKey(name)); 588 if (compressorStreamProvider != null) { 589 return compressorStreamProvider.createCompressorInputStream(name, in, actualDecompressConcatenated); 590 } 591 592 throw new CompressorException("Compressor: " + name + " not found."); 593 } 594 595 /** 596 * Creates an compressor output stream from an compressor name and an output 597 * stream. 598 * 599 * @param name 600 * the compressor name, i.e. {@value #GZIP}, {@value #BZIP2}, 601 * {@value #XZ}, {@value #PACK200}, {@value #SNAPPY_FRAMED}, 602 * {@value #LZ4_BLOCK}, {@value #LZ4_FRAMED} 603 * or {@value #DEFLATE} 604 * @param out 605 * the output stream 606 * @return the compressor output stream 607 * @throws CompressorException 608 * if the archiver name is not known 609 * @throws IllegalArgumentException 610 * if the archiver name or stream is null 611 */ 612 @Override 613 public CompressorOutputStream createCompressorOutputStream(final String name, final OutputStream out) 614 throws CompressorException { 615 if (name == null || out == null) { 616 throw new IllegalArgumentException("Compressor name and stream must not be null."); 617 } 618 619 try { 620 621 if (GZIP.equalsIgnoreCase(name)) { 622 return new GzipCompressorOutputStream(out); 623 } 624 625 if (BZIP2.equalsIgnoreCase(name)) { 626 return new BZip2CompressorOutputStream(out); 627 } 628 629 if (XZ.equalsIgnoreCase(name)) { 630 return new XZCompressorOutputStream(out); 631 } 632 633 if (PACK200.equalsIgnoreCase(name)) { 634 return new Pack200CompressorOutputStream(out); 635 } 636 637 if (LZMA.equalsIgnoreCase(name)) { 638 return new LZMACompressorOutputStream(out); 639 } 640 641 if (DEFLATE.equalsIgnoreCase(name)) { 642 return new DeflateCompressorOutputStream(out); 643 } 644 645 if (SNAPPY_FRAMED.equalsIgnoreCase(name)) { 646 return new FramedSnappyCompressorOutputStream(out); 647 } 648 649 if (LZ4_BLOCK.equalsIgnoreCase(name)) { 650 return new BlockLZ4CompressorOutputStream(out); 651 } 652 653 if (LZ4_FRAMED.equalsIgnoreCase(name)) { 654 return new FramedLZ4CompressorOutputStream(out); 655 } 656 657 } catch (final IOException e) { 658 throw new CompressorException("Could not create CompressorOutputStream", e); 659 } 660 final CompressorStreamProvider compressorStreamProvider = getCompressorOutputStreamProviders().get(toKey(name)); 661 if (compressorStreamProvider != null) { 662 return compressorStreamProvider.createCompressorOutputStream(name, out); 663 } 664 throw new CompressorException("Compressor: " + name + " not found."); 665 } 666 667 public SortedMap<String, CompressorStreamProvider> getCompressorInputStreamProviders() { 668 if (compressorInputStreamProviders == null) { 669 compressorInputStreamProviders = Collections 670 .unmodifiableSortedMap(findAvailableCompressorInputStreamProviders()); 671 } 672 return compressorInputStreamProviders; 673 } 674 675 public SortedMap<String, CompressorStreamProvider> getCompressorOutputStreamProviders() { 676 if (compressorOutputStreamProviders == null) { 677 compressorOutputStreamProviders = Collections 678 .unmodifiableSortedMap(findAvailableCompressorOutputStreamProviders()); 679 } 680 return compressorOutputStreamProviders; 681 } 682 683 // For Unit tests 684 boolean getDecompressConcatenated() { 685 return decompressConcatenated; 686 } 687 688 public Boolean getDecompressUntilEOF() { 689 return decompressUntilEOF; 690 } 691 692 @Override 693 public Set<String> getInputStreamCompressorNames() { 694 return Sets.newHashSet(GZIP, BROTLI, BZIP2, XZ, LZMA, PACK200, DEFLATE, SNAPPY_RAW, SNAPPY_FRAMED, Z, LZ4_BLOCK, 695 LZ4_FRAMED); 696 } 697 698 @Override 699 public Set<String> getOutputStreamCompressorNames() { 700 return Sets.newHashSet(GZIP, BZIP2, XZ, LZMA, PACK200, DEFLATE, SNAPPY_FRAMED, LZ4_BLOCK, LZ4_FRAMED); 701 } 702 703 /** 704 * Whether to decompress the full input or only the first stream in formats 705 * supporting multiple concatenated input streams. 706 * 707 * <p> 708 * This setting applies to the gzip, bzip2 and xz formats only. 709 * </p> 710 * 711 * @param decompressConcatenated 712 * if true, decompress until the end of the input; if false, stop 713 * after the first stream and leave the input position to point 714 * to the next byte after the stream 715 * @since 1.5 716 * @deprecated 1.10 use the {@link #CompressorStreamFactory(boolean)} 717 * constructor instead 718 * @throws IllegalStateException 719 * if the constructor {@link #CompressorStreamFactory(boolean)} 720 * was used to create the factory 721 */ 722 @Deprecated 723 public void setDecompressConcatenated(final boolean decompressConcatenated) { 724 if (this.decompressUntilEOF != null) { 725 throw new IllegalStateException("Cannot override the setting defined by the constructor"); 726 } 727 this.decompressConcatenated = decompressConcatenated; 728 } 729 730}