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 * https://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.xz; 020 021import java.io.IOException; 022import java.io.OutputStream; 023 024import org.apache.commons.compress.compressors.CompressorOutputStream; 025import org.apache.commons.io.build.AbstractStreamBuilder; 026import org.tukaani.xz.LZMA2Options; 027import org.tukaani.xz.XZOutputStream; 028 029// @formatter:off 030/** 031 * Compresses an output stream using the XZ and LZMA2 compression options. 032 * <p> 033 * For example: 034 * </p> 035 * <pre>{@code 036 * XZCompressorOutputStream s = XZCompressorOutputStream.builder() 037 * .setPath(path) 038 * .setLzma2Options(new LZMA2Options(...)) 039 * .get(); 040 * } 041 * </pre> 042 * 043 * <h2>Calling flush</h2> 044 * <p> 045 * Calling {@link #flush()} flushes the encoder and calls {@code outputStream.flush()}. All buffered pending data will then be decompressible from the output 046 * stream. Calling this function very often may increase the compressed file size a lot. 047 * </p> 048 * 049 * @since 1.4 050 */ 051// @formatter:on 052public class XZCompressorOutputStream extends CompressorOutputStream<XZOutputStream> { 053 054 // @formatter:off 055 /** 056 * Builds a new {@link XZCompressorOutputStream}. 057 * 058 * <p> 059 * For example: 060 * </p> 061 * <pre>{@code 062 * XZCompressorOutputStream s = XZCompressorOutputStream.builder() 063 * .setPath(path) 064 * .setLzma2Options(new LZMA2Options(...)) 065 * .get(); 066 * } 067 * </pre> 068 * 069 * @see #get() 070 * @since 1.28.0 071 */ 072 // @formatter:on 073 public static class Builder extends AbstractStreamBuilder<XZCompressorOutputStream, Builder> { 074 075 private LZMA2Options lzma2Options = new LZMA2Options(); 076 077 /** 078 * Constructs a new builder of {@link XZCompressorOutputStream}. 079 */ 080 public Builder() { 081 // empty 082 } 083 084 @Override 085 public XZCompressorOutputStream get() throws IOException { 086 return new XZCompressorOutputStream(this); 087 } 088 089 /** 090 * Sets LZMA options. 091 * <p> 092 * Passing {@code null} resets to the default value {@link LZMA2Options#LZMA2Options()}. 093 * </p> 094 * 095 * @param lzma2Options LZMA options. 096 * @return this instance. 097 */ 098 public Builder setLzma2Options(final LZMA2Options lzma2Options) { 099 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}