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
commit facbd45c65bd6a151c0f705a2dbbff55864d91cc Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Wed Jul 3 10:35:23 2024 -0400 ArchiveOutputStream now extends FilterOutputStream --- src/changes/changes.xml | 1 + .../compress/archivers/ArchiveOutputStream.java | 24 +++++++- .../archivers/ar/ArArchiveOutputStream.java | 3 +- .../archivers/cpio/CpioArchiveOutputStream.java | 4 +- .../archivers/tar/TarArchiveOutputStream.java | 7 +-- .../archivers/zip/ZipArchiveOutputStream.java | 68 +++++++++++----------- .../compress/archivers/cpio/CpioArchiveTest.java | 47 ++++++++++++++- 7 files changed, 109 insertions(+), 45 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 412f6aa99..103217cbb 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -50,6 +50,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="fix" issue="COMPRESS-681" dev="ggregory" due-to="joker53-1, Gary Gregory">Support reading a 7z file that writing archive properties #541.</action> <action type="fix" dev="ggregory" due-to="Mike Drob, Gary Gregory">Upgrade commons-io from 2.15.1 to 2.16.1 #513</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">CompressorOutputStream now extends FilterOutputStream.</action> + <action type="fix" dev="ggregory" due-to="Gary Gregory">ArchiveOutputStream now extends FilterOutputStream.</action> <!-- ADD --> <action type="add" dev="ggregory" due-to="Gary Gregory">Add ArchiveInputStream.forEach(IOConsumer).</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add ArchiveInputStream.iterator().</action> diff --git a/src/main/java/org/apache/commons/compress/archivers/ArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/ArchiveOutputStream.java index 7199ca437..038a2ea42 100644 --- a/src/main/java/org/apache/commons/compress/archivers/ArchiveOutputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/ArchiveOutputStream.java @@ -19,6 +19,7 @@ package org.apache.commons.compress.archivers; import java.io.File; +import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.LinkOption; @@ -48,7 +49,7 @@ import java.nio.file.Path; * * @param <E> The type of {@link ArchiveEntry} consumed. */ -public abstract class ArchiveOutputStream<E extends ArchiveEntry> extends OutputStream { +public abstract class ArchiveOutputStream<E extends ArchiveEntry> extends FilterOutputStream { static final int BYTE_MASK = 0xFF; @@ -58,6 +59,27 @@ public abstract class ArchiveOutputStream<E extends ArchiveEntry> extends Output /** Holds the number of bytes written to this stream. */ private long bytesWritten; + /** + * Constructs a new instance without a backing OutputStream. + * <p> + * You must initialize {@code this.out} after construction. + * </p> + */ + public ArchiveOutputStream() { + super(null); + } + + /** + * Constructs a new instance with the given backing OutputStream. + * + * @param out the underlying output stream to be assigned to the field {@code this.out} for later use, or {@code null} if this instance is to be created + * without an underlying stream. + * @since 1.27.0. + */ + public ArchiveOutputStream(final OutputStream out) { + super(out); + } + /** * Whether this stream is able to write the given entry. * diff --git a/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveOutputStream.java index c3323a61f..61445a363 100644 --- a/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveOutputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveOutputStream.java @@ -46,7 +46,6 @@ public class ArArchiveOutputStream extends ArchiveOutputStream<ArArchiveEntry> { /** BSD ar extensions are used to store long file names in the archive. */ public static final int LONGFILE_BSD = 1; - private final OutputStream out; private long entryOffset; private int headerPlus; private ArArchiveEntry prevEntry; @@ -57,7 +56,7 @@ public class ArArchiveOutputStream extends ArchiveOutputStream<ArArchiveEntry> { private boolean finished; public ArArchiveOutputStream(final OutputStream out) { - this.out = out; + super(out); } /** 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 1d1e000d4..bf16427ed 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 @@ -87,8 +87,6 @@ public class CpioArchiveOutputStream extends ArchiveOutputStream<CpioArchiveEntr private long written; - private final OutputStream out; - private final int blockSize; private long nextArtificalDeviceAndInode = 1; @@ -145,7 +143,7 @@ public class CpioArchiveOutputStream extends ArchiveOutputStream<CpioArchiveEntr * @since 1.6 */ public CpioArchiveOutputStream(final OutputStream out, final short format, final int blockSize, final String encoding) { - this.out = out; + super(out); switch (format) { case FORMAT_NEW: case FORMAT_NEW_CRC: diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java index 492bdb4ea..82838af1f 100644 --- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java @@ -122,8 +122,6 @@ public class TarArchiveOutputStream extends ArchiveOutputStream<TarArchiveEntry> */ private boolean finished; - private final FixedLengthBlockOutputStream out; - private final CountingOutputStream countingOut; private final ZipEncoding zipEncoding; @@ -199,6 +197,7 @@ public class TarArchiveOutputStream extends ArchiveOutputStream<TarArchiveEntry> * @since 1.4 */ public TarArchiveOutputStream(final OutputStream os, final int blockSize, final String encoding) { + super(os); final int realBlockSize; if (BLOCK_SIZE_UNSPECIFIED == blockSize) { realBlockSize = RECORD_SIZE; @@ -209,7 +208,7 @@ public class TarArchiveOutputStream extends ArchiveOutputStream<TarArchiveEntry> if (realBlockSize <= 0 || realBlockSize % RECORD_SIZE != 0) { throw new IllegalArgumentException("Block size must be a multiple of 512 bytes. Attempt to use set size of " + blockSize); } - out = new FixedLengthBlockOutputStream(countingOut = new CountingOutputStream(os), RECORD_SIZE); + this.out = new FixedLengthBlockOutputStream(countingOut = new CountingOutputStream(os), RECORD_SIZE); this.charsetName = Charsets.toCharset(encoding).name(); this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); @@ -326,7 +325,7 @@ public class TarArchiveOutputStream extends ArchiveOutputStream<TarArchiveEntry> if (!haveUnclosedEntry) { throw new IOException("No current entry to close"); } - out.flushBlock(); + ((FixedLengthBlockOutputStream) out).flushBlock(); if (currBytes < currSize) { throw new IOException( "Entry '" + currName + "' closed at '" + currBytes + "' before the '" + currSize + "' bytes specified in the header were written"); diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java index 488b3d8ca..bd0a5ad45 100644 --- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java @@ -337,7 +337,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> */ protected final Deflater def; - private final OutputStream outputStream; + private final OutputStream out; /** * whether to use the general purpose bit flag when writing UTF-8 file names or not. @@ -415,7 +415,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> * @param out the outputstream to zip */ public ZipArchiveOutputStream(final OutputStream out) { - this.outputStream = out; + this.out = out; this.def = new Deflater(level, true); this.streamCompressor = StreamCompressor.create(out, def); this.isSplitZip = false; @@ -440,8 +440,8 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> */ public ZipArchiveOutputStream(final Path path, final long zipSplitSize) throws IOException { this.def = new Deflater(level, true); - this.outputStream = new ZipSplitOutputStream(path, zipSplitSize); - this.streamCompressor = StreamCompressor.create(this.outputStream, def); + this.out = new ZipSplitOutputStream(path, zipSplitSize); + this.streamCompressor = StreamCompressor.create(this.out, def); this.isSplitZip = true; } @@ -455,8 +455,8 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> */ public ZipArchiveOutputStream(final Path file, final OpenOption... options) throws IOException { this.def = new Deflater(level, true); - this.outputStream = options.length == 0 ? new FileRandomAccessOutputStream(file) : new FileRandomAccessOutputStream(file, options); - this.streamCompressor = StreamCompressor.create(outputStream, def); + this.out = options.length == 0 ? new FileRandomAccessOutputStream(file) : new FileRandomAccessOutputStream(file, options); + this.streamCompressor = StreamCompressor.create(out, def); this.isSplitZip = false; } @@ -471,9 +471,9 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> * @since 1.13 */ public ZipArchiveOutputStream(final SeekableByteChannel channel) { - this.outputStream = new SeekableChannelRandomAccessOutputStream(channel); + this.out = new SeekableChannelRandomAccessOutputStream(channel); this.def = new Deflater(level, true); - this.streamCompressor = StreamCompressor.create(outputStream, def); + this.streamCompressor = StreamCompressor.create(out, def); this.isSplitZip = false; } @@ -609,7 +609,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> } private void closeEntry(final boolean actuallyNeedsZip64, final boolean phased) throws IOException { - if (!phased && outputStream instanceof RandomAccessOutputStream) { + if (!phased && out instanceof RandomAccessOutputStream) { rewriteSizesAndCrc(actuallyNeedsZip64); } @@ -707,7 +707,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> if (isSplitZip) { // calculate the disk number for every central file header, // this will be used in writing End Of Central Directory and Zip64 End Of Central Directory - final int currentSplitSegment = ((ZipSplitOutputStream) this.outputStream).getCurrentSplitSegmentIndex(); + final int currentSplitSegment = ((ZipSplitOutputStream) this.out).getCurrentSplitSegmentIndex(); if (numberOfCDInDiskData.get(currentSplitSegment) == null) { numberOfCDInDiskData.put(currentSplitSegment, 1); } else { @@ -849,7 +849,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> ZipUtil.toDosTime(ze.getTime(), buf, LFH_TIME_OFFSET); // CRC - if (phased || !(zipMethod == DEFLATED || outputStream instanceof RandomAccessOutputStream)) { + if (phased || !(zipMethod == DEFLATED || out instanceof RandomAccessOutputStream)) { ZipLong.putLong(ze.getCrc(), buf, LFH_CRC_OFFSET); } else { System.arraycopy(LZERO, 0, buf, LFH_CRC_OFFSET, ZipConstants.WORD); @@ -866,7 +866,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> } else if (phased) { ZipLong.putLong(ze.getCompressedSize(), buf, LFH_COMPRESSED_SIZE_OFFSET); ZipLong.putLong(ze.getSize(), buf, LFH_ORIGINAL_SIZE_OFFSET); - } else if (zipMethod == DEFLATED || outputStream instanceof RandomAccessOutputStream) { + } else if (zipMethod == DEFLATED || out instanceof RandomAccessOutputStream) { System.arraycopy(LZERO, 0, buf, LFH_COMPRESSED_SIZE_OFFSET, ZipConstants.WORD); System.arraycopy(LZERO, 0, buf, LFH_ORIGINAL_SIZE_OFFSET, ZipConstants.WORD); } else { // Stored @@ -904,8 +904,8 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> * </p> */ void destroy() throws IOException { - if (outputStream != null) { - outputStream.close(); + if (out != null) { + out.close(); } } @@ -930,7 +930,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> if (isSplitZip) { // when creating a split zip, the offset should be // the offset to the corresponding segment disk - final ZipSplitOutputStream zipSplitOutputStream = (ZipSplitOutputStream) this.outputStream; + final ZipSplitOutputStream zipSplitOutputStream = (ZipSplitOutputStream) this.out; cdOffset = zipSplitOutputStream.getCurrentSplitSegmentBytesWritten(); cdDiskNumberStart = zipSplitOutputStream.getCurrentSplitSegmentIndex(); } @@ -958,7 +958,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> streamCompressor.close(); if (isSplitZip) { // trigger the ZipSplitOutputStream to write the final split segment - outputStream.close(); + out.close(); } finished = true; } @@ -970,8 +970,8 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> */ @Override public void flush() throws IOException { - if (outputStream != null) { - outputStream.flush(); + if (out != null) { + out.flush(); } } @@ -1001,7 +1001,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> * @since 1.3 */ private Zip64Mode getEffectiveZip64Mode(final ZipArchiveEntry ze) { - if (zip64Mode != Zip64Mode.AsNeeded || outputStream instanceof RandomAccessOutputStream || + if (zip64Mode != Zip64Mode.AsNeeded || out instanceof RandomAccessOutputStream || ze.getMethod() != DEFLATED || ze.getSize() != ArchiveEntry.SIZE_UNKNOWN) { return zip64Mode; } @@ -1074,7 +1074,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> entry.entry.setCompressedSize(bytesWritten); entry.entry.setCrc(crc); - } else if (!(outputStream instanceof RandomAccessOutputStream)) { + } else if (!(out instanceof RandomAccessOutputStream)) { if (entry.entry.getCrc() != crc) { throw new ZipException("Bad CRC checksum for entry " + entry.entry.getName() + ": " + Long.toHexString(entry.entry.getCrc()) + " instead of " + Long.toHexString(crc)); @@ -1140,7 +1140,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> * @return true if seekable */ public boolean isSeekable() { - return outputStream instanceof RandomAccessOutputStream; + return out instanceof RandomAccessOutputStream; } private boolean isTooLargeForZip32(final ZipArchiveEntry zipArchiveEntry) { @@ -1239,7 +1239,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> * sizes. */ private void rewriteSizesAndCrc(final boolean actuallyNeedsZip64) throws IOException { - final RandomAccessOutputStream randomStream = (RandomAccessOutputStream) outputStream; + final RandomAccessOutputStream randomStream = (RandomAccessOutputStream) out; long dataStart = entry.localDataStart; if (randomStream instanceof ZipSplitOutputStream) { dataStart = ((ZipSplitOutputStream) randomStream).calculateDiskPosition(entry.entry.getDiskNumberStart(), dataStart); @@ -1446,7 +1446,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> private boolean shouldAddZip64Extra(final ZipArchiveEntry entry, final Zip64Mode mode) { return mode == Zip64Mode.Always || mode == Zip64Mode.AlwaysWithCompatibility || entry.getSize() >= ZipConstants.ZIP64_MAGIC || entry.getCompressedSize() >= ZipConstants.ZIP64_MAGIC - || entry.getSize() == ArchiveEntry.SIZE_UNKNOWN && outputStream instanceof RandomAccessOutputStream && mode != Zip64Mode.Never; + || entry.getSize() == ArchiveEntry.SIZE_UNKNOWN && out instanceof RandomAccessOutputStream && mode != Zip64Mode.Never; } /** @@ -1458,7 +1458,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> private boolean shouldUseZip64EOCD() { int numberOfThisDisk = 0; if (isSplitZip) { - numberOfThisDisk = ((ZipSplitOutputStream) this.outputStream).getCurrentSplitSegmentIndex(); + numberOfThisDisk = ((ZipSplitOutputStream) this.out).getCurrentSplitSegmentIndex(); } final int numOfEntriesOnThisDisk = numberOfCDInDiskData.getOrDefault(numberOfThisDisk, 0); return numberOfThisDisk >= ZipConstants.ZIP64_MAGIC_SHORT /* number of this disk */ @@ -1472,7 +1472,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> } private boolean usesDataDescriptor(final int zipMethod, final boolean phased) { - return !phased && zipMethod == DEFLATED && !(outputStream instanceof RandomAccessOutputStream); + return !phased && zipMethod == DEFLATED && !(out instanceof RandomAccessOutputStream); } /** @@ -1488,7 +1488,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> int numberOfThisDisk = 0; if (isSplitZip) { - numberOfThisDisk = ((ZipSplitOutputStream) this.outputStream).getCurrentSplitSegmentIndex(); + numberOfThisDisk = ((ZipSplitOutputStream) this.out).getCurrentSplitSegmentIndex(); } if (numberOfThisDisk >= ZipConstants.ZIP64_MAGIC_SHORT) { throw new Zip64RequiredException(Zip64RequiredException.DISK_NUMBER_TOO_BIG_MESSAGE); @@ -1523,7 +1523,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> */ private void validateSizeInformation(final Zip64Mode effectiveMode) throws ZipException { // Size/CRC not required if SeekableByteChannel is used - if (entry.entry.getMethod() == STORED && !(outputStream instanceof RandomAccessOutputStream)) { + if (entry.entry.getMethod() == STORED && !(out instanceof RandomAccessOutputStream)) { if (entry.entry.getSize() == ArchiveEntry.SIZE_UNKNOWN) { throw new ZipException("Uncompressed size is required for" + " STORED method when not writing to a" + " file"); } @@ -1580,7 +1580,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> */ protected void writeCentralDirectoryEnd() throws IOException { if (!hasUsedZip64 && isSplitZip) { - ((ZipSplitOutputStream) this.outputStream).prepareToWriteUnsplittableContent(eocdLength); + ((ZipSplitOutputStream) this.out).prepareToWriteUnsplittableContent(eocdLength); } validateIfZip64IsNeededInEOCD(); @@ -1590,7 +1590,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> // number of this disk int numberOfThisDisk = 0; if (isSplitZip) { - numberOfThisDisk = ((ZipSplitOutputStream) this.outputStream).getCurrentSplitSegmentIndex(); + numberOfThisDisk = ((ZipSplitOutputStream) this.out).getCurrentSplitSegmentIndex(); } writeCounted(ZipShort.getBytes(numberOfThisDisk)); @@ -1700,7 +1700,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> if (isSplitZip) { // when creating a split zip, the offset should be // the offset to the corresponding segment disk - final ZipSplitOutputStream splitOutputStream = (ZipSplitOutputStream) this.outputStream; + final ZipSplitOutputStream splitOutputStream = (ZipSplitOutputStream) this.out; ze.setDiskNumberStart(splitOutputStream.getCurrentSplitSegmentIndex()); localHeaderStart = splitOutputStream.getCurrentSplitSegmentBytesWritten(); } @@ -1786,7 +1786,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> if (isSplitZip) { // when creating a split zip, the offset of should be // the offset to the corresponding segment disk - final ZipSplitOutputStream zipSplitOutputStream = (ZipSplitOutputStream) this.outputStream; + final ZipSplitOutputStream zipSplitOutputStream = (ZipSplitOutputStream) this.out; offset = zipSplitOutputStream.getCurrentSplitSegmentBytesWritten(); diskNumberStart = zipSplitOutputStream.getCurrentSplitSegmentIndex(); } @@ -1811,7 +1811,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> // number of this disk int numberOfThisDisk = 0; if (isSplitZip) { - numberOfThisDisk = ((ZipSplitOutputStream) this.outputStream).getCurrentSplitSegmentIndex(); + numberOfThisDisk = ((ZipSplitOutputStream) this.out).getCurrentSplitSegmentIndex(); } writeOut(ZipLong.getBytes(numberOfThisDisk)); @@ -1842,7 +1842,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> + ZipConstants.WORD /* total number of disks */; final long unsplittableContentSize = zip64EOCDLOCLength + eocdLength; - ((ZipSplitOutputStream) this.outputStream).prepareToWriteUnsplittableContent(unsplittableContentSize); + ((ZipSplitOutputStream) this.out).prepareToWriteUnsplittableContent(unsplittableContentSize); } // and now the "ZIP64 end of central directory locator" @@ -1856,7 +1856,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> if (isSplitZip) { // the Zip64 End Of Central Directory Locator and the End Of Central Directory must be // in the same split disk, it means they must be located in the last disk - final int totalNumberOfDisks = ((ZipSplitOutputStream) this.outputStream).getCurrentSplitSegmentIndex() + 1; + final int totalNumberOfDisks = ((ZipSplitOutputStream) this.out).getCurrentSplitSegmentIndex() + 1; writeOut(ZipLong.getBytes(totalNumberOfDisks)); } else { writeOut(ONE); 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 e02b1c9ef..1818f68f2 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 @@ -28,6 +28,7 @@ import java.nio.charset.StandardCharsets; import java.util.stream.Stream; import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -39,9 +40,53 @@ public class CpioArchiveTest { Arguments.of(CpioConstants.FORMAT_OLD_BINARY)); } + @Test + public void utf18RoundtripTestCtor2() throws Exception { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + try (CpioArchiveOutputStream os = new CpioArchiveOutputStream(baos, StandardCharsets.UTF_8.name())) { + final CpioArchiveEntry entry = new CpioArchiveEntry("Test.txt", 4); + os.putArchiveEntry(entry); + os.write(new byte[] { 1, 2, 3, 4 }); + os.closeArchiveEntry(); + } + baos.close(); + try (ByteArrayInputStream bin = new ByteArrayInputStream(baos.toByteArray()); + CpioArchiveInputStream in = new CpioArchiveInputStream(bin, StandardCharsets.UTF_8.name())) { + final CpioArchiveEntry entry = in.getNextEntry(); + assertNotNull(entry); + assertEquals("Test.txt", entry.getName()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, IOUtils.toByteArray(in)); + } + } + } + + @ParameterizedTest + @MethodSource("factory") + public void utf18RoundtripTestCtor3(final short format) throws Exception { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + try (CpioArchiveOutputStream os = new CpioArchiveOutputStream(baos, format, CpioConstants.BLOCK_SIZE)) { + final CpioArchiveEntry entry = new CpioArchiveEntry(format, "T\u00e4st.txt", 4); + if (format == CpioConstants.FORMAT_NEW_CRC) { + entry.setChksum(10); + } + os.putArchiveEntry(entry); + os.write(new byte[] { 1, 2, 3, 4 }); + os.closeArchiveEntry(); + } + baos.close(); + try (ByteArrayInputStream bin = new ByteArrayInputStream(baos.toByteArray()); + CpioArchiveInputStream in = new CpioArchiveInputStream(bin)) { + final CpioArchiveEntry entry = in.getNextEntry(); + assertNotNull(entry); + assertEquals("T%U00E4st.txt", entry.getName()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, IOUtils.toByteArray(in)); + } + } + } + @ParameterizedTest @MethodSource("factory") - public void utf18RoundtripTest(final short format) throws Exception { + public void utf18RoundtripTestCtor4(final short format) throws Exception { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { try (CpioArchiveOutputStream os = new CpioArchiveOutputStream(baos, format, CpioConstants.BLOCK_SIZE, StandardCharsets.UTF_16LE.name())) { final CpioArchiveEntry entry = new CpioArchiveEntry(format, "T\u00e4st.txt", 4);