package gnu.zip;
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Hashtable;
import org.albite.io.RandomReadingFile;
import org.albite.io.decoders.AlbiteStreamReader;
import org.albite.io.decoders.Encodings;
public class ZipFile implements ZipConstants
{
public static final int OPEN_READ = 0x1;
public static final int OPEN_DELETE = 0x4;
static final int ENDNRD = 4;
private final String name;
private final RandomReadingFile rrf;
private Hashtable entries;
private boolean closed = false;
public ZipFile(
final RandomReadingFile file)
throws ZipException, IOException {
this.rrf = file;
this.name = file.getName();
checkZipFile();
}
{
}
{
if (closed)
throw new IllegalStateException("ZipFile has closed: " + name);
}
private void readEntries()
throws ZipException, IOException
{
PartialInputStream inp = new PartialInputStream(rrf, 4096);
long pos = rrf.length() - ENDHDR;
long top = Math.max(0, pos - 65536);
do
{
if (pos < top)
throw new ZipException
("central directory not found, probably not a zip file: " + name);
inp.seek(pos--);
}
while (inp.readLeInt() != ENDSIG);
if (inp.skip(ENDTOT - ENDNRD) != ENDTOT - ENDNRD)
throw new EOFException(name);
int count = inp.readLeShort();
if (inp.skip(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ)
throw new EOFException(name);
int centralOffset = inp.readLeInt();
entries = new Hashtable(count+count/2);
inp.seek(centralOffset);
for (int i = 0; i < count; i++)
{
if (inp.readLeInt() != CENSIG)
throw new ZipException("Wrong Central Directory signature: " + name);
inp.skip(6);
int method = inp.readLeShort();
int dostime = inp.readLeInt();
int crc = inp.readLeInt();
int csize = inp.readLeInt();
int size = inp.readLeInt();
int nameLen = inp.readLeShort();
int extraLen = inp.readLeShort();
int commentLen = inp.readLeShort();
inp.skip(8);
int offset = inp.readLeInt();
String name = inp.readString(nameLen);
ZipEntry entry = new ZipEntry(name);
entry.setMethod(method);
entry.setCrc(crc & 0xffffffffL);
entry.setSize(size & 0xffffffffL);
entry.setCompressedSize(csize & 0xffffffffL);
entry.setDOSTime(dostime);
if (extraLen > 0)
{
byte[] extra = new byte[extraLen];
inp.readFully(extra);
entry.setExtra(extra);
}
if (commentLen > 0)
{
entry.setComment(inp.readString(commentLen));
}
entry.offset = offset;
entries.put(name, entry);
}
}
public void close()
throws IOException
{
RandomReadingFile rrf = this.rrf;
if (rrf == null)
return;
synchronized (rrf)
{
closed = true;
entries = null;
rrf.close();
}
}
protected void finalize()
throws IOException
{
if (!closed && rrf != null) close();
}
{
synchronized(rrf)
{
checkClosed();
if (entries == null)
readEntries();
return entries;
}
}
{
checkClosed();
try
{
Hashtable entries = getEntries();
ZipEntry entry = (ZipEntry) entries.get(name);
if (entry == null && !name.endsWith("/"))
entry = (ZipEntry) entries.get(name + '/');
return entry != null ? new ZipEntry(entry, name) : null;
}
catch (IOException ioe)
{
return null;
}
}
{
checkClosed();
Hashtable entries = getEntries();
String name = entry.getName();
ZipEntry zipEntry = (ZipEntry) entries.get(name);
if (zipEntry == null)
return null;
PartialInputStream inp = new PartialInputStream(rrf, 1024);
inp.seek(zipEntry.offset);
if (inp.readLeInt() != LOCSIG)
throw new ZipException("Wrong Local header signature: " + name);
inp.skip(4);
if (zipEntry.getMethod() != inp.readLeShort())
throw new ZipException("Compression method mismatch: " + name);
inp.skip(16);
int nameLen = inp.readLeShort();
int extraLen = inp.readLeShort();
inp.skip(nameLen + extraLen);
inp.setLength(zipEntry.getCompressedSize());
int method = zipEntry.getMethod();
switch (method)
{
case ZipEntry.STORED:
return inp;
case ZipEntry.DEFLATED:
inp.addDummyByte();
final Inflater inf = new Inflater(true);
final int sz = (int) entry.getSize();
return new InflaterInputStream(inp, inf)
{
{
if (sz == -1)
return super.available();
if (super.available() != 0)
return sz - inf.getTotalOut();
return 0;
}
};
default:
throw new ZipException("Unknown compression method " + method);
}
}
{
return name;
}
{
checkClosed();
try
{
return getEntries().size();
}
catch (IOException ioe)
{
return 0;
}
}
{
private final RandomReadingFile rrf;
private final byte[] buffer;
private long bufferOffset;
private int pos;
private long end;
private int dummyByteCount;
throws IOException
{
this.rrf = rrf;
buffer = new byte[bufferSize];
bufferOffset = -buffer.length;
pos = buffer.length;
end = rrf.length();
}
{
end = bufferOffset + pos + length;
}
{
synchronized (rrf)
{
long len = end - bufferOffset;
if (len == 0 && dummyByteCount > 0)
{
buffer[0] = 0;
dummyByteCount = 0;
}
else
{
rrf.seek((int) bufferOffset);
rrf.readFully(buffer, 0, (int) Math.min(buffer.length, len));
}
}
}
{
long amount = end - (bufferOffset + pos);
if (amount > Integer.MAX_VALUE)
return Integer.MAX_VALUE;
return (int) amount;
}
public int read()
throws IOException
{
if (bufferOffset + pos >= end + dummyByteCount)
return -1;
if (pos == buffer.length)
{
bufferOffset += buffer.length;
pos = 0;
fillBuffer();
}
return buffer[pos++] & 0xFF;
}
public int read(
byte[] b,
int off,
int len)
throws IOException
{
if (len > end + dummyByteCount - (bufferOffset + pos))
{
len = (int) (end + dummyByteCount - (bufferOffset + pos));
if (len == 0)
return -1;
}
int totalBytesRead = Math.min(buffer.length - pos, len);
System.arraycopy(buffer, pos, b, off, totalBytesRead);
pos += totalBytesRead;
off += totalBytesRead;
len -= totalBytesRead;
while (len > 0)
{
bufferOffset += buffer.length;
pos = 0;
fillBuffer();
int remain = Math.min(buffer.length, len);
System.arraycopy(buffer, pos, b, off, remain);
pos += remain;
off += remain;
len -= remain;
totalBytesRead += remain;
}
return totalBytesRead;
}
public long skip(
long amount)
throws IOException
{
if (amount < 0)
return 0;
if (amount > end - (bufferOffset + pos))
amount = end - (bufferOffset + pos);
seek(bufferOffset + pos + amount);
return amount;
}
void seek(
long newpos)
throws IOException
{
long offset = newpos - bufferOffset;
if (offset >= 0 && offset <= buffer.length)
{
pos = (int) offset;
}
else
{
bufferOffset = newpos;
pos = 0;
fillBuffer();
}
}
void readFully(
byte[] buf)
throws IOException
{
if (read(buf, 0, buf.length) != buf.length)
throw new EOFException();
}
void readFully(
byte[] buf,
int off,
int len)
throws IOException
{
if (read(buf, off, len) != len)
throw new EOFException();
}
{
int result;
if(pos + 1 < buffer.length)
{
result = ((buffer[pos + 0] & 0xff) | (buffer[pos + 1] & 0xff) << 8);
pos += 2;
}
else
{
int b0 = read();
int b1 = read();
if (b1 == -1)
throw new EOFException();
result = (b0 & 0xff) | (b1 & 0xff) << 8;
}
return result;
}
{
int result;
if(pos + 3 < buffer.length)
{
result = (((buffer[pos + 0] & 0xff) | (buffer[pos + 1] & 0xff) << 8)
| ((buffer[pos + 2] & 0xff)
| (buffer[pos + 3] & 0xff) << 8) << 16);
pos += 4;
}
else
{
int b0 = read();
int b1 = read();
int b2 = read();
int b3 = read();
if (b3 == -1)
throw new EOFException();
result = (((b0 & 0xff) | (b1 & 0xff) << 8) | ((b2 & 0xff)
| (b3 & 0xff) << 8) << 16);
}
return result;
}
private String
decodeChars(
byte[] buffer,
int pos,
int length)
throws IOException
{
String result;
int i=length - 1;
while ((i >= 0) && (buffer[i] <= 0x7f))
{
i--;
}
if (i < 0)
{
result = stringFromSubarray(buffer, 0, pos, length);
}
else
{
ByteBuffer bufferBuffer = ByteBuffer.wrap(buffer, pos, length);
ByteArrayInputStream in = new ByteArrayInputStream(buffer);
AlbiteStreamReader r =
new AlbiteStreamReader(in, Encodings.UTF_8);
char[] characters = r.read(buffer.length);
result = String.valueOf(characters);
}
return result;
}
{
if (length > end - (bufferOffset + pos))
throw new EOFException();
String result = null;
try
{
if (buffer.length - pos >= length)
{
result = decodeChars(buffer, pos, length);
pos += length;
}
else
{
byte[] b = new byte[length];
readFully(b);
result = decodeChars(b, 0, length);
}
}
catch (UnsupportedEncodingException uee)
{
throw new Error();
}
return result;
}
{
dummyByteCount = 1;
}
}
byte ascii[], int hibyte, int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset > ascii.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
char value[] = new char[count];
if (hibyte == 0) {
for (int i = count ; i-- > 0 ;) {
value[i] = (char) (ascii[i + offset] & 0xff);
}
} else {
hibyte <<= 8;
for (int i = count ; i-- > 0 ;) {
value[i] = (char) (hibyte | (ascii[i + offset] & 0xff));
}
}
return new String(value);
}
}