home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / util / zip / ZipInputStream.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  7.5 KB  |  279 lines

  1. /*
  2.  * @(#)ZipInputStream.java    1.14 98/03/18
  3.  *
  4.  * Copyright 1996, 1997 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.util.zip;
  16.  
  17. import java.io.InputStream;
  18. import java.io.IOException;
  19. import java.io.EOFException;
  20. import java.io.PushbackInputStream;
  21.  
  22. /**
  23.  * This class implements an input stream filter for reading files in the
  24.  * ZIP file format. Includes support for both compressed and uncompressed
  25.  * entries.
  26.  *
  27.  * @author    David Connelly
  28.  * @version    1.14, 03/18/98
  29.  */
  30. public
  31. class ZipInputStream extends InflaterInputStream implements ZipConstants {
  32.     private ZipEntry entry;
  33.     private CRC32 crc = new CRC32();
  34.     private long remaining;
  35.     private byte[] tmpbuf = new byte[512];
  36.  
  37.     private static final int STORED = ZipEntry.STORED;
  38.     private static final int DEFLATED = ZipEntry.DEFLATED;
  39.  
  40.     /**
  41.      * Creates a new ZIP input stream.
  42.      * @param in the actual input stream
  43.      */
  44.     public ZipInputStream(InputStream in) {
  45.     super(new PushbackInputStream(in, 512), new Inflater(true), 512);
  46.     }
  47.  
  48.     /**
  49.      * Reads the next ZIP file entry and positions stream at the beginning
  50.      * of the entry data.
  51.      * @exception ZipException if a ZIP file error has occurred
  52.      * @exception IOException if an I/O error has occurred
  53.      */
  54.     public ZipEntry getNextEntry() throws IOException {
  55.     if (entry != null) {
  56.         closeEntry();
  57.     }
  58.     crc.reset();
  59.     inf.reset();
  60.     if ((entry = readLOC()) == null) {
  61.         return null;
  62.     }
  63.     if (entry.method == STORED) {
  64.         remaining = entry.size;
  65.     }
  66.     return entry;
  67.     }
  68.  
  69.     /**
  70.      * Closes the current ZIP entry and positions the stream for reading the
  71.      * next entry.
  72.      * @exception ZipException if a ZIP file error has occurred
  73.      * @exception IOException if an I/O error has occurred
  74.      */
  75.     public void closeEntry() throws IOException {
  76.     while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
  77.     }
  78.     
  79.     /**
  80.      * Reads from the current ZIP entry into an array of bytes. Blocks until
  81.      * some input is available.
  82.      * @param b the buffer into which the data is read
  83.      * @param off the start offset of the data
  84.      * @param len the maximum number of bytes read
  85.      * @return the actual number of bytes read, or -1 if the end of the
  86.      *         entry is reached
  87.      * @exception ZipException if a ZIP file error has occurred
  88.      * @exception IOException if an I/O error has occurred
  89.      */
  90.     public int read(byte[] b, int off, int len) throws IOException {
  91.     if (entry == null) {
  92.         return -1;
  93.     }
  94.     switch (entry.method) {
  95.     case DEFLATED:
  96.         len = super.read(b, off, len);
  97.         if (len == -1) {
  98.         readEnd(entry);
  99.         entry = null;
  100.         } else {
  101.         crc.update(b, off, len);
  102.         }
  103.         return len;
  104.     case STORED:
  105.         if (remaining <= 0) {
  106.         entry = null;
  107.         return -1;
  108.         }
  109.         if (len > remaining) {
  110.         len = (int)remaining;
  111.         }
  112.         len = in.read(b, off, len);
  113.         if (len == -1) {
  114.         throw new ZipException("unexpected EOF");
  115.         }
  116.         crc.update(b, off, len);
  117.         remaining -= len;
  118.         return len;
  119.     default:
  120.         throw new InternalError("invalid compression method");
  121.     }
  122.     }
  123.  
  124.     /**
  125.      * Skips specified number of bytes in the current ZIP entry.
  126.      * @param n the number of bytes to skip
  127.      * @return the actual number of bytes skipped
  128.      * @exception ZipException if a ZIP file error has occurred
  129.      * @exception IOException if an I/O error has occurred
  130.      */
  131.     public long skip(long n) throws IOException {
  132.     if (n <= 0) {
  133.         return 0;
  134.     }
  135.     n = Math.min(n, Integer.MAX_VALUE);
  136.     int total = 0;
  137.     while (total < n) {
  138.         int len = read(tmpbuf, 0, (int)n - total);
  139.         if (len == -1) {
  140.         break;
  141.         }
  142.         total += len;
  143.     }
  144.     return total;
  145.     }
  146.  
  147.     /**
  148.      * Closes the ZIP input stream.
  149.      * @exception IOException if an I/O error has occurred
  150.      */
  151.     public void close() throws IOException {
  152.     in.close();
  153.     }
  154.  
  155.     /*
  156.      * Reads local file (LOC) header for next entry.
  157.      */
  158.     private ZipEntry readLOC() throws IOException {
  159.     try {
  160.         readFully(tmpbuf, 0, LOCHDR);
  161.     } catch (EOFException e) {
  162.         return null;
  163.     }
  164.     if (get32(tmpbuf, 0) != LOCSIG) {
  165.         return null;
  166.     }
  167.     // get the entry name and create the ZipEntry first
  168.     int len = get16(tmpbuf, LOCNAM);
  169.     if (len == 0) {
  170.         throw new ZipException("missing entry name");
  171.     }
  172.     byte[] b = new byte[len];
  173.     readFully(b, 0, len);
  174.     ZipEntry e = createZipEntry(new String(b, 0, 0, len));
  175.     // now get the remaining fields for the entry
  176.     e.version = get16(tmpbuf, LOCVER);
  177.     e.flag = get16(tmpbuf, LOCFLG);
  178.     if ((e.flag & 1) == 1) {
  179.         throw new ZipException("encrypted ZIP entry not supported");
  180.     }
  181.     e.method = get16(tmpbuf, LOCHOW);
  182.     e.time = get32(tmpbuf, LOCTIM);
  183.     if ((e.flag & 8) == 8) {
  184.         /* EXT descriptor present */
  185.         if (e.method != DEFLATED) {
  186.         throw new ZipException(
  187.             "only DEFLATED entries can have EXT descriptor");
  188.         }
  189.     } else {
  190.         e.crc = get32(tmpbuf, LOCCRC);
  191.         e.csize = get32(tmpbuf, LOCSIZ);
  192.         e.size = get32(tmpbuf, LOCLEN);
  193.     }
  194.     len = get16(tmpbuf, LOCEXT);
  195.     if (len > 0) {
  196.         b = new byte[len];
  197.         readFully(b, 0, len);
  198.         e.extra = b;
  199.     }
  200.     return e;
  201.     }
  202.  
  203.     /**
  204.      * Creates a new <code>ZipEntry</code> object for the specified
  205.      * entry name.
  206.      *
  207.      * @param name the ZIP file entry name
  208.      */
  209.     protected ZipEntry createZipEntry(String name) {
  210.     return new ZipEntry(name);
  211.     }
  212.  
  213.     /*
  214.      * Reads end of deflated entry as well as EXT descriptor if present.
  215.      */
  216.     private void readEnd(ZipEntry e) throws IOException {
  217.     int n = inf.getRemaining();
  218.     if (n > 0) {
  219.         ((PushbackInputStream)in).unread(buf, len - n, n);
  220.     }
  221.     if ((e.flag & 8) == 8) {
  222.         /* EXT descriptor present */
  223.         readFully(tmpbuf, 0, EXTHDR);
  224.         long sig = get32(tmpbuf, 0);
  225.         if (sig != EXTSIG) {
  226.         throw new ZipException("invalid EXT descriptor signature");
  227.         }
  228.         e.crc = get32(tmpbuf, EXTCRC);
  229.         e.csize = get32(tmpbuf, EXTSIZ);
  230.         e.size = get32(tmpbuf, EXTLEN);
  231.     }
  232.     if (e.size != inf.getTotalOut()) {
  233.         throw new ZipException(
  234.         "invalid entry size (expected " + e.size + " but got " +
  235.         inf.getTotalOut() + " bytes)");
  236.     }
  237.     if (e.csize != inf.getTotalIn()) {
  238.         throw new ZipException(
  239.         "invalid entry compressed size (expected " + e.csize +
  240.         " but got " + inf.getTotalIn() + " bytes)");
  241.     }
  242.     if (e.crc != crc.getValue()) {
  243.         throw new ZipException(
  244.         "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
  245.         " but got 0x" + Long.toHexString(crc.getValue()) + ")");
  246.     }
  247.     }
  248.  
  249.     /*
  250.      * Reads bytes, blocking until all bytes are read.
  251.      */
  252.     private void readFully(byte[] b, int off, int len) throws IOException {
  253.     while (len > 0) {
  254.         int n = in.read(b, off, len);
  255.         if (n == -1) {
  256.         throw new EOFException();
  257.         }
  258.         off += n;
  259.         len -= n;
  260.     }
  261.     }
  262.  
  263.     /*
  264.      * Fetches unsigned 16-bit value from byte array at specified offset.
  265.      * The bytes are assumed to be in Intel (little-endian) byte order.
  266.      */
  267.     private static final int get16(byte b[], int off) {
  268.     return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
  269.     }
  270.  
  271.     /*
  272.      * Fetches unsigned 32-bit value from byte array at specified offset.
  273.      * The bytes are assumed to be in Intel (little-endian) byte order.
  274.      */
  275.     private static final long get32(byte b[], int off) {
  276.     return get16(b, off) | ((long)get16(b, off+2) << 16);
  277.     }
  278. }
  279.