< 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 instance of ZipCryption
 338      * @return the input stream for reading the contents of the specified
 339      * zip file entry.
 340      * @throws ZipException if a ZIP format error has occurred
 341      * @throws IOException if an I/O error has occurred
 342      * @throws IllegalStateException if the zip file has been closed
 343      */
 344     public InputStream getInputStream(ZipEntry entry, ZipCryption zipCryption)
 345                                                             throws IOException {
 346         Objects.requireNonNull(entry, "entry");
 347 
 348         if ((entry.flag & 1) == 1) {
 349             Objects.requireNonNull(entry, "Passphrase is required");
 350             zipCryption.reset();
 351         }
 352 
 353         int pos = -1;
 354         ZipFileInputStream in = null;
 355         synchronized (this) {
 356             ensureOpen();
 357             if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
 358                 pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
 359             } else {
 360                 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
 361             }
 362             if (pos == -1) {
 363                 return null;
 364             }
 365             in = new ZipFileInputStream(zsrc.cen, pos, zipCryption);
 366             switch (CENHOW(zsrc.cen, pos)) {
 367             case STORED:
 368                 if((entry.flag & 1) == 1) {
 369                    byte[] encryptionHeader =
 370                                 new byte[zipCryption.getEncryptionHeaderSize()];
 371                    in.readRaw(encryptionHeader, 0, encryptionHeader.length);
 372                    zipCryption.decryptBytes(encryptionHeader);
 373 
 374                    if (!zipCryption.isValid(entry, encryptionHeader)) {
 375                        throw new ZipException("possibly incorrect passphrase");
 376                    }
 377                 }
 378                 synchronized (streams) {
 379                     streams.put(in, null);
 380                 }
 381                 return in;
 382             case DEFLATED:
 383                 // Inflater likes a bit of slack
 384                 // MORE: Compute good size for inflater stream:
 385                 long size = CENLEN(zsrc.cen, pos) + 2;
 386                 if (size > 65536) {
 387                     size = 8192;
 388                 }
 389                 if (size <= 0) {
 390                     size = 4096;
 391                 }
 392                 Inflater inf = getInflater();
 393 
 394                 if((entry.flag & 1) == 1) {
 395                    byte[] encryptionHeader =
 396                                 new byte[zipCryption.getEncryptionHeaderSize()];
 397                    in.readRaw(encryptionHeader, 0, encryptionHeader.length);
 398                    zipCryption.decryptBytes(encryptionHeader);
 399 
 400                    if (!zipCryption.isValid(entry, encryptionHeader)) {
 401                        throw new ZipException("possibly incorrect passphrase");
 402                    }
 403                 }
 404 
 405                 InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size);
 406                 synchronized (streams) {
 407                     streams.put(is, inf);
 408                 }
 409                 return is;
 410             default:
 411                 throw new ZipException("invalid compression method");
 412             }
 413         }
 414     }
 415 
 416     private class ZipFileInflaterInputStream extends InflaterInputStream {
 417         private volatile boolean closeRequested = false;
 418         private boolean eof = false;
 419         private final ZipFileInputStream zfin;
 420 
 421         ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf,
 422                 int size) {
 423             super(zfin, inf, size);
 424             this.zfin = zfin;


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


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


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


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


< prev index next >