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 }