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 6c0ffcb32 [COMPRESS-695] Ability to use different InputStreams for 
Zstd (#655)
6c0ffcb32 is described below

commit 6c0ffcb329c69c721b2104a2dd349643c80dd5b8
Author: mehmet-karaman <mehmet.kara...@advantest.com>
AuthorDate: Sun Mar 23 15:04:33 2025 +0100

    [COMPRESS-695] Ability to use different InputStreams for Zstd (#655)
    
    * Adjusted the ZipFile and the Builder. Added a Test for checking both.
    * Implemented PR Comments.
    * Fix Javadoc and checkstyle problem
---
 .../commons/compress/archivers/zip/ZipFile.java    | 43 ++++++++++++++--
 .../harmony/unpack200/bytecode/Attribute.java      |  2 +-
 .../compress/archivers/zip/ZipFileTest.java        | 57 ++++++++++++++++++++++
 3 files changed, 97 insertions(+), 5 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java 
b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
index cb5e482ab..c0bfd7c80 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
@@ -65,6 +65,7 @@
 import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.build.AbstractOrigin.ByteArrayOrigin;
 import org.apache.commons.io.build.AbstractStreamBuilder;
+import org.apache.commons.io.function.IOFunction;
 import org.apache.commons.io.function.IOStream;
 import org.apache.commons.io.input.BoundedInputStream;
 
@@ -138,6 +139,7 @@ public static class Builder extends 
AbstractStreamBuilder<ZipFile, Builder> {
         private boolean useUnicodeExtraFields = true;
         private boolean ignoreLocalFileHeader;
         private long maxNumberOfDisks = 1;
+        private IOFunction<InputStream, InputStream> zstdInputStream = 
ZstdCompressorInputStream::new;
 
         /**
          * Constructs a new instance.
@@ -167,7 +169,24 @@ public ZipFile get() throws IOException {
                 actualDescription = path.toString();
             }
             final boolean closeOnError = seekableByteChannel != null;
-            return new ZipFile(actualChannel, actualDescription, getCharset(), 
useUnicodeExtraFields, closeOnError, ignoreLocalFileHeader);
+            return new ZipFile(actualChannel, actualDescription, getCharset(), 
useUnicodeExtraFields, closeOnError, ignoreLocalFileHeader, zstdInputStream);
+        }
+
+        /**
+         * This method sets the {@link IOFunction} which will be used the 
create an
+         * {@link InputStream}, which could be used to replace the officially 
supported
+         * ZSTD compression library.
+         *
+         * @param zstdInpStreamFactory the IOFunction which gives the ability 
to return
+         *                             a different InputStream for Zstd 
compression, if
+         *                             parameter is null than it will be set 
to default.
+         * @return {@code this} instance
+         * @since 1.28.0
+         */
+        public Builder setZstdInputStreamFactory(IOFunction<InputStream, 
InputStream> zstdInpStreamFactory) {
+            this.zstdInputStream = zstdInpStreamFactory == null ? 
ZstdCompressorInputStream::new : zstdInpStreamFactory;
+
+            return this;
         }
 
         /**
@@ -721,6 +740,8 @@ private static boolean tryToLocateSignature(final 
SeekableByteChannel channel, f
 
     private final ByteBuffer shortBbuf = ByteBuffer.wrap(shortBuf);
 
+    private final IOFunction<InputStream, InputStream> zstdInputStream;
+
     private long centralDirectoryStartDiskNumber;
 
     private long centralDirectoryStartRelativeOffset;
@@ -892,12 +913,13 @@ public ZipFile(final SeekableByteChannel channel, final 
String encoding) throws
     }
 
     private ZipFile(final SeekableByteChannel channel, final String 
channelDescription, final Charset encoding, final boolean useUnicodeExtraFields,
-            final boolean closeOnError, final boolean ignoreLocalFileHeader) 
throws IOException {
+            final boolean closeOnError, final boolean ignoreLocalFileHeader, 
IOFunction<InputStream, InputStream> zstdInputStream) throws IOException {
         this.isSplitZipArchive = channel instanceof 
ZipSplitReadOnlySeekableByteChannel;
         this.encoding = Charsets.toCharset(encoding, Builder.DEFAULT_CHARSET);
         this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
         this.useUnicodeExtraFields = useUnicodeExtraFields;
         this.archive = channel;
+        this.zstdInputStream = zstdInputStream;
         boolean success = false;
         try {
             final Map<ZipArchiveEntry, NameAndComment> entriesWithoutUTF8Flag 
= populateFromCentralDirectory();
@@ -966,7 +988,8 @@ public ZipFile(final SeekableByteChannel channel, final 
String channelDescriptio
 
     private ZipFile(final SeekableByteChannel channel, final String 
channelDescription, final String encoding, final boolean useUnicodeExtraFields,
             final boolean closeOnError, final boolean ignoreLocalFileHeader) 
throws IOException {
-        this(channel, channelDescription, Charsets.toCharset(encoding), 
useUnicodeExtraFields, closeOnError, ignoreLocalFileHeader);
+        this(channel, channelDescription, Charsets.toCharset(encoding), 
useUnicodeExtraFields, closeOnError,
+                ignoreLocalFileHeader, ZstdCompressorInputStream::new);
     }
 
     /**
@@ -1234,7 +1257,7 @@ public void close() throws IOException {
             return new Deflate64CompressorInputStream(is);
         case ZSTD:
         case ZSTD_DEPRECATED:
-            return new ZstdCompressorInputStream(is);
+            return createZstdInputStream(is);
         case XZ:
             return new XZCompressorInputStream(is);
         case AES_ENCRYPTED:
@@ -1254,6 +1277,18 @@ public void close() throws IOException {
         }
     }
 
+    /**
+     * Creates the appropriate InputStream for the ZSTD compression method.
+     *
+     * @param is the input stream which should be used for compression.
+     * @return the {@link InputStream} for handling the Zstd compression.
+     * @throws IOException if an I/O error occurs.
+     * @since 1.28.0
+     */
+    protected InputStream createZstdInputStream(final InputStream is) throws 
IOException {
+        return zstdInputStream.apply(is);
+    }
+
     /**
      * Gets the raw stream of the archive entry (compressed form).
      * <p>
diff --git 
a/src/main/java/org/apache/commons/compress/harmony/unpack200/bytecode/Attribute.java
 
b/src/main/java/org/apache/commons/compress/harmony/unpack200/bytecode/Attribute.java
index 1ba085b0a..d18ed20a6 100644
--- 
a/src/main/java/org/apache/commons/compress/harmony/unpack200/bytecode/Attribute.java
+++ 
b/src/main/java/org/apache/commons/compress/harmony/unpack200/bytecode/Attribute.java
@@ -126,7 +126,7 @@ protected void resolve(final ClassConstantPool pool) {
      * Writes this body to the given output stream.
      *
      * @param out the output.
-     * @throws IOException
+     * @throws IOException if an I/O error occurs.
      */
     protected abstract void writeBody(DataOutputStream out) throws IOException;
 
diff --git 
a/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java 
b/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
index 8f4e013f4..ebc4b7c0d 100644
--- a/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java
@@ -66,8 +66,36 @@
 import org.junit.jupiter.api.Assumptions;
 import org.junit.jupiter.api.Test;
 
+import io.airlift.compress.zstd.ZstdInputStream;
+
 public class ZipFileTest extends AbstractTest {
 
+    /**
+     * This Class simulates the case where the Zip File uses the 
aircompressors {@link ZstdInputStream}
+     */
+    private final class AirliftZstdZipFile extends ZipFile {
+        private boolean used;
+
+        private AirliftZstdZipFile(final File file) throws IOException {
+            super(file);
+        }
+
+        protected InputStream createZstdInputStream(final InputStream is) 
throws IOException {
+            return new ZstdInputStream(is) {
+
+                @Override
+                public int read(final byte[] outputBuffer, final int 
outputOffset, final int outputLength) throws IOException {
+                    used = true;
+                    return super.read(outputBuffer, outputOffset, 
outputLength);
+                }
+            };
+        }
+
+        public boolean isUsed() {
+            return used;
+        }
+    }
+
     private static final int OUT_OF_MEMORY = 137;
 
     private static void assertEntryName(final ArrayList<ZipArchiveEntry> 
entries, final int index, final String expectedName) {
@@ -382,6 +410,35 @@ public void testDuplicateEntry() throws Exception {
         }
     }
 
+    @Test
+    public void testAlternativeZstdInputStream() throws Exception {
+        final File archive = getFile("COMPRESS-692/compress-692.zip");
+        try (AirliftZstdZipFile zf = new AirliftZstdZipFile(archive)) {
+            final byte[] buffer = new byte[7000];
+            final ZipArchiveEntry ze = zf.getEntry("dolor.txt");
+            assertNotNull(ze);
+            try (InputStream inputStream = zf.getInputStream(ze)) {
+                assertNotNull(inputStream);
+                assertFalse(zf.isUsed());
+                final int bytesRead = 
org.apache.commons.compress.utils.IOUtils.readFully(inputStream, buffer);
+                assertEquals(6066, bytesRead);
+                assertTrue(zf.isUsed());
+            }
+        }
+
+        try (ZipFile builtZipFile = 
ZipFile.builder().setPath(archive.getAbsolutePath()).setZstdInputStreamFactory(ZstdInputStream::new).get())
 {
+            final byte[] buffer = new byte[7000];
+            final ZipArchiveEntry ze = builtZipFile.getEntry("dolor.txt");
+            assertNotNull(ze);
+            try (InputStream inputStream = builtZipFile.getInputStream(ze)) {
+                assertTrue(inputStream instanceof ZstdInputStream);
+                assertNotNull(inputStream);
+                final int bytesRead = 
org.apache.commons.compress.utils.IOUtils.readFully(inputStream, buffer);
+                assertEquals(6066, bytesRead);
+            }
+        }
+    }
+
     /**
      * Test entries alignment.
      */

Reply via email to