/* * Returns an input stream on the data of the specified {@code ZipEntry}. * * @param entry * the ZipEntry. * @return an input stream of the data contained in the {@code ZipEntry}. * @throws IOException * if an {@code IOException} occurs. * @throws IllegalStateException if this ZIP file has been closed. */ public java.io.InputStream getInputStream(ZipEntry entry) // throws IOException { /* * Make sure this ZipEntry is in this Zip file. We run it through * the name lookup. */ { entry = getEntry(entry.getName()); if (entry == null) { return(null); } /* * Create a ZipInputStream at the right part of the file. */ java.io.RandomAccessFile raf = mRaf; lock (raf) { // We don't know the entry data's start position. All we have is the // position of the entry's local header. At position 28 we find the // length of the extra data. In some cases this length differs from // the one coming in the central header. RAFStream rafstrm = new RAFStream(raf, entry.mLocalHeaderRelOffset + 28); int localExtraLenOrWhatever = ler.readShortLE(rafstrm); // Skip the name and this "extra" data or whatever it is: rafstrm.skip(entry.nameLen + localExtraLenOrWhatever); rafstrm.mLength = rafstrm.mOffset + entry.compressedSize; if (entry.compressionMethod == ZipEntry.DEFLATED) { int bufSize = java.lang.Math.max(1024, (int)java.lang.Math.min(entry.getSize(), 65535L)); return(new ZipInflaterInputStream(rafstrm, new Inflater(true), bufSize, entry)); } else { return(rafstrm); } } }
/* * Find the central directory and read the contents. * * <p>The central directory can be followed by a variable-length comment * field, so we have to scan through it backwards. The comment is at * most 64K, plus we have 18 bytes for the end-of-central-dir stuff * itself, plus apparently sometimes people throw random junk on the end * just for the fun of it.</p> * * <p>This is all a little wobbly. If the wrong value ends up in the EOCD * area, we're hosed. This appears to be the way that everybody handles * it though, so we're in good company if this fails.</p> */ private void readCentralDir() //throws IOException { /* * Scan back, looking for the End Of Central Directory field. If * the archive doesn't have a comment, we'll hit it on the first * try. * * No need to synchronize mRaf here -- we only do this when we * first open the Zip file. */ { long scanOffset = mRaf.length() - ENDHDR; if (scanOffset < 0) { throw new ZipException("too short to be Zip"); } long stopOffset = scanOffset - 65536; if (stopOffset < 0) { stopOffset = 0; } while (true) { mRaf.seek(scanOffset); if (ZipEntry.readIntLE(mRaf) == 101010256L) { break; } scanOffset--; if (scanOffset < stopOffset) { throw new ZipException("EOCD not found; not a Zip archive?"); } } /* * Found it, read the EOCD. * * For performance we want to use buffered I/O when reading the * file. We wrap a buffered stream around the random-access file * object. If we just read from the RandomAccessFile we'll be * doing a read() system call every time. */ RAFStream rafs = new RAFStream(mRaf, mRaf.getFilePointer()); java.io.BufferedInputStream bin = new java.io.BufferedInputStream(rafs, ENDHDR); int diskNumber = ler.readShortLE(bin); int diskWithCentralDir = ler.readShortLE(bin); int numEntries = ler.readShortLE(bin); int totalNumEntries = ler.readShortLE(bin); /*centralDirSize =*/ ler.readIntLE(bin); long centralDirOffset = ler.readIntLE(bin); /*commentLen =*/ ler.readShortLE(bin); if (numEntries != totalNumEntries || diskNumber != 0 || diskWithCentralDir != 0) { throw new ZipException("spanned archives not supported"); } /* * Seek to the first CDE and read all entries. * However, when Z_SYNC_FLUSH is used the offset may not point directly * to the CDE so skip over until we find it. * At most it will be 6 bytes away (one or two bytes for empty block, 4 bytes for * empty block signature). */ scanOffset = centralDirOffset; stopOffset = scanOffset + 6; while (true) { mRaf.seek(scanOffset); if (ZipEntry.readIntLE(mRaf) == CENSIG) { break; } scanOffset++; if (scanOffset > stopOffset) { throw new ZipException("Central Directory Entry not found"); } } // If CDE is found then go and read all the entries rafs = new RAFStream(mRaf, scanOffset); bin = new java.io.BufferedInputStream(rafs, 4096); for (int i = 0; i < numEntries; i++) { ZipEntry newEntry = new ZipEntry(ler, bin); mEntries.put(newEntry.getName(), newEntry); } }