360 * Closing this ZIP file will, in turn, close all input streams that
361 * have been returned by invocations of this method.
362 *
363 * @param entry the zip file entry
364 * @return the input stream for reading the contents of the specified
365 * zip file entry.
366 * @throws ZipException if a ZIP format error has occurred
367 * @throws IOException if an I/O error has occurred
368 * @throws IllegalStateException if the zip file has been closed
369 */
370 public InputStream getInputStream(ZipEntry entry) throws IOException {
371 Objects.requireNonNull(entry, "entry");
372 int pos = -1;
373 ZipFileInputStream in;
374 Source zsrc = res.zsrc;
375 Set<InputStream> istreams = res.istreams;
376 synchronized (this) {
377 ensureOpen();
378 if (Objects.equals(lastEntryName, entry.name)) {
379 pos = lastEntryPos;
380 } else if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
381 pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
382 } else {
383 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
384 }
385 if (pos == -1) {
386 return null;
387 }
388 in = new ZipFileInputStream(zsrc.cen, pos);
389 switch (CENHOW(zsrc.cen, pos)) {
390 case STORED:
391 synchronized (istreams) {
392 istreams.add(in);
393 }
394 return in;
395 case DEFLATED:
396 // Inflater likes a bit of slack
397 // MORE: Compute good size for inflater stream:
398 long size = CENLEN(zsrc.cen, pos) + 2;
399 if (size > 65536) {
400 size = 8192;
588 * Returns an ordered {@code Stream} over the ZIP file entries.
589 *
590 * Entries appear in the {@code Stream} in the order they appear in
591 * the central directory of the ZIP file.
592 *
593 * @return an ordered {@code Stream} of entries in this ZIP file
594 * @throws IllegalStateException if the zip file has been closed
595 * @since 1.8
596 */
597 public Stream<? extends ZipEntry> stream() {
598 synchronized (this) {
599 ensureOpen();
600 return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total,
601 pos -> getZipEntry(null, null, pos, ZipEntry::new)), false);
602 }
603 }
604
605 private String getEntryName(int pos) {
606 byte[] cen = res.zsrc.cen;
607 int nlen = CENNAM(cen, pos);
608 if (!zc.isUTF8() && (CENFLG(cen, pos) & EFS) != 0) {
609 return zc.toStringUTF8(cen, pos + CENHDR, nlen);
610 } else {
611 return zc.toString(cen, pos + CENHDR, nlen);
612 }
613 }
614
615 /*
616 * Returns an ordered {@code Stream} over the zip file entry names.
617 *
618 * Entry names appear in the {@code Stream} in the order they appear in
619 * the central directory of the ZIP file.
620 *
621 * @return an ordered {@code Stream} of entry names in this zip file
622 * @throws IllegalStateException if the zip file has been closed
623 * @since 10
624 */
625 private Stream<String> entryNameStream() {
626 synchronized (this) {
627 ensureOpen();
628 return StreamSupport.stream(
648 pos -> (JarEntry)getZipEntry(null, null, pos, func)), false);
649 }
650 }
651
652 private String lastEntryName;
653 private int lastEntryPos;
654
655 /* Checks ensureOpen() before invoke this method */
656 private ZipEntry getZipEntry(String name, byte[] bname, int pos,
657 Function<String, ? extends ZipEntry> func) {
658 byte[] cen = res.zsrc.cen;
659 int nlen = CENNAM(cen, pos);
660 int elen = CENEXT(cen, pos);
661 int clen = CENCOM(cen, pos);
662 int flag = CENFLG(cen, pos);
663 if (name == null || bname.length != nlen) {
664 // to use the entry name stored in cen, if the passed in name is
665 // (1) null, invoked from iterator, or
666 // (2) not equal to the name stored, a slash is appended during
667 // getEntryPos() search.
668 if (!zc.isUTF8() && (flag & EFS) != 0) {
669 name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
670 } else {
671 name = zc.toString(cen, pos + CENHDR, nlen);
672 }
673 }
674 ZipEntry e = func.apply(name); //ZipEntry e = new ZipEntry(name);
675 e.flag = flag;
676 e.xdostime = CENTIM(cen, pos);
677 e.crc = CENCRC(cen, pos);
678 e.size = CENLEN(cen, pos);
679 e.csize = CENSIZ(cen, pos);
680 e.method = CENHOW(cen, pos);
681 if (elen != 0) {
682 int start = pos + CENHDR + nlen;
683 e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true);
684 }
685 if (clen != 0) {
686 int start = pos + CENHDR + nlen + elen;
687 if (!zc.isUTF8() && (flag & EFS) != 0) {
688 e.comment = zc.toStringUTF8(cen, start, clen);
689 } else {
690 e.comment = zc.toString(cen, start, clen);
691 }
692 }
693 lastEntryName = e.name;
694 lastEntryPos = pos;
695 return e;
696 }
697
698 /**
699 * Returns the number of entries in the ZIP file.
700 *
701 * @return the number of entries in the ZIP file
702 * @throws IllegalStateException if the zip file has been closed
703 */
704 public int size() {
705 synchronized (this) {
706 ensureOpen();
707 return res.zsrc.total;
967 if (rem == ZIP64_MAGICVAL) {
968 if (sz < 8 || (off + 8) > end)
969 break;
970 rem = get64(cen, off);
971 sz -= 8;
972 off += 8;
973 }
974 if (pos == ZIP64_MAGICVAL) {
975 if (sz < 8 || (off + 8) > end)
976 break;
977 pos = get64(cen, off);
978 sz -= 8;
979 off += 8;
980 }
981 break;
982 }
983 off += sz;
984 }
985 }
986
987 /* The Zip file spec explicitly allows the LOC extra data size to
988 * be different from the CEN extra data size. Since we cannot trust
989 * the CEN extra data size, we need to read the LOC to determine
990 * the entry data offset.
991 */
992 private long initDataOffset() throws IOException {
993 if (pos <= 0) {
994 byte[] loc = new byte[LOCHDR];
995 pos = -pos;
996 int len = ZipFile.this.res.zsrc.readFullyAt(loc, 0, loc.length, pos);
997 if (len != LOCHDR) {
998 throw new ZipException("ZipFile error reading zip file");
999 }
1000 if (LOCSIG(loc) != LOCSIG) {
1001 throw new ZipException("ZipFile invalid LOC header (bad signature)");
1002 }
1003 pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1004 }
1005 return pos;
1006 }
1007
1272 try {
1273 this.zfile.close();
1274 } catch (IOException xx) {}
1275 throw x;
1276 }
1277 }
1278
1279 private void close() throws IOException {
1280 zfile.close();
1281 zfile = null;
1282 cen = null;
1283 entries = null;
1284 table = null;
1285 metanames = null;
1286 }
1287
1288 private static final int BUF_SIZE = 8192;
1289 private final int readFullyAt(byte[] buf, int off, int len, long pos)
1290 throws IOException
1291 {
1292 synchronized(zfile) {
1293 zfile.seek(pos);
1294 int N = len;
1295 while (N > 0) {
1296 int n = Math.min(BUF_SIZE, N);
1297 zfile.readFully(buf, off, n);
1298 off += n;
1299 N -= n;
1300 }
1301 return len;
1302 }
1303 }
1304
1305 private final int readAt(byte[] buf, int off, int len, long pos)
1306 throws IOException
1307 {
1308 synchronized(zfile) {
1309 zfile.seek(pos);
1310 return zfile.read(buf, off, len);
1311 }
1312 }
1313
1314 private static final int hashN(byte[] a, int off, int len) {
1315 int h = 1;
1316 while (len-- > 0) {
1317 h = 31 * h + a[off++];
1318 }
1319 return h;
1320 }
1321
1322 private static final int hash_append(int hash, byte b) {
1323 return hash * 31 + b;
1324 }
1325
1326 private static class End {
1327 int centot; // 4 bytes
1328 long cenlen; // 4 bytes
1527 private static void zerror(String msg) throws ZipException {
1528 throw new ZipException(msg);
1529 }
1530
1531 /*
1532 * Returns the {@code pos} of the zip cen entry corresponding to the
1533 * specified entry name, or -1 if not found.
1534 */
1535 private int getEntryPos(byte[] name, boolean addSlash) {
1536 if (total == 0) {
1537 return -1;
1538 }
1539 int hsh = hashN(name, 0, name.length);
1540 int idx = table[(hsh & 0x7fffffff) % tablelen];
1541 /*
1542 * This while loop is an optimization where a double lookup
1543 * for name and name+/ is being performed. The name char
1544 * array has enough room at the end to try again with a
1545 * slash appended if the first table lookup does not succeed.
1546 */
1547 while(true) {
1548 /*
1549 * Search down the target hash chain for a entry whose
1550 * 32 bit hash matches the hashed name.
1551 */
1552 while (idx != ZIP_ENDCHAIN) {
1553 if (getEntryHash(idx) == hsh) {
1554 // The CEN name must match the specfied one
1555 int pos = getEntryPos(idx);
1556 if (name.length == CENNAM(cen, pos)) {
1557 boolean matched = true;
1558 int nameoff = pos + CENHDR;
1559 for (int i = 0; i < name.length; i++) {
1560 if (name[i] != cen[nameoff++]) {
1561 matched = false;
1562 break;
1563 }
1564 }
1565 if (matched) {
1566 return pos;
1567 }
|
360 * Closing this ZIP file will, in turn, close all input streams that
361 * have been returned by invocations of this method.
362 *
363 * @param entry the zip file entry
364 * @return the input stream for reading the contents of the specified
365 * zip file entry.
366 * @throws ZipException if a ZIP format error has occurred
367 * @throws IOException if an I/O error has occurred
368 * @throws IllegalStateException if the zip file has been closed
369 */
370 public InputStream getInputStream(ZipEntry entry) throws IOException {
371 Objects.requireNonNull(entry, "entry");
372 int pos = -1;
373 ZipFileInputStream in;
374 Source zsrc = res.zsrc;
375 Set<InputStream> istreams = res.istreams;
376 synchronized (this) {
377 ensureOpen();
378 if (Objects.equals(lastEntryName, entry.name)) {
379 pos = lastEntryPos;
380 } else if (!zc.isUTF8() && (entry.flag & USE_UTF8) != 0) {
381 pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
382 } else {
383 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
384 }
385 if (pos == -1) {
386 return null;
387 }
388 in = new ZipFileInputStream(zsrc.cen, pos);
389 switch (CENHOW(zsrc.cen, pos)) {
390 case STORED:
391 synchronized (istreams) {
392 istreams.add(in);
393 }
394 return in;
395 case DEFLATED:
396 // Inflater likes a bit of slack
397 // MORE: Compute good size for inflater stream:
398 long size = CENLEN(zsrc.cen, pos) + 2;
399 if (size > 65536) {
400 size = 8192;
588 * Returns an ordered {@code Stream} over the ZIP file entries.
589 *
590 * Entries appear in the {@code Stream} in the order they appear in
591 * the central directory of the ZIP file.
592 *
593 * @return an ordered {@code Stream} of entries in this ZIP file
594 * @throws IllegalStateException if the zip file has been closed
595 * @since 1.8
596 */
597 public Stream<? extends ZipEntry> stream() {
598 synchronized (this) {
599 ensureOpen();
600 return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total,
601 pos -> getZipEntry(null, null, pos, ZipEntry::new)), false);
602 }
603 }
604
605 private String getEntryName(int pos) {
606 byte[] cen = res.zsrc.cen;
607 int nlen = CENNAM(cen, pos);
608 if (!zc.isUTF8() && (CENFLG(cen, pos) & USE_UTF8) != 0) {
609 return zc.toStringUTF8(cen, pos + CENHDR, nlen);
610 } else {
611 return zc.toString(cen, pos + CENHDR, nlen);
612 }
613 }
614
615 /*
616 * Returns an ordered {@code Stream} over the zip file entry names.
617 *
618 * Entry names appear in the {@code Stream} in the order they appear in
619 * the central directory of the ZIP file.
620 *
621 * @return an ordered {@code Stream} of entry names in this zip file
622 * @throws IllegalStateException if the zip file has been closed
623 * @since 10
624 */
625 private Stream<String> entryNameStream() {
626 synchronized (this) {
627 ensureOpen();
628 return StreamSupport.stream(
648 pos -> (JarEntry)getZipEntry(null, null, pos, func)), false);
649 }
650 }
651
652 private String lastEntryName;
653 private int lastEntryPos;
654
655 /* Checks ensureOpen() before invoke this method */
656 private ZipEntry getZipEntry(String name, byte[] bname, int pos,
657 Function<String, ? extends ZipEntry> func) {
658 byte[] cen = res.zsrc.cen;
659 int nlen = CENNAM(cen, pos);
660 int elen = CENEXT(cen, pos);
661 int clen = CENCOM(cen, pos);
662 int flag = CENFLG(cen, pos);
663 if (name == null || bname.length != nlen) {
664 // to use the entry name stored in cen, if the passed in name is
665 // (1) null, invoked from iterator, or
666 // (2) not equal to the name stored, a slash is appended during
667 // getEntryPos() search.
668 if (!zc.isUTF8() && (flag & USE_UTF8) != 0) {
669 name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
670 } else {
671 name = zc.toString(cen, pos + CENHDR, nlen);
672 }
673 }
674 ZipEntry e = func.apply(name); //ZipEntry e = new ZipEntry(name);
675 e.flag = flag;
676 e.xdostime = CENTIM(cen, pos);
677 e.crc = CENCRC(cen, pos);
678 e.size = CENLEN(cen, pos);
679 e.csize = CENSIZ(cen, pos);
680 e.method = CENHOW(cen, pos);
681 if (elen != 0) {
682 int start = pos + CENHDR + nlen;
683 e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true);
684 }
685 if (clen != 0) {
686 int start = pos + CENHDR + nlen + elen;
687 if (!zc.isUTF8() && (flag & USE_UTF8) != 0) {
688 e.comment = zc.toStringUTF8(cen, start, clen);
689 } else {
690 e.comment = zc.toString(cen, start, clen);
691 }
692 }
693 lastEntryName = e.name;
694 lastEntryPos = pos;
695 return e;
696 }
697
698 /**
699 * Returns the number of entries in the ZIP file.
700 *
701 * @return the number of entries in the ZIP file
702 * @throws IllegalStateException if the zip file has been closed
703 */
704 public int size() {
705 synchronized (this) {
706 ensureOpen();
707 return res.zsrc.total;
967 if (rem == ZIP64_MAGICVAL) {
968 if (sz < 8 || (off + 8) > end)
969 break;
970 rem = get64(cen, off);
971 sz -= 8;
972 off += 8;
973 }
974 if (pos == ZIP64_MAGICVAL) {
975 if (sz < 8 || (off + 8) > end)
976 break;
977 pos = get64(cen, off);
978 sz -= 8;
979 off += 8;
980 }
981 break;
982 }
983 off += sz;
984 }
985 }
986
987 /*
988 * The Zip file spec explicitly allows the LOC extra data size to
989 * be different from the CEN extra data size. Since we cannot trust
990 * the CEN extra data size, we need to read the LOC to determine
991 * the entry data offset.
992 */
993 private long initDataOffset() throws IOException {
994 if (pos <= 0) {
995 byte[] loc = new byte[LOCHDR];
996 pos = -pos;
997 int len = ZipFile.this.res.zsrc.readFullyAt(loc, 0, loc.length, pos);
998 if (len != LOCHDR) {
999 throw new ZipException("ZipFile error reading zip file");
1000 }
1001 if (LOCSIG(loc) != LOCSIG) {
1002 throw new ZipException("ZipFile invalid LOC header (bad signature)");
1003 }
1004 pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1005 }
1006 return pos;
1007 }
1008
1273 try {
1274 this.zfile.close();
1275 } catch (IOException xx) {}
1276 throw x;
1277 }
1278 }
1279
1280 private void close() throws IOException {
1281 zfile.close();
1282 zfile = null;
1283 cen = null;
1284 entries = null;
1285 table = null;
1286 metanames = null;
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
1306 private final int readAt(byte[] buf, int off, int len, long pos)
1307 throws IOException
1308 {
1309 synchronized (zfile) {
1310 zfile.seek(pos);
1311 return zfile.read(buf, off, len);
1312 }
1313 }
1314
1315 private static final int hashN(byte[] a, int off, int len) {
1316 int h = 1;
1317 while (len-- > 0) {
1318 h = 31 * h + a[off++];
1319 }
1320 return h;
1321 }
1322
1323 private static final int hash_append(int hash, byte b) {
1324 return hash * 31 + b;
1325 }
1326
1327 private static class End {
1328 int centot; // 4 bytes
1329 long cenlen; // 4 bytes
1528 private static void zerror(String msg) throws ZipException {
1529 throw new ZipException(msg);
1530 }
1531
1532 /*
1533 * Returns the {@code pos} of the zip cen entry corresponding to the
1534 * specified entry name, or -1 if not found.
1535 */
1536 private int getEntryPos(byte[] name, boolean addSlash) {
1537 if (total == 0) {
1538 return -1;
1539 }
1540 int hsh = hashN(name, 0, name.length);
1541 int idx = table[(hsh & 0x7fffffff) % tablelen];
1542 /*
1543 * This while loop is an optimization where a double lookup
1544 * for name and name+/ is being performed. The name char
1545 * array has enough room at the end to try again with a
1546 * slash appended if the first table lookup does not succeed.
1547 */
1548 while (true) {
1549 /*
1550 * Search down the target hash chain for a entry whose
1551 * 32 bit hash matches the hashed name.
1552 */
1553 while (idx != ZIP_ENDCHAIN) {
1554 if (getEntryHash(idx) == hsh) {
1555 // The CEN name must match the specfied one
1556 int pos = getEntryPos(idx);
1557 if (name.length == CENNAM(cen, pos)) {
1558 boolean matched = true;
1559 int nameoff = pos + CENHDR;
1560 for (int i = 0; i < name.length; i++) {
1561 if (name[i] != cen[nameoff++]) {
1562 matched = false;
1563 break;
1564 }
1565 }
1566 if (matched) {
1567 return pos;
1568 }
|