Commit 1a82c94b by Artur Biesiadowski Committed by Mark Wielaard

ZipFile.java (entries): Now HashMap.

	* java/util/zip/ZipFile.java (entries): Now HashMap.
	(readLeShort(DataInput, byte[])): Read from given byte array.
	(readLeInt(DataInput, byte[]): Likewise.
	(readLeShort(byte[] b, int off)): New method.
	(readLeInt(byte[] b, int off)): Likewise.
	(readEntries): Use byte arrays to read info in bigger chunks.
	(getEntries): Return HashMap.
	(getEntry): Use HashMap.
	(locBuf): New private field.
	(checkLocalHeader): Use locBuf to read info in one chunk.
	(getInputStream): Use entries HashMap, wrap PartialInputStream
	in BufferedInputStream.
	(ZipEntryEnumeration): Use HashMap and Interator.

Co-Authored-By: Mark Wielaard <mark@klomp.org>

From-SVN: r60803
parent 1092805d
2003-01-02 Artur Biesiadowski <abies@pg.gda.pl>
Mark Wielaard <mark@klomp.org>
* java/util/zip/ZipFile.java (entries): Now HashMap.
(readLeShort(DataInput, byte[])): Read from given byte array.
(readLeInt(DataInput, byte[]): Likewise.
(readLeShort(byte[] b, int off)): New method.
(readLeInt(byte[] b, int off)): Likewise.
(readEntries): Use byte arrays to read info in bigger chunks.
(getEntries): Return HashMap.
(getEntry): Use HashMap.
(locBuf): New private field.
(checkLocalHeader): Use locBuf to read info in one chunk.
(getInputStream): Use entries HashMap, wrap PartialInputStream
in BufferedInputStream.
(ZipEntryEnumeration): Use HashMap and Interator.
2003-01-02 Mark Wielaard <mark@klomp.org> 2003-01-02 Mark Wielaard <mark@klomp.org>
Jeroen Frijters <jeroen@sumatra.nl> Jeroen Frijters <jeroen@sumatra.nl>
......
/* java.util.zip.ZipFile /* java.util.zip.ZipFile
Copyright (C) 2001, 2002 Free Software Foundation, Inc. Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
...@@ -37,6 +37,7 @@ exception statement from your version. */ ...@@ -37,6 +37,7 @@ exception statement from your version. */
package java.util.zip; package java.util.zip;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataInputStream; import java.io.DataInputStream;
...@@ -46,7 +47,8 @@ import java.io.IOException; ...@@ -46,7 +47,8 @@ import java.io.IOException;
import java.io.EOFException; import java.io.EOFException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Hashtable; import java.util.HashMap;
import java.util.Iterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
/** /**
...@@ -58,6 +60,7 @@ import java.util.NoSuchElementException; ...@@ -58,6 +60,7 @@ import java.util.NoSuchElementException;
* entries in different threads. * entries in different threads.
* *
* @author Jochen Hoenicke * @author Jochen Hoenicke
* @author Artur Biesiadowski
*/ */
public class ZipFile implements ZipConstants public class ZipFile implements ZipConstants
{ {
...@@ -79,7 +82,7 @@ public class ZipFile implements ZipConstants ...@@ -79,7 +82,7 @@ public class ZipFile implements ZipConstants
private final RandomAccessFile raf; private final RandomAccessFile raf;
// The entries of this zip file when initialized and not yet closed. // The entries of this zip file when initialized and not yet closed.
private Hashtable entries; private HashMap entries;
private boolean closed = false; private boolean closed = false;
...@@ -137,33 +140,74 @@ public class ZipFile implements ZipConstants ...@@ -137,33 +140,74 @@ public class ZipFile implements ZipConstants
} }
/** /**
* Read an unsigned short in little endian byte order. * Read an unsigned short in little endian byte order from the given
* DataInput stream using the given byte buffer.
*
* @param di DataInput stream to read from.
* @param b the byte buffer to read in (must be at least 2 bytes long).
* @return The value read.
*
* @exception IOException if a i/o error occured. * @exception IOException if a i/o error occured.
* @exception EOFException if the file ends prematurely * @exception EOFException if the file ends prematurely
*/ */
private final int readLeShort(DataInput di) throws IOException private final int readLeShort(DataInput di, byte[] b) throws IOException
{ {
byte[] b = new byte[2]; di.readFully(b, 0, 2);
di.readFully(b);
return (b[0] & 0xff) | (b[1] & 0xff) << 8; return (b[0] & 0xff) | (b[1] & 0xff) << 8;
} }
/** /**
* Read an int in little endian byte order. * Read an int in little endian byte order from the given
* DataInput stream using the given byte buffer.
*
* @param di DataInput stream to read from.
* @param b the byte buffer to read in (must be at least 4 bytes long).
* @return The value read.
*
* @exception IOException if a i/o error occured. * @exception IOException if a i/o error occured.
* @exception EOFException if the file ends prematurely * @exception EOFException if the file ends prematurely
*/ */
private final int readLeInt(DataInput di) throws IOException private final int readLeInt(DataInput di, byte[] b) throws IOException
{ {
byte[] b = new byte[4]; di.readFully(b, 0, 4);
di.readFully(b);
return ((b[0] & 0xff) | (b[1] & 0xff) << 8) return ((b[0] & 0xff) | (b[1] & 0xff) << 8)
| ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16; | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16;
} }
/**
* Read an unsigned short in little endian byte order from the given
* byte buffer at the given offset.
*
* @param b the byte array to read from.
* @param off the offset to read from.
* @return The value read.
*/
private final int readLeShort(byte[] b, int off)
{
return (b[off] & 0xff) | (b[off+1] & 0xff) << 8;
}
/**
* Read an int in little endian byte order from the given
* byte buffer at the given offset.
*
* @param b the byte array to read from.
* @param off the offset to read from.
* @return The value read.
*/
private final int readLeInt(byte[] b, int off)
{
return ((b[off] & 0xff) | (b[off+1] & 0xff) << 8)
| ((b[off+2] & 0xff) | (b[off+3] & 0xff) << 8) << 16;
}
/** /**
* Read the central directory of a zip file and fill the entries * Read the central directory of a zip file and fill the entries
* array. This is called exactly once when first needed. * array. This is called exactly once when first needed. It is called
* while holding the lock on <code>raf</code>.
*
* @exception IOException if a i/o error occured. * @exception IOException if a i/o error occured.
* @exception ZipException if the central directory is malformed * @exception ZipException if the central directory is malformed
*/ */
...@@ -175,6 +219,8 @@ public class ZipFile implements ZipConstants ...@@ -175,6 +219,8 @@ public class ZipFile implements ZipConstants
* file isn't a zip file. * file isn't a zip file.
*/ */
long pos = raf.length() - ENDHDR; long pos = raf.length() - ENDHDR;
byte[] ebs = new byte[CENHDR];
do do
{ {
if (pos < 0) if (pos < 0)
...@@ -182,45 +228,42 @@ public class ZipFile implements ZipConstants ...@@ -182,45 +228,42 @@ public class ZipFile implements ZipConstants
("central directory not found, probably not a zip file: " + name); ("central directory not found, probably not a zip file: " + name);
raf.seek(pos--); raf.seek(pos--);
} }
while (readLeInt(raf) != ENDSIG); while (readLeInt(raf, ebs) != ENDSIG);
if (raf.skipBytes(ENDTOT - ENDNRD) != ENDTOT - ENDNRD) if (raf.skipBytes(ENDTOT - ENDNRD) != ENDTOT - ENDNRD)
throw new EOFException(name); throw new EOFException(name);
int count = readLeShort(raf); int count = readLeShort(raf, ebs);
if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ) if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ)
throw new EOFException(name); throw new EOFException(name);
int centralOffset = readLeInt(raf); int centralOffset = readLeInt(raf, ebs);
entries = new Hashtable(count); entries = new HashMap(count+count/2);
raf.seek(centralOffset); raf.seek(centralOffset);
byte[] ebs = new byte[24];
ByteArrayInputStream ebais = new ByteArrayInputStream(ebs); byte[] buffer = new byte[16];
DataInputStream edip = new DataInputStream(ebais);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
if (readLeInt(raf) != CENSIG) raf.readFully(ebs);
if (readLeInt(ebs, 0) != CENSIG)
throw new ZipException("Wrong Central Directory signature: " + name); throw new ZipException("Wrong Central Directory signature: " + name);
if (raf.skipBytes(CENHOW - CENVEM) != CENHOW - CENVEM)
throw new EOFException(name); int method = readLeShort(ebs, CENHOW);
int dostime = readLeInt(ebs, CENTIM);
raf.readFully(ebs); int crc = readLeInt(ebs, CENCRC);
ebais.reset(); int csize = readLeInt(ebs, CENSIZ);
int method = readLeShort(edip); int size = readLeInt(ebs, CENLEN);
int dostime = readLeInt(edip); int nameLen = readLeShort(ebs, CENNAM);
int crc = readLeInt(edip); int extraLen = readLeShort(ebs, CENEXT);
int csize = readLeInt(edip); int commentLen = readLeShort(ebs, CENCOM);
int size = readLeInt(edip);
int nameLen = readLeShort(edip); int offset = readLeInt(ebs, CENOFF);
int extraLen = readLeShort(edip);
int commentLen = readLeShort(edip); int needBuffer = Math.max(nameLen, commentLen);
if (buffer.length < needBuffer)
if (raf.skipBytes(CENOFF - CENDSK) != CENOFF - CENDSK) buffer = new byte[needBuffer];
throw new EOFException(name);
int offset = readLeInt(raf);
byte[] buffer = new byte[Math.max(nameLen, commentLen)];
raf.readFully(buffer, 0, nameLen); raf.readFully(buffer, 0, nameLen);
String name = new String(buffer, 0, nameLen); String name = new String(buffer, 0, 0, nameLen);
ZipEntry entry = new ZipEntry(name); ZipEntry entry = new ZipEntry(name);
entry.setMethod(method); entry.setMethod(method);
...@@ -248,6 +291,7 @@ public class ZipFile implements ZipConstants ...@@ -248,6 +291,7 @@ public class ZipFile implements ZipConstants
* Closes the ZipFile. This also closes all input streams given by * Closes the ZipFile. This also closes all input streams given by
* this class. After this is called, no further method should be * this class. After this is called, no further method should be
* called. * called.
*
* @exception IOException if a i/o error occured. * @exception IOException if a i/o error occured.
*/ */
public void close() throws IOException public void close() throws IOException
...@@ -267,7 +311,7 @@ public class ZipFile implements ZipConstants ...@@ -267,7 +311,7 @@ public class ZipFile implements ZipConstants
{ {
try try
{ {
return new ZipEntryEnumeration(getEntries().elements()); return new ZipEntryEnumeration(getEntries().values().iterator());
} }
catch (IOException ioe) catch (IOException ioe)
{ {
...@@ -281,7 +325,7 @@ public class ZipFile implements ZipConstants ...@@ -281,7 +325,7 @@ public class ZipFile implements ZipConstants
* @exception IllegalStateException when the ZipFile has already been closed. * @exception IllegalStateException when the ZipFile has already been closed.
* @exception IOEexception when the entries could not be read. * @exception IOEexception when the entries could not be read.
*/ */
private Hashtable getEntries() throws IOException private HashMap getEntries() throws IOException
{ {
synchronized(raf) synchronized(raf)
{ {
...@@ -297,15 +341,16 @@ public class ZipFile implements ZipConstants ...@@ -297,15 +341,16 @@ public class ZipFile implements ZipConstants
/** /**
* Searches for a zip entry in this archive with the given name. * Searches for a zip entry in this archive with the given name.
*
* @param the name. May contain directory components separated by * @param the name. May contain directory components separated by
* slashes ('/'). * slashes ('/').
* @return the zip entry, or null if no entry with that name exists. * @return the zip entry, or null if no entry with that name exists.
* @see #entries */ */
public ZipEntry getEntry(String name) public ZipEntry getEntry(String name)
{ {
try try
{ {
Hashtable entries = getEntries(); HashMap entries = getEntries();
ZipEntry entry = (ZipEntry) entries.get(name); ZipEntry entry = (ZipEntry) entries.get(name);
return entry != null ? (ZipEntry) entry.clone() : null; return entry != null ? (ZipEntry) entry.clone() : null;
} }
...@@ -315,10 +360,17 @@ public class ZipFile implements ZipConstants ...@@ -315,10 +360,17 @@ public class ZipFile implements ZipConstants
} }
} }
//access should be protected by synchronized(raf)
private byte[] locBuf = new byte[LOCHDR];
/** /**
* Checks, if the local header of the entry at index i matches the * Checks, if the local header of the entry at index i matches the
* central directory, and returns the offset to the data. * central directory, and returns the offset to the data.
*
* @param entry to check.
* @return the start offset of the (compressed) data. * @return the start offset of the (compressed) data.
*
* @exception IOException if a i/o error occured. * @exception IOException if a i/o error occured.
* @exception ZipException if the local header doesn't match the * @exception ZipException if the local header doesn't match the
* central directory header * central directory header
...@@ -328,24 +380,18 @@ public class ZipFile implements ZipConstants ...@@ -328,24 +380,18 @@ public class ZipFile implements ZipConstants
synchronized (raf) synchronized (raf)
{ {
raf.seek(entry.offset); raf.seek(entry.offset);
if (readLeInt(raf) != LOCSIG) raf.readFully(locBuf);
if (readLeInt(locBuf, 0) != LOCSIG)
throw new ZipException("Wrong Local header signature: " + name); throw new ZipException("Wrong Local header signature: " + name);
/* skip version and flags */ if (entry.getMethod() != readLeShort(locBuf, LOCHOW))
if (raf.skipBytes(LOCHOW - LOCVER) != LOCHOW - LOCVER)
throw new EOFException(name);
if (entry.getMethod() != readLeShort(raf))
throw new ZipException("Compression method mismatch: " + name); throw new ZipException("Compression method mismatch: " + name);
/* Skip time, crc, size and csize */ if (entry.getName().length() != readLeShort(locBuf, LOCNAM))
if (raf.skipBytes(LOCNAM - LOCTIM) != LOCNAM - LOCTIM)
throw new EOFException(name);
if (entry.getName().length() != readLeShort(raf))
throw new ZipException("file name length mismatch: " + name); throw new ZipException("file name length mismatch: " + name);
int extraLen = entry.getName().length() + readLeShort(raf); int extraLen = entry.getName().length() + readLeShort(locBuf, LOCEXT);
return entry.offset + LOCHDR + extraLen; return entry.offset + LOCHDR + extraLen;
} }
} }
...@@ -354,13 +400,16 @@ public class ZipFile implements ZipConstants ...@@ -354,13 +400,16 @@ public class ZipFile implements ZipConstants
* Creates an input stream reading the given zip entry as * Creates an input stream reading the given zip entry as
* uncompressed data. Normally zip entry should be an entry * uncompressed data. Normally zip entry should be an entry
* returned by getEntry() or entries(). * returned by getEntry() or entries().
*
* @param entry the entry to create an InputStream for.
* @return the input stream. * @return the input stream.
*
* @exception IOException if a i/o error occured. * @exception IOException if a i/o error occured.
* @exception ZipException if the Zip archive is malformed. * @exception ZipException if the Zip archive is malformed.
*/ */
public InputStream getInputStream(ZipEntry entry) throws IOException public InputStream getInputStream(ZipEntry entry) throws IOException
{ {
Hashtable entries = getEntries(); HashMap entries = getEntries();
String name = entry.getName(); String name = entry.getName();
ZipEntry zipEntry = (ZipEntry) entries.get(name); ZipEntry zipEntry = (ZipEntry) entries.get(name);
if (zipEntry == null) if (zipEntry == null)
...@@ -368,8 +417,8 @@ public class ZipFile implements ZipConstants ...@@ -368,8 +417,8 @@ public class ZipFile implements ZipConstants
long start = checkLocalHeader(zipEntry); long start = checkLocalHeader(zipEntry);
int method = zipEntry.getMethod(); int method = zipEntry.getMethod();
InputStream is = new PartialInputStream InputStream is = new BufferedInputStream(new PartialInputStream
(raf, start, zipEntry.getCompressedSize()); (raf, start, zipEntry.getCompressedSize()));
switch (method) switch (method)
{ {
case ZipOutputStream.STORED: case ZipOutputStream.STORED:
...@@ -406,16 +455,16 @@ public class ZipFile implements ZipConstants ...@@ -406,16 +455,16 @@ public class ZipFile implements ZipConstants
private static class ZipEntryEnumeration implements Enumeration private static class ZipEntryEnumeration implements Enumeration
{ {
private final Enumeration elements; private final Iterator elements;
public ZipEntryEnumeration(Enumeration elements) public ZipEntryEnumeration(Iterator elements)
{ {
this.elements = elements; this.elements = elements;
} }
public boolean hasMoreElements() public boolean hasMoreElements()
{ {
return elements.hasMoreElements(); return elements.hasNext();
} }
public Object nextElement() public Object nextElement()
...@@ -423,13 +472,13 @@ public class ZipFile implements ZipConstants ...@@ -423,13 +472,13 @@ public class ZipFile implements ZipConstants
/* We return a clone, just to be safe that the user doesn't /* We return a clone, just to be safe that the user doesn't
* change the entry. * change the entry.
*/ */
return ((ZipEntry)elements.nextElement()).clone(); return ((ZipEntry)elements.next()).clone();
} }
} }
private static class PartialInputStream extends InputStream private static class PartialInputStream extends InputStream
{ {
RandomAccessFile raf; private final RandomAccessFile raf;
long filepos, end; long filepos, end;
public PartialInputStream(RandomAccessFile raf, long start, long len) public PartialInputStream(RandomAccessFile raf, long start, long len)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment