< prev index next >

src/java.base/share/classes/java/util/zip/ZipFile.java

Print this page
rev 59204 : imported patch jarf_signature


  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'


< prev index next >