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 519d752b104f03de8575936308f5c7d661c35547 Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Sun Oct 29 09:36:33 2023 -0400 Add a generic type parameter to ArchiveOutputStream and avoid unchecked/unconfirmed type casts in subclasses --- src/changes/changes.xml | 1 + .../compress/archivers/ArchiveOutputStream.java | 9 +++-- .../archivers/ar/ArArchiveOutputStream.java | 28 +++++++------- .../archivers/cpio/CpioArchiveOutputStream.java | 27 +++++++------ .../archivers/jar/JarArchiveOutputStream.java | 6 +-- .../archivers/tar/TarArchiveOutputStream.java | 44 +++++++++++----------- .../archivers/zip/ZipArchiveOutputStream.java | 14 +++---- 7 files changed, 63 insertions(+), 66 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 19103f92..85550977 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -79,6 +79,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="fix" dev="ggregory" due-to="Gary Gregory">Refactor internal SevenZ AES256SHA256Decoder InputStream into a named static inner class.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">Refactor internal SevenZ AES256SHA256Decoder OutputStream into a named static inner class.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">Use the root Locale for string conversion of command line options in org.apache.commons.compress.archivers.sevenz.CLI.</action> + <action type="fix" dev="ggregory" due-to="Gary Gregory">Add a generic type parameter to ArchiveOutputStream and avoid unchecked/unconfirmed type casts in subclasses.</action> <!-- UPDATE --> <action type="update" dev="ggregory" due-to="Dependabot">Bump org.slf4j:slf4j-api from 2.0.8 to 2.0.9 #413.</action> <action type="update" dev="ggregory" due-to="Gary Gregory">Bump commons-io:commons-io from 2.13.0 to 2.15.0.</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 2d5fbfa5..0bd61ea9 100644 --- a/src/main/java/org/apache/commons/compress/archivers/ArchiveOutputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/ArchiveOutputStream.java @@ -45,8 +45,9 @@ import java.nio.file.Path; * <li> optionally write additional data, provided format supports it,</li> * <li>{@link #close()}.</li> * </ul> + * @param <E> The type of {@link ArchiveEntry} produced. */ -public abstract class ArchiveOutputStream extends OutputStream { +public abstract class ArchiveOutputStream<E extends ArchiveEntry> extends OutputStream { static final int BYTE_MASK = 0xFF; /** Temporary buffer used for the {@link #write(int)} method */ @@ -110,7 +111,7 @@ public abstract class ArchiveOutputStream extends OutputStream { * * @throws IOException if an I/O error occurs */ - public abstract ArchiveEntry createArchiveEntry(File inputFile, String entryName) throws IOException; + public abstract E createArchiveEntry(File inputFile, String entryName) throws IOException; // Generic implementations of OutputStream methods that may be useful to sub-classes @@ -130,7 +131,7 @@ public abstract class ArchiveOutputStream extends OutputStream { * @throws IOException if an I/O error occurs * @since 1.21 */ - public ArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException { + public E createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException { return createArchiveEntry(inputPath.toFile(), entryName); } @@ -170,7 +171,7 @@ public abstract class ArchiveOutputStream extends OutputStream { * @param entry describes the entry * @throws IOException if an I/O error occurs */ - public abstract void putArchiveEntry(ArchiveEntry entry) throws IOException; + public abstract void putArchiveEntry(E entry) throws IOException; /** * Writes a byte to the current archive 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 ebfbacfc..5c363a9b 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 @@ -26,7 +26,6 @@ import java.io.OutputStream; import java.nio.file.LinkOption; import java.nio.file.Path; -import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveOutputStream; import org.apache.commons.compress.utils.ArchiveUtils; @@ -35,7 +34,7 @@ import org.apache.commons.compress.utils.ArchiveUtils; * * @NotThreadSafe */ -public class ArArchiveOutputStream extends ArchiveOutputStream { +public class ArArchiveOutputStream extends ArchiveOutputStream<ArArchiveEntry> { /** Fail if a long file name is required in the archive. */ public static final int LONGFILE_ERROR = 0; @@ -85,7 +84,7 @@ public class ArArchiveOutputStream extends ArchiveOutputStream { } @Override - public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName) + public ArArchiveEntry createArchiveEntry(final File inputFile, final String entryName) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); @@ -99,7 +98,7 @@ public class ArArchiveOutputStream extends ArchiveOutputStream { * @since 1.21 */ @Override - public ArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException { + public ArArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); } @@ -130,12 +129,11 @@ public class ArArchiveOutputStream extends ArchiveOutputStream { } @Override - public void putArchiveEntry(final ArchiveEntry pEntry) throws IOException { + public void putArchiveEntry(final ArArchiveEntry entry) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); } - final ArArchiveEntry pArEntry = (ArArchiveEntry) pEntry; if (prevEntry == null) { writeArchiveHeader(); } else { @@ -148,9 +146,9 @@ public class ArArchiveOutputStream extends ArchiveOutputStream { } } - prevEntry = pArEntry; + prevEntry = entry; - writeEntryHeader(pArEntry); + writeEntryHeader(entry); entryOffset = 0; haveUnclosedEntry = true; @@ -186,12 +184,12 @@ public class ArArchiveOutputStream extends ArchiveOutputStream { out.write(header); } - private void writeEntryHeader(final ArArchiveEntry pEntry) throws IOException { + private void writeEntryHeader(final ArArchiveEntry entry) throws IOException { long offset = 0; boolean mustAppendName = false; - final String n = pEntry.getName(); + final String n = entry.getName(); final int nLength = n.length(); if (LONGFILE_ERROR == longFileMode && nLength > 16) { throw new IOException("File name too long, > 16 chars: "+n); @@ -205,28 +203,28 @@ public class ArArchiveOutputStream extends ArchiveOutputStream { } offset = fill(offset, 16, ' '); - final String m = "" + pEntry.getLastModified(); + final String m = "" + entry.getLastModified(); if (m.length() > 12) { throw new IOException("Last modified too long"); } offset += write(m); offset = fill(offset, 28, ' '); - final String u = "" + pEntry.getUserId(); + final String u = "" + entry.getUserId(); if (u.length() > 6) { throw new IOException("User id too long"); } offset += write(u); offset = fill(offset, 34, ' '); - final String g = "" + pEntry.getGroupId(); + final String g = "" + entry.getGroupId(); if (g.length() > 6) { throw new IOException("Group id too long"); } offset += write(g); offset = fill(offset, 40, ' '); - final String fm = "" + Integer.toString(pEntry.getMode(), 8); + final String fm = "" + Integer.toString(entry.getMode(), 8); if (fm.length() > 8) { throw new IOException("Filemode too long"); } @@ -234,7 +232,7 @@ public class ArArchiveOutputStream extends ArchiveOutputStream { offset = fill(offset, 48, ' '); final String s = - String.valueOf(pEntry.getLength() + String.valueOf(entry.getLength() + (mustAppendName ? nLength : 0)); if (s.length() > 10) { throw new IOException("Size too long"); 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 de3a6e76..70ad4342 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 @@ -64,7 +64,7 @@ import org.apache.commons.compress.utils.CharsetNames; * * <p>based on code from the jRPM project (jrpm.sourceforge.net)</p> */ -public class CpioArchiveOutputStream extends ArchiveOutputStream implements +public class CpioArchiveOutputStream extends ArchiveOutputStream<CpioArchiveEntry> implements CpioConstants { private CpioArchiveEntry entry; @@ -248,12 +248,12 @@ public class CpioArchiveOutputStream extends ArchiveOutputStream implements } /** - * Creates a new ArchiveEntry. The entryName must be an ASCII encoded string. + * Creates a new CpioArchiveEntry. The entryName must be an ASCII encoded string. * * @see org.apache.commons.compress.archivers.ArchiveOutputStream#createArchiveEntry(java.io.File, String) */ @Override - public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName) + public CpioArchiveEntry createArchiveEntry(final File inputFile, final String entryName) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); @@ -262,12 +262,12 @@ public class CpioArchiveOutputStream extends ArchiveOutputStream implements } /** - * Creates a new ArchiveEntry. The entryName must be an ASCII encoded string. + * Creates a new CpioArchiveEntry. The entryName must be an ASCII encoded string. * * @see org.apache.commons.compress.archivers.ArchiveOutputStream#createArchiveEntry(java.io.File, String) */ @Override - public ArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) + public CpioArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); @@ -356,31 +356,30 @@ public class CpioArchiveOutputStream extends ArchiveOutputStream implements * @throws ClassCastException if entry is not an instance of CpioArchiveEntry */ @Override - public void putArchiveEntry(final ArchiveEntry entry) throws IOException { + public void putArchiveEntry(final CpioArchiveEntry entry) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); } - final CpioArchiveEntry e = (CpioArchiveEntry) entry; ensureOpen(); if (this.entry != null) { closeArchiveEntry(); // close previous entry } - if (e.getTime() == -1) { - e.setTime(System.currentTimeMillis() / 1000); + if (entry.getTime() == -1) { + entry.setTime(System.currentTimeMillis() / 1000); } - final short format = e.getFormat(); + final short format = entry.getFormat(); if (format != this.entryFormat){ throw new IOException("Header format: "+format+" does not match existing format: "+this.entryFormat); } - if (this.names.put(e.getName(), e) != null) { - throw new IOException("Duplicate entry: " + e.getName()); + if (this.names.put(entry.getName(), entry) != null) { + throw new IOException("Duplicate entry: " + entry.getName()); } - writeHeader(e); - this.entry = e; + writeHeader(entry); + this.entry = entry; this.written = 0; } diff --git a/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java index 68550593..ed9b26ca 100644 --- a/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java @@ -55,11 +55,11 @@ public class JarArchiveOutputStream extends ZipArchiveOutputStream { // @throws ClassCastException if entry is not an instance of ZipArchiveEntry @Override - public void putArchiveEntry(final ArchiveEntry ze) throws IOException { + public void putArchiveEntry(final ZipArchiveEntry entry) throws IOException { if (!jarMarkerAdded) { - ((ZipArchiveEntry) ze).addAsFirstExtraField(JarMarker.getInstance()); + entry.addAsFirstExtraField(JarMarker.getInstance()); jarMarkerAdded = true; } - super.putArchiveEntry(ze); + super.putArchiveEntry(entry); } } 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 625a6c4c..2c1a7511 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 @@ -35,7 +35,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveOutputStream; import org.apache.commons.compress.archivers.zip.ZipEncoding; import org.apache.commons.compress.archivers.zip.ZipEncodingHelper; @@ -58,7 +57,7 @@ import org.apache.commons.compress.utils.TimeUtils; * * @NotThreadSafe */ -public class TarArchiveOutputStream extends ArchiveOutputStream { +public class TarArchiveOutputStream extends ArchiveOutputStream<TarArchiveEntry> { /** * Fail if a long file name is required in the archive. @@ -361,7 +360,7 @@ public class TarArchiveOutputStream extends ArchiveOutputStream { } @Override - public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName) + public TarArchiveEntry createArchiveEntry(final File inputFile, final String entryName) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); @@ -370,7 +369,7 @@ public class TarArchiveOutputStream extends ArchiveOutputStream { } @Override - public ArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException { + public TarArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); } @@ -565,35 +564,34 @@ public class TarArchiveOutputStream extends ArchiveOutputStream { * exceeds the limits of a traditional tar header. */ @Override - public void putArchiveEntry(final ArchiveEntry archiveEntry) throws IOException { + public void putArchiveEntry(final TarArchiveEntry archiveEntry) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); } - final TarArchiveEntry entry = (TarArchiveEntry) archiveEntry; - if (entry.isGlobalPaxHeader()) { - final byte[] data = encodeExtendedPaxHeadersContents(entry.getExtraPaxHeaders()); - entry.setSize(data.length); - entry.writeEntryHeader(recordBuf, zipEncoding, bigNumberMode == BIGNUMBER_STAR); + if (archiveEntry.isGlobalPaxHeader()) { + final byte[] data = encodeExtendedPaxHeadersContents(archiveEntry.getExtraPaxHeaders()); + archiveEntry.setSize(data.length); + archiveEntry.writeEntryHeader(recordBuf, zipEncoding, bigNumberMode == BIGNUMBER_STAR); writeRecord(recordBuf); - currSize= entry.getSize(); + currSize= archiveEntry.getSize(); currBytes = 0; this.haveUnclosedEntry = true; write(data); closeArchiveEntry(); } else { final Map<String, String> paxHeaders = new HashMap<>(); - final String entryName = entry.getName(); - final boolean paxHeaderContainsPath = handleLongName(entry, entryName, paxHeaders, "path", + final String entryName = archiveEntry.getName(); + final boolean paxHeaderContainsPath = handleLongName(archiveEntry, entryName, paxHeaders, "path", TarConstants.LF_GNUTYPE_LONGNAME, "file name"); - final String linkName = entry.getLinkName(); + final String linkName = archiveEntry.getLinkName(); final boolean paxHeaderContainsLinkPath = linkName != null && !linkName.isEmpty() - && handleLongName(entry, linkName, paxHeaders, "linkpath", + && handleLongName(archiveEntry, linkName, paxHeaders, "linkpath", TarConstants.LF_GNUTYPE_LONGLINK, "link name"); if (bigNumberMode == BIGNUMBER_POSIX) { - addPaxHeadersForBigNumbers(paxHeaders, entry); + addPaxHeadersForBigNumbers(paxHeaders, archiveEntry); } else if (bigNumberMode != BIGNUMBER_STAR) { - failForBigNumbers(entry); + failForBigNumbers(archiveEntry); } if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsPath @@ -602,25 +600,25 @@ public class TarArchiveOutputStream extends ArchiveOutputStream { } if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsLinkPath - && (entry.isLink() || entry.isSymbolicLink()) + && (archiveEntry.isLink() || archiveEntry.isSymbolicLink()) && !ASCII.canEncode(linkName)) { paxHeaders.put("linkpath", linkName); } - paxHeaders.putAll(entry.getExtraPaxHeaders()); + paxHeaders.putAll(archiveEntry.getExtraPaxHeaders()); if (!paxHeaders.isEmpty()) { - writePaxHeaders(entry, entryName, paxHeaders); + writePaxHeaders(archiveEntry, entryName, paxHeaders); } - entry.writeEntryHeader(recordBuf, zipEncoding, bigNumberMode == BIGNUMBER_STAR); + archiveEntry.writeEntryHeader(recordBuf, zipEncoding, bigNumberMode == BIGNUMBER_STAR); writeRecord(recordBuf); currBytes = 0; - if (entry.isDirectory()) { + if (archiveEntry.isDirectory()) { currSize = 0; } else { - currSize = entry.getSize(); + currSize = archiveEntry.getSize(); } currName = entryName; haveUnclosedEntry = true; 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 fc3c4ba7..ab6d797e 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 @@ -59,7 +59,7 @@ import org.apache.commons.compress.utils.IOUtils; * calculate them yourself. Unfortunately, this is not possible for * the {@link #STORED STORED} method, where setting the CRC and * uncompressed size information is required before {@link - * #putArchiveEntry(ArchiveEntry)} can be called.</p> + * #putArchiveEntry(ZipArchiveEntry)} can be called.</p> * * <p>As of Apache Commons Compress 1.3, the class transparently supports Zip64 * extensions and thus individual entries and archives larger than 4 @@ -70,7 +70,7 @@ import org.apache.commons.compress.utils.IOUtils; * * @NotThreadSafe */ -public class ZipArchiveOutputStream extends ArchiveOutputStream { +public class ZipArchiveOutputStream extends ArchiveOutputStream<ZipArchiveEntry> { /** * Structure collecting information for the entry that is @@ -713,7 +713,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream { * <p>Must not be used if the stream has already been closed.</p> */ @Override - public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName) + public ZipArchiveEntry createArchiveEntry(final File inputFile, final String entryName) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); @@ -739,7 +739,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream { * @since 1.21 */ @Override - public ArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) + public ZipArchiveEntry createArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException { if (finished) { throw new IOException("Stream has already been finished"); @@ -1259,7 +1259,7 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream { * * <p>For seekable streams, you don't need to calculate the CRC or * uncompressed size for {@link #STORED} entries before - * invoking {@link #putArchiveEntry(ArchiveEntry)}. + * invoking {@link #putArchiveEntry(ZipArchiveEntry)}. * @return true if seekable */ public boolean isSeekable() { @@ -1296,8 +1296,8 @@ public class ZipArchiveOutputStream extends ArchiveOutputStream { * is {@link Zip64Mode#Never}. */ @Override - public void putArchiveEntry(final ArchiveEntry archiveEntry) throws IOException { - putArchiveEntry((ZipArchiveEntry) archiveEntry, false); + public void putArchiveEntry(final ZipArchiveEntry archiveEntry) throws IOException { + putArchiveEntry(archiveEntry, false); } /**