diff --git a/jdk/make/java/zip/FILES_c.gmk b/jdk/make/java/zip/FILES_c.gmk index 6426cea2ced..f88386c8ee9 100644 --- a/jdk/make/java/zip/FILES_c.gmk +++ b/jdk/make/java/zip/FILES_c.gmk @@ -29,7 +29,6 @@ FILES_c = \ Deflater.c \ Inflater.c \ ZipFile.c \ - ZipEntry.c \ zadler32.c \ zcrc32.c \ deflate.c \ diff --git a/jdk/make/java/zip/mapfile-vers b/jdk/make/java/zip/mapfile-vers index 443ea67c83e..096fa35e434 100644 --- a/jdk/make/java/zip/mapfile-vers +++ b/jdk/make/java/zip/mapfile-vers @@ -50,15 +50,17 @@ SUNWprivate_1.1 { Java_java_util_zip_Inflater_initIDs; Java_java_util_zip_Inflater_reset; Java_java_util_zip_Inflater_setDictionary; - Java_java_util_zip_ZipEntry_initFields; - Java_java_util_zip_ZipEntry_initIDs; Java_java_util_zip_ZipFile_close; Java_java_util_zip_ZipFile_freeEntry; - Java_java_util_zip_ZipFile_getCSize; Java_java_util_zip_ZipFile_getEntry; - Java_java_util_zip_ZipFile_getMethod; + Java_java_util_zip_ZipFile_getEntryBytes; + Java_java_util_zip_ZipFile_getEntryCrc; + Java_java_util_zip_ZipFile_getEntryCSize; + Java_java_util_zip_ZipFile_getEntryFlag; + Java_java_util_zip_ZipFile_getEntryMethod; + Java_java_util_zip_ZipFile_getEntrySize; + Java_java_util_zip_ZipFile_getEntryTime; Java_java_util_zip_ZipFile_getNextEntry; - Java_java_util_zip_ZipFile_getSize; Java_java_util_zip_ZipFile_getZipMessage; Java_java_util_zip_ZipFile_getTotal; Java_java_util_zip_ZipFile_initIDs; diff --git a/jdk/make/java/zip/reorder-i586 b/jdk/make/java/zip/reorder-i586 index d1af81c9d7a..d9e90ead435 100644 --- a/jdk/make/java/zip/reorder-i586 +++ b/jdk/make/java/zip/reorder-i586 @@ -20,12 +20,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs; text: .text%Java_java_util_zip_ZipFile_open; text: .text%Java_java_util_zip_ZipFile_getTotal; text: .text%Java_java_util_zip_ZipFile_getEntry; -text: .text%Java_java_util_zip_ZipEntry_initIDs; -text: .text%Java_java_util_zip_ZipEntry_initFields; text: .text%Java_java_util_zip_ZipFile_freeEntry; -text: .text%Java_java_util_zip_ZipFile_getCSize; -text: .text%Java_java_util_zip_ZipFile_getSize; -text: .text%Java_java_util_zip_ZipFile_getMethod; +text: .text%Java_java_util_zip_ZipFile_getEntryTime; +text: .text%Java_java_util_zip_ZipFile_getEntryCrc; +text: .text%Java_java_util_zip_ZipFile_getEntryCSize; +text: .text%Java_java_util_zip_ZipFile_getEntrySize; +text: .text%Java_java_util_zip_ZipFile_getEntryFlag; +text: .text%Java_java_util_zip_ZipFile_getEntryMethod; +text: .text%Java_java_util_zip_ZipFile_getEntryBytes; text: .text%Java_java_util_zip_Inflater_initIDs; text: .text%Java_java_util_zip_Inflater_init; text: .text%inflateInit2_; diff --git a/jdk/make/java/zip/reorder-sparc b/jdk/make/java/zip/reorder-sparc index b004b3c7d0c..82cc81b6322 100644 --- a/jdk/make/java/zip/reorder-sparc +++ b/jdk/make/java/zip/reorder-sparc @@ -19,12 +19,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs; text: .text%Java_java_util_zip_ZipFile_open; text: .text%Java_java_util_zip_ZipFile_getTotal; text: .text%Java_java_util_zip_ZipFile_getEntry; -text: .text%Java_java_util_zip_ZipEntry_initIDs; -text: .text%Java_java_util_zip_ZipEntry_initFields; text: .text%Java_java_util_zip_ZipFile_freeEntry; -text: .text%Java_java_util_zip_ZipFile_getCSize; -text: .text%Java_java_util_zip_ZipFile_getSize; -text: .text%Java_java_util_zip_ZipFile_getMethod; +text: .text%Java_java_util_zip_ZipFile_getEntryTime; +text: .text%Java_java_util_zip_ZipFile_getEntryCrc; +text: .text%Java_java_util_zip_ZipFile_getEntryCSize; +text: .text%Java_java_util_zip_ZipFile_getEntrySize; +text: .text%Java_java_util_zip_ZipFile_getEntryFlag; +text: .text%Java_java_util_zip_ZipFile_getEntryMethod; +text: .text%Java_java_util_zip_ZipFile_getEntryBytes; text: .text%Java_java_util_zip_Inflater_initIDs; text: .text%Java_java_util_zip_Inflater_init; text: .text%inflateInit2_; diff --git a/jdk/make/java/zip/reorder-sparcv9 b/jdk/make/java/zip/reorder-sparcv9 index e1061f8ebae..a2b0f467df0 100644 --- a/jdk/make/java/zip/reorder-sparcv9 +++ b/jdk/make/java/zip/reorder-sparcv9 @@ -20,12 +20,14 @@ text: .text%Java_java_util_zip_ZipFile_initIDs; text: .text%Java_java_util_zip_ZipFile_open; text: .text%Java_java_util_zip_ZipFile_getTotal; text: .text%Java_java_util_zip_ZipFile_getEntry; -text: .text%Java_java_util_zip_ZipEntry_initIDs; -text: .text%Java_java_util_zip_ZipEntry_initFields; text: .text%Java_java_util_zip_ZipFile_freeEntry; -text: .text%Java_java_util_zip_ZipFile_getCSize; -text: .text%Java_java_util_zip_ZipFile_getSize; -text: .text%Java_java_util_zip_ZipFile_getMethod; +text: .text%Java_java_util_zip_ZipFile_getEntryTime; +text: .text%Java_java_util_zip_ZipFile_getEntryCrc; +text: .text%Java_java_util_zip_ZipFile_getEntryCSize; +text: .text%Java_java_util_zip_ZipFile_getEntrySize; +text: .text%Java_java_util_zip_ZipFile_getEntryFlag; +text: .text%Java_java_util_zip_ZipFile_getEntryMethod; +text: .text%Java_java_util_zip_ZipFile_getEntryBytes; text: .text%Java_java_util_zip_Inflater_initIDs; text: .text%Java_java_util_zip_Inflater_init; text: .text%inflateInit2_; diff --git a/jdk/src/share/classes/java/util/zip/ZipCoder.java b/jdk/src/share/classes/java/util/zip/ZipCoder.java new file mode 100644 index 00000000000..6442bea819d --- /dev/null +++ b/jdk/src/share/classes/java/util/zip/ZipCoder.java @@ -0,0 +1,139 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package java.util.zip; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.util.Arrays; + +/** + * Utility class for zipfile name and comment decoding and encoding + */ + +final class ZipCoder { + + String toString(byte[] ba, int length) { + CharsetDecoder cd = decoder().reset(); + int len = (int)(length * cd.maxCharsPerByte()); + char[] ca = new char[len]; + if (len == 0) + return new String(ca); + ByteBuffer bb = ByteBuffer.wrap(ba, 0, length); + CharBuffer cb = CharBuffer.wrap(ca); + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + return new String(ca, 0, cb.position()); + } + + String toString(byte[] ba) { + return toString(ba, ba.length); + } + + byte[] getBytes(String s) { + CharsetEncoder ce = encoder().reset(); + char[] ca = s.toCharArray(); + int len = (int)(ca.length * ce.maxBytesPerChar()); + byte[] ba = new byte[len]; + if (len == 0) + return ba; + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca); + CoderResult cr = ce.encode(cb, bb, true); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + cr = ce.flush(bb); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + if (bb.position() == ba.length) // defensive copy? + return ba; + else + return Arrays.copyOf(ba, bb.position()); + } + + // assume invoked only if "this" is not utf8 + byte[] getBytesUTF8(String s) { + if (isutf8) + return getBytes(s); + if (utf8 == null) + utf8 = new ZipCoder(Charset.forName("UTF-8")); + return utf8.getBytes(s); + } + + + String toStringUTF8(byte[] ba, int len) { + if (isutf8) + return toString(ba, len); + if (utf8 == null) + utf8 = new ZipCoder(Charset.forName("UTF-8")); + return utf8.toString(ba, len); + } + + boolean isUTF8() { + return isutf8; + } + + private Charset cs; + private CharsetDecoder dec; + private CharsetEncoder enc; + private boolean isutf8; + private ZipCoder utf8; + + private ZipCoder(Charset cs) { + this.cs = cs; + this.isutf8 = cs.name().equals("UTF-8"); + } + + static ZipCoder get(Charset charset) { + return new ZipCoder(charset); + } + + private CharsetDecoder decoder() { + if (dec == null) { + dec = cs.newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + } + return dec; + } + + private CharsetEncoder encoder() { + if (enc == null) { + enc = cs.newEncoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + } + return enc; + } +} diff --git a/jdk/src/share/classes/java/util/zip/ZipConstants64.java b/jdk/src/share/classes/java/util/zip/ZipConstants64.java index 1bf3b1841b4..b844b2cccee 100644 --- a/jdk/src/share/classes/java/util/zip/ZipConstants64.java +++ b/jdk/src/share/classes/java/util/zip/ZipConstants64.java @@ -73,5 +73,12 @@ class ZipConstants64 { static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte + /* + * Language encoding flag EFS + */ + static final int EFS = 0x800; // If this bit is set the filename and + // comment fields for this file must be + // encoded using UTF-8. + private ZipConstants64() {} } diff --git a/jdk/src/share/classes/java/util/zip/ZipEntry.java b/jdk/src/share/classes/java/util/zip/ZipEntry.java index 6c16a9adb15..96e3b4d828e 100644 --- a/jdk/src/share/classes/java/util/zip/ZipEntry.java +++ b/jdk/src/share/classes/java/util/zip/ZipEntry.java @@ -40,6 +40,7 @@ class ZipEntry implements ZipConstants, Cloneable { long size = -1; // uncompressed size of entry data long csize = -1; // compressed size of entry data int method = -1; // compression method + int flag = 0; // general purpose flag byte[] extra; // optional extra field data for entry String comment; // optional comment string for entry @@ -53,13 +54,6 @@ class ZipEntry implements ZipConstants, Cloneable { */ public static final int DEFLATED = 8; - static { - /* Zip library is loaded from System.initializeSystemClass */ - initIDs(); - } - - private static native void initIDs(); - /** * Creates a new zip entry with the specified name. * @@ -90,28 +84,15 @@ class ZipEntry implements ZipConstants, Cloneable { size = e.size; csize = e.csize; method = e.method; + flag = e.flag; extra = e.extra; comment = e.comment; } /* - * Creates a new zip entry for the given name with fields initialized - * from the specified jzentry data. + * Creates a new un-initialized zip entry */ - ZipEntry(String name, long jzentry) { - this.name = name; - initFields(jzentry); - } - - private native void initFields(long jzentry); - - /* - * Creates a new zip entry with fields initialized from the specified - * jzentry data. - */ - ZipEntry(long jzentry) { - initFields(jzentry); - } + ZipEntry() {} /** * Returns the name of the entry. @@ -258,16 +239,16 @@ class ZipEntry implements ZipConstants, Cloneable { /** * Sets the optional comment string for the entry. + * + *
ZIP entry comments have maximum length of 0xffff. If the length of the + * specified comment string is greater than 0xFFFF bytes after encoding, only + * the first 0xFFFF bytes are output to the ZIP file entry. + * * @param comment the comment string - * @exception IllegalArgumentException if the length of the specified - * comment string is greater than 0xFFFF bytes + * * @see #getComment() */ public void setComment(String comment) { - if (comment != null && comment.length() > 0xffff/3 - && ZipOutputStream.getUTF8Length(comment) > 0xffff) { - throw new IllegalArgumentException("invalid entry comment length"); - } this.comment = comment; } diff --git a/jdk/src/share/classes/java/util/zip/ZipFile.java b/jdk/src/share/classes/java/util/zip/ZipFile.java index 37e92ddecb7..8ee0bc2eb57 100644 --- a/jdk/src/share/classes/java/util/zip/ZipFile.java +++ b/jdk/src/share/classes/java/util/zip/ZipFile.java @@ -29,9 +29,11 @@ import java.io.InputStream; import java.io.IOException; import java.io.EOFException; import java.io.File; +import java.nio.charset.Charset; import java.util.Vector; import java.util.Enumeration; import java.util.NoSuchElementException; +import static java.util.zip.ZipConstants64.*; /** * This class is used to read entries from a zip file. @@ -76,16 +78,19 @@ class ZipFile implements ZipConstants { /** * Opens a zip file for reading. * - *
First, if there is a security
- * manager, its checkRead
method
- * is called with the name
argument
- * as its argument to ensure the read is allowed.
+ *
First, if there is a security manager, its checkRead
+ * method is called with the name
argument as its argument
+ * to ensure the read is allowed.
+ *
+ *
The UTF-8 {@link java.nio.charset.Charset charset} is used to
+ * decode the entry names and comments.
*
* @param name the name of the zip file
* @throws ZipException if a ZIP format error has occurred
* @throws IOException if an I/O error has occurred
* @throws SecurityException if a security manager exists and its
* checkRead
method doesn't allow read access to the file.
+ *
* @see SecurityManager#checkRead(java.lang.String)
*/
public ZipFile(String name) throws IOException {
@@ -101,6 +106,9 @@ class ZipFile implements ZipConstants {
* method is called with the name
argument as its argument to
* ensure the read is allowed.
*
+ *
The UTF-8 {@link java.nio.charset.Charset charset} is used to + * decode the entry names and comments + * * @param file the ZIP file to be opened for reading * @param mode the mode in which the file is to be opened * @throws ZipException if a ZIP format error has occurred @@ -115,6 +123,59 @@ class ZipFile implements ZipConstants { * @since 1.3 */ public ZipFile(File file, int mode) throws IOException { + this(file, mode, Charset.forName("UTF-8")); + } + + /** + * Opens a ZIP file for reading given the specified File object. + * + *
The UTF-8 {@link java.nio.charset.Charset charset} is used to
+ * decode the entry names and comments.
+ *
+ * @param file the ZIP file to be opened for reading
+ * @throws ZipException if a ZIP format error has occurred
+ * @throws IOException if an I/O error has occurred
+ */
+ public ZipFile(File file) throws ZipException, IOException {
+ this(file, OPEN_READ);
+ }
+
+ private ZipCoder zc;
+
+ /**
+ * Opens a new ZipFile
to read from the specified
+ * File
object in the specified mode. The mode argument
+ * must be either OPEN_READ or OPEN_READ | OPEN_DELETE.
+ *
+ *
First, if there is a security manager, its checkRead
+ * method is called with the name
argument as its argument to
+ * ensure the read is allowed.
+ *
+ * @param file the ZIP file to be opened for reading
+ * @param mode the mode in which the file is to be opened
+ * @param charset
+ * the {@link java.nio.charset.Charset {@code charset}} to
+ * be used to decode the ZIP entry name and comment that are not
+ * encoded by using UTF-8 encoding (indicated by entry's general
+ * purpose flag).
+ *
+ * @throws ZipException if a ZIP format error has occurred
+ * @throws IOException if an I/O error has occurred
+ *
+ * @throws SecurityException
+ * if a security manager exists and its checkRead
+ * method doesn't allow read access to the file,or its
+ * checkDelete
method doesn't allow deleting the
+ * file when the OPEN_DELETE flag is set
+ *
+ * @throws IllegalArgumentException if the mode argument is invalid
+ *
+ * @see SecurityManager#checkRead(java.lang.String)
+ *
+ * @since 1.7
+ */
+ public ZipFile(File file, int mode, Charset charset) throws IOException
+ {
if (((mode & OPEN_READ) == 0) ||
((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) {
throw new IllegalArgumentException("Illegal mode: 0x"+
@@ -128,24 +189,61 @@ class ZipFile implements ZipConstants {
sm.checkDelete(name);
}
}
+ if (charset == null)
+ throw new NullPointerException("charset is null");
+ this.zc = ZipCoder.get(charset);
jzfile = open(name, mode, file.lastModified());
-
this.name = name;
this.total = getTotal(jzfile);
}
- private static native long open(String name, int mode, long lastModified);
- private static native int getTotal(long jzfile);
-
+ /**
+ * Opens a zip file for reading.
+ *
+ *
First, if there is a security manager, its checkRead
+ * method is called with the name
argument as its argument
+ * to ensure the read is allowed.
+ *
+ * @param name the name of the zip file
+ * @param charset
+ * the {@link java.nio.charset.Charset {@code charset}} to
+ * be used to decode the ZIP entry name and comment that are not
+ * encoded by using UTF-8 encoding (indicated by entry's general
+ * purpose flag).
+ *
+ * @throws ZipException if a ZIP format error has occurred
+ * @throws IOException if an I/O error has occurred
+ * @throws SecurityException
+ * if a security manager exists and its checkRead
+ * method doesn't allow read access to the file
+ *
+ * @see SecurityManager#checkRead(java.lang.String)
+ *
+ * @since 1.7
+ */
+ public ZipFile(String name, Charset charset) throws IOException
+ {
+ this(new File(name), OPEN_READ, charset);
+ }
/**
* Opens a ZIP file for reading given the specified File object.
* @param file the ZIP file to be opened for reading
- * @throws ZipException if a ZIP error has occurred
+ * @param charset
+ * The {@link java.nio.charset.Charset {@code charset}} to be
+ * used to decode the ZIP entry name and comment (ignored if
+ * the language
+ * encoding bit of the ZIP entry's general purpose bit
+ * flag is set).
+ *
+ * @throws ZipException if a ZIP format error has occurred
* @throws IOException if an I/O error has occurred
+ *
+ * @since 1.7
*/
- public ZipFile(File file) throws ZipException, IOException {
- this(file, OPEN_READ);
+ public ZipFile(File file, Charset charset) throws IOException
+ {
+ this(file, OPEN_READ, charset);
}
/**
@@ -163,9 +261,9 @@ class ZipFile implements ZipConstants {
long jzentry = 0;
synchronized (this) {
ensureOpen();
- jzentry = getEntry(jzfile, name, true);
+ jzentry = getEntry(jzfile, zc.getBytes(name), true);
if (jzentry != 0) {
- ZipEntry ze = new ZipEntry(name, jzentry);
+ ZipEntry ze = getZipEntry(name, jzentry);
freeEntry(jzfile, jzentry);
return ze;
}
@@ -173,7 +271,7 @@ class ZipFile implements ZipConstants {
return null;
}
- private static native long getEntry(long jzfile, String name,
+ private static native long getEntry(long jzfile, byte[] name,
boolean addSlash);
// freeEntry releases the C jzentry struct.
@@ -194,36 +292,30 @@ class ZipFile implements ZipConstants {
* @throws IllegalStateException if the zip file has been closed
*/
public InputStream getInputStream(ZipEntry entry) throws IOException {
- return getInputStream(entry.name);
- }
-
- /**
- * Returns an input stream for reading the contents of the specified
- * entry, or null if the entry was not found.
- */
- private InputStream getInputStream(String name) throws IOException {
- if (name == null) {
- throw new NullPointerException("name");
+ if (entry == null) {
+ throw new NullPointerException("entry");
}
long jzentry = 0;
ZipFileInputStream in = null;
synchronized (this) {
ensureOpen();
- jzentry = getEntry(jzfile, name, false);
+ if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
+ jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
+ } else {
+ jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
+ }
if (jzentry == 0) {
return null;
}
-
in = new ZipFileInputStream(jzentry);
-
}
final ZipFileInputStream zfin = in;
- switch (getMethod(jzentry)) {
+ switch (getEntryMethod(jzentry)) {
case STORED:
return zfin;
case DEFLATED:
// MORE: Compute good size for inflater stream:
- long size = getSize(jzentry) + 2; // Inflater likes a bit of slack
+ long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
if (size > 65536) size = 8192;
if (size <= 0) size = 4096;
return new InflaterInputStream(zfin, getInflater(), (int)size) {
@@ -267,8 +359,6 @@ class ZipFile implements ZipConstants {
}
}
- private static native int getMethod(long jzentry);
-
/*
* Gets an inflater from the list of available inflaters or allocates
* a new one.
@@ -343,7 +433,7 @@ class ZipFile implements ZipConstants {
",\n message = " + message
);
}
- ZipEntry ze = new ZipEntry(jzentry);
+ ZipEntry ze = getZipEntry(null, jzentry);
freeEntry(jzfile, jzentry);
return ze;
}
@@ -351,6 +441,38 @@ class ZipFile implements ZipConstants {
};
}
+ private ZipEntry getZipEntry(String name, long jzentry) {
+ ZipEntry e = new ZipEntry();
+ e.flag = getEntryFlag(jzentry); // get the flag first
+ if (name != null) {
+ e.name = name;
+ } else {
+ byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
+ if (!zc.isUTF8() && (e.flag & EFS) != 0) {
+ e.name = zc.toStringUTF8(bname, bname.length);
+ } else {
+ e.name = zc.toString(bname, bname.length);
+ }
+ }
+ e.time = getEntryTime(jzentry);
+ e.crc = getEntryCrc(jzentry);
+ e.size = getEntrySize(jzentry);
+ e. csize = getEntryCSize(jzentry);
+ e.method = getEntryMethod(jzentry);
+ e.extra = getEntryBytes(jzentry, JZENTRY_EXTRA);
+ byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
+ if (bcomm == null) {
+ e.comment = null;
+ } else {
+ if (!zc.isUTF8() && (e.flag & EFS) != 0) {
+ e.comment = zc.toStringUTF8(bcomm, bcomm.length);
+ } else {
+ e.comment = zc.toString(bcomm, bcomm.length);
+ }
+ }
+ return e;
+ }
+
private static native long getNextEntry(long jzfile, int i);
/**
@@ -443,8 +565,8 @@ class ZipFile implements ZipConstants {
ZipFileInputStream(long jzentry) {
pos = 0;
- rem = getCSize(jzentry);
- size = getSize(jzentry);
+ rem = getEntryCSize(jzentry);
+ size = getEntrySize(jzentry);
this.jzentry = jzentry;
}
@@ -514,13 +636,25 @@ class ZipFile implements ZipConstants {
}
+
+ private static native long open(String name, int mode, long lastModified)
+ throws IOException;
+ private static native int getTotal(long jzfile);
private static native int read(long jzfile, long jzentry,
long pos, byte[] b, int off, int len);
- private static native long getCSize(long jzentry);
+ // access to the native zentry object
+ private static native long getEntryTime(long jzentry);
+ private static native long getEntryCrc(long jzentry);
+ private static native long getEntryCSize(long jzentry);
+ private static native long getEntrySize(long jzentry);
+ private static native int getEntryMethod(long jzentry);
+ private static native int getEntryFlag(long jzentry);
- private static native long getSize(long jzentry);
+ private static final int JZENTRY_NAME = 0;
+ private static final int JZENTRY_EXTRA = 1;
+ private static final int JZENTRY_COMMENT = 2;
+ private static native byte[] getEntryBytes(long jzentry, int type);
- // Temporary add on for bug troubleshooting
private static native String getZipMessage(long jzfile);
}
diff --git a/jdk/src/share/classes/java/util/zip/ZipInputStream.java b/jdk/src/share/classes/java/util/zip/ZipInputStream.java
index 1b9b93415cb..83f9ad4b753 100644
--- a/jdk/src/share/classes/java/util/zip/ZipInputStream.java
+++ b/jdk/src/share/classes/java/util/zip/ZipInputStream.java
@@ -29,6 +29,7 @@ import java.io.InputStream;
import java.io.IOException;
import java.io.EOFException;
import java.io.PushbackInputStream;
+import java.nio.charset.Charset;
import static java.util.zip.ZipConstants64.*;
/**
@@ -54,6 +55,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
// one entry
private boolean entryEOF = false;
+ private ZipCoder zc;
+
/**
* Check to make sure that this stream has not been closed
*/
@@ -65,14 +68,39 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
/**
* Creates a new ZIP input stream.
+ *
+ *
The UTF-8 {@link java.nio.charset.Charset charset} is used to
+ * decode the entry names.
+ *
* @param in the actual input stream
*/
public ZipInputStream(InputStream in) {
+ this(in, Charset.forName("UTF-8"));
+ }
+
+ /**
+ * Creates a new ZIP input stream.
+ *
+ * @param in the actual input stream
+ *
+ * @param charset
+ * The {@link java.nio.charset.Charset {@code charset}} to be
+ * used to decode the ZIP entry name (ignored if the
+ * language
+ * encoding bit of the ZIP entry's general purpose bit
+ * flag is set).
+ *
+ * @since 1.7
+ */
+ public ZipInputStream(InputStream in, Charset charset) {
super(new PushbackInputStream(in, 512), new Inflater(true), 512);
usesDefaultInflater = true;
if(in == null) {
throw new NullPointerException("in is null");
}
+ if (charset == null)
+ throw new NullPointerException("charset is null");
+ this.zc = ZipCoder.get(charset);
}
/**
@@ -141,8 +169,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
* @param len the maximum number of bytes read
* @return the actual number of bytes read, or -1 if the end of the
* entry is reached
- * @exception NullPointerException If b
is null
.
- * @exception IndexOutOfBoundsException If off
is negative,
+ * @exception NullPointerException if b
is null
.
+ * @exception IndexOutOfBoundsException if off
is negative,
* len
is negative, or len
is greater than
* b.length - off
* @exception ZipException if a ZIP file error has occurred
@@ -252,6 +280,8 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
if (get32(tmpbuf, 0) != LOCSIG) {
return null;
}
+ // get flag first, we need check EFS.
+ flag = get16(tmpbuf, LOCFLG);
// get the entry name and create the ZipEntry first
int len = get16(tmpbuf, LOCNAM);
int blen = b.length;
@@ -262,9 +292,11 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
b = new byte[blen];
}
readFully(b, 0, len);
- ZipEntry e = createZipEntry(getUTF8String(b, 0, len));
+ // Force to use UTF-8 if the EFS bit is ON, even the cs is NOT UTF-8
+ ZipEntry e = createZipEntry(((flag & EFS) != 0)
+ ? zc.toStringUTF8(b, len)
+ : zc.toString(b, 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");
}
@@ -313,71 +345,6 @@ class ZipInputStream extends InflaterInputStream implements ZipConstants {
return e;
}
- /*
- * Fetches a UTF8-encoded String from the specified byte array.
- */
- private static 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 ((b[i++] & 0xc0) != 0x80) {
- throw new IllegalArgumentException();
- }
- count++;
- break;
- case 14:
- // 1110xxxx 10xxxxxx 10xxxxxx
- if (((b[i++] & 0xc0) != 0x80) ||
- ((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);
- }
-
/**
* Creates a new ZipEntry
object for the specified
* entry name.
diff --git a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java
index bd44d3213cf..da35ed97f14 100644
--- a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java
+++ b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java
@@ -27,6 +27,7 @@ package java.util.zip;
import java.io.OutputStream;
import java.io.IOException;
+import java.nio.charset.Charset;
import java.util.Vector;
import java.util.HashSet;
import static java.util.zip.ZipConstants64.*;
@@ -44,19 +45,9 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
private static class XEntry {
public final ZipEntry entry;
public final long offset;
- public final int flag;
public XEntry(ZipEntry entry, long offset) {
this.entry = entry;
this.offset = offset;
- this.flag = (entry.method == DEFLATED &&
- (entry.size == -1 ||
- entry.csize == -1 ||
- entry.crc == -1))
- // store size, compressed size, and crc-32 in data descriptor
- // immediately following the compressed entry data
- ? 8
- // store size, compressed size, and crc-32 in LOC header
- : 0;
}
}
@@ -66,12 +57,14 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
private CRC32 crc = new CRC32();
private long written = 0;
private long locoff = 0;
- private String comment;
+ private byte[] comment;
private int method = DEFLATED;
private boolean finished;
private boolean closed = false;
+ private final ZipCoder zc;
+
private static int version(ZipEntry e) throws ZipException {
switch (e.method) {
case DEFLATED: return 20;
@@ -100,10 +93,31 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
/**
* Creates a new ZIP output stream.
+ *
+ *
The UTF-8 {@link java.nio.charset.Charset charset} is used
+ * to encode the entry names and comments.
+ *
* @param out the actual output stream
*/
public ZipOutputStream(OutputStream out) {
+ this(out, Charset.forName("UTF-8"));
+ }
+
+ /**
+ * Creates a new ZIP output stream.
+ *
+ * @param out the actual output stream
+ *
+ * @param charset the {@link java.nio.charset.Charset charset
+
+
}
+ * to be used to encode the entry names and comments
+ *
+ * @since 1.7
+ */
+ public ZipOutputStream(OutputStream out, Charset charset) {
super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+ if (charset == null)
+ throw new NullPointerException("charset is null");
+ this.zc = ZipCoder.get(charset);
usesDefaultDeflater = true;
}
@@ -114,11 +128,11 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
* ZIP file comment is greater than 0xFFFF bytes
*/
public void setComment(String comment) {
- if (comment != null && comment.length() > 0xffff/3
- && getUTF8Length(comment) > 0xffff) {
- throw new IllegalArgumentException("ZIP file comment too long.");
+ if (comment != null) {
+ this.comment = zc.getBytes(comment);
+ if (this.comment.length > 0xffff)
+ throw new IllegalArgumentException("ZIP file comment too long.");
}
- this.comment = comment;
}
/**
@@ -167,8 +181,15 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (e.method == -1) {
e.method = method; // use default method
}
+ // store size, compressed size, and crc-32 in LOC header
+ e.flag = 0;
switch (e.method) {
case DEFLATED:
+ // store size, compressed size, and crc-32 in data descriptor
+ // immediately following the compressed entry data
+ if (e.size == -1 || e.csize == -1 || e.crc == -1)
+ e.flag = 8;
+
break;
case STORED:
// compressed size, uncompressed size, and crc-32 must all be
@@ -192,6 +213,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (! names.add(e.name)) {
throw new ZipException("duplicate entry: " + e.name);
}
+ if (zc.isUTF8())
+ e.flag |= EFS;
current = new XEntry(e, written);
xentries.add(current);
writeLOC(current);
@@ -213,7 +236,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
while (!def.finished()) {
deflate();
}
- if ((current.flag & 8) == 0) {
+ if ((e.flag & 8) == 0) {
// verify size, compressed size, and crc-32 settings
if (e.size != def.getBytesRead()) {
throw new ZipException(
@@ -343,11 +366,11 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
*/
private void writeLOC(XEntry xentry) throws IOException {
ZipEntry e = xentry.entry;
- int flag = xentry.flag;
+ int flag = e.flag;
int elen = (e.extra != null) ? e.extra.length : 0;
boolean hasZip64 = false;
- writeInt(LOCSIG); // LOC header signature
+ writeInt(LOCSIG); // LOC header signature
if ((flag & 8) == 8) {
writeShort(version(e)); // version needed to extract
@@ -380,7 +403,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeInt(e.size); // uncompressed size
}
}
- byte[] nameBytes = getUTF8Bytes(e.name);
+ byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length);
writeShort(elen);
writeBytes(nameBytes, 0, nameBytes.length);
@@ -417,7 +440,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
*/
private void writeCEN(XEntry xentry) throws IOException {
ZipEntry e = xentry.entry;
- int flag = xentry.flag;
+ int flag = e.flag;
int version = version(e);
long csize = e.csize;
@@ -454,7 +477,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeInt(e.crc); // crc-32
writeInt(csize); // compressed size
writeInt(size); // uncompressed size
- byte[] nameBytes = getUTF8Bytes(e.name);
+ byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length);
if (hasZip64) {
// + headid(2) + datasize(2)
@@ -464,8 +487,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
}
byte[] commentBytes;
if (e.comment != null) {
- commentBytes = getUTF8Bytes(e.comment);
- writeShort(commentBytes.length);
+ commentBytes = zc.getBytes(e.comment);
+ writeShort(Math.min(commentBytes.length, 0xffff));
} else {
commentBytes = null;
writeShort(0);
@@ -489,7 +512,7 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeBytes(e.extra, 0, e.extra.length);
}
if (commentBytes != null) {
- writeBytes(commentBytes, 0, commentBytes.length);
+ writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
}
}
@@ -541,9 +564,8 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
writeInt(xlen); // length of central directory
writeInt(xoff); // offset of central directory
if (comment != null) { // zip file comment
- byte[] b = getUTF8Bytes(comment);
- writeShort(b.length);
- writeBytes(b, 0, b.length);
+ writeShort(comment.length);
+ writeBytes(comment, 0, comment.length);
} else {
writeShort(0);
}
@@ -594,60 +616,4 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
super.out.write(b, off, len);
written += len;
}
-
- /*
- * Returns the length of String's UTF8 encoding.
- */
- static int getUTF8Length(String s) {
- int count = 0;
- for (int i = 0; i < s.length(); i++) {
- char ch = s.charAt(i);
- if (ch <= 0x7f) {
- count++;
- } else if (ch <= 0x7ff) {
- count += 2;
- } else {
- count += 3;
- }
- }
- return count;
- }
-
- /*
- * Returns an array of bytes representing the UTF8 encoding
- * of the specified String.
- */
- private static byte[] getUTF8Bytes(String s) {
- char[] c = s.toCharArray();
- int len = c.length;
- // Count the number of encoded bytes...
- int count = 0;
- for (int i = 0; i < len; i++) {
- int ch = c[i];
- if (ch <= 0x7f) {
- count++;
- } else if (ch <= 0x7ff) {
- count += 2;
- } else {
- count += 3;
- }
- }
- // Now return the encoded bytes...
- byte[] b = new byte[count];
- int off = 0;
- for (int i = 0; i < len; i++) {
- int ch = c[i];
- if (ch <= 0x7f) {
- b[off++] = (byte)ch;
- } else if (ch <= 0x7ff) {
- b[off++] = (byte)((ch >> 6) | 0xc0);
- b[off++] = (byte)((ch & 0x3f) | 0x80);
- } else {
- b[off++] = (byte)((ch >> 12) | 0xe0);
- b[off++] = (byte)(((ch >> 6) & 0x3f) | 0x80);
- b[off++] = (byte)((ch & 0x3f) | 0x80);
- }
- }
- return b;
- }
}
diff --git a/jdk/src/share/classes/java/util/zip/package.html b/jdk/src/share/classes/java/util/zip/package.html
index d4b59263678..83d117de55e 100644
--- a/jdk/src/share/classes/java/util/zip/package.html
+++ b/jdk/src/share/classes/java/util/zip/package.html
@@ -52,6 +52,11 @@ input streams.
PKWARE ZIP File Format Specification. The ZIP64(tm) format extensions
are used to overcome the size limitations of the original ZIP format.
+