1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
/* Copyright (C) 1999 Cygnus Solutions
This file is part of libgcj.
This software is copyrighted work licensed under the terms of the
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
details. */
package java.util.zip;
import java.io.*;
/**
* @author Per Bothner
* @date May 1999.
*/
/*
* Written using on-line Java Platform 1.2 API Specification, as well
* as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
* Status: Quite incomplete, but can read uncompressed .zip archives.
*/
// JDK1.2 has "protected ZipEntry createZipEntry(String)" but is very
// vague about what the method does. FIXME.
// We do not calculate the CRC and compare it with the specified value;
// we probably should. FIXME.
public class ZipInputStream extends InflaterInputStream implements ZipConstants
{
public ZipInputStream (InputStream in)
{
super (in, new Inflater (true));
}
public ZipEntry getNextEntry () throws IOException
{
if (current != null)
closeEntry();
if (in.read() != 'P'
|| in.read() != 'K')
return null;
int code = in.read();
while (code == '\001')
{
code = in.read();
if (code != '\002')
return null;
in.skip(16);
int size = read4();
in.skip(4);
int fname_length = readu2();
int extra_length = readu2();
int fcomment_length = readu2();
in.skip(12+fname_length+extra_length+fcomment_length+size);
if (in.read() != 'P' || in.read() != 'K')
return null;
code = in.read();
}
if (code == '\005')
{
if (in.read() != '\006')
return null;
in.skip(16);
int comment_size = readu2();
in.skip(comment_size);
if (in.read() != 'P' || in.read() != 'K')
return null;
code = in.read();
}
if (code != '\003'
|| in.read() != '\004')
return null;
int ex_version = readu2();
current_flags = readu2();
int method = readu2();
int modtime = readu2();
int moddate = readu2();
int crc = read4();
int compressedSize = read4();
int uncompressedSize = read4();
int filenameLength = readu2();
int extraLength = readu2();
byte[] bname = new byte[filenameLength];
readFully(bname);
ZipEntry entry = new ZipEntry(new String(bname, "8859_1"));
if (extraLength > 0)
{
byte[] bextra = new byte[extraLength];
readFully(bextra);
entry.extra = bextra;
}
entry.compressedSize = compressedSize;
entry.size = uncompressedSize;
entry.crc = (long) crc & 0xffffffffL;
entry.method = method;
entry.time = ZipEntry.timeFromDOS(moddate, modtime);
current = entry;
avail = uncompressedSize;
compressed_bytes = compressedSize;
return entry;
}
// We override fill to let us control how much data gets read from
// the underlying input stream. This lets us avoid having to push
// back data.
protected void fill () throws IOException
{
int count = buf.length;
if (count > compressed_bytes)
count = compressed_bytes;
len = in.read(buf, 0, count);
if (len != -1)
{
compressed_bytes -= len;
inf.setInput(buf, 0, len);
}
}
public int read (byte[] b, int off, int len) throws IOException
{
if (len > avail)
len = avail;
int count;
if (current.method == Deflater.DEFLATED)
count = super.read(b, off, len);
else
count = in.read(b, off, len);
if (count == -1 || avail == 0)
{
inf.reset();
count = -1;
}
else
avail -= count;
return count;
}
public long skip (long n) throws IOException
{
if (n > avail)
n = avail;
long count;
if (current.method == Deflater.DEFLATED)
count = super.skip(n);
else
count = in.skip(n);
avail = avail - (int) count;
return count;
}
private void readFully (byte[] b) throws IOException
{
int off = 0;
int len = b.length;
while (len > 0)
{
int count = in.read(b, off, len);
if (count <= 0)
throw new EOFException(".zip archive ended prematurely");
off += count;
len -= count;
}
}
private int readu2 () throws IOException
{
int byte0 = in.read();
int byte1 = in.read();
if (byte0 < 0 || byte1 < 0)
throw new EOFException(".zip archive ended prematurely");
return ((byte1 & 0xFF) << 8) | (byte0 & 0xFF);
}
private int read4 () throws IOException
{
int byte0 = in.read();
int byte1 = in.read();
int byte2 = in.read();
int byte3 = in.read();
if (byte3 < 0)
throw new EOFException(".zip archive ended prematurely");
return ((byte3 & 0xFF) << 24) + ((byte2 & 0xFF) << 16)
+ ((byte1 & 0xFF) << 8) + (byte0 & 0xFF);
}
public void closeEntry () throws IOException
{
if (current != null)
{
if (avail > 0)
skip (avail);
if ((current_flags & 8) != 0)
{
int sig = read4();
if (sig != 0x04034b50)
throw new ZipException("bad/missing magic number at end of .zip entry");
int crc = read4();
int compressedSize = read4();
int uncompressedSize = read4();
if (current.compressedSize != compressedSize
|| current.size != uncompressedSize
|| current.crc != crc)
throw new ZipException("bad data descriptor at end of .zip entry");
}
current = null;
avail = 0;
}
}
public void close () throws IOException
{
current = null;
super.close();
}
private ZipEntry current;
private int current_flags;
// Number of uncompressed bytes to be read.
private int avail;
// Number of bytes we can read from underlying stream.
private int compressed_bytes;
}
|