37
37
import java .nio .file .InvalidPathException ;
38
38
import java .nio .file .attribute .BasicFileAttributes ;
39
39
import java .nio .file .Files ;
40
- import java .util .ArrayDeque ;
41
- import java .util .ArrayList ;
42
- import java .util .Arrays ;
43
- import java .util .Collections ;
44
- import java .util .Deque ;
45
- import java .util .Enumeration ;
46
- import java .util .HashMap ;
47
- import java .util .Iterator ;
48
- import java .util .List ;
49
- import java .util .Locale ;
50
- import java .util .Objects ;
51
- import java .util .NoSuchElementException ;
52
- import java .util .Set ;
53
- import java .util .Spliterator ;
54
- import java .util .Spliterators ;
55
- import java .util .TreeSet ;
56
- import java .util .WeakHashMap ;
40
+ import java .util .*;
57
41
import java .util .function .Consumer ;
58
42
import java .util .function .IntFunction ;
59
43
import java .util .jar .JarEntry ;
64
48
import jdk .internal .access .JavaUtilJarAccess ;
65
49
import jdk .internal .access .SharedSecrets ;
66
50
import jdk .internal .util .ArraysSupport ;
51
+ import jdk .internal .util .DecimalDigits ;
67
52
import jdk .internal .util .OperatingSystem ;
68
53
import jdk .internal .perf .PerfCounter ;
69
54
import jdk .internal .ref .CleanerFactory ;
@@ -1090,19 +1075,23 @@ private String getManifestName(boolean onlyIfSignatureRelatedFiles) {
1090
1075
}
1091
1076
1092
1077
/**
1093
- * Returns the versions for which there exists a non-directory
1094
- * entry that begin with "META-INF/versions/" (case ignored).
1078
+ * Returns a BitSet where the set bits represents versions found for
1079
+ * the given entry name. For performance reasons, the name is looked
1080
+ * up only by hashcode, meaning the result is an over-approximation.
1095
1081
* This method is used in JarFile, via SharedSecrets, as an
1096
1082
* optimization when looking up potentially versioned entries.
1097
- * Returns an empty array if no versioned entries exist.
1083
+ * Returns an empty BitSet if no versioned entries exist for this
1084
+ * name.
1098
1085
*/
1099
- private int [] getMetaInfVersions () {
1086
+ private BitSet getMetaInfVersions (String name ) {
1100
1087
synchronized (this ) {
1101
1088
ensureOpen ();
1102
- return res .zsrc .metaVersions ;
1089
+ return res .zsrc .metaVersions . getOrDefault ( ZipCoder . hash ( name ), EMPTY_VERSIONS ) ;
1103
1090
}
1104
1091
}
1105
1092
1093
+ private static final BitSet EMPTY_VERSIONS = new BitSet ();
1094
+
1106
1095
/**
1107
1096
* Returns the value of the System property which indicates whether the
1108
1097
* Extra ZIP64 validation should be disabled.
@@ -1139,8 +1128,8 @@ public String getManifestName(JarFile jar, boolean onlyIfHasSignatureRelatedFile
1139
1128
return ((ZipFile )jar ).getManifestName (onlyIfHasSignatureRelatedFiles );
1140
1129
}
1141
1130
@ Override
1142
- public int [] getMetaInfVersions (JarFile jar ) {
1143
- return ((ZipFile )jar ).getMetaInfVersions ();
1131
+ public BitSet getMetaInfVersions (JarFile jar , String name ) {
1132
+ return ((ZipFile )jar ).getMetaInfVersions (name );
1144
1133
}
1145
1134
@ Override
1146
1135
public Enumeration <JarEntry > entries (ZipFile zip ) {
@@ -1175,7 +1164,8 @@ private static class Source {
1175
1164
private static final JavaUtilJarAccess JUJA = SharedSecrets .javaUtilJarAccess ();
1176
1165
// "META-INF/".length()
1177
1166
private static final int META_INF_LEN = 9 ;
1178
- private static final int [] EMPTY_META_VERSIONS = new int [0 ];
1167
+ // "META-INF/versions//".length()
1168
+ private static final int META_INF_VERSIONS_LEN = 19 ;
1179
1169
// CEN size is limited to the maximum array size in the JDK
1180
1170
private static final int MAX_CEN_SIZE = ArraysSupport .SOFT_MAX_ARRAY_LENGTH ;
1181
1171
@@ -1192,7 +1182,7 @@ private static class Source {
1192
1182
private int manifestPos = -1 ; // position of the META-INF/MANIFEST.MF, if exists
1193
1183
private int manifestNum = 0 ; // number of META-INF/MANIFEST.MF, case insensitive
1194
1184
private int [] signatureMetaNames ; // positions of signature related entries, if such exist
1195
- private int [] metaVersions ; // list of unique versions found in META-INF/versions/
1185
+ private Map < Integer , BitSet > metaVersions ; // Versions found in META-INF/versions/, by entry name hash
1196
1186
private final boolean startsWithLoc ; // true, if ZIP file starts with LOCSIG (usually true)
1197
1187
1198
1188
// A Hashmap for all entries.
@@ -1574,7 +1564,7 @@ private void close() throws IOException {
1574
1564
manifestPos = -1 ;
1575
1565
manifestNum = 0 ;
1576
1566
signatureMetaNames = null ;
1577
- metaVersions = EMPTY_META_VERSIONS ;
1567
+ metaVersions = null ;
1578
1568
}
1579
1569
1580
1570
private static final int BUF_SIZE = 8192 ;
@@ -1759,8 +1749,6 @@ private void initCEN(int knownTotal) throws IOException {
1759
1749
1760
1750
// list for all meta entries
1761
1751
ArrayList <Integer > signatureNames = null ;
1762
- // Set of all version numbers seen in META-INF/versions/
1763
- Set <Integer > metaVersionsSet = null ;
1764
1752
1765
1753
// Iterate through the entries in the central directory
1766
1754
int idx = 0 ; // Index into the entries array
@@ -1799,9 +1787,19 @@ private void initCEN(int knownTotal) throws IOException {
1799
1787
// performance in multi-release jar files
1800
1788
int version = getMetaVersion (entryPos + META_INF_LEN , nlen - META_INF_LEN );
1801
1789
if (version > 0 ) {
1802
- if (metaVersionsSet == null )
1803
- metaVersionsSet = new TreeSet <>();
1804
- metaVersionsSet .add (version );
1790
+ try {
1791
+ // Compute hash code of name from "META-INF/versions/{version)/{name}
1792
+ int prefixLen = META_INF_VERSIONS_LEN + DecimalDigits .stringSize (version );
1793
+ int hashCode = zipCoderForPos (pos ).checkedHash (cen ,
1794
+ entryPos + prefixLen ,
1795
+ nlen - prefixLen );
1796
+ // Register version for this hash code
1797
+ if (metaVersions == null )
1798
+ metaVersions = new HashMap <>();
1799
+ metaVersions .computeIfAbsent (hashCode , _ -> new BitSet ()).set (version );
1800
+ } catch (Exception e ) {
1801
+ throw new IllegalArgumentException (e );
1802
+ }
1805
1803
}
1806
1804
}
1807
1805
}
@@ -1819,14 +1817,8 @@ private void initCEN(int knownTotal) throws IOException {
1819
1817
signatureMetaNames [j ] = signatureNames .get (j );
1820
1818
}
1821
1819
}
1822
- if (metaVersionsSet != null ) {
1823
- metaVersions = new int [metaVersionsSet .size ()];
1824
- int c = 0 ;
1825
- for (Integer version : metaVersionsSet ) {
1826
- metaVersions [c ++] = version ;
1827
- }
1828
- } else {
1829
- metaVersions = EMPTY_META_VERSIONS ;
1820
+ if (metaVersions == null ) {
1821
+ metaVersions = Map .of ();
1830
1822
}
1831
1823
if (pos != cen .length ) {
1832
1824
zerror ("invalid CEN header (bad header size)" );
0 commit comments