This is an automated email from the ASF dual-hosted git repository. pkarwasz pushed a commit to branch feat/archive-builders in repository https://gitbox.apache.org/repos/asf/commons-compress.git
commit d4bcf0e7754bef7cbde7a85ef3fd0de058648db1 Author: Piotr P. Karwasz <pkarwasz-git...@apache.org> AuthorDate: Fri Sep 12 18:37:47 2025 +0200 feat: add builder for `CpioArchiveInputStream` Introduce a builder for `CpioArchiveInputStream` and refactor existing constructor calls to use it. --- .../compress/archivers/ArchiveStreamFactory.java | 5 +- .../archivers/cpio/CpioArchiveInputStream.java | 79 +++++++++++++++++++--- .../archivers/cpio/CpioArchiveOutputStream.java | 4 +- .../commons/compress/archivers/cpio/CpioUtil.java | 3 +- .../commons/compress/archivers/CpioTest.java | 10 +-- .../archivers/cpio/CpioArchiveInputStreamTest.java | 31 +++++---- .../cpio/CpioArchiveOutputStreamTest.java | 2 +- .../compress/archivers/cpio/CpioArchiveTest.java | 18 +++-- 8 files changed, 111 insertions(+), 41 deletions(-) diff --git a/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java b/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java index 8559b8bd1..64b76288f 100644 --- a/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java +++ b/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java @@ -458,10 +458,11 @@ public <I extends ArchiveInputStream<? extends ArchiveEntry>> I createArchiveInp return (I) new JarArchiveInputStream(in); } if (CPIO.equalsIgnoreCase(archiverName)) { + final CpioArchiveInputStream.Builder cpioBuilder = CpioArchiveInputStream.builder().setInputStream(in); if (actualEncoding != null) { - return (I) new CpioArchiveInputStream(in, actualEncoding); + cpioBuilder.setCharset(actualEncoding); } - return (I) new CpioArchiveInputStream(in); + return (I) cpioBuilder.get(); } if (DUMP.equalsIgnoreCase(archiverName)) { if (actualEncoding != null) { diff --git a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java index 85c137725..e2008005b 100644 --- a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java @@ -64,6 +64,48 @@ */ public class CpioArchiveInputStream extends ArchiveInputStream<CpioArchiveEntry> implements CpioConstants { + /** + * Builds a new {@link CpioArchiveInputStream}. + * <p> + * For example: + * </p> + * <pre>{@code + * CpioArchiveInputStream in = CpioArchiveInputStream.builder() + * .setBlockSize(1024) + * .setPath(inputPath) + * .setCharset(StandardCharsets.UTF_8) + * .get(); + * }</pre> + * @since 1.29.0 + */ + public static final class Builder extends ArchiveInputStream.Builder<CpioArchiveInputStream, Builder> { + + private int blockSize = BLOCK_SIZE; + + private Builder() { + setCharset(CpioUtil.DEFAULT_CHARSET); + } + + /** + * Sets the block size of the archive. + * <p> + * Default value is {@value CpioConstants#BLOCK_SIZE}. + * </p> + * + * @param blockSize The block size must be bigger than 0 + * @return this + */ + public Builder setBlockSize(final int blockSize) { + this.blockSize = blockSize; + return asThis(); + } + + @Override + public CpioArchiveInputStream get() throws IOException { + return new CpioArchiveInputStream(this); + } + } + /** * Checks if the signature matches one of the following magic values: * @@ -117,6 +159,16 @@ public static boolean matches(final byte[] signature, final int length) { return false; } + /** + * Creates a new builder. + * + * @return A new builder + * @since 1.29.0 + */ + public static Builder builder() { + return new Builder(); + } + private boolean closed; private CpioArchiveEntry entry; @@ -150,7 +202,7 @@ public static boolean matches(final byte[] signature, final int length) { * @param in The cpio stream */ public CpioArchiveInputStream(final InputStream in) { - this(in, BLOCK_SIZE, CpioUtil.DEFAULT_CHARSET_NAME); + this(in, builder()); } /** @@ -161,7 +213,7 @@ public CpioArchiveInputStream(final InputStream in) { * @since 1.5 */ public CpioArchiveInputStream(final InputStream in, final int blockSize) { - this(in, blockSize, CpioUtil.DEFAULT_CHARSET_NAME); + this(in, builder().setBlockSize(blockSize)); } /** @@ -174,13 +226,7 @@ public CpioArchiveInputStream(final InputStream in, final int blockSize) { * @since 1.6 */ public CpioArchiveInputStream(final InputStream in, final int blockSize, final String encoding) { - super(in, encoding); - this.in = in; - if (blockSize <= 0) { - throw new IllegalArgumentException("blockSize must be bigger than 0"); - } - this.blockSize = blockSize; - this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); + this(in, builder().setBlockSize(blockSize).setCharset(encoding)); } /** @@ -191,7 +237,20 @@ public CpioArchiveInputStream(final InputStream in, final int blockSize, final S * @since 1.6 */ public CpioArchiveInputStream(final InputStream in, final String encoding) { - this(in, BLOCK_SIZE, encoding); + this(in, builder().setCharset(encoding)); + } + + private CpioArchiveInputStream(final Builder builder) throws IOException { + this(builder.getInputStream(), builder); + } + + private CpioArchiveInputStream(final InputStream in, final Builder builder) { + super(in, builder.getCharset()); + if (builder.blockSize <= 0) { + throw new IllegalArgumentException("blockSize must be bigger than 0"); + } + this.blockSize = builder.blockSize; + this.zipEncoding = ZipEncodingHelper.getZipEncoding(builder.getCharset()); } /** diff --git a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java index d03e14807..e0e7d2361 100644 --- a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java @@ -116,7 +116,7 @@ public CpioArchiveOutputStream(final OutputStream out) { * @param format The format of the stream */ public CpioArchiveOutputStream(final OutputStream out, final short format) { - this(out, format, BLOCK_SIZE, CpioUtil.DEFAULT_CHARSET_NAME); + this(out, format, BLOCK_SIZE, CpioUtil.DEFAULT_CHARSET.name()); } /** @@ -128,7 +128,7 @@ public CpioArchiveOutputStream(final OutputStream out, final short format) { * @since 1.1 */ public CpioArchiveOutputStream(final OutputStream out, final short format, final int blockSize) { - this(out, format, blockSize, CpioUtil.DEFAULT_CHARSET_NAME); + this(out, format, blockSize, CpioUtil.DEFAULT_CHARSET.name()); } /** diff --git a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioUtil.java b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioUtil.java index 7c71ee1dd..a43409822 100644 --- a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioUtil.java +++ b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioUtil.java @@ -18,6 +18,7 @@ */ package org.apache.commons.compress.archivers.cpio; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -28,7 +29,7 @@ */ final class CpioUtil { - static final String DEFAULT_CHARSET_NAME = StandardCharsets.US_ASCII.name(); + static final Charset DEFAULT_CHARSET = StandardCharsets.US_ASCII; /** * Converts a byte array to a long. Halfwords can be swapped by setting swapHalfWord=true. diff --git a/src/test/java/org/apache/commons/compress/archivers/CpioTest.java b/src/test/java/org/apache/commons/compress/archivers/CpioTest.java index 1168e217f..72efa86a8 100644 --- a/src/test/java/org/apache/commons/compress/archivers/CpioTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/CpioTest.java @@ -120,7 +120,7 @@ void testDirectoryEntryFromFile() throws Exception { tos.closeArchiveEntry(); } final CpioArchiveEntry entryOut; - try (CpioArchiveInputStream tis = new CpioArchiveInputStream(Files.newInputStream(archive.toPath()))) { + try (CpioArchiveInputStream tis = CpioArchiveInputStream.builder().setFile(archive).get()) { entryOut = tis.getNextCPIOEntry(); } assertNotNull(entryOut); @@ -144,7 +144,7 @@ void testExplicitDirectoryEntry() throws Exception { tos.closeArchiveEntry(); } final CpioArchiveEntry out; - try (CpioArchiveInputStream tis = new CpioArchiveInputStream(Files.newInputStream(archive.toPath()))) { + try (CpioArchiveInputStream tis = CpioArchiveInputStream.builder().setFile(archive).get()) { out = tis.getNextCPIOEntry(); } assertNotNull(out); @@ -168,7 +168,7 @@ void testExplicitFileEntry() throws Exception { tos.closeArchiveEntry(); } final CpioArchiveEntry out; - try (CpioArchiveInputStream tis = new CpioArchiveInputStream(Files.newInputStream(archive.toPath()))) { + try (CpioArchiveInputStream tis = CpioArchiveInputStream.builder().setFile(archive).get()) { out = tis.getNextCPIOEntry(); } assertNotNull(out); @@ -189,7 +189,7 @@ void testFileEntryFromFile() throws Exception { tos.closeArchiveEntry(); } final CpioArchiveEntry out; - try (CpioArchiveInputStream tis = new CpioArchiveInputStream(Files.newInputStream(archive.toPath()))) { + try (CpioArchiveInputStream tis = CpioArchiveInputStream.builder().setFile(archive).get()) { out = tis.getNextCPIOEntry(); } assertNotNull(out); @@ -220,7 +220,7 @@ void testSymbolicLinkFileEntry() throws Exception { tos.closeArchiveEntry(); } final CpioArchiveEntry entry; - try (CpioArchiveInputStream tis = new CpioArchiveInputStream(Files.newInputStream(archive.toPath()))) { + try (CpioArchiveInputStream tis = CpioArchiveInputStream.builder().setFile(archive).get()) { entry = tis.getNextEntry(); assertEquals(nameLink, IOUtils.toString(tis, charset)); } diff --git a/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStreamTest.java b/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStreamTest.java index 2a0490909..b8eb5f5f9 100644 --- a/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStreamTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStreamTest.java @@ -22,9 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import org.apache.commons.compress.AbstractTest; @@ -52,7 +50,8 @@ void testCpioUnarchive() throws Exception { expected.append("<empty/>./test2.xml<?xml version=\"1.0\"?>\n"); expected.append("<empty/>\n"); final StringBuilder result = new StringBuilder(); - try (CpioArchiveInputStream in = new CpioArchiveInputStream(newInputStream("bla.cpio"))) { + try (CpioArchiveInputStream in = + CpioArchiveInputStream.builder().setURI(getURI("bla.cpio")).get()) { CpioArchiveEntry entry; while ((entry = in.getNextEntry()) != null) { result.append(entry.getName()); @@ -68,7 +67,9 @@ void testCpioUnarchive() throws Exception { @Test void testCpioUnarchiveCreatedByRedlineRpm() throws Exception { long count = 0; - try (CpioArchiveInputStream in = new CpioArchiveInputStream(newInputStream("redline.cpio"))) { + try (CpioArchiveInputStream in = CpioArchiveInputStream.builder() + .setURI(getURI("redline.cpio")) + .get()) { count = consumeEntries(in); } assertEquals(count, 1); @@ -77,7 +78,10 @@ void testCpioUnarchiveCreatedByRedlineRpm() throws Exception { @Test void testCpioUnarchiveMultibyteCharName() throws Exception { long count = 0; - try (CpioArchiveInputStream in = new CpioArchiveInputStream(newInputStream("COMPRESS-459.cpio"), StandardCharsets.UTF_8.name())) { + try (CpioArchiveInputStream in = CpioArchiveInputStream.builder() + .setURI(getURI("COMPRESS-459.cpio")) + .setCharset(StandardCharsets.UTF_8) + .get()) { count = consumeEntries(in); } assertEquals(2, count); @@ -105,7 +109,7 @@ void testEndOfFileInEntry_c_namesize_0x7FFFFFFF() throws Exception { // @formatter:on final byte[] data = new byte[header.getBytes(StandardCharsets.US_ASCII).length + 1]; System.arraycopy(header.getBytes(), 0, data, 0, header.getBytes().length); - try (CpioArchiveInputStream cpio = new CpioArchiveInputStream(new ByteArrayInputStream(data))) { + try (CpioArchiveInputStream cpio = CpioArchiveInputStream.builder().setByteArray(data).get()) { assertThrows(MemoryLimitException.class, () -> cpio.getNextEntry()); } } @@ -132,15 +136,16 @@ void testEndOfFileInEntry_c_namesize_0xFFFFFFFF() throws Exception { // @formatter:on final byte[] data = new byte[header.getBytes(StandardCharsets.US_ASCII).length + 1]; System.arraycopy(header.getBytes(), 0, data, 0, header.getBytes().length); - try (CpioArchiveInputStream cpio = new CpioArchiveInputStream(new ByteArrayInputStream(data))) { + try (CpioArchiveInputStream cpio = CpioArchiveInputStream.builder().setByteArray(data).get()) { assertThrows(ArchiveException.class, () -> cpio.getNextEntry()); } } @Test void testInvalidLongValueInMetadata() throws Exception { - try (InputStream in = newInputStream("org/apache/commons/compress/cpio/bad_long_value.cpio"); - CpioArchiveInputStream archive = new CpioArchiveInputStream(in)) { + try (CpioArchiveInputStream archive = CpioArchiveInputStream.builder() + .setURI(getURI("org/apache/commons/compress/cpio/bad_long_value.cpio")) + .get()) { assertThrows(IOException.class, archive::getNextEntry); } } @@ -148,8 +153,8 @@ void testInvalidLongValueInMetadata() throws Exception { @Test void testMultiByteReadConsistentlyReturnsMinusOneAtEof() throws Exception { final byte[] buf = new byte[2]; - try (InputStream in = newInputStream("bla.cpio"); - CpioArchiveInputStream archive = new CpioArchiveInputStream(in)) { + try (CpioArchiveInputStream archive = + CpioArchiveInputStream.builder().setURI(getURI("bla.cpio")).get()) { assertNotNull(archive.getNextEntry()); IOUtils.toByteArray(archive); assertEquals(-1, archive.read(buf)); @@ -159,8 +164,8 @@ void testMultiByteReadConsistentlyReturnsMinusOneAtEof() throws Exception { @Test void testSingleByteReadConsistentlyReturnsMinusOneAtEof() throws Exception { - try (InputStream in = newInputStream("bla.cpio"); - CpioArchiveInputStream archive = new CpioArchiveInputStream(in)) { + try (CpioArchiveInputStream archive = + CpioArchiveInputStream.builder().setURI(getURI("bla.cpio")).get()) { assertNotNull(archive.getNextEntry()); IOUtils.toByteArray(archive); assertEquals(-1, archive.read()); diff --git a/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStreamTest.java b/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStreamTest.java index 1dfc94371..7ec8d49bf 100644 --- a/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStreamTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStreamTest.java @@ -42,7 +42,7 @@ void testWriteOldBinary() throws Exception { outputStream.closeArchiveEntry(); } assertTrue(ref.isClosed()); - try (CpioArchiveInputStream in = new CpioArchiveInputStream(Files.newInputStream(output.toPath()))) { + try (CpioArchiveInputStream in = CpioArchiveInputStream.builder().setFile(output).get()) { final CpioArchiveEntry e = in.getNextCPIOEntry(); assertEquals("test1.xml", e.getName()); assertNull(in.getNextEntry()); diff --git a/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveTest.java b/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveTest.java index 805a0cef5..6df89bb2c 100644 --- a/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/cpio/CpioArchiveTest.java @@ -22,7 +22,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.util.stream.Stream; @@ -50,8 +49,10 @@ void utf18RoundtripTestCtor2() throws Exception { os.closeArchiveEntry(); } baos.close(); - try (ByteArrayInputStream bin = new ByteArrayInputStream(baos.toByteArray()); - CpioArchiveInputStream in = new CpioArchiveInputStream(bin, StandardCharsets.UTF_8.name())) { + try (CpioArchiveInputStream in = CpioArchiveInputStream.builder() + .setByteArray(baos.toByteArray()) + .setCharset(StandardCharsets.UTF_8) + .get()) { final CpioArchiveEntry entry = in.getNextEntry(); assertNotNull(entry); assertEquals("Test.txt", entry.getName()); @@ -74,8 +75,9 @@ public void utf18RoundtripTestCtor3(final short format) throws Exception { os.closeArchiveEntry(); } baos.close(); - try (ByteArrayInputStream bin = new ByteArrayInputStream(baos.toByteArray()); - CpioArchiveInputStream in = new CpioArchiveInputStream(bin)) { + try (CpioArchiveInputStream in = CpioArchiveInputStream.builder() + .setByteArray(baos.toByteArray()) + .get()) { final CpioArchiveEntry entry = in.getNextEntry(); assertNotNull(entry); assertEquals("T%U00E4st.txt", entry.getName()); @@ -98,8 +100,10 @@ public void utf18RoundtripTestCtor4(final short format) throws Exception { os.closeArchiveEntry(); } baos.close(); - try (ByteArrayInputStream bin = new ByteArrayInputStream(baos.toByteArray()); - CpioArchiveInputStream in = new CpioArchiveInputStream(bin, StandardCharsets.UTF_16LE.name())) { + try (CpioArchiveInputStream in = CpioArchiveInputStream.builder() + .setByteArray(baos.toByteArray()) + .setCharset(StandardCharsets.UTF_16LE) + .get()) { final CpioArchiveEntry entry = in.getNextEntry(); assertNotNull(entry); assertEquals("T\u00e4st.txt", entry.getName());