2912 lines
110 KiB
Diff
2912 lines
110 KiB
Diff
From 7590fffae62f5a4157ab7612c186b442c81d5682 Mon Sep 17 00:00:00 2001
|
|
Date: Thu, 21 Sep 2023 15:15:39 +0800
|
|
Subject: add 8142508-To-bring-j.u.z.ZipFile-s-native-implementati
|
|
|
|
---
|
|
jdk/make/mapfiles/libzip/mapfile-vers | 23 +-
|
|
jdk/make/mapfiles/libzip/reorder-sparc | 17 -
|
|
jdk/make/mapfiles/libzip/reorder-sparcv9 | 16 -
|
|
jdk/make/mapfiles/libzip/reorder-x86 | 19 -
|
|
.../share/classes/java/util/jar/JarFile.java | 5 +-
|
|
.../share/classes/java/util/zip/ZipCoder.java | 21 +-
|
|
.../share/classes/java/util/zip/ZipFile.java | 933 ++++++++++++++----
|
|
.../share/classes/java/util/zip/ZipUtils.java | 79 +-
|
|
.../sun/misc/JavaUtilZipFileAccess.java | 1 +
|
|
jdk/src/share/classes/sun/misc/VM.java | 3 -
|
|
jdk/src/share/native/java/util/zip/ZipFile.c | 403 --------
|
|
jdk/src/share/native/java/util/zip/zip_util.c | 29 +-
|
|
jdk/src/share/native/java/util/zip/zip_util.h | 1 -
|
|
jdk/test/java/nio/file/spi/TestProvider.java | 274 ++++-
|
|
.../java/util/zip/ZipFile/TestZipFile.java | 375 +++++++
|
|
.../imageio/plugins/png/ItxtUtf8Test.java | 2 +-
|
|
16 files changed, 1440 insertions(+), 761 deletions(-)
|
|
delete mode 100644 jdk/src/share/native/java/util/zip/ZipFile.c
|
|
create mode 100644 jdk/test/java/util/zip/ZipFile/TestZipFile.java
|
|
|
|
diff --git a/jdk/make/mapfiles/libzip/mapfile-vers b/jdk/make/mapfiles/libzip/mapfile-vers
|
|
index 5d33990c3..e7394ae61 100644
|
|
--- a/jdk/make/mapfiles/libzip/mapfile-vers
|
|
+++ b/jdk/make/mapfiles/libzip/mapfile-vers
|
|
@@ -1,5 +1,5 @@
|
|
#
|
|
-# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
+# Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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
|
|
@@ -27,7 +27,6 @@
|
|
|
|
SUNWprivate_1.1 {
|
|
global:
|
|
- Java_java_util_jar_JarFile_getMetaInfEntryNames;
|
|
Java_java_util_zip_Adler32_update;
|
|
Java_java_util_zip_Adler32_updateBytes;
|
|
Java_java_util_zip_Adler32_updateByteBuffer;
|
|
@@ -48,26 +47,6 @@ 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_ZipFile_close;
|
|
- Java_java_util_zip_ZipFile_getCommentBytes;
|
|
- Java_java_util_zip_ZipFile_freeEntry;
|
|
- Java_java_util_zip_ZipFile_getEntry;
|
|
- 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_getZipMessage;
|
|
- Java_java_util_zip_ZipFile_getTotal;
|
|
- Java_java_util_zip_ZipFile_initIDs;
|
|
- Java_java_util_zip_ZipFile_open;
|
|
- Java_java_util_zip_ZipFile_read;
|
|
- Java_java_util_zip_ZipFile_startsWithLOC;
|
|
- Java_java_util_zip_ZipFile_getManifestNum;
|
|
-
|
|
ZIP_Close;
|
|
ZIP_CRC32;
|
|
ZIP_FindEntry;
|
|
diff --git a/jdk/make/mapfiles/libzip/reorder-sparc b/jdk/make/mapfiles/libzip/reorder-sparc
|
|
index 9d3aae88e..b1957dce7 100644
|
|
--- a/jdk/make/mapfiles/libzip/reorder-sparc
|
|
+++ b/jdk/make/mapfiles/libzip/reorder-sparc
|
|
@@ -15,31 +15,14 @@ text: .text%ZIP_GetEntry;
|
|
text: .text%ZIP_Lock;
|
|
text: .text%ZIP_Unlock;
|
|
text: .text%ZIP_FreeEntry;
|
|
-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_startsWithLOC;
|
|
-text: .text%Java_java_util_zip_ZipFile_getManifestNum;
|
|
-text: .text%Java_java_util_zip_ZipFile_getEntry;
|
|
-text: .text%Java_java_util_zip_ZipFile_freeEntry;
|
|
-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_;
|
|
text: .text%zcalloc;
|
|
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
|
-text: .text%Java_java_util_zip_ZipFile_read;
|
|
text: .text%ZIP_Read;
|
|
text: .text%zcfree;
|
|
-text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
|
|
text: .text%Java_java_util_zip_Inflater_reset;
|
|
text: .text%Java_java_util_zip_Inflater_end;
|
|
text: .text%inflateEnd;
|
|
-text: .text%Java_java_util_zip_ZipFile_close;
|
|
text: .text%ZIP_Close;
|
|
diff --git a/jdk/make/mapfiles/libzip/reorder-sparcv9 b/jdk/make/mapfiles/libzip/reorder-sparcv9
|
|
index bf127e9cf..458d4c34f 100644
|
|
--- a/jdk/make/mapfiles/libzip/reorder-sparcv9
|
|
+++ b/jdk/make/mapfiles/libzip/reorder-sparcv9
|
|
@@ -15,20 +15,6 @@ text: .text%ZIP_Lock;
|
|
text: .text%readLOC: OUTPUTDIR/zip_util.o;
|
|
text: .text%ZIP_Unlock;
|
|
text: .text%ZIP_FreeEntry;
|
|
-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_startsWithLOC;
|
|
-text: .text%Java_java_util_zip_ZipFile_getManifestNum;
|
|
-text: .text%Java_java_util_zip_ZipFile_getEntry;
|
|
-text: .text%Java_java_util_zip_ZipFile_freeEntry;
|
|
-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_;
|
|
@@ -36,7 +22,6 @@ text: .text%zcalloc;
|
|
text: .text%inflateReset;
|
|
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
|
text: .text%inflate;
|
|
-text: .text%Java_java_util_zip_ZipFile_read;
|
|
text: .text%ZIP_Read;
|
|
text: .text%huft_build: OUTPUTDIR/inftrees.o;
|
|
text: .text%zcfree;
|
|
@@ -45,6 +30,5 @@ text: .text%ZIP_ReadEntry;
|
|
text: .text%InflateFully;
|
|
text: .text%inflateEnd;
|
|
text: .text%Java_java_util_zip_Inflater_reset;
|
|
-text: .text%Java_java_util_zip_ZipFile_close;
|
|
text: .text%ZIP_Close;
|
|
text: .text%Java_java_util_zip_Inflater_end;
|
|
diff --git a/jdk/make/mapfiles/libzip/reorder-x86 b/jdk/make/mapfiles/libzip/reorder-x86
|
|
index d4e84c38c..62f11a990 100644
|
|
--- a/jdk/make/mapfiles/libzip/reorder-x86
|
|
+++ b/jdk/make/mapfiles/libzip/reorder-x86
|
|
@@ -16,36 +16,17 @@ text: .text%ZIP_Lock;
|
|
text: .text%readLOC: OUTPUTDIR/zip_util.o;
|
|
text: .text%ZIP_Unlock;
|
|
text: .text%ZIP_FreeEntry;
|
|
-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_startsWithLOC;
|
|
-text: .text%Java_java_util_zip_ZipFile_getManifestNum;
|
|
-text: .text%Java_java_util_zip_ZipFile_getEntry;
|
|
-text: .text%Java_java_util_zip_ZipFile_freeEntry;
|
|
-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_;
|
|
text: .text%zcalloc;
|
|
text: .text%inflateReset;
|
|
text: .text%Java_java_util_zip_Inflater_inflateBytes;
|
|
text: .text%inflate;
|
|
-text: .text%Java_java_util_zip_ZipFile_read;
|
|
text: .text%ZIP_Read;
|
|
text: .text%huft_build: OUTPUTDIR/inftrees.o;
|
|
text: .text%zcfree;
|
|
-text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
|
|
text: .text%ZIP_ReadEntry;
|
|
text: .text%InflateFully;
|
|
text: .text%inflateEnd;
|
|
text: .text%Java_java_util_zip_Inflater_reset;
|
|
-text: .text%Java_java_util_zip_ZipFile_close;
|
|
text: .text%ZIP_Close;
|
|
text: .text%Java_java_util_zip_Inflater_end;
|
|
diff --git a/jdk/src/share/classes/java/util/jar/JarFile.java b/jdk/src/share/classes/java/util/jar/JarFile.java
|
|
index a26dcc4a1..2878e175e 100644
|
|
--- a/jdk/src/share/classes/java/util/jar/JarFile.java
|
|
+++ b/jdk/src/share/classes/java/util/jar/JarFile.java
|
|
@@ -213,7 +213,10 @@ class JarFile extends ZipFile {
|
|
return man;
|
|
}
|
|
|
|
- private native String[] getMetaInfEntryNames();
|
|
+ private String[] getMetaInfEntryNames() {
|
|
+ return sun.misc.SharedSecrets.getJavaUtilZipFileAccess()
|
|
+ .getMetaInfEntryNames((ZipFile)this);
|
|
+ }
|
|
|
|
/**
|
|
* Returns the <code>JarEntry</code> for the given entry name or
|
|
diff --git a/jdk/src/share/classes/java/util/zip/ZipCoder.java b/jdk/src/share/classes/java/util/zip/ZipCoder.java
|
|
index b920b820e..243d6e8c0 100644
|
|
--- a/jdk/src/share/classes/java/util/zip/ZipCoder.java
|
|
+++ b/jdk/src/share/classes/java/util/zip/ZipCoder.java
|
|
@@ -43,7 +43,7 @@ import sun.nio.cs.ArrayEncoder;
|
|
|
|
final class ZipCoder {
|
|
|
|
- String toString(byte[] ba, int length) {
|
|
+ String toString(byte[] ba, int off, int length) {
|
|
CharsetDecoder cd = decoder().reset();
|
|
int len = (int)(length * cd.maxCharsPerByte());
|
|
char[] ca = new char[len];
|
|
@@ -53,12 +53,12 @@ final class ZipCoder {
|
|
// CodingErrorAction.REPLACE mode. ZipCoder uses
|
|
// REPORT mode.
|
|
if (isUTF8 && cd instanceof ArrayDecoder) {
|
|
- int clen = ((ArrayDecoder)cd).decode(ba, 0, length, ca);
|
|
+ int clen = ((ArrayDecoder)cd).decode(ba, off, length, ca);
|
|
if (clen == -1) // malformed
|
|
throw new IllegalArgumentException("MALFORMED");
|
|
return new String(ca, 0, clen);
|
|
}
|
|
- ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
|
|
+ ByteBuffer bb = ByteBuffer.wrap(ba, off, length);
|
|
CharBuffer cb = CharBuffer.wrap(ca);
|
|
CoderResult cr = cd.decode(bb, cb, true);
|
|
if (!cr.isUnderflow())
|
|
@@ -69,8 +69,12 @@ final class ZipCoder {
|
|
return new String(ca, 0, cb.position());
|
|
}
|
|
|
|
+ String toString(byte[] ba, int length) {
|
|
+ return toString(ba, 0, length);
|
|
+ }
|
|
+
|
|
String toString(byte[] ba) {
|
|
- return toString(ba, ba.length);
|
|
+ return toString(ba, 0, ba.length);
|
|
}
|
|
|
|
byte[] getBytes(String s) {
|
|
@@ -111,13 +115,16 @@ final class ZipCoder {
|
|
return utf8.getBytes(s);
|
|
}
|
|
|
|
-
|
|
String toStringUTF8(byte[] ba, int len) {
|
|
+ return toStringUTF8(ba, 0, len);
|
|
+ }
|
|
+
|
|
+ String toStringUTF8(byte[] ba, int off, int len) {
|
|
if (isUTF8)
|
|
- return toString(ba, len);
|
|
+ return toString(ba, off, len);
|
|
if (utf8 == null)
|
|
utf8 = new ZipCoder(StandardCharsets.UTF_8);
|
|
- return utf8.toString(ba, len);
|
|
+ return utf8.toString(ba, off, len);
|
|
}
|
|
|
|
boolean isUTF8() {
|
|
diff --git a/jdk/src/share/classes/java/util/zip/ZipFile.java b/jdk/src/share/classes/java/util/zip/ZipFile.java
|
|
index 9f8aff6ef..5d9b0de97 100644
|
|
--- a/jdk/src/share/classes/java/util/zip/ZipFile.java
|
|
+++ b/jdk/src/share/classes/java/util/zip/ZipFile.java
|
|
@@ -30,14 +30,24 @@ import java.io.InputStream;
|
|
import java.io.IOException;
|
|
import java.io.EOFException;
|
|
import java.io.File;
|
|
+import java.io.FileNotFoundException;
|
|
+import java.io.RandomAccessFile;
|
|
import java.nio.charset.Charset;
|
|
import java.nio.charset.StandardCharsets;
|
|
+import java.nio.file.attribute.BasicFileAttributes;
|
|
+import java.nio.file.Path;
|
|
+import java.nio.file.Files;
|
|
+import java.nio.file.NoSuchFileException;
|
|
+
|
|
import java.util.ArrayDeque;
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
import java.util.Deque;
|
|
import java.util.Enumeration;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.Map;
|
|
+import java.util.Objects;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Spliterator;
|
|
import java.util.Spliterators;
|
|
@@ -46,7 +56,9 @@ import java.util.jar.JarFile;
|
|
import java.util.stream.Stream;
|
|
import java.util.stream.StreamSupport;
|
|
|
|
+import static java.util.zip.ZipConstants.*;
|
|
import static java.util.zip.ZipConstants64.*;
|
|
+import static java.util.zip.ZipUtils.*;
|
|
|
|
/**
|
|
* This class is used to read entries from a zip file.
|
|
@@ -59,12 +71,11 @@ import static java.util.zip.ZipConstants64.*;
|
|
*/
|
|
public
|
|
class ZipFile implements ZipConstants, Closeable {
|
|
- private long jzfile; // address of jzfile data
|
|
+
|
|
private final String name; // zip file name
|
|
- private final int total; // total number of entries
|
|
- private final boolean locsig; // if zip file starts with LOCSIG (usually true)
|
|
private volatile boolean closeRequested = false;
|
|
- private int manifestNum = 0; // number of META-INF/MANIFEST.MF, case insensitive
|
|
+ private Source zsrc;
|
|
+ private ZipCoder zc;
|
|
|
|
private static final int STORED = ZipEntry.STORED;
|
|
private static final int DEFLATED = ZipEntry.DEFLATED;
|
|
@@ -83,26 +94,11 @@ class ZipFile implements ZipConstants, Closeable {
|
|
*/
|
|
public static final int OPEN_DELETE = 0x4;
|
|
|
|
- static {
|
|
- /* Zip library is loaded from System.initializeSystemClass */
|
|
- initIDs();
|
|
- }
|
|
-
|
|
- private static native void initIDs();
|
|
-
|
|
- private static final boolean usemmap;
|
|
-
|
|
private static final boolean ensuretrailingslash;
|
|
|
|
static {
|
|
- // A system prpperty to disable mmap use to avoid vm crash when
|
|
- // in-use zip file is accidently overwritten by others.
|
|
- String prop = sun.misc.VM.getSavedProperty("sun.zip.disableMemoryMapping");
|
|
- usemmap = (prop == null ||
|
|
- !(prop.length() == 0 || prop.equalsIgnoreCase("true")));
|
|
-
|
|
// see getEntry() for details
|
|
- prop = sun.misc.VM.getSavedProperty("jdk.util.zip.ensureTrailingSlash");
|
|
+ String prop = sun.misc.VM.getSavedProperty("jdk.util.zip.ensureTrailingSlash");
|
|
ensuretrailingslash = prop == null || !prop.equalsIgnoreCase("false");
|
|
}
|
|
|
|
@@ -171,8 +167,6 @@ class ZipFile implements ZipConstants, Closeable {
|
|
this(file, OPEN_READ);
|
|
}
|
|
|
|
- private ZipCoder zc;
|
|
-
|
|
/**
|
|
* Opens a new <code>ZipFile</code> to read from the specified
|
|
* <code>File</code> object in the specified mode. The mode argument
|
|
@@ -224,17 +218,13 @@ class ZipFile implements ZipConstants, Closeable {
|
|
sm.checkDelete(name);
|
|
}
|
|
}
|
|
- if (charset == null)
|
|
- throw new NullPointerException("charset is null");
|
|
+ Objects.requireNonNull(charset, "charset");
|
|
this.zc = ZipCoder.get(charset);
|
|
+ this.name = name;
|
|
long t0 = System.nanoTime();
|
|
- jzfile = open(name, mode, file.lastModified(), usemmap);
|
|
+ this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0);
|
|
sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
|
|
sun.misc.PerfCounter.getZipFileCount().increment();
|
|
- this.name = name;
|
|
- this.total = getTotal(jzfile);
|
|
- this.locsig = startsWithLOC(jzfile);
|
|
- this.manifestNum = getManifestNum(jzfile);
|
|
}
|
|
|
|
/**
|
|
@@ -268,6 +258,7 @@ class ZipFile implements ZipConstants, Closeable {
|
|
|
|
/**
|
|
* Opens a ZIP file for reading given the specified File object.
|
|
+ *
|
|
* @param file the ZIP file to be opened for reading
|
|
* @param charset
|
|
* The {@linkplain java.nio.charset.Charset charset} to be
|
|
@@ -298,10 +289,10 @@ class ZipFile implements ZipConstants, Closeable {
|
|
public String getComment() {
|
|
synchronized (this) {
|
|
ensureOpen();
|
|
- byte[] bcomm = getCommentBytes(jzfile);
|
|
- if (bcomm == null)
|
|
+ if (zsrc.comment == null) {
|
|
return null;
|
|
- return zc.toString(bcomm, bcomm.length);
|
|
+ }
|
|
+ return zc.toString(zsrc.comment);
|
|
}
|
|
}
|
|
|
|
@@ -314,47 +305,29 @@ class ZipFile implements ZipConstants, Closeable {
|
|
* @throws IllegalStateException if the zip file has been closed
|
|
*/
|
|
public ZipEntry getEntry(String name) {
|
|
- if (name == null) {
|
|
- throw new NullPointerException("name");
|
|
- }
|
|
- long jzentry = 0;
|
|
+
|
|
+ Objects.requireNonNull(name, "name");
|
|
synchronized (this) {
|
|
ensureOpen();
|
|
- jzentry = getEntry(jzfile, zc.getBytes(name), true);
|
|
- if (jzentry != 0) {
|
|
- // If no entry is found for the specified 'name' and
|
|
- // the 'name' does not end with a forward slash '/',
|
|
- // the implementation tries to find the entry with a
|
|
- // slash '/' appended to the end of the 'name', before
|
|
- // returning null. When such entry is found, the name
|
|
- // that actually is found (with a slash '/' attached)
|
|
- // is used
|
|
- // (disabled if jdk.util.zip.ensureTrailingSlash=false)
|
|
- ZipEntry ze = ensuretrailingslash ? getZipEntry(null, jzentry)
|
|
- : getZipEntry(name, jzentry);
|
|
- freeEntry(jzfile, jzentry);
|
|
- return ze;
|
|
+ int pos = zsrc.getEntryPos(zc.getBytes(name), true);
|
|
+ if (pos != -1) {
|
|
+ return ensuretrailingslash ? getZipEntry(null, pos)
|
|
+ : getZipEntry(name, pos);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
- private static native long getEntry(long jzfile, byte[] name,
|
|
- boolean addSlash);
|
|
-
|
|
- // freeEntry releases the C jzentry struct.
|
|
- private static native void freeEntry(long jzfile, long jzentry);
|
|
-
|
|
- // the outstanding inputstreams that need to be closed,
|
|
+ // The outstanding inputstreams that need to be closed,
|
|
// mapped to the inflater objects they use.
|
|
private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
|
|
|
|
/**
|
|
* Returns an input stream for reading the contents of the specified
|
|
* zip file entry.
|
|
- *
|
|
- * <p> Closing this ZIP file will, in turn, close all input
|
|
- * streams that have been returned by invocations of this method.
|
|
+ * <p>
|
|
+ * Closing this ZIP file will, in turn, close all input streams that
|
|
+ * have been returned by invocations of this method.
|
|
*
|
|
* @param entry the zip file entry
|
|
* @return the input stream for reading the contents of the specified
|
|
@@ -364,37 +337,38 @@ class ZipFile implements ZipConstants, Closeable {
|
|
* @throws IllegalStateException if the zip file has been closed
|
|
*/
|
|
public InputStream getInputStream(ZipEntry entry) throws IOException {
|
|
- if (entry == null) {
|
|
- throw new NullPointerException("entry");
|
|
- }
|
|
- long jzentry = 0;
|
|
+ Objects.requireNonNull(entry, "entry");
|
|
+ int pos = -1;
|
|
ZipFileInputStream in = null;
|
|
synchronized (this) {
|
|
ensureOpen();
|
|
if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
|
|
- jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
|
|
+ pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
|
|
} else {
|
|
- jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
|
|
+ pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
|
|
}
|
|
- if (jzentry == 0) {
|
|
+ if (pos == -1) {
|
|
return null;
|
|
}
|
|
- in = new ZipFileInputStream(jzentry);
|
|
-
|
|
- switch (getEntryMethod(jzentry)) {
|
|
+ in = new ZipFileInputStream(zsrc.cen, pos);
|
|
+ switch (CENHOW(zsrc.cen, pos)) {
|
|
case STORED:
|
|
synchronized (streams) {
|
|
streams.put(in, null);
|
|
}
|
|
return in;
|
|
case DEFLATED:
|
|
+ // Inflater likes a bit of slack
|
|
// MORE: Compute good size for inflater stream:
|
|
- long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
|
|
- if (size > 65536) size = 8192;
|
|
- if (size <= 0) size = 4096;
|
|
+ long size = CENLEN(zsrc.cen, pos) + 2;
|
|
+ if (size > 65536) {
|
|
+ size = 8192;
|
|
+ }
|
|
+ if (size <= 0) {
|
|
+ size = 4096;
|
|
+ }
|
|
Inflater inf = getInflater();
|
|
- InputStream is =
|
|
- new ZipFileInflaterInputStream(in, inf, (int)size);
|
|
+ InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size);
|
|
synchronized (streams) {
|
|
streams.put(is, inf);
|
|
}
|
|
@@ -467,8 +441,8 @@ class ZipFile implements ZipConstants, Closeable {
|
|
private Inflater getInflater() {
|
|
Inflater inf;
|
|
synchronized (inflaterCache) {
|
|
- while (null != (inf = inflaterCache.poll())) {
|
|
- if (false == inf.ended()) {
|
|
+ while ((inf = inflaterCache.poll()) != null) {
|
|
+ if (!inf.ended()) {
|
|
return inf;
|
|
}
|
|
}
|
|
@@ -480,7 +454,7 @@ class ZipFile implements ZipConstants, Closeable {
|
|
* Releases the specified inflater to the list of available inflaters.
|
|
*/
|
|
private void releaseInflater(Inflater inf) {
|
|
- if (false == inf.ended()) {
|
|
+ if (!inf.ended()) {
|
|
inf.reset();
|
|
synchronized (inflaterCache) {
|
|
inflaterCache.add(inf);
|
|
@@ -489,7 +463,7 @@ class ZipFile implements ZipConstants, Closeable {
|
|
}
|
|
|
|
// List of available Inflater objects for decompression
|
|
- private Deque<Inflater> inflaterCache = new ArrayDeque<>();
|
|
+ private final Deque<Inflater> inflaterCache = new ArrayDeque<>();
|
|
|
|
/**
|
|
* Returns the path name of the ZIP file.
|
|
@@ -501,9 +475,13 @@ class ZipFile implements ZipConstants, Closeable {
|
|
|
|
private class ZipEntryIterator implements Enumeration<ZipEntry>, Iterator<ZipEntry> {
|
|
private int i = 0;
|
|
+ private final int entryCount;
|
|
|
|
public ZipEntryIterator() {
|
|
- ensureOpen();
|
|
+ synchronized (ZipFile.this) {
|
|
+ ensureOpen();
|
|
+ this.entryCount = zsrc.total;
|
|
+ }
|
|
}
|
|
|
|
public boolean hasMoreElements() {
|
|
@@ -511,10 +489,7 @@ class ZipFile implements ZipConstants, Closeable {
|
|
}
|
|
|
|
public boolean hasNext() {
|
|
- synchronized (ZipFile.this) {
|
|
- ensureOpen();
|
|
- return i < total;
|
|
- }
|
|
+ return i < entryCount;
|
|
}
|
|
|
|
public ZipEntry nextElement() {
|
|
@@ -524,28 +499,11 @@ class ZipFile implements ZipConstants, Closeable {
|
|
public ZipEntry next() {
|
|
synchronized (ZipFile.this) {
|
|
ensureOpen();
|
|
- if (i >= total) {
|
|
+ if (!hasNext()) {
|
|
throw new NoSuchElementException();
|
|
}
|
|
- long jzentry = getNextEntry(jzfile, i++);
|
|
- if (jzentry == 0) {
|
|
- String message;
|
|
- if (closeRequested) {
|
|
- message = "ZipFile concurrently closed";
|
|
- } else {
|
|
- message = getZipMessage(ZipFile.this.jzfile);
|
|
- }
|
|
- throw new ZipError("jzentry == 0" +
|
|
- ",\n jzfile = " + ZipFile.this.jzfile +
|
|
- ",\n total = " + ZipFile.this.total +
|
|
- ",\n name = " + ZipFile.this.name +
|
|
- ",\n i = " + i +
|
|
- ",\n message = " + message
|
|
- );
|
|
- }
|
|
- ZipEntry ze = getZipEntry(null, jzentry);
|
|
- freeEntry(jzfile, jzentry);
|
|
- return ze;
|
|
+ // each "entry" has 3 ints in table entries
|
|
+ return getZipEntry(null, zsrc.getEntryPos(i++ * 3));
|
|
}
|
|
}
|
|
}
|
|
@@ -575,50 +533,53 @@ class ZipFile implements ZipConstants, Closeable {
|
|
Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
|
|
}
|
|
|
|
- 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 (bname == null) {
|
|
- e.name = ""; // length 0 empty name
|
|
- } else if (!zc.isUTF8() && (e.flag & EFS) != 0) {
|
|
- e.name = zc.toStringUTF8(bname, bname.length);
|
|
+ /* Checks ensureOpen() before invoke this method */
|
|
+ private ZipEntry getZipEntry(String name, int pos) {
|
|
+ byte[] cen = zsrc.cen;
|
|
+ int nlen = CENNAM(cen, pos);
|
|
+ int elen = CENEXT(cen, pos);
|
|
+ int clen = CENCOM(cen, pos);
|
|
+ int flag = CENFLG(cen, pos);
|
|
+ if (name == null) {
|
|
+ if (!zc.isUTF8() && (flag & EFS) != 0) {
|
|
+ name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
|
|
} else {
|
|
- e.name = zc.toString(bname, bname.length);
|
|
- }
|
|
- }
|
|
- e.xdostime = getEntryTime(jzentry);
|
|
- e.crc = getEntryCrc(jzentry);
|
|
- e.size = getEntrySize(jzentry);
|
|
- e.csize = getEntryCSize(jzentry);
|
|
- e.method = getEntryMethod(jzentry);
|
|
- e.setExtra0(getEntryBytes(jzentry, JZENTRY_EXTRA), false);
|
|
- 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);
|
|
+ name = zc.toString(cen, pos + CENHDR, nlen);
|
|
+ }
|
|
+ }
|
|
+ ZipEntry e = new ZipEntry(name);
|
|
+ e.flag = flag;
|
|
+ e.xdostime = CENTIM(cen, pos);
|
|
+ e.crc = CENCRC(cen, pos);
|
|
+ e.size = CENLEN(cen, pos);
|
|
+ e.csize = CENSIZ(cen, pos);
|
|
+ e.method = CENHOW(cen, pos);
|
|
+ if (elen != 0) {
|
|
+ int start = pos + CENHDR + nlen;
|
|
+ e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true);
|
|
+ }
|
|
+ if (clen != 0) {
|
|
+ int start = pos + CENHDR + nlen + elen;
|
|
+ if (!zc.isUTF8() && (flag & EFS) != 0) {
|
|
+ e.comment = zc.toStringUTF8(cen, start, clen);
|
|
} else {
|
|
- e.comment = zc.toString(bcomm, bcomm.length);
|
|
+ e.comment = zc.toString(cen, start, clen);
|
|
}
|
|
}
|
|
return e;
|
|
}
|
|
|
|
- private static native long getNextEntry(long jzfile, int i);
|
|
-
|
|
/**
|
|
* Returns the number of entries in the ZIP file.
|
|
+ *
|
|
* @return the number of entries in the ZIP file
|
|
* @throws IllegalStateException if the zip file has been closed
|
|
*/
|
|
public int size() {
|
|
- ensureOpen();
|
|
- return total;
|
|
+ synchronized (this) {
|
|
+ ensureOpen();
|
|
+ return zsrc.total;
|
|
+ }
|
|
}
|
|
|
|
/**
|
|
@@ -630,14 +591,15 @@ class ZipFile implements ZipConstants, Closeable {
|
|
* @throws IOException if an I/O error has occurred
|
|
*/
|
|
public void close() throws IOException {
|
|
- if (closeRequested)
|
|
+ if (closeRequested) {
|
|
return;
|
|
+ }
|
|
closeRequested = true;
|
|
|
|
synchronized (this) {
|
|
// Close streams, release their inflaters
|
|
synchronized (streams) {
|
|
- if (false == streams.isEmpty()) {
|
|
+ if (!streams.isEmpty()) {
|
|
Map<InputStream, Inflater> copy = new HashMap<>(streams);
|
|
streams.clear();
|
|
for (Map.Entry<InputStream, Inflater> e : copy.entrySet()) {
|
|
@@ -649,21 +611,17 @@ class ZipFile implements ZipConstants, Closeable {
|
|
}
|
|
}
|
|
}
|
|
-
|
|
// Release cached inflaters
|
|
- Inflater inf;
|
|
synchronized (inflaterCache) {
|
|
- while (null != (inf = inflaterCache.poll())) {
|
|
+ Inflater inf;
|
|
+ while ((inf = inflaterCache.poll()) != null) {
|
|
inf.end();
|
|
}
|
|
}
|
|
-
|
|
- if (jzfile != 0) {
|
|
- // Close the zip file
|
|
- long zf = this.jzfile;
|
|
- jzfile = 0;
|
|
-
|
|
- close(zf);
|
|
+ // Release zip src
|
|
+ if (zsrc != null) {
|
|
+ Source.close(zsrc);
|
|
+ zsrc = null;
|
|
}
|
|
}
|
|
}
|
|
@@ -686,14 +644,11 @@ class ZipFile implements ZipConstants, Closeable {
|
|
close();
|
|
}
|
|
|
|
- private static native void close(long jzfile);
|
|
-
|
|
private void ensureOpen() {
|
|
if (closeRequested) {
|
|
throw new IllegalStateException("zip file closed");
|
|
}
|
|
-
|
|
- if (jzfile == 0) {
|
|
+ if (zsrc == null) {
|
|
throw new IllegalStateException("The object is not initialized.");
|
|
}
|
|
}
|
|
@@ -709,40 +664,99 @@ class ZipFile implements ZipConstants, Closeable {
|
|
* (possibly compressed) zip file entry.
|
|
*/
|
|
private class ZipFileInputStream extends InputStream {
|
|
- private volatile boolean zfisCloseRequested = false;
|
|
- protected long jzentry; // address of jzentry data
|
|
+ private volatile boolean closeRequested = false;
|
|
private long pos; // current position within entry data
|
|
protected long rem; // number of remaining bytes within entry
|
|
protected long size; // uncompressed size of this entry
|
|
|
|
- ZipFileInputStream(long jzentry) {
|
|
- pos = 0;
|
|
- rem = getEntryCSize(jzentry);
|
|
- size = getEntrySize(jzentry);
|
|
- this.jzentry = jzentry;
|
|
+ ZipFileInputStream(byte[] cen, int cenpos) throws IOException {
|
|
+ rem = CENSIZ(cen, cenpos);
|
|
+ size = CENLEN(cen, cenpos);
|
|
+ pos = CENOFF(cen, cenpos);
|
|
+ // zip64
|
|
+ if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL ||
|
|
+ pos == ZIP64_MAGICVAL) {
|
|
+ checkZIP64(cen, cenpos);
|
|
+ }
|
|
+ // negative for lazy initialization, see getDataOffset();
|
|
+ pos = - (pos + ZipFile.this.zsrc.locpos);
|
|
+ }
|
|
+
|
|
+ private void checkZIP64(byte[] cen, int cenpos) throws IOException {
|
|
+ int off = cenpos + CENHDR + CENNAM(cen, cenpos);
|
|
+ int end = off + CENEXT(cen, cenpos);
|
|
+ while (off + 4 < end) {
|
|
+ int tag = get16(cen, off);
|
|
+ int sz = get16(cen, off + 2);
|
|
+ off += 4;
|
|
+ if (off + sz > end) // invalid data
|
|
+ break;
|
|
+ if (tag == EXTID_ZIP64) {
|
|
+ if (size == ZIP64_MAGICVAL) {
|
|
+ if (sz < 8 || (off + 8) > end)
|
|
+ break;
|
|
+ size = get64(cen, off);
|
|
+ sz -= 8;
|
|
+ off += 8;
|
|
+ }
|
|
+ if (rem == ZIP64_MAGICVAL) {
|
|
+ if (sz < 8 || (off + 8) > end)
|
|
+ break;
|
|
+ rem = get64(cen, off);
|
|
+ sz -= 8;
|
|
+ off += 8;
|
|
+ }
|
|
+ if (pos == ZIP64_MAGICVAL) {
|
|
+ if (sz < 8 || (off + 8) > end)
|
|
+ break;
|
|
+ pos = get64(cen, off);
|
|
+ sz -= 8;
|
|
+ off += 8;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ off += sz;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* The Zip file spec explicitly allows the LOC extra data size to
|
|
+ * be different from the CEN extra data size. Since we cannot trust
|
|
+ * the CEN extra data size, we need to read the LOC to determine
|
|
+ * the entry data offset.
|
|
+ */
|
|
+ private long initDataOffset() throws IOException {
|
|
+ if (pos <= 0) {
|
|
+ byte[] loc = new byte[LOCHDR];
|
|
+ pos = -pos;
|
|
+ int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos);
|
|
+ if (len != LOCHDR) {
|
|
+ throw new ZipException("ZipFile error reading zip file");
|
|
+ }
|
|
+ if (LOCSIG(loc) != LOCSIG) {
|
|
+ throw new ZipException("ZipFile invalid LOC header (bad signature)");
|
|
+ }
|
|
+ pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
|
|
+ }
|
|
+ return pos;
|
|
}
|
|
|
|
public int read(byte b[], int off, int len) throws IOException {
|
|
synchronized (ZipFile.this) {
|
|
- long rem = this.rem;
|
|
- long pos = this.pos;
|
|
+ ensureOpenOrZipException();
|
|
+ initDataOffset();
|
|
if (rem == 0) {
|
|
return -1;
|
|
}
|
|
- if (len <= 0) {
|
|
- return 0;
|
|
- }
|
|
if (len > rem) {
|
|
len = (int) rem;
|
|
}
|
|
-
|
|
- // Check if ZipFile open
|
|
- ensureOpenOrZipException();
|
|
- len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
|
|
- off, len);
|
|
+ if (len <= 0) {
|
|
+ return 0;
|
|
+ }
|
|
+ len = ZipFile.this.zsrc.readAt(b, off, len, pos);
|
|
if (len > 0) {
|
|
- this.pos = (pos + len);
|
|
- this.rem = (rem - len);
|
|
+ pos += len;
|
|
+ rem -= len;
|
|
}
|
|
}
|
|
if (rem == 0) {
|
|
@@ -760,11 +774,16 @@ class ZipFile implements ZipConstants, Closeable {
|
|
}
|
|
}
|
|
|
|
- public long skip(long n) {
|
|
- if (n > rem)
|
|
- n = rem;
|
|
- pos += n;
|
|
- rem -= n;
|
|
+ public long skip(long n) throws IOException {
|
|
+ synchronized (ZipFile.this) {
|
|
+ ensureOpenOrZipException();
|
|
+ initDataOffset();
|
|
+ if (n > rem) {
|
|
+ n = rem;
|
|
+ }
|
|
+ pos += n;
|
|
+ rem -= n;
|
|
+ }
|
|
if (rem == 0) {
|
|
close();
|
|
}
|
|
@@ -780,17 +799,11 @@ class ZipFile implements ZipConstants, Closeable {
|
|
}
|
|
|
|
public void close() {
|
|
- if (zfisCloseRequested)
|
|
+ if (closeRequested) {
|
|
return;
|
|
- zfisCloseRequested = true;
|
|
-
|
|
- rem = 0;
|
|
- synchronized (ZipFile.this) {
|
|
- if (jzentry != 0 && ZipFile.this.jzfile != 0) {
|
|
- freeEntry(ZipFile.this.jzfile, jzentry);
|
|
- jzentry = 0;
|
|
- }
|
|
}
|
|
+ closeRequested = true;
|
|
+ rem = 0;
|
|
synchronized (streams) {
|
|
streams.remove(this);
|
|
}
|
|
@@ -805,7 +818,10 @@ class ZipFile implements ZipConstants, Closeable {
|
|
sun.misc.SharedSecrets.setJavaUtilZipFileAccess(
|
|
new sun.misc.JavaUtilZipFileAccess() {
|
|
public boolean startsWithLocHeader(ZipFile zip) {
|
|
- return zip.startsWithLocHeader();
|
|
+ return zip.zsrc.startsWithLoc;
|
|
+ }
|
|
+ public String[] getMetaInfEntryNames(ZipFile zip) {
|
|
+ return zip.getMetaInfEntryNames();
|
|
}
|
|
public int getManifestNum(JarFile jar) {
|
|
return ((ZipFile)jar).getManifestNum();
|
|
@@ -815,11 +831,27 @@ class ZipFile implements ZipConstants, Closeable {
|
|
}
|
|
|
|
/**
|
|
- * Returns {@code true} if, and only if, the zip file begins with {@code
|
|
- * LOCSIG}.
|
|
+ * Returns an array of strings representing the names of all entries
|
|
+ * that begin with "META-INF/" (case ignored). This method is used
|
|
+ * in JarFile, via SharedSecrets, as an optimization when looking up
|
|
+ * manifest and signature file entries. Returns null if no entries
|
|
+ * were found.
|
|
*/
|
|
- private boolean startsWithLocHeader() {
|
|
- return locsig;
|
|
+ private String[] getMetaInfEntryNames() {
|
|
+ synchronized (this) {
|
|
+ ensureOpen();
|
|
+ if (zsrc.metanames == null) {
|
|
+ return null;
|
|
+ }
|
|
+ String[] names = new String[zsrc.metanames.length];
|
|
+ byte[] cen = zsrc.cen;
|
|
+ for (int i = 0; i < names.length; i++) {
|
|
+ int pos = zsrc.metanames[i];
|
|
+ names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos),
|
|
+ StandardCharsets.UTF_8);
|
|
+ }
|
|
+ return names;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -830,31 +862,506 @@ class ZipFile implements ZipConstants, Closeable {
|
|
private int getManifestNum() {
|
|
synchronized (this) {
|
|
ensureOpen();
|
|
- return manifestNum;
|
|
+ return zsrc.manifestNum;
|
|
}
|
|
}
|
|
+
|
|
+ private static class Source {
|
|
+ // "META-INF/".length()
|
|
+ private static final int META_INF_LEN = 9;
|
|
+ private final Key key; // the key in files
|
|
+ private int refs = 1;
|
|
+
|
|
+ private RandomAccessFile zfile; // zfile of the underlying zip file
|
|
+ private byte[] cen; // CEN & ENDHDR
|
|
+ private long locpos; // position of first LOC header (usually 0)
|
|
+ private byte[] comment; // zip file comment
|
|
+ // list of meta entries in META-INF dir
|
|
+ private int[] metanames;
|
|
+ private int manifestNum = 0; // number of META-INF/MANIFEST.MF, case insensitive
|
|
+ private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
|
|
+
|
|
+ // A Hashmap for all entries.
|
|
+ //
|
|
+ // A cen entry of Zip/JAR file. As we have one for every entry in every active Zip/JAR,
|
|
+ // We might have a lot of these in a typical system. In order to save space we don't
|
|
+ // keep the name in memory, but merely remember a 32 bit {@code hash} value of the
|
|
+ // entry name and its offset {@code pos} in the central directory hdeader.
|
|
+ //
|
|
+ // private static class Entry {
|
|
+ // int hash; // 32 bit hashcode on name
|
|
+ // int next; // hash chain: index into entries
|
|
+ // int pos; // Offset of central directory file header
|
|
+ // }
|
|
+ // private Entry[] entries; // array of hashed cen entry
|
|
+ //
|
|
+ // To reduce the total size of entries further, we use a int[] here to store 3 "int"
|
|
+ // {@code hash}, {@code next and {@code "pos for each entry. The entry can then be
|
|
+ // referred by their index of their positions in the {@code entries}.
|
|
+ //
|
|
+ private int[] entries; // array of hashed cen entry
|
|
+ private int addEntry(int index, int hash, int next, int pos) {
|
|
+ entries[index++] = hash;
|
|
+ entries[index++] = next;
|
|
+ entries[index++] = pos;
|
|
+ return index;
|
|
+ }
|
|
+ private int getEntryHash(int index) { return entries[index]; }
|
|
+ private int getEntryNext(int index) { return entries[index + 1]; }
|
|
+ private int getEntryPos(int index) { return entries[index + 2]; }
|
|
+ private static final int ZIP_ENDCHAIN = -1;
|
|
+ private int total; // total number of entries
|
|
+ private int[] table; // Hash chain heads: indexes into entries
|
|
+ private int tablelen; // number of hash heads
|
|
+
|
|
+ private static class Key {
|
|
+ BasicFileAttributes attrs;
|
|
+ File file;
|
|
+
|
|
+ public Key(File file, BasicFileAttributes attrs) {
|
|
+ this.attrs = attrs;
|
|
+ this.file = file;
|
|
+ }
|
|
+
|
|
+ public int hashCode() {
|
|
+ long t = attrs.lastModifiedTime().toMillis();
|
|
+ return ((int)(t ^ (t >>> 32))) + file.hashCode();
|
|
+ }
|
|
+
|
|
+ public boolean equals(Object obj) {
|
|
+ if (obj instanceof Key) {
|
|
+ Key key = (Key)obj;
|
|
+ if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) {
|
|
+ return false;
|
|
+ }
|
|
+ Object fk = attrs.fileKey();
|
|
+ if (fk != null) {
|
|
+ return fk.equals(key.attrs.fileKey());
|
|
+ } else {
|
|
+ return file.equals(key.file);
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ private static final HashMap<Key, Source> files = new HashMap<>();
|
|
+
|
|
+
|
|
+ public static Source get(File file, boolean toDelete) throws IOException {
|
|
+ Key key = null;
|
|
+ try {
|
|
+ key = new Key(file,
|
|
+ Files.readAttributes(file.toPath(), BasicFileAttributes.class));
|
|
+ } catch (NoSuchFileException exception) {
|
|
+ throw new FileNotFoundException(exception.getMessage());
|
|
+ }
|
|
+ Source src = null;
|
|
+ synchronized (files) {
|
|
+ src = files.get(key);
|
|
+ if (src != null) {
|
|
+ src.refs++;
|
|
+ return src;
|
|
+ }
|
|
+ }
|
|
+ src = new Source(key, toDelete);
|
|
+
|
|
+ synchronized (files) {
|
|
+ if (files.containsKey(key)) { // someone else put in first
|
|
+ src.close(); // close the newly created one
|
|
+ src = files.get(key);
|
|
+ src.refs++;
|
|
+ return src;
|
|
+ }
|
|
+ files.put(key, src);
|
|
+ return src;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void close(Source src) throws IOException {
|
|
+ synchronized (files) {
|
|
+ if (--src.refs == 0) {
|
|
+ files.remove(src.key);
|
|
+ src.close();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private Source(Key key, boolean toDelete) throws IOException {
|
|
+ this.key = key;
|
|
+ this.zfile = new RandomAccessFile(key.file, "r");
|
|
+ if (toDelete) {
|
|
+ key.file.delete();
|
|
+ }
|
|
+ try {
|
|
+ initCEN(-1);
|
|
+ byte[] buf = new byte[4];
|
|
+ readFullyAt(buf, 0, 4, 0);
|
|
+ this.startsWithLoc = (LOCSIG(buf) == LOCSIG);
|
|
+ } catch (IOException x) {
|
|
+ try {
|
|
+ this.zfile.close();
|
|
+ } catch (IOException xx) {}
|
|
+ throw x;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void close() throws IOException {
|
|
+ zfile.close();
|
|
+ zfile = null;
|
|
+ cen = null;
|
|
+ entries = null;
|
|
+ table = null;
|
|
+ manifestNum = 0;
|
|
+ metanames = null;
|
|
+ }
|
|
+
|
|
+ private static final int BUF_SIZE = 8192;
|
|
+ private final int readFullyAt(byte[] buf, int off, int len, long pos)
|
|
+ throws IOException
|
|
+ {
|
|
+ synchronized(zfile) {
|
|
+ zfile.seek(pos);
|
|
+ int N = len;
|
|
+ while (N > 0) {
|
|
+ int n = Math.min(BUF_SIZE, N);
|
|
+ zfile.readFully(buf, off, n);
|
|
+ off += n;
|
|
+ N -= n;
|
|
+ }
|
|
+ return len;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private final int readAt(byte[] buf, int off, int len, long pos)
|
|
+ throws IOException
|
|
+ {
|
|
+ synchronized(zfile) {
|
|
+ zfile.seek(pos);
|
|
+ return zfile.read(buf, off, len);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static final int hashN(byte[] a, int off, int len) {
|
|
+ int h = 1;
|
|
+ while (len-- > 0) {
|
|
+ h = 31 * h + a[off++];
|
|
+ }
|
|
+ return h;
|
|
+ }
|
|
+
|
|
+ private static final int hash_append(int hash, byte b) {
|
|
+ return hash * 31 + b;
|
|
+ }
|
|
|
|
- private static native long open(String name, int mode, long lastModified,
|
|
- boolean usemmap) throws IOException;
|
|
- private static native int getTotal(long jzfile);
|
|
- private static native boolean startsWithLOC(long jzfile);
|
|
- private static native int getManifestNum(long jzfile);
|
|
- private static native int read(long jzfile, long jzentry,
|
|
- long pos, byte[] b, int off, int len);
|
|
-
|
|
- // 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 byte[] getCommentBytes(long jzfile);
|
|
-
|
|
- 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);
|
|
-
|
|
- private static native String getZipMessage(long jzfile);
|
|
+ private static class End {
|
|
+ int centot; // 4 bytes
|
|
+ long cenlen; // 4 bytes
|
|
+ long cenoff; // 4 bytes
|
|
+ long endpos; // 4 bytes
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Searches for end of central directory (END) header. The contents of
|
|
+ * the END header will be read and placed in endbuf. Returns the file
|
|
+ * position of the END header, otherwise returns -1 if the END header
|
|
+ * was not found or an error occurred.
|
|
+ */
|
|
+ private End findEND() throws IOException {
|
|
+ long ziplen = zfile.length();
|
|
+ if (ziplen <= 0)
|
|
+ zerror("zip file is empty");
|
|
+ End end = new End();
|
|
+ byte[] buf = new byte[READBLOCKSZ];
|
|
+ long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0;
|
|
+ long minPos = minHDR - (buf.length - ENDHDR);
|
|
+ for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) {
|
|
+ int off = 0;
|
|
+ if (pos < 0) {
|
|
+ // Pretend there are some NUL bytes before start of file
|
|
+ off = (int)-pos;
|
|
+ Arrays.fill(buf, 0, off, (byte)0);
|
|
+ }
|
|
+ int len = buf.length - off;
|
|
+ if (readFullyAt(buf, off, len, pos + off) != len ) {
|
|
+ zerror("zip END header not found");
|
|
+ }
|
|
+ // Now scan the block backwards for END header signature
|
|
+ for (int i = buf.length - ENDHDR; i >= 0; i--) {
|
|
+ if (buf[i+0] == (byte)'P' &&
|
|
+ buf[i+1] == (byte)'K' &&
|
|
+ buf[i+2] == (byte)'\005' &&
|
|
+ buf[i+3] == (byte)'\006') {
|
|
+ // Found ENDSIG header
|
|
+ byte[] endbuf = Arrays.copyOfRange(buf, i, i + ENDHDR);
|
|
+ end.centot = ENDTOT(endbuf);
|
|
+ end.cenlen = ENDSIZ(endbuf);
|
|
+ end.cenoff = ENDOFF(endbuf);
|
|
+ end.endpos = pos + i;
|
|
+ int comlen = ENDCOM(endbuf);
|
|
+ if (end.endpos + ENDHDR + comlen != ziplen) {
|
|
+ // ENDSIG matched, however the size of file comment in it does
|
|
+ // not match the real size. One "common" cause for this problem
|
|
+ // is some "extra" bytes are padded at the end of the zipfile.
|
|
+ // Let's do some extra verification, we don't care about the
|
|
+ // performance in this situation.
|
|
+ byte[] sbuf = new byte[4];
|
|
+ long cenpos = end.endpos - end.cenlen;
|
|
+ long locpos = cenpos - end.cenoff;
|
|
+ if (cenpos < 0 ||
|
|
+ locpos < 0 ||
|
|
+ readFullyAt(sbuf, 0, sbuf.length, cenpos) != 4 ||
|
|
+ GETSIG(sbuf) != CENSIG ||
|
|
+ readFullyAt(sbuf, 0, sbuf.length, locpos) != 4 ||
|
|
+ GETSIG(sbuf) != LOCSIG) {
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ if (comlen > 0) { // this zip file has comlen
|
|
+ comment = new byte[comlen];
|
|
+ if (readFullyAt(comment, 0, comlen, end.endpos + ENDHDR) != comlen) {
|
|
+ zerror("zip comment read failed");
|
|
+ }
|
|
+ }
|
|
+ if (end.cenlen == ZIP64_MAGICVAL ||
|
|
+ end.cenoff == ZIP64_MAGICVAL ||
|
|
+ end.centot == ZIP64_MAGICCOUNT)
|
|
+ {
|
|
+ // need to find the zip64 end;
|
|
+ try {
|
|
+ byte[] loc64 = new byte[ZIP64_LOCHDR];
|
|
+ if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
|
|
+ != loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) {
|
|
+ return end;
|
|
+ }
|
|
+ long end64pos = ZIP64_LOCOFF(loc64);
|
|
+ byte[] end64buf = new byte[ZIP64_ENDHDR];
|
|
+ if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
|
|
+ != end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) {
|
|
+ return end;
|
|
+ }
|
|
+ // end64 found, re-calcualte everything.
|
|
+ end.cenlen = ZIP64_ENDSIZ(end64buf);
|
|
+ end.cenoff = ZIP64_ENDOFF(end64buf);
|
|
+ end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g
|
|
+ end.endpos = end64pos;
|
|
+ } catch (IOException x) {} // no zip64 loc/end
|
|
+ }
|
|
+ return end;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ zerror("zip END header not found");
|
|
+ return null; //make compiler happy
|
|
+ }
|
|
+
|
|
+ // Reads zip file central directory.
|
|
+ private void initCEN(int knownTotal) throws IOException {
|
|
+ if (knownTotal == -1) {
|
|
+ End end = findEND();
|
|
+ if (end.endpos == 0) {
|
|
+ locpos = 0;
|
|
+ total = 0;
|
|
+ entries = new int[0];
|
|
+ cen = null;
|
|
+ return; // only END header present
|
|
+ }
|
|
+ if (end.cenlen > end.endpos)
|
|
+ zerror("invalid END header (bad central directory size)");
|
|
+ long cenpos = end.endpos - end.cenlen; // position of CEN table
|
|
+ // Get position of first local file (LOC) header, taking into
|
|
+ // account that there may be a stub prefixed to the zip file.
|
|
+ locpos = cenpos - end.cenoff;
|
|
+ if (locpos < 0) {
|
|
+ zerror("invalid END header (bad central directory offset)");
|
|
+ }
|
|
+ // read in the CEN and END
|
|
+ cen = new byte[(int)(end.cenlen + ENDHDR)];
|
|
+ if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) {
|
|
+ zerror("read CEN tables failed");
|
|
+ }
|
|
+ total = end.centot;
|
|
+ } else {
|
|
+ total = knownTotal;
|
|
+ }
|
|
+ // hash table for entries
|
|
+ entries = new int[total * 3];
|
|
+ tablelen = ((total/2) | 1); // Odd -> fewer collisions
|
|
+ table = new int[tablelen];
|
|
+ Arrays.fill(table, ZIP_ENDCHAIN);
|
|
+ int idx = 0;
|
|
+ int hash = 0;
|
|
+ int next = -1;
|
|
+
|
|
+ // list for all meta entries
|
|
+ ArrayList<Integer> metanamesList = null;
|
|
+
|
|
+ // Iterate through the entries in the central directory
|
|
+ int i = 0;
|
|
+ int hsh = 0;
|
|
+ int pos = 0;
|
|
+ int limit = cen.length - ENDHDR;
|
|
+ manifestNum = 0;
|
|
+ while (pos + CENHDR <= limit) {
|
|
+ if (i >= total) {
|
|
+ // This will only happen if the zip file has an incorrect
|
|
+ // ENDTOT field, which usually means it contains more than
|
|
+ // 65535 entries.
|
|
+ initCEN(countCENHeaders(cen, limit));
|
|
+ return;
|
|
+ }
|
|
+ if (CENSIG(cen, pos) != CENSIG)
|
|
+ zerror("invalid CEN header (bad signature)");
|
|
+ int method = CENHOW(cen, pos);
|
|
+ int nlen = CENNAM(cen, pos);
|
|
+ int elen = CENEXT(cen, pos);
|
|
+ int clen = CENCOM(cen, pos);
|
|
+ if ((CENFLG(cen, pos) & 1) != 0)
|
|
+ zerror("invalid CEN header (encrypted entry)");
|
|
+ if (method != STORED && method != DEFLATED)
|
|
+ zerror("invalid CEN header (bad compression method: " + method + ")");
|
|
+ if (pos + CENHDR + nlen > limit)
|
|
+ zerror("invalid CEN header (bad header size)");
|
|
+ // Record the CEN offset and the name hash in our hash cell.
|
|
+ hash = hashN(cen, pos + CENHDR, nlen);
|
|
+ hsh = (hash & 0x7fffffff) % tablelen;
|
|
+ next = table[hsh];
|
|
+ table[hsh] = idx;
|
|
+ idx = addEntry(idx, hash, next, pos);
|
|
+ // Adds name to metanames.
|
|
+ if (isMetaName(cen, pos + CENHDR, nlen)) {
|
|
+ if (metanamesList == null)
|
|
+ metanamesList = new ArrayList<>(4);
|
|
+ metanamesList.add(pos);
|
|
+ if (isManifestName(cen, pos + CENHDR +
|
|
+ META_INF_LEN, nlen - META_INF_LEN)) {
|
|
+ manifestNum++;
|
|
+ }
|
|
+ }
|
|
+ // skip ext and comment
|
|
+ pos += (CENHDR + nlen + elen + clen);
|
|
+ i++;
|
|
+ }
|
|
+ total = i;
|
|
+ if (metanamesList != null) {
|
|
+ metanames = new int[metanamesList.size()];
|
|
+ for (int j = 0, len = metanames.length; j < len; j++) {
|
|
+ metanames[j] = metanamesList.get(j);
|
|
+ }
|
|
+ }
|
|
+ if (pos + ENDHDR != cen.length) {
|
|
+ zerror("invalid CEN header (bad header size)");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void zerror(String msg) throws ZipException {
|
|
+ throw new ZipException(msg);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Returns the {@code pos} of the zip cen entry corresponding to the
|
|
+ * specified entry name, or -1 if not found.
|
|
+ */
|
|
+ private int getEntryPos(byte[] name, boolean addSlash) {
|
|
+ if (total == 0) {
|
|
+ return -1;
|
|
+ }
|
|
+ int hsh = hashN(name, 0, name.length);
|
|
+ int idx = table[(hsh & 0x7fffffff) % tablelen];
|
|
+ /*
|
|
+ * This while loop is an optimization where a double lookup
|
|
+ * for name and name+/ is being performed. The name char
|
|
+ * array has enough room at the end to try again with a
|
|
+ * slash appended if the first table lookup does not succeed.
|
|
+ */
|
|
+ while(true) {
|
|
+ /*
|
|
+ * Search down the target hash chain for a entry whose
|
|
+ * 32 bit hash matches the hashed name.
|
|
+ */
|
|
+ while (idx != ZIP_ENDCHAIN) {
|
|
+ if (getEntryHash(idx) == hsh) {
|
|
+ // The CEN name must match the specfied one
|
|
+ int pos = getEntryPos(idx);
|
|
+ if (name.length == CENNAM(cen, pos)) {
|
|
+ boolean matched = true;
|
|
+ int nameoff = pos + CENHDR;
|
|
+ for (int i = 0; i < name.length; i++) {
|
|
+ if (name[i] != cen[nameoff++]) {
|
|
+ matched = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (matched) {
|
|
+ return pos;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ idx = getEntryNext(idx);
|
|
+ }
|
|
+ /* If not addSlash, or slash is already there, we are done */
|
|
+ if (!addSlash || name[name.length - 1] == '/') {
|
|
+ return -1;
|
|
+ }
|
|
+ /* Add slash and try once more */
|
|
+ name = Arrays.copyOf(name, name.length + 1);
|
|
+ name[name.length - 1] = '/';
|
|
+ hsh = hash_append(hsh, (byte)'/');
|
|
+ //idx = table[hsh % tablelen];
|
|
+ idx = table[(hsh & 0x7fffffff) % tablelen];
|
|
+ addSlash = false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns true if the bytes represent a non-directory name
|
|
+ * beginning with "META-INF/", disregarding ASCII case.
|
|
+ */
|
|
+ private static boolean isMetaName(byte[] name, int off, int len) {
|
|
+ // Use the "oldest ASCII trick in the book"
|
|
+ return len > 9 // "META-INF/".length()
|
|
+ && name[off + len - 1] != '/' // non-directory
|
|
+ && (name[off++] | 0x20) == 'm'
|
|
+ && (name[off++] | 0x20) == 'e'
|
|
+ && (name[off++] | 0x20) == 't'
|
|
+ && (name[off++] | 0x20) == 'a'
|
|
+ && (name[off++] ) == '-'
|
|
+ && (name[off++] | 0x20) == 'i'
|
|
+ && (name[off++] | 0x20) == 'n'
|
|
+ && (name[off++] | 0x20) == 'f'
|
|
+ && (name[off] ) == '/';
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Check if the bytes represents a name equals to MANIFEST.MF
|
|
+ */
|
|
+ private boolean isManifestName(byte[] name, int off, int len) {
|
|
+ return (len == 11 // "MANIFEST.MF".length()
|
|
+ && (name[off++] | 0x20) == 'm'
|
|
+ && (name[off++] | 0x20) == 'a'
|
|
+ && (name[off++] | 0x20) == 'n'
|
|
+ && (name[off++] | 0x20) == 'i'
|
|
+ && (name[off++] | 0x20) == 'f'
|
|
+ && (name[off++] | 0x20) == 'e'
|
|
+ && (name[off++] | 0x20) == 's'
|
|
+ && (name[off++] | 0x20) == 't'
|
|
+ && (name[off++] ) == '.'
|
|
+ && (name[off++] | 0x20) == 'm'
|
|
+ && (name[off] | 0x20) == 'f');
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Counts the number of CEN headers in a central directory extending
|
|
+ * from BEG to END. Might return a bogus answer if the zip file is
|
|
+ * corrupt, but will not crash.
|
|
+ */
|
|
+ static int countCENHeaders(byte[] cen, int end) {
|
|
+ int count = 0;
|
|
+ int pos = 0;
|
|
+ while (pos + CENHDR <= end) {
|
|
+ count++;
|
|
+ pos += (CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos));
|
|
+ }
|
|
+ return count;
|
|
+ }
|
|
+ }
|
|
}
|
|
diff --git a/jdk/src/share/classes/java/util/zip/ZipUtils.java b/jdk/src/share/classes/java/util/zip/ZipUtils.java
|
|
index cd8b05278..a9b9db948 100644
|
|
--- a/jdk/src/share/classes/java/util/zip/ZipUtils.java
|
|
+++ b/jdk/src/share/classes/java/util/zip/ZipUtils.java
|
|
@@ -29,6 +29,8 @@ import java.nio.file.attribute.FileTime;
|
|
import java.util.Date;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
+import static java.util.zip.ZipConstants.ENDHDR;
|
|
+
|
|
class ZipUtils {
|
|
|
|
// used to adjust values between Windows and java epoch
|
|
@@ -126,7 +128,7 @@ class ZipUtils {
|
|
* The bytes are assumed to be in Intel (little-endian) byte order.
|
|
*/
|
|
public static final int get16(byte b[], int off) {
|
|
- return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
|
|
+ return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8);
|
|
}
|
|
|
|
/**
|
|
@@ -144,4 +146,79 @@ class ZipUtils {
|
|
public static final long get64(byte b[], int off) {
|
|
return get32(b, off) | (get32(b, off+4) << 32);
|
|
}
|
|
+
|
|
+ // fields access methods
|
|
+ static final int CH(byte[] b, int n) {
|
|
+ return b[n] & 0xff ;
|
|
+ }
|
|
+
|
|
+ static final int SH(byte[] b, int n) {
|
|
+ return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8);
|
|
+ }
|
|
+
|
|
+ static final long LG(byte[] b, int n) {
|
|
+ return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
|
|
+ }
|
|
+
|
|
+ static final long LL(byte[] b, int n) {
|
|
+ return (LG(b, n)) | (LG(b, n + 4) << 32);
|
|
+ }
|
|
+
|
|
+ static final long GETSIG(byte[] b) {
|
|
+ return LG(b, 0);
|
|
+ }
|
|
+
|
|
+ // local file (LOC) header fields
|
|
+ static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
|
|
+ static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
|
|
+ static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
|
|
+ static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
|
|
+ static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
|
|
+ static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
|
|
+ static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
|
|
+ static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
|
|
+ static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
|
|
+ static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
|
|
+
|
|
+ // extra local (EXT) header fields
|
|
+ static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
|
|
+ static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
|
|
+ static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
|
|
+
|
|
+ // end of central directory header (END) fields
|
|
+ static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
|
|
+ static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
|
|
+ static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
|
|
+ static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
|
|
+ static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment
|
|
+ static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
|
|
+
|
|
+ // zip64 end of central directory recoder fields
|
|
+ static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
|
|
+ static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
|
|
+ static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
|
|
+ static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
|
|
+ static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
|
|
+
|
|
+ // central directory header (CEN) fields
|
|
+ static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
|
|
+ static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
|
|
+ static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
|
|
+ static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
|
|
+ static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
|
|
+ static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
|
|
+ static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
|
|
+ static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
|
|
+ static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
|
|
+ static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
|
|
+ static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
|
|
+ static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
|
|
+ static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
|
|
+ static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
|
|
+ static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
|
|
+ static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
|
|
+
|
|
+ // The END header is followed by a variable length comment of size < 64k.
|
|
+ static final long END_MAXLEN = 0xFFFF + ENDHDR;
|
|
+ static final int READBLOCKSZ = 128;
|
|
}
|
|
diff --git a/jdk/src/share/classes/sun/misc/JavaUtilZipFileAccess.java b/jdk/src/share/classes/sun/misc/JavaUtilZipFileAccess.java
|
|
index 0d931d1db..d140f54a5 100644
|
|
--- a/jdk/src/share/classes/sun/misc/JavaUtilZipFileAccess.java
|
|
+++ b/jdk/src/share/classes/sun/misc/JavaUtilZipFileAccess.java
|
|
@@ -31,5 +31,6 @@ import java.util.zip.ZipFile;
|
|
public interface JavaUtilZipFileAccess {
|
|
public boolean startsWithLocHeader(ZipFile zip);
|
|
public int getManifestNum(JarFile zip);
|
|
+ public String[] getMetaInfEntryNames(ZipFile zip);
|
|
}
|
|
|
|
diff --git a/jdk/src/share/classes/sun/misc/VM.java b/jdk/src/share/classes/sun/misc/VM.java
|
|
index 3e64628c6..cb757b3e3 100644
|
|
--- a/jdk/src/share/classes/sun/misc/VM.java
|
|
+++ b/jdk/src/share/classes/sun/misc/VM.java
|
|
@@ -310,9 +310,6 @@ public class VM {
|
|
// used by java.lang.Integer.IntegerCache
|
|
props.remove("java.lang.Integer.IntegerCache.high");
|
|
|
|
- // used by java.util.zip.ZipFile
|
|
- props.remove("sun.zip.disableMemoryMapping");
|
|
-
|
|
// used by sun.launcher.LauncherHelper
|
|
props.remove("sun.java.launcher.diag");
|
|
|
|
diff --git a/jdk/src/share/native/java/util/zip/ZipFile.c b/jdk/src/share/native/java/util/zip/ZipFile.c
|
|
deleted file mode 100644
|
|
index 8e3698290..000000000
|
|
--- a/jdk/src/share/native/java/util/zip/ZipFile.c
|
|
+++ /dev/null
|
|
@@ -1,403 +0,0 @@
|
|
-/*
|
|
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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. Oracle designates this
|
|
- * particular file as subject to the "Classpath" exception as provided
|
|
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
- * or visit www.oracle.com if you need additional information or have any
|
|
- * questions.
|
|
- */
|
|
-
|
|
-/*
|
|
- * Native method support for java.util.zip.ZipFile
|
|
- */
|
|
-
|
|
-#include <stdio.h>
|
|
-#include <stdlib.h>
|
|
-#include <string.h>
|
|
-#include <errno.h>
|
|
-#include <ctype.h>
|
|
-#include <assert.h>
|
|
-#include "jlong.h"
|
|
-#include "jvm.h"
|
|
-#include "jni.h"
|
|
-#include "jni_util.h"
|
|
-#include "zip_util.h"
|
|
-#ifdef WIN32
|
|
-#include "io_util_md.h"
|
|
-#else
|
|
-#include "io_util.h"
|
|
-#endif
|
|
-
|
|
-#include "java_util_zip_ZipFile.h"
|
|
-#include "java_util_jar_JarFile.h"
|
|
-
|
|
-#define DEFLATED 8
|
|
-#define STORED 0
|
|
-
|
|
-static jfieldID jzfileID;
|
|
-
|
|
-static int OPEN_READ = java_util_zip_ZipFile_OPEN_READ;
|
|
-static int OPEN_DELETE = java_util_zip_ZipFile_OPEN_DELETE;
|
|
-
|
|
-JNIEXPORT void JNICALL
|
|
-Java_java_util_zip_ZipFile_initIDs(JNIEnv *env, jclass cls)
|
|
-{
|
|
- jzfileID = (*env)->GetFieldID(env, cls, "jzfile", "J");
|
|
- assert(jzfileID != 0);
|
|
-}
|
|
-
|
|
-static void
|
|
-ThrowZipException(JNIEnv *env, const char *msg)
|
|
-{
|
|
- jstring s = NULL;
|
|
- jobject x;
|
|
-
|
|
- if (msg != NULL) {
|
|
- s = JNU_NewStringPlatform(env, msg);
|
|
- }
|
|
- if (s != NULL) {
|
|
- x = JNU_NewObjectByName(env,
|
|
- "java/util/zip/ZipException",
|
|
- "(Ljava/lang/String;)V", s);
|
|
- if (x != NULL) {
|
|
- (*env)->Throw(env, x);
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-JNIEXPORT jlong JNICALL
|
|
-Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name,
|
|
- jint mode, jlong lastModified,
|
|
- jboolean usemmap)
|
|
-{
|
|
- const char *path = JNU_GetStringPlatformChars(env, name, 0);
|
|
- char *msg = 0;
|
|
- jlong result = 0;
|
|
- int flag = 0;
|
|
- jzfile *zip = 0;
|
|
-
|
|
- if (mode & OPEN_READ) flag |= O_RDONLY;
|
|
- if (mode & OPEN_DELETE) flag |= JVM_O_DELETE;
|
|
-
|
|
- if (path != 0) {
|
|
- zip = ZIP_Get_From_Cache(path, &msg, lastModified);
|
|
- if (zip == 0 && msg == 0) {
|
|
- ZFILE zfd = 0;
|
|
-#ifdef WIN32
|
|
- zfd = winFileHandleOpen(env, name, flag);
|
|
- if (zfd == -1) {
|
|
- /* Exception already pending. */
|
|
- goto finally;
|
|
- }
|
|
-#else
|
|
- zfd = JVM_Open(path, flag, 0);
|
|
- if (zfd < 0) {
|
|
- throwFileNotFoundException(env, name);
|
|
- goto finally;
|
|
- }
|
|
-#endif
|
|
- zip = ZIP_Put_In_Cache0(path, zfd, &msg, lastModified, usemmap);
|
|
- }
|
|
-
|
|
- if (zip != 0) {
|
|
- result = ptr_to_jlong(zip);
|
|
- } else if (msg != 0) {
|
|
- ThrowZipException(env, msg);
|
|
- free(msg);
|
|
- } else if (errno == ENOMEM) {
|
|
- JNU_ThrowOutOfMemoryError(env, 0);
|
|
- } else {
|
|
- ThrowZipException(env, "error in opening zip file");
|
|
- }
|
|
-finally:
|
|
- JNU_ReleaseStringPlatformChars(env, name, path);
|
|
- }
|
|
- return result;
|
|
-}
|
|
-
|
|
-JNIEXPORT jint JNICALL
|
|
-Java_java_util_zip_ZipFile_getTotal(JNIEnv *env, jclass cls, jlong zfile)
|
|
-{
|
|
- jzfile *zip = jlong_to_ptr(zfile);
|
|
-
|
|
- return zip->total;
|
|
-}
|
|
-
|
|
-JNIEXPORT jboolean JNICALL
|
|
-Java_java_util_zip_ZipFile_startsWithLOC(JNIEnv *env, jclass cls, jlong zfile)
|
|
-{
|
|
- jzfile *zip = jlong_to_ptr(zfile);
|
|
-
|
|
- return zip->locsig;
|
|
-}
|
|
-
|
|
-JNIEXPORT jint JNICALL
|
|
-Java_java_util_zip_ZipFile_getManifestNum(JNIEnv *env, jclass cls, jlong zfile)
|
|
-{
|
|
- jzfile *zip = jlong_to_ptr(zfile);
|
|
-
|
|
- return zip->manifestNum;
|
|
-}
|
|
-
|
|
-JNIEXPORT void JNICALL
|
|
-Java_java_util_zip_ZipFile_close(JNIEnv *env, jclass cls, jlong zfile)
|
|
-{
|
|
- ZIP_Close(jlong_to_ptr(zfile));
|
|
-}
|
|
-
|
|
-JNIEXPORT jlong JNICALL
|
|
-Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile,
|
|
- jbyteArray name, jboolean addSlash)
|
|
-{
|
|
-#define MAXNAME 1024
|
|
- jzfile *zip = jlong_to_ptr(zfile);
|
|
- jsize ulen = (*env)->GetArrayLength(env, name);
|
|
- char buf[MAXNAME+2], *path;
|
|
- jzentry *ze;
|
|
-
|
|
- if (ulen > MAXNAME) {
|
|
- path = malloc(ulen + 2);
|
|
- if (path == 0) {
|
|
- JNU_ThrowOutOfMemoryError(env, 0);
|
|
- return 0;
|
|
- }
|
|
- } else {
|
|
- path = buf;
|
|
- }
|
|
- (*env)->GetByteArrayRegion(env, name, 0, ulen, (jbyte *)path);
|
|
- path[ulen] = '\0';
|
|
- ze = ZIP_GetEntry2(zip, path, (jint)ulen, addSlash);
|
|
- if (path != buf) {
|
|
- free(path);
|
|
- }
|
|
- return ptr_to_jlong(ze);
|
|
-}
|
|
-
|
|
-JNIEXPORT void JNICALL
|
|
-Java_java_util_zip_ZipFile_freeEntry(JNIEnv *env, jclass cls, jlong zfile,
|
|
- jlong zentry)
|
|
-{
|
|
- jzfile *zip = jlong_to_ptr(zfile);
|
|
- jzentry *ze = jlong_to_ptr(zentry);
|
|
- ZIP_FreeEntry(zip, ze);
|
|
-}
|
|
-
|
|
-JNIEXPORT jlong JNICALL
|
|
-Java_java_util_zip_ZipFile_getNextEntry(JNIEnv *env, jclass cls, jlong zfile,
|
|
- jint n)
|
|
-{
|
|
- jzentry *ze = ZIP_GetNextEntry(jlong_to_ptr(zfile), n);
|
|
- return ptr_to_jlong(ze);
|
|
-}
|
|
-
|
|
-JNIEXPORT jint JNICALL
|
|
-Java_java_util_zip_ZipFile_getEntryMethod(JNIEnv *env, jclass cls, jlong zentry)
|
|
-{
|
|
- jzentry *ze = jlong_to_ptr(zentry);
|
|
- return ze->csize != 0 ? DEFLATED : STORED;
|
|
-}
|
|
-
|
|
-JNIEXPORT jint JNICALL
|
|
-Java_java_util_zip_ZipFile_getEntryFlag(JNIEnv *env, jclass cls, jlong zentry)
|
|
-{
|
|
- jzentry *ze = jlong_to_ptr(zentry);
|
|
- return ze->flag;
|
|
-}
|
|
-
|
|
-JNIEXPORT jlong JNICALL
|
|
-Java_java_util_zip_ZipFile_getEntryCSize(JNIEnv *env, jclass cls, jlong zentry)
|
|
-{
|
|
- jzentry *ze = jlong_to_ptr(zentry);
|
|
- return ze->csize != 0 ? ze->csize : ze->size;
|
|
-}
|
|
-
|
|
-JNIEXPORT jlong JNICALL
|
|
-Java_java_util_zip_ZipFile_getEntrySize(JNIEnv *env, jclass cls, jlong zentry)
|
|
-{
|
|
- jzentry *ze = jlong_to_ptr(zentry);
|
|
- return ze->size;
|
|
-}
|
|
-
|
|
-JNIEXPORT jlong JNICALL
|
|
-Java_java_util_zip_ZipFile_getEntryTime(JNIEnv *env, jclass cls, jlong zentry)
|
|
-{
|
|
- jzentry *ze = jlong_to_ptr(zentry);
|
|
- return (jlong)ze->time & 0xffffffffUL;
|
|
-}
|
|
-
|
|
-JNIEXPORT jlong JNICALL
|
|
-Java_java_util_zip_ZipFile_getEntryCrc(JNIEnv *env, jclass cls, jlong zentry)
|
|
-{
|
|
- jzentry *ze = jlong_to_ptr(zentry);
|
|
- return (jlong)ze->crc & 0xffffffffUL;
|
|
-}
|
|
-
|
|
-JNIEXPORT jbyteArray JNICALL
|
|
-Java_java_util_zip_ZipFile_getCommentBytes(JNIEnv *env,
|
|
- jclass cls,
|
|
- jlong zfile)
|
|
-{
|
|
- jzfile *zip = jlong_to_ptr(zfile);
|
|
- jbyteArray jba = NULL;
|
|
-
|
|
- if (zip->comment != NULL) {
|
|
- if ((jba = (*env)->NewByteArray(env, zip->clen)) == NULL)
|
|
- return NULL;
|
|
- (*env)->SetByteArrayRegion(env, jba, 0, zip->clen, (jbyte*)zip->comment);
|
|
- }
|
|
- return jba;
|
|
-}
|
|
-
|
|
-JNIEXPORT jbyteArray JNICALL
|
|
-Java_java_util_zip_ZipFile_getEntryBytes(JNIEnv *env,
|
|
- jclass cls,
|
|
- jlong zentry, jint type)
|
|
-{
|
|
- jzentry *ze = jlong_to_ptr(zentry);
|
|
- int len = 0;
|
|
- jbyteArray jba = NULL;
|
|
- switch (type) {
|
|
- case java_util_zip_ZipFile_JZENTRY_NAME:
|
|
- if (ze->name != 0) {
|
|
- len = (int)ze->nlen;
|
|
- if (len == 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
|
|
- break;
|
|
- (*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte *)ze->name);
|
|
- }
|
|
- break;
|
|
- case java_util_zip_ZipFile_JZENTRY_EXTRA:
|
|
- if (ze->extra != 0) {
|
|
- unsigned char *bp = (unsigned char *)&ze->extra[0];
|
|
- len = (bp[0] | (bp[1] << 8));
|
|
- if (len <= 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
|
|
- break;
|
|
- (*env)->SetByteArrayRegion(env, jba, 0, len, &ze->extra[2]);
|
|
- }
|
|
- break;
|
|
- case java_util_zip_ZipFile_JZENTRY_COMMENT:
|
|
- if (ze->comment != 0) {
|
|
- len = (int)strlen(ze->comment);
|
|
- if (len == 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
|
|
- break;
|
|
- (*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte*)ze->comment);
|
|
- }
|
|
- break;
|
|
- }
|
|
- return jba;
|
|
-}
|
|
-
|
|
-JNIEXPORT jint JNICALL
|
|
-Java_java_util_zip_ZipFile_read(JNIEnv *env, jclass cls, jlong zfile,
|
|
- jlong zentry, jlong pos, jbyteArray bytes,
|
|
- jint off, jint len)
|
|
-{
|
|
- jzfile *zip = jlong_to_ptr(zfile);
|
|
- char *msg;
|
|
-
|
|
-#define BUFSIZE 8192
|
|
- /* copy via tmp stack buffer: */
|
|
- jbyte buf[BUFSIZE];
|
|
-
|
|
- if (len > BUFSIZE) {
|
|
- len = BUFSIZE;
|
|
- }
|
|
-
|
|
- ZIP_Lock(zip);
|
|
- len = ZIP_Read(zip, jlong_to_ptr(zentry), pos, buf, len);
|
|
- msg = zip->msg;
|
|
- ZIP_Unlock(zip);
|
|
- if (len != -1) {
|
|
- (*env)->SetByteArrayRegion(env, bytes, off, len, buf);
|
|
- }
|
|
-
|
|
- if (len == -1) {
|
|
- if (msg != 0) {
|
|
- ThrowZipException(env, msg);
|
|
- } else {
|
|
- char errmsg[128];
|
|
- sprintf(errmsg, "errno: %d, error: %s\n",
|
|
- errno, "Error reading ZIP file");
|
|
- JNU_ThrowIOExceptionWithLastError(env, errmsg);
|
|
- }
|
|
- }
|
|
-
|
|
- return len;
|
|
-}
|
|
-
|
|
-/*
|
|
- * Returns an array of strings representing the names of all entries
|
|
- * that begin with "META-INF/" (case ignored). This native method is
|
|
- * used in JarFile as an optimization when looking up manifest and
|
|
- * signature file entries. Returns null if no entries were found.
|
|
- */
|
|
-JNIEXPORT jobjectArray JNICALL
|
|
-Java_java_util_jar_JarFile_getMetaInfEntryNames(JNIEnv *env, jobject obj)
|
|
-{
|
|
- jlong zfile = (*env)->GetLongField(env, obj, jzfileID);
|
|
- jzfile *zip;
|
|
- int i, count;
|
|
- jobjectArray result = 0;
|
|
-
|
|
- if (zfile == 0) {
|
|
- JNU_ThrowByName(env,
|
|
- "java/lang/IllegalStateException", "zip file closed");
|
|
- return NULL;
|
|
- }
|
|
- zip = jlong_to_ptr(zfile);
|
|
-
|
|
- /* count the number of valid ZIP metanames */
|
|
- count = 0;
|
|
- if (zip->metanames != 0) {
|
|
- for (i = 0; i < zip->metacount; i++) {
|
|
- if (zip->metanames[i] != 0) {
|
|
- count++;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
- /* If some names were found then build array of java strings */
|
|
- if (count > 0) {
|
|
- jclass cls = JNU_ClassString(env);
|
|
- CHECK_NULL_RETURN(cls, NULL);
|
|
- result = (*env)->NewObjectArray(env, count, cls, 0);
|
|
- CHECK_NULL_RETURN(result, NULL);
|
|
- if (result != 0) {
|
|
- for (i = 0; i < count; i++) {
|
|
- jstring str = (*env)->NewStringUTF(env, zip->metanames[i]);
|
|
- if (str == 0) {
|
|
- break;
|
|
- }
|
|
- (*env)->SetObjectArrayElement(env, result, i, str);
|
|
- (*env)->DeleteLocalRef(env, str);
|
|
- }
|
|
- }
|
|
- }
|
|
- return result;
|
|
-}
|
|
-
|
|
-JNIEXPORT jstring JNICALL
|
|
-Java_java_util_zip_ZipFile_getZipMessage(JNIEnv *env, jclass cls, jlong zfile)
|
|
-{
|
|
- jzfile *zip = jlong_to_ptr(zfile);
|
|
- char *msg = zip->msg;
|
|
- if (msg == NULL) {
|
|
- return NULL;
|
|
- }
|
|
- return JNU_NewStringPlatform(env, msg);
|
|
-}
|
|
diff --git a/jdk/src/share/native/java/util/zip/zip_util.c b/jdk/src/share/native/java/util/zip/zip_util.c
|
|
index ff59c5ecc..ffe094065 100644
|
|
--- a/jdk/src/share/native/java/util/zip/zip_util.c
|
|
+++ b/jdk/src/share/native/java/util/zip/zip_util.c
|
|
@@ -74,8 +74,6 @@ static void freeCEN(jzfile *);
|
|
#define PATH_MAX 1024
|
|
#endif
|
|
|
|
-#define META_INF_LEN 9 /* "META-INF/".length() */
|
|
-
|
|
static jint INITIAL_META_COUNT = 2; /* initial number of entries in meta name array */
|
|
|
|
#ifdef LINUX
|
|
@@ -475,25 +473,6 @@ isMetaName(const char *name, int length)
|
|
return 1;
|
|
}
|
|
|
|
-/*
|
|
- * Check if the bytes represents a name equals to MANIFEST.MF
|
|
- */
|
|
-static int
|
|
-isManifestName(const char *name, int length)
|
|
-{
|
|
- const char *s;
|
|
- if (length != (int)sizeof("MANIFEST.MF") - 1)
|
|
- return 0;
|
|
- for (s = "MANIFEST.MF"; *s != '\0'; s++) {
|
|
- char c = *name++;
|
|
- // Avoid toupper; it's locale-dependent
|
|
- if (c >= 'a' && c <= 'z') c += 'A' - 'a';
|
|
- if (*s != c)
|
|
- return 0;
|
|
- }
|
|
- return 1;
|
|
-}
|
|
-
|
|
/*
|
|
* Increases the capacity of zip->metanames.
|
|
* Returns non-zero in case of allocation error.
|
|
@@ -564,7 +543,6 @@ freeCEN(jzfile *zip)
|
|
{
|
|
free(zip->entries); zip->entries = NULL;
|
|
free(zip->table); zip->table = NULL;
|
|
- zip->manifestNum = 0;
|
|
freeMetaNames(zip);
|
|
}
|
|
|
|
@@ -718,8 +696,6 @@ readCEN(jzfile *zip, jint knownTotal)
|
|
for (j = 0; j < tablelen; j++)
|
|
table[j] = ZIP_ENDCHAIN;
|
|
|
|
- zip->manifestNum = 0;
|
|
-
|
|
/* Iterate through the entries in the central directory */
|
|
for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) {
|
|
/* Following are unsigned 16-bit */
|
|
@@ -747,12 +723,9 @@ readCEN(jzfile *zip, jint knownTotal)
|
|
ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
|
|
|
|
/* if the entry is metadata add it to our metadata names */
|
|
- if (isMetaName((char *)cp+CENHDR, nlen)) {
|
|
- if (isManifestName((char *)cp+CENHDR+META_INF_LEN, nlen-META_INF_LEN))
|
|
- zip->manifestNum++;
|
|
+ if (isMetaName((char *)cp+CENHDR, nlen))
|
|
if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0)
|
|
goto Catch;
|
|
- }
|
|
|
|
/* Record the CEN offset and the name hash in our hash cell. */
|
|
entries[i].cenpos = cenpos + (cp - cenbuf);
|
|
diff --git a/jdk/src/share/native/java/util/zip/zip_util.h b/jdk/src/share/native/java/util/zip/zip_util.h
|
|
index 2a7ae4b7e..a64668cd6 100644
|
|
--- a/jdk/src/share/native/java/util/zip/zip_util.h
|
|
+++ b/jdk/src/share/native/java/util/zip/zip_util.h
|
|
@@ -229,7 +229,6 @@ typedef struct jzfile { /* Zip file */
|
|
char **metanames; /* array of meta names (may have null names) */
|
|
jint metacurrent; /* the next empty slot in metanames array */
|
|
jint metacount; /* number of slots in metanames array */
|
|
- jint manifestNum; /* number of META-INF/MANIFEST.MF, case insensitive */
|
|
jlong lastModified; /* last modified time */
|
|
jlong locpos; /* position of first LOC header (usually 0) */
|
|
} jzfile;
|
|
diff --git a/jdk/test/java/nio/file/spi/TestProvider.java b/jdk/test/java/nio/file/spi/TestProvider.java
|
|
index b2744f4c0..c975b8e27 100644
|
|
--- a/jdk/test/java/nio/file/spi/TestProvider.java
|
|
+++ b/jdk/test/java/nio/file/spi/TestProvider.java
|
|
@@ -21,20 +21,34 @@
|
|
* questions.
|
|
*/
|
|
|
|
-import java.nio.file.spi.FileSystemProvider;
|
|
+import java.io.File;
|
|
import java.nio.file.*;
|
|
-import java.nio.file.attribute.*;
|
|
+import java.nio.file.attribute.BasicFileAttributes;
|
|
+import java.nio.file.attribute.FileAttribute;
|
|
+import java.nio.file.attribute.FileAttributeView;
|
|
+import java.nio.file.attribute.UserPrincipalLookupService;
|
|
+import java.nio.file.spi.FileSystemProvider;
|
|
import java.nio.channels.SeekableByteChannel;
|
|
import java.net.URI;
|
|
-import java.util.*;
|
|
import java.io.IOException;
|
|
+import java.util.Collections;
|
|
+import java.util.Iterator;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
|
|
public class TestProvider extends FileSystemProvider {
|
|
|
|
- private final FileSystem theFileSystem;
|
|
+ private final FileSystemProvider defaultProvider;
|
|
+ private final TestFileSystem theFileSystem;
|
|
|
|
public TestProvider(FileSystemProvider defaultProvider) {
|
|
- theFileSystem = new TestFileSystem(this);
|
|
+ this.defaultProvider = defaultProvider;
|
|
+ FileSystem fs = defaultProvider.getFileSystem(URI.create("file:/"));
|
|
+ this.theFileSystem = new TestFileSystem(fs, this);
|
|
+ }
|
|
+
|
|
+ FileSystemProvider defaultProvider() {
|
|
+ return defaultProvider;
|
|
}
|
|
|
|
@Override
|
|
@@ -43,8 +57,8 @@ public class TestProvider extends FileSystemProvider {
|
|
}
|
|
|
|
@Override
|
|
- public FileSystem newFileSystem(URI uri, Map<String,?> env) {
|
|
- throw new RuntimeException("not implemented");
|
|
+ public FileSystem newFileSystem(URI uri, Map<String,?> env) throws IOException {
|
|
+ return defaultProvider.newFileSystem(uri, env);
|
|
}
|
|
|
|
@Override
|
|
@@ -54,7 +68,8 @@ public class TestProvider extends FileSystemProvider {
|
|
|
|
@Override
|
|
public Path getPath(URI uri) {
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path path = defaultProvider.getPath(uri);
|
|
+ return theFileSystem.wrap(path);
|
|
}
|
|
|
|
@Override
|
|
@@ -70,7 +85,8 @@ public class TestProvider extends FileSystemProvider {
|
|
LinkOption... options)
|
|
throws IOException
|
|
{
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path delegate = theFileSystem.unwrap(file);
|
|
+ return defaultProvider.readAttributes(delegate, attributes, options);
|
|
}
|
|
|
|
@Override
|
|
@@ -79,7 +95,8 @@ public class TestProvider extends FileSystemProvider {
|
|
LinkOption... options)
|
|
throws IOException
|
|
{
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path delegate = theFileSystem.unwrap(file);
|
|
+ return defaultProvider.readAttributes(delegate, type, options);
|
|
}
|
|
|
|
@Override
|
|
@@ -87,13 +104,14 @@ public class TestProvider extends FileSystemProvider {
|
|
Class<V> type,
|
|
LinkOption... options)
|
|
{
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path delegate = theFileSystem.unwrap(file);
|
|
+ return defaultProvider.getFileAttributeView(delegate, type, options);
|
|
}
|
|
|
|
-
|
|
@Override
|
|
public void delete(Path file) throws IOException {
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path delegate = theFileSystem.unwrap(file);
|
|
+ defaultProvider.delete(delegate);
|
|
}
|
|
|
|
@Override
|
|
@@ -110,10 +128,11 @@ public class TestProvider extends FileSystemProvider {
|
|
|
|
@Override
|
|
public Path readSymbolicLink(Path link) throws IOException {
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path delegate = theFileSystem.unwrap(link);
|
|
+ Path target = defaultProvider.readSymbolicLink(delegate);
|
|
+ return theFileSystem.wrap(target);
|
|
}
|
|
|
|
-
|
|
@Override
|
|
public void copy(Path source, Path target, CopyOption... options)
|
|
throws IOException
|
|
@@ -140,7 +159,8 @@ public class TestProvider extends FileSystemProvider {
|
|
public void createDirectory(Path dir, FileAttribute<?>... attrs)
|
|
throws IOException
|
|
{
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path delegate = theFileSystem.unwrap(dir);
|
|
+ defaultProvider.createDirectory(delegate, attrs);
|
|
}
|
|
|
|
@Override
|
|
@@ -149,13 +169,13 @@ public class TestProvider extends FileSystemProvider {
|
|
FileAttribute<?>... attrs)
|
|
throws IOException
|
|
{
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path delegate = theFileSystem.unwrap(file);
|
|
+ return defaultProvider.newByteChannel(delegate, options, attrs);
|
|
}
|
|
|
|
-
|
|
@Override
|
|
public boolean isHidden(Path file) throws IOException {
|
|
- throw new RuntimeException("not implemented");
|
|
+ throw new ReadOnlyFileSystemException();
|
|
}
|
|
|
|
@Override
|
|
@@ -176,12 +196,26 @@ public class TestProvider extends FileSystemProvider {
|
|
}
|
|
|
|
static class TestFileSystem extends FileSystem {
|
|
+ private final FileSystem delegate;
|
|
private final TestProvider provider;
|
|
|
|
- TestFileSystem(TestProvider provider) {
|
|
+ TestFileSystem(FileSystem delegate, TestProvider provider) {
|
|
+ this.delegate = delegate;
|
|
this.provider = provider;
|
|
}
|
|
|
|
+ Path wrap(Path path) {
|
|
+ return (path != null) ? new TestPath(this, path) : null;
|
|
+ }
|
|
+
|
|
+ Path unwrap(Path wrapper) {
|
|
+ if (wrapper == null)
|
|
+ throw new NullPointerException();
|
|
+ if (!(wrapper instanceof TestPath))
|
|
+ throw new ProviderMismatchException();
|
|
+ return ((TestPath)wrapper).unwrap();
|
|
+ }
|
|
+
|
|
@Override
|
|
public FileSystemProvider provider() {
|
|
return provider;
|
|
@@ -194,17 +228,17 @@ public class TestProvider extends FileSystemProvider {
|
|
|
|
@Override
|
|
public boolean isOpen() {
|
|
- throw new RuntimeException("not implemented");
|
|
+ return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isReadOnly() {
|
|
- throw new RuntimeException("not implemented");
|
|
+ return false;
|
|
}
|
|
|
|
@Override
|
|
public String getSeparator() {
|
|
- throw new RuntimeException("not implemented");
|
|
+ return delegate.getSeparator();
|
|
}
|
|
|
|
@Override
|
|
@@ -219,27 +253,209 @@ public class TestProvider extends FileSystemProvider {
|
|
|
|
@Override
|
|
public Set<String> supportedFileAttributeViews() {
|
|
- throw new RuntimeException("not implemented");
|
|
+ return delegate.supportedFileAttributeViews();
|
|
}
|
|
|
|
@Override
|
|
public Path getPath(String first, String... more) {
|
|
- throw new RuntimeException("not implemented");
|
|
+ Path path = delegate.getPath(first, more);
|
|
+ return wrap(path);
|
|
}
|
|
|
|
@Override
|
|
public PathMatcher getPathMatcher(String syntaxAndPattern) {
|
|
- throw new RuntimeException("not implemented");
|
|
+ return delegate.getPathMatcher(syntaxAndPattern);
|
|
}
|
|
|
|
@Override
|
|
public UserPrincipalLookupService getUserPrincipalLookupService() {
|
|
- throw new RuntimeException("not implemented");
|
|
+ return delegate.getUserPrincipalLookupService();
|
|
}
|
|
|
|
@Override
|
|
public WatchService newWatchService() throws IOException {
|
|
- throw new RuntimeException("not implemented");
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static class TestPath implements Path {
|
|
+ private final TestFileSystem fs;
|
|
+ private final Path delegate;
|
|
+
|
|
+ TestPath(TestFileSystem fs, Path delegate) {
|
|
+ this.fs = fs;
|
|
+ this.delegate = delegate;
|
|
+ }
|
|
+
|
|
+ Path unwrap() {
|
|
+ return delegate;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public FileSystem getFileSystem() {
|
|
+ return fs;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isAbsolute() {
|
|
+ return delegate.isAbsolute();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path getRoot() {
|
|
+ return fs.wrap(delegate.getRoot());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path getParent() {
|
|
+ return fs.wrap(delegate.getParent());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int getNameCount() {
|
|
+ return delegate.getNameCount();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path getFileName() {
|
|
+ return fs.wrap(delegate.getFileName());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path getName(int index) {
|
|
+ return fs.wrap(delegate.getName(index));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path subpath(int beginIndex, int endIndex) {
|
|
+ return fs.wrap(delegate.subpath(beginIndex, endIndex));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean startsWith(Path other) {
|
|
+ return delegate.startsWith(fs.unwrap(other));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean startsWith(String other) {
|
|
+ return delegate.startsWith(other);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean endsWith(Path other) {
|
|
+ return delegate.endsWith(fs.unwrap(other));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean endsWith(String other) {
|
|
+ return delegate.endsWith(other);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path normalize() {
|
|
+ return fs.wrap(delegate.normalize());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path resolve(Path other) {
|
|
+ return fs.wrap(delegate.resolve(fs.unwrap(other)));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path resolve(String other) {
|
|
+ return fs.wrap(delegate.resolve(other));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path resolveSibling(Path other) {
|
|
+ return fs.wrap(delegate.resolveSibling(fs.unwrap(other)));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path resolveSibling(String other) {
|
|
+ return fs.wrap(delegate.resolveSibling(other));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path relativize(Path other) {
|
|
+ return fs.wrap(delegate.relativize(fs.unwrap(other)));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean equals(Object other) {
|
|
+ if (!(other instanceof TestPath))
|
|
+ return false;
|
|
+ return delegate.equals(fs.unwrap((TestPath) other));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int hashCode() {
|
|
+ return delegate.hashCode();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public String toString() {
|
|
+ return delegate.toString();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public URI toUri() {
|
|
+ String ssp = delegate.toUri().getSchemeSpecificPart();
|
|
+ return URI.create(fs.provider().getScheme() + ":" + ssp);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path toAbsolutePath() {
|
|
+ return fs.wrap(delegate.toAbsolutePath());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Path toRealPath(LinkOption... options) throws IOException {
|
|
+ return fs.wrap(delegate.toRealPath(options));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public File toFile() {
|
|
+ return new File(toString());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Iterator<Path> iterator() {
|
|
+ final Iterator<Path> itr = delegate.iterator();
|
|
+ return new Iterator<Path>() {
|
|
+ @Override
|
|
+ public boolean hasNext() {
|
|
+ return itr.hasNext();
|
|
+ }
|
|
+ @Override
|
|
+ public Path next() {
|
|
+ return fs.wrap(itr.next());
|
|
+ }
|
|
+ @Override
|
|
+ public void remove() {
|
|
+ itr.remove();
|
|
+ }
|
|
+ };
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public int compareTo(Path other) {
|
|
+ return delegate.compareTo(fs.unwrap(other));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public WatchKey register(WatchService watcher,
|
|
+ WatchEvent.Kind<?>[] events,
|
|
+ WatchEvent.Modifier... modifiers)
|
|
+ {
|
|
+ throw new UnsupportedOperationException();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public WatchKey register(WatchService watcher,
|
|
+ WatchEvent.Kind<?>... events)
|
|
+ {
|
|
+ throw new UnsupportedOperationException();
|
|
}
|
|
}
|
|
-}
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/jdk/test/java/util/zip/ZipFile/TestZipFile.java b/jdk/test/java/util/zip/ZipFile/TestZipFile.java
|
|
new file mode 100644
|
|
index 000000000..30bae3bb9
|
|
--- /dev/null
|
|
+++ b/jdk/test/java/util/zip/ZipFile/TestZipFile.java
|
|
@@ -0,0 +1,375 @@
|
|
+/*
|
|
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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.
|
|
+ *
|
|
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
+ * or visit www.oracle.com if you need additional information or have any
|
|
+ * questions.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * @test
|
|
+ * @bug 8142508
|
|
+ * @summary Tests various ZipFile apis
|
|
+ * @run main/manual TestZipFile
|
|
+ */
|
|
+
|
|
+import java.io.*;
|
|
+import java.lang.reflect.Method;
|
|
+import java.nio.file.*;
|
|
+import java.nio.file.attribute.*;
|
|
+import java.util.*;
|
|
+import java.util.concurrent.*;
|
|
+import java.util.zip.*;
|
|
+
|
|
+public class TestZipFile {
|
|
+
|
|
+ private static Random r = new Random();
|
|
+ private static int N = 50;
|
|
+ private static int NN = 10;
|
|
+ private static int ENUM = 10000;
|
|
+ private static int ESZ = 10000;
|
|
+ private static ExecutorService executor = Executors.newFixedThreadPool(20);
|
|
+ private static Set<Path> paths = new HashSet<>();
|
|
+
|
|
+ static void realMain (String[] args) throws Throwable {
|
|
+
|
|
+ try {
|
|
+ for (int i = 0; i < N; i++) {
|
|
+ test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
|
+ test(r.nextInt(ENUM), r.nextInt(ESZ), true, true);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < NN; i++) {
|
|
+ test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), false, true);
|
|
+ test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), true, true);
|
|
+ testCachedDelete();
|
|
+ testCachedOverwrite();
|
|
+ //test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
|
+ }
|
|
+
|
|
+ test(70000, 1000, false, true); // > 65536 entry number;
|
|
+ testDelete(); // OPEN_DELETE
|
|
+
|
|
+ executor.shutdown();
|
|
+ executor.awaitTermination(10, TimeUnit.MINUTES);
|
|
+ } finally {
|
|
+ for (Path path : paths) {
|
|
+ Files.deleteIfExists(path);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static void test(int numEntry, int szMax, boolean addPrefix, boolean cleanOld) {
|
|
+ String name = "zftest" + r.nextInt() + ".zip";
|
|
+ Zip zip = new Zip(name, numEntry, szMax, addPrefix, cleanOld);
|
|
+ for (int i = 0; i < NN; i++) {
|
|
+ executor.submit(() -> doTest(zip));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // test scenario:
|
|
+ // (1) open the ZipFile(zip) with OPEN_READ | OPEN_DELETE
|
|
+ // (2) test the ZipFile works correctly
|
|
+ // (3) check the zip is deleted after ZipFile gets closed
|
|
+ static void testDelete() throws Throwable {
|
|
+ String name = "zftest" + r.nextInt() + ".zip";
|
|
+ Zip zip = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
|
+ try (ZipFile zf = new ZipFile(new File(zip.name),
|
|
+ ZipFile.OPEN_READ | ZipFile.OPEN_DELETE ))
|
|
+ {
|
|
+ doTest0(zip, zf);
|
|
+ }
|
|
+ Path p = Paths.get(name);
|
|
+ if (Files.exists(p)) {
|
|
+ fail("Failed to delete " + name + " with OPEN_DELETE");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // test scenario:
|
|
+ // (1) keep a ZipFile(zip1) alive (in ZipFile's cache), dont close it
|
|
+ // (2) delete zip1 and create zip2 with the same name the zip1 with zip2
|
|
+ // (3) zip1 tests should fail, but no crash
|
|
+ // (4) zip2 tasks should all get zip2, then pass normal testing.
|
|
+ static void testCachedDelete() throws Throwable {
|
|
+ String name = "zftest" + r.nextInt() + ".zip";
|
|
+ Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
|
+
|
|
+ try (ZipFile zf = new ZipFile(zip1.name)) {
|
|
+ for (int i = 0; i < NN; i++) {
|
|
+ executor.submit(() -> verifyNoCrash(zip1));
|
|
+ }
|
|
+ // delete the "zip1" and create a new one to test
|
|
+ Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
|
+ /*
|
|
+ System.out.println("========================================");
|
|
+ System.out.printf(" zip1=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
|
|
+ zip1.name, zip1.lastModified, zip1.entries.size(),
|
|
+ zip1.attrs.fileKey(), zip1.attrs.size(), zip1.attrs.lastModifiedTime().toMillis());
|
|
+ System.out.printf(" zip2=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
|
|
+ zip2.name, zip2.lastModified, zip2.entries.size(),
|
|
+ zip2.attrs.fileKey(), zip2.attrs.size(), zip2.attrs.lastModifiedTime().toMillis());
|
|
+ */
|
|
+ for (int i = 0; i < NN; i++) {
|
|
+ executor.submit(() -> doTest(zip2));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // overwrite the "zip1" and create a new one to test. So the two zip files
|
|
+ // have the same fileKey, but probably different lastModified()
|
|
+ static void testCachedOverwrite() throws Throwable {
|
|
+ String name = "zftest" + r.nextInt() + ".zip";
|
|
+ Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
|
+ try (ZipFile zf = new ZipFile(zip1.name)) {
|
|
+ for (int i = 0; i < NN; i++) {
|
|
+ executor.submit(() -> verifyNoCrash(zip1));
|
|
+ }
|
|
+ // overwrite the "zip1" with new contents
|
|
+ Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, false);
|
|
+ for (int i = 0; i < NN; i++) {
|
|
+ executor.submit(() -> doTest(zip2));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // This method is used to replace the InputStream.readAllBytes method(need JDK version >= 9).
|
|
+ public static byte[] readAllBytes(InputStream inputStream) throws IOException {
|
|
+ byte[] buffer = new byte[1024];
|
|
+ int len;
|
|
+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
|
+ while ((len = inputStream.read(buffer)) > -1) {
|
|
+ outputStream.write(buffer, 0, len);
|
|
+ }
|
|
+ return outputStream.toByteArray();
|
|
+ } catch (IOException e) {
|
|
+ throw e;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // just check the entries and contents. since the file has been either overwritten
|
|
+ // or deleted/rewritten, we only care if it crahes or not.
|
|
+ static void verifyNoCrash(Zip zip) throws RuntimeException {
|
|
+ try (ZipFile zf = new ZipFile(zip.name)) {
|
|
+ List<ZipEntry> zlist = new ArrayList(zip.entries.keySet());
|
|
+ String[] elist = zf.stream().map( e -> e.getName()).toArray(String[]::new);
|
|
+ if (!Arrays.equals(elist,
|
|
+ zlist.stream().map( e -> e.getName()).toArray(String[]::new)))
|
|
+ {
|
|
+ //System.out.printf("++++++ LIST NG [%s] entries.len=%d, expected=%d+++++++%n",
|
|
+ // zf.getName(), elist.length, zlist.size());
|
|
+ return;
|
|
+ }
|
|
+ for (ZipEntry ze : zlist) {
|
|
+ byte[] zdata = zip.entries.get(ze);
|
|
+ ZipEntry e = zf.getEntry(ze.getName());
|
|
+ if (e != null) {
|
|
+ checkEqual(e, ze);
|
|
+ if (!e.isDirectory()) {
|
|
+ // check with readAllBytes
|
|
+ try (InputStream is = zf.getInputStream(e)) {
|
|
+ if (!Arrays.equals(zdata, readAllBytes(is))) {
|
|
+ //System.out.printf("++++++ BYTES NG [%s]/[%s] ++++++++%n",
|
|
+ // zf.getName(), ze.getName());
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ } catch (Throwable t) {
|
|
+ // t.printStackTrace();
|
|
+ // fail(t.toString());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static void checkEqual(ZipEntry x, ZipEntry y) {
|
|
+ if (x.getName().equals(y.getName()) &&
|
|
+ x.isDirectory() == y.isDirectory() &&
|
|
+ x.getMethod() == y.getMethod() &&
|
|
+ (x.getTime() / 2000) == y.getTime() / 2000 &&
|
|
+ x.getSize() == y.getSize() &&
|
|
+ x.getCompressedSize() == y.getCompressedSize() &&
|
|
+ x.getCrc() == y.getCrc() &&
|
|
+ x.getComment().equals(y.getComment())
|
|
+ ) {
|
|
+ pass();
|
|
+ } else {
|
|
+ fail(x + " not equal to " + y);
|
|
+ System.out.printf(" %s %s%n", x.getName(), y.getName());
|
|
+ System.out.printf(" %d %d%n", x.getMethod(), y.getMethod());
|
|
+ System.out.printf(" %d %d%n", x.getTime(), y.getTime());
|
|
+ System.out.printf(" %d %d%n", x.getSize(), y.getSize());
|
|
+ System.out.printf(" %d %d%n", x.getCompressedSize(), y.getCompressedSize());
|
|
+ System.out.printf(" %d %d%n", x.getCrc(), y.getCrc());
|
|
+ System.out.println("-----------------");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static void doTest(Zip zip) throws RuntimeException {
|
|
+ //Thread me = Thread.currentThread();
|
|
+ try (ZipFile zf = new ZipFile(zip.name)) {
|
|
+ doTest0(zip, zf);
|
|
+ } catch (Throwable t) {
|
|
+ throw new RuntimeException(t);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static void doTest0(Zip zip, ZipFile zf) throws Throwable {
|
|
+ List<ZipEntry> list = new ArrayList(zip.entries.keySet());
|
|
+ // (1) check entry list, in expected order
|
|
+ if (!check(Arrays.equals(
|
|
+ list.stream().map( e -> e.getName()).toArray(String[]::new),
|
|
+ zf.stream().map( e -> e.getName()).toArray(String[]::new)))) {
|
|
+ return;
|
|
+ }
|
|
+ // (2) shuffle, and check each entry and its bytes
|
|
+ Collections.shuffle(list);
|
|
+ for (ZipEntry ze : list) {
|
|
+ byte[] data = zip.entries.get(ze);
|
|
+ ZipEntry e = zf.getEntry(ze.getName());
|
|
+ checkEqual(e, ze);
|
|
+ if (!e.isDirectory()) {
|
|
+ // check with readAllBytes
|
|
+ try (InputStream is = zf.getInputStream(e)) {
|
|
+ check(Arrays.equals(data, readAllBytes(is)));
|
|
+ }
|
|
+ // check with smaller sized buf
|
|
+ try (InputStream is = zf.getInputStream(e)) {
|
|
+ byte[] buf = new byte[(int)e.getSize()];
|
|
+ int sz = r.nextInt((int)e.getSize()/4 + 1) + 1;
|
|
+ int off = 0;
|
|
+ int n;
|
|
+ while ((n = is.read(buf, off, buf.length - off)) > 0) {
|
|
+ off += n;
|
|
+ }
|
|
+ check(is.read() == -1);
|
|
+ check(Arrays.equals(data, buf));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // (3) check getMetaInfEntryNames
|
|
+ String[] metas = list.stream()
|
|
+ .map( e -> e.getName())
|
|
+ .filter( s -> s.startsWith("META-INF/"))
|
|
+ .sorted()
|
|
+ .toArray(String[]::new);
|
|
+ if (metas.length > 0) {
|
|
+ // meta-inf entries
|
|
+ Method getMetas = ZipFile.class.getDeclaredMethod("getMetaInfEntryNames");
|
|
+ getMetas.setAccessible(true);
|
|
+ String[] names = (String[])getMetas.invoke(zf);
|
|
+ if (names == null) {
|
|
+ fail("Failed to get metanames from " + zf);
|
|
+ } else {
|
|
+ Arrays.sort(names);
|
|
+ check(Arrays.equals(names, metas));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static class Zip {
|
|
+ String name;
|
|
+ Map<ZipEntry, byte[]> entries;
|
|
+ BasicFileAttributes attrs;
|
|
+ long lastModified;
|
|
+
|
|
+ Zip(String name, int num, int szMax, boolean prefix, boolean clean) {
|
|
+ this.name = name;
|
|
+ entries = new LinkedHashMap<>(num);
|
|
+ try {
|
|
+ Path p = Paths.get(name);
|
|
+ if (clean) {
|
|
+ Files.deleteIfExists(p);
|
|
+ }
|
|
+ paths.add(p);
|
|
+ } catch (Exception x) {
|
|
+ throw (RuntimeException)x;
|
|
+ }
|
|
+
|
|
+ try (FileOutputStream fos = new FileOutputStream(name);
|
|
+ BufferedOutputStream bos = new BufferedOutputStream(fos);
|
|
+ ZipOutputStream zos = new ZipOutputStream(bos))
|
|
+ {
|
|
+ if (prefix) {
|
|
+ byte[] bytes = new byte[r.nextInt(1000)];
|
|
+ r.nextBytes(bytes);
|
|
+ bos.write(bytes);
|
|
+ }
|
|
+ CRC32 crc = new CRC32();
|
|
+ for (int i = 0; i < num; i++) {
|
|
+ String ename = "entry-" + i + "-name-" + r.nextLong();
|
|
+ ZipEntry ze = new ZipEntry(ename);
|
|
+ int method = r.nextBoolean() ? ZipEntry.STORED : ZipEntry.DEFLATED;
|
|
+ writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
|
|
+ }
|
|
+ // add some manifest entries
|
|
+ for (int i = 0; i < r.nextInt(20); i++) {
|
|
+ String meta = "META-INF/" + "entry-" + i + "-metainf-" + r.nextLong();
|
|
+ ZipEntry ze = new ZipEntry(meta);
|
|
+ writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
|
|
+ }
|
|
+ } catch (Exception x) {
|
|
+ throw (RuntimeException)x;
|
|
+ }
|
|
+ try {
|
|
+ this.attrs = Files.readAttributes(Paths.get(name), BasicFileAttributes.class);
|
|
+ this.lastModified = new File(name).lastModified();
|
|
+ } catch (Exception x) {
|
|
+ throw (RuntimeException)x;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void writeEntry(ZipOutputStream zos, CRC32 crc,
|
|
+ ZipEntry ze, int method, int szMax)
|
|
+ throws IOException
|
|
+ {
|
|
+ ze.setMethod(method);
|
|
+ byte[] data = new byte[r.nextInt(szMax + 1)];
|
|
+ r.nextBytes(data);
|
|
+ if (method == ZipEntry.STORED) { // must set size/csize/crc
|
|
+ ze.setSize(data.length);
|
|
+ ze.setCompressedSize(data.length);
|
|
+ crc.reset();
|
|
+ crc.update(data);
|
|
+ ze.setCrc(crc.getValue());
|
|
+ }
|
|
+ ze.setTime(System.currentTimeMillis());
|
|
+ ze.setComment(ze.getName());
|
|
+ zos.putNextEntry(ze);
|
|
+ zos.write(data);
|
|
+ zos.closeEntry();
|
|
+ entries.put(ze, data);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ //--------------------- Infrastructure ---------------------------
|
|
+ static volatile int passed = 0, failed = 0;
|
|
+ static void pass() {passed++;}
|
|
+ static void pass(String msg) {System.out.println(msg); passed++;}
|
|
+ static void fail() {failed++; Thread.dumpStack();}
|
|
+ static void fail(String msg) {System.out.println(msg); fail();}
|
|
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
|
+ static void unexpected(Throwable t, String msg) {
|
|
+ System.out.println(msg); failed++; t.printStackTrace();}
|
|
+ static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
|
+
|
|
+ public static void main(String[] args) throws Throwable {
|
|
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
|
+ System.out.println("\nPassed = " + passed + " failed = " + failed);
|
|
+ if (failed > 0) throw new AssertionError("Some tests failed");}
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java b/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java
|
|
index 89853c639..74938bcda 100644
|
|
--- a/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java
|
|
+++ b/jdk/test/javax/imageio/plugins/png/ItxtUtf8Test.java
|
|
@@ -30,7 +30,7 @@
|
|
*
|
|
* @run main ItxtUtf8Test
|
|
*
|
|
- * @run main/othervm/timeout=10 -Xmx2m ItxtUtf8Test truncate
|
|
+ * @run main/othervm/timeout=10 -Xmx4m ItxtUtf8Test truncate
|
|
*/
|
|
|
|
import java.awt.image.BufferedImage;
|
|
--
|
|
2.22.0
|
|
|