diff options
Diffstat (limited to 'libjava/classpath/java/util/zip/ZipFile.java')
-rw-r--r-- | libjava/classpath/java/util/zip/ZipFile.java | 137 |
1 files changed, 107 insertions, 30 deletions
diff --git a/libjava/classpath/java/util/zip/ZipFile.java b/libjava/classpath/java/util/zip/ZipFile.java index 47ced0fb84f..3b34bd1f50b 100644 --- a/libjava/classpath/java/util/zip/ZipFile.java +++ b/libjava/classpath/java/util/zip/ZipFile.java @@ -48,6 +48,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedHashMap; @@ -88,7 +91,7 @@ public class ZipFile implements ZipConstants private final RandomAccessFile raf; // The entries of this zip file when initialized and not yet closed. - private LinkedHashMap entries; + private LinkedHashMap<String, ZipEntry> entries; private boolean closed = false; @@ -250,7 +253,7 @@ public class ZipFile implements ZipConstants throw new EOFException(name); int centralOffset = inp.readLeInt(); - entries = new LinkedHashMap(count+count/2); + entries = new LinkedHashMap<String, ZipEntry> (count+count/2); inp.seek(centralOffset); for (int i = 0; i < count; i++) @@ -327,7 +330,7 @@ public class ZipFile implements ZipConstants * * @exception IllegalStateException when the ZipFile has already been closed */ - public Enumeration entries() + public Enumeration<? extends ZipEntry> entries() { checkClosed(); @@ -347,7 +350,7 @@ public class ZipFile implements ZipConstants * @exception IllegalStateException when the ZipFile has already been closed. * @exception IOException when the entries could not be read. */ - private LinkedHashMap getEntries() throws IOException + private LinkedHashMap<String, ZipEntry> getEntries() throws IOException { synchronized(raf) { @@ -375,11 +378,11 @@ public class ZipFile implements ZipConstants try { - LinkedHashMap entries = getEntries(); - ZipEntry entry = (ZipEntry) entries.get(name); + LinkedHashMap<String, ZipEntry> entries = getEntries(); + ZipEntry entry = entries.get(name); // If we didn't find it, maybe it's a directory. if (entry == null && !name.endsWith("/")) - entry = (ZipEntry) entries.get(name + '/'); + entry = entries.get(name + '/'); return entry != null ? new ZipEntry(entry, name) : null; } catch (IOException ioe) @@ -414,9 +417,9 @@ public class ZipFile implements ZipConstants { checkClosed(); - LinkedHashMap entries = getEntries(); + LinkedHashMap<String, ZipEntry> entries = getEntries(); String name = entry.getName(); - ZipEntry zipEntry = (ZipEntry) entries.get(name); + ZipEntry zipEntry = entries.get(name); if (zipEntry == null) return null; @@ -491,11 +494,11 @@ public class ZipFile implements ZipConstants } } - private static class ZipEntryEnumeration implements Enumeration + private static class ZipEntryEnumeration implements Enumeration<ZipEntry> { - private final Iterator elements; + private final Iterator<ZipEntry> elements; - public ZipEntryEnumeration(Iterator elements) + public ZipEntryEnumeration(Iterator<ZipEntry> elements) { this.elements = elements; } @@ -505,17 +508,27 @@ public class ZipFile implements ZipConstants return elements.hasNext(); } - public Object nextElement() + public ZipEntry nextElement() { /* We return a clone, just to be safe that the user doesn't * change the entry. */ - return ((ZipEntry)elements.next()).clone(); + return (ZipEntry) (elements.next().clone()); } } private static final class PartialInputStream extends InputStream { + /** + * The UTF-8 charset use for decoding the filenames. + */ + private static final Charset UTF8CHARSET = Charset.forName("UTF-8"); + + /** + * The actual UTF-8 decoder. Created on demand. + */ + private CharsetDecoder utf8Decoder; + private final RandomAccessFile raf; private final byte[] buffer; private long bufferOffset; @@ -652,23 +665,86 @@ public class ZipFile implements ZipConstants int readLeShort() throws IOException { - int b0 = read(); - int b1 = read(); - if (b1 == -1) - throw new EOFException(); - return (b0 & 0xff) | (b1 & 0xff) << 8; + 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 readLeInt() throws IOException { - int b0 = read(); - int b1 = read(); - int b2 = read(); - int b3 = read(); - if (b3 == -1) - throw new EOFException(); - return ((b0 & 0xff) | (b1 & 0xff) << 8) - | ((b2 & 0xff) | (b3 & 0xff) << 8) << 16; + 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; + } + + /** + * Decode chars from byte buffer using UTF8 encoding. This + * operation is performance-critical since a jar file contains a + * large number of strings for the name of each file in the + * archive. This routine therefore avoids using the expensive + * utf8Decoder when decoding is straightforward. + * + * @param buffer the buffer that contains the encoded character + * data + * @param pos the index in buffer of the first byte of the encoded + * data + * @param length the length of the encoded data in number of + * bytes. + * + * @return a String that contains the decoded characters. + */ + 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 = new String(buffer, 0, pos, length); + } + else + { + ByteBuffer bufferBuffer = ByteBuffer.wrap(buffer, pos, length); + if (utf8Decoder == null) + utf8Decoder = UTF8CHARSET.newDecoder(); + utf8Decoder.reset(); + char [] characters = utf8Decoder.decode(bufferBuffer).array(); + result = String.valueOf(characters); + } + return result; } String readString(int length) throws IOException @@ -676,25 +752,26 @@ public class ZipFile implements ZipConstants if (length > end - (bufferOffset + pos)) throw new EOFException(); + String result = null; try { if (buffer.length - pos >= length) { - String s = new String(buffer, pos, length, "UTF-8"); + result = decodeChars(buffer, pos, length); pos += length; - return s; } else { byte[] b = new byte[length]; readFully(b); - return new String(b, 0, length, "UTF-8"); + result = decodeChars(b, 0, length); } } catch (UnsupportedEncodingException uee) { throw new AssertionError(uee); } + return result; } public void addDummyByte() |