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 / GZIPInputStream.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  5.4 KB  |  211 lines

  1. /*
  2.  * @(#)GZIPInputStream.java    1.17 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.SequenceInputStream;
  18. import java.io.ByteArrayInputStream;
  19. import java.io.InputStream;
  20. import java.io.IOException;
  21. import java.io.EOFException;
  22.  
  23. /**
  24.  * This class implements a stream filter for reading compressed data in
  25.  * the GZIP format.
  26.  *
  27.  * @see        InflaterInputStream
  28.  * @version     1.17, 03/18/98
  29.  * @author     David Connelly
  30.  *
  31.  */
  32. public
  33. class GZIPInputStream extends InflaterInputStream {
  34.     /**
  35.      * CRC-32 for uncompressed data.
  36.      */
  37.     protected CRC32 crc = new CRC32();
  38.  
  39.     /**
  40.      * Indicates end of input stream.
  41.      */
  42.     protected boolean eos;
  43.  
  44.     /**
  45.      * Creates a new input stream with the specified buffer size.
  46.      * @param in the input stream
  47.      * @param size the input buffer size
  48.      * @exception IOException if an I/O error has occurred
  49.      */
  50.     public GZIPInputStream(InputStream in, int size) throws IOException {
  51.     super(in, new Inflater(true), size);
  52.     readHeader();
  53.     crc.reset();
  54.     }
  55.  
  56.     /**
  57.      * Creates a new input stream with a default buffer size.
  58.      * @param in the input stream
  59.      * @exception IOException if an I/O error has occurred
  60.      */
  61.     public GZIPInputStream(InputStream in) throws IOException {
  62.     this(in, 512);
  63.     }
  64.  
  65.     /**
  66.      * Reads uncompressed data into an array of bytes. Blocks until enough
  67.      * input is available for decompression.
  68.      * @param buf the buffer into which the data is read
  69.      * @param off the start offset of the data
  70.      * @param len the maximum number of bytes read
  71.      * @return    the actual number of bytes read, or -1 if the end of the
  72.      *        compressed input stream is reached
  73.      * @exception IOException if an I/O error has occurred or the compressed
  74.      *                  input data is corrupt
  75.      */
  76.     public int read(byte[] buf, int off, int len) throws IOException {
  77.     if (eos) {
  78.         return -1;
  79.     }
  80.     len = super.read(buf, off, len);
  81.     if (len == -1) {
  82.         readTrailer();
  83.         eos = true;
  84.     } else {
  85.         crc.update(buf, off, len);
  86.     }
  87.     return len;
  88.     }
  89.  
  90.     /**
  91.      * Closes the input stream.
  92.      * @exception IOException if an I/O error has occurred
  93.      */
  94.     public void close() throws IOException {
  95.     inf.end();
  96.     in.close();
  97.     eos = true;
  98.     }
  99.  
  100.     /**
  101.      * GZIP header magic number.
  102.      */
  103.     public final static int GZIP_MAGIC = 0x8b1f;
  104.  
  105.     /*
  106.      * File header flags.
  107.      */
  108.     private final static int FTEXT    = 1;    // Extra text
  109.     private final static int FHCRC    = 2;    // Header CRC
  110.     private final static int FEXTRA    = 4;    // Extra field
  111.     private final static int FNAME    = 8;    // File name
  112.     private final static int FCOMMENT    = 16;    // File comment
  113.  
  114.     /*
  115.      * Reads GZIP member header.
  116.      */
  117.     private void readHeader() throws IOException {
  118.     CheckedInputStream in = new CheckedInputStream(this.in, crc);
  119.     crc.reset();
  120.     // Check header magic
  121.     if (readUShort(in) != GZIP_MAGIC) {
  122.         throw new IOException("Not in GZIP format");
  123.     }
  124.     // Check compression method
  125.     if (readUByte(in) != 8) {
  126.         throw new IOException("Unsupported compression method");
  127.     }
  128.     // Read flags
  129.     int flg = readUByte(in);
  130.     // Skip MTIME, XFL, and OS fields
  131.     skipBytes(in, 6);
  132.     // Skip optional extra field
  133.     if ((flg & FEXTRA) == FEXTRA) {
  134.         skipBytes(in, readUShort(in));
  135.     }
  136.     // Skip optional file name
  137.     if ((flg & FNAME) == FNAME) {
  138.         while (readUByte(in) != 0) ;
  139.     }
  140.     // Skip optional file comment
  141.     if ((flg & FCOMMENT) == FCOMMENT) {
  142.         while (readUByte(in) != 0) ;
  143.     }
  144.     // Check optional header CRC
  145.     if ((flg & FHCRC) == FHCRC) {
  146.         int v = (int)crc.getValue() & 0xffff;
  147.         if (readUShort(in) != v) {
  148.         throw new IOException("Corrupt GZIP header");
  149.         }
  150.     }
  151.     }
  152.  
  153.     /*
  154.      * Reads GZIP member trailer.
  155.      */
  156.     private void readTrailer() throws IOException {
  157.     InputStream in = this.in;
  158.     int n = inf.getRemaining();
  159.     if (n > 0) {
  160.         in = new SequenceInputStream(
  161.             new ByteArrayInputStream(buf, len - n, n), in);
  162.     }
  163.     long v = crc.getValue();
  164.     if (readUInt(in) != v || readUInt(in) != inf.getTotalOut()) {
  165.         throw new IOException("Corrupt GZIP trailer");
  166.     }
  167.     }
  168.  
  169.     /*
  170.      * Reads unsigned integer in Intel byte order.
  171.      */
  172.     private long readUInt(InputStream in) throws IOException {
  173.     long s = readUShort(in);
  174.     return ((long)readUShort(in) << 16) | s;
  175.     }
  176.  
  177.     /*
  178.      * Reads unsigned short in Intel byte order.
  179.      */
  180.     private int readUShort(InputStream in) throws IOException {
  181.     int b = readUByte(in);
  182.     return ((int)readUByte(in) << 8) | b;
  183.     }
  184.  
  185.     /*
  186.      * Reads unsigned byte.
  187.      */
  188.     private int readUByte(InputStream in) throws IOException {
  189.     int b = in.read();
  190.     if (b == -1) {
  191.         throw new EOFException();
  192.     }
  193.     return b;
  194.     }
  195.  
  196.     /*
  197.      * Skips bytes of input data blocking until all bytes are skipped.
  198.      * Does not assume that the input stream is capable of seeking.
  199.      */
  200.     private void skipBytes(InputStream in, int n) throws IOException {
  201.     byte[] buf = new byte[128];
  202.     while (n > 0) {
  203.         int len = in.read(buf, 0, n < buf.length ? n : buf.length);
  204.         if (len == -1) {
  205.         throw new EOFException();
  206.         }
  207.         n -= len;
  208.     }
  209.     }
  210. }
  211.