FileDocCategorySizeDatePackage
ZipInputStream.javaAPI DocJava SE 6 API11930Tue Jun 10 00:26:02 BST 2008java.util.zip

ZipInputStream

public class ZipInputStream extends InflaterInputStream implements ZipConstants
This class implements an input stream filter for reading files in the ZIP file format. Includes support for both compressed and uncompressed entries.
author
David Connelly
version
1.44, 06/15/07

Fields Summary
private ZipEntry
entry
private int
flag
private CRC32
crc
private long
remaining
private byte[]
tmpbuf
private static final int
STORED
private static final int
DEFLATED
private boolean
closed
private boolean
entryEOF
private byte[]
b
Constructors Summary
public ZipInputStream(InputStream in)
Creates a new ZIP input stream.

param
in the actual input stream

	super(new PushbackInputStream(in, 512), new Inflater(true), 512);
        usesDefaultInflater = true;
        if(in == null) {
            throw new NullPointerException("in is null");
        }
    
Methods Summary
public intavailable()
Returns 0 after EOF has reached for the current entry data, otherwise always return 1.

Programs should not count on this method to return the actual number of bytes that could be read without blocking.

return
1 before EOF and 0 after EOF has reached for current entry.
exception
IOException if an I/O error occurs.

        ensureOpen();
        if (entryEOF) {
            return 0;
        } else {
            return 1;
        }
    
public voidclose()
Closes this input stream and releases any system resources associated with the stream.

exception
IOException if an I/O error has occurred

        if (!closed) {
	    super.close();
            closed = true;
        }
    
public voidcloseEntry()
Closes the current ZIP entry and positions the stream for reading the next entry.

exception
ZipException if a ZIP file error has occurred
exception
IOException if an I/O error has occurred

        ensureOpen();
	while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
        entryEOF = true;
    
protected java.util.zip.ZipEntrycreateZipEntry(java.lang.String name)
Creates a new ZipEntry object for the specified entry name.

param
name the ZIP file entry name
return
the ZipEntry just created

	return new ZipEntry(name);
    
private voidensureOpen()
Check to make sure that this stream has not been closed


                    
         
	if (closed) {
	    throw new IOException("Stream closed");
        }
    
private static final intget16(byte[] b, int off)

	return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
    
private static final longget32(byte[] b, int off)

	return get16(b, off) | ((long)get16(b, off+2) << 16);
    
public java.util.zip.ZipEntrygetNextEntry()
Reads the next ZIP file entry and positions the stream at the beginning of the entry data.

return
the next ZIP file entry, or null if there are no more entries
exception
ZipException if a ZIP file error has occurred
exception
IOException if an I/O error has occurred

        ensureOpen();
	if (entry != null) {
	    closeEntry();
	}
	crc.reset();
	inf.reset();
	if ((entry = readLOC()) == null) {
	    return null;
	}
	if (entry.method == STORED) {
	    remaining = entry.size;
	}
        entryEOF = false;
	return entry;
    
private static java.lang.StringgetUTF8String(byte[] b, int off, int len)

	// First, count the number of characters in the sequence
	int count = 0;
	int max = off + len;
	int i = off;
	while (i < max) {
	    int c = b[i++] & 0xff;
	    switch (c >> 4) {
	    case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
		// 0xxxxxxx
		count++;
		break;
	    case 12: case 13:
		// 110xxxxx 10xxxxxx
		if ((int)(b[i++] & 0xc0) != 0x80) {
		    throw new IllegalArgumentException();
		}
		count++;
		break;
	    case 14:
		// 1110xxxx 10xxxxxx 10xxxxxx
		if (((int)(b[i++] & 0xc0) != 0x80) ||
		    ((int)(b[i++] & 0xc0) != 0x80)) {
		    throw new IllegalArgumentException();
		}
		count++;
		break;
	    default:
		// 10xxxxxx, 1111xxxx
		throw new IllegalArgumentException();
	    }
	}
	if (i != max) {
	    throw new IllegalArgumentException();
	}
	// Now decode the characters...
	char[] cs = new char[count];
	i = 0;
	while (off < max) {
	    int c = b[off++] & 0xff;
	    switch (c >> 4) {
	    case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
		// 0xxxxxxx
		cs[i++] = (char)c;
		break;
	    case 12: case 13:
		// 110xxxxx 10xxxxxx
		cs[i++] = (char)(((c & 0x1f) << 6) | (b[off++] & 0x3f));
		break;
	    case 14:
		// 1110xxxx 10xxxxxx 10xxxxxx
		int t = (b[off++] & 0x3f) << 6;
		cs[i++] = (char)(((c & 0x0f) << 12) | t | (b[off++] & 0x3f));
		break;
	    default:
		// 10xxxxxx, 1111xxxx
		throw new IllegalArgumentException();
	    }
	}
	return new String(cs, 0, count);
    
public intread(byte[] b, int off, int len)
Reads from the current ZIP entry into an array of bytes. If len is not zero, the method blocks until some input is available; otherwise, no bytes are read and 0 is returned.

