< prev index next >

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

Print this page




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






















 326         Objects.requireNonNull(entry, "entry");






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










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












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


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

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

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

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


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










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


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




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


 690         if (zsrc == null) {
 691             throw new IllegalStateException("The object is not initialized.");
 692         }
 693     }
 694 
 695     private void ensureOpenOrZipException() throws IOException {
 696         if (closeRequested) {
 697             throw new ZipException("ZipFile closed");
 698         }
 699     }
 700 
 701     /*
 702      * Inner class implementing the input stream used to read a
 703      * (possibly compressed) zip file entry.
 704      */
 705    private class ZipFileInputStream extends InputStream {
 706         private volatile boolean closeRequested = false;
 707         private   long pos;     // current position within entry data
 708         protected long rem;     // number of remaining bytes within entry
 709         protected long size;    // uncompressed size of this entry
 710         private ZipCryption zipCryption; // ZIP encrypt/decrypt engine
 711 
 712         ZipFileInputStream(byte[] cen, int cenpos, ZipCryption zipCryption)
 713                                                             throws IOException {
 714             rem = CENSIZ(cen, cenpos);
 715             size = CENLEN(cen, cenpos);
 716             pos = CENOFF(cen, cenpos);
 717             // zip64
 718             if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL ||
 719                 pos == ZIP64_MAGICVAL) {
 720                 checkZIP64(cen, cenpos);
 721             }
 722             // negative for lazy initialization, see getDataOffset();
 723             pos = - (pos + ZipFile.this.zsrc.locpos);
 724             this.zipCryption = zipCryption;
 725         }
 726 
 727         private void checkZIP64(byte[] cen, int cenpos) throws IOException {
 728             int off = cenpos + CENHDR + CENNAM(cen, cenpos);
 729             int end = off + CENEXT(cen, cenpos);
 730             while (off + 4 < end) {
 731                 int tag = get16(cen, off);
 732                 int sz = get16(cen, off + 2);
 733                 off += 4;
 734                 if (off + sz > end)         // invalid data
 735                     break;
 736                 if (tag == EXTID_ZIP64) {
 737                     if (size == ZIP64_MAGICVAL) {
 738                         if (sz < 8 || (off + 8) > end)
 739                             break;
 740                         size = get64(cen, off);
 741                         sz -= 8;
 742                         off += 8;
 743                     }
 744                     if (rem == ZIP64_MAGICVAL) {


 766         * the CEN extra data size, we need to read the LOC to determine
 767         * the entry data offset.
 768         */
 769         private long initDataOffset() throws IOException {
 770             if (pos <= 0) {
 771                 byte[] loc = new byte[LOCHDR];
 772                 pos = -pos;
 773                 int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos);
 774                 if (len != LOCHDR) {
 775                     throw new ZipException("ZipFile error reading zip file");
 776                 }
 777                 if (LOCSIG(loc) != LOCSIG) {
 778                     throw new ZipException("ZipFile invalid LOC header (bad signature)");
 779                 }
 780                 pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
 781             }
 782             return pos;
 783         }
 784 
 785         public int read(byte b[], int off, int len) throws IOException {
 786             len = readRaw(b, off, len);
 787 
 788             if (zipCryption != null) {
 789                 zipCryption.decryptBytes(b, off, len);
 790             }
 791 
 792             return len;
 793         }
 794 
 795         public int readRaw(byte b[], int off, int len) throws IOException {
 796             synchronized (ZipFile.this) {
 797                 ensureOpenOrZipException();
 798                 initDataOffset();
 799                 if (rem == 0) {
 800                     return -1;
 801                 }
 802                 if (len > rem) {
 803                     len = (int) rem;
 804                 }
 805                 if (len <= 0) {
 806                     return 0;
 807                 }
 808                 len = ZipFile.this.zsrc.readAt(b, off, len, pos);
 809                 if (len > 0) {
 810                     pos += len;
 811                     rem -= len;
 812                 }
 813             }
 814             if (rem == 0) {
 815                 close();


1225 
1226             // Iterate through the entries in the central directory
1227             int i = 0;
1228             int hsh = 0;
1229             int pos = 0;
1230             int limit = cen.length - ENDHDR;
1231             while (pos + CENHDR  <= limit) {
1232                 if (i >= total) {
1233                     // This will only happen if the zip file has an incorrect
1234                     // ENDTOT field, which usually means it contains more than
1235                     // 65535 entries.
1236                     initCEN(countCENHeaders(cen, limit));
1237                     return;
1238                 }
1239                 if (CENSIG(cen, pos) != CENSIG)
1240                     zerror("invalid CEN header (bad signature)");
1241                 int method = CENHOW(cen, pos);
1242                 int nlen   = CENNAM(cen, pos);
1243                 int elen   = CENEXT(cen, pos);
1244                 int clen   = CENCOM(cen, pos);


1245                 if (method != STORED && method != DEFLATED)
1246                     zerror("invalid CEN header (bad compression method: " + method + ")");
1247                 if (pos + CENHDR + nlen > limit)
1248                     zerror("invalid CEN header (bad header size)");
1249                 // Record the CEN offset and the name hash in our hash cell.
1250                 hash = hashN(cen, pos + CENHDR, nlen);
1251                 hsh = (hash & 0x7fffffff) % tablelen;
1252                 next = table[hsh];
1253                 table[hsh] = idx;
1254                 idx = addEntry(idx, hash, next, pos);
1255                 // Adds name to metanames.
1256                 if (isMetaName(cen, pos + CENHDR, nlen)) {
1257                     metanames.add(pos);
1258                 }
1259                 // skip ext and comment
1260                 pos += (CENHDR + nlen + elen + clen);
1261                 i++;
1262             }
1263             total = i;
1264             if (pos + ENDHDR != cen.length) {


< prev index next >