ZipInputStreampublic class ZipInputStream extends InflaterInputStream implements ZipConstantsThis class implements an input stream filter for reading files in the
ZIP file format. Includes support for both compressed and uncompressed
entries. |
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.
super(new PushbackInputStream(in, 512), new Inflater(true), 512);
usesDefaultInflater = true;
if(in == null) {
throw new NullPointerException("in is null");
}
|
Methods Summary |
---|
public int | available()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.
ensureOpen();
if (entryEOF) {
return 0;
} else {
return 1;
}
| public void | close()Closes this input stream and releases any system resources associated
with the stream.
if (!closed) {
super.close();
closed = true;
}
| public void | closeEntry()Closes the current ZIP entry and positions the stream for reading the
next entry.
ensureOpen();
while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
entryEOF = true;
| protected java.util.zip.ZipEntry | createZipEntry(java.lang.String name)Creates a new ZipEntry object for the specified
entry name.
return new ZipEntry(name);
| private void | ensureOpen()Check to make sure that this stream has not been closed
if (closed) {
throw new IOException("Stream closed");
}
| private static final int | get16(byte[] b, int off)
return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
| private static final long | get32(byte[] b, int off)
return get16(b, off) | ((long)get16(b, off+2) << 16);
| public java.util.zip.ZipEntry | getNextEntry()Reads the next ZIP file entry and positions the stream at the
beginning of the entry data.
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.String | getUTF8String(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 int | read(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.
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 void | readEnd(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 void | readFully(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.ZipEntry | readLOC()
/*
* 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 long | skip(long n)Skips specified number of bytes in the current ZIP entry.
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;
|
|