< prev index next >

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

Print this page




 308     // The outstanding inputstreams that need to be closed,
 309     // mapped to the inflater objects they use.
 310     private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
 311 
 312     /**
 313      * Returns an input stream for reading the contents of the specified
 314      * zip file entry.
 315      * <p>
 316      * Closing this ZIP file will, in turn, close all input streams that
 317      * have been returned by invocations of this method.
 318      *
 319      * @param entry the zip file entry
 320      * @return the input stream for reading the contents of the specified
 321      * zip file entry.
 322      * @throws ZipException if a ZIP format error has occurred
 323      * @throws IOException if an I/O error has occurred
 324      * @throws IllegalStateException if the zip file has been closed
 325      */
 326     public InputStream getInputStream(ZipEntry entry) throws IOException {
 327         Objects.requireNonNull(entry, "entry");







 328         int pos = -1;
 329         ZipFileInputStream in = null;
 330         synchronized (this) {
 331             ensureOpen();
 332             if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
 333                 pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
 334             } else {
 335                 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
 336             }
 337             if (pos == -1) {
 338                 return null;
 339             }
 340             in = new ZipFileInputStream(zsrc.cen, pos);
 341             switch (CENHOW(zsrc.cen, pos)) {
 342             case STORED:










 343                 synchronized (streams) {
 344                     streams.put(in, null);
 345                 }
 346                 return in;
 347             case DEFLATED:
 348                 // Inflater likes a bit of slack
 349                 // MORE: Compute good size for inflater stream:
 350                 long size = CENLEN(zsrc.cen, pos) + 2;
 351                 if (size > 65536) {
 352                     size = 8192;
 353                 }
 354                 if (size <= 0) {
 355                     size = 4096;
 356                 }
 357                 Inflater inf = getInflater();











 358                 InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size);
 359                 synchronized (streams) {
 360                     streams.put(is, inf);
 361                 }
 362                 return is;
 363             default:
 364                 throw new ZipException("invalid compression method");
 365             }
 366         }
 367     }
 368 
 369     private class ZipFileInflaterInputStream extends InflaterInputStream {
 370         private volatile boolean closeRequested;
 371         private boolean eof = false;
 372         private final ZipFileInputStream zfin;
 373 
 374         ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf,
 375                 int size) {
 376             super(zfin, inf, size);
 377             this.zfin = zfin;


 641         if (zsrc == null) {
 642             throw new IllegalStateException("The object is not initialized.");
 643         }
 644     }
 645 
 646     private void ensureOpenOrZipException() throws IOException {
 647         if (closeRequested) {
 648             throw new ZipException("ZipFile closed");
 649         }
 650     }
 651 
 652     /*
 653      * Inner class implementing the input stream used to read a
 654      * (possibly compressed) zip file entry.
 655      */
 656    private class ZipFileInputStream extends InputStream {
 657         private volatile boolean closeRequested;
 658         private   long pos;     // current position within entry data
 659         protected long rem;     // number of remaining bytes within entry
 660         protected long size;    // uncompressed size of this entry

 661 
 662         ZipFileInputStream(byte[] cen, int cenpos) throws IOException {

 663             rem = CENSIZ(cen, cenpos);
 664             size = CENLEN(cen, cenpos);
 665             pos = CENOFF(cen, cenpos);
 666             // zip64
 667             if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL ||
 668                 pos == ZIP64_MAGICVAL) {
 669                 checkZIP64(cen, cenpos);
 670             }
 671             // negative for lazy initialization, see getDataOffset();
 672             pos = - (pos + ZipFile.this.zsrc.locpos);

 673         }
 674 
 675         private void checkZIP64(byte[] cen, int cenpos) throws IOException {
 676             int off = cenpos + CENHDR + CENNAM(cen, cenpos);
 677             int end = off + CENEXT(cen, cenpos);
 678             while (off + 4 < end) {
 679                 int tag = get16(cen, off);
 680                 int sz = get16(cen, off + 2);
 681                 off += 4;
 682                 if (off + sz > end)         // invalid data
 683                     break;
 684                 if (tag == EXTID_ZIP64) {
 685                     if (size == ZIP64_MAGICVAL) {
 686                         if (sz < 8 || (off + 8) > end)
 687                             break;
 688                         size = get64(cen, off);
 689                         sz -= 8;
 690                         off += 8;
 691                     }
 692                     if (rem == ZIP64_MAGICVAL) {


 714         * the CEN extra data size, we need to read the LOC to determine
 715         * the entry data offset.
 716         */
 717         private long initDataOffset() throws IOException {
 718             if (pos <= 0) {
 719                 byte[] loc = new byte[LOCHDR];
 720                 pos = -pos;
 721                 int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos);
 722                 if (len != LOCHDR) {
 723                     throw new ZipException("ZipFile error reading zip file");
 724                 }
 725                 if (LOCSIG(loc) != LOCSIG) {
 726                     throw new ZipException("ZipFile invalid LOC header (bad signature)");
 727                 }
 728                 pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
 729             }
 730             return pos;
 731         }
 732 
 733         public int read(byte b[], int off, int len) throws IOException {










 734             synchronized (ZipFile.this) {
 735                 ensureOpenOrZipException();
 736                 initDataOffset();
 737                 if (rem == 0) {
 738                     return -1;
 739                 }
 740                 if (len > rem) {
 741                     len = (int) rem;
 742                 }
 743                 if (len <= 0) {
 744                     return 0;
 745                 }
 746                 len = ZipFile.this.zsrc.readAt(b, off, len, pos);
 747                 if (len > 0) {
 748                     pos += len;
 749                     rem -= len;
 750                 }
 751             }
 752             if (rem == 0) {
 753                 close();


1163 
1164             // Iterate through the entries in the central directory
1165             int i = 0;
1166             int hsh = 0;
1167             int pos = 0;
1168             int limit = cen.length - ENDHDR;
1169             while (pos + CENHDR  <= limit) {
1170                 if (i >= total) {
1171                     // This will only happen if the zip file has an incorrect
1172                     // ENDTOT field, which usually means it contains more than
1173                     // 65535 entries.
1174                     initCEN(countCENHeaders(cen, limit));
1175                     return;
1176                 }
1177                 if (CENSIG(cen, pos) != CENSIG)
1178                     zerror("invalid CEN header (bad signature)");
1179                 int method = CENHOW(cen, pos);
1180                 int nlen   = CENNAM(cen, pos);
1181                 int elen   = CENEXT(cen, pos);
1182                 int clen   = CENCOM(cen, pos);
1183                 if ((CENFLG(cen, pos) & 1) != 0)
1184                     zerror("invalid CEN header (encrypted entry)");
1185                 if (method != STORED && method != DEFLATED)
1186                     zerror("invalid CEN header (bad compression method: " + method + ")");
1187                 if (pos + CENHDR + nlen > limit)
1188                     zerror("invalid CEN header (bad header size)");
1189                 // Record the CEN offset and the name hash in our hash cell.
1190                 hash = hashN(cen, pos + CENHDR, nlen);
1191                 hsh = (hash & 0x7fffffff) % tablelen;
1192                 next = table[hsh];
1193                 table[hsh] = idx;
1194                 idx = addEntry(idx, hash, next, pos);
1195                 // Adds name to metanames.
1196                 if (isMetaName(cen, pos + CENHDR, nlen)) {
1197                     metanames.add(pos);
1198                 }
1199                 // skip ext and comment
1200                 pos += (CENHDR + nlen + elen + clen);
1201                 i++;
1202             }
1203             total = i;
1204             if (pos + ENDHDR != cen.length) {




 308     // The outstanding inputstreams that need to be closed,
 309     // mapped to the inflater objects they use.
 310     private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
 311 
 312     /**
 313      * Returns an input stream for reading the contents of the specified
 314      * zip file entry.
 315      * <p>
 316      * Closing this ZIP file will, in turn, close all input streams that
 317      * have been returned by invocations of this method.
 318      *
 319      * @param entry the zip file entry
 320      * @return the input stream for reading the contents of the specified
 321      * zip file entry.
 322      * @throws ZipException if a ZIP format error has occurred
 323      * @throws IOException if an I/O error has occurred
 324      * @throws IllegalStateException if the zip file has been closed
 325      */
 326     public InputStream getInputStream(ZipEntry entry) throws IOException {
 327         Objects.requireNonNull(entry, "entry");
 328         ZipCryption zipCryption = null;
 329 
 330         if (entry.isPassphraseRequired()) {
 331             zipCryption = entry.zipCryption;
 332             Objects.requireNonNull(zipCryption, "Passphrase is required.");
 333         }
 334 
 335         int pos = -1;
 336         ZipFileInputStream in = null;
 337         synchronized (this) {
 338             ensureOpen();
 339             if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
 340                 pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
 341             } else {
 342                 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
 343             }
 344             if (pos == -1) {
 345                 return null;
 346             }
 347             in = new ZipFileInputStream(zsrc.cen, pos, zipCryption);
 348             switch (CENHOW(zsrc.cen, pos)) {
 349             case STORED:
 350                 if (entry.isPassphraseRequired()) {
 351                     entry.encryptionHeader =
 352                         new byte[TraditionalZipCryption.ENCRYPTION_HEADER_SIZE];
 353                     in.readRaw(entry.encryptionHeader, 0,
 354                                               entry.encryptionHeader.length);
 355                     if (!entry.isValidPassphrase()) {
 356                         throw new ZipException("possibly incorrect passphrase");
 357                     }
 358                 }
 359 
 360                 synchronized (streams) {
 361                     streams.put(in, null);
 362                 }
 363                 return in;
 364             case DEFLATED:
 365                 // Inflater likes a bit of slack
 366                 // MORE: Compute good size for inflater stream:
 367                 long size = CENLEN(zsrc.cen, pos) + 2;
 368                 if (size > 65536) {
 369                     size = 8192;
 370                 }
 371                 if (size <= 0) {
 372                     size = 4096;
 373                 }
 374                 Inflater inf = getInflater();
 375 
 376                 if (entry.isPassphraseRequired()) {
 377                     entry.encryptionHeader =
 378                         new byte[TraditionalZipCryption.ENCRYPTION_HEADER_SIZE];
 379                     in.readRaw(entry.encryptionHeader, 0,
 380                                               entry.encryptionHeader.length);
 381                     if (!entry.isValidPassphrase()) {
 382                         throw new ZipException("possibly incorrect passphrase");
 383                     }
 384                 }
 385 
 386                 InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size);
 387                 synchronized (streams) {
 388                     streams.put(is, inf);
 389                 }
 390                 return is;
 391             default:
 392                 throw new ZipException("invalid compression method");
 393             }
 394         }
 395     }
 396 
 397     private class ZipFileInflaterInputStream extends InflaterInputStream {
 398         private volatile boolean closeRequested;
 399         private boolean eof = false;
 400         private final ZipFileInputStream zfin;
 401 
 402         ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf,
 403                 int size) {
 404             super(zfin, inf, size);
 405             this.zfin = zfin;


 669         if (zsrc == null) {
 670             throw new IllegalStateException("The object is not initialized.");
 671         }
 672     }
 673 
 674     private void ensureOpenOrZipException() throws IOException {
 675         if (closeRequested) {
 676             throw new ZipException("ZipFile closed");
 677         }
 678     }
 679 
 680     /*
 681      * Inner class implementing the input stream used to read a
 682      * (possibly compressed) zip file entry.
 683      */
 684    private class ZipFileInputStream extends InputStream {
 685         private volatile boolean closeRequested;
 686         private   long pos;     // current position within entry data
 687         protected long rem;     // number of remaining bytes within entry
 688         protected long size;    // uncompressed size of this entry
 689         private ZipCryption zipCryption; // ZIP encrypt/decrypt engine
 690 
 691         ZipFileInputStream(byte[] cen, int cenpos, ZipCryption zipCryption)
 692                                                             throws IOException {
 693             rem = CENSIZ(cen, cenpos);
 694             size = CENLEN(cen, cenpos);
 695             pos = CENOFF(cen, cenpos);
 696             // zip64
 697             if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL ||
 698                 pos == ZIP64_MAGICVAL) {
 699                 checkZIP64(cen, cenpos);
 700             }
 701             // negative for lazy initialization, see getDataOffset();
 702             pos = - (pos + ZipFile.this.zsrc.locpos);
 703             this.zipCryption = zipCryption;
 704         }
 705 
 706         private void checkZIP64(byte[] cen, int cenpos) throws IOException {
 707             int off = cenpos + CENHDR + CENNAM(cen, cenpos);
 708             int end = off + CENEXT(cen, cenpos);
 709             while (off + 4 < end) {
 710                 int tag = get16(cen, off);
 711                 int sz = get16(cen, off + 2);
 712                 off += 4;
 713                 if (off + sz > end)         // invalid data
 714                     break;
 715                 if (tag == EXTID_ZIP64) {
 716                     if (size == ZIP64_MAGICVAL) {
 717                         if (sz < 8 || (off + 8) > end)
 718                             break;
 719                         size = get64(cen, off);
 720                         sz -= 8;
 721                         off += 8;
 722                     }
 723                     if (rem == ZIP64_MAGICVAL) {


 745         * the CEN extra data size, we need to read the LOC to determine
 746         * the entry data offset.
 747         */
 748         private long initDataOffset() throws IOException {
 749             if (pos <= 0) {
 750                 byte[] loc = new byte[LOCHDR];
 751                 pos = -pos;
 752                 int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos);
 753                 if (len != LOCHDR) {
 754                     throw new ZipException("ZipFile error reading zip file");
 755                 }
 756                 if (LOCSIG(loc) != LOCSIG) {
 757                     throw new ZipException("ZipFile invalid LOC header (bad signature)");
 758                 }
 759                 pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
 760             }
 761             return pos;
 762         }
 763 
 764         public int read(byte b[], int off, int len) throws IOException {
 765             len = readRaw(b, off, len);
 766 
 767             if (zipCryption != null) {
 768                 zipCryption.decryptBytes(b, off, len);
 769             }
 770 
 771             return len;
 772         }
 773 
 774         public int readRaw(byte b[], int off, int len) throws IOException {
 775             synchronized (ZipFile.this) {
 776                 ensureOpenOrZipException();
 777                 initDataOffset();
 778                 if (rem == 0) {
 779                     return -1;
 780                 }
 781                 if (len > rem) {
 782                     len = (int) rem;
 783                 }
 784                 if (len <= 0) {
 785                     return 0;
 786                 }
 787                 len = ZipFile.this.zsrc.readAt(b, off, len, pos);
 788                 if (len > 0) {
 789                     pos += len;
 790                     rem -= len;
 791                 }
 792             }
 793             if (rem == 0) {
 794                 close();


1204 
1205             // Iterate through the entries in the central directory
1206             int i = 0;
1207             int hsh = 0;
1208             int pos = 0;
1209             int limit = cen.length - ENDHDR;
1210             while (pos + CENHDR  <= limit) {
1211                 if (i >= total) {
1212                     // This will only happen if the zip file has an incorrect
1213                     // ENDTOT field, which usually means it contains more than
1214                     // 65535 entries.
1215                     initCEN(countCENHeaders(cen, limit));
1216                     return;
1217                 }
1218                 if (CENSIG(cen, pos) != CENSIG)
1219                     zerror("invalid CEN header (bad signature)");
1220                 int method = CENHOW(cen, pos);
1221                 int nlen   = CENNAM(cen, pos);
1222                 int elen   = CENEXT(cen, pos);
1223                 int clen   = CENCOM(cen, pos);


1224                 if (method != STORED && method != DEFLATED)
1225                     zerror("invalid CEN header (bad compression method: " + method + ")");
1226                 if (pos + CENHDR + nlen > limit)
1227                     zerror("invalid CEN header (bad header size)");
1228                 // Record the CEN offset and the name hash in our hash cell.
1229                 hash = hashN(cen, pos + CENHDR, nlen);
1230                 hsh = (hash & 0x7fffffff) % tablelen;
1231                 next = table[hsh];
1232                 table[hsh] = idx;
1233                 idx = addEntry(idx, hash, next, pos);
1234                 // Adds name to metanames.
1235                 if (isMetaName(cen, pos + CENHDR, nlen)) {
1236                     metanames.add(pos);
1237                 }
1238                 // skip ext and comment
1239                 pos += (CENHDR + nlen + elen + clen);
1240                 i++;
1241             }
1242             total = i;
1243             if (pos + ENDHDR != cen.length) {


< prev index next >