param
b the buffer into which the data is read
param
off the start offset in the destination array b
param
len the maximum number of bytes read
return
the actual number of bytes read, or -1 if the end of the entry is reached
exception
NullPointerException If b is null.
exception
IndexOutOfBoundsException If off is negative, len is negative, or len is greater than b.length - off
exception
ZipException if a ZIP file error has occurred
exception
IOException if an I/O error has occurred

        ensureOpen();
        if (off < 0 || len < 0 || off > b.length - len) {
	    throw new IndexOutOfBoundsException();
	} else if (len == 0) {
	    return 0;
	}

	if (entry == null) {
	    return -1;
	}
	switch (entry.method) {
	case DEFLATED:
	    len = super.read(b, off, len);
	    if (len == -1) {
		readEnd(entry);
                entryEOF = true;
		entry = null;
	    } else {
		crc.update(b, off, len);
	    }
	    return len;
	case STORED:
	    if (remaining <= 0) {
                entryEOF = true;
		entry = null;
		return -1;
	    }
	    if (len > remaining) {
		len = (int)remaining;
	    }
	    len = in.read(b, off, len);
	    if (len == -1) {
		throw new ZipException("unexpected EOF");
	    }
	    crc.update(b, off, len);
	    remaining -= len;
	    if (remaining == 0 && entry.crc != crc.getValue()) {
		throw new ZipException(
		    "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +
		    " but got 0x" + Long.toHexString(crc.getValue()) + ")");
	    }
	    return len;
	default:
	    throw new ZipException("invalid compression method");
	}
    
private voidreadEnd(java.util.zip.ZipEntry e)

	int n = inf.getRemaining();
	if (n > 0) {
	    ((PushbackInputStream)in).unread(buf, len - n, n);
	}
	if ((flag & 8) == 8) {
	    /* "Data Descriptor" present */
	    readFully(tmpbuf, 0, EXTHDR);
	    long sig = get32(tmpbuf, 0);
            if (sig != EXTSIG) { // no EXTSIG present
                e.crc = sig;
                e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
                e.size = get32(tmpbuf, EXTLEN - EXTCRC);
                ((PushbackInputStream)in).unread(
                                           tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
            } else {
                e.crc = get32(tmpbuf, EXTCRC);
                e.csize = get32(tmpbuf, EXTSIZ);
                e.size = get32(tmpbuf, EXTLEN);
            }
	}
	if (e.size != inf.getBytesWritten()) {
	    throw new ZipException(
		"invalid entry size (expected " + e.size +
		" but got " + inf.getBytesWritten() + " bytes)");
	}
	if (e.csize != inf.getBytesRead()) {
	    throw new ZipException(
		"invalid entry compressed size (expected " + e.csize +
		" but got " + inf.getBytesRead() + " bytes)");
	}
	if (e.crc != crc.getValue()) {
	    throw new ZipException(
		"invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
		" but got 0x" + Long.toHexString(crc.getValue()) + ")");
	}
    
private voidreadFully(byte[] b, int off, int len)

	while (len > 0) {
	    int n = in.read(b, off, len);
	    if (n == -1) {
		throw new EOFException();
	    }
	    off += n;
	    len -= n;
	}
    
private java.util.zip.ZipEntryreadLOC()


    /*
     * Reads local file (LOC) header for next entry.
     */
         
	try {
	    readFully(tmpbuf, 0, LOCHDR);
	} catch (EOFException e) {
	    return null;
	}
	if (get32(tmpbuf, 0) != LOCSIG) {
	    return null;
	}
	// get the entry name and create the ZipEntry first
	int len = get16(tmpbuf, LOCNAM);
        int blen = b.length;
        if (len > blen) {
            do
                blen = blen * 2;
            while (len > blen);
            b = new byte[blen];
        }
	readFully(b, 0, len);
	ZipEntry e = createZipEntry(getUTF8String(b, 0, len));
	// now get the remaining fields for the entry
	flag = get16(tmpbuf, LOCFLG);
	if ((flag & 1) == 1) {
	    throw new ZipException("encrypted ZIP entry not supported");
	}
	e.method = get16(tmpbuf, LOCHOW);
	e.time = get32(tmpbuf, LOCTIM);
	if ((flag & 8) == 8) {
	    /* "Data Descriptor" present */
	    if (e.method != DEFLATED) {
		throw new ZipException(
			"only DEFLATED entries can have EXT descriptor");
	    }
	} else {
	    e.crc = get32(tmpbuf, LOCCRC);
	    e.csize = get32(tmpbuf, LOCSIZ);
	    e.size = get32(tmpbuf, LOCLEN);
	}
	len = get16(tmpbuf, LOCEXT);
	if (len > 0) {
	    byte[] bb = new byte[len];
	    readFully(bb, 0, len);
	    e.setExtra(bb);
	}
	return e;
    
public longskip(long n)
Skips specified number of bytes in the current ZIP entry.

param
n the number of bytes to skip
return
the actual number of bytes skipped
exception
ZipException if a ZIP file error has occurred
exception
IOException if an I/O error has occurred
exception
IllegalArgumentException if n < 0

        if (n < 0) {
            throw new IllegalArgumentException("negative skip length");
        }
        ensureOpen();
	int max = (int)Math.min(n, Integer.MAX_VALUE);
	int total = 0;
	while (total < max) {
	    int len = max - total;
	    if (len > tmpbuf.length) {
		len = tmpbuf.length;
	    }
	    len = read(tmpbuf, 0, len);
	    if (len == -1) {
                entryEOF = true;
		break;
	    }
	    total += len;
	}
	return total;