28 import java.io.Closeable;
29 import java.io.InputStream;
30 import java.io.IOException;
31 import java.io.EOFException;
32 import java.io.File;
33 import java.io.RandomAccessFile;
34 import java.io.UncheckedIOException;
35 import java.lang.ref.Cleaner.Cleanable;
36 import java.nio.charset.Charset;
37 import java.nio.file.InvalidPathException;
38 import java.nio.file.attribute.BasicFileAttributes;
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.Objects;
49 import java.util.NoSuchElementException;
50 import java.util.Set;
51 import java.util.Spliterator;
52 import java.util.Spliterators;
53 import java.util.TreeSet;
54 import java.util.WeakHashMap;
55 import java.util.function.Consumer;
56 import java.util.function.Function;
57 import java.util.function.IntFunction;
58 import java.util.jar.JarEntry;
59 import java.util.jar.JarFile;
60 import java.util.stream.Stream;
61 import java.util.stream.StreamSupport;
62 import jdk.internal.access.JavaUtilZipFileAccess;
63 import jdk.internal.access.SharedSecrets;
64 import jdk.internal.misc.VM;
65 import jdk.internal.perf.PerfCounter;
66 import jdk.internal.ref.CleanerFactory;
67 import jdk.internal.vm.annotation.Stable;
993 }
994
995 public long size() {
996 return size;
997 }
998
999 public void close() {
1000 if (closeRequested) {
1001 return;
1002 }
1003 closeRequested = true;
1004 rem = 0;
1005 synchronized (res.istreams) {
1006 res.istreams.remove(this);
1007 }
1008 }
1009
1010 }
1011
1012 /**
1013 * Returns the names of all non-directory entries that begin with
1014 * "META-INF/" (case ignored). This method is used in JarFile, via
1015 * SharedSecrets, as an optimization when looking up manifest and
1016 * signature file entries. Returns null if no entries were found.
1017 */
1018 private String[] getMetaInfEntryNames() {
1019 synchronized (this) {
1020 ensureOpen();
1021 Source zsrc = res.zsrc;
1022 if (zsrc.metanames == null) {
1023 return null;
1024 }
1025 String[] names = new String[zsrc.metanames.length];
1026 byte[] cen = zsrc.cen;
1027 for (int i = 0; i < names.length; i++) {
1028 int pos = zsrc.metanames[i];
1029 // This will only be invoked on JarFile, which is guaranteed
1030 // to use (or be compatible with) UTF-8 encoding.
1031 names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos),
1032 UTF_8.INSTANCE);
1033 }
1034 return names;
1035 }
1036 }
1037
1038 /**
1039 * Returns the versions for which there exists a non-directory
1040 * entry that begin with "META-INF/versions/" (case ignored).
1041 * This method is used in JarFile, via SharedSecrets, as an
1042 * optimization when looking up potentially versioned entries.
1043 * Returns an empty array if no versioned entries exist.
1044 */
1045 private int[] getMetaInfVersions() {
1046 synchronized (this) {
1047 ensureOpen();
1048 return res.zsrc.metaVersions;
1049 }
1050 }
1051
1052 private static boolean isWindows;
1053
1054 static {
1055 SharedSecrets.setJavaUtilZipFileAccess(
1056 new JavaUtilZipFileAccess() {
1057 @Override
1058 public boolean startsWithLocHeader(ZipFile zip) {
1059 return zip.res.zsrc.startsWithLoc;
1060 }
1061 @Override
1062 public String[] getMetaInfEntryNames(JarFile jar) {
1063 return ((ZipFile)jar).getMetaInfEntryNames();
1064 }
1065 @Override
1066 public int[] getMetaInfVersions(JarFile jar) {
1067 return ((ZipFile)jar).getMetaInfVersions();
1068 }
1069 @Override
1070 public JarEntry getEntry(ZipFile zip, String name,
1071 Function<String, JarEntry> func) {
1072 return (JarEntry)zip.getEntry(name, func);
1073 }
1074 @Override
1075 public Enumeration<JarEntry> entries(ZipFile zip,
1076 Function<String, JarEntry> func) {
1077 return zip.entries(func);
1078 }
1079 @Override
1080 public Stream<JarEntry> stream(ZipFile zip,
1081 Function<String, JarEntry> func) {
1082 return zip.stream(func);
1083 }
1088 }
1089 );
1090 isWindows = VM.getSavedProperty("os.name").contains("Windows");
1091 }
1092
1093 private static class Source {
1094 // "META-INF/".length()
1095 private static final int META_INF_LENGTH = 9;
1096 private static final int[] EMPTY_META_VERSIONS = new int[0];
1097
1098 private final Key key; // the key in files
1099 private final @Stable ZipCoder zc; // zip coder used to decode/encode
1100
1101 private int refs = 1;
1102
1103 private RandomAccessFile zfile; // zfile of the underlying zip file
1104 private byte[] cen; // CEN & ENDHDR
1105 private long locpos; // position of first LOC header (usually 0)
1106 private byte[] comment; // zip file comment
1107 // list of meta entries in META-INF dir
1108 private int[] metanames;
1109 private int[] metaVersions; // list of unique versions found in META-INF/versions/
1110 private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
1111
1112 // A Hashmap for all entries.
1113 //
1114 // A cen entry of Zip/JAR file. As we have one for every entry in every active Zip/JAR,
1115 // We might have a lot of these in a typical system. In order to save space we don't
1116 // keep the name in memory, but merely remember a 32 bit {@code hash} value of the
1117 // entry name and its offset {@code pos} in the central directory hdeader.
1118 //
1119 // private static class Entry {
1120 // int hash; // 32 bit hashcode on name
1121 // int next; // hash chain: index into entries
1122 // int pos; // Offset of central directory file header
1123 // }
1124 // private Entry[] entries; // array of hashed cen entry
1125 //
1126 // To reduce the total size of entries further, we use a int[] here to store 3 "int"
1127 // {@code hash}, {@code next and {@code "pos for each entry. The entry can then be
1128 // referred by their index of their positions in the {@code entries}.
1237 }
1238 try {
1239 initCEN(-1);
1240 byte[] buf = new byte[4];
1241 readFullyAt(buf, 0, 4, 0);
1242 this.startsWithLoc = (LOCSIG(buf) == LOCSIG);
1243 } catch (IOException x) {
1244 try {
1245 this.zfile.close();
1246 } catch (IOException xx) {}
1247 throw x;
1248 }
1249 }
1250
1251 private void close() throws IOException {
1252 zfile.close();
1253 zfile = null;
1254 cen = null;
1255 entries = null;
1256 table = null;
1257 metanames = null;
1258 metaVersions = EMPTY_META_VERSIONS;
1259 }
1260
1261 private static final int BUF_SIZE = 8192;
1262 private final int readFullyAt(byte[] buf, int off, int len, long pos)
1263 throws IOException
1264 {
1265 synchronized (zfile) {
1266 zfile.seek(pos);
1267 int N = len;
1268 while (N > 0) {
1269 int n = Math.min(BUF_SIZE, N);
1270 zfile.readFully(buf, off, n);
1271 off += n;
1272 N -= n;
1273 }
1274 return len;
1275 }
1276 }
1277
1421 total = end.centot;
1422 } else {
1423 cen = this.cen;
1424 total = knownTotal;
1425 }
1426 // hash table for entries
1427 entries = new int[total * 3];
1428
1429 this.tablelen = ((total/2) | 1); // Odd -> fewer collisions
1430 int tablelen = this.tablelen;
1431
1432 this.table = new int[tablelen];
1433 int[] table = this.table;
1434
1435 Arrays.fill(table, ZIP_ENDCHAIN);
1436 int idx = 0;
1437 int hash;
1438 int next;
1439
1440 // list for all meta entries
1441 ArrayList<Integer> metanamesList = null;
1442 // Set of all version numbers seen in META-INF/versions/
1443 Set<Integer> metaVersionsSet = null;
1444
1445 // Iterate through the entries in the central directory
1446 int i = 0;
1447 int hsh;
1448 int pos = 0;
1449 int entryPos = CENHDR;
1450 int limit = cen.length - ENDHDR;
1451 while (entryPos <= limit) {
1452 if (i >= total) {
1453 // This will only happen if the zip file has an incorrect
1454 // ENDTOT field, which usually means it contains more than
1455 // 65535 entries.
1456 initCEN(countCENHeaders(cen, limit));
1457 return;
1458 }
1459 if (CENSIG(cen, pos) != CENSIG)
1460 zerror("invalid CEN header (bad signature)");
1461 int method = CENHOW(cen, pos);
1462 int nlen = CENNAM(cen, pos);
1463 int elen = CENEXT(cen, pos);
1464 int clen = CENCOM(cen, pos);
1465 if ((CENFLG(cen, pos) & 1) != 0)
1466 zerror("invalid CEN header (encrypted entry)");
1467 if (method != STORED && method != DEFLATED)
1468 zerror("invalid CEN header (bad compression method: " + method + ")");
1469 if (entryPos + nlen > limit)
1470 zerror("invalid CEN header (bad header size)");
1471 // Record the CEN offset and the name hash in our hash cell.
1472 hash = zipCoderForPos(pos).normalizedHash(cen, entryPos, nlen);
1473 hsh = (hash & 0x7fffffff) % tablelen;
1474 next = table[hsh];
1475 table[hsh] = idx;
1476 idx = addEntry(idx, hash, next, pos);
1477 // Adds name to metanames.
1478 if (isMetaName(cen, entryPos, nlen)) {
1479 if (metanamesList == null)
1480 metanamesList = new ArrayList<>(4);
1481 metanamesList.add(pos);
1482
1483 // If this is a versioned entry, parse the version
1484 // and store it for later. This optimizes lookup
1485 // performance in multi-release jar files
1486 int version = getMetaVersion(cen,
1487 entryPos + META_INF_LENGTH, nlen - META_INF_LENGTH);
1488 if (version > 0) {
1489 if (metaVersionsSet == null)
1490 metaVersionsSet = new TreeSet<>();
1491 metaVersionsSet.add(version);
1492 }
1493 }
1494 // skip ext and comment
1495 pos = entryPos + nlen + elen + clen;
1496 entryPos = pos + CENHDR;
1497 i++;
1498 }
1499 total = i;
1500 if (metanamesList != null) {
1501 metanames = new int[metanamesList.size()];
1502 for (int j = 0, len = metanames.length; j < len; j++) {
1503 metanames[j] = metanamesList.get(j);
1504 }
1505 }
1506 if (metaVersionsSet != null) {
1507 metaVersions = new int[metaVersionsSet.size()];
1508 int c = 0;
1509 for (Integer version : metaVersionsSet) {
1510 metaVersions[c++] = version;
1511 }
1512 } else {
1513 metaVersions = EMPTY_META_VERSIONS;
1514 }
1515 if (pos + ENDHDR != cen.length) {
1516 zerror("invalid CEN header (bad header size)");
1517 }
1518 }
1519
1520 private static void zerror(String msg) throws ZipException {
1521 throw new ZipException(msg);
1522 }
1523
1575 return zc;
1576 }
1577
1578 /**
1579 * Returns true if the bytes represent a non-directory name
1580 * beginning with "META-INF/", disregarding ASCII case.
1581 */
1582 private static boolean isMetaName(byte[] name, int off, int len) {
1583 // Use the "oldest ASCII trick in the book"
1584 return len > META_INF_LENGTH // "META-INF/".length()
1585 && name[off + len - 1] != '/' // non-directory
1586 && (name[off++] | 0x20) == 'm'
1587 && (name[off++] | 0x20) == 'e'
1588 && (name[off++] | 0x20) == 't'
1589 && (name[off++] | 0x20) == 'a'
1590 && (name[off++] ) == '-'
1591 && (name[off++] | 0x20) == 'i'
1592 && (name[off++] | 0x20) == 'n'
1593 && (name[off++] | 0x20) == 'f'
1594 && (name[off] ) == '/';
1595 }
1596
1597 /*
1598 * If the bytes represents a non-directory name beginning
1599 * with "versions/", continuing with a positive integer,
1600 * followed by a '/', then return that integer value.
1601 * Otherwise, return 0
1602 */
1603 private static int getMetaVersion(byte[] name, int off, int len) {
1604 int nend = off + len;
1605 if (!(len > 10 // "versions//".length()
1606 && name[off + len - 1] != '/' // non-directory
1607 && (name[off++] | 0x20) == 'v'
1608 && (name[off++] | 0x20) == 'e'
1609 && (name[off++] | 0x20) == 'r'
1610 && (name[off++] | 0x20) == 's'
1611 && (name[off++] | 0x20) == 'i'
1612 && (name[off++] | 0x20) == 'o'
1613 && (name[off++] | 0x20) == 'n'
1614 && (name[off++] | 0x20) == 's'
|
28 import java.io.Closeable;
29 import java.io.InputStream;
30 import java.io.IOException;
31 import java.io.EOFException;
32 import java.io.File;
33 import java.io.RandomAccessFile;
34 import java.io.UncheckedIOException;
35 import java.lang.ref.Cleaner.Cleanable;
36 import java.nio.charset.Charset;
37 import java.nio.file.InvalidPathException;
38 import java.nio.file.attribute.BasicFileAttributes;
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;
57 import java.util.function.Consumer;
58 import java.util.function.Function;
59 import java.util.function.IntFunction;
60 import java.util.jar.JarEntry;
61 import java.util.jar.JarFile;
62 import java.util.stream.Stream;
63 import java.util.stream.StreamSupport;
64 import jdk.internal.access.JavaUtilZipFileAccess;
65 import jdk.internal.access.SharedSecrets;
66 import jdk.internal.misc.VM;
67 import jdk.internal.perf.PerfCounter;
68 import jdk.internal.ref.CleanerFactory;
69 import jdk.internal.vm.annotation.Stable;
995 }
996
997 public long size() {
998 return size;
999 }
1000
1001 public void close() {
1002 if (closeRequested) {
1003 return;
1004 }
1005 closeRequested = true;
1006 rem = 0;
1007 synchronized (res.istreams) {
1008 res.istreams.remove(this);
1009 }
1010 }
1011
1012 }
1013
1014 /**
1015 * Returns the names of the META-INF/MANIFEST.MF entry - if exists -
1016 * and any signature-related files under META-INF. This method is used in
1017 * JarFile, via SharedSecrets, as an optimization.
1018 */
1019 private List<String> getManifestAndSignatureRelatedFiles() {
1020 synchronized (this) {
1021 ensureOpen();
1022 Source zsrc = res.zsrc;
1023 int[] metanames = zsrc.signatureMetaNames;
1024 List<String> files = null;
1025 if (zsrc.manifestPos >= 0) {
1026 files = new ArrayList<>();
1027 files.add(getEntryName(zsrc.manifestPos));
1028 }
1029 if (metanames != null) {
1030 if (files == null) {
1031 files = new ArrayList<>();
1032 }
1033 for (int i = 0; i < metanames.length; i++) {
1034 files.add(getEntryName(metanames[i]));
1035 }
1036 }
1037 return files == null ? List.of() : files;
1038 }
1039 }
1040
1041 /**
1042 * Returns the name of the META-INF/MANIFEST.MF entry, ignoring
1043 * case. If {@code onlyIfSignatureRelatedFiles} is true, we only return the
1044 * manifest if there is also at least one signature-related file.
1045 * This method is used in JarFile, via SharedSecrets, as an optimization
1046 * when looking up the manifest file.
1047 */
1048 private String getManifestName(boolean onlyIfSignatureRelatedFiles) {
1049 synchronized (this) {
1050 ensureOpen();
1051 Source zsrc = res.zsrc;
1052 int pos = zsrc.manifestPos;
1053 if (pos >= 0 && (!onlyIfSignatureRelatedFiles || zsrc.signatureMetaNames != null)) {
1054 return getEntryName(pos);
1055 }
1056 }
1057 return null;
1058 }
1059
1060 /**
1061 * Returns the versions for which there exists a non-directory
1062 * entry that begin with "META-INF/versions/" (case ignored).
1063 * This method is used in JarFile, via SharedSecrets, as an
1064 * optimization when looking up potentially versioned entries.
1065 * Returns an empty array if no versioned entries exist.
1066 */
1067 private int[] getMetaInfVersions() {
1068 synchronized (this) {
1069 ensureOpen();
1070 return res.zsrc.metaVersions;
1071 }
1072 }
1073
1074 private static boolean isWindows;
1075
1076 static {
1077 SharedSecrets.setJavaUtilZipFileAccess(
1078 new JavaUtilZipFileAccess() {
1079 @Override
1080 public boolean startsWithLocHeader(ZipFile zip) {
1081 return zip.res.zsrc.startsWithLoc;
1082 }
1083 @Override
1084 public List<String> getManifestAndSignatureRelatedFiles(JarFile jar) {
1085 return ((ZipFile)jar).getManifestAndSignatureRelatedFiles();
1086 }
1087 @Override
1088 public String getManifestName(JarFile jar, boolean onlyIfHasSignatureRelatedFiles) {
1089 return ((ZipFile)jar).getManifestName(onlyIfHasSignatureRelatedFiles);
1090 }
1091 @Override
1092 public int[] getMetaInfVersions(JarFile jar) {
1093 return ((ZipFile)jar).getMetaInfVersions();
1094 }
1095 @Override
1096 public JarEntry getEntry(ZipFile zip, String name,
1097 Function<String, JarEntry> func) {
1098 return (JarEntry)zip.getEntry(name, func);
1099 }
1100 @Override
1101 public Enumeration<JarEntry> entries(ZipFile zip,
1102 Function<String, JarEntry> func) {
1103 return zip.entries(func);
1104 }
1105 @Override
1106 public Stream<JarEntry> stream(ZipFile zip,
1107 Function<String, JarEntry> func) {
1108 return zip.stream(func);
1109 }
1114 }
1115 );
1116 isWindows = VM.getSavedProperty("os.name").contains("Windows");
1117 }
1118
1119 private static class Source {
1120 // "META-INF/".length()
1121 private static final int META_INF_LENGTH = 9;
1122 private static final int[] EMPTY_META_VERSIONS = new int[0];
1123
1124 private final Key key; // the key in files
1125 private final @Stable ZipCoder zc; // zip coder used to decode/encode
1126
1127 private int refs = 1;
1128
1129 private RandomAccessFile zfile; // zfile of the underlying zip file
1130 private byte[] cen; // CEN & ENDHDR
1131 private long locpos; // position of first LOC header (usually 0)
1132 private byte[] comment; // zip file comment
1133 // list of meta entries in META-INF dir
1134 private int manifestPos = -1; // position of the META-INF/MANIFEST.MF, if exists
1135 private int[] signatureMetaNames; // positions of signature related entries, if such exist
1136 private int[] metaVersions; // list of unique versions found in META-INF/versions/
1137 private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
1138
1139 // A Hashmap for all entries.
1140 //
1141 // A cen entry of Zip/JAR file. As we have one for every entry in every active Zip/JAR,
1142 // We might have a lot of these in a typical system. In order to save space we don't
1143 // keep the name in memory, but merely remember a 32 bit {@code hash} value of the
1144 // entry name and its offset {@code pos} in the central directory hdeader.
1145 //
1146 // private static class Entry {
1147 // int hash; // 32 bit hashcode on name
1148 // int next; // hash chain: index into entries
1149 // int pos; // Offset of central directory file header
1150 // }
1151 // private Entry[] entries; // array of hashed cen entry
1152 //
1153 // To reduce the total size of entries further, we use a int[] here to store 3 "int"
1154 // {@code hash}, {@code next and {@code "pos for each entry. The entry can then be
1155 // referred by their index of their positions in the {@code entries}.
1264 }
1265 try {
1266 initCEN(-1);
1267 byte[] buf = new byte[4];
1268 readFullyAt(buf, 0, 4, 0);
1269 this.startsWithLoc = (LOCSIG(buf) == LOCSIG);
1270 } catch (IOException x) {
1271 try {
1272 this.zfile.close();
1273 } catch (IOException xx) {}
1274 throw x;
1275 }
1276 }
1277
1278 private void close() throws IOException {
1279 zfile.close();
1280 zfile = null;
1281 cen = null;
1282 entries = null;
1283 table = null;
1284 manifestPos = -1;
1285 signatureMetaNames = null;
1286 metaVersions = EMPTY_META_VERSIONS;
1287 }
1288
1289 private static final int BUF_SIZE = 8192;
1290 private final int readFullyAt(byte[] buf, int off, int len, long pos)
1291 throws IOException
1292 {
1293 synchronized (zfile) {
1294 zfile.seek(pos);
1295 int N = len;
1296 while (N > 0) {
1297 int n = Math.min(BUF_SIZE, N);
1298 zfile.readFully(buf, off, n);
1299 off += n;
1300 N -= n;
1301 }
1302 return len;
1303 }
1304 }
1305
1449 total = end.centot;
1450 } else {
1451 cen = this.cen;
1452 total = knownTotal;
1453 }
1454 // hash table for entries
1455 entries = new int[total * 3];
1456
1457 this.tablelen = ((total/2) | 1); // Odd -> fewer collisions
1458 int tablelen = this.tablelen;
1459
1460 this.table = new int[tablelen];
1461 int[] table = this.table;
1462
1463 Arrays.fill(table, ZIP_ENDCHAIN);
1464 int idx = 0;
1465 int hash;
1466 int next;
1467
1468 // list for all meta entries
1469 ArrayList<Integer> signatureNames = null;
1470 // Set of all version numbers seen in META-INF/versions/
1471 Set<Integer> metaVersionsSet = null;
1472
1473 // Iterate through the entries in the central directory
1474 int i = 0;
1475 int hsh;
1476 int pos = 0;
1477 int entryPos = CENHDR;
1478 int limit = cen.length - ENDHDR;
1479 while (entryPos <= limit) {
1480 if (i >= total) {
1481 // This will only happen if the zip file has an incorrect
1482 // ENDTOT field, which usually means it contains more than
1483 // 65535 entries.
1484 initCEN(countCENHeaders(cen, limit));
1485 return;
1486 }
1487 if (CENSIG(cen, pos) != CENSIG)
1488 zerror("invalid CEN header (bad signature)");
1489 int method = CENHOW(cen, pos);
1490 int nlen = CENNAM(cen, pos);
1491 int elen = CENEXT(cen, pos);
1492 int clen = CENCOM(cen, pos);
1493 if ((CENFLG(cen, pos) & 1) != 0)
1494 zerror("invalid CEN header (encrypted entry)");
1495 if (method != STORED && method != DEFLATED)
1496 zerror("invalid CEN header (bad compression method: " + method + ")");
1497 if (entryPos + nlen > limit)
1498 zerror("invalid CEN header (bad header size)");
1499 // Record the CEN offset and the name hash in our hash cell.
1500 hash = zipCoderForPos(pos).normalizedHash(cen, entryPos, nlen);
1501 hsh = (hash & 0x7fffffff) % tablelen;
1502 next = table[hsh];
1503 table[hsh] = idx;
1504 idx = addEntry(idx, hash, next, pos);
1505 // Adds name to metanames.
1506 if (isMetaName(cen, entryPos, nlen)) {
1507 if (isManifestName(cen, entryPos + META_INF_LENGTH,
1508 nlen - META_INF_LENGTH)) {
1509 manifestPos = entryPos;
1510 } else {
1511 if (isSignatureRelated(cen, entryPos, nlen)) {
1512 if (signatureNames == null)
1513 signatureNames = new ArrayList<>(4);
1514 signatureNames.add(pos);
1515 }
1516
1517 // If this is a versioned entry, parse the version
1518 // and store it for later. This optimizes lookup
1519 // performance in multi-release jar files
1520 int version = getMetaVersion(cen,
1521 entryPos + META_INF_LENGTH, nlen - META_INF_LENGTH);
1522 if (version > 0) {
1523 if (metaVersionsSet == null)
1524 metaVersionsSet = new TreeSet<>();
1525 metaVersionsSet.add(version);
1526 }
1527 }
1528 }
1529 // skip ext and comment
1530 pos = entryPos + nlen + elen + clen;
1531 entryPos = pos + CENHDR;
1532 i++;
1533 }
1534 total = i;
1535 if (signatureNames != null) {
1536 int len = signatureNames.size();
1537 signatureMetaNames = new int[len];
1538 for (int j = 0; j < len; j++) {
1539 signatureMetaNames[j] = signatureNames.get(j);
1540 }
1541 }
1542 if (metaVersionsSet != null) {
1543 metaVersions = new int[metaVersionsSet.size()];
1544 int c = 0;
1545 for (Integer version : metaVersionsSet) {
1546 metaVersions[c++] = version;
1547 }
1548 } else {
1549 metaVersions = EMPTY_META_VERSIONS;
1550 }
1551 if (pos + ENDHDR != cen.length) {
1552 zerror("invalid CEN header (bad header size)");
1553 }
1554 }
1555
1556 private static void zerror(String msg) throws ZipException {
1557 throw new ZipException(msg);
1558 }
1559
1611 return zc;
1612 }
1613
1614 /**
1615 * Returns true if the bytes represent a non-directory name
1616 * beginning with "META-INF/", disregarding ASCII case.
1617 */
1618 private static boolean isMetaName(byte[] name, int off, int len) {
1619 // Use the "oldest ASCII trick in the book"
1620 return len > META_INF_LENGTH // "META-INF/".length()
1621 && name[off + len - 1] != '/' // non-directory
1622 && (name[off++] | 0x20) == 'm'
1623 && (name[off++] | 0x20) == 'e'
1624 && (name[off++] | 0x20) == 't'
1625 && (name[off++] | 0x20) == 'a'
1626 && (name[off++] ) == '-'
1627 && (name[off++] | 0x20) == 'i'
1628 && (name[off++] | 0x20) == 'n'
1629 && (name[off++] | 0x20) == 'f'
1630 && (name[off] ) == '/';
1631 }
1632
1633 /*
1634 * Check if the bytes represents a name equals to MANIFEST.MF
1635 */
1636 private static boolean isManifestName(byte[] name, int off, int len) {
1637 return (len == 11 // "MANIFEST.MF".length()
1638 && (name[off++] | 0x20) == 'm'
1639 && (name[off++] | 0x20) == 'a'
1640 && (name[off++] | 0x20) == 'n'
1641 && (name[off++] | 0x20) == 'i'
1642 && (name[off++] | 0x20) == 'f'
1643 && (name[off++] | 0x20) == 'e'
1644 && (name[off++] | 0x20) == 's'
1645 && (name[off++] | 0x20) == 't'
1646 && (name[off++] | 0x20) == '.'
1647 && (name[off++] | 0x20) == 'm'
1648 && (name[off++] | 0x20) == 'f');
1649 }
1650
1651 private boolean isSignatureRelated(byte[] cen, int start, int len) {
1652 // Check if entry ends with .EC and .SF
1653 if (cen[start + len - 3] == '.') {
1654 int b1 = cen[start + len - 2] | 0x20;
1655 int b2 = cen[start + len - 1] | 0x20;
1656 if ((b1 == 'e' && b2 == 'c') || (b1 == 's' && b2 == 'f')) {
1657 return true;
1658 }
1659 }
1660 // Check if entry ends with .DSA and .RSA
1661 if (cen[start + len - 4] == '.') {
1662 int b1 = cen[start + len - 3] | 0x20;
1663 int b2 = cen[start + len - 2] | 0x20;
1664 int b3 = cen[start + len - 1] | 0x20;
1665 if ((b1 == 'r' || b1 == 'd') && b2 == 's' && b3 == 'a') {
1666 return true;
1667 }
1668 }
1669 return false;
1670 }
1671
1672 /*
1673 * If the bytes represents a non-directory name beginning
1674 * with "versions/", continuing with a positive integer,
1675 * followed by a '/', then return that integer value.
1676 * Otherwise, return 0
1677 */
1678 private static int getMetaVersion(byte[] name, int off, int len) {
1679 int nend = off + len;
1680 if (!(len > 10 // "versions//".length()
1681 && name[off + len - 1] != '/' // non-directory
1682 && (name[off++] | 0x20) == 'v'
1683 && (name[off++] | 0x20) == 'e'
1684 && (name[off++] | 0x20) == 'r'
1685 && (name[off++] | 0x20) == 's'
1686 && (name[off++] | 0x20) == 'i'
1687 && (name[off++] | 0x20) == 'o'
1688 && (name[off++] | 0x20) == 'n'
1689 && (name[off++] | 0x20) == 's'
|