You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2024/02/10 20:40:27 UTC
(commons-compress) branch master updated: Drop reflection from ExtraFieldUtils static initialization (#480)
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 22a1d2d6a Drop reflection from ExtraFieldUtils static initialization (#480)
22a1d2d6a is described below
commit 22a1d2d6a9c1310141426d1298f3caa57cf8529e
Author: Romain Manni-Bucau <rm...@gmail.com>
AuthorDate: Sat Feb 10 21:40:23 2024 +0100
Drop reflection from ExtraFieldUtils static initialization (#480)
* Drop reflection from ExtraFieldUtils
* [tests] fix IT (wrong assert usage)
* [deprecation] deprecate ExtraFieldUtils#register which is not globally usable except in the single case you are in a flat leaf classloader case and you register the extra field support for the lifetime of the app [compress] is deployed into
* [fixes] fix @since tags and javadoc build, plus ensure backward compat with extra fields implementation registration
---
.../compress/archivers/zip/AsiExtraField.java | 2 +-
.../compress/archivers/zip/ExtraFieldUtils.java | 65 +++++++----
.../commons/compress/archivers/zip/JarMarker.java | 2 +-
.../archivers/zip/X0014_X509Certificates.java | 4 +-
.../archivers/zip/X0015_CertificateIdForFile.java | 4 +-
.../X0016_CertificateIdForCentralDirectory.java | 4 +-
.../zip/X0017_StrongEncryptionHeader.java | 4 +-
.../X0019_EncryptionRecipientCertificateList.java | 4 +-
.../compress/archivers/zip/X7875_NewUnix.java | 2 +-
.../compress/archivers/zip/ZipArchiveEntry.java | 119 +++++++++++++++++++--
.../archivers/zip/ZipArchiveInputStream.java | 16 +++
.../zip/ZipSplitReadOnlySeekableByteChannel.java | 1 +
.../compress/archivers/tar/FileTimesIT.java | 38 +++----
13 files changed, 209 insertions(+), 56 deletions(-)
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java b/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
index 856c4c918..57c7a7b8f 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/AsiExtraField.java
@@ -61,7 +61,7 @@ import java.util.zip.ZipException;
*/
public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable {
- private static final ZipShort HEADER_ID = new ZipShort(0x756E);
+ static final ZipShort HEADER_ID = new ZipShort(0x756E);
private static final int MIN_SIZE = WORD + SHORT + WORD + SHORT + SHORT;
/**
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java b/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
index a90131b19..0a2c84260 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ExtraFieldUtils.java
@@ -16,11 +16,14 @@
*/
package org.apache.commons.compress.archivers.zip;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
import java.util.zip.ZipException;
/**
@@ -113,24 +116,25 @@ public class ExtraFieldUtils {
/**
* Static registry of known extra fields.
*/
- private static final Map<ZipShort, Class<?>> IMPLEMENTATIONS;
+ private static final Map<ZipShort, Supplier<ZipExtraField>> IMPLEMENTATIONS;
static {
- IMPLEMENTATIONS = new ConcurrentHashMap<>();
- register(AsiExtraField.class);
- register(X5455_ExtendedTimestamp.class);
- register(X7875_NewUnix.class);
- register(JarMarker.class);
- register(UnicodePathExtraField.class);
- register(UnicodeCommentExtraField.class);
- register(Zip64ExtendedInformationExtraField.class);
- register(X000A_NTFS.class);
- register(X0014_X509Certificates.class);
- register(X0015_CertificateIdForFile.class);
- register(X0016_CertificateIdForCentralDirectory.class);
- register(X0017_StrongEncryptionHeader.class);
- register(X0019_EncryptionRecipientCertificateList.class);
- register(ResourceAlignmentExtraField.class);
+ IMPLEMENTATIONS = new ConcurrentHashMap<>(); // it can't be used at runtime by design so no need to be concurrent
+ // IMPLEMENTATIONS = new HashMap<>(); // see register() comment
+ IMPLEMENTATIONS.put(AsiExtraField.HEADER_ID, AsiExtraField::new);
+ IMPLEMENTATIONS.put(X5455_ExtendedTimestamp.HEADER_ID, X5455_ExtendedTimestamp::new);
+ IMPLEMENTATIONS.put(X7875_NewUnix.HEADER_ID, X7875_NewUnix::new);
+ IMPLEMENTATIONS.put(JarMarker.ID, JarMarker::new);
+ IMPLEMENTATIONS.put(UnicodePathExtraField.UPATH_ID, UnicodePathExtraField::new);
+ IMPLEMENTATIONS.put(UnicodeCommentExtraField.UCOM_ID, UnicodeCommentExtraField::new);
+ IMPLEMENTATIONS.put(Zip64ExtendedInformationExtraField.HEADER_ID, Zip64ExtendedInformationExtraField::new);
+ IMPLEMENTATIONS.put(X000A_NTFS.HEADER_ID, X000A_NTFS::new);
+ IMPLEMENTATIONS.put(X0014_X509Certificates.HEADER_ID, X0014_X509Certificates::new);
+ IMPLEMENTATIONS.put(X0015_CertificateIdForFile.HEADER_ID, X0015_CertificateIdForFile::new);
+ IMPLEMENTATIONS.put(X0016_CertificateIdForCentralDirectory.HEADER_ID, X0016_CertificateIdForCentralDirectory::new);
+ IMPLEMENTATIONS.put(X0017_StrongEncryptionHeader.HEADER_ID, X0017_StrongEncryptionHeader::new);
+ IMPLEMENTATIONS.put(X0019_EncryptionRecipientCertificateList.HEADER_ID, X0019_EncryptionRecipientCertificateList::new);
+ IMPLEMENTATIONS.put(ResourceAlignmentExtraField.ID, ResourceAlignmentExtraField::new);
}
static final ZipExtraField[] EMPTY_ZIP_EXTRA_FIELD_ARRAY = {};
@@ -163,9 +167,9 @@ public class ExtraFieldUtils {
* @since 1.19
*/
public static ZipExtraField createExtraFieldNoDefault(final ZipShort headerId) throws InstantiationException, IllegalAccessException {
- final Class<?> c = IMPLEMENTATIONS.get(headerId);
- if (c != null) {
- return (ZipExtraField) c.newInstance();
+ final Supplier<ZipExtraField> provider = IMPLEMENTATIONS.get(headerId);
+ if (provider != null) {
+ return provider.get();
}
return null;
}
@@ -379,11 +383,30 @@ public class ExtraFieldUtils {
* </p>
*
* @param c the class to register
+ *
+ * @deprecated use {@link ZipArchiveInputStream#setExtraFieldSupport} instead
+ * to not leak instances between archives and applications.
*/
+ @Deprecated // note: when dropping update registration to move to a HashMap (static init)
public static void register(final Class<?> c) {
try {
- final ZipExtraField ze = (ZipExtraField) c.getConstructor().newInstance();
- IMPLEMENTATIONS.put(ze.getHeaderId(), c);
+ final Constructor<? extends ZipExtraField> constructor = c
+ .asSubclass(ZipExtraField.class)
+ .getConstructor();
+ final ZipExtraField ze = constructor.newInstance();
+ IMPLEMENTATIONS.put(ze.getHeaderId(), () -> {
+ try {
+ return constructor.newInstance();
+ } catch (final InstantiationException | IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ } catch (final InvocationTargetException e) {
+ final Throwable cause = e.getTargetException();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ }
+ throw new IllegalStateException(cause);
+ }
+ });
} catch (final ClassCastException cc) { // NOSONAR
throw new IllegalArgumentException(c + " doesn't implement ZipExtraField"); // NOSONAR
} catch (final InstantiationException ie) { // NOSONAR
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java b/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java
index 031dc00e1..093a940e9 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/JarMarker.java
@@ -27,7 +27,7 @@ import org.apache.commons.compress.utils.ByteUtils;
*/
public final class JarMarker implements ZipExtraField {
- private static final ZipShort ID = new ZipShort(0xCAFE);
+ static final ZipShort ID = new ZipShort(0xCAFE);
private static final ZipShort NULL = new ZipShort(0);
private static final JarMarker DEFAULT = new JarMarker();
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java
index aa4b985d5..93a690d05 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0014_X509Certificates.java
@@ -44,8 +44,10 @@ package org.apache.commons.compress.archivers.zip;
*/
public class X0014_X509Certificates extends PKWareExtraHeader {
+ static final ZipShort HEADER_ID = new ZipShort(0x0014);
+
public X0014_X509Certificates() {
- super(new ZipShort(0x0014));
+ super(HEADER_ID);
}
}
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java
index 79c51925e..bd01381aa 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0015_CertificateIdForFile.java
@@ -47,12 +47,14 @@ import java.util.zip.ZipException;
*/
public class X0015_CertificateIdForFile extends PKWareExtraHeader {
+ static final ZipShort HEADER_ID = new ZipShort(0x0015);
+
private int rcount;
private HashAlgorithm hashAlg;
public X0015_CertificateIdForFile() {
- super(new ZipShort(0x0015));
+ super(HEADER_ID);
}
/**
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java
index 4af4bef54..43bd0da45 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0016_CertificateIdForCentralDirectory.java
@@ -48,12 +48,14 @@ import java.util.zip.ZipException;
*/
public class X0016_CertificateIdForCentralDirectory extends PKWareExtraHeader {
+ static final ZipShort HEADER_ID = new ZipShort(0x0016);
+
private int rcount;
private HashAlgorithm hashAlg;
public X0016_CertificateIdForCentralDirectory() {
- super(new ZipShort(0x0016));
+ super(HEADER_ID);
}
/**
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java
index fca05a6ac..d579949bd 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0017_StrongEncryptionHeader.java
@@ -257,6 +257,8 @@ import java.util.zip.ZipException;
*/
public class X0017_StrongEncryptionHeader extends PKWareExtraHeader {
+ static final ZipShort HEADER_ID = new ZipShort(0x0017);
+
private int format; // TODO written but not read
private EncryptionAlgorithm algId;
@@ -279,7 +281,7 @@ public class X0017_StrongEncryptionHeader extends PKWareExtraHeader {
private byte[] vCRC32;
public X0017_StrongEncryptionHeader() {
- super(new ZipShort(0x0017));
+ super(HEADER_ID);
}
private void assertDynamicLengthFits(final String what, final int dynamicLength, final int prefixLength, final int length) throws ZipException {
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java b/src/main/java/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java
index a3e5af807..9922a5847 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X0019_EncryptionRecipientCertificateList.java
@@ -50,8 +50,10 @@ package org.apache.commons.compress.archivers.zip;
*/
public class X0019_EncryptionRecipientCertificateList extends PKWareExtraHeader {
+ static final ZipShort HEADER_ID = new ZipShort(0x0019);
+
public X0019_EncryptionRecipientCertificateList() {
- super(new ZipShort(0x0019));
+ super(HEADER_ID);
}
}
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X7875_NewUnix.java b/src/main/java/org/apache/commons/compress/archivers/zip/X7875_NewUnix.java
index e36b187bc..fee17e57c 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/X7875_NewUnix.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/X7875_NewUnix.java
@@ -57,7 +57,7 @@ import org.apache.commons.compress.utils.ByteUtils;
* @since 1.5
*/
public class X7875_NewUnix implements ZipExtraField, Cloneable, Serializable {
- private static final ZipShort HEADER_ID = new ZipShort(0x7875);
+ static final ZipShort HEADER_ID = new ZipShort(0x7875);
private static final ZipShort ZERO = new ZipShort(0);
private static final BigInteger ONE_THOUSAND = BigInteger.valueOf(1000);
private static final long serialVersionUID = 1L;
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
index 125437d04..8ddded61c 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
@@ -30,6 +30,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.function.Function;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
@@ -265,6 +266,7 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
private long dataOffset = OFFSET_UNKNOWN;
private boolean isStreamContiguous;
private NameSource nameSource = NameSource.NAME;
+ private final Function<ZipShort, ZipExtraField> extraFieldFactory;
private CommentSource commentSource = CommentSource.COMMENT;
@@ -288,11 +290,13 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
* will be stripped from the entry name.
* </p>
*
+ * @param extraFieldFactory custom lookup factory for extra fields or null
* @param inputFile file to create the entry from
* @param entryName name of the entry
+ * @since 1.26.0
*/
- public ZipArchiveEntry(final File inputFile, final String entryName) {
- this(inputFile.isDirectory() && !entryName.endsWith("/") ? entryName + "/" : entryName);
+ ZipArchiveEntry(final Function<ZipShort, ZipExtraField> extraFieldFactory, final File inputFile, final String entryName) {
+ this(extraFieldFactory, inputFile.isDirectory() && !entryName.endsWith("/") ? entryName + "/" : entryName);
try {
setAttributes(inputFile.toPath());
} catch (final IOException e) { // NOSONAR
@@ -303,6 +307,21 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
}
}
+ /**
+ * Creates a new ZIP entry taking some information from the given file and using the provided name.
+ *
+ * <p>
+ * The name will be adjusted to end with a forward slash "/" if the file is a directory. If the file is not a directory a potential trailing forward slash
+ * will be stripped from the entry name.
+ * </p>
+ *
+ * @param inputFile file to create the entry from
+ * @param entryName name of the entry
+ */
+ public ZipArchiveEntry(final File inputFile, final String entryName) {
+ this(null, inputFile, entryName);
+ }
+
/**
* Creates a new ZIP entry with fields taken from the specified ZIP entry.
*
@@ -314,11 +333,29 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
* @throws ZipException on error
*/
public ZipArchiveEntry(final java.util.zip.ZipEntry entry) throws ZipException {
+ this(null, entry);
+ }
+
+ /**
+ * Creates a new ZIP entry with fields taken from the specified ZIP entry.
+ *
+ * <p>
+ * Assumes the entry represents a directory if and only if the name ends with a forward slash "/".
+ * </p>
+ *
+ * @param extraFieldFactory the extra field lookup factory.
+ * @param entry the entry to get fields from
+ * @throws ZipException on error
+ * @since 1.26.0
+ */
+ ZipArchiveEntry(final Function<ZipShort, ZipExtraField> extraFieldFactory,
+ final java.util.zip.ZipEntry entry) throws ZipException {
super(entry);
+ this.extraFieldFactory = extraFieldFactory;
setName(entry.getName());
final byte[] extra = entry.getExtra();
if (extra != null) {
- setExtraFields(ExtraFieldUtils.parse(extra, true, ExtraFieldParsingMode.BEST_EFFORT));
+ setExtraFields(parseExtraFields(extra, true, ExtraFieldParsingMode.BEST_EFFORT));
} else {
// initializes extra data to an empty byte array
setExtra();
@@ -342,7 +379,27 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
* @since 1.21
*/
public ZipArchiveEntry(final Path inputPath, final String entryName, final LinkOption... options) throws IOException {
- this(Files.isDirectory(inputPath, options) && !entryName.endsWith("/") ? entryName + "/" : entryName);
+ this(null, inputPath, entryName, options);
+ }
+
+ /**
+ * Creates a new ZIP entry taking some information from the given path and using the provided name.
+ *
+ * <p>
+ * The name will be adjusted to end with a forward slash "/" if the file is a directory. If the file is not a directory a potential trailing forward slash
+ * will be stripped from the entry name.
+ * </p>
+ *
+ * @param extraFieldFactory custom lookup factory for extra fields or null
+ * @param inputPath path to create the entry from.
+ * @param entryName name of the entry.
+ * @param options options indicating how symbolic links are handled.
+ * @throws IOException if an I/O error occurs.
+ * @since 1.26.0
+ */
+ ZipArchiveEntry(final Function<ZipShort, ZipExtraField> extraFieldFactory,
+ final Path inputPath, final String entryName, final LinkOption... options) throws IOException {
+ this(extraFieldFactory, Files.isDirectory(inputPath, options) && !entryName.endsWith("/") ? entryName + "/" : entryName);
setAttributes(inputPath, options);
}
@@ -354,9 +411,27 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
* </p>
*
* @param name the name of the entry
+ * @since 1.26.0
*/
public ZipArchiveEntry(final String name) {
+ this((Function<ZipShort, ZipExtraField>) null, name);
+ }
+
+ /**
+ * Creates a new ZIP entry with the specified name.
+ *
+ * <p>
+ * Assumes the entry represents a directory if and only if the name ends with a forward slash "/".
+ * </p>
+ *
+ * @param extraFieldFactory custom lookup factory for extra fields or null
+ * @param name the name of the entry
+ * @since 1.26.0
+ */
+ ZipArchiveEntry(final Function<ZipShort, ZipExtraField> extraFieldFactory,
+ final String name) {
super(name);
+ this.extraFieldFactory = extraFieldFactory;
setName(name);
}
@@ -642,9 +717,9 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
return getExtraFields(false);
}
final byte[] local = getExtra();
- final List<ZipExtraField> localFields = new ArrayList<>(Arrays.asList(ExtraFieldUtils.parse(local, true, parsingBehavior)));
+ final List<ZipExtraField> localFields = new ArrayList<>(Arrays.asList(parseExtraFields(local, true, parsingBehavior)));
final byte[] central = getCentralDirectoryExtra();
- final List<ZipExtraField> centralFields = new ArrayList<>(Arrays.asList(ExtraFieldUtils.parse(central, false, parsingBehavior)));
+ final List<ZipExtraField> centralFields = new ArrayList<>(Arrays.asList(parseExtraFields(central, false, parsingBehavior)));
final List<ZipExtraField> merged = new ArrayList<>();
for (final ZipExtraField l : localFields) {
ZipExtraField c;
@@ -1079,7 +1154,7 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
*/
public void setCentralDirectoryExtra(final byte[] b) {
try {
- mergeExtraFields(ExtraFieldUtils.parse(b, false, ExtraFieldParsingMode.BEST_EFFORT), false);
+ mergeExtraFields(parseExtraFields(b, false, ExtraFieldParsingMode.BEST_EFFORT), false);
} catch (final ZipException e) {
// actually this is not possible as of Commons Compress 1.19
throw new IllegalArgumentException(e.getMessage(), e); // NOSONAR
@@ -1157,7 +1232,7 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
@Override
public void setExtra(final byte[] extra) throws RuntimeException {
try {
- mergeExtraFields(ExtraFieldUtils.parse(extra, true, ExtraFieldParsingMode.BEST_EFFORT), true);
+ mergeExtraFields(parseExtraFields(extra, true, ExtraFieldParsingMode.BEST_EFFORT), true);
} catch (final ZipException e) {
// actually this is not possible as of Commons Compress 1.1
throw new IllegalArgumentException("Error parsing extra fields for entry: " // NOSONAR
@@ -1456,4 +1531,32 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEn
}
}
}
+
+ private ZipExtraField[] parseExtraFields(final byte[] data, final boolean local,
+ final ExtraFieldParsingBehavior parsingBehavior) throws ZipException {
+ if (extraFieldFactory != null) {
+ return ExtraFieldUtils.parse(data, local, new ExtraFieldParsingBehavior() {
+ @Override
+ public ZipExtraField createExtraField(final ZipShort headerId) throws ZipException, InstantiationException, IllegalAccessException {
+ final ZipExtraField field = extraFieldFactory.apply(headerId);
+ return field == null ? parsingBehavior.createExtraField(headerId) : field;
+ }
+
+ @Override
+ public ZipExtraField fill(final ZipExtraField field,
+ final byte[] data, final int off, final int len,
+ final boolean local) throws ZipException {
+ return parsingBehavior.fill(field, data, off, len, local);
+ }
+
+ @Override
+ public ZipExtraField onUnparseableExtraField(
+ final byte[] data, final int off, final int len,
+ final boolean local, final int claimedLength) throws ZipException {
+ return parsingBehavior.onUnparseableExtraField(data, off, len, local, claimedLength);
+ }
+ });
+ }
+ return ExtraFieldUtils.parse(data, local, parsingBehavior);
+ }
}
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
index 7b017bdee..d3b493fd6 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
@@ -33,6 +33,7 @@ import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Objects;
+import java.util.function.Function;
import java.util.zip.CRC32;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@@ -292,6 +293,11 @@ public class ZipArchiveInputStream extends ArchiveInputStream<ZipArchiveEntry> i
private int entriesRead;
+ /**
+ * The factory for extra fields or null.
+ */
+ private Function<ZipShort, ZipExtraField> extraFieldSupport;
+
/**
* Constructs an instance using UTF-8 encoding
*
@@ -360,6 +366,16 @@ public class ZipArchiveInputStream extends ArchiveInputStream<ZipArchiveEntry> i
buf.limit(0);
}
+ /**
+ * Enable custom extra fields factory.
+ * @param extraFieldSupport the lookup function based on extra field header id.
+ * @return the archive.
+ */
+ public ZipArchiveInputStream setExtraFieldSupport(final Function<ZipShort, ZipExtraField> extraFieldSupport) {
+ this.extraFieldSupport = extraFieldSupport;
+ return this;
+ }
+
/**
* Checks whether the current buffer contains the signature of a "data descriptor", "local file header" or "central directory
* entry".
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java
index 29815d25a..43ea678d8 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java
@@ -197,6 +197,7 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
*
* @param paths the file paths to concatenate, note that the LAST FILE of files should be the LAST SEGMENT(.zip) and these files should be added in correct
* order (e.g.: .z01, .z02... .z99, .zip)
+ * @param openOptions the options to open paths (shared by all paths).
* @return SeekableByteChannel that concatenates all provided files
* @throws NullPointerException if files is null
* @throws IOException if opening a channel for one of the files fails
diff --git a/src/test/java/org/apache/commons/compress/archivers/tar/FileTimesIT.java b/src/test/java/org/apache/commons/compress/archivers/tar/FileTimesIT.java
index ed8d6c0ea..d5414a62a 100644
--- a/src/test/java/org/apache/commons/compress/archivers/tar/FileTimesIT.java
+++ b/src/test/java/org/apache/commons/compress/archivers/tar/FileTimesIT.java
@@ -52,7 +52,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/", e.getName());
+ assertEquals("test/", e.getName());
assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
assertTrue(e.isDirectory());
assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getLastModifiedTime(), "mtime");
@@ -62,7 +62,7 @@ public class FileTimesIT extends AbstractTest {
e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/test-times.txt", e.getName());
+ assertEquals("test/test-times.txt", e.getName());
assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
assertTrue(e.isFile());
assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
@@ -81,7 +81,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveInputStream tin = new TarArchiveInputStream(in)) {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
- assertEquals("name", "test/", e.getName());
+ assertEquals("test/", e.getName());
assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
assertTrue(e.isDirectory());
assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getLastModifiedTime(), "mtime");
@@ -90,7 +90,7 @@ public class FileTimesIT extends AbstractTest {
assertNull(e.getCreationTime(), "birthtime");
assertGlobalHeaders(e);
e = tin.getNextTarEntry();
- assertEquals("name", "test/test-times.txt", e.getName());
+ assertEquals("test/test-times.txt", e.getName());
assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
assertTrue(e.isFile());
assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
@@ -130,7 +130,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test-times.txt", e.getName());
+ assertEquals("test-times.txt", e.getName());
assertEquals(toFileTime("2022-03-14T01:25:03Z"), e.getLastModifiedTime(), "mtime");
assertNull(e.getLastAccessTime(), "atime");
assertNull(e.getStatusChangeTime(), "ctime");
@@ -138,7 +138,7 @@ public class FileTimesIT extends AbstractTest {
e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test-times.txt", e.getName());
+ assertEquals("test-times.txt", e.getName());
assertEquals(toFileTime("2022-03-14T03:17:05Z"), e.getLastModifiedTime(), "mtime");
assertEquals(toFileTime("2022-03-14T03:17:10Z"), e.getLastAccessTime(), "atime");
assertEquals(toFileTime("2022-03-14T03:17:10Z"), e.getStatusChangeTime(), "ctime");
@@ -210,7 +210,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test-times.txt", e.getName());
+ assertEquals("test-times.txt", e.getName());
assertEquals(toFileTime("2022-03-14T01:25:03Z"), e.getLastModifiedTime(), "mtime");
assertNull(e.getLastAccessTime(), "atime");
assertNull(e.getStatusChangeTime(), "ctime");
@@ -218,7 +218,7 @@ public class FileTimesIT extends AbstractTest {
e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test-times.txt", e.getName());
+ assertEquals("test-times.txt", e.getName());
assertEquals(toFileTime("2022-03-14T03:17:05Z"), e.getLastModifiedTime(), "mtime");
assertEquals(toFileTime("2022-03-14T03:17:06Z"), e.getLastAccessTime(), "atime");
assertEquals(toFileTime("2022-03-14T03:17:05Z"), e.getStatusChangeTime(), "ctime");
@@ -237,7 +237,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/", e.getName());
+ assertEquals("test/", e.getName());
assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
assertTrue(e.isDirectory());
assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getLastModifiedTime(), "mtime");
@@ -247,7 +247,7 @@ public class FileTimesIT extends AbstractTest {
e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/test-times.txt", e.getName());
+ assertEquals("test/test-times.txt", e.getName());
assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
assertTrue(e.isFile());
assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");
@@ -286,7 +286,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/", e.getName());
+ assertEquals("test/", e.getName());
assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
assertTrue(e.isDirectory());
assertEquals(toFileTime("2022-03-16T10:19:43.382883700Z"), e.getLastModifiedTime(), "mtime");
@@ -296,7 +296,7 @@ public class FileTimesIT extends AbstractTest {
e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/test-times.txt", e.getName());
+ assertEquals("test/test-times.txt", e.getName());
assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
assertTrue(e.isFile());
assertEquals(toFileTime("2022-03-16T10:21:00.249238500Z"), e.getLastModifiedTime(), "mtime");
@@ -334,7 +334,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/", e.getName());
+ assertEquals("test/", e.getName());
assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
assertTrue(e.isDirectory());
assertEquals(toFileTime("2022-03-17T00:24:44Z"), e.getLastModifiedTime(), "mtime");
@@ -343,7 +343,7 @@ public class FileTimesIT extends AbstractTest {
assertNull(e.getCreationTime(), "birthtime");
e = tin.getNextTarEntry();
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/test-times.txt", e.getName());
+ assertEquals("test/test-times.txt", e.getName());
assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
assertTrue(e.isFile());
assertEquals(toFileTime("2022-03-17T00:38:20Z"), e.getLastModifiedTime(), "mtime");
@@ -414,7 +414,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/", e.getName());
+ assertEquals("test/", e.getName());
assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
assertTrue(e.isDirectory());
assertEquals(toFileTime("2022-03-17T00:24:44Z"), e.getLastModifiedTime(), "mtime");
@@ -422,7 +422,7 @@ public class FileTimesIT extends AbstractTest {
assertEquals(toFileTime("2022-03-17T00:24:44Z"), e.getStatusChangeTime(), "ctime");
assertNull(e.getCreationTime(), "birthtime");
e = tin.getNextTarEntry();
- assertEquals("name", "test/test-times.txt", e.getName());
+ assertEquals("test/test-times.txt", e.getName());
assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
assertTrue(e.isFile());
assertTrue(e.getExtraPaxHeaders().isEmpty());
@@ -443,7 +443,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test-times.txt", e.getName());
+ assertEquals("test-times.txt", e.getName());
assertEquals(toFileTime("2022-03-14T04:03:29Z"), e.getLastModifiedTime(), "mtime");
assertEquals(toFileTime("2022-03-14T04:03:29Z"), e.getLastAccessTime(), "atime");
assertEquals(toFileTime("2022-03-14T04:03:29Z"), e.getStatusChangeTime(), "ctime");
@@ -486,7 +486,7 @@ public class FileTimesIT extends AbstractTest {
TarArchiveEntry e = tin.getNextTarEntry();
assertNotNull(e);
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/", e.getName());
+ assertEquals("test/", e.getName());
assertEquals(TarConstants.LF_DIR, e.getLinkFlag());
assertTrue(e.isDirectory());
assertEquals(toFileTime("2022-03-17T00:24:44.147126600Z"), e.getLastModifiedTime(), "mtime");
@@ -495,7 +495,7 @@ public class FileTimesIT extends AbstractTest {
assertNull(e.getCreationTime(), "birthtime");
e = tin.getNextTarEntry();
assertTrue(e.getExtraPaxHeaders().isEmpty());
- assertEquals("name", "test/test-times.txt", e.getName());
+ assertEquals("test/test-times.txt", e.getName());
assertEquals(TarConstants.LF_NORMAL, e.getLinkFlag());
assertTrue(e.isFile());
assertEquals(toFileTime("2022-03-17T00:38:20.470751500Z"), e.getLastModifiedTime(), "mtime");