This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git


The following commit(s) were added to refs/heads/master by this push:
     new 55ecb7f1b Add 
org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream.builder/Builder()
55ecb7f1b is described below

commit 55ecb7f1b8f58408c525fef742dcf27d51efebf3
Author: Gary D. Gregory <garydgreg...@gmail.com>
AuthorDate: Wed Apr 16 14:52:26 2025 -0400

    Add 
org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream.builder/Builder()
    
    - Add 
org.apache.commons.compress.compressors.lzma.LZMACompressorOutputStream.builder/Builder()
    - Add LZMACompressorOutputStreamTest
    - Deprecate
    
org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream.LZMACompressorInputStream(InputStream,
    int)
---
 src/changes/changes.xml                            |  2 +
 .../compressors/CompressorStreamFactory.java       |  2 +-
 .../lzma/LZMACompressorInputStream.java            | 76 +++++++++++++++++---
 .../lzma/LZMACompressorOutputStream.java           | 71 ++++++++++++++++++-
 .../lzma/LZMACompressorOutputStreamTest.java       | 82 ++++++++++++++++++++++
 5 files changed, 222 insertions(+), 11 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 0ad2a5b33..6532f4e8d 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -109,6 +109,8 @@ The <action> type attribute can be add,update,fix,remove.
       <action type="add" dev="ggregory" due-to="Gary Gregory" 
issue="COMPRESS-695">Add 
ZipArchiveInputStream.createZstdInputStream(InputStream) to provide a different 
InputStream implementation for Zstandard (Zstd) #649.</action>
       <action type="add" dev="ggregory" due-to="Gary Gregory">Add 
org.apache.commons.compress.harmony.pack200.Pack200Exception.Pack200Exception(String,
 Throwable).</action>
       <action type="add" issue="COMPRESS-697" dev="ggregory" due-to="Fredrik 
Kjellberg, Gary Gregory">Move BitStream.nextBit() method to BitInputStream 
#663.</action>
+      <action type="add" dev="ggregory" due-to="Gary Gregory">Add 
org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream.builder/Builder().</action>
+      <action type="add" dev="ggregory" due-to="Gary Gregory">Add 
org.apache.commons.compress.compressors.lzma.LZMACompressorOutputStream.builder/Builder().</action>
       <!-- UPDATE -->
       <action type="update" dev="sebb">Bump Commons Parent from 79 to 
81</action>
       <action type="update" dev="ggregory" due-to="Dependabot, Gary 
Gregory">Bump org.apache.commons:commons-parent from 72 to 79 #563, #567, #574, 
#582, #587, #595.</action>
diff --git 
a/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
 
b/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
index e54b15179..c6b1b0993 100644
--- 
a/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
+++ 
b/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
@@ -619,7 +619,7 @@ public CompressorInputStream 
createCompressorInputStream(final String name, fina
                 if (!LZMAUtils.isLZMACompressionAvailable()) {
                     throw new CompressorException("LZMA compression is not 
available" + YOU_NEED_XZ_JAVA);
                 }
-                return new LZMACompressorInputStream(in, memoryLimitInKb);
+                return 
LZMACompressorInputStream.builder().setInputStream(in).setMemoryLimitKiB(memoryLimitInKb).get();
             }
             if (PACK200.equalsIgnoreCase(name)) {
                 return new Pack200CompressorInputStream(in);
diff --git 
a/src/main/java/org/apache/commons/compress/compressors/lzma/LZMACompressorInputStream.java
 
b/src/main/java/org/apache/commons/compress/compressors/lzma/LZMACompressorInputStream.java
index 48e5b3cd2..0f5c04362 100644
--- 
a/src/main/java/org/apache/commons/compress/compressors/lzma/LZMACompressorInputStream.java
+++ 
b/src/main/java/org/apache/commons/compress/compressors/lzma/LZMACompressorInputStream.java
@@ -24,7 +24,9 @@
 import org.apache.commons.compress.MemoryLimitException;
 import org.apache.commons.compress.compressors.CompressorInputStream;
 import org.apache.commons.compress.utils.InputStreamStatistics;
+import org.apache.commons.io.build.AbstractStreamBuilder;
 import org.apache.commons.io.input.BoundedInputStream;
+import org.tukaani.xz.LZMA2Options;
 import org.tukaani.xz.LZMAInputStream;
 
 /**
@@ -34,6 +36,57 @@
  */
 public class LZMACompressorInputStream extends CompressorInputStream 
implements InputStreamStatistics {
 
+    // @formatter:off
+    /**
+     * Builds a new {@link LZMACompressorInputStream}.
+     *
+     * <p>
+     * For example:
+     * </p>
+     * <pre>{@code
+     * LZMACompressorOutputStream s = LZMACompressorInputStream.builder()
+     *   .setPath(path)
+     *   .get();
+     * }
+     * </pre>
+     *
+     * @see #get()
+     * @see LZMA2Options
+     * @since 1.28.0
+     */
+    // @formatter:on
+    public static class Builder extends 
AbstractStreamBuilder<LZMACompressorInputStream, Builder> {
+
+        private int memoryLimitKiB = -1;
+
+        @Override
+        public LZMACompressorInputStream get() throws IOException {
+            return new LZMACompressorInputStream(this);
+        }
+
+        /**
+         * Sets a working memory threshold in kibibytes (KiB).
+         *
+         * @param memoryLimitKiB Sets a working memory threshold in kibibytes 
(KiB). Processing throws MemoryLimitException if memory use is above this
+         *                       threshold.
+         * @return this instance.
+         */
+        public Builder setMemoryLimitKiB(int memoryLimitKiB) {
+            this.memoryLimitKiB = memoryLimitKiB;
+            return this;
+        }
+    }
+
+    /**
+     * Constructs a new builder of {@link LZMACompressorOutputStream}.
+     *
+     * @return a new builder of {@link LZMACompressorOutputStream}.
+     * @since 1.28.0
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
     /**
      * Checks if the signature matches what is expected for an LZMA file.
      *
@@ -50,6 +103,16 @@ public static boolean matches(final byte[] signature, final 
int length) {
 
     private final InputStream in;
 
+    @SuppressWarnings("resource") // Caller closes
+    private LZMACompressorInputStream(final Builder builder) throws 
IOException {
+        try {
+            in = new LZMAInputStream(countingStream = 
BoundedInputStream.builder().setInputStream(builder.getInputStream()).get(), 
builder.memoryLimitKiB);
+        } catch (final org.tukaani.xz.MemoryLimitException e) {
+            // convert to Commons Compress exception
+            throw new MemoryLimitException(e.getMemoryNeeded(), 
e.getMemoryLimit(), (Throwable) e);
+        }
+    }
+
     /**
      * Creates a new input stream that decompresses LZMA-compressed data from 
the specified input stream.
      *
@@ -58,26 +121,23 @@ public static boolean matches(final byte[] signature, 
final int length) {
      *                     this implementation, or the underlying {@code 
inputStream} throws an exception
      */
     public LZMACompressorInputStream(final InputStream inputStream) throws 
IOException {
-        in = new LZMAInputStream(countingStream = 
BoundedInputStream.builder().setInputStream(inputStream).get(), -1);
+        this(builder().setInputStream(inputStream));
     }
 
     /**
      * Creates a new input stream that decompresses LZMA-compressed data from 
the specified input stream.
      *
      * @param inputStream     where to read the compressed data
-     * @param memoryLimitKiB calculated memory use threshold in kibibytes 
(KiB). Throws MemoryLimitException if calculate memory use is above this 
threshold
+     * @param memoryLimitKiB Sets a working memory threshold in kibibytes 
(KiB). Processing throws MemoryLimitException if memory use is above this 
threshold.
      * @throws IOException if the input is not in the .lzma format, the input 
is corrupt or truncated, the .lzma headers specify sizes that are not supported 
by
      *                     this implementation, or the underlying {@code 
inputStream} throws an exception
      *
      * @since 1.14
+     * @deprecated Use {@link #builder()}.
      */
+    @Deprecated
     public LZMACompressorInputStream(final InputStream inputStream, final int 
memoryLimitKiB) throws IOException {
-        try {
-            in = new LZMAInputStream(countingStream = 
BoundedInputStream.builder().setInputStream(inputStream).get(), memoryLimitKiB);
-        } catch (final org.tukaani.xz.MemoryLimitException e) {
-            // convert to commons-compress exception
-            throw new MemoryLimitException(e.getMemoryNeeded(), 
e.getMemoryLimit(), (Throwable) e);
-        }
+        
this(builder().setInputStream(inputStream).setMemoryLimitKiB(memoryLimitKiB));
     }
 
     /** {@inheritDoc} */
diff --git 
a/src/main/java/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStream.java
 
b/src/main/java/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStream.java
index 082fe81b1..4aae9eb89 100644
--- 
a/src/main/java/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStream.java
+++ 
b/src/main/java/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStream.java
@@ -22,6 +22,7 @@
 import java.io.OutputStream;
 
 import org.apache.commons.compress.compressors.CompressorOutputStream;
+import org.apache.commons.io.build.AbstractStreamBuilder;
 import org.tukaani.xz.LZMA2Options;
 import org.tukaani.xz.LZMAOutputStream;
 
@@ -32,15 +33,81 @@
  */
 public class LZMACompressorOutputStream extends 
CompressorOutputStream<LZMAOutputStream> {
 
+    // @formatter:off
+    /**
+     * Builds a new {@link LZMACompressorOutputStream}.
+     *
+     * <p>
+     * For example:
+     * </p>
+     * <pre>{@code
+     * LZMACompressorOutputStream s = LZMACompressorOutputStream.builder()
+     *   .setPath(path)
+     *   .setLzma2Options(new LZMA2Options(...))
+     *   .get();
+     * }
+     * </pre>
+     *
+     * @see #get()
+     * @see LZMA2Options
+     * @since 1.28.0
+     */
+    // @formatter:on
+    public static class Builder extends 
AbstractStreamBuilder<LZMACompressorOutputStream, Builder> {
+
+        private LZMA2Options lzma2Options = new LZMA2Options();
+
+        /**
+         * Constructs a new builder of {@link LZMACompressorOutputStream}.
+         */
+        public Builder() {
+            // empty
+        }
+
+        @Override
+        public LZMACompressorOutputStream get() throws IOException {
+            return new LZMACompressorOutputStream(this);
+        }
+
+        /**
+         * Sets LZMA options.
+         * <p>
+         * Passing {@code null} resets to the default value {@link 
LZMA2Options#LZMA2Options()}.
+         * </p>
+         *
+         * @param lzma2Options LZMA options.
+         * @return this instance.
+         */
+        public Builder setLzma2Options(final LZMA2Options lzma2Options) {
+            this.lzma2Options = lzma2Options != null ? lzma2Options : new 
LZMA2Options();
+            return this;
+        }
+
+    }
+
+    /**
+     * Constructs a new builder of {@link LZMACompressorOutputStream}.
+     *
+     * @return a new builder of {@link LZMACompressorOutputStream}.
+     * @since 1.28.0
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    @SuppressWarnings("resource") // Caller closes
+    private LZMACompressorOutputStream(final Builder builder) throws 
IOException {
+        super(new LZMAOutputStream(builder.getOutputStream(), 
builder.lzma2Options, -1));
+    }
+
     /**
      * Creates a LZMA compressor.
      *
      * @param outputStream the stream to wrap
      * @throws IOException on error
      */
-    @SuppressWarnings("resource") // Caller closes
     public LZMACompressorOutputStream(final OutputStream outputStream) throws 
IOException {
-        super(new LZMAOutputStream(outputStream, new LZMA2Options(), -1));
+        this(builder().setOutputStream(outputStream));
     }
 
     /**
diff --git 
a/src/test/java/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStreamTest.java
 
b/src/test/java/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStreamTest.java
new file mode 100644
index 000000000..7b8287702
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/compress/compressors/lzma/LZMACompressorOutputStreamTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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
+ *
+ *   https://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.lzma;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.tukaani.xz.LZMA2Options;
+
+/**
+ * Tests {@link LZMACompressorOutputStream}.
+ */
+public class LZMACompressorOutputStreamTest {
+
+    @TempDir
+    static Path tempDir;
+
+    private void roundtrip(final Path outPath, final LZMA2Options options) 
throws IOException {
+        final String data = "Hello World!";
+        try (LZMACompressorOutputStream out = 
LZMACompressorOutputStream.builder().setPath(outPath).setLzma2Options(options).get())
 {
+            out.writeUtf8(data);
+        }
+        try (LZMACompressorInputStream out = 
LZMACompressorInputStream.builder().setPath(outPath).setMemoryLimitKiB(-1).get())
 {
+            assertEquals(data, IOUtils.toString(out, StandardCharsets.UTF_8));
+        }
+    }
+
+    @Test
+    public void testBuilderOptionsAll() throws IOException {
+        final int dictSize = LZMA2Options.DICT_SIZE_MAX;
+        final int lc = LZMA2Options.LC_LP_MAX - 4;
+        final int lp = LZMA2Options.LC_LP_MAX - 4;
+        final int pb = LZMA2Options.PB_MAX;
+        final int mode = LZMA2Options.MODE_NORMAL;
+        final int niceLen = LZMA2Options.NICE_LEN_MAX;
+        final int mf = LZMA2Options.MF_BT4;
+        final int depthLimit = 50;
+        roundtrip(tempDir.resolve("out.lzma"), new LZMA2Options(dictSize, lc, 
lp, pb, mode, niceLen, mf, depthLimit));
+    }
+
+    @Test
+    public void testBuilderOptionsDefault() throws IOException {
+        roundtrip(tempDir.resolve("out.lzma"), new LZMA2Options());
+    }
+
+    @Test
+    public void testBuilderOptionsPreset() throws IOException {
+        roundtrip(tempDir.resolve("out.lzma"), new 
LZMA2Options(LZMA2Options.PRESET_MAX));
+    }
+
+    @Test
+    public void testBuilderPath() throws IOException {
+        // This test does not use LZMA2Options
+        final Path outPath = tempDir.resolve("out.lzma");
+        try (LZMACompressorOutputStream out = 
LZMACompressorOutputStream.builder().setPath(outPath).get()) {
+            out.writeUtf8("Hello World!");
+        }
+    }
+}

Reply via email to