1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * https://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.commons.compress.compressors.xz; 20 21 import java.io.IOException; 22 import java.io.OutputStream; 23 24 import org.apache.commons.compress.compressors.CompressorOutputStream; 25 import org.apache.commons.io.build.AbstractStreamBuilder; 26 import org.tukaani.xz.LZMA2Options; 27 import org.tukaani.xz.XZOutputStream; 28 29 // @formatter:off 30 /** 31 * Compresses an output stream using the XZ and LZMA2 compression options. 32 * <p> 33 * For example: 34 * </p> 35 * <pre>{@code 36 * XZCompressorOutputStream s = XZCompressorOutputStream.builder() 37 * .setPath(path) 38 * .setLzma2Options(new LZMA2Options(...)) 39 * .get(); 40 * } 41 * </pre> 42 * 43 * <h2>Calling flush</h2> 44 * <p> 45 * Calling {@link #flush()} flushes the encoder and calls {@code outputStream.flush()}. All buffered pending data will then be decompressible from the output 46 * stream. Calling this function very often may increase the compressed file size a lot. 47 * </p> 48 * 49 * @since 1.4 50 */ 51 // @formatter:on 52 public class XZCompressorOutputStream extends CompressorOutputStream<XZOutputStream> { 53 54 // @formatter:off 55 /** 56 * Builds a new {@link XZCompressorOutputStream}. 57 * 58 * <p> 59 * For example: 60 * </p> 61 * <pre>{@code 62 * XZCompressorOutputStream s = XZCompressorOutputStream.builder() 63 * .setPath(path) 64 * .setLzma2Options(new LZMA2Options(...)) 65 * .get(); 66 * } 67 * </pre> 68 * 69 * @see #get() 70 * @since 1.28.0 71 */ 72 // @formatter:on 73 public static class Builder extends AbstractStreamBuilder<XZCompressorOutputStream, Builder> { 74 75 private LZMA2Options lzma2Options = new LZMA2Options(); 76 77 /** 78 * Constructs a new builder of {@link XZCompressorOutputStream}. 79 */ 80 public Builder() { 81 // empty 82 } 83 84 @Override 85 public XZCompressorOutputStream get() throws IOException { 86 return new XZCompressorOutputStream(this); 87 } 88 89 /** 90 * Sets LZMA options. 91 * <p> 92 * Passing {@code null} resets to the default value {@link LZMA2Options#LZMA2Options()}. 93 * </p> 94 * 95 * @param lzma2Options LZMA options. 96 * @return this instance. 97 */ 98 public Builder setLzma2Options(final LZMA2Options lzma2Options) { 99 this.lzma2Options = lzma2Options != null ? lzma2Options : new LZMA2Options(); 100 return this; 101 } 102 103 } 104 105 /** 106 * Constructs a new builder of {@link XZCompressorOutputStream}. 107 * 108 * @return a new builder of {@link XZCompressorOutputStream}. 109 * @since 1.28.0 110 */ 111 public static Builder builder() { 112 return new Builder(); 113 } 114 115 @SuppressWarnings("resource") // Caller closes 116 private XZCompressorOutputStream(final Builder builder) throws IOException { 117 super(new XZOutputStream(builder.getOutputStream(), builder.lzma2Options)); 118 } 119 120 /** 121 * Creates a new XZ compressor using the default LZMA2 options. This is equivalent to {@code XZCompressorOutputStream(outputStream, 6)}. 122 * 123 * @param outputStream the stream to wrap 124 * @throws IOException on error 125 */ 126 public XZCompressorOutputStream(final OutputStream outputStream) throws IOException { 127 this(builder().setOutputStream(outputStream)); 128 } 129 130 /** 131 * Creates a new XZ compressor using the specified LZMA2 preset level. 132 * <p> 133 * The presets 0-3 are fast presets with medium compression. The presets 4-6 are fairly slow presets with high compression. The default preset is 6. 134 * </p> 135 * <p> 136 * The presets 7-9 are like the preset 6 but use bigger dictionaries and have higher compressor and decompressor memory requirements. Unless the 137 * uncompressed size of the file exceeds 8 MiB, 16 MiB, or 32 MiB, it is waste of memory to use the presets 7, 8, or 9, respectively. 138 * </p> 139 * 140 * @param outputStream the stream to wrap 141 * @param preset the preset 142 * @throws IOException on error 143 * @deprecated Use {@link #builder()}. 144 */ 145 @Deprecated 146 @SuppressWarnings("resource") // Caller closes 147 public XZCompressorOutputStream(final OutputStream outputStream, final int preset) throws IOException { 148 super(new XZOutputStream(outputStream, new LZMA2Options(preset))); 149 } 150 151 /** 152 * Finishes compression without closing the underlying stream. No more data can be written to this stream after finishing. 153 * 154 * @throws IOException on error 155 */ 156 @Override 157 @SuppressWarnings("resource") // instance variable access 158 public void finish() throws IOException { 159 out().finish(); 160 } 161 162 @Override 163 public void write(final byte[] buf, final int off, final int len) throws IOException { 164 out.write(buf, off, len); 165 } 166 167 }