undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
138
test/jdk/java/util/zip/3GBZipFiles.sh
Normal file
138
test/jdk/java/util/zip/3GBZipFiles.sh
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
# Copyright (c) 2003, 2012, 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.
|
||||
#
|
||||
# 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 4262583 4418997 4795136
|
||||
# @summary Check support for jar file members with sizes > 2GB
|
||||
# @author Martin Buchholz
|
||||
#
|
||||
# @build FileBuilder
|
||||
# @run shell 3GBZipFiles.sh 9986
|
||||
# @ignore runs for hours and eats up 7 Gigabytes of disk space
|
||||
# @run shell/timeout=604800 3GBZipFiles.sh 3141592653
|
||||
# @key randomness
|
||||
|
||||
# Command-line usage:
|
||||
# javac FileBuilder.java && sh 3GBZipFiles.sh /path/to/jdk filesize
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Testing strategy: We want to test for size limits on the Jar file
|
||||
# itself, as well as on the compressed and uncompressed sizes of the
|
||||
# files stored therein. All of these limits should be 4GB and should
|
||||
# be tested in the 2GB-4GB range. We also want to check that it is
|
||||
# possible to store more than 6GB of actual data in a zip file, if we
|
||||
# have two files of size 3GB which compress nicely. We also want to
|
||||
# test both the "STORED" and "DEFLATED" compression methods.
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
die () { echo "$1" >&2; exit 1; }
|
||||
|
||||
sys () { "$@" || die "Command $@ failed: rc=$?"; }
|
||||
|
||||
set -u
|
||||
|
||||
myName=`printf %s "$0" | sed 's:.*[/\\]::'`;
|
||||
|
||||
if test -z "${TESTJAVA-}"; then
|
||||
test "$#" -eq 2 || die "Usage: $myName /path/to/jdk filesize"
|
||||
TESTJAVA="$1"; shift
|
||||
TESTCLASSES="`pwd`"
|
||||
fi
|
||||
|
||||
hugeSize="$1"; shift
|
||||
tinySize=42
|
||||
|
||||
JAVA="$TESTJAVA/bin/java"
|
||||
JAR="$TESTJAVA/bin/jar"
|
||||
|
||||
currentDir="`pwd`"
|
||||
tmpDir="$myName.tmp"
|
||||
|
||||
cleanup () { cd "$currentDir" && rm -rf "$tmpDir"; }
|
||||
|
||||
trap cleanup 0 1 2 15
|
||||
|
||||
sys rm -rf "$tmpDir"
|
||||
sys mkdir "$tmpDir"
|
||||
cd "$tmpDir"
|
||||
|
||||
buildFile ()
|
||||
{
|
||||
filetype_="$1"
|
||||
filename_="$2"
|
||||
case "$filename_" in
|
||||
huge-*) filesize_="$hugeSize" ;;
|
||||
tiny-*) filesize_="$tinySize" ;;
|
||||
esac
|
||||
sys "$JAVA" ${TESTVMOPTS} "-cp" "$TESTCLASSES" "FileBuilder" \
|
||||
"$filetype_" "$filename_" "$filesize_"
|
||||
}
|
||||
|
||||
testJarFile ()
|
||||
{
|
||||
echo "-------------------------------------------------------"
|
||||
echo "Testing $1 $2"
|
||||
echo "-------------------------------------------------------"
|
||||
|
||||
filetype="$1"
|
||||
if test "$2" = "STORED"; then jarOpt="0"; else jarOpt=""; fi
|
||||
filelist="$3"
|
||||
jarFile="$myName.jar"
|
||||
|
||||
for file in $filelist; do
|
||||
buildFile "$filetype" "$file"
|
||||
done
|
||||
|
||||
sys "$JAR" cvM${jarOpt}f "$jarFile" $filelist
|
||||
sys ls -l "$jarFile"
|
||||
sys "$JAR" tvf "$jarFile"
|
||||
|
||||
for file in $filelist; do
|
||||
case "$file" in
|
||||
huge-*) size="$hugeSize" ;;
|
||||
tiny-*) size="$tinySize" ;;
|
||||
esac
|
||||
case "`$JAR tvf $jarFile $file`" in
|
||||
*"$size"*"$file"*) : ;;
|
||||
*) die "Output of \"jar tvf\" is incorrect." ;;
|
||||
esac
|
||||
# Try to minimize disk space used while verifying the jar file.
|
||||
sum1="`sum $file`"
|
||||
sys rm "$file"
|
||||
sys "$JAR" xvf "$jarFile" "$file"
|
||||
sum2="`sum $file`"
|
||||
test "$sum1" = "$sum2" || die "Jar File is corrupted."
|
||||
sys rm "$file"
|
||||
# unzip $jarFile $file
|
||||
# sys rm "$file"
|
||||
done
|
||||
|
||||
sys rm "$jarFile"
|
||||
}
|
||||
|
||||
testJarFile "MostlyEmpty" "DEFLATED" "tiny-1 huge-1 tiny-2 huge-2 tiny-3"
|
||||
testJarFile "MostlyEmpty" "STORED" "tiny-1 huge-1 tiny-2"
|
||||
testJarFile "SlightlyCompressible" "DEFLATED" "tiny-1 huge-1 tiny-2"
|
||||
|
||||
cleanup
|
||||
|
||||
exit 0
|
||||
157
test/jdk/java/util/zip/Available.java
Normal file
157
test/jdk/java/util/zip/Available.java
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2024, 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.
|
||||
*
|
||||
* 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 4028605 4109069 4234207 4401122 8339154
|
||||
* @summary Verify that ZipInputStream, InflaterInputStream, ZipFileInputStream,
|
||||
* ZipFileInflaterInputStream.available() return values according
|
||||
* to their specification or long-standing behavior
|
||||
* @run junit Available
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class Available {
|
||||
|
||||
// ZIP file produced in this test
|
||||
private final Path zip = Path.of("available.jar");
|
||||
|
||||
/**
|
||||
* Create the ZIP file used in this test, containing
|
||||
* one deflated and one stored entry.
|
||||
*
|
||||
* @throws IOException if an unexpected error occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setup() throws IOException {
|
||||
byte[] contents = "contents".repeat(10).getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
// First entry uses DEFLATE method
|
||||
zo.putNextEntry(new ZipEntry("deflated.txt"));
|
||||
zo.write(contents);
|
||||
|
||||
// Second entry uses STORED method
|
||||
ZipEntry stored = new ZipEntry("stored.txt");
|
||||
stored.setMethod(ZipEntry.STORED);
|
||||
stored.setSize(contents.length);
|
||||
CRC32 crc32 = new CRC32();
|
||||
crc32.update(contents);
|
||||
stored.setCrc(crc32.getValue());
|
||||
zo.putNextEntry(stored);
|
||||
zo.write(contents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file created by this test
|
||||
*
|
||||
* @throws IOException if an unexpected error occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipInputStream.available() returns 0 after EOF or
|
||||
* closeEntry, otherwise 1, as specified in the API description.
|
||||
* This tests 4028605 4109069 4234207
|
||||
* @throws IOException if an unexpected error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testZipInputStream() throws IOException {
|
||||
try (InputStream in = Files.newInputStream(zip)) {
|
||||
ZipInputStream z = new ZipInputStream(in);
|
||||
z.getNextEntry();
|
||||
assertEquals(1, z.available());
|
||||
z.read();
|
||||
assertEquals(1, z.available());
|
||||
z.transferTo(OutputStream.nullOutputStream());
|
||||
assertEquals(0, z.available(),
|
||||
"ZipInputStream.available() should return 0 after EOF");
|
||||
|
||||
z.close();
|
||||
assertThrows(IOException.class, () -> z.available(),
|
||||
"Expected an IOException when calling available on a closed stream");
|
||||
}
|
||||
|
||||
try (InputStream in = Files.newInputStream(zip);
|
||||
ZipInputStream z = new ZipInputStream(in)) {
|
||||
z.getNextEntry();
|
||||
z.closeEntry();
|
||||
assertEquals(0, z.available(),
|
||||
"ZipInputStream.available() should return 0 after closeEntry");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFileInputStream|ZipFileInflaterInputStream.available()
|
||||
* return the number of remaining uncompressed bytes.
|
||||
*
|
||||
* This verifies unspecified, but long-standing behavior. See 4401122.
|
||||
*
|
||||
* @throws IOException if an unexpected error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "stored.txt", "deflated.txt" })
|
||||
public void testZipFileStreamsRemainingBytes(String entryName) throws IOException {
|
||||
try (ZipFile zfile = new ZipFile(zip.toFile())) {
|
||||
ZipEntry entry = zfile.getEntry(entryName);
|
||||
// Could be ZipFileInputStream or ZipFileInflaterInputStream
|
||||
InputStream in = zfile.getInputStream(entry);
|
||||
|
||||
int initialAvailable = in.available();
|
||||
|
||||
// Initally, the number of remaining uncompressed bytes is the entry size
|
||||
assertEquals(entry.getSize(), initialAvailable);
|
||||
|
||||
// Read all bytes one by one
|
||||
for (int i = initialAvailable; i > 0; i--) {
|
||||
// Reading a single byte should decrement available by 1
|
||||
in.read();
|
||||
assertEquals(i - 1, in.available(), "Available not decremented");
|
||||
}
|
||||
|
||||
// No remaining uncompressed bytes
|
||||
assertEquals(0, in.available());
|
||||
|
||||
// available() should still return 0 after close
|
||||
in.close();
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
}
|
||||
}
|
||||
68
test/jdk/java/util/zip/Bounds.java
Normal file
68
test/jdk/java/util/zip/Bounds.java
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 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.
|
||||
*
|
||||
* 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 4811913 6894950
|
||||
* @summary Test bounds checking in zip package
|
||||
*/
|
||||
|
||||
import java.util.zip.*;
|
||||
|
||||
public class Bounds {
|
||||
public static void main(String[] args) throws Exception {
|
||||
byte[] b = new byte[0];
|
||||
int offset = 4;
|
||||
int length = Integer.MAX_VALUE - 3;
|
||||
|
||||
try {
|
||||
(new CRC32()).update(b, offset, length);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||
// Correct result
|
||||
}
|
||||
try {
|
||||
(new Deflater()).setDictionary(b, offset, length);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||
// Correct result
|
||||
}
|
||||
try {
|
||||
(new Adler32()).update(b, offset, length);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||
// Correct result
|
||||
}
|
||||
try {
|
||||
(new Deflater()).deflate(b, offset, length);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||
// Correct result
|
||||
}
|
||||
try {
|
||||
(new Inflater()).inflate(b, offset, length);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (ArrayIndexOutOfBoundsException aioobe) {
|
||||
// Correct result
|
||||
}
|
||||
}
|
||||
}
|
||||
205
test/jdk/java/util/zip/ChecksumBase.java
Normal file
205
test/jdk/java/util/zip/ChecksumBase.java
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
/**
|
||||
* Base class for Checksum tests
|
||||
*/
|
||||
public class ChecksumBase {
|
||||
|
||||
private static final byte[] BYTES_123456789 = "123456789".getBytes(StandardCharsets.US_ASCII);
|
||||
|
||||
public static void testAll(Checksum checksum, long expected) {
|
||||
testBytes(checksum, expected);
|
||||
testByteArray(checksum, expected);
|
||||
testWrappedMemorySegment(checksum, expected);
|
||||
testWrappedByteBuffer(checksum, expected);
|
||||
testReadonlyByteBuffer(checksum, expected);
|
||||
testDirectByteBuffer(checksum, expected);
|
||||
testByteArrayOffset(checksum, expected);
|
||||
testDirectByteBufferOffset(checksum, expected);
|
||||
testLittleEndianDirectByteBufferOffset(checksum, expected);
|
||||
testWrappedByteBufferOffset(checksum, expected);
|
||||
testLittleEndianWrappedByteBufferOffset(checksum, expected);
|
||||
testReadonlyByteBufferOffset(checksum, expected);
|
||||
testLittleEndianReadonlyByteBufferOffset(checksum, expected);
|
||||
}
|
||||
|
||||
private static void testBytes(Checksum checksum, long expected) {
|
||||
checksum.reset();
|
||||
for (byte bits : BYTES_123456789) {
|
||||
checksum.update(bits);
|
||||
}
|
||||
checkChecksum(checksum, expected);
|
||||
}
|
||||
|
||||
private static void testByteArray(Checksum checksum, long expected) {
|
||||
checksum.reset();
|
||||
checksum.update(BYTES_123456789);
|
||||
checkChecksum(checksum, expected);
|
||||
}
|
||||
|
||||
private static void testWrappedByteBuffer(Checksum checksum, long expected) {
|
||||
checksum.reset();
|
||||
ByteBuffer bb = ByteBuffer.wrap(BYTES_123456789);
|
||||
checksum.update(bb);
|
||||
checkChecksum(checksum, expected);
|
||||
}
|
||||
|
||||
private static void testWrappedMemorySegment(Checksum checksum, long expected) {
|
||||
checksum.reset();
|
||||
ByteBuffer bb = MemorySegment.ofArray(BYTES_123456789).asByteBuffer();
|
||||
checksum.update(bb);
|
||||
checkChecksum(checksum, expected);
|
||||
}
|
||||
|
||||
private static void testReadonlyByteBuffer(Checksum checksum, long expected) {
|
||||
checksum.reset();
|
||||
ByteBuffer bb = ByteBuffer.wrap(BYTES_123456789).asReadOnlyBuffer();
|
||||
checksum.update(bb);
|
||||
checkChecksum(checksum, expected);
|
||||
}
|
||||
|
||||
private static void testDirectByteBuffer(Checksum checksum, long expected) {
|
||||
checksum.reset();
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(BYTES_123456789.length);
|
||||
bb.put(BYTES_123456789);
|
||||
bb.rewind();
|
||||
checksum.update(bb);
|
||||
checkChecksum(checksum, expected);
|
||||
}
|
||||
|
||||
private static void checkChecksum(Checksum checksum, long expected) {
|
||||
if (checksum.getValue() != expected) {
|
||||
throw new RuntimeException("Calculated checksum result was invalid."
|
||||
+ " Expected " + Long.toHexString(expected)
|
||||
+ ", but got " + Long.toHexString(checksum.getValue()) + ".");
|
||||
}
|
||||
}
|
||||
|
||||
private static void testByteArrayOffset(Checksum checksum, long expected) {
|
||||
byte[] unaligned_bytes_123456789 = new byte[BYTES_123456789.length + 64];
|
||||
for (int i = 0; i < unaligned_bytes_123456789.length - BYTES_123456789.length; i++) {
|
||||
checksum.reset();
|
||||
System.arraycopy(BYTES_123456789, 0, unaligned_bytes_123456789, i, BYTES_123456789.length);
|
||||
checksum.update(unaligned_bytes_123456789, i, BYTES_123456789.length);
|
||||
checkChecksumOffset(checksum, expected, i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testDirectByteBufferOffset(Checksum checksum, long expected) {
|
||||
byte[] unaligned_bytes_123456789 = new byte[BYTES_123456789.length + 64];
|
||||
for (int i = 0; i < unaligned_bytes_123456789.length - BYTES_123456789.length; i++) {
|
||||
checksum.reset();
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(unaligned_bytes_123456789.length);
|
||||
System.arraycopy(BYTES_123456789, 0, unaligned_bytes_123456789, i, BYTES_123456789.length);
|
||||
bb.put(unaligned_bytes_123456789);
|
||||
bb.position(i);
|
||||
bb.limit(i + BYTES_123456789.length);
|
||||
checksum.update(bb);
|
||||
checkChecksumOffset(checksum, expected, i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLittleEndianDirectByteBufferOffset(Checksum checksum, long expected) {
|
||||
byte[] unaligned_bytes_123456789 = new byte[BYTES_123456789.length + 64];
|
||||
for (int i = 0; i < unaligned_bytes_123456789.length - BYTES_123456789.length; i++) {
|
||||
checksum.reset();
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(unaligned_bytes_123456789.length);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
System.arraycopy(BYTES_123456789, 0, unaligned_bytes_123456789, i, BYTES_123456789.length);
|
||||
bb.put(unaligned_bytes_123456789);
|
||||
bb.position(i);
|
||||
bb.limit(i + BYTES_123456789.length);
|
||||
checksum.update(bb);
|
||||
checkChecksumOffset(checksum, expected, i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testWrappedByteBufferOffset(Checksum checksum, long expected) {
|
||||
byte[] unaligned_bytes_123456789 = new byte[BYTES_123456789.length + 64];
|
||||
for (int i = 0; i < unaligned_bytes_123456789.length - BYTES_123456789.length; i++) {
|
||||
checksum.reset();
|
||||
System.arraycopy(BYTES_123456789, 0, unaligned_bytes_123456789, i, BYTES_123456789.length);
|
||||
ByteBuffer bb = ByteBuffer.wrap(unaligned_bytes_123456789);
|
||||
bb.position(i);
|
||||
bb.limit(i + BYTES_123456789.length);
|
||||
checksum.update(bb);
|
||||
checkChecksumOffset(checksum, expected, i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLittleEndianWrappedByteBufferOffset(Checksum checksum, long expected) {
|
||||
byte[] unaligned_bytes_123456789 = new byte[BYTES_123456789.length + 64];
|
||||
for (int i = 0; i < unaligned_bytes_123456789.length - BYTES_123456789.length; i++) {
|
||||
checksum.reset();
|
||||
System.arraycopy(BYTES_123456789, 0, unaligned_bytes_123456789, i, BYTES_123456789.length);
|
||||
ByteBuffer bb = ByteBuffer.wrap(unaligned_bytes_123456789);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
bb.position(i);
|
||||
bb.limit(i + BYTES_123456789.length);
|
||||
checksum.update(bb);
|
||||
checkChecksumOffset(checksum, expected, i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testReadonlyByteBufferOffset(Checksum checksum, long expected) {
|
||||
byte[] unaligned_bytes_123456789 = new byte[BYTES_123456789.length + 64];
|
||||
for (int i = 0; i < unaligned_bytes_123456789.length - BYTES_123456789.length; i++) {
|
||||
checksum.reset();
|
||||
System.arraycopy(BYTES_123456789, 0, unaligned_bytes_123456789, i, BYTES_123456789.length);
|
||||
ByteBuffer bb = ByteBuffer.wrap(unaligned_bytes_123456789).asReadOnlyBuffer();
|
||||
bb.position(i);
|
||||
bb.limit(i + BYTES_123456789.length);
|
||||
checksum.update(bb);
|
||||
checkChecksumOffset(checksum, expected, i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLittleEndianReadonlyByteBufferOffset(Checksum checksum, long expected) {
|
||||
byte[] unaligned_bytes_123456789 = new byte[BYTES_123456789.length + 64];
|
||||
for (int i = 0; i < unaligned_bytes_123456789.length - BYTES_123456789.length; i++) {
|
||||
checksum.reset();
|
||||
System.arraycopy(BYTES_123456789, 0, unaligned_bytes_123456789, i, BYTES_123456789.length);
|
||||
ByteBuffer bb = ByteBuffer.wrap(unaligned_bytes_123456789).asReadOnlyBuffer();
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
bb.position(i);
|
||||
bb.limit(i + BYTES_123456789.length);
|
||||
checksum.update(bb);
|
||||
checkChecksumOffset(checksum, expected, i);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkChecksumOffset(Checksum checksum, long expected, int offset) {
|
||||
if (checksum.getValue() != expected) {
|
||||
throw new RuntimeException("Calculated CRC32C result was invalid. Array offset "
|
||||
+ offset + ". Expected: " + Long.toHexString(expected) + ", Got: "
|
||||
+ Long.toHexString(checksum.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
212
test/jdk/java/util/zip/CloseInflaterDeflaterTest.java
Normal file
212
test/jdk/java/util/zip/CloseInflaterDeflaterTest.java
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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.
|
||||
*
|
||||
* 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 8193682 8278794 8284771
|
||||
* @summary Test Infinite loop while writing on closed Deflater and Inflater.
|
||||
* @run junit CloseInflaterDeflaterTest
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Random;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.DeflaterInputStream;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.InflaterOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class CloseInflaterDeflaterTest {
|
||||
|
||||
// Number of bytes to write/read from Deflater/Inflater
|
||||
private static final int INPUT_LENGTH= 512;
|
||||
// OutputStream that will throw an exception during a write operation
|
||||
private static OutputStream outStream = new OutputStream() {
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {}
|
||||
@Override
|
||||
public void write(int b) throws IOException {}
|
||||
};
|
||||
// InputStream that will throw an exception during a read operation
|
||||
private static InputStream inStream = new InputStream() {
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
throw new IOException();
|
||||
}
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException { throw new IOException();}
|
||||
@Override
|
||||
public int read() throws IOException { throw new IOException();}
|
||||
};
|
||||
// Input bytes for read/write operation
|
||||
private static byte[] inputBytes = new byte[INPUT_LENGTH];
|
||||
// Random function to add bytes to inputBytes
|
||||
private static Random rand = new Random();
|
||||
|
||||
/**
|
||||
* MethodSource to specify whether to use close() or finish() of OutputStream
|
||||
*
|
||||
* @return Stream indicating which method to use for closing OutputStream
|
||||
*/
|
||||
public static Stream<Boolean> testOutputStreams() {
|
||||
return Stream.of(true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* MethodSource to specify on which outputstream closeEntry() has to be called
|
||||
*
|
||||
* @return Stream consisting of either a JarOutputStream or ZipOutputStream
|
||||
*/
|
||||
public static Stream<ZipOutputStream> testZipAndJar() throws IOException{
|
||||
return Stream.of(new JarOutputStream(outStream), new ZipOutputStream(outStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add inputBytes array with random bytes to write into OutputStream
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void before_test()
|
||||
{
|
||||
rand.nextBytes(inputBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for infinite loop by writing bytes to closed GZIPOutputStream
|
||||
*
|
||||
* @param useCloseMethod indicates whether to use Close() or finish() method
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("testOutputStreams")
|
||||
public void testGZip(boolean useCloseMethod) throws IOException {
|
||||
GZIPOutputStream gzip = new GZIPOutputStream(outStream);
|
||||
gzip.write(inputBytes, 0, INPUT_LENGTH);
|
||||
assertThrows(IOException.class, () -> {
|
||||
// Close GZIPOutputStream
|
||||
if (useCloseMethod) {
|
||||
gzip.close();
|
||||
} else {
|
||||
gzip.finish();
|
||||
}
|
||||
});
|
||||
// Write on a closed GZIPOutputStream, closed Deflater IllegalStateException expected
|
||||
assertThrows(IllegalStateException.class , () -> gzip.write(inputBytes, 0, INPUT_LENGTH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for infinite loop by writing bytes to closed DeflaterOutputStream
|
||||
*
|
||||
* @param useCloseMethod indicates whether to use Close() or finish() method
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("testOutputStreams")
|
||||
public void testDeflaterOutputStream(boolean useCloseMethod) throws IOException {
|
||||
DeflaterOutputStream def = new DeflaterOutputStream(outStream);
|
||||
assertThrows(IOException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH));
|
||||
assertThrows(IOException.class, () -> {
|
||||
// Close DeflaterOutputStream
|
||||
if (useCloseMethod) {
|
||||
def.close();
|
||||
} else {
|
||||
def.finish();
|
||||
}
|
||||
});
|
||||
// Write on a closed DeflaterOutputStream, IllegalStateException is expected
|
||||
assertThrows(IllegalStateException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for infinite loop by reading bytes from closed DeflaterInputStream
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testDeflaterInputStream() throws IOException {
|
||||
DeflaterInputStream def = new DeflaterInputStream(inStream);
|
||||
assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH));
|
||||
// Close DeflaterInputStream
|
||||
def.close();
|
||||
// Read from a closed DeflaterInputStream, closed Deflater IOException expected
|
||||
assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for infinite loop by writing bytes to closed InflaterOutputStream
|
||||
*
|
||||
* Note: Disabling this test as it is failing intermittently.
|
||||
* @param useCloseMethod indicates whether to use Close() or finish() method
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Disabled
|
||||
@ParameterizedTest
|
||||
@MethodSource("testOutputStreams")
|
||||
public void testInflaterOutputStream(boolean useCloseMethod) throws IOException {
|
||||
InflaterOutputStream inf = new InflaterOutputStream(outStream);
|
||||
assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH));
|
||||
assertThrows(IOException.class , () -> {
|
||||
// Close InflaterOutputStream
|
||||
if (useCloseMethod) {
|
||||
inf.close();
|
||||
} else {
|
||||
inf.finish();
|
||||
}
|
||||
});
|
||||
// Write on a closed InflaterOutputStream , closed Inflater IOException expected
|
||||
assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for infinite loop by writing bytes to closed ZipOutputStream/JarOutputStream
|
||||
*
|
||||
* @param zip will be the instance of either JarOutputStream or ZipOutputStream
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest(autoCloseArguments = false)
|
||||
@MethodSource("testZipAndJar")
|
||||
public void testZipCloseEntry(ZipOutputStream zip) throws IOException {
|
||||
assertThrows(IOException.class , () -> zip.putNextEntry(new ZipEntry("")));
|
||||
zip.write(inputBytes, 0, INPUT_LENGTH);
|
||||
assertThrows(IOException.class , () -> zip.closeEntry());
|
||||
// Write on a closed ZipOutputStream , IllegalStateException is expected
|
||||
assertThrows(IllegalStateException.class , () -> zip.write(inputBytes, 0, INPUT_LENGTH));
|
||||
}
|
||||
|
||||
}
|
||||
174
test/jdk/java/util/zip/ConstructDeflaterInput.java
Normal file
174
test/jdk/java/util/zip/ConstructDeflaterInput.java
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 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.
|
||||
*
|
||||
* 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 4679743 8148624
|
||||
* @summary Test parts of DeflaterInputStream code that don't really do I/O.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class ConstructDeflaterInput {
|
||||
|
||||
static class MyDeflater extends Deflater {
|
||||
volatile boolean ended = false;
|
||||
public void end() {
|
||||
ended = true;
|
||||
super.end();
|
||||
}
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
final MyDeflater def = new MyDeflater();
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(
|
||||
"hello, world".getBytes());
|
||||
DeflaterInputStream dis = null;
|
||||
byte[] b = new byte[512];
|
||||
|
||||
// Check construction
|
||||
//
|
||||
try {
|
||||
dis = new DeflaterInputStream(null);
|
||||
fail();
|
||||
} catch (NullPointerException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
dis = new DeflaterInputStream(bais, null);
|
||||
fail();
|
||||
} catch (NullPointerException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
dis = new DeflaterInputStream(bais, def, 0);
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
// Check sanity checks in read methods
|
||||
//
|
||||
dis = new DeflaterInputStream(bais, def);
|
||||
|
||||
try {
|
||||
dis.read(null, 5, 2);
|
||||
fail();
|
||||
} catch (NullPointerException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
dis.read(b, -1, 0);
|
||||
fail();
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
dis.read(b, 0, -1);
|
||||
fail();
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
dis.read(b, 0, 600);
|
||||
fail();
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
try {
|
||||
len = dis.read(b, 0, 0);
|
||||
check(len == 0);
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
fail("Read of length 0 should return 0, but returned " + len);
|
||||
}
|
||||
|
||||
try {
|
||||
dis.skip(-1);
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
// Check unsupported operations
|
||||
//
|
||||
check(!dis.markSupported());
|
||||
check(dis.available() == 1);
|
||||
check(!def.ended);
|
||||
try {
|
||||
dis.reset();
|
||||
fail();
|
||||
} catch (IOException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
// Check close
|
||||
//
|
||||
dis.close();
|
||||
check(!def.ended);
|
||||
|
||||
try {
|
||||
dis.available();
|
||||
fail();
|
||||
} catch (IOException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
int x = dis.read();
|
||||
fail();
|
||||
} catch (IOException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
dis.skip(1);
|
||||
fail();
|
||||
} catch (IOException ex) {
|
||||
pass();
|
||||
}
|
||||
java.lang.ref.Reference.reachabilityFence(def);
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {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 check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
151
test/jdk/java/util/zip/ConstructInflaterOutput.java
Normal file
151
test/jdk/java/util/zip/ConstructInflaterOutput.java
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 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.
|
||||
*
|
||||
* 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 4679743 8148624
|
||||
* @summary Test parts of InflaterOutputStream code that don't really do I/O.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class ConstructInflaterOutput {
|
||||
|
||||
static class MyInflater extends Inflater {
|
||||
volatile boolean ended = false;
|
||||
public void end() {
|
||||
ended = true;
|
||||
super.end();
|
||||
}
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
final MyInflater inf = new MyInflater();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InflaterOutputStream ios = null;
|
||||
byte[] b = new byte[512];
|
||||
|
||||
// Check construction
|
||||
//
|
||||
try {
|
||||
ios = new InflaterOutputStream(null);
|
||||
fail();
|
||||
} catch (NullPointerException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
ios = new InflaterOutputStream(baos, null);
|
||||
fail();
|
||||
} catch (NullPointerException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
ios = new InflaterOutputStream(baos, inf, 0);
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
// Check sanity checks in write methods
|
||||
//
|
||||
ios = new InflaterOutputStream(baos, inf);
|
||||
|
||||
try {
|
||||
ios.write(null, 5, 2);
|
||||
fail();
|
||||
} catch (NullPointerException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
ios.write(b, -1, 0);
|
||||
fail();
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
ios.write(b, 0, -1);
|
||||
fail();
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
try {
|
||||
ios.write(b, 0, 600);
|
||||
fail();
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
ios.flush();
|
||||
check(!inf.ended);
|
||||
ios.flush();
|
||||
check(!inf.ended);
|
||||
ios.finish();
|
||||
check(!inf.ended);
|
||||
ios.close();
|
||||
check(!inf.ended);
|
||||
try {
|
||||
ios.finish();
|
||||
fail();
|
||||
} catch (IOException ex) {
|
||||
pass();
|
||||
}
|
||||
try {
|
||||
ios.write(13);
|
||||
fail();
|
||||
} catch (IOException ex) {
|
||||
pass();
|
||||
}
|
||||
|
||||
ios = new InflaterOutputStream(baos);
|
||||
ios.flush();
|
||||
ios.finish();
|
||||
ios.close();
|
||||
try {
|
||||
ios.flush();
|
||||
} catch (IOException ex) {
|
||||
pass();
|
||||
}
|
||||
java.lang.ref.Reference.reachabilityFence(inf);
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {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 check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
268
test/jdk/java/util/zip/CopyZipFile.java
Normal file
268
test/jdk/java/util/zip/CopyZipFile.java
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright Amazon.com Inc. 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.
|
||||
*
|
||||
* 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 8253952
|
||||
* @summary Test behaviour when copying ZipEntries between zip files.
|
||||
* @run junit CopyZipFile
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Enumeration;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CopyZipFile {
|
||||
// ZIP file created in this test
|
||||
private Path zip = Path.of("first.zip");
|
||||
// The content to put in each entry
|
||||
private static final byte[] TEST_STRING = "TestTestTest".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
/**
|
||||
* Create the sample ZIP file used in this test, including a STORED entry
|
||||
* and DEFLATE entries with various compression levels.
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void createZip() throws IOException {
|
||||
// By default, ZipOutputStream creates zip files with Local File Headers
|
||||
// without size, compressed size and crc values and an extra Data
|
||||
// Descriptor (see https://en.wikipedia.org/wiki/Zip_(file_format)
|
||||
// after the data belonging to that entry with these values if in the
|
||||
// corresponding ZipEntry one of the size, compressedSize or crc fields is
|
||||
// equal to '-1' (which is the default for newly created ZipEntries).
|
||||
try (OutputStream os = Files.newOutputStream(zip) ;
|
||||
ZipOutputStream zos = new ZipOutputStream(os)) {
|
||||
// First file will be compressed with DEFAULT_COMPRESSION (i.e. -1 or 6)
|
||||
zos.setLevel(Deflater.DEFAULT_COMPRESSION);
|
||||
zos.putNextEntry(new ZipEntry("DEFAULT_COMPRESSION.txt"));
|
||||
zos.write(TEST_STRING);
|
||||
|
||||
// Second file won't be compressed at all (i.e. STORED)
|
||||
zos.setMethod(ZipOutputStream.STORED);
|
||||
ZipEntry ze = new ZipEntry("STORED.txt");
|
||||
ze.setSize(TEST_STRING.length);
|
||||
ze.setCompressedSize(TEST_STRING.length);
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(TEST_STRING);
|
||||
ze.setCrc(crc.getValue());
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(TEST_STRING);
|
||||
|
||||
// Third file will be compressed with NO_COMPRESSION (i.e. 0)
|
||||
zos.setMethod(ZipOutputStream.DEFLATED);
|
||||
zos.setLevel(Deflater.NO_COMPRESSION);
|
||||
zos.putNextEntry(new ZipEntry("NO_COMPRESSION.txt"));
|
||||
zos.write(TEST_STRING);
|
||||
|
||||
// Fourth file will be compressed with BEST_SPEED (i.e. 1)
|
||||
zos.setLevel(Deflater.BEST_SPEED);
|
||||
zos.putNextEntry(new ZipEntry("BEST_SPEED.txt"));
|
||||
zos.write(TEST_STRING);
|
||||
|
||||
// Fifth file will be compressed with BEST_COMPRESSION (i.e. 9)
|
||||
zos.setLevel(Deflater.BEST_COMPRESSION);
|
||||
zos.putNextEntry(new ZipEntry("BEST_COMPRESSION.txt"));
|
||||
zos.write(TEST_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all entries using ZipInputStream.getNextEntry and copy them
|
||||
* to a new zip file using ZipOutputStream.putNextEntry. This only works
|
||||
* reliably because the input zip file has no values for the size, compressedSize
|
||||
* and crc values of streamed zip entries in the local file header and
|
||||
* therefore the ZipEntry objects created by ZipOutputStream.getNextEntry
|
||||
* will have all these fields set to '-1'.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void copyFromZipInputStreamToZipOutputStream() throws IOException {
|
||||
|
||||
try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(zip));
|
||||
ZipOutputStream zos = new ZipOutputStream(OutputStream.nullOutputStream())) {
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
// ZipInputStream.getNextEntry() only reads the Local File Header of a zip entry,
|
||||
// so for the zip file we've just generated the ZipEntry fields 'size', 'compressedSize`
|
||||
// and 'crc' for deflated entries should be uninitialized (i.e. '-1').
|
||||
System.out.println(
|
||||
String.format("name=%s, clen=%d, len=%d, crc=%d",
|
||||
entry.getName(), entry.getCompressedSize(), entry.getSize(), entry.getCrc()));
|
||||
if (entry.getMethod() == ZipEntry.DEFLATED) {
|
||||
// Expect size, compressed size and crc to not be initialized at this point
|
||||
assertEquals(-1, entry.getCompressedSize());
|
||||
assertEquals(-1, entry.getSize());
|
||||
assertEquals(-1, entry.getCrc());
|
||||
}
|
||||
zos.putNextEntry(entry);
|
||||
zis.transferTo(zos);
|
||||
// After all the data belonging to a zip entry has been inflated (i.e. after ZipInputStream.read()
|
||||
// returned '-1'), it is guaranteed that the ZipInputStream will also have consumed the Data
|
||||
// Descriptor (if any) after the data and will have updated the 'size', 'compressedSize' and 'crc'
|
||||
// fields of the ZipEntry object.
|
||||
System.out.println(
|
||||
String.format("name=%s, clen=%d, len=%d, crc=%d\n",
|
||||
entry.getName(), entry.getCompressedSize(), entry.getSize(), entry.getCrc()));
|
||||
// Expect size, compressed size and crc to be initialized at this point
|
||||
assertNotEquals(-1, entry.getCompressedSize());
|
||||
assertNotEquals(-1, entry.getSize());
|
||||
assertNotEquals(-1, entry.getCrc());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all entries using the ZipFile class and copy them to a new zip file
|
||||
* using ZipOutputStream.putNextEntry.
|
||||
* The ZipFile class reads all the zip entries from the Central
|
||||
* Directory, which has accurate information for size, compressedSize and crc.
|
||||
* This means that all ZipEntry objects returned from ZipFile will have correct
|
||||
* settings for these fields.
|
||||
* If the compression level was different in the input zip file (which we can't know
|
||||
* because the zip file format doesn't record this information), the
|
||||
* size of the re-compressed entry we are writing to the ZipOutputStream might differ
|
||||
* from the original compressed size recorded in the ZipEntry. This would result in an
|
||||
* "invalid entry compressed size" ZipException if ZipOutputStream wouldn't ignore
|
||||
* the implicitely set compressed size attribute of ZipEntries read from a ZipFile
|
||||
* or ZipInputStream.
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void copyFromZipFileToZipOutputStream() throws IOException {
|
||||
try (ZipOutputStream zos = new ZipOutputStream(OutputStream.nullOutputStream());
|
||||
ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry entry;
|
||||
Enumeration<? extends ZipEntry> entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
entry = entries.nextElement();
|
||||
System.out.println(
|
||||
String.format("name=%s, clen=%d, len=%d, crc=%d\n",
|
||||
entry.getName(), entry.getCompressedSize(),
|
||||
entry.getSize(), entry.getCrc()));
|
||||
// Expect size, compressed size and crc to be initialized at this point
|
||||
assertNotEquals(-1, entry.getCompressedSize());
|
||||
assertNotEquals(-1, entry.getSize());
|
||||
assertNotEquals(-1, entry.getCrc());
|
||||
|
||||
zos.putNextEntry(entry);
|
||||
try (InputStream is = zf.getInputStream(entry)) {
|
||||
is.transferTo(zos);
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the compressed size is set explicitly using ZipEntry.setCompressedSize(),
|
||||
* then the entry will be restreamed with a data descriptor and the compressed size
|
||||
* recomputed. If the source compression level was different from the target compression
|
||||
* level, the compressed sizes may differ and a ZipException will be thrown
|
||||
* when the entry is closed in ZipOutputStream.closeEntry
|
||||
*
|
||||
* @throws IOException if an unexpected IOException is thrown
|
||||
*/
|
||||
@Test
|
||||
public void explicitCompressedSizeWithDifferentCompressionLevels() throws IOException {
|
||||
try (ZipOutputStream zos = new ZipOutputStream(OutputStream.nullOutputStream());
|
||||
ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
// Be explicit about the default compression level
|
||||
zos.setLevel(Deflater.DEFAULT_COMPRESSION);
|
||||
|
||||
Enumeration<? extends ZipEntry> entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
|
||||
// Explicitly setting the compressed size will disable data descriptors
|
||||
// and enable validation that the compressed size in the ZipEntry matches the
|
||||
// actual compressed size written by ZipOutputStream
|
||||
entry.setCompressedSize(entry.getCompressedSize());
|
||||
|
||||
try (InputStream is = zf.getInputStream(entry)) {
|
||||
zos.putNextEntry(entry);
|
||||
is.transferTo(zos);
|
||||
// Some compression levels lead to unexpected recompressed sizes when closing the entry
|
||||
switch (entry.getName()) {
|
||||
case "DEFAULT_COMPRESSION.txt" -> {
|
||||
// DEFAULT_COMPRESSION matches expected size
|
||||
zos.closeEntry();
|
||||
}
|
||||
case "STORED.txt" -> {
|
||||
// STORED should not throw
|
||||
zos.closeEntry();
|
||||
}
|
||||
case "NO_COMPRESSION.txt", "BEST_SPEED.txt" -> {
|
||||
// NO_COMPRESSION and BEST_SPEED should lead to an unexpected recompressed size
|
||||
ZipException ze = assertThrows(ZipException.class, () -> {
|
||||
zos.closeEntry();
|
||||
});
|
||||
|
||||
// Hack to fix and close the offending zip entry with the correct recompressed size.
|
||||
// The exception message is something like:
|
||||
// "invalid entry compressed size (expected 12 but got 7 bytes)"
|
||||
// and we need to extract the second integer.
|
||||
Pattern cSize = Pattern.compile("\\d+");
|
||||
Matcher m = cSize.matcher(ze.getMessage());
|
||||
m.find();
|
||||
m.find();
|
||||
entry.setCompressedSize(Integer.parseInt(m.group()));
|
||||
zos.closeEntry();
|
||||
}
|
||||
case "BEST_COMPRESSION.txt" -> {
|
||||
// BEST_COMPRESSION produces the same compressed
|
||||
// size as DEFAULT_COMPRESSION for sample content
|
||||
zos.closeEntry();
|
||||
}
|
||||
default -> {
|
||||
throw new IllegalArgumentException("Unexpected entry " + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
125
test/jdk/java/util/zip/DataDescriptor.java
Normal file
125
test/jdk/java/util/zip/DataDescriptor.java
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*
|
||||
* 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 6334171
|
||||
* @summary Test that zip file's data descriptor is written correctly.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
/**
|
||||
* Bug 6252735 ZipEntry contains wasteful "temporary storage" fields introduced
|
||||
* a regression. The value of the general purpose flag bit in a LOC header is
|
||||
* written incorrectly, because it is computed on stale data.
|
||||
* <p>
|
||||
* With the bug present, zipbytes2 is written incorrectly: when the LOC
|
||||
* header is written, (flag(e) & 8) == 8. This is correct: the data will be
|
||||
* compressed, so we don't have data length, etc. yet; that should be written
|
||||
* in the DataDescriptor after the data itself is written. However, when the
|
||||
* ZipOutputStream that wraps zipbytes2 is closed, the data length _is_
|
||||
* available, therefore (flag(e) & 8) = 0), therefore the DataDescriptor is
|
||||
* not written. This is why, with the bug, zipbytes1.length == sizeof(ext
|
||||
* header) + zipbytes2.length.
|
||||
* <p>
|
||||
* The result is an invalid LOC header in zipbytes2. So when we again use
|
||||
* copyZip, we attempt to read a data length not from the LOC header but from
|
||||
* the non-existent EXT header, and at that position in the file is some
|
||||
* arbitrary and incorrect value.
|
||||
*/
|
||||
public class DataDescriptor {
|
||||
static void copyZip(ZipInputStream in, ZipOutputStream out) throws IOException {
|
||||
byte[] buffer = new byte[1 << 14];
|
||||
for (ZipEntry ze; (ze = in.getNextEntry()) != null; ) {
|
||||
out.putNextEntry(ze);
|
||||
// When the bug is present, it shows up here. The second call to
|
||||
// copyZip will throw an exception while reading data.
|
||||
for (int nr; 0 < (nr = in.read(buffer)); ) {
|
||||
out.write(buffer, 0, nr);
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
|
||||
private static void realMain(String[] args) throws Throwable {
|
||||
// Create zip output in byte array zipbytes
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos);
|
||||
ZipEntry e = new ZipEntry("testdir/foo");
|
||||
byte[] data = "entry data".getBytes("ASCII");
|
||||
zos.putNextEntry(e);
|
||||
zos.write(data);
|
||||
zos.close();
|
||||
byte[] zipbytes1 = baos.toByteArray();
|
||||
int length1 = zipbytes1.length;
|
||||
System.out.println("zip bytes pre-copy length=" + length1);
|
||||
|
||||
// Make a ZipInputStream around zipbytes, and use
|
||||
// copyZip to get a new byte array.
|
||||
ZipInputStream zis =
|
||||
new ZipInputStream(
|
||||
new ByteArrayInputStream(zipbytes1));
|
||||
baos.reset();
|
||||
zos = new ZipOutputStream(baos);
|
||||
copyZip(zis, zos);
|
||||
zos.close();
|
||||
byte[] zipbytes2 = baos.toByteArray();
|
||||
int length2 = zipbytes2.length;
|
||||
// When the bug is present, pre- and post-copy lengths are different!
|
||||
System.out.println("zip bytes post-copy length=" + length2);
|
||||
|
||||
equal(length1, length2);
|
||||
check(Arrays.equals(zipbytes1, zipbytes2));
|
||||
|
||||
// Now use copyZip again on the bytes resulting from the previous
|
||||
// copy. When the bug is present, copyZip will get an exception this
|
||||
// time.
|
||||
baos.reset();
|
||||
zos = new ZipOutputStream(baos);
|
||||
copyZip(new ZipInputStream(new ByteArrayInputStream(zipbytes2)), zos);
|
||||
zos.close();
|
||||
byte[] zipbytes3 = baos.toByteArray();
|
||||
int length3 = zipbytes3.length;
|
||||
System.out.println("zip bytes post-copy length=" + length3);
|
||||
|
||||
equal(length1, length3);
|
||||
check(Arrays.equals(zipbytes1, zipbytes3));
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {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 check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
||||
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
||||
180
test/jdk/java/util/zip/DataDescriptorIgnoreCrcAndSizeFields.java
Normal file
180
test/jdk/java/util/zip/DataDescriptorIgnoreCrcAndSizeFields.java
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2024, 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.
|
||||
*
|
||||
* 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 8321396
|
||||
* @summary Verify that ZipInputStream ignores non-zero, incorrect 'crc',
|
||||
* 'compressed size' and 'uncompressed size' values when in streaming mode.
|
||||
* @run junit DataDescriptorIgnoreCrcAndSizeFields
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class DataDescriptorIgnoreCrcAndSizeFields {
|
||||
|
||||
/**
|
||||
* Verify that ZipInputStream correctly ignores values from a LOC header's
|
||||
* 'crc', 'compressed size' and 'uncompressed size' fields, when in
|
||||
* streaming mode and these fields are incorrectly set to non-zero values.
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnoreCrcAndSizeValuesInStreamingMode() throws IOException {
|
||||
// ZIP with incorrect 'CRC', 'compressed size' and 'uncompressed size' values
|
||||
byte[] zip = zipWithIncorrectCrcAndSizeValuesInLocalHeader();
|
||||
|
||||
// ZipInputStream should ignore the incorrect field values
|
||||
try (ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(zip))) {
|
||||
ZipEntry first = in.getNextEntry();
|
||||
assertNotNull(first, "Zip file is unexpectedly missing first entry");
|
||||
|
||||
// CRC, compressed size and size should be uninitialized at this point
|
||||
assertCrcAndSize(first, -1, -1, -1);
|
||||
// Check that name and contents is as expected
|
||||
assertNameAndContents("first", first, in);
|
||||
// At this point, ZipInputStream should have read correct values from the data descriptor
|
||||
assertCrcAndSize(first, crc32("first"), compressedSize("first"), uncompressedSize("first"));
|
||||
|
||||
// For extra caution, also read and validate the second entry
|
||||
ZipEntry second = in.getNextEntry();
|
||||
assertNotNull(second, "Zip file is unexpectedly missing second entry");
|
||||
|
||||
// CRC, compressed size and size should be uninitialized at this point
|
||||
assertCrcAndSize(second, -1, -1, -1);
|
||||
// Check that name and contents is as expected
|
||||
assertNameAndContents("second", second, in);
|
||||
// At this point, ZipInputStream should have read correct values from the data descriptor
|
||||
assertCrcAndSize(second, crc32("second"), compressedSize("second"), uncompressedSize("second"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the given ZipEntry has the expected name and that
|
||||
* the expected content can be read from the ZipInputStream
|
||||
* @param expected the expected name and content
|
||||
* @param entry the entry to check the name of
|
||||
* @param in the ZipInputStream to check the entry content of
|
||||
* @throws IOException if an IO exception occurs
|
||||
*/
|
||||
private static void assertNameAndContents(String expected, ZipEntry entry, ZipInputStream in) throws IOException {
|
||||
assertEquals(expected, entry.getName());
|
||||
assertArrayEquals(expected.getBytes(StandardCharsets.UTF_8), in.readAllBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a ZipEntry has the expected CRC-32, compressed size and uncompressed size values
|
||||
* @param entry the ZipEntry to validate
|
||||
* @param expectedCrc the expected CRC-32 value
|
||||
* @param expectedCompressedSize the exprected compressed size value
|
||||
* @param expectedSize the expected size value
|
||||
*/
|
||||
private static void assertCrcAndSize(ZipEntry entry, long expectedCrc, long expectedCompressedSize, long expectedSize) {
|
||||
assertEquals(expectedCrc, entry.getCrc());
|
||||
assertEquals(expectedCompressedSize, entry.getCompressedSize());
|
||||
assertEquals(expectedSize, entry.getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CRC-32 value for the given string encoded in UTF-8
|
||||
* @param content the string to produce a CRC-32 checksum for
|
||||
* @return the CRC-value of the encoded string
|
||||
*/
|
||||
private long crc32(String content) {
|
||||
CRC32 crc32 = new CRC32();
|
||||
crc32.update(content.getBytes(StandardCharsets.UTF_8));
|
||||
return crc32.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of the given content encoded in UTF-8
|
||||
* @param content the content to return the encoded length for
|
||||
* @return the uncompressed size of the encoded content
|
||||
*/
|
||||
private long uncompressedSize(String content) {
|
||||
return content.getBytes(StandardCharsets.UTF_8).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the given content, as if it was encoded in UTF-8 and then deflated
|
||||
* @param content the content to get the compressed size of
|
||||
* @return the compressed size of the content
|
||||
* @throws IOException if an IO exception occurs
|
||||
*/
|
||||
private long compressedSize(String content) throws IOException {
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
try (OutputStream o = new DeflaterOutputStream(bao, new Deflater(Deflater.DEFAULT_COMPRESSION, true))) {
|
||||
o.write(content.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return bao.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* When a ZIP entry is created in 'streaming' mode, the 'general purpose bit flag' 3
|
||||
* is set, and the fields crc-32, compressed size and uncompressed size are set to
|
||||
* zero in the local header.
|
||||
*
|
||||
* Certain legacy ZIP tools incorrectly set non-zero values for one or more of these
|
||||
* three fields when in streaming mode.
|
||||
*
|
||||
* This method creates a ZIP where the first entry has a local header where the
|
||||
* mentioned fields are set to a non-zero, incorrect values. The second entry
|
||||
* has the correct zero values for these fields.
|
||||
*/
|
||||
private static byte[] zipWithIncorrectCrcAndSizeValuesInLocalHeader() throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
// Write a first entry
|
||||
zo.putNextEntry(new ZipEntry("first"));
|
||||
zo.write("first".getBytes(StandardCharsets.UTF_8));
|
||||
// Add a second entry
|
||||
zo.putNextEntry(new ZipEntry("second"));
|
||||
zo.write("second".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
// ZipOutputStream correctly produces local headers with zero crc and sizes values
|
||||
byte[] zip = out.toByteArray();
|
||||
|
||||
// Buffer for updating the local header values
|
||||
ByteBuffer buffer = ByteBuffer.wrap(zip).order(ByteOrder.LITTLE_ENDIAN);
|
||||
// Set the CRC-32 field to an incorrect value
|
||||
buffer.putShort(ZipEntry.LOCCRC, (short) 42);
|
||||
// Set the compressed size to an incorrect value
|
||||
buffer.putShort(ZipEntry.LOCSIZ, (short) 42);
|
||||
// Set the uncompressed size to an incorrect value
|
||||
buffer.putShort(ZipEntry.LOCLEN, (short) 42);
|
||||
|
||||
return zip;
|
||||
}
|
||||
}
|
||||
161
test/jdk/java/util/zip/DataDescriptorSignatureMissing.java
Normal file
161
test/jdk/java/util/zip/DataDescriptorSignatureMissing.java
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright 2012 Google, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2023, 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.
|
||||
*
|
||||
* 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 8056934
|
||||
* @summary Verify the ability to read zip files whose local header
|
||||
* data descriptor is missing the optional signature
|
||||
* <p>
|
||||
* No way to adapt the technique in this test to get a ZIP64 zip file
|
||||
* without data descriptors was found.
|
||||
* @run junit DataDescriptorSignatureMissing
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class DataDescriptorSignatureMissing {
|
||||
|
||||
/**
|
||||
* Verify that ZipInputStream correctly parses a ZIP with a Data Descriptor without
|
||||
* the recommended but optional signature.
|
||||
*/
|
||||
@Test
|
||||
public void shouldParseSignaturelessDescriptor() throws IOException {
|
||||
// The ZIP with a signature-less descriptor
|
||||
byte[] zip = makeZipWithSignaturelessDescriptor();
|
||||
|
||||
// ZipInputStream should read the signature-less data descriptor
|
||||
try (ZipInputStream in = new ZipInputStream(
|
||||
new ByteArrayInputStream(zip))) {
|
||||
ZipEntry first = in.getNextEntry();
|
||||
assertNotNull(first, "Zip file is unexpectedly missing first entry");
|
||||
assertEquals("first", first.getName());
|
||||
assertArrayEquals("first".getBytes(StandardCharsets.UTF_8), in.readAllBytes());
|
||||
|
||||
ZipEntry second = in.getNextEntry();
|
||||
assertNotNull(second, "Zip file is unexpectedly missing second entry");
|
||||
assertEquals("second", second.getName());
|
||||
assertArrayEquals("second".getBytes(StandardCharsets.UTF_8), in.readAllBytes());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The 'Data descriptor' record is used to facilitate ZIP streaming. If the size of an
|
||||
* entry is unknown at the time the LOC header is written, bit 3 of the General Purpose Bit Flag
|
||||
* is set, and the File data is immediately followed by the 'Data descriptor' record. This record
|
||||
* then contains the compressed and uncompressed sizes of the entry and also the CRC value.
|
||||
*
|
||||
* The 'Data descriptor' record is usually preceded by the recommended, but optional
|
||||
* signature value 0x08074b50.
|
||||
*
|
||||
* A ZIP entry in streaming mode has the following structure:
|
||||
*
|
||||
* ------ Local File Header ------
|
||||
* 000000 signature 0x04034b50
|
||||
* 000004 version 20
|
||||
* 000006 flags 0x0808 # Notice bit 3 is set
|
||||
* [..] Omitted for brevity
|
||||
*
|
||||
* ------ File Data ------
|
||||
* 000035 data 7 bytes
|
||||
*
|
||||
* ------ Data Descriptor ------
|
||||
* 000042 signature 0x08074b50
|
||||
* 000046 crc 0x3610a686
|
||||
* 000050 csize 7
|
||||
* 000054 size 5
|
||||
*
|
||||
* A signature-less data descriptor will look like the following:
|
||||
*
|
||||
* ------ Data Descriptor ------
|
||||
* 000042 crc 0x3610a686
|
||||
* 000046 csize 7
|
||||
* 000050 size 5
|
||||
*
|
||||
* This method produces a ZIP with two entries, where the first entry
|
||||
* is made signature-less.
|
||||
*/
|
||||
private static byte[] makeZipWithSignaturelessDescriptor() throws IOException {
|
||||
// Offset of the signed data descriptor
|
||||
int sigOffset;
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
// Write a first entry
|
||||
zo.putNextEntry(new ZipEntry("first"));
|
||||
zo.write("first".getBytes(StandardCharsets.UTF_8));
|
||||
// Force the data descriptor to be written out
|
||||
zo.closeEntry();
|
||||
// Signed data descriptor starts 16 bytes before current offset
|
||||
sigOffset = out.size() - 4 * Integer.BYTES;
|
||||
// Add a second entry
|
||||
zo.putNextEntry(new ZipEntry("second"));
|
||||
zo.write("second".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
// The generated ZIP file with a signed data descriptor
|
||||
byte[] sigZip = out.toByteArray();
|
||||
|
||||
// The offset of the CRC immediately following the 4-byte signature
|
||||
int crcOffset = sigOffset + Integer.BYTES;
|
||||
|
||||
// Create a ZIP file with a signature-less data descriptor for the first entry
|
||||
ByteArrayOutputStream sigLess = new ByteArrayOutputStream();
|
||||
sigLess.write(sigZip, 0, sigOffset);
|
||||
// Skip the signature
|
||||
sigLess.write(sigZip, crcOffset, sigZip.length - crcOffset);
|
||||
|
||||
byte[] siglessZip = sigLess.toByteArray();
|
||||
|
||||
// Adjust the CEN offset in the END header
|
||||
ByteBuffer buffer = ByteBuffer.wrap(siglessZip).order(ByteOrder.LITTLE_ENDIAN);
|
||||
// Reduce cenOffset by 4 bytes
|
||||
int cenOff = siglessZip.length - ZipFile.ENDHDR + ZipFile.ENDOFF;
|
||||
int realCenOff = buffer.getInt(cenOff) - Integer.BYTES;
|
||||
buffer.putInt(cenOff, realCenOff);
|
||||
|
||||
// Adjust the LOC offset in the second CEN header
|
||||
int cen = realCenOff;
|
||||
// Skip past the first CEN header
|
||||
int nlen = buffer.getShort(cen + ZipFile.CENNAM);
|
||||
cen += ZipFile.CENHDR + nlen;
|
||||
|
||||
// Reduce LOC offset by 4 bytes
|
||||
int locOff = cen + ZipFile.CENOFF;
|
||||
buffer.putInt(locOff, buffer.getInt(locOff) - Integer.BYTES);
|
||||
|
||||
return siglessZip;
|
||||
}
|
||||
}
|
||||
345
test/jdk/java/util/zip/DeInflate.java
Normal file
345
test/jdk/java/util/zip/DeInflate.java
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2025, 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.
|
||||
*
|
||||
* 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 7110149 8184306 6341887 8357145
|
||||
* @summary Test basic deflater and inflater functionality
|
||||
* @key randomness
|
||||
* @run main/timeout=480 DeInflate
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.foreign.Arena;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
|
||||
public class DeInflate {
|
||||
|
||||
private static Random rnd = new Random();
|
||||
|
||||
|
||||
static void checkStream(Deflater def, byte[] in, int len,
|
||||
byte[] out1, byte[] out2, boolean nowrap)
|
||||
throws Throwable
|
||||
{
|
||||
Arrays.fill(out1, (byte)0);
|
||||
Arrays.fill(out2, (byte)0);
|
||||
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
try (DeflaterOutputStream defos = new DeflaterOutputStream(baos, def)) {
|
||||
defos.write(in, 0, len);
|
||||
}
|
||||
out1 = baos.toByteArray();
|
||||
}
|
||||
int m = out1.length;
|
||||
|
||||
Inflater inf = new Inflater(nowrap);
|
||||
inf.setInput(out1, 0, m);
|
||||
int n = inf.inflate(out2);
|
||||
|
||||
if (n != len ||
|
||||
!Arrays.equals(Arrays.copyOf(in, len), Arrays.copyOf(out2, len)) ||
|
||||
inf.inflate(out2) != 0) {
|
||||
System.out.printf("m=%d, n=%d, len=%d, eq=%b%n",
|
||||
m, n, len, Arrays.equals(in, out2));
|
||||
throw new RuntimeException("De/inflater failed:" + def);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkByteBuffer(Deflater def, Inflater inf,
|
||||
ByteBuffer in, ByteBuffer out1, ByteBuffer out2,
|
||||
byte[] expected, int len, byte[] result,
|
||||
boolean out1ReadOnlyWhenInflate)
|
||||
throws Throwable {
|
||||
def.reset();
|
||||
inf.reset();
|
||||
|
||||
def.setInput(in);
|
||||
def.finish();
|
||||
int m = def.deflate(out1);
|
||||
|
||||
out1.flip();
|
||||
if (out1ReadOnlyWhenInflate)
|
||||
out1 = out1.asReadOnlyBuffer();
|
||||
inf.setInput(out1);
|
||||
int n = inf.inflate(out2);
|
||||
|
||||
out2.flip();
|
||||
out2.get(result, 0, n);
|
||||
|
||||
if (n != len || out2.position() != len ||
|
||||
!Arrays.equals(Arrays.copyOf(expected, len), Arrays.copyOf(result, len)) ||
|
||||
inf.inflate(result) != 0) {
|
||||
throw new RuntimeException("De/inflater(buffer) failed:" + def);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkByteBufferReadonly(Deflater def, Inflater inf,
|
||||
ByteBuffer in, ByteBuffer out1, ByteBuffer out2)
|
||||
throws Throwable {
|
||||
def.reset();
|
||||
inf.reset();
|
||||
def.setInput(in);
|
||||
def.finish();
|
||||
int m = -1;
|
||||
if (!out2.isReadOnly())
|
||||
out2 = out2.asReadOnlyBuffer();
|
||||
try {
|
||||
m = def.deflate(out2);
|
||||
throw new RuntimeException("deflater: ReadOnlyBufferException: failed");
|
||||
} catch (ReadOnlyBufferException robe) {}
|
||||
m = def.deflate(out1);
|
||||
out1.flip();
|
||||
inf.setInput(out1);
|
||||
try {
|
||||
inf.inflate(out2);
|
||||
throw new RuntimeException("inflater: ReadOnlyBufferException: failed");
|
||||
} catch (ReadOnlyBufferException robe) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the {@code def} deflater to deflate the input data {@code in} of length {@code len}.
|
||||
* A new {@link Inflater} is then created within this method to inflate the deflated data. The
|
||||
* inflated data is then compared with the {@code in} to assert that it matches the original
|
||||
* input data.
|
||||
* This method repeats these checks for the different overloaded methods of
|
||||
* {@code Deflater.deflate(...)} and {@code Inflater.inflate(...)}
|
||||
*
|
||||
* @param def the deflater to use for deflating the contents in {@code in}
|
||||
* @param in the input content
|
||||
* @param len the length of the input content to use
|
||||
* @param nowrap will be passed to the constructor of the {@code Inflater} used in this
|
||||
* method
|
||||
* @throws Throwable if any error occurs during the check
|
||||
*/
|
||||
static void check(Deflater def, byte[] in, int len, boolean nowrap)
|
||||
throws Throwable
|
||||
{
|
||||
byte[] tempBuffer = new byte[1024];
|
||||
byte[] out1, out2;
|
||||
int m = 0, n = 0;
|
||||
Inflater inf = new Inflater(nowrap);
|
||||
def.setInput(in, 0, len);
|
||||
def.finish();
|
||||
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
while (!def.finished()) {
|
||||
int temp_counter = def.deflate(tempBuffer);
|
||||
m += temp_counter;
|
||||
baos.write(tempBuffer, 0, temp_counter);
|
||||
}
|
||||
out1 = baos.toByteArray();
|
||||
baos.reset();
|
||||
|
||||
inf.setInput(out1, 0, m);
|
||||
|
||||
while (!inf.finished()) {
|
||||
int temp_counter = inf.inflate(tempBuffer);
|
||||
n += temp_counter;
|
||||
baos.write(tempBuffer, 0, temp_counter);
|
||||
}
|
||||
out2 = baos.toByteArray();
|
||||
if (n != len ||
|
||||
!Arrays.equals(in, 0, len, out2, 0, len) ||
|
||||
inf.inflate(out2) != 0) {
|
||||
System.out.printf("m=%d, n=%d, len=%d, eq=%b%n",
|
||||
m, n, len, Arrays.equals(in, out2));
|
||||
throw new RuntimeException("De/inflater failed:" + def);
|
||||
}
|
||||
}
|
||||
|
||||
// readable
|
||||
Arrays.fill(out1, (byte)0);
|
||||
Arrays.fill(out2, (byte)0);
|
||||
ByteBuffer bbIn = ByteBuffer.wrap(in, 0, len);
|
||||
ByteBuffer bbOut1 = ByteBuffer.wrap(out1);
|
||||
ByteBuffer bbOut2 = ByteBuffer.wrap(out2);
|
||||
checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false);
|
||||
checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
|
||||
|
||||
// readonly in
|
||||
Arrays.fill(out1, (byte)0);
|
||||
Arrays.fill(out2, (byte)0);
|
||||
bbIn = ByteBuffer.wrap(in, 0, len).asReadOnlyBuffer();
|
||||
bbOut1 = ByteBuffer.wrap(out1);
|
||||
bbOut2 = ByteBuffer.wrap(out2);
|
||||
checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false);
|
||||
checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
|
||||
|
||||
// readonly out1 when inflate
|
||||
Arrays.fill(out1, (byte)0);
|
||||
Arrays.fill(out2, (byte)0);
|
||||
bbIn = ByteBuffer.wrap(in, 0, len);
|
||||
bbOut1 = ByteBuffer.wrap(out1);
|
||||
bbOut2 = ByteBuffer.wrap(out2);
|
||||
checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, true);
|
||||
checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
|
||||
|
||||
// direct
|
||||
bbIn = ByteBuffer.allocateDirect(in.length);
|
||||
bbIn.put(in, 0, n).flip();
|
||||
bbOut1 = ByteBuffer.allocateDirect(out1.length);
|
||||
bbOut2 = ByteBuffer.allocateDirect(out2.length);
|
||||
checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false);
|
||||
checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
|
||||
|
||||
// segment
|
||||
try (var arena = Arena.ofConfined()) {
|
||||
bbIn = arena.allocate(in.length).asByteBuffer();
|
||||
bbIn.put(in, 0, n).flip();
|
||||
bbOut1 = arena.allocate(out1.length).asByteBuffer();
|
||||
bbOut2 = arena.allocate(out2.length).asByteBuffer();
|
||||
checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false);
|
||||
checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkDict(Deflater def, Inflater inf, byte[] src,
|
||||
byte[] dstDef, byte[] dstInf,
|
||||
ByteBuffer dictDef, ByteBuffer dictInf) throws Throwable {
|
||||
def.reset();
|
||||
inf.reset();
|
||||
|
||||
def.setDictionary(dictDef);
|
||||
def.setInput(src);
|
||||
def.finish();
|
||||
int n = def.deflate(dstDef);
|
||||
|
||||
inf.setInput(dstDef, 0, n);
|
||||
n = inf.inflate(dstInf);
|
||||
if (n != 0 || !inf.needsDictionary()) {
|
||||
throw new RuntimeException("checkDict failed: need dict to continue");
|
||||
}
|
||||
inf.setDictionary(dictInf);
|
||||
n = inf.inflate(dstInf);
|
||||
// System.out.println("result: " + new String(dstInf, 0, n));
|
||||
if (n != src.length || !Arrays.equals(Arrays.copyOf(dstInf, n), src)) {
|
||||
throw new RuntimeException("checkDict failed: inflate result");
|
||||
}
|
||||
}
|
||||
|
||||
static void checkDict(int level, int strategy) throws Throwable {
|
||||
|
||||
Deflater def = newDeflater(level, strategy, false, new byte[0]);
|
||||
Inflater inf = new Inflater();
|
||||
|
||||
byte[] src = "hello world, hello world, hello sherman".getBytes();
|
||||
byte[] dict = "hello".getBytes();
|
||||
|
||||
byte[] dstDef = new byte[1024];
|
||||
byte[] dstInf = new byte[1024];
|
||||
|
||||
def.setDictionary(dict);
|
||||
def.setInput(src);
|
||||
def.finish();
|
||||
int n = def.deflate(dstDef);
|
||||
|
||||
inf.setInput(dstDef, 0, n);
|
||||
n = inf.inflate(dstInf);
|
||||
if (n != 0 || !inf.needsDictionary()) {
|
||||
throw new RuntimeException("checkDict failed: need dict to continue");
|
||||
}
|
||||
inf.setDictionary(dict);
|
||||
n = inf.inflate(dstInf);
|
||||
//System.out.println("result: " + new String(dstInf, 0, n));
|
||||
if (n != src.length || !Arrays.equals(Arrays.copyOf(dstInf, n), src)) {
|
||||
throw new RuntimeException("checkDict failed: inflate result");
|
||||
}
|
||||
|
||||
ByteBuffer dictDef = ByteBuffer.wrap(dict);
|
||||
ByteBuffer dictInf = ByteBuffer.wrap(dict);
|
||||
checkDict(def, inf, src, dstDef, dstInf, dictDef, dictInf);
|
||||
|
||||
dictDef = ByteBuffer.allocateDirect(dict.length);
|
||||
dictInf = ByteBuffer.allocateDirect(dict.length);
|
||||
dictDef.put(dict).flip();
|
||||
dictInf.put(dict).flip();
|
||||
checkDict(def, inf, src, dstDef, dstInf, dictDef, dictInf);
|
||||
|
||||
def.end();
|
||||
inf.end();
|
||||
}
|
||||
|
||||
private static Deflater newDeflater(int level, int strategy, boolean dowrap, byte[] tmp) {
|
||||
Deflater def = new Deflater(level, dowrap);
|
||||
if (strategy != Deflater.DEFAULT_STRATEGY) {
|
||||
def.setStrategy(strategy);
|
||||
// The first invocation after setLevel/Strategy()
|
||||
// with a different level/stragety returns 0, if
|
||||
// there is no need to flush out anything for the
|
||||
// previous setting/"data", this is tricky and
|
||||
// appears un-documented.
|
||||
def.deflate(tmp);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
private static Deflater resetDeflater(Deflater def, int level, int strategy) {
|
||||
def.setLevel(level);
|
||||
def.setStrategy(strategy);
|
||||
def.reset();
|
||||
return def;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
|
||||
byte[] dataIn = new byte[1024 * 512];
|
||||
rnd.nextBytes(dataIn);
|
||||
byte[] dataOut1 = new byte[dataIn.length + 1024];
|
||||
byte[] dataOut2 = new byte[dataIn.length];
|
||||
|
||||
Deflater defNotWrap = new Deflater(Deflater.DEFAULT_COMPRESSION, false);
|
||||
Deflater defWrap = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
|
||||
|
||||
for (int level = Deflater.DEFAULT_COMPRESSION;
|
||||
level <= Deflater.BEST_COMPRESSION; level++) {
|
||||
for (int strategy = Deflater.DEFAULT_STRATEGY;
|
||||
strategy <= Deflater.HUFFMAN_ONLY; strategy++) {
|
||||
for (boolean dowrap : new boolean[] { false, true }) {
|
||||
System.out.println("level:" + level +
|
||||
", strategy: " + strategy +
|
||||
", dowrap: " + dowrap);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int len = (i == 0)? dataIn.length
|
||||
: new Random().nextInt(dataIn.length);
|
||||
System.out.println("iteration: " + (i + 1) + " input length: " + len);
|
||||
// use a new deflater
|
||||
Deflater def = newDeflater(level, strategy, dowrap, dataOut2);
|
||||
check(def, dataIn, len, dowrap);
|
||||
def.end();
|
||||
|
||||
// reuse the deflater (with reset) and test on stream, which
|
||||
// uses a "smaller" buffer (smaller than the overall data)
|
||||
def = resetDeflater(dowrap ? defWrap : defNotWrap, level, strategy);
|
||||
checkStream(def, dataIn, len, dataOut1, dataOut2, dowrap);
|
||||
}
|
||||
}
|
||||
// test setDictionary()
|
||||
checkDict(level, strategy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
392
test/jdk/java/util/zip/DeflateIn_InflateOut.java
Normal file
392
test/jdk/java/util/zip/DeflateIn_InflateOut.java
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2025, 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.
|
||||
*
|
||||
* 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 4679743
|
||||
* @summary Test basic functionality of DeflaterInputStream and InflaterOutputStream
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class DeflateIn_InflateOut {
|
||||
private static byte[] data = new byte[1024 * 1024];
|
||||
|
||||
private static ByteArrayInputStream bais;
|
||||
private static DeflaterInputStream dis;
|
||||
|
||||
private static ByteArrayOutputStream baos;
|
||||
private static InflaterOutputStream ios;
|
||||
|
||||
private static Inflater reset(byte[] dict) {
|
||||
bais = new ByteArrayInputStream(data);
|
||||
if (dict == null) {
|
||||
dis = new DeflaterInputStream(bais);
|
||||
} else {
|
||||
Deflater def = new Deflater();
|
||||
def.setDictionary(dict);
|
||||
dis = new DeflaterInputStream(bais, def);
|
||||
}
|
||||
|
||||
baos = new ByteArrayOutputStream();
|
||||
if (dict == null) {
|
||||
ios = new InflaterOutputStream(baos);
|
||||
return null;
|
||||
} else {
|
||||
Inflater inf = new Inflater();
|
||||
ios = new InflaterOutputStream(baos, inf);
|
||||
return inf;
|
||||
}
|
||||
}
|
||||
|
||||
private static void reset() {
|
||||
reset(null);
|
||||
}
|
||||
|
||||
/** Check byte arrays read/write. */
|
||||
private static void ArrayReadWrite() throws Throwable {
|
||||
byte[] buf = new byte[512];
|
||||
|
||||
reset();
|
||||
check(dis.available() == 1);
|
||||
for (;;) {
|
||||
int len = dis.read(buf, 0, buf.length);
|
||||
if (len < 0) {
|
||||
break;
|
||||
} else {
|
||||
ios.write(buf, 0, len);
|
||||
}
|
||||
}
|
||||
check(dis.available() == 0);
|
||||
ios.close();
|
||||
check(Arrays.equals(data, baos.toByteArray()));
|
||||
}
|
||||
|
||||
/** Check byte arrays read, single byte write */
|
||||
private static void ArrayReadByteWrite() throws Throwable {
|
||||
byte[] buf = new byte[512];
|
||||
|
||||
reset();
|
||||
for (;;) {
|
||||
int len = dis.read(buf, 0, buf.length);
|
||||
if (len <= 0) {
|
||||
break;
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte x = (byte) (buf[i] & 0xff);
|
||||
ios.write(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
check(dis.available() == 0);
|
||||
ios.close();
|
||||
check(Arrays.equals(data, baos.toByteArray()));
|
||||
}
|
||||
|
||||
/** Check single byte read, byte array write.
|
||||
* <p>
|
||||
* Note that this test relies on the vaule from DeflaterInputStream.read()
|
||||
* to determine when to stop reading.
|
||||
*/
|
||||
private static void ByteReadArrayWrite() throws Throwable {
|
||||
byte[] buf = new byte[8192];
|
||||
int off = 0;
|
||||
|
||||
reset();
|
||||
int datum = dis.read();
|
||||
while (datum != -1) {
|
||||
if (off == 8192) {
|
||||
ios.write(buf, 0, off);
|
||||
off = 0;
|
||||
}
|
||||
buf[off++] = (byte) (datum & 0xff);
|
||||
datum = dis.read();
|
||||
}
|
||||
if (off > 0) {
|
||||
ios.write(buf, 0, off);
|
||||
}
|
||||
ios.close();
|
||||
check(Arrays.equals(data, baos.toByteArray()));
|
||||
}
|
||||
|
||||
/** Check single byte read/write.
|
||||
* <p>
|
||||
* Note that this test relies on DeflaterInputStream.available() to
|
||||
* determine when to stop reading.
|
||||
*/
|
||||
private static void ByteReadByteWrite() throws Throwable {
|
||||
byte[] buf = new byte[512];
|
||||
boolean reachEOF = false;
|
||||
|
||||
reset();
|
||||
while (dis.available() == 1) {
|
||||
int datum = dis.read();
|
||||
if (datum == -1) {
|
||||
reachEOF = true;
|
||||
} else {
|
||||
if (datum < 0 || datum > 255) {
|
||||
fail("datum out of range: " + datum);
|
||||
}
|
||||
ios.write(datum);
|
||||
}
|
||||
}
|
||||
dis.close();
|
||||
ios.close();
|
||||
check(data[0] == baos.toByteArray()[0]);
|
||||
}
|
||||
|
||||
/** Check skip(). */
|
||||
private static void SkipBytes() throws Throwable {
|
||||
byte[] buf = new byte[512];
|
||||
int numReadable = 0;
|
||||
|
||||
// Count number of bytes that are read
|
||||
reset();
|
||||
check(dis.available() == 1);
|
||||
for (;;) {
|
||||
int count = dis.read(buf, 0, buf.length);
|
||||
if (count < 0) {
|
||||
break;
|
||||
} else {
|
||||
numReadable += count;
|
||||
}
|
||||
}
|
||||
check(dis.available() == 0);
|
||||
|
||||
// Verify that skipping the first several bytes works.
|
||||
reset();
|
||||
int numNotSkipped = 0;
|
||||
int numSkipBytes = 2053; // arbitrarily chosen prime
|
||||
check(dis.skip(numSkipBytes) == numSkipBytes);
|
||||
for (int i = 0; ; i++) {
|
||||
int count = dis.read(buf, 0, buf.length);
|
||||
if (count < 0) {
|
||||
break;
|
||||
} else {
|
||||
numNotSkipped += count;
|
||||
}
|
||||
}
|
||||
check(numNotSkipped + numSkipBytes == numReadable);
|
||||
|
||||
// Verify that skipping some bytes mid-stream works.
|
||||
reset();
|
||||
numNotSkipped = 0;
|
||||
numSkipBytes = 8887; // arbitrarily chosen prime
|
||||
for (int i = 0; ; i++) {
|
||||
if (i == 13) { // Arbitrarily chosen
|
||||
check(dis.skip(numSkipBytes) == numSkipBytes);
|
||||
} else {
|
||||
int count = dis.read(buf, 0, buf.length);
|
||||
if (count < 0) {
|
||||
break;
|
||||
} else {
|
||||
numNotSkipped += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
check(numNotSkipped + numSkipBytes == numReadable);
|
||||
|
||||
// Verify that skipping the last N bytes works.
|
||||
reset();
|
||||
numNotSkipped = 0;
|
||||
numSkipBytes = 6449; // arbitrarily chosen prime
|
||||
for (int i = 0; ; i++) {
|
||||
if (numNotSkipped + numSkipBytes > numReadable) {
|
||||
numSkipBytes = numReadable - numNotSkipped;
|
||||
check(dis.skip(numSkipBytes) == numSkipBytes);
|
||||
check(dis.read(buf, 0, buf.length) == -1);
|
||||
check(dis.available() == 0);
|
||||
} else {
|
||||
int count = dis.read(buf, 0, buf.length);
|
||||
if (count < 0) {
|
||||
break;
|
||||
} else {
|
||||
numNotSkipped += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
check(numNotSkipped + numSkipBytes == numReadable);
|
||||
}
|
||||
|
||||
/** Check "needsDictionary()". */
|
||||
private static void NeedsDictionary() throws Throwable {
|
||||
byte[] dict = {1, 2, 3, 4};
|
||||
Adler32 adler32 = new Adler32();
|
||||
adler32.update(dict);
|
||||
long checksum = adler32.getValue();
|
||||
byte[] buf = new byte[512];
|
||||
|
||||
Inflater inf = reset(dict);
|
||||
check(dis.available() == 1);
|
||||
boolean dictSet = false;
|
||||
for (;;) {
|
||||
int len = dis.read(buf, 0, buf.length);
|
||||
if (len < 0) {
|
||||
break;
|
||||
} else {
|
||||
try {
|
||||
ios.write(buf, 0, len);
|
||||
if (dictSet == false) {
|
||||
check(false, "Must throw ZipException without dictionary");
|
||||
return;
|
||||
}
|
||||
} catch (ZipException ze) {
|
||||
check(dictSet == false, "Dictonary must be set only once");
|
||||
check(checksum == inf.getAdler(), "Incorrect dictionary");
|
||||
inf.setDictionary(dict);
|
||||
// After setting the dictionary, we have to flush the
|
||||
// InflaterOutputStream now in order to consume all the
|
||||
// pending input data from the last, failed call to "write()".
|
||||
ios.flush();
|
||||
dictSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
check(dis.available() == 0);
|
||||
ios.close();
|
||||
check(Arrays.equals(data, baos.toByteArray()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that when a DeflaterInputStream is constructed
|
||||
* by passing a Deflater instance, then closing the DeflaterInputStream
|
||||
* will not close the passed Deflater instance.
|
||||
*/
|
||||
private static void deflaterInputStreamDeflaterNotClosed() throws Throwable {
|
||||
// some arbitrary content
|
||||
final byte[] original = "foo".repeat(1024).getBytes(StandardCharsets.US_ASCII);
|
||||
// run the DeflaterInputStream tests
|
||||
try (final Deflater def = new Deflater()) {
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(original);
|
||||
DeflaterInputStream iis = new DeflaterInputStream(bis, def)) {
|
||||
iis.readAllBytes();
|
||||
}
|
||||
// verify the deflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the deflater is closed
|
||||
def.reset();
|
||||
|
||||
// repeat the test with the other constructor
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(original);
|
||||
DeflaterInputStream iis = new DeflaterInputStream(bis, def, 1024)) {
|
||||
iis.readAllBytes();
|
||||
}
|
||||
// verify the deflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the deflater is closed
|
||||
def.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] deflate(final byte[] original) {
|
||||
final ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream();
|
||||
try (Deflater compressor = new Deflater()) {
|
||||
compressor.setInput(original);
|
||||
compressor.finish();
|
||||
while (!compressor.finished()) {
|
||||
byte[] tmpBuffer = new byte[1024];
|
||||
int numCompressed = compressor.deflate(tmpBuffer);
|
||||
compressedBaos.write(tmpBuffer, 0, numCompressed);
|
||||
}
|
||||
}
|
||||
return compressedBaos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that when a InflaterOutputStream is constructed
|
||||
* by passing a Inflater instance, then closing the InflaterOutputStream
|
||||
* will not close the passed Inflater instance.
|
||||
*/
|
||||
private static void inflaterOutputStreamInflaterNotClosed() throws Throwable {
|
||||
// some arbitrary content
|
||||
final byte[] original = "bar".repeat(1024).getBytes(StandardCharsets.US_ASCII);
|
||||
// deflate it
|
||||
final byte[] deflated = deflate(original);
|
||||
try (final Inflater infl = new Inflater()) {
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
InflaterOutputStream dos = new InflaterOutputStream(bos, infl)) {
|
||||
dos.write(deflated);
|
||||
dos.flush();
|
||||
check(Arrays.equals(original, bos.toByteArray()));
|
||||
}
|
||||
// verify the inflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the inflater is closed
|
||||
infl.reset();
|
||||
|
||||
// repeat the test with the other constructor
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
InflaterOutputStream dos = new InflaterOutputStream(bos, infl, 1024)) {
|
||||
dos.write(deflated);
|
||||
dos.flush();
|
||||
check(Arrays.equals(original, bos.toByteArray()));
|
||||
}
|
||||
// verify the inflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the inflater is closed
|
||||
infl.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
new Random(new Date().getTime()).nextBytes(data);
|
||||
|
||||
ArrayReadWrite();
|
||||
|
||||
ArrayReadByteWrite();
|
||||
|
||||
ByteReadArrayWrite();
|
||||
|
||||
ByteReadByteWrite();
|
||||
|
||||
SkipBytes();
|
||||
|
||||
NeedsDictionary();
|
||||
|
||||
deflaterInputStreamDeflaterNotClosed();
|
||||
|
||||
inflaterOutputStreamInflaterNotClosed();
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {passed++;}
|
||||
static void fail() { fail(null); }
|
||||
static void fail(String msg) {
|
||||
failed++;
|
||||
if (msg != null) {
|
||||
System.err.println(msg);
|
||||
}
|
||||
Thread.dumpStack();
|
||||
}
|
||||
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
static void check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void check(boolean cond, String msg) {if (cond) pass(); else fail(msg);}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
223
test/jdk/java/util/zip/DeflaterClose.java
Normal file
223
test/jdk/java/util/zip/DeflaterClose.java
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225763
|
||||
* @summary Test that the close() and end() methods on java.util.zip.Deflater
|
||||
* @run junit DeflaterClose
|
||||
*/
|
||||
public class DeflaterClose {
|
||||
|
||||
private static final String data = "foobarhelloworld!!!!";
|
||||
|
||||
/**
|
||||
* Closes the Deflater multiple times and then expects close() and end() each
|
||||
* to be called that many times.
|
||||
*/
|
||||
@Test
|
||||
public void testCloseMultipleTimes() throws Exception {
|
||||
final int numTimes = 3;
|
||||
final Deflater simpleDeflater = new Deflater();
|
||||
closeMultipleTimesAfterCompressing(numTimes, simpleDeflater);
|
||||
|
||||
final OverrideClose overriddenClose = new OverrideClose();
|
||||
closeMultipleTimesAfterCompressing(numTimes, overriddenClose);
|
||||
// make sure close was called numTimes
|
||||
assertEquals(numTimes, overriddenClose.numTimesCloseCalled, "close() was expected to be" +
|
||||
" called " + numTimes + ", but was called " + overriddenClose.numTimesCloseCalled +
|
||||
" time(s) on " + overriddenClose.getClass().getName());
|
||||
|
||||
final OverrideEnd overriddenEnd = new OverrideEnd();
|
||||
closeMultipleTimesAfterCompressing(numTimes, overriddenEnd);
|
||||
// make sure end was called called numTimes
|
||||
assertEquals(numTimes, overriddenEnd.numTimesEndCalled, "end() was expected to be called " +
|
||||
numTimes + ", but was called " + overriddenEnd.numTimesEndCalled + " time(s) on " +
|
||||
overriddenEnd.getClass().getName());
|
||||
|
||||
final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
|
||||
closeMultipleTimesAfterCompressing(numTimes, overriddenCloseAndEnd);
|
||||
// make sure end was called called numTimes
|
||||
assertEquals(numTimes, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected to be called " +
|
||||
numTimes + ", but was called" + overriddenCloseAndEnd.numTimesEndCalled +
|
||||
" time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
assertEquals(numTimes, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected" +
|
||||
" to be called " + numTimes + ", but was called " +
|
||||
overriddenClose.numTimesCloseCalled + " time(s) on " +
|
||||
overriddenCloseAndEnd.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the Deflater first and then calls end(). Verifies that close() was called
|
||||
* just once but end() was called twice (once internally through close() and once
|
||||
* explicitly)
|
||||
*/
|
||||
@Test
|
||||
public void testCloseThenEnd() throws Exception {
|
||||
final Deflater simpleDeflater = new Deflater();
|
||||
compressCloseThenEnd(simpleDeflater);
|
||||
|
||||
final OverrideClose overriddenClose = new OverrideClose();
|
||||
compressCloseThenEnd(overriddenClose);
|
||||
// make sure close was called once
|
||||
assertEquals(1, overriddenClose.numTimesCloseCalled, "close() was expected to be called" +
|
||||
" once, but was called " + overriddenClose.numTimesCloseCalled +
|
||||
" time(s) on " + overriddenClose.getClass().getName());
|
||||
|
||||
final OverrideEnd overriddenEnd = new OverrideEnd();
|
||||
compressCloseThenEnd(overriddenEnd);
|
||||
// make sure end was called twice (once through close() and then explicitly)
|
||||
assertEquals(2, overriddenEnd.numTimesEndCalled, "end() was expected to be called" +
|
||||
" twice, but was called " + overriddenEnd.numTimesEndCalled +
|
||||
" time(s) on " + overriddenEnd.getClass().getName());
|
||||
|
||||
final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
|
||||
compressCloseThenEnd(overriddenCloseAndEnd);
|
||||
// make sure end was called twice (once through close and once explicitly)
|
||||
// and close was called once
|
||||
assertEquals(2, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected to" +
|
||||
" be called twice, but was called " + overriddenCloseAndEnd.numTimesEndCalled +
|
||||
" time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
assertEquals(1, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected to be" +
|
||||
" called once, but was called " + overriddenClose.numTimesCloseCalled +
|
||||
" time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls end() on the Deflater first and then calls close(). Verifies that close() was called
|
||||
* just once and end() twice.
|
||||
*/
|
||||
@Test
|
||||
public void testEndThenClose() throws Exception {
|
||||
final Deflater simpleDeflater = new Deflater();
|
||||
compressEndThenClose(simpleDeflater);
|
||||
|
||||
final OverrideClose overriddenClose = new OverrideClose();
|
||||
compressEndThenClose(overriddenClose);
|
||||
// make sure close was called once
|
||||
assertEquals(1, overriddenClose.numTimesCloseCalled, "close() was expected to be called" +
|
||||
" once, but was called " + overriddenClose.numTimesCloseCalled +
|
||||
" time(s) on " + overriddenClose.getClass().getName());
|
||||
|
||||
final OverrideEnd overriddenEnd = new OverrideEnd();
|
||||
compressEndThenClose(overriddenEnd);
|
||||
// make sure end was called twice (once through the explicit end call and
|
||||
// once through close())
|
||||
assertEquals(2, overriddenEnd.numTimesEndCalled, "end() was expected to be called twice," +
|
||||
" but was called " + overriddenEnd.numTimesEndCalled +
|
||||
" time(s) on " + overriddenEnd.getClass().getName());
|
||||
|
||||
final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
|
||||
compressEndThenClose(overriddenCloseAndEnd);
|
||||
// make sure end was called twice (once through the explicit end call and
|
||||
// once through close())
|
||||
assertEquals(2, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected to be called" +
|
||||
" twice, but was called " + overriddenCloseAndEnd.numTimesEndCalled +
|
||||
" time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
assertEquals(1, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected to be " +
|
||||
"called once, but was called " + overriddenClose.numTimesCloseCalled +
|
||||
" time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
}
|
||||
|
||||
private void closeMultipleTimesAfterCompressing(final int numTimes, final Deflater deflater) {
|
||||
compress(deflater);
|
||||
// call close() multiple times
|
||||
for (int i = 0; i < numTimes; i++) {
|
||||
deflater.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void compressCloseThenEnd(final Deflater deflater) {
|
||||
// compress the data then close() and then end()
|
||||
try (final Deflater compressor = deflater) {
|
||||
compress(compressor);
|
||||
}
|
||||
deflater.end();
|
||||
}
|
||||
|
||||
private void compressEndThenClose(final Deflater deflater) {
|
||||
// compress the data then end() and then close()
|
||||
try (final Deflater compressor = deflater) {
|
||||
compress(compressor);
|
||||
// end() it first before it's (auto)closed by the try-with-resources
|
||||
compressor.end();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] compress(final Deflater deflater) {
|
||||
deflater.setInput(data.getBytes(StandardCharsets.UTF_8));
|
||||
deflater.finish();
|
||||
final ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream();
|
||||
while (!deflater.finished()) {
|
||||
final byte[] tmpBuffer = new byte[100];
|
||||
final int numCompressed = deflater.deflate(tmpBuffer);
|
||||
compressedBaos.write(tmpBuffer, 0, numCompressed);
|
||||
}
|
||||
return compressedBaos.toByteArray();
|
||||
}
|
||||
|
||||
private static final class OverrideEnd extends Deflater {
|
||||
private int numTimesEndCalled = 0;
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
this.numTimesEndCalled++;
|
||||
super.end();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class OverrideClose extends Deflater {
|
||||
private int numTimesCloseCalled = 0;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.numTimesCloseCalled++;
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class OverrideCloseAndEnd extends Deflater {
|
||||
private int numTimesEndCalled = 0;
|
||||
private int numTimesCloseCalled = 0;
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
this.numTimesEndCalled++;
|
||||
super.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.numTimesCloseCalled++;
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
247
test/jdk/java/util/zip/DeflaterDictionaryTests.java
Normal file
247
test/jdk/java/util/zip/DeflaterDictionaryTests.java
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8252739
|
||||
* @summary Verify Deflater.setDictionary(dictionary, offset, length) uses the offset
|
||||
* @run junit/othervm DeflaterDictionaryTests
|
||||
*/
|
||||
public class DeflaterDictionaryTests {
|
||||
// Output buffer size
|
||||
private static final int RESULT_SIZE = 1024;
|
||||
// Data to compress
|
||||
private static final String SRC_DATA = "Welcome to the US Open;".repeat(6);
|
||||
// Dictionary to be used
|
||||
private static final String DICTIONARY = "US Open";
|
||||
private static final int DICTIONARY_OFFSET = 1;
|
||||
private static final int DICTIONARY_LENGTH = 3;
|
||||
|
||||
/**
|
||||
* MethodSource with offsets which should be valid for setDictionary
|
||||
*
|
||||
* @return Stream of valid offset values
|
||||
*/
|
||||
protected static IntStream validDictionaryOffsets() {
|
||||
return IntStream.of(0, DICTIONARY_OFFSET, DICTIONARY_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* MethodSource with invalid offsets for setDictionary
|
||||
*
|
||||
* @return Stream of invalid offset values
|
||||
*/
|
||||
protected static IntStream invalidDictionaryOffsets() {
|
||||
return IntStream.of(-1, DICTIONARY_LENGTH + 2, DICTIONARY.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an offset can be used with Deflater::setDictionary
|
||||
*
|
||||
* @param dictionary_offset offset value to be used
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("validDictionaryOffsets")
|
||||
public void testByteArray(int dictionary_offset) throws Exception {
|
||||
byte[] input = SRC_DATA.getBytes(UTF_8);
|
||||
byte[] output = new byte[RESULT_SIZE];
|
||||
Deflater deflater = new Deflater();
|
||||
Inflater inflater = new Inflater();
|
||||
try {
|
||||
// Compress the bytes
|
||||
deflater.setDictionary(DICTIONARY.getBytes(UTF_8), dictionary_offset, DICTIONARY_LENGTH);
|
||||
deflater.setInput(input);
|
||||
deflater.finish();
|
||||
int compressedDataLength = deflater.deflate(output, 0, output.length, Deflater.NO_FLUSH);
|
||||
System.out.printf("Deflater::getBytesWritten:%d, Deflater::getAdler: %d," +
|
||||
" compressed length: %d%n", deflater.getBytesWritten(),
|
||||
deflater.getAdler(), compressedDataLength);
|
||||
deflater.finished();
|
||||
|
||||
// Decompress the bytes
|
||||
inflater.setInput(output, 0, compressedDataLength);
|
||||
byte[] result = new byte[RESULT_SIZE];
|
||||
int resultLength = inflater.inflate(result);
|
||||
if (inflater.needsDictionary()) {
|
||||
System.out.println("Specifying Dictionary");
|
||||
inflater.setDictionary(DICTIONARY.getBytes(UTF_8), dictionary_offset, DICTIONARY_LENGTH);
|
||||
resultLength = inflater.inflate(result);
|
||||
} else {
|
||||
System.out.println("Did not need to use a Dictionary");
|
||||
}
|
||||
inflater.finished();
|
||||
System.out.printf("Inflater::getAdler:%d, length: %d%n",
|
||||
inflater.getAdler(), resultLength);
|
||||
|
||||
assertEquals(SRC_DATA.length(), resultLength);
|
||||
assertArrayEquals(input, Arrays.copyOf(result, resultLength));
|
||||
} finally {
|
||||
// Release Resources
|
||||
deflater.end();
|
||||
inflater.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ByteBuffer can be used with Deflater::setDictionary
|
||||
*
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testHeapByteBuffer() throws Exception {
|
||||
byte[] input = SRC_DATA.getBytes(UTF_8);
|
||||
byte[] output = new byte[RESULT_SIZE];
|
||||
ByteBuffer dictDef = ByteBuffer.wrap(DICTIONARY.getBytes(UTF_8), DICTIONARY_OFFSET, DICTIONARY_LENGTH);
|
||||
ByteBuffer dictInf = ByteBuffer.wrap(DICTIONARY.getBytes(UTF_8), DICTIONARY_OFFSET, DICTIONARY_LENGTH);
|
||||
Deflater deflater = new Deflater();
|
||||
Inflater inflater = new Inflater();
|
||||
try {
|
||||
// Compress the bytes
|
||||
deflater.setDictionary(dictDef);
|
||||
deflater.setInput(input);
|
||||
deflater.finish();
|
||||
int compressedDataLength = deflater.deflate(output, 0, output.length, Deflater.NO_FLUSH);
|
||||
System.out.printf("Deflater::getBytesWritten:%d, Deflater::getAdler: %d," +
|
||||
" compressed length: %d%n", deflater.getBytesWritten(),
|
||||
deflater.getAdler(), compressedDataLength);
|
||||
deflater.finished();
|
||||
|
||||
// Decompress the bytes
|
||||
inflater.setInput(output, 0, compressedDataLength);
|
||||
byte[] result = new byte[RESULT_SIZE];
|
||||
int resultLength = inflater.inflate(result);
|
||||
if (inflater.needsDictionary()) {
|
||||
System.out.println("Specifying Dictionary");
|
||||
inflater.setDictionary(dictInf);
|
||||
resultLength = inflater.inflate(result);
|
||||
} else {
|
||||
System.out.println("Did not need to use a Dictionary");
|
||||
}
|
||||
inflater.finished();
|
||||
System.out.printf("Inflater::getAdler:%d, length: %d%n",
|
||||
inflater.getAdler(), resultLength);
|
||||
|
||||
assertEquals(resultLength, SRC_DATA.length());
|
||||
assertArrayEquals(Arrays.copyOf(result, resultLength), input);
|
||||
} finally {
|
||||
// Release Resources
|
||||
deflater.end();
|
||||
inflater.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that ByteBuffer::allocateDirect can be used with Deflater::setDictionary
|
||||
*
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testByteBufferDirect() throws Exception {
|
||||
byte[] input = SRC_DATA.getBytes(UTF_8);
|
||||
byte[] output = new byte[RESULT_SIZE];
|
||||
ByteBuffer dictDef = ByteBuffer.allocateDirect(DICTIONARY.length());
|
||||
ByteBuffer dictInf = ByteBuffer.allocateDirect(DICTIONARY.length());
|
||||
dictDef.put(DICTIONARY.getBytes(UTF_8));
|
||||
dictInf.put(DICTIONARY.getBytes(UTF_8));
|
||||
dictDef.position(DICTIONARY_OFFSET);
|
||||
dictDef.limit(DICTIONARY_LENGTH);
|
||||
dictInf.position(DICTIONARY_OFFSET);
|
||||
dictInf.limit(DICTIONARY_LENGTH);
|
||||
Deflater deflater = new Deflater();
|
||||
Inflater inflater = new Inflater();
|
||||
try {
|
||||
// Compress the bytes
|
||||
deflater.setDictionary(dictDef.slice());
|
||||
deflater.setInput(input);
|
||||
deflater.finish();
|
||||
int compressedDataLength = deflater.deflate(output, 0, output.length, Deflater.NO_FLUSH);
|
||||
System.out.printf("Deflater::getBytesWritten:%d, Deflater::getAdler: %d," +
|
||||
" compressed length: %d%n", deflater.getBytesWritten(),
|
||||
deflater.getAdler(), compressedDataLength);
|
||||
deflater.finished();
|
||||
|
||||
// Decompress the bytes
|
||||
inflater.setInput(output, 0, compressedDataLength);
|
||||
byte[] result = new byte[RESULT_SIZE];
|
||||
int resultLength = inflater.inflate(result);
|
||||
if (inflater.needsDictionary()) {
|
||||
System.out.println("Specifying Dictionary");
|
||||
inflater.setDictionary(dictInf.slice());
|
||||
resultLength = inflater.inflate(result);
|
||||
} else {
|
||||
System.out.println("Did not need to use a Dictionary");
|
||||
}
|
||||
inflater.finished();
|
||||
System.out.printf("Inflater::getAdler:%d, length: %d%n",
|
||||
inflater.getAdler(), resultLength);
|
||||
|
||||
assertEquals(resultLength, SRC_DATA.length());
|
||||
assertArrayEquals(Arrays.copyOf(result, resultLength), input);
|
||||
} finally {
|
||||
// Release Resources
|
||||
deflater.end();
|
||||
inflater.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an invalid offset used with setDictionary will
|
||||
* throw an Exception
|
||||
*
|
||||
* @param dictionary_offset offset value to be used
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("invalidDictionaryOffsets")
|
||||
public void testInvalidOffsets(int dictionary_offset) {
|
||||
byte[] dictionary = DICTIONARY.getBytes(UTF_8);
|
||||
|
||||
Deflater deflater = new Deflater();
|
||||
Inflater inflater = new Inflater();
|
||||
try {
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () ->
|
||||
deflater.setDictionary(dictionary, dictionary_offset, DICTIONARY_LENGTH));
|
||||
assertThrows(ArrayIndexOutOfBoundsException.class, () ->
|
||||
inflater.setDictionary(dictionary, dictionary_offset, DICTIONARY_LENGTH));
|
||||
} finally {
|
||||
// Release Resources
|
||||
deflater.end();
|
||||
inflater.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
175
test/jdk/java/util/zip/EntryCount64k.java
Normal file
175
test/jdk/java/util/zip/EntryCount64k.java
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Google Inc. All rights reserved.
|
||||
* Copyright (c) 2024, 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.
|
||||
*
|
||||
* 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
|
||||
* @summary Test java.util.zip behavior with ~64k entries
|
||||
* @library /test/lib
|
||||
* @run main/othervm EntryCount64k
|
||||
* @run main/othervm -Djdk.util.zip.inhibitZip64=true EntryCount64k
|
||||
* @run main/othervm -Djdk.util.zip.inhibitZip64=false EntryCount64k
|
||||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
public class EntryCount64k {
|
||||
|
||||
private static final String MAIN_CLASS_MSG = "foo bar hello world Main";
|
||||
|
||||
public static class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println(MAIN_CLASS_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
static final String MAIN_CLASS = "EntryCount64k$Main";
|
||||
static final String THIS_CLASS = "EntryCount64k";
|
||||
static final String[] SPECIAL_CLASSES = { MAIN_CLASS, THIS_CLASS };
|
||||
// static final String[] SPECIAL_CLASSES = { MAIN_CLASS };
|
||||
static final int SPECIAL_COUNT = 1 + SPECIAL_CLASSES.length;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
for (int i = (1 << 16) - 3; i < (1 << 16) + 2; i++)
|
||||
test(i);
|
||||
}
|
||||
|
||||
static void test(int entryCount) throws Throwable {
|
||||
File zipFile = new File("EntryCount64k-tmp.zip");
|
||||
zipFile.delete();
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos)) {
|
||||
|
||||
// Add entries to allow the zip file to be used with "java -jar"
|
||||
zos.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
|
||||
for (String line : new String[] {
|
||||
"Manifest-Version: 1.0",
|
||||
"Main-Class: " + MAIN_CLASS,
|
||||
})
|
||||
zos.write((line + "\n").getBytes("US-ASCII"));
|
||||
zos.closeEntry();
|
||||
|
||||
String testClasses = System.getProperty("test.classes");
|
||||
for (String className : SPECIAL_CLASSES) {
|
||||
String baseName = className + ".class";
|
||||
ZipEntry ze = new ZipEntry(baseName);
|
||||
File file = new File(testClasses, baseName);
|
||||
zos.putNextEntry(ze);
|
||||
Files.copy(file.toPath(), zos);
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
for (int i = SPECIAL_COUNT; i < entryCount; i++) {
|
||||
zos.putNextEntry(new ZipEntry(Integer.toString(i)));
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
String p = System.getProperty("jdk.util.zip.inhibitZip64");
|
||||
boolean tooManyEntries = entryCount >= (1 << 16) - 1;
|
||||
boolean shouldUseZip64 = tooManyEntries & !("true".equals(p));
|
||||
boolean usesZip64 = usesZip64(zipFile);
|
||||
String details = String.format
|
||||
("entryCount=%d shouldUseZip64=%s usesZip64=%s zipSize=%d%n",
|
||||
entryCount, shouldUseZip64, usesZip64, zipFile.length());
|
||||
System.err.println(details);
|
||||
checkCanRead(zipFile, entryCount);
|
||||
if (shouldUseZip64 != usesZip64)
|
||||
throw new Error(details);
|
||||
zipFile.delete();
|
||||
}
|
||||
|
||||
static boolean usesZip64(File zipFile) throws Exception {
|
||||
RandomAccessFile raf = new RandomAccessFile(zipFile, "r");
|
||||
byte[] buf = new byte[4096];
|
||||
raf.seek(raf.length() - buf.length);
|
||||
raf.read(buf);
|
||||
for (int i = 0; i < buf.length - 4; i++) {
|
||||
// Look for ZIP64 End Header Signature
|
||||
// Phil Katz: yes, we will always remember you
|
||||
if (buf[i+0] == 'P' &&
|
||||
buf[i+1] == 'K' &&
|
||||
buf[i+2] == 6 &&
|
||||
buf[i+3] == 6)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void checkCanRead(File zipFile, int entryCount) throws Throwable {
|
||||
// Check ZipInputStream API
|
||||
try (FileInputStream fis = new FileInputStream(zipFile);
|
||||
BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
ZipInputStream zis = new ZipInputStream(bis)) {
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
ZipEntry e = zis.getNextEntry();
|
||||
if (i >= SPECIAL_COUNT) // skip special entries
|
||||
if (Integer.parseInt(e.getName()) != i)
|
||||
throw new AssertionError(e.getName());
|
||||
}
|
||||
if (zis.getNextEntry() != null)
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// Check ZipFile API
|
||||
try (ZipFile zf = new ZipFile(zipFile)) {
|
||||
Enumeration<? extends ZipEntry> en = zf.entries();
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
ZipEntry e = en.nextElement();
|
||||
if (i >= SPECIAL_COUNT) // skip special entries
|
||||
if (Integer.parseInt(e.getName()) != i)
|
||||
throw new AssertionError();
|
||||
}
|
||||
if (en.hasMoreElements()
|
||||
|| (zf.size() != entryCount)
|
||||
|| (zf.getEntry(Integer.toString(entryCount - 1)) == null)
|
||||
|| (zf.getEntry(Integer.toString(entryCount)) != null))
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// Check java -jar
|
||||
OutputAnalyzer a = ProcessTools.executeTestJava("-jar", zipFile.getName());
|
||||
a.shouldHaveExitValue(0);
|
||||
// expect the message from the application on stdout
|
||||
a.stdoutContains(MAIN_CLASS_MSG);
|
||||
// nothing is expected on stderr (apart from any probable deprecation
|
||||
// warnings from the launcher/JVM)
|
||||
a.stderrShouldMatchIgnoreDeprecatedWarnings("\\A\\Z");
|
||||
}
|
||||
}
|
||||
76
test/jdk/java/util/zip/FileBuilder.java
Normal file
76
test/jdk/java/util/zip/FileBuilder.java
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2011, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* Driven by: 3GBZipFiles.sh
|
||||
*/
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
public class FileBuilder {
|
||||
private static void usageError() {
|
||||
System.err.println("Usage: FileBuilder filetype filename filesize");
|
||||
System.err.println("");
|
||||
System.err.println("Makes a file named FILENAME of size FILESIZE.");
|
||||
System.err.println("If FILETYPE is \"MostlyEmpty\", the file contents is mostly null bytes");
|
||||
System.err.println("(which might occupy no disk space if the right OS support exists).");
|
||||
System.err.println("If FILETYPE is \"SlightlyCompressible\", the file contents are");
|
||||
System.err.println("approximately 90% random data.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public static void main (String[] args) throws IOException {
|
||||
if (args.length != 3)
|
||||
usageError();
|
||||
String filetype = args[0];
|
||||
String filename = args[1];
|
||||
long filesize = Long.parseLong(args[2]);
|
||||
|
||||
if (! (filetype.equals("MostlyEmpty") ||
|
||||
filetype.equals("SlightlyCompressible")))
|
||||
usageError();
|
||||
|
||||
try (RandomAccessFile raf = new RandomAccessFile(filename, "rw")) {
|
||||
if (filetype.equals("SlightlyCompressible")) {
|
||||
byte[] randomBytes = new byte[16384];
|
||||
byte[] nullBytes = new byte[randomBytes.length/10];
|
||||
Random rand = new Random();
|
||||
for (int i = 0; raf.length() < filesize; ++i) {
|
||||
rand.nextBytes(randomBytes);
|
||||
raf.write(nullBytes);
|
||||
raf.write(randomBytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure file is exactly the requested size, and that
|
||||
// a unique identifying trailer is written.
|
||||
byte[] filenameBytes = filename.getBytes("UTF8");
|
||||
raf.seek(filesize-filenameBytes.length);
|
||||
raf.write(filenameBytes);
|
||||
raf.setLength(filesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
295
test/jdk/java/util/zip/FlaterCriticalArray.java
Normal file
295
test/jdk/java/util/zip/FlaterCriticalArray.java
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ZIP inflater/deflater performance.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Run this test on JDK 6 and on later
|
||||
* JDKs to compare results:
|
||||
* java -server -Xms1024M -Xmx1024M -Ddebug=true FlaterCriticalArray
|
||||
*
|
||||
* The performance issues can be readily seen on JDK 6, and so this code is
|
||||
* written to compile on that platform: it does *not* use any JDK 7 - specific
|
||||
* features.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class FlaterCriticalArray {
|
||||
// If true, print information about performance
|
||||
private static final boolean debug = System.getProperty("debug") != null;
|
||||
|
||||
private static void debug(String s) {
|
||||
if (debug) System.out.println(s);
|
||||
}
|
||||
|
||||
private static void debug(String name, String inOut, long time, int length) {
|
||||
debug(name + ": Duration of " + inOut + "(in ms): " + time);
|
||||
debug(name + ": " + inOut + "d data length: " + length + " bytes");
|
||||
}
|
||||
|
||||
private static byte[] grow(byte[] a, int capacity) {
|
||||
while (a.length < capacity) {
|
||||
byte[] a2 = new byte[a.length * 2];
|
||||
System.arraycopy(a, 0, a2, 0, a.length);
|
||||
a = a2;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
private static byte[] trim(byte[] a, int length) {
|
||||
byte[] res = new byte[length];
|
||||
System.arraycopy(a, 0, res, 0, length);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Base class for individual test cases
|
||||
*/
|
||||
private abstract static class TestCase {
|
||||
protected String name; // For information in debug messages
|
||||
protected byte data[]; // Data to be deflated and subsequently inflated
|
||||
protected int level; // Compression level for deflater
|
||||
|
||||
protected TestCase(String name, byte data[]) {
|
||||
this(name, data, -1);
|
||||
}
|
||||
|
||||
protected TestCase(String name, byte data[], int level) {
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public void runTest() throws Throwable {
|
||||
long time0, time1;
|
||||
byte deflated[], inflated[];
|
||||
|
||||
debug("");
|
||||
|
||||
time0 = System.currentTimeMillis();
|
||||
deflated = deflate(data, level);
|
||||
time1 = System.currentTimeMillis();
|
||||
inform("Deflate", time1 - time0, deflated.length);
|
||||
|
||||
time0 = System.currentTimeMillis();
|
||||
inflated = inflate(deflated);
|
||||
time1 = System.currentTimeMillis();
|
||||
inform("Inflate", time1 - time0, inflated.length);
|
||||
|
||||
check(Arrays.equals(data, inflated),
|
||||
name + ": Inflated and deflated arrays do not match");
|
||||
}
|
||||
|
||||
private void inform(String inOut, long duration, int length) {
|
||||
debug(name, inOut, duration, length);
|
||||
}
|
||||
|
||||
protected abstract byte[] deflate(byte data[], int level) throws Throwable;
|
||||
|
||||
protected abstract byte[] inflate(byte deflated[]) throws Throwable;
|
||||
}
|
||||
|
||||
/*
|
||||
* Following are the individual test cases
|
||||
*/
|
||||
|
||||
private static class StrideTest extends TestCase {
|
||||
static final int STRIDE = 1024;
|
||||
|
||||
public StrideTest(byte data[], int level) {
|
||||
super("STRIDE", data, level);
|
||||
}
|
||||
|
||||
protected byte[] deflate(byte in[], int level) throws Throwable {
|
||||
final int len = in.length;
|
||||
final Deflater deflater = new Deflater(level);
|
||||
final byte[] smallBuffer = new byte[32];
|
||||
byte[] flated = new byte[32];
|
||||
int count = 0;
|
||||
for (int i = 0; i<len; i+= STRIDE) {
|
||||
deflater.setInput(in, i, Math.min(STRIDE, len-i));
|
||||
while (!deflater.needsInput()) {
|
||||
int n = deflater.deflate(smallBuffer);
|
||||
flated = grow(flated, count + n);
|
||||
System.arraycopy(smallBuffer, 0, flated, count, n);
|
||||
count += n;
|
||||
}
|
||||
}
|
||||
deflater.finish();
|
||||
int n;
|
||||
do {
|
||||
n = deflater.deflate(smallBuffer);
|
||||
flated = grow(flated, count + n);
|
||||
System.arraycopy(smallBuffer, 0, flated, count, n);
|
||||
count += n;
|
||||
} while (n > 0);
|
||||
return trim(flated, count);
|
||||
}
|
||||
|
||||
protected byte[] inflate(byte in[]) throws Throwable {
|
||||
final int len = in.length;
|
||||
final Inflater inflater = new Inflater();
|
||||
final byte[] smallBuffer = new byte[3200];
|
||||
|
||||
byte[] flated = new byte[32];
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i<len; i+= STRIDE) {
|
||||
inflater.setInput(in, i, Math.min(STRIDE, len-i));
|
||||
while (!inflater.needsInput()) {
|
||||
int n;
|
||||
while ((n = inflater.inflate(smallBuffer)) > 0) {
|
||||
flated = grow(flated, count + n);
|
||||
System.arraycopy(smallBuffer, 0, flated, count, n);
|
||||
count += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
return trim(flated, count);
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoStrideTest extends TestCase {
|
||||
public NoStrideTest(byte data[], int level) {
|
||||
super("NO STRIDE", data, level);
|
||||
}
|
||||
|
||||
public byte[] deflate(byte in[], int level) throws Throwable {
|
||||
final Deflater flater = new Deflater(level);
|
||||
flater.setInput(in);
|
||||
flater.finish();
|
||||
final byte[] smallBuffer = new byte[32];
|
||||
byte[] flated = new byte[32];
|
||||
int count = 0;
|
||||
int n;
|
||||
while ((n = flater.deflate(smallBuffer)) > 0) {
|
||||
flated = grow(flated, count + n);
|
||||
System.arraycopy(smallBuffer, 0, flated, count, n);
|
||||
count += n;
|
||||
}
|
||||
return trim(flated, count);
|
||||
}
|
||||
|
||||
public byte[] inflate(byte in[]) throws Throwable {
|
||||
final Inflater flater = new Inflater();
|
||||
flater.setInput(in);
|
||||
final byte[] smallBuffer = new byte[32];
|
||||
byte[] flated = new byte[32];
|
||||
int count = 0;
|
||||
int n;
|
||||
while ((n = flater.inflate(smallBuffer)) > 0) {
|
||||
flated = grow(flated, count + n);
|
||||
System.arraycopy(smallBuffer, 0, flated, count, n);
|
||||
count += n;
|
||||
}
|
||||
return trim(flated, count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Deflater{In,Out}putStream by way of GZIP{In,Out}putStream
|
||||
*/
|
||||
private static class GZIPTest extends TestCase {
|
||||
public GZIPTest(byte data[]) {
|
||||
super("GZIP", data);
|
||||
}
|
||||
|
||||
public byte[] deflate(byte data[], int ignored) throws Throwable {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
OutputStream gzos = new GZIPOutputStream(baos);
|
||||
gzos.write(data, 0, data.length);
|
||||
gzos.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public byte[] inflate(byte deflated[]) throws Throwable {
|
||||
InputStream bais = new ByteArrayInputStream(deflated);
|
||||
GZIPInputStream gzis = new GZIPInputStream(bais);
|
||||
byte[] inflated = new byte[data.length];
|
||||
int numRead = 0;
|
||||
int count = 0;
|
||||
while ((numRead = gzis.read(inflated, count, data.length - count)) > 0) {
|
||||
count += numRead;
|
||||
}
|
||||
check(count == data.length, name + ": Read " + count + "; expected " + data.length);
|
||||
return inflated;
|
||||
}
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
byte data[];
|
||||
int level = -1;
|
||||
if (args.length > 0) {
|
||||
level = Integer.parseInt(args[0]);
|
||||
}
|
||||
debug("Using level " + level);
|
||||
|
||||
if (args.length > 1) {
|
||||
FileInputStream fis = new FileInputStream(args[1]);
|
||||
int len = fis.available();
|
||||
data = new byte[len];
|
||||
check(fis.read(data, 0, len) == len, "Did not read complete file");
|
||||
debug("Original data from " + args[1]);
|
||||
fis.close();
|
||||
} else {
|
||||
ByteBuffer bb = ByteBuffer.allocate(8);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < 1024 * 64; i++) { // data length
|
||||
bb.putDouble(0, Math.random());
|
||||
baos.write(bb.array(), 0, 8);
|
||||
}
|
||||
data = baos.toByteArray();
|
||||
debug("Original data from random byte array");
|
||||
}
|
||||
debug("Original data length: " + data.length + " bytes");
|
||||
|
||||
new StrideTest(data, level).runTest();
|
||||
new NoStrideTest(data, level).runTest();
|
||||
new GZIPTest(data).runTest();
|
||||
}
|
||||
|
||||
//--------------------- 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;}
|
||||
static boolean check(boolean cond, String msg) {if (cond) pass(); else fail(msg); return cond;}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
226
test/jdk/java/util/zip/FlaterTest.java
Normal file
226
test/jdk/java/util/zip/FlaterTest.java
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2019, 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.
|
||||
*
|
||||
* 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 6348045 6341887 8231770
|
||||
* @summary GZipOutputStream/InputStream goes critical(calls JNI_Get*Critical)
|
||||
* and causes slowness. This test uses Deflater and Inflater directly.
|
||||
* @key randomness
|
||||
* @run main/othervm -Xcheck:jni FlaterTest
|
||||
*/
|
||||
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
/**
|
||||
* This test runs Inflater and Defalter in a number of simultaneous threads,
|
||||
* validating that the deflated & then inflated data matches the original
|
||||
* data.
|
||||
*/
|
||||
public class FlaterTest extends Thread {
|
||||
private static final int DATA_LEN = 1024 * 128;
|
||||
|
||||
private static ByteBuffer dataDirect;
|
||||
private static ByteBuffer dataHeap;
|
||||
|
||||
// If true, print extra info.
|
||||
private static final boolean debug = false;
|
||||
|
||||
// Set of Flater threads running.
|
||||
private static Set<Flater> flaters =
|
||||
Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
/** Fill in {@code data} with random values. */
|
||||
static void createData() {
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(DATA_LEN * 8);
|
||||
for (int i = 0; i < DATA_LEN * 8; i += 8) {
|
||||
bb.putDouble(i, Math.random());
|
||||
}
|
||||
dataDirect = bb;
|
||||
final ByteBuffer hb = ByteBuffer.allocate(bb.capacity());
|
||||
hb.duplicate().put(bb.duplicate());
|
||||
dataHeap = hb;
|
||||
if (debug) System.out.println("data length is " + bb.capacity());
|
||||
}
|
||||
|
||||
/** @return the length of the deflated {@code data}. */
|
||||
private static int getDeflatedLength() {
|
||||
Deflater deflater = new Deflater();
|
||||
deflater.setInput(dataDirect.duplicate());
|
||||
deflater.finish();
|
||||
byte[] out = new byte[dataDirect.capacity()];
|
||||
int rc = deflater.deflate(out);
|
||||
deflater.end();
|
||||
if (debug) System.out.println("deflatedLength is " + rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** Compares given bytes with those in {@code data}.
|
||||
* @throws Exception if given bytes don't match {@code data}.
|
||||
*/
|
||||
private static void validate(ByteBuffer buf, int offset, int len) throws Exception {
|
||||
for (int i = 0; i < len; i++ ) {
|
||||
if (buf.get(i) != dataDirect.get(offset+i)) {
|
||||
throw new Exception("mismatch at " + (offset + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) {
|
||||
int numThreads = args.length > 0 ? Integer.parseInt(args[0]) : 5;
|
||||
createData();
|
||||
for (int srcMode = 0; srcMode <= 2; srcMode ++) {
|
||||
for (int dstMode = 0; dstMode <= 2; dstMode ++) {
|
||||
new FlaterTest().go(numThreads, srcMode, dstMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void go(int numThreads, int srcMode, int dstMode) {
|
||||
int deflatedLength = getDeflatedLength();
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
Flater f = new Flater(deflatedLength, srcMode, dstMode);
|
||||
flaters.add(f);
|
||||
f.start();
|
||||
}
|
||||
synchronized (flaters) {
|
||||
while (flaters.size() != 0) {
|
||||
try {
|
||||
flaters.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
unexpected(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
time = System.currentTimeMillis() - time;
|
||||
System.out.println("Time needed for " + numThreads
|
||||
+ " threads to deflate/inflate: " + time + " ms (srcMode="+srcMode+",dstMode="+dstMode+")");
|
||||
}
|
||||
|
||||
/** Deflates and inflates data. */
|
||||
static class Flater extends Thread {
|
||||
private final int deflatedLength;
|
||||
private final int srcMode, dstMode;
|
||||
|
||||
private Flater(int length, int srcMode, int dstMode) {
|
||||
this.deflatedLength = length;
|
||||
this.srcMode = srcMode;
|
||||
this.dstMode = dstMode;
|
||||
}
|
||||
|
||||
/** Deflates and inflates {@code data}. */
|
||||
public void run() {
|
||||
if (debug) System.out.println(getName() + " starting run()");
|
||||
try {
|
||||
ByteBuffer deflated = DeflateData(deflatedLength);
|
||||
InflateData(deflated);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
fail(getName() + " failed");
|
||||
} finally {
|
||||
synchronized (flaters) {
|
||||
flaters.remove(this);
|
||||
if (flaters.isEmpty()) {
|
||||
flaters.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a copy of {@code data} in deflated form. */
|
||||
private ByteBuffer DeflateData(int length) {
|
||||
Deflater deflater = new Deflater();
|
||||
if (srcMode == 0) {
|
||||
deflater.setInput(dataHeap.array());
|
||||
} else if (srcMode == 1) {
|
||||
deflater.setInput(dataHeap.duplicate());
|
||||
} else {
|
||||
assert srcMode == 2;
|
||||
deflater.setInput(dataDirect.duplicate());
|
||||
}
|
||||
deflater.finish();
|
||||
ByteBuffer out = dstMode == 2 ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length);
|
||||
int deflated;
|
||||
if (dstMode == 0) {
|
||||
deflated = deflater.deflate(out.array(), 0, length);
|
||||
out.position(deflated);
|
||||
} else {
|
||||
deflater.deflate(out);
|
||||
}
|
||||
out.flip();
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Inflate a byte array, comparing it with {@code data} during
|
||||
* inflation.
|
||||
* @throws Exception if inflated bytes don't match {@code data}.
|
||||
*/
|
||||
private void InflateData(ByteBuffer bytes) throws Throwable {
|
||||
Inflater inflater = new Inflater();
|
||||
if (dstMode == 0) {
|
||||
inflater.setInput(bytes.array(), 0, bytes.remaining());
|
||||
} else {
|
||||
inflater.setInput(bytes);
|
||||
}
|
||||
if (inflater.getRemaining() == 0) {
|
||||
throw new Exception("Nothing to inflate (bytes=" + bytes + ")");
|
||||
}
|
||||
int len = 1024 * 8;
|
||||
int offset = 0;
|
||||
ByteBuffer buf = srcMode == 2 ? ByteBuffer.allocateDirect(len) : ByteBuffer.allocate(len);
|
||||
while (inflater.getRemaining() > 0) {
|
||||
buf.clear();
|
||||
int inflated;
|
||||
if (srcMode == 0) {
|
||||
inflated = inflater.inflate(buf.array(), 0, buf.remaining());
|
||||
} else {
|
||||
inflated = inflater.inflate(buf);
|
||||
}
|
||||
if (inflated == 0) {
|
||||
throw new Exception("Nothing inflated (dst=" + buf + ",offset=" + offset + ",rem=" + inflater.getRemaining() + ",srcMode="+srcMode+",dstMode="+dstMode+")");
|
||||
}
|
||||
validate(buf, offset, inflated);
|
||||
offset += inflated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {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 check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
91
test/jdk/java/util/zip/GZIP/Accordion.java
Normal file
91
test/jdk/java/util/zip/GZIP/Accordion.java
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2011, 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.
|
||||
*
|
||||
* 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 5092263
|
||||
* @summary GZIPInputStream o GZIPOutputStream === the identity stream
|
||||
* @author Martin Buchholz
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
// To manually test for uncompressed streams larger than 2GB, do
|
||||
// javac Accordion.java && java -server Accordion 3325349068
|
||||
// javac Accordion.java && java -server Accordion 5470735564
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class Accordion {
|
||||
private static void readFully(InputStream s, byte[] buf) throws Throwable {
|
||||
int pos = 0;
|
||||
int n;
|
||||
while ((n = s.read(buf, pos, buf.length-pos)) > 0)
|
||||
pos += n;
|
||||
if (pos != buf.length)
|
||||
throw new Exception("Unexpected EOF");
|
||||
}
|
||||
|
||||
private static volatile Throwable trouble;
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
if (args.length > 1)
|
||||
throw new Exception("Usage: java Accordion [BYTES]");
|
||||
|
||||
final long bytes = args.length == 0 ? 10001 : Long.parseLong(args[0]);
|
||||
final int bufsize = 1729;
|
||||
final long count = bytes/bufsize;
|
||||
final PipedOutputStream out = new PipedOutputStream();
|
||||
final PipedInputStream in = new PipedInputStream(out);
|
||||
final Random random = new Random();
|
||||
final byte[] data = new byte[1729];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
data[i] = (byte)random.nextInt(255);
|
||||
System.out.println("count="+count);
|
||||
|
||||
Thread compressor = new Thread() { public void run() {
|
||||
try (GZIPOutputStream s = new GZIPOutputStream(out)) {
|
||||
for (long i = 0; i < count; i++)
|
||||
s.write(data, 0, data.length);
|
||||
} catch (Throwable t) { trouble = t; }}};
|
||||
|
||||
Thread uncompressor = new Thread() { public void run() {
|
||||
try (GZIPInputStream s = new GZIPInputStream(in)) {
|
||||
final byte[] maybeBytes = new byte[data.length];
|
||||
for (long i = 0; i < count; i++) {
|
||||
readFully(s, maybeBytes);
|
||||
if (! Arrays.equals(data, maybeBytes))
|
||||
throw new Exception("data corruption");
|
||||
}
|
||||
if (s.read(maybeBytes, 0, 1) > 0)
|
||||
throw new Exception("Unexpected NON-EOF");
|
||||
} catch (Throwable t) { trouble = t; }}};
|
||||
|
||||
compressor.start(); uncompressor.start();
|
||||
compressor.join(); uncompressor.join();
|
||||
|
||||
if (trouble != null)
|
||||
throw trouble;
|
||||
}
|
||||
}
|
||||
95
test/jdk/java/util/zip/GZIP/BasicGZIPInputStreamTest.java
Normal file
95
test/jdk/java/util/zip/GZIP/BasicGZIPInputStreamTest.java
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary basic API verification tests for GZIPInputStream
|
||||
* @run junit BasicGZIPInputStreamTest
|
||||
*/
|
||||
public class BasicGZIPInputStreamTest {
|
||||
|
||||
|
||||
private static Stream<Arguments> npeFromConstructors() {
|
||||
return Stream.of(Arguments.of((Executable) () -> new GZIPInputStream(null)),
|
||||
Arguments.of((Executable) () -> new GZIPInputStream(null, 1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that the GZIPInputStream constructors throw the expected NullPointerException
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("npeFromConstructors")
|
||||
public void testNPEFromConstructors(final Executable constructor) {
|
||||
Assertions.assertThrows(NullPointerException.class, constructor,
|
||||
"GZIPInputStream constructor did not throw NullPointerException");
|
||||
}
|
||||
|
||||
private static Stream<Arguments> iaeFromConstructors() {
|
||||
return Stream.of(
|
||||
Arguments.of((Executable) () -> new GZIPInputStream(
|
||||
new ByteArrayInputStream(new byte[0]), 0)),
|
||||
Arguments.of((Executable) () -> new GZIPInputStream(
|
||||
new ByteArrayInputStream(new byte[0]), -1)),
|
||||
Arguments.of((Executable) () -> new GZIPInputStream(
|
||||
new ByteArrayInputStream(new byte[0]), -42)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that the GZIPInputStream constructors throw the expected IllegalArgumentException
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("iaeFromConstructors")
|
||||
public void testIAEFromConstructors(final Executable constructor) {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, constructor,
|
||||
"GZIPInputStream constructor did not throw IllegalArgumentException");
|
||||
}
|
||||
|
||||
private static Stream<Arguments> ioeFromConstructors() {
|
||||
final ByteArrayInputStream notGZIPContent = new ByteArrayInputStream(new byte[0]);
|
||||
return Stream.of(
|
||||
Arguments.of((Executable) () -> new GZIPInputStream(notGZIPContent)),
|
||||
Arguments.of((Executable) () -> new GZIPInputStream(
|
||||
notGZIPContent, 1024 /* buffer size */)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Verifies that the GZIPInputStream constructors throw the expected IOException
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("ioeFromConstructors")
|
||||
public void testIOEFromConstructors(final Executable constructor) {
|
||||
Assertions.assertThrows(IOException.class, constructor,
|
||||
"GZIPInputStream constructor did not throw IOException");
|
||||
}
|
||||
}
|
||||
97
test/jdk/java/util/zip/GZIP/GZIPInZip.java
Normal file
97
test/jdk/java/util/zip/GZIP/GZIPInZip.java
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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.
|
||||
*
|
||||
* 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 7021870 8023431 8026756
|
||||
* @summary Reading last gzip chain member must not close the input stream.
|
||||
* Garbage following gzip entry must be ignored.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
|
||||
public class GZIPInZip {
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Throwable {
|
||||
|
||||
doTest(false, false);
|
||||
doTest(false, true);
|
||||
doTest(true, false);
|
||||
doTest(true, true);
|
||||
}
|
||||
|
||||
private static void doTest(final boolean appendGarbage,
|
||||
final boolean limitGISBuff)
|
||||
throws Throwable {
|
||||
|
||||
byte[] buf;
|
||||
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
|
||||
final byte[] xbuf = { 'x' };
|
||||
|
||||
zos.putNextEntry(new ZipEntry("a.gz"));
|
||||
GZIPOutputStream gos1 = new GZIPOutputStream(zos);
|
||||
gos1.write(xbuf);
|
||||
gos1.finish();
|
||||
if (appendGarbage)
|
||||
zos.write(xbuf);
|
||||
zos.closeEntry();
|
||||
|
||||
zos.putNextEntry(new ZipEntry("b.gz"));
|
||||
GZIPOutputStream gos2 = new GZIPOutputStream(zos);
|
||||
gos2.write(xbuf);
|
||||
gos2.finish();
|
||||
zos.closeEntry();
|
||||
|
||||
zos.flush();
|
||||
buf = baos.toByteArray();
|
||||
}
|
||||
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(buf);
|
||||
ZipInputStream zis = new ZipInputStream(bais)) {
|
||||
|
||||
zis.getNextEntry();
|
||||
GZIPInputStream gis1 = limitGISBuff ?
|
||||
new GZIPInputStream(zis, 4) :
|
||||
new GZIPInputStream(zis);
|
||||
// try to read more than the entry has
|
||||
gis1.skip(2);
|
||||
|
||||
try {
|
||||
zis.getNextEntry();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("ZIP stream was prematurely closed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
93
test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java
Normal file
93
test/jdk/java/util/zip/GZIP/GZIPInputStreamAvailable.java
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2024, 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.
|
||||
*
|
||||
* 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 7036144
|
||||
* @summary Test concatenated gz streams when available() returns zero
|
||||
* @run junit GZIPInputStreamAvailable
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
|
||||
public class GZIPInputStreamAvailable {
|
||||
|
||||
public static final int NUM_COPIES = 100;
|
||||
|
||||
@Test
|
||||
public void testZeroAvailable() throws IOException {
|
||||
|
||||
// Create some uncompressed data and then repeat it NUM_COPIES times
|
||||
byte[] uncompressed1 = "this is a test".getBytes("ASCII");
|
||||
byte[] uncompressedN = repeat(uncompressed1, NUM_COPIES);
|
||||
|
||||
// Compress the original data and then repeat that NUM_COPIES times
|
||||
byte[] compressed1 = deflate(uncompressed1);
|
||||
byte[] compressedN = repeat(compressed1, NUM_COPIES);
|
||||
|
||||
// (a) Read back inflated data from a stream where available() is accurate and verify
|
||||
byte[] readback1 = inflate(new ByteArrayInputStream(compressedN));
|
||||
assertArrayEquals(uncompressedN, readback1);
|
||||
|
||||
// (b) Read back inflated data from a stream where available() always returns zero and verify
|
||||
byte[] readback2 = inflate(new ZeroAvailableStream(new ByteArrayInputStream(compressedN)));
|
||||
assertArrayEquals(uncompressedN, readback2);
|
||||
}
|
||||
|
||||
public static byte[] repeat(byte[] data, int count) {
|
||||
byte[] repeat = new byte[data.length * count];
|
||||
int off = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
System.arraycopy(data, 0, repeat, off, data.length);
|
||||
off += data.length;
|
||||
}
|
||||
return repeat;
|
||||
}
|
||||
|
||||
public static byte[] deflate(byte[] data) throws IOException {
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream out = new GZIPOutputStream(buf)) {
|
||||
out.write(data);
|
||||
}
|
||||
return buf.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] inflate(InputStream in) throws IOException {
|
||||
return new GZIPInputStream(in).readAllBytes();
|
||||
}
|
||||
|
||||
public static class ZeroAvailableStream extends FilterInputStream {
|
||||
public ZeroAvailableStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
@Override
|
||||
public int available() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
101
test/jdk/java/util/zip/GZIP/GZIPInputStreamRead.java
Normal file
101
test/jdk/java/util/zip/GZIP/GZIPInputStreamRead.java
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2011, 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.
|
||||
*
|
||||
* 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 4691425
|
||||
* @summary Test the read and write of GZIPInput/OutputStream, including
|
||||
* concatenated .gz inputstream
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class GZIPInputStreamRead {
|
||||
public static void main(String[] args) throws Throwable {
|
||||
Random rnd = new Random();
|
||||
for (int i = 1; i < 100; i++) {
|
||||
int members = rnd.nextInt(10) + 1;
|
||||
|
||||
ByteArrayOutputStream srcBAOS = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream dstBAOS = new ByteArrayOutputStream();
|
||||
for (int j = 0; j < members; j++) {
|
||||
byte[] src = new byte[rnd.nextInt(8192) + 1];
|
||||
rnd.nextBytes(src);
|
||||
srcBAOS.write(src);
|
||||
|
||||
try (GZIPOutputStream gzos = new GZIPOutputStream(dstBAOS)) {
|
||||
gzos.write(src);
|
||||
}
|
||||
}
|
||||
byte[] srcBytes = srcBAOS.toByteArray();
|
||||
byte[] dstBytes = dstBAOS.toByteArray();
|
||||
// try different size of buffer to read the
|
||||
// GZIPInputStream
|
||||
/* just for fun when running manually
|
||||
for (int j = 1; j < 10; j++) {
|
||||
test(srcBytes, dstBytes, j);
|
||||
}
|
||||
*/
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int readBufSZ = rnd.nextInt(2048) + 1;
|
||||
test(srcBytes,
|
||||
dstBytes,
|
||||
readBufSZ,
|
||||
512); // the defualt buffer size
|
||||
test(srcBytes,
|
||||
dstBytes,
|
||||
readBufSZ,
|
||||
rnd.nextInt(4096) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void test(byte[] src, byte[] dst,
|
||||
int readBufSize, int gzisBufSize)
|
||||
throws Throwable
|
||||
{
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(dst);
|
||||
GZIPInputStream gzis = new GZIPInputStream(bais, gzisBufSize))
|
||||
{
|
||||
byte[] result = new byte[src.length + 10];
|
||||
byte[] buf = new byte[readBufSize];
|
||||
int n = 0;
|
||||
int off = 0;
|
||||
|
||||
while ((n = gzis.read(buf, 0, buf.length)) != -1) {
|
||||
System.arraycopy(buf, 0, result, off, n);
|
||||
off += n;
|
||||
// no range check, if overflow, let it fail
|
||||
}
|
||||
if (off != src.length || gzis.available() != 0 ||
|
||||
!Arrays.equals(src, Arrays.copyOf(result, off))) {
|
||||
throw new RuntimeException(
|
||||
"GZIPInputStream reading failed! " +
|
||||
", src.len=" + src.length +
|
||||
", read=" + off);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
test/jdk/java/util/zip/GZIP/GZIPOutputStreamHeaderTest.java
Normal file
76
test/jdk/java/util/zip/GZIP/GZIPOutputStreamHeaderTest.java
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8244706
|
||||
* @summary Verify that the OS header flag in the stream written out by java.util.zip.GZIPOutputStream
|
||||
* has the correct expected value
|
||||
* @run junit GZIPOutputStreamHeaderTest
|
||||
*/
|
||||
public class GZIPOutputStreamHeaderTest {
|
||||
|
||||
private static final int OS_HEADER_INDEX = 9;
|
||||
private static final int HEADER_VALUE_OS_UNKNOWN = 255;
|
||||
|
||||
/**
|
||||
* Test that the {@code OS} header field in the GZIP output stream
|
||||
* has a value of {@code 255} which represents "unknown"
|
||||
*/
|
||||
@Test
|
||||
public void testOSHeader() throws Exception {
|
||||
final String data = "Hello world!!!";
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos);) {
|
||||
gzipOutputStream.write(data.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
final byte[] compressed = baos.toByteArray();
|
||||
assertNotNull(compressed, "Compressed data is null");
|
||||
assertEquals(HEADER_VALUE_OS_UNKNOWN, toUnsignedByte(compressed[OS_HEADER_INDEX]),
|
||||
"Unexpected value for OS header");
|
||||
// finally verify that the compressed data is readable back to the original
|
||||
final String uncompressed;
|
||||
try (final ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
final ByteArrayInputStream bis = new ByteArrayInputStream(compressed);
|
||||
final GZIPInputStream gzipInputStream = new GZIPInputStream(bis)) {
|
||||
gzipInputStream.transferTo(os);
|
||||
uncompressed = new String(os.toByteArray(), StandardCharsets.UTF_8);
|
||||
}
|
||||
assertEquals(data, uncompressed, "Unexpected data read from GZIPInputStream");
|
||||
}
|
||||
|
||||
private static int toUnsignedByte(final byte b) {
|
||||
return b & 0xff;
|
||||
}
|
||||
}
|
||||
72
test/jdk/java/util/zip/GZIP/ReadUByte.java
Normal file
72
test/jdk/java/util/zip/GZIP/ReadUByte.java
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*
|
||||
* 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 6336960
|
||||
* @summary Validate that GZIPInputStream.readUByte throws the correct
|
||||
* exception when read() on the InputStream with which the GZIPInputStream was
|
||||
* created returns an out-of-bounds value.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class ReadUByte {
|
||||
/** Guaranteed to return a value that is out-of-spec for read(). */
|
||||
static class BrokenInputStream extends ByteArrayInputStream {
|
||||
BrokenInputStream() {
|
||||
super(new byte[16]);
|
||||
}
|
||||
|
||||
public int read() {
|
||||
return -33;
|
||||
}
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
try {
|
||||
new GZIPInputStream(new BrokenInputStream());
|
||||
fail("Failed to throw expected IOException");
|
||||
} catch (IOException ex) {
|
||||
String msg = ex.getMessage();
|
||||
if (msg.indexOf("ReadUByte$BrokenInputStream.read() returned value out of range") < 0) {
|
||||
fail("IOException contains incorrect message: '" + msg + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {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 check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
500
test/jdk/java/util/zip/InflateIn_DeflateOut.java
Normal file
500
test/jdk/java/util/zip/InflateIn_DeflateOut.java
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* Copyright 2009 Google, Inc. All Rights Reserved.
|
||||
* Copyright (c) 2025, 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.
|
||||
*
|
||||
* 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 4206909 4813885 8191918
|
||||
* @summary Test basic functionality of DeflaterOutputStream/InflaterInputStream
|
||||
* and GZIPOutputStream/GZIPInputStream, including flush
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class InflateIn_DeflateOut {
|
||||
|
||||
private static class PairedInputStream extends ByteArrayInputStream {
|
||||
private PairedOutputStream out = null;
|
||||
private Random random;
|
||||
|
||||
public PairedInputStream() {
|
||||
// The ByteArrayInputStream needs to start with a buffer, but we
|
||||
// need to set it to have no data
|
||||
super(new byte[1]);
|
||||
count = 0;
|
||||
pos = 0;
|
||||
random = new Random(new Date().getTime());
|
||||
}
|
||||
|
||||
public void setPairedOutputStream(PairedOutputStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
private void maybeFlushPair() {
|
||||
if (random.nextInt(100) < 10) {
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public int read() {
|
||||
maybeFlushPair();
|
||||
return super.read();
|
||||
}
|
||||
|
||||
public int read(byte b[], int off, int len) {
|
||||
maybeFlushPair();
|
||||
return super.read(b, off, len);
|
||||
}
|
||||
|
||||
public void addBytes(byte[] bytes, int len) {
|
||||
int oldavail = count - pos;
|
||||
int newcount = oldavail + len;
|
||||
byte[] newbuf = new byte[newcount];
|
||||
System.arraycopy(buf, pos, newbuf, 0, oldavail);
|
||||
System.arraycopy(bytes, 0, newbuf, oldavail, len);
|
||||
pos = 0;
|
||||
count = newcount;
|
||||
buf = newbuf;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PairedOutputStream extends ByteArrayOutputStream {
|
||||
private PairedInputStream pairedStream = null;
|
||||
|
||||
public PairedOutputStream(PairedInputStream inputPair) {
|
||||
super();
|
||||
this.pairedStream = inputPair;
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
if (count > 0) {
|
||||
pairedStream.addBytes(buf, count);
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean readFully(InputStream in, byte[] buf, int length)
|
||||
throws IOException {
|
||||
int pos = 0;
|
||||
int n;
|
||||
while ((n = in.read(buf, pos, length - pos)) > 0) {
|
||||
pos += n;
|
||||
if (pos == length) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean readLineIfAvailable(InputStream in, StringBuilder sb)
|
||||
throws IOException {
|
||||
try {
|
||||
while (in.available() > 0) {
|
||||
int i = in.read();
|
||||
if (i < 0) break;
|
||||
char c = (char) (((byte) i) & 0xff);
|
||||
sb.append(c);
|
||||
if (c == '\n') return true;
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
// empty
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Check that written, closed and read */
|
||||
private static void WriteCloseRead() throws Throwable {
|
||||
Random random = new Random(new Date().getTime());
|
||||
|
||||
PairedInputStream pis = new PairedInputStream();
|
||||
InflaterInputStream iis = new InflaterInputStream(pis);
|
||||
|
||||
PairedOutputStream pos = new PairedOutputStream(pis);
|
||||
pis.setPairedOutputStream(pos);
|
||||
|
||||
byte[] data = new byte[random.nextInt(1024 * 1024)];
|
||||
byte[] buf = new byte[data.length];
|
||||
random.nextBytes(data);
|
||||
|
||||
try (DeflaterOutputStream dos = new DeflaterOutputStream(pos, true)) {
|
||||
dos.write(data);
|
||||
}
|
||||
check(readFully(iis, buf, buf.length));
|
||||
check(Arrays.equals(data, buf));
|
||||
}
|
||||
|
||||
private static void TestFlushableGZIPOutputStream() throws Throwable {
|
||||
var random = new Random(new Date().getTime());
|
||||
|
||||
var byteOutStream = new ByteArrayOutputStream();
|
||||
var output = new FlushableGZIPOutputStream(byteOutStream);
|
||||
|
||||
var data = new byte[random.nextInt(1024 * 1024)];
|
||||
var buf = new byte[data.length];
|
||||
random.nextBytes(data);
|
||||
|
||||
output.write(data);
|
||||
for (int i=0; i<data.length; i++) {
|
||||
output.write(data[i]);
|
||||
}
|
||||
output.flush();
|
||||
for (int i=0; i<data.length; i++) {
|
||||
output.write(data[i]);
|
||||
}
|
||||
output.write(data);
|
||||
output.close();
|
||||
|
||||
var baos = new ByteArrayOutputStream();
|
||||
try (var gzis = new GZIPInputStream(new
|
||||
ByteArrayInputStream(byteOutStream.toByteArray()))) {
|
||||
gzis.transferTo(baos);
|
||||
}
|
||||
var decompressedBytes = baos.toByteArray();
|
||||
check(decompressedBytes.length == data.length * 4);
|
||||
}
|
||||
|
||||
private static void check(InputStream is, OutputStream os)
|
||||
throws Throwable
|
||||
{
|
||||
Random random = new Random(new Date().getTime());
|
||||
// Large writes
|
||||
for (int x = 0; x < 200 ; x++) {
|
||||
// byte[] data = new byte[random.nextInt(1024 * 1024)];
|
||||
byte[] data = new byte[1024];
|
||||
byte[] buf = new byte[data.length];
|
||||
random.nextBytes(data);
|
||||
|
||||
os.write(data);
|
||||
os.flush();
|
||||
check(readFully(is, buf, buf.length));
|
||||
check(Arrays.equals(data, buf));
|
||||
}
|
||||
|
||||
// Small writes
|
||||
for (int x = 0; x < 2000 ; x++) {
|
||||
byte[] data = new byte[random.nextInt(20) + 10];
|
||||
byte[] buf = new byte[data.length];
|
||||
random.nextBytes(data);
|
||||
|
||||
os.write(data);
|
||||
os.flush();
|
||||
if (!readFully(is, buf, buf.length)) {
|
||||
fail("Didn't read full buffer of " + buf.length);
|
||||
}
|
||||
check(Arrays.equals(data, buf));
|
||||
}
|
||||
|
||||
String quit = "QUIT\r\n";
|
||||
|
||||
// Close it out
|
||||
os.write(quit.getBytes());
|
||||
os.close();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
check(readLineIfAvailable(is, sb));
|
||||
equal(sb.toString(), quit);
|
||||
}
|
||||
|
||||
/** Check that written, flushed and read */
|
||||
private static void WriteFlushRead() throws Throwable {
|
||||
PairedInputStream pis = new PairedInputStream();
|
||||
InflaterInputStream iis = new InflaterInputStream(pis);
|
||||
|
||||
PairedOutputStream pos = new PairedOutputStream(pis);
|
||||
pis.setPairedOutputStream(pos);
|
||||
DeflaterOutputStream dos = new DeflaterOutputStream(pos, true);
|
||||
|
||||
check(iis, dos);
|
||||
}
|
||||
|
||||
private static void GZWriteFlushRead() throws Throwable {
|
||||
PairedInputStream pis = new PairedInputStream();
|
||||
PairedOutputStream pos = new PairedOutputStream(pis);
|
||||
pis.setPairedOutputStream(pos);
|
||||
|
||||
GZIPOutputStream gos = new GZIPOutputStream(pos, true);
|
||||
gos.flush(); // flush the head out, so gis can read
|
||||
GZIPInputStream gis = new GZIPInputStream(pis);
|
||||
|
||||
check(gis, gos);
|
||||
}
|
||||
|
||||
private static void checkLOP(InputStream is, OutputStream os)
|
||||
throws Throwable
|
||||
{
|
||||
boolean flushed = false;
|
||||
int count = 0;
|
||||
|
||||
// Do at least a certain number of lines, but too many without a
|
||||
// flush means this test isn't testing anything
|
||||
while ((count < 10 && flushed) || (count < 1000 && !flushed)) {
|
||||
String command = "PING " + count + "\r\n";
|
||||
os.write(command.getBytes());
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if (!readLineIfAvailable(is, buf)) {
|
||||
flushed = true;
|
||||
os.flush();
|
||||
check(readLineIfAvailable(is, buf));
|
||||
}
|
||||
equal(buf.toString(), command);
|
||||
count++;
|
||||
}
|
||||
check(flushed);
|
||||
}
|
||||
|
||||
/** Validate that we need to use flush at least once on a line
|
||||
* oriented protocol */
|
||||
private static void LineOrientedProtocol() throws Throwable {
|
||||
PairedInputStream pis = new PairedInputStream();
|
||||
InflaterInputStream iis = new InflaterInputStream(pis);
|
||||
|
||||
PairedOutputStream pos = new PairedOutputStream(pis);
|
||||
pis.setPairedOutputStream(pos);
|
||||
DeflaterOutputStream dos = new DeflaterOutputStream(pos, true);
|
||||
|
||||
checkLOP(iis, dos);
|
||||
}
|
||||
|
||||
private static void GZLineOrientedProtocol() throws Throwable {
|
||||
PairedInputStream pis = new PairedInputStream();
|
||||
PairedOutputStream pos = new PairedOutputStream(pis);
|
||||
pis.setPairedOutputStream(pos);
|
||||
|
||||
GZIPOutputStream gos = new GZIPOutputStream(pos, true);
|
||||
gos.flush(); // flush the head out, so gis can read
|
||||
GZIPInputStream gis = new GZIPInputStream(pis);
|
||||
|
||||
checkLOP(gis, gos);
|
||||
}
|
||||
|
||||
private static byte[] deflate(final byte[] original) {
|
||||
final ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream();
|
||||
try (Deflater compressor = new Deflater()) {
|
||||
compressor.setInput(original);
|
||||
compressor.finish();
|
||||
while (!compressor.finished()) {
|
||||
byte[] tmpBuffer = new byte[1024];
|
||||
int numCompressed = compressor.deflate(tmpBuffer);
|
||||
compressedBaos.write(tmpBuffer, 0, numCompressed);
|
||||
}
|
||||
}
|
||||
return compressedBaos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that when a InflaterInputStream is constructed
|
||||
* by passing a Inflater instance, then closing the InflaterInputStream
|
||||
* will not close the passed Inflater instance.
|
||||
*/
|
||||
private static void inflaterInputStreamInflaterNotClosed() throws Throwable {
|
||||
// some arbitrary content
|
||||
final byte[] original = "foo".repeat(1024).getBytes(StandardCharsets.US_ASCII);
|
||||
// deflate it
|
||||
final byte[] deflated = deflate(original);
|
||||
// run the InflaterInputStream tests
|
||||
try (final Inflater infl = new Inflater()) {
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(deflated);
|
||||
InflaterInputStream iis = new InflaterInputStream(bis, infl)) {
|
||||
final byte[] inflated = iis.readAllBytes();
|
||||
check(Arrays.equals(original, inflated));
|
||||
}
|
||||
// verify the inflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the inflater is closed
|
||||
infl.reset();
|
||||
|
||||
// repeat the test with the other constructor
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(deflated);
|
||||
InflaterInputStream iis = new InflaterInputStream(bis, infl, 1024)) {
|
||||
final byte[] inflated = iis.readAllBytes();
|
||||
check(Arrays.equals(original, inflated));
|
||||
}
|
||||
// verify the inflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the inflater is closed
|
||||
infl.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that when a DeflaterOutputStream is constructed
|
||||
* by passing a Deflater instance, then closing the DeflaterOutputStream
|
||||
* will not close the passed Deflater instance.
|
||||
*/
|
||||
private static void deflaterOutputStreamDeflaterNotClosed() throws Throwable {
|
||||
// some arbitrary content
|
||||
final byte[] data = "bar".repeat(1024).getBytes(StandardCharsets.US_ASCII);
|
||||
// run the InflaterInputStream tests
|
||||
try (final Deflater def = new Deflater()) {
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DeflaterOutputStream dos = new DeflaterOutputStream(bos, def)) {
|
||||
dos.write(data);
|
||||
}
|
||||
// verify the deflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the deflater is closed
|
||||
def.reset();
|
||||
|
||||
// repeat the test with the other constructor
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DeflaterOutputStream dos = new DeflaterOutputStream(bos, def, 1024)) {
|
||||
dos.write(data);
|
||||
}
|
||||
// verify the deflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the deflater is closed
|
||||
def.reset();
|
||||
|
||||
// repeat the test with the other constructor
|
||||
for (boolean syncFlush : new boolean[] {false, true}) {
|
||||
System.out.println("testing with syncFlush = " + syncFlush);
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DeflaterOutputStream dos = new DeflaterOutputStream(bos, def, syncFlush)) {
|
||||
dos.write(data);
|
||||
}
|
||||
// verify the deflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the deflater is closed
|
||||
def.reset();
|
||||
}
|
||||
|
||||
// repeat the test with the other constructor
|
||||
for (boolean syncFlush : new boolean[] {false, true}) {
|
||||
System.out.println("testing with syncFlush = " + syncFlush);
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DeflaterOutputStream dos = new DeflaterOutputStream(bos, def, 1024, syncFlush)) {
|
||||
dos.write(data);
|
||||
}
|
||||
// verify the deflater wasn't closed - reset() will throw IllegalStateException if
|
||||
// the deflater is closed
|
||||
def.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
WriteCloseRead();
|
||||
WriteFlushRead();
|
||||
LineOrientedProtocol();
|
||||
GZWriteFlushRead();
|
||||
GZLineOrientedProtocol();
|
||||
TestFlushableGZIPOutputStream();
|
||||
inflaterInputStreamInflaterNotClosed();
|
||||
deflaterOutputStreamDeflaterNotClosed();
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {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 check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
|
||||
class FlushableGZIPOutputStream extends GZIPOutputStream {
|
||||
public FlushableGZIPOutputStream(OutputStream os) throws IOException {
|
||||
super(os);
|
||||
}
|
||||
|
||||
private static final byte[] EMPTYBYTEARRAY = new byte[0];
|
||||
private boolean hasData = false;
|
||||
|
||||
/**
|
||||
* Here we make sure we have received data, so that the header has been for
|
||||
* sure written to the output stream already.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void write(byte[] bytes, int i, int i1)
|
||||
throws IOException {
|
||||
super.write(bytes, i, i1);
|
||||
hasData = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(int i) throws IOException {
|
||||
super.write(i);
|
||||
hasData = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] bytes) throws IOException {
|
||||
super.write(bytes);
|
||||
hasData = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() throws IOException {
|
||||
if (!hasData) {
|
||||
return; // do not allow the gzip header to be flushed on its own
|
||||
}
|
||||
|
||||
// trick the deflater to flush
|
||||
/**
|
||||
* Now this is tricky: We force the Deflater to flush its data by
|
||||
* switching compression level. As yet, a perplexingly simple workaround
|
||||
* for
|
||||
* http://developer.java.sun.com/developer/bugParade/bugs/4255743.html
|
||||
*/
|
||||
if (!def.finished()) {
|
||||
def.setInput(EMPTYBYTEARRAY, 0, 0);
|
||||
|
||||
def.setLevel(Deflater.NO_COMPRESSION);
|
||||
deflate();
|
||||
|
||||
def.setLevel(Deflater.DEFAULT_COMPRESSION);
|
||||
deflate();
|
||||
|
||||
out.flush();
|
||||
}
|
||||
|
||||
hasData = false; // no more data to flush
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep on calling deflate until it runs dry. The default implementation
|
||||
* only does it once and can therefore hold onto data when they need to be
|
||||
* flushed out.
|
||||
*/
|
||||
@Override
|
||||
protected void deflate() throws IOException {
|
||||
int len;
|
||||
do {
|
||||
len = def.deflate(buf, 0, buf.length);
|
||||
if (len > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
} while (len != 0);
|
||||
}
|
||||
|
||||
}
|
||||
164
test/jdk/java/util/zip/InflaterBufferSize.java
Normal file
164
test/jdk/java/util/zip/InflaterBufferSize.java
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 6571338
|
||||
* @summary Inflater should not require a buffer to the inflate() methods
|
||||
* larger than 1 byte.
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class InflaterBufferSize {
|
||||
private static final int DATA_LEN = 1024 *64;
|
||||
private static byte[] data;
|
||||
|
||||
// If true, print extra info.
|
||||
private static final boolean debug = System.getProperty("debug") != null;
|
||||
|
||||
private static void debug(String s) {
|
||||
if (debug) System.out.println(s);
|
||||
}
|
||||
|
||||
private static void createData() {
|
||||
ByteBuffer bb = ByteBuffer.allocate(8);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < DATA_LEN; i++) {
|
||||
bb.putDouble(0, Math.random());
|
||||
baos.write(bb.array(), 0, 8);
|
||||
}
|
||||
data = baos.toByteArray();
|
||||
}
|
||||
|
||||
private static byte[] grow(byte[] a, int capacity) {
|
||||
while (a.length < capacity) {
|
||||
byte[] a2 = new byte[a.length * 2];
|
||||
System.arraycopy(a, 0, a2, 0, a.length);
|
||||
a = a2;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
private static byte[] trim(byte[] a, int length) {
|
||||
byte[] res = new byte[length];
|
||||
System.arraycopy(a, 0, res, 0, length);
|
||||
return res;
|
||||
}
|
||||
|
||||
private static byte[] deflate(byte[] in, int level) throws Throwable {
|
||||
final Deflater flater = new Deflater(level);
|
||||
flater.setInput(in);
|
||||
flater.finish();
|
||||
final byte[] smallBuffer = new byte[32];
|
||||
byte[] flated = new byte[32];
|
||||
int count = 0;
|
||||
int n;
|
||||
while ((n = flater.deflate(smallBuffer)) > 0) {
|
||||
flated = grow(flated, count + n);
|
||||
System.arraycopy(smallBuffer, 0, flated, count, n);
|
||||
count += n;
|
||||
}
|
||||
return trim(flated, count);
|
||||
}
|
||||
|
||||
private static byte[] inflate(byte[] in) throws Throwable {
|
||||
final Inflater flater = new Inflater();
|
||||
flater.setInput(in);
|
||||
// This is the buffer of interest. It should be possible to use any
|
||||
// non-zero size.
|
||||
final byte[] smallBuffer = new byte[1];
|
||||
byte[] flated = new byte[32];
|
||||
int count = 0;
|
||||
int n;
|
||||
while ((n = flater.inflate(smallBuffer)) > 0) {
|
||||
flated = grow(flated, count + n);
|
||||
System.arraycopy(smallBuffer, 0, flated, count, n);
|
||||
count += n;
|
||||
}
|
||||
return trim(flated, count);
|
||||
}
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
byte deflated[], inflated[];
|
||||
|
||||
int level = -1;
|
||||
if (args.length > 0) {
|
||||
level = Integer.parseInt(args[0]);
|
||||
}
|
||||
debug("Using level " + level);
|
||||
|
||||
if (args.length > 1) {
|
||||
FileInputStream fis = new FileInputStream(args[1]);
|
||||
int len = fis.available();
|
||||
data = new byte[len];
|
||||
check(fis.read(data, 0, len) == len, "Did not read complete file");
|
||||
debug("Original data from " + args[1]);
|
||||
fis.close();
|
||||
} else {
|
||||
createData();
|
||||
debug("Original data from random byte array");
|
||||
}
|
||||
debug("Original data length: " + data.length + " bytes");
|
||||
|
||||
debug("");
|
||||
deflated = deflate(data, level);
|
||||
debug("Deflated data length: " + deflated.length + " bytes");
|
||||
|
||||
inflated = inflate(deflated);
|
||||
debug("Inflated data length: "+ inflated.length + " bytes" );
|
||||
|
||||
if (!check(Arrays.equals(data, inflated),
|
||||
"Inflated and deflated arrays do not match")) {
|
||||
OutputStream os = new BufferedOutputStream(new FileOutputStream("deflated.zip"));
|
||||
try {
|
||||
os.write(deflated);
|
||||
} finally {
|
||||
os.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- 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;}
|
||||
static boolean check(boolean cond, String msg) {if (cond) pass(); else fail(msg); return cond;}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
271
test/jdk/java/util/zip/InflaterClose.java
Normal file
271
test/jdk/java/util/zip/InflaterClose.java
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225763
|
||||
* @summary Test that the close() and end() methods on java.util.zip.Inflater
|
||||
* @run junit InflaterClose
|
||||
*/
|
||||
public class InflaterClose {
|
||||
|
||||
private static final String originalStr = "foobarhelloworld!!!!";
|
||||
private static final byte[] originalBytes = originalStr.getBytes(US_ASCII);
|
||||
private static final byte[] compressedData = compress();
|
||||
|
||||
/**
|
||||
* Closes the Inflater multiple times and then expects close() and end() to be called that
|
||||
* many times.
|
||||
*/
|
||||
@Test
|
||||
public void testCloseMultipleTimes() throws Exception {
|
||||
final int numTimes = 3;
|
||||
final Inflater simpleInflater = new Inflater();
|
||||
final String inflatedData = closeMultipleTimesAfterInflating(numTimes, simpleInflater);
|
||||
assertValidInflatedData(inflatedData, simpleInflater.getClass());
|
||||
|
||||
final OverrideClose overriddenClose = new OverrideClose();
|
||||
final String ocInflatedData = closeMultipleTimesAfterInflating(numTimes, overriddenClose);
|
||||
assertValidInflatedData(ocInflatedData, overriddenClose.getClass());
|
||||
// make sure close was called numTimes
|
||||
assertEquals(numTimes, overriddenClose.numTimesCloseCalled, "close() was expected to be" +
|
||||
" called " + numTimes + ", but was called " + overriddenClose.numTimesCloseCalled +
|
||||
" time(s) on " + overriddenClose.getClass().getName());
|
||||
|
||||
final OverrideEnd overriddenEnd = new OverrideEnd();
|
||||
final String oeInflatedData = closeMultipleTimesAfterInflating(numTimes, overriddenEnd);
|
||||
assertValidInflatedData(oeInflatedData, overriddenEnd.getClass());
|
||||
// make sure end was called called numTimes
|
||||
assertEquals(numTimes, overriddenEnd.numTimesEndCalled, "end() was expected to be called " +
|
||||
numTimes + ", but was called " + overriddenEnd.numTimesEndCalled + " time(s) on " +
|
||||
overriddenEnd.getClass().getName());
|
||||
|
||||
final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
|
||||
final String oceInflatedData = closeMultipleTimesAfterInflating(numTimes,
|
||||
overriddenCloseAndEnd);
|
||||
assertValidInflatedData(oceInflatedData, overriddenCloseAndEnd.getClass());
|
||||
// make sure end was called called numTimes
|
||||
assertEquals(numTimes, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected" +
|
||||
" to be called " + numTimes + ", but was called " +
|
||||
overriddenCloseAndEnd.numTimesEndCalled +
|
||||
" time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
assertEquals(numTimes, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected" +
|
||||
" to be called " + numTimes + ", but was called " +
|
||||
overriddenCloseAndEnd.numTimesCloseCalled + " time(s) on " +
|
||||
overriddenCloseAndEnd.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the Inflater first and then calls end(). Verifies that close() was called
|
||||
* just once but end() was called twice (once internally through close() and once
|
||||
* explicitly)
|
||||
*/
|
||||
@Test
|
||||
public void testCloseThenEnd() throws Exception {
|
||||
final Inflater simpleInflater = new Inflater();
|
||||
final String inflatedData = inflateCloseThenEnd(simpleInflater);
|
||||
assertValidInflatedData(inflatedData, simpleInflater.getClass());
|
||||
|
||||
final OverrideClose overriddenClose = new OverrideClose();
|
||||
final String ocInflatedData = inflateCloseThenEnd(overriddenClose);
|
||||
assertValidInflatedData(ocInflatedData, overriddenClose.getClass());
|
||||
// make sure close was called once
|
||||
assertEquals(1, overriddenClose.numTimesCloseCalled, "close() was expected to be called" +
|
||||
" once, but was called " + overriddenClose.numTimesCloseCalled + " time(s) on "
|
||||
+ overriddenClose.getClass().getName());
|
||||
|
||||
final OverrideEnd overriddenEnd = new OverrideEnd();
|
||||
final String oeInflatedData = inflateCloseThenEnd(overriddenEnd);
|
||||
assertValidInflatedData(oeInflatedData, overriddenEnd.getClass());
|
||||
// make sure end was called twice (once through close() and then explicitly)
|
||||
assertEquals(2, overriddenEnd.numTimesEndCalled, "end() was expected to be called twice," +
|
||||
" but was called " + overriddenEnd.numTimesEndCalled + " time(s) on "
|
||||
+ overriddenEnd.getClass().getName());
|
||||
|
||||
final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
|
||||
final String oceInflatedData = inflateCloseThenEnd(overriddenCloseAndEnd);
|
||||
assertValidInflatedData(oceInflatedData, overriddenCloseAndEnd.getClass());
|
||||
// make sure end was called twice (once through close and once explicitly)
|
||||
// and close was called once
|
||||
assertEquals(2, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected to be called" +
|
||||
" twice, but was called " + overriddenCloseAndEnd.numTimesEndCalled
|
||||
+ " time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
assertEquals(1, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected to be" +
|
||||
" called once, but was called " + overriddenClose.numTimesCloseCalled
|
||||
+ " time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls end() on the Inflater first and then calls close(). Verifies that close() was called
|
||||
* just once and end() twice.
|
||||
*/
|
||||
@Test
|
||||
public void testEndThenClose() throws Exception {
|
||||
final Inflater simpleInflater = new Inflater();
|
||||
final String inflatedData = inflateThenEndThenClose(simpleInflater);
|
||||
assertValidInflatedData(inflatedData, simpleInflater.getClass());
|
||||
|
||||
final OverrideClose overriddenClose = new OverrideClose();
|
||||
final String ocInflatedData = inflateThenEndThenClose(overriddenClose);
|
||||
assertValidInflatedData(ocInflatedData, overriddenClose.getClass());
|
||||
// make sure close was called once
|
||||
assertEquals(1, overriddenClose.numTimesCloseCalled, "close() was expected to be" +
|
||||
" called once, but was called " + overriddenClose.numTimesCloseCalled +
|
||||
" time(s) on " + overriddenClose.getClass().getName());
|
||||
|
||||
final OverrideEnd overriddenEnd = new OverrideEnd();
|
||||
final String oeInflatedData = inflateThenEndThenClose(overriddenEnd);
|
||||
assertValidInflatedData(oeInflatedData, overriddenEnd.getClass());
|
||||
// make sure end was called twice (once through the explicit end call and
|
||||
// once through close())
|
||||
assertEquals(2, overriddenEnd.numTimesEndCalled, "end() was expected to be called twice," +
|
||||
" but was called " + overriddenEnd.numTimesEndCalled + " time(s) on "
|
||||
+ overriddenEnd.getClass().getName());
|
||||
|
||||
final OverrideCloseAndEnd overriddenCloseAndEnd = new OverrideCloseAndEnd();
|
||||
final String oceInflatedData = inflateThenEndThenClose(overriddenCloseAndEnd);
|
||||
assertValidInflatedData(oceInflatedData, overriddenCloseAndEnd.getClass());
|
||||
// make sure end was called twice (once through the explicit end call and
|
||||
// once through close())
|
||||
assertEquals(2, overriddenCloseAndEnd.numTimesEndCalled, "end() was expected to be called" +
|
||||
" twice, but was called " + overriddenCloseAndEnd.numTimesEndCalled +
|
||||
" time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
assertEquals(1, overriddenCloseAndEnd.numTimesCloseCalled, "close() was expected to be" +
|
||||
" called once, but was called " + overriddenClose.numTimesCloseCalled +
|
||||
" time(s) on " + overriddenCloseAndEnd.getClass().getName());
|
||||
}
|
||||
|
||||
|
||||
private String closeMultipleTimesAfterInflating(final int numTimes, final Inflater inflater)
|
||||
throws DataFormatException {
|
||||
// inflate() then call close() multiple times
|
||||
final byte[] inflatedData = inflate(inflater, compressedData);
|
||||
// call close()
|
||||
for (int i = 0; i < numTimes; i++) {
|
||||
inflater.close();
|
||||
}
|
||||
return new String(inflatedData, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private String inflateCloseThenEnd(final Inflater inflater) throws Exception {
|
||||
final byte[] inflatedData;
|
||||
// inflate then close() and then end()
|
||||
try (final Inflater inflt = inflater) {
|
||||
inflatedData = inflate(inflt, compressedData);
|
||||
}
|
||||
// end() the already closed inflater
|
||||
inflater.end();
|
||||
return new String(inflatedData, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private String inflateThenEndThenClose(final Inflater inflater) throws Exception {
|
||||
final byte[] inflatedData;
|
||||
// inflate then end() and then close()
|
||||
try (final Inflater inflt = inflater) {
|
||||
inflatedData = inflate(inflt, compressedData);
|
||||
// end() it first before it's (auto)closed by the try-with-resources
|
||||
inflt.end();
|
||||
}
|
||||
return new String(inflatedData, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static byte[] inflate(final Inflater inflater, final byte[] compressedData)
|
||||
throws DataFormatException {
|
||||
final ByteArrayOutputStream inflatedData = new ByteArrayOutputStream();
|
||||
inflater.setInput(compressedData);
|
||||
while (!inflater.finished()) {
|
||||
byte[] tmpBuffer = new byte[100];
|
||||
final int numDecompressed = inflater.inflate(tmpBuffer);
|
||||
inflatedData.write(tmpBuffer, 0, numDecompressed);
|
||||
}
|
||||
return inflatedData.toByteArray();
|
||||
}
|
||||
|
||||
private static byte[] compress() {
|
||||
final ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream();
|
||||
try (final Deflater deflater = new Deflater()) {
|
||||
deflater.setInput(originalBytes);
|
||||
deflater.finish();
|
||||
while (!deflater.finished()) {
|
||||
final byte[] tmpBuffer = new byte[100];
|
||||
final int numCompressed = deflater.deflate(tmpBuffer);
|
||||
compressedBaos.write(tmpBuffer, 0, numCompressed);
|
||||
}
|
||||
}
|
||||
return compressedBaos.toByteArray();
|
||||
}
|
||||
|
||||
private static void assertValidInflatedData(final String inflatedData,
|
||||
final Class<?> inflaterType) {
|
||||
assertEquals(originalStr, inflatedData, "Unexpected inflated data " + inflatedData
|
||||
+ " generated by " + inflaterType.getName() + ", expected " + originalStr);
|
||||
}
|
||||
|
||||
private static final class OverrideEnd extends Inflater {
|
||||
private int numTimesEndCalled = 0;
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
this.numTimesEndCalled++;
|
||||
super.end();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class OverrideClose extends Inflater {
|
||||
private int numTimesCloseCalled = 0;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.numTimesCloseCalled++;
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class OverrideCloseAndEnd extends Inflater {
|
||||
private int numTimesEndCalled = 0;
|
||||
private int numTimesCloseCalled = 0;
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
this.numTimesEndCalled++;
|
||||
super.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.numTimesCloseCalled++;
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
59
test/jdk/java/util/zip/InflaterInputStream/MarkReset.java
Normal file
59
test/jdk/java/util/zip/InflaterInputStream/MarkReset.java
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 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.
|
||||
*
|
||||
* 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 4812237
|
||||
* @summary Make sure that the mark() and reset() methods behave as expected.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
|
||||
public class MarkReset {
|
||||
public static void main(String args[]) throws Exception {
|
||||
test1();
|
||||
}
|
||||
|
||||
private static void test1() throws Exception {
|
||||
boolean expOccurred = false;
|
||||
byte data[] = {90, 91, 92, 93, 94, 95, 96, 97};
|
||||
InflaterInputStream in =
|
||||
new InflaterInputStream(new ByteArrayInputStream(data));
|
||||
in.mark(-5);
|
||||
in.mark(6);
|
||||
in.mark(Integer.MAX_VALUE);
|
||||
try {
|
||||
in.reset();
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (IOException e) {
|
||||
// Correct result
|
||||
}
|
||||
try {
|
||||
in.reset();
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (IOException e) {
|
||||
// Correct result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 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.
|
||||
*
|
||||
* 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
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @run main TestAvailable
|
||||
* @bug 7031075 8161426
|
||||
* @summary Make sure that available() method behaves as expected.
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Random;
|
||||
import java.util.zip.*;
|
||||
import jdk.test.lib.RandomFactory;
|
||||
|
||||
public class TestAvailable {
|
||||
|
||||
public static void main(String args[]) throws Throwable {
|
||||
Random r = RandomFactory.getRandom();
|
||||
for (int n = 0; n < 10; n++) {
|
||||
byte[] src = new byte[r.nextInt(100) + 1];
|
||||
r.nextBytes(src);
|
||||
// test InflaterInputStream
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (DeflaterOutputStream dos = new DeflaterOutputStream(baos)) {
|
||||
dos.write(src);
|
||||
}
|
||||
try (InflaterInputStream iis = new InflaterInputStream(
|
||||
new ByteArrayInputStream(baos.toByteArray()))) {
|
||||
test(iis, src);
|
||||
}
|
||||
|
||||
// test GZIPInputStream
|
||||
baos = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream dos = new GZIPOutputStream(baos)) {
|
||||
dos.write(src);
|
||||
}
|
||||
try (GZIPInputStream gis = new GZIPInputStream(
|
||||
new ByteArrayInputStream(baos.toByteArray()))) {
|
||||
test(gis, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void test(InputStream is, byte[] expected) throws IOException {
|
||||
int cnt = 0;
|
||||
do {
|
||||
int available = is.available();
|
||||
if (available > 0) {
|
||||
int b = is.read();
|
||||
if (b == -1) {
|
||||
throw new RuntimeException("available() > 0, read() == -1 : failed!");
|
||||
}
|
||||
if (expected[cnt++] != (byte)b) {
|
||||
throw new RuntimeException("read() : failed!");
|
||||
}
|
||||
} else if (available == 0) {
|
||||
if (is.read() != -1) {
|
||||
throw new RuntimeException("available() == 0, read() != -1 : failed!");
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
throw new RuntimeException("available() < 0 : failed!");
|
||||
}
|
||||
} while (true);
|
||||
if (cnt != expected.length) {
|
||||
throw new RuntimeException("read : failed!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*
|
||||
* 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 8292327
|
||||
* @summary Test the case where Inflater.needsInput() is true but the native
|
||||
* inflater still has unwritten output in its internal buffer.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.DeflaterInputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
public class UnexpectedEndOfZlibStream {
|
||||
public static void main(String[] args) throws Exception {
|
||||
String original = "Readsuncompresseddataintoanarrayofbytes0123456789Ifcodelenis" +
|
||||
"notzerothemethodwillblockReadsuncompresseddataintoanarrayofbytes123456789";
|
||||
byte[] deflated =
|
||||
new DeflaterInputStream(
|
||||
new ByteArrayInputStream(original.getBytes("US-ASCII")),
|
||||
new Deflater(Deflater.DEFAULT_COMPRESSION, /*nowrap=*/ true)
|
||||
).readAllBytes();
|
||||
|
||||
// using readAllBytes succeeds, the underlying gzip data seems to be well-formed
|
||||
byte[] inflated =
|
||||
new InflaterInputStream(
|
||||
new ByteArrayInputStream(deflated),
|
||||
new Inflater(/*nowrap=*/ true)
|
||||
).readAllBytes();
|
||||
|
||||
if (!original.equals(new String(inflated, "US-ASCII"))) {
|
||||
throw new Exception("Inflated output differs from original");
|
||||
}
|
||||
|
||||
// a 128 byte read followed by a 512 byte read fails after JDK-8281962
|
||||
InflaterInputStream is =
|
||||
new InflaterInputStream(
|
||||
new ByteArrayInputStream(deflated),
|
||||
new Inflater(/*nowrap=*/ true));
|
||||
byte[] buf = new byte[512];
|
||||
int n = is.read(buf, 0, 128);
|
||||
int pos = n;
|
||||
while (n > 0) {
|
||||
if ((n = is.read(buf, pos, 1)) > 0) { // Unexpected end of ZLIB input stream
|
||||
pos+= n;
|
||||
}
|
||||
}
|
||||
if (!original.equals(new String(buf, 0, pos, "US-ASCII"))) {
|
||||
throw new Exception("Inflated output differs from original");
|
||||
}
|
||||
}
|
||||
}
|
||||
157
test/jdk/java/util/zip/InflaterOutputStreamTest.java
Normal file
157
test/jdk/java/util/zip/InflaterOutputStreamTest.java
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8369181
|
||||
* @summary Verify the behaviour of basic operations on InflaterOutputStream
|
||||
* @run junit ${test.main.class}
|
||||
*/
|
||||
class InflaterOutputStreamTest {
|
||||
|
||||
private static final byte[] INPUT_CONTENT = "hello world".getBytes(US_ASCII);
|
||||
private static byte[] COMPRESSED_CONTENT;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() throws Exception {
|
||||
// created the compressed content
|
||||
final ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream();
|
||||
try (Deflater compressor = new Deflater()) {
|
||||
compressor.setInput(INPUT_CONTENT);
|
||||
compressor.finish();
|
||||
while (!compressor.finished()) {
|
||||
final byte[] tmpBuffer = new byte[100];
|
||||
final int numCompressed = compressor.deflate(tmpBuffer);
|
||||
compressedBaos.write(tmpBuffer, 0, numCompressed);
|
||||
}
|
||||
}
|
||||
COMPRESSED_CONTENT = compressedBaos.toByteArray();
|
||||
}
|
||||
|
||||
static List<Arguments> inflaterOutputStreams() {
|
||||
final List<Arguments> args = new ArrayList<>();
|
||||
args.add(Arguments.of(new InflaterOutputStream(new ByteArrayOutputStream())));
|
||||
args.add(Arguments.of(new InflaterOutputStream(new ByteArrayOutputStream(),
|
||||
new Inflater())));
|
||||
args.add(Arguments.of(new InflaterOutputStream(new ByteArrayOutputStream(),
|
||||
new Inflater(), 1024)));
|
||||
return args;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that write() methods throw an IOException when the InflaterOutputStream
|
||||
* is already closed.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("inflaterOutputStreams")
|
||||
void testWriteAfterClose(final InflaterOutputStream ios) throws Exception {
|
||||
ios.close();
|
||||
IOException ioe = assertThrows(IOException.class, () -> ios.write(COMPRESSED_CONTENT));
|
||||
// verify it failed for right reason
|
||||
assertStreamClosedIOE(ioe);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that flush() throws an IOException when the InflaterOutputStream
|
||||
* is already closed
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("inflaterOutputStreams")
|
||||
void testFlushAfterClose(final InflaterOutputStream ios) throws Exception {
|
||||
ios.close();
|
||||
final IOException ioe = assertThrows(IOException.class, ios::flush);
|
||||
// verify it failed for right reason
|
||||
assertStreamClosedIOE(ioe);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that finish() throws an IOException when the InflaterOutputStream
|
||||
* is already closed.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("inflaterOutputStreams")
|
||||
void testFinishAfterClose(final InflaterOutputStream ios) throws Exception {
|
||||
ios.close();
|
||||
final IOException ioe = assertThrows(IOException.class, ios::finish);
|
||||
// verify it failed for right reason
|
||||
assertStreamClosedIOE(ioe);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that after finish() is called on an InflaterOutputStream that was constructed
|
||||
* without specifying a Inflater, any subsequent writes will throw an IOException.
|
||||
*/
|
||||
@Test
|
||||
void testWriteAfterFinish() throws IOException {
|
||||
// InflaterOutputStream that constructs an internal default Inflater
|
||||
final InflaterOutputStream ios = new InflaterOutputStream(new ByteArrayOutputStream());
|
||||
ios.finish();
|
||||
final IOException ioe = assertThrows(IOException.class, () -> ios.write(COMPRESSED_CONTENT));
|
||||
final String msg = ioe.getMessage();
|
||||
// verify that it's the right IOException
|
||||
if (msg == null || !msg.contains("Inflater closed")) {
|
||||
// propagate the original exception
|
||||
fail("unexpected exception message in IOException", ioe);
|
||||
}
|
||||
|
||||
// repeat with a InflaterOutputStream that is passed a Inflater
|
||||
try (Inflater intf = new Inflater();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InflaterOutputStream stream = new InflaterOutputStream(baos, intf)) {
|
||||
|
||||
stream.finish();
|
||||
// not expected to throw any exception
|
||||
stream.write(COMPRESSED_CONTENT);
|
||||
stream.flush();
|
||||
// verify the decompressed content is as expected
|
||||
final byte[] decompressed = baos.toByteArray();
|
||||
assertArrayEquals(INPUT_CONTENT, decompressed, "unexpected decompressed content");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertStreamClosedIOE(final IOException ioe) {
|
||||
final String msg = ioe.getMessage();
|
||||
if (msg == null || !msg.contains("Stream closed")) {
|
||||
// propagate the original exception
|
||||
fail("unexpected exception message in IOException", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
124
test/jdk/java/util/zip/InfoZip.java
Normal file
124
test/jdk/java/util/zip/InfoZip.java
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2011, 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.
|
||||
*
|
||||
* 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 6237956
|
||||
* @summary We must be able to read zip files created by Unix Info-Zip
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.io.*;
|
||||
|
||||
public class InfoZip {
|
||||
static int passed = 0, failed = 0;
|
||||
|
||||
static void fail(String msg) {
|
||||
failed++;
|
||||
new Exception(msg).printStackTrace();
|
||||
}
|
||||
|
||||
static void unexpected(Throwable t) {
|
||||
failed++;
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
static void check(boolean condition, String msg) {
|
||||
if (! condition)
|
||||
fail(msg);
|
||||
}
|
||||
|
||||
static void check(boolean condition) {
|
||||
check(condition, "Something's wrong");
|
||||
}
|
||||
|
||||
private static String contents(ZipFile zf, ZipEntry ze) throws Exception {
|
||||
InputStream is = zf.getInputStream(ze);
|
||||
String result = contents(is);
|
||||
is.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String contents(InputStream is) throws Exception {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int c;
|
||||
while ((c = is.read()) != -1)
|
||||
sb.append((char)c);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void checkZipEntry(ZipEntry ze, String contents) {
|
||||
check(ze.getName().equals("someFile"), "filename");
|
||||
check(ze.getExtra() != null, "extra");
|
||||
check(contents.equals("Message in a Bottle\n"), "contents");
|
||||
check(ze.getSize() == "Message in a Bottle\n".length());
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
//----------------------------------------------------------------
|
||||
// The file InfoZip.zip was created using Unix Info-Zip's zip, thus:
|
||||
// echo Message in a Bottle > someFile; zip InfoZip.zip someFile
|
||||
// Such a file has a LOC extra different from the CEN extra,
|
||||
// which cannot happen using JDK APIs.
|
||||
//----------------------------------------------------------------
|
||||
File f = new File("InfoZip.zip");
|
||||
|
||||
try (OutputStream os = new FileOutputStream(f)) {
|
||||
os.write(new byte[]
|
||||
{'P', 'K', 3, 4, 10, 0, 0, 0, 0, 0, -68, 8, 'k',
|
||||
'2', 'V', -7, 'm', 9, 20, 0, 0, 0, 20, 0, 0, 0,
|
||||
8, 0, 21, 0, 's', 'o', 'm', 'e', 'F', 'i', 'l', 'e', 'U',
|
||||
'T', 9, 0, 3, 't', '_', '1', 'B', 't', '_', '1', 'B', 'U',
|
||||
'x', 4, 0, -14, 'v', 26, 4, 'M', 'e', 's', 's', 'a', 'g',
|
||||
'e', ' ', 'i', 'n', ' ', 'a', ' ', 'B', 'o', 't', 't', 'l', 'e',
|
||||
10, 'P', 'K', 1, 2, 23, 3, 10, 0, 0, 0, 0, 0,
|
||||
-68, 8, 'k', '2', 'V', -7, 'm', 9, 20, 0, 0, 0, 20,
|
||||
0, 0, 0, 8, 0, 13, 0, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, -92, -127, 0, 0, 0, 0, 's', 'o', 'm', 'e', 'F',
|
||||
'i', 'l', 'e', 'U', 'T', 5, 0, 3, 't', '_', '1', 'B', 'U',
|
||||
'x', 0, 0, 'P', 'K', 5, 6, 0, 0, 0, 0, 1, 0,
|
||||
1, 0, 'C', 0, 0, 0, 'O', 0, 0, 0, 0, 0, });
|
||||
}
|
||||
|
||||
ZipEntry ze = null;
|
||||
try (ZipFile zf = new ZipFile(f)) {
|
||||
Enumeration<? extends ZipEntry> entries = zf.entries();
|
||||
ze = entries.nextElement();
|
||||
check(! entries.hasMoreElements());
|
||||
checkZipEntry(ze, contents(zf, ze));
|
||||
}
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(f);
|
||||
ZipInputStream is = new ZipInputStream(fis))
|
||||
{
|
||||
ze = is.getNextEntry();
|
||||
checkZipEntry(ze, contents(is));
|
||||
check(is.getNextEntry() == null);
|
||||
}
|
||||
f.delete();
|
||||
System.out.printf("passed = %d, failed = %d%n", passed, failed);
|
||||
if (failed > 0) throw new Exception("Some tests failed");
|
||||
}
|
||||
}
|
||||
54
test/jdk/java/util/zip/InterruptibleZip.java
Normal file
54
test/jdk/java/util/zip/InterruptibleZip.java
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2025, 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.
|
||||
*
|
||||
* 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 6304463
|
||||
* @summary Test whether the zip file still can be read after thread is interrupted
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class InterruptibleZip {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
/* Interrupt the current thread. The is.read call below
|
||||
should continue reading input.jar.
|
||||
*/
|
||||
Thread.currentThread().interrupt();
|
||||
ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), "input.jar"));
|
||||
ZipEntry ze = zf.getEntry("Available.java");
|
||||
InputStream is = zf.getInputStream(ze);
|
||||
byte[] buf = new byte[512];
|
||||
int n = is.read(buf);
|
||||
boolean interrupted = Thread.interrupted();
|
||||
System.out.printf("interrupted=%s n=%d name=%s%n",
|
||||
interrupted, n, ze.getName());
|
||||
if (! interrupted) {
|
||||
throw new Error("Wrong interrupted status");
|
||||
}
|
||||
if (n != buf.length) {
|
||||
throw new Error("Read error");
|
||||
}
|
||||
}
|
||||
}
|
||||
264
test/jdk/java/util/zip/LargeZip.java
Normal file
264
test/jdk/java/util/zip/LargeZip.java
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2013, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.nio.file.spi.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static java.nio.file.StandardCopyOption.*;
|
||||
|
||||
public class LargeZip {
|
||||
// If true, don't delete large ZIP file created for test.
|
||||
static final boolean debug = System.getProperty("debug") != null;
|
||||
|
||||
//static final int DATA_LEN = 1024 * 1024;
|
||||
static final int DATA_LEN = 80 * 1024;
|
||||
static final int DATA_SIZE = 8;
|
||||
|
||||
static long fileSize = 6L * 1024L * 1024L * 1024L; // 6GB
|
||||
|
||||
static boolean userFile = false;
|
||||
static byte[] data;
|
||||
static File largeFile;
|
||||
static String lastEntryName;
|
||||
|
||||
/* args can be empty, in which case check a 3 GB file which is created for
|
||||
* this test (and then deleted). Or it can be a number, in which case
|
||||
* that designates the size of the file that's created for this test (and
|
||||
* then deleted). Or it can be the name of a file to use for the test, in
|
||||
* which case it is *not* deleted. Note that in this last case, the data
|
||||
* comparison might fail.
|
||||
*/
|
||||
static void realMain (String[] args) throws Throwable {
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
fileSize = Long.parseLong(args[0]);
|
||||
System.out.println("Testing with file of size " + fileSize);
|
||||
} catch (NumberFormatException ex) {
|
||||
largeFile = new File(args[0]);
|
||||
if (!largeFile.exists()) {
|
||||
throw new Exception("Specified file " + args[0] + " does not exist");
|
||||
}
|
||||
userFile = true;
|
||||
System.out.println("Testing with user-provided file " + largeFile);
|
||||
}
|
||||
}
|
||||
File testDir = null;
|
||||
if (largeFile == null) {
|
||||
testDir = new File(System.getProperty("test.scratch", "."),
|
||||
"LargeZip");
|
||||
if (testDir.exists()) {
|
||||
if (!testDir.delete()) {
|
||||
throw new Exception("Cannot delete already-existing test directory");
|
||||
}
|
||||
}
|
||||
check(!testDir.exists() && testDir.mkdirs());
|
||||
largeFile = new File(testDir, "largezip.zip");
|
||||
createLargeZip();
|
||||
} else {
|
||||
if (args.length > 1)
|
||||
updateLargeZip(args[1]); // add new entry with zfs
|
||||
}
|
||||
readLargeZip1();
|
||||
readLargeZip2();
|
||||
|
||||
if (!userFile && !debug) {
|
||||
check(largeFile.delete());
|
||||
check(testDir.delete());
|
||||
}
|
||||
}
|
||||
|
||||
static void createLargeZip() throws Throwable {
|
||||
int iterations = DATA_LEN / DATA_SIZE;
|
||||
ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
bb.putDouble(0, Math.random());
|
||||
baos.write(bb.array(), 0, DATA_SIZE);
|
||||
}
|
||||
data = baos.toByteArray();
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(largeFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos))
|
||||
{
|
||||
long length = 0;
|
||||
while (length < fileSize) {
|
||||
ZipEntry ze = new ZipEntry("entry-" + length);
|
||||
lastEntryName = ze.getName();
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(data, 0, data.length);
|
||||
zos.closeEntry();
|
||||
length = largeFile.length();
|
||||
}
|
||||
System.out.println("Last entry written is " + lastEntryName);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte buf[] = new byte[4096];
|
||||
|
||||
static void checkEntry(ZipEntry e, InputStream is) throws Throwable {
|
||||
long N = 0;
|
||||
int n = 0;
|
||||
while ((n = is.read(buf)) >= 0) {
|
||||
N += n;
|
||||
}
|
||||
check(N == e.getSize());
|
||||
}
|
||||
|
||||
static void readLargeZip1() throws Throwable {
|
||||
ZipFile zipFile = new ZipFile(largeFile);
|
||||
ZipEntry entry = null;
|
||||
String entryName = null;
|
||||
int count = 0;
|
||||
System.out.println("ZipFile:");
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
entry = entries.nextElement();
|
||||
entryName = entry.getName();
|
||||
System.out.println(" checking " + entryName);
|
||||
if (!entry.isDirectory()) {
|
||||
try (InputStream zeis = zipFile.getInputStream(entry)) {
|
||||
checkEntry(entry, zeis);
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
System.out.println("Number of entries read: " + count);
|
||||
check(!entry.isDirectory());
|
||||
if (userFile || check(entryName.equals(lastEntryName))) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = zipFile.getInputStream(entry);
|
||||
int len;
|
||||
while ((len = is.read(buf)) >= 0) {
|
||||
baos.write(buf, 0, len);
|
||||
}
|
||||
baos.close();
|
||||
is.close();
|
||||
if (!userFile)
|
||||
check(Arrays.equals(data, baos.toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
static void readLargeZip2() throws Throwable {
|
||||
System.out.println("ZipInputStream:");
|
||||
try (FileInputStream fis = new FileInputStream(largeFile);
|
||||
BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
ZipInputStream zis = new ZipInputStream(bis))
|
||||
{
|
||||
ZipEntry entry = null;
|
||||
String entryName = null;
|
||||
int count = 0;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
entryName = entry.getName();
|
||||
|
||||
System.out.println(" checking " + entryName +
|
||||
", method=" + entry.getMethod());
|
||||
if (entryName.equals(lastEntryName)) {
|
||||
break;
|
||||
}
|
||||
if (!entry.isDirectory()) {
|
||||
checkEntry(entry, zis);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
System.out.println("Number of entries read: " + count);
|
||||
System.out.println("Last entry read is " + entryName);
|
||||
if (!userFile) {
|
||||
check(!entry.isDirectory());
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte buf[] = new byte[4096];
|
||||
int len;
|
||||
while ((len = zis.read(buf)) >= 0) {
|
||||
baos.write(buf, 0, len);
|
||||
}
|
||||
baos.close();
|
||||
check(Arrays.equals(data, baos.toByteArray()));
|
||||
check(zis.getNextEntry() == null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateFile(FileSystem fs, Path src) throws IOException {
|
||||
Path dst = fs.getPath(src.toString());
|
||||
Path parent = dst.getParent();
|
||||
if (parent != null && Files.notExists(parent))
|
||||
Files.createDirectories(parent);
|
||||
Files.copy(src, dst, REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
private static FileSystemProvider getZipFSProvider() {
|
||||
for (FileSystemProvider provider : FileSystemProvider.installedProviders()) {
|
||||
if ("jar".equalsIgnoreCase(provider.getScheme()))
|
||||
return provider;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void updateLargeZip(String pName) throws Throwable {
|
||||
FileSystemProvider provider = getZipFSProvider();
|
||||
if (provider == null) {
|
||||
System.err.println("ZIP filesystem provider is not installed");
|
||||
System.exit(1);
|
||||
}
|
||||
Map<String, Object> env = env = new HashMap<>();
|
||||
try (FileSystem fs = provider.newFileSystem(largeFile.toPath(), env)) {
|
||||
Path path = FileSystems.getDefault().getPath(pName);
|
||||
Files.walkFileTree(
|
||||
path,
|
||||
new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file,
|
||||
BasicFileAttributes attrs)
|
||||
throws IOException
|
||||
{
|
||||
updateFile(fs, file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------- 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;}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
49
test/jdk/java/util/zip/ReadLoc.java
Normal file
49
test/jdk/java/util/zip/ReadLoc.java
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 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.
|
||||
*
|
||||
* 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 4766057
|
||||
* @summary Test for VM crash in getEntry
|
||||
*/
|
||||
|
||||
import java.util.zip.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
public class ReadLoc {
|
||||
public static void main(String[] args) throws Exception {
|
||||
int iterations = 0;
|
||||
File zFile1 = new File(System.getProperty("test.src", "."),
|
||||
"pkware123456789012345.zip");
|
||||
while (iterations < 2500) {
|
||||
ZipFile zipFile = new ZipFile(zFile1);
|
||||
List entries = Collections.list(zipFile.entries());
|
||||
for (Iterator it = entries.iterator(); it.hasNext();) {
|
||||
ZipEntry zipEntry = (ZipEntry)it.next();
|
||||
InputStream in = zipFile.getInputStream(zipEntry);
|
||||
in.close();
|
||||
}
|
||||
iterations++;
|
||||
}
|
||||
}
|
||||
}
|
||||
123
test/jdk/java/util/zip/StoredCRC.java
Normal file
123
test/jdk/java/util/zip/StoredCRC.java
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2013, 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.
|
||||
*
|
||||
* 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 4879507
|
||||
* @summary ZipInputStream does not check CRC for stored (uncompressed) files
|
||||
* @author Dave Bristor
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class StoredCRC {
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos);
|
||||
|
||||
ZipEntry ze = new ZipEntry("test");
|
||||
ze.setMethod(ZipOutputStream.STORED);
|
||||
|
||||
String writtenString = "hello, world";
|
||||
byte[] writtenData = writtenString.getBytes("ASCII");
|
||||
ze.setSize(writtenData.length);
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(writtenData);
|
||||
ze.setCrc(crc.getValue());
|
||||
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(writtenData, 0, writtenData.length);
|
||||
zos.close();
|
||||
|
||||
byte[] data = baos.toByteArray();
|
||||
|
||||
// Run with an arg to create a test file that can be used to figure
|
||||
// out what position in the data stream can be changed.
|
||||
if (args.length > 0) {
|
||||
FileOutputStream fos = new FileOutputStream("stored.zip");
|
||||
fos.write(data, 0, data.length);
|
||||
fos.close();
|
||||
} else {
|
||||
// Test that reading byte-at-a-time works
|
||||
ZipInputStream zis = new ZipInputStream(
|
||||
new ByteArrayInputStream(data));
|
||||
ze = zis.getNextEntry();
|
||||
int pos = 0;
|
||||
byte[] readData = new byte[256];
|
||||
try {
|
||||
int count = zis.read(readData, pos, 1);
|
||||
while (count > 0) {
|
||||
count = zis.read(readData, ++pos, 1);
|
||||
}
|
||||
check(writtenString.equals(new String(readData, 0, pos, "ASCII")));
|
||||
} catch (Throwable t) {
|
||||
unexpected(t);
|
||||
}
|
||||
|
||||
// Test that data corruption is detected. "offset" was
|
||||
// determined to be in the entry's uncompressed data.
|
||||
data[getDataOffset(data) + 4] ^= 1;
|
||||
|
||||
zis = new ZipInputStream(
|
||||
new ByteArrayInputStream(data));
|
||||
ze = zis.getNextEntry();
|
||||
|
||||
try {
|
||||
zis.read(readData, 0, readData.length);
|
||||
fail("Did not catch expected ZipException" );
|
||||
} catch (ZipException ex) {
|
||||
String msg = ex.getMessage();
|
||||
check(msg != null && msg.startsWith("invalid entry CRC (expected 0x"));
|
||||
} catch (Throwable t) {
|
||||
unexpected(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final int getDataOffset(byte b[]) {
|
||||
final int LOCHDR = 30; // LOC header size
|
||||
final int LOCEXT = 28; // extra field length
|
||||
final int LOCNAM = 26; // filename length
|
||||
int lenExt = Byte.toUnsignedInt(b[LOCEXT]) | (Byte.toUnsignedInt(b[LOCEXT + 1]) << 8);
|
||||
int lenNam = Byte.toUnsignedInt(b[LOCNAM]) | (Byte.toUnsignedInt(b[LOCNAM + 1]) << 8);
|
||||
return LOCHDR + lenExt + lenNam;
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static boolean pass() {passed++; return true;}
|
||||
static boolean fail() {failed++; Thread.dumpStack(); return false;}
|
||||
static boolean fail(String msg) {System.out.println(msg); return fail();}
|
||||
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
||||
static boolean equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) return pass();
|
||||
else return fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
79
test/jdk/java/util/zip/StreamConstructor.java
Normal file
79
test/jdk/java/util/zip/StreamConstructor.java
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 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.
|
||||
*
|
||||
* 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 4111750 4114745
|
||||
@summary test if Deflater/Inflater constructor will
|
||||
check the arguments correctly.
|
||||
*/
|
||||
import java.util.zip.*;
|
||||
import java.io.*;
|
||||
|
||||
public class StreamConstructor {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
Deflater def = new Deflater();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(new byte[10]);
|
||||
Inflater inf = new Inflater();
|
||||
InflaterInputStream infOS;
|
||||
DeflaterOutputStream defOS;
|
||||
|
||||
try {
|
||||
defOS = new DeflaterOutputStream(bos, null);
|
||||
throw new Exception("didn't catch illegal argument");
|
||||
} catch (NullPointerException e){
|
||||
}
|
||||
|
||||
try {
|
||||
defOS = new DeflaterOutputStream(null, def);
|
||||
throw new Exception("didn't catch illegal argument");
|
||||
} catch (NullPointerException e){
|
||||
}
|
||||
|
||||
try {
|
||||
defOS = new DeflaterOutputStream(bos, def, -1);
|
||||
throw new Exception("didn't catch illegal argument");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
infOS = new InflaterInputStream(bis, null);
|
||||
throw new Exception("didn't catch illegal argument");
|
||||
} catch (NullPointerException e){
|
||||
}
|
||||
|
||||
try {
|
||||
infOS = new InflaterInputStream(null, inf);
|
||||
throw new Exception("didn't catch illegal argument");
|
||||
} catch (NullPointerException e){
|
||||
}
|
||||
|
||||
try {
|
||||
infOS = new InflaterInputStream(bis, inf, -1);
|
||||
throw new Exception("didn't catch illegal argument");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
78
test/jdk/java/util/zip/StreamIOAfterClose.java
Normal file
78
test/jdk/java/util/zip/StreamIOAfterClose.java
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 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.
|
||||
*
|
||||
* 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 4110528 4112112 4112103
|
||||
@summary Test if zip related in/output streams will
|
||||
prevent i/o after stream has been closed.
|
||||
*/
|
||||
import java.util.zip.*;
|
||||
import java.util.jar.*;
|
||||
import java.io.*;
|
||||
|
||||
public class StreamIOAfterClose {
|
||||
// compressed stub data
|
||||
private static byte[] compressed = {
|
||||
31,-117,8,0,0,0,0,0,0,0,-85,-107,-79,74,85,97,117,48,
|
||||
-9,117,-47,114,15,-87,-27,-9,-54,-48,49,-108,17,19,20,
|
||||
118,-87,-84,78,-15,-10,-87,-112,51,115,16,85,81,54,11,
|
||||
114,44,11,98,116,17,102,-10,72,-10,80,-79,101,14,47,-50,
|
||||
16,117,-9,-83,16,13,-55,83,83,103,-30,-117,-42,-82,-105,
|
||||
-119,46,-16,20,-111,-85,-16,-48,54,79,-53,-76,116,
|
||||
-80,-78,77,-88,-85,50,113,-54,15,-74,-28,-44,101,-43,47,
|
||||
85,54,-74,1,0,85,69,28,117,100,0,0,0
|
||||
};
|
||||
|
||||
private static void testRead(InputStream in) throws Exception {
|
||||
in.close();
|
||||
try {
|
||||
in.read();
|
||||
throw new Exception("read allowed after stream is closed");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private static void testWrite(ZipOutputStream out) throws Exception {
|
||||
out.close();
|
||||
try {
|
||||
out.putNextEntry(new ZipEntry(""));
|
||||
throw new Exception("write allowed after stream is closed");
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String argv[]) throws Exception {
|
||||
ZipOutputStream zos = new ZipOutputStream(new ByteArrayOutputStream());
|
||||
zos.putNextEntry(new ZipEntry("1"));
|
||||
testWrite(zos);
|
||||
|
||||
JarOutputStream jos = new JarOutputStream(new ByteArrayOutputStream());
|
||||
jos.putNextEntry(new ZipEntry("1"));
|
||||
testWrite(jos);
|
||||
|
||||
InputStream bis = new ByteArrayInputStream(new byte[10]);
|
||||
InputStream bis1 = new ByteArrayInputStream(compressed);
|
||||
testRead(new ZipInputStream(bis));
|
||||
testRead(new GZIPInputStream(bis1));
|
||||
}
|
||||
}
|
||||
39
test/jdk/java/util/zip/TestCRC32.java
Normal file
39
test/jdk/java/util/zip/TestCRC32.java
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
/**
|
||||
* @test @summary Check that CRC-32 returns the expected CRC value for the
|
||||
* string 123456789
|
||||
* http://reveng.sourceforge.net/crc-catalogue/all.htm#crc.cat.crc-32
|
||||
* @build ChecksumBase
|
||||
* @run main TestCRC32
|
||||
*/
|
||||
|
||||
public class TestCRC32 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ChecksumBase.testAll(new CRC32(), 0xCBF43926L);
|
||||
}
|
||||
}
|
||||
39
test/jdk/java/util/zip/TestCRC32C.java
Normal file
39
test/jdk/java/util/zip/TestCRC32C.java
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.util.zip.CRC32C;
|
||||
|
||||
/**
|
||||
* @test @summary Check that CRC-32C returns the expected CRC value for the
|
||||
* string 123456789
|
||||
* http://reveng.sourceforge.net/crc-catalogue/all.htm#crc.cat.crc-32c
|
||||
* @build ChecksumBase
|
||||
* @run main TestCRC32C
|
||||
*/
|
||||
|
||||
public class TestCRC32C {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ChecksumBase.testAll(new CRC32C(), 0xE3069283L);
|
||||
}
|
||||
}
|
||||
66
test/jdk/java/util/zip/TestChecksum.java
Normal file
66
test/jdk/java/util/zip/TestChecksum.java
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*
|
||||
* 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 @summary Test that default methods in Checksum works as expected
|
||||
* @build ChecksumBase
|
||||
* @run main TestChecksum
|
||||
*/
|
||||
import java.util.zip.CRC32C;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
public class TestChecksum {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ChecksumBase.testAll(new MyCRC32C(), 0xE3069283L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only implementing required methods
|
||||
*/
|
||||
private static class MyCRC32C implements Checksum {
|
||||
|
||||
private final CRC32C crc32c = new CRC32C();
|
||||
|
||||
@Override
|
||||
public void update(int b) {
|
||||
crc32c.update(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(byte[] b, int off, int len) {
|
||||
crc32c.update(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getValue() {
|
||||
return crc32c.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
crc32c.reset();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
141
test/jdk/java/util/zip/TestEmptyZip.java
Normal file
141
test/jdk/java/util/zip/TestEmptyZip.java
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2011, 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.
|
||||
*
|
||||
* 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 6334003 6440786
|
||||
* @summary Test ability to write and read zip files that have no entries.
|
||||
* @author Dave Bristor
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class TestEmptyZip {
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
String zipName = "foo.zip";
|
||||
File f = new File(System.getProperty("test.scratch", "."), zipName);
|
||||
if (f.exists() && !f.delete()) {
|
||||
throw new Exception("failed to delete " + zipName);
|
||||
}
|
||||
|
||||
f.createNewFile();
|
||||
try {
|
||||
// Verify 0-length file cannot be read
|
||||
checkCannotRead(f);
|
||||
|
||||
// Verify non-zip file cannot be read
|
||||
OutputStream out = new FileOutputStream(f);
|
||||
try {
|
||||
out.write("class Foo { }".getBytes());
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
checkCannotRead(f);
|
||||
|
||||
} finally {
|
||||
f.delete();
|
||||
}
|
||||
|
||||
// Verify 0-entries file can be written
|
||||
write(f);
|
||||
|
||||
// Verify 0-entries file can be read
|
||||
readFile(f);
|
||||
readStream(f);
|
||||
|
||||
f.delete();
|
||||
}
|
||||
|
||||
static void checkCannotRead(File f) throws IOException {
|
||||
try {
|
||||
new ZipFile(f).close();
|
||||
fail();
|
||||
} catch (ZipException ze) {
|
||||
if (f.length() == 0) {
|
||||
check(ze.getMessage().contains("zip file is empty"));
|
||||
} else {
|
||||
pass();
|
||||
}
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(f);
|
||||
ZipInputStream zis = new ZipInputStream(fis))
|
||||
{
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
check(ze == null);
|
||||
} catch (IOException ex) {
|
||||
unexpected(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void write(File f) throws Exception {
|
||||
try (FileOutputStream fis = new FileOutputStream(f);
|
||||
ZipOutputStream zos = new ZipOutputStream(fis))
|
||||
{
|
||||
zos.finish();
|
||||
pass();
|
||||
} catch (Exception ex) {
|
||||
unexpected(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void readFile(File f) throws Exception {
|
||||
try (ZipFile zf = new ZipFile(f)) {
|
||||
|
||||
Enumeration e = zf.entries();
|
||||
while (e.hasMoreElements()) {
|
||||
ZipEntry entry = (ZipEntry) e.nextElement();
|
||||
fail();
|
||||
}
|
||||
pass();
|
||||
} catch (Exception ex) {
|
||||
unexpected(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void readStream(File f) throws Exception {
|
||||
try (FileInputStream fis = new FileInputStream(f);
|
||||
ZipInputStream zis = new ZipInputStream(fis))
|
||||
{
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
check(ze == null);
|
||||
byte[] buf = new byte[1024];
|
||||
check(zis.read(buf, 0, 1024) == -1);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static boolean pass() {passed++; return true;}
|
||||
static boolean fail() {failed++; Thread.dumpStack(); return false;}
|
||||
static boolean fail(String msg) {System.out.println(msg); return fail();}
|
||||
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
||||
static boolean equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) return pass();
|
||||
else return fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
369
test/jdk/java/util/zip/TestExtraTime.java
Normal file
369
test/jdk/java/util/zip/TestExtraTime.java
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2023, 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.
|
||||
*
|
||||
* 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 4759491 6303183 7012868 8015666 8023713 8068790 8076641 8075526 8130914
|
||||
* 8161942 8206389
|
||||
* @summary Test ZOS and ZIS timestamp in extra field correctly
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributeView;
|
||||
import java.nio.file.attribute.FileOwnerAttributeView;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
|
||||
|
||||
public class TestExtraTime {
|
||||
|
||||
public static void main(String[] args) throws Throwable{
|
||||
|
||||
File src = new File(System.getProperty("test.src", "."), "TestExtraTime.java");
|
||||
if (!src.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
|
||||
|
||||
// A structurally valid extra data example
|
||||
byte[] sampleExtra = new byte[Short.BYTES*3];
|
||||
ByteBuffer.wrap(sampleExtra).order(ByteOrder.LITTLE_ENDIAN)
|
||||
.putShort((short) 123) // ID: 123
|
||||
.putShort((short) Short.BYTES) // Size: 2
|
||||
.putShort((short) 42); // Data: Two bytes
|
||||
|
||||
for (byte[] extra : new byte[][] { null, sampleExtra}) {
|
||||
|
||||
// ms-dos 1980 epoch problem
|
||||
test0(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null, extra);
|
||||
// negative epoch time
|
||||
test0(FileTime.from(-100, TimeUnit.DAYS), null, null, null, extra);
|
||||
|
||||
long time = src.lastModified();
|
||||
test(FileTime.from(time, TimeUnit.MILLISECONDS),
|
||||
FileTime.from(time + 300000, TimeUnit.MILLISECONDS),
|
||||
FileTime.from(time - 300000, TimeUnit.MILLISECONDS),
|
||||
tz, extra);
|
||||
|
||||
// now
|
||||
time = Instant.now().toEpochMilli();
|
||||
test(FileTime.from(time, TimeUnit.MILLISECONDS),
|
||||
FileTime.from(time + 300000, TimeUnit.MILLISECONDS),
|
||||
FileTime.from(time - 300000, TimeUnit.MILLISECONDS),
|
||||
tz, extra);
|
||||
|
||||
// unix 2038
|
||||
time = 0x80000000L;
|
||||
test(FileTime.from(time, TimeUnit.SECONDS),
|
||||
FileTime.from(time, TimeUnit.SECONDS),
|
||||
FileTime.from(time, TimeUnit.SECONDS),
|
||||
tz, extra);
|
||||
|
||||
// mtime < unix 2038
|
||||
time = 0x7fffffffL;
|
||||
test(FileTime.from(time, TimeUnit.SECONDS),
|
||||
FileTime.from(time + 30000, TimeUnit.SECONDS),
|
||||
FileTime.from(time + 30000, TimeUnit.SECONDS),
|
||||
tz, extra);
|
||||
}
|
||||
|
||||
testNullHandling();
|
||||
testTagOnlyHandling();
|
||||
testTimeConversions();
|
||||
testNullMtime();
|
||||
}
|
||||
|
||||
static void test(FileTime mtime, FileTime atime, FileTime ctime,
|
||||
TimeZone tz, byte[] extra) throws Throwable {
|
||||
test0(mtime, null, null, null, extra);
|
||||
test0(mtime, null, null, tz, extra); // non-default tz
|
||||
test0(mtime, atime, null, null, extra);
|
||||
test0(mtime, null, ctime, null, extra);
|
||||
test0(mtime, atime, ctime, null, extra);
|
||||
test0(mtime, atime, null, tz, extra);
|
||||
test0(mtime, null, ctime, tz, extra);
|
||||
test0(mtime, atime, ctime, tz, extra);
|
||||
}
|
||||
|
||||
static void test0(FileTime mtime, FileTime atime, FileTime ctime,
|
||||
TimeZone tz, byte[] extra) throws Throwable {
|
||||
System.out.printf("--------------------%nTesting: [%s]/[%s]/[%s]%n",
|
||||
mtime, atime, ctime);
|
||||
TimeZone tz0 = TimeZone.getDefault();
|
||||
if (tz != null) {
|
||||
TimeZone.setDefault(tz);
|
||||
}
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos);
|
||||
ZipEntry ze = new ZipEntry("TestExtraTime.java");
|
||||
ze.setExtra(extra);
|
||||
ze.setLastModifiedTime(mtime);
|
||||
if (atime != null)
|
||||
ze.setLastAccessTime(atime);
|
||||
if (ctime != null)
|
||||
ze.setCreationTime(ctime);
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(new byte[] { 1,2 ,3, 4});
|
||||
|
||||
// append an extra entry to help check if the length and data
|
||||
// of the extra field are being correctly written (in previous
|
||||
// entry).
|
||||
if (extra != null) {
|
||||
ze = new ZipEntry("TestExtraEntry");
|
||||
zos.putNextEntry(ze);
|
||||
}
|
||||
zos.close();
|
||||
if (tz != null) {
|
||||
TimeZone.setDefault(tz0);
|
||||
}
|
||||
// ZipInputStream
|
||||
ZipInputStream zis = new ZipInputStream(
|
||||
new ByteArrayInputStream(baos.toByteArray()));
|
||||
ze = zis.getNextEntry();
|
||||
zis.close();
|
||||
check(mtime, atime, ctime, ze, extra);
|
||||
|
||||
// ZipFile
|
||||
Path zpath = Paths.get(System.getProperty("test.dir", "."),
|
||||
"TestExtraTime.zip");
|
||||
Path zparent = zpath.getParent();
|
||||
if (zparent != null && !Files.isWritable(zparent)) {
|
||||
System.err.format("zpath %s parent %s is not writable%n",
|
||||
zpath, zparent);
|
||||
}
|
||||
if (Files.exists(zpath)) {
|
||||
System.err.format("zpath %s already exists%n", zpath);
|
||||
if (Files.isDirectory(zpath)) {
|
||||
System.err.format("%n%s contents:%n", zpath);
|
||||
Files.list(zpath).forEach(System.err::println);
|
||||
}
|
||||
FileOwnerAttributeView foav = Files.getFileAttributeView(zpath,
|
||||
FileOwnerAttributeView.class);
|
||||
System.err.format("zpath %s owner: %s%n", zpath, foav.getOwner());
|
||||
System.err.format("zpath %s permissions:%n", zpath);
|
||||
Set<PosixFilePermission> perms =
|
||||
Files.getPosixFilePermissions(zpath);
|
||||
perms.stream().forEach(System.err::println);
|
||||
}
|
||||
if (Files.isSymbolicLink(zpath)) {
|
||||
System.err.format("zpath %s is a symbolic link%n", zpath);
|
||||
}
|
||||
Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath);
|
||||
try (ZipFile zf = new ZipFile(zpath.toFile())) {
|
||||
ze = zf.getEntry("TestExtraTime.java");
|
||||
// ZipFile read entry from cen, which does not have a/ctime,
|
||||
// for now.
|
||||
check(mtime, null, null, ze, extra);
|
||||
} finally {
|
||||
Files.delete(zpath);
|
||||
}
|
||||
}
|
||||
|
||||
static void check(FileTime mtime, FileTime atime, FileTime ctime,
|
||||
ZipEntry ze, byte[] extra) {
|
||||
/*
|
||||
System.out.printf(" mtime [%tc]: [%tc]/[%tc]%n",
|
||||
mtime.to(TimeUnit.MILLISECONDS),
|
||||
ze.getTime(),
|
||||
ze.getLastModifiedTime().to(TimeUnit.MILLISECONDS));
|
||||
*/
|
||||
if (mtime != null &&
|
||||
mtime.to(TimeUnit.SECONDS) !=
|
||||
ze.getLastModifiedTime().to(TimeUnit.SECONDS)) {
|
||||
throw new RuntimeException("Timestamp: storing mtime failed!");
|
||||
}
|
||||
if (atime != null &&
|
||||
atime.to(TimeUnit.SECONDS) !=
|
||||
ze.getLastAccessTime().to(TimeUnit.SECONDS))
|
||||
throw new RuntimeException("Timestamp: storing atime failed!");
|
||||
if (ctime != null &&
|
||||
ctime.to(TimeUnit.SECONDS) !=
|
||||
ze.getCreationTime().to(TimeUnit.SECONDS))
|
||||
throw new RuntimeException("Timestamp: storing ctime failed!");
|
||||
if (extra != null) {
|
||||
// if extra data exists, the current implementation put it at
|
||||
// the end of the extra data array (implementation detail)
|
||||
byte[] extra1 = ze.getExtra();
|
||||
if (extra1 == null || extra1.length < extra.length ||
|
||||
!Arrays.equals(Arrays.copyOfRange(extra1,
|
||||
extra1.length - extra.length,
|
||||
extra1.length),
|
||||
extra)) {
|
||||
throw new RuntimeException("Timestamp: storing extra field failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testNullHandling() {
|
||||
ZipEntry ze = new ZipEntry("TestExtraTime.java");
|
||||
try {
|
||||
ze.setLastAccessTime(null);
|
||||
throw new RuntimeException("setLastAccessTime(null) should throw NPE");
|
||||
} catch (NullPointerException ignored) {
|
||||
// pass
|
||||
}
|
||||
try {
|
||||
ze.setCreationTime(null);
|
||||
throw new RuntimeException("setCreationTime(null) should throw NPE");
|
||||
} catch (NullPointerException ignored) {
|
||||
// pass
|
||||
}
|
||||
try {
|
||||
ze.setLastModifiedTime(null);
|
||||
throw new RuntimeException("setLastModifiedTime(null) should throw NPE");
|
||||
} catch (NullPointerException ignored) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
|
||||
// verify that setting and getting any time is possible as per the intent
|
||||
// of 4759491
|
||||
static void testTimeConversions() {
|
||||
// Sample across the entire range
|
||||
long step = Long.MAX_VALUE / 100L;
|
||||
testTimeConversions(Long.MIN_VALUE, Long.MAX_VALUE - step, step);
|
||||
|
||||
// Samples through the near future
|
||||
long currentTime = System.currentTimeMillis();
|
||||
testTimeConversions(currentTime, currentTime + 1_000_000, 10_000);
|
||||
}
|
||||
|
||||
static void testTimeConversions(long from, long to, long step) {
|
||||
ZipEntry ze = new ZipEntry("TestExtraTime.java");
|
||||
for (long time = from; time <= to; time += step) {
|
||||
ze.setTime(time);
|
||||
FileTime lastModifiedTime = ze.getLastModifiedTime();
|
||||
if (lastModifiedTime.toMillis() != time) {
|
||||
throw new RuntimeException("setTime should make getLastModifiedTime " +
|
||||
"return the specified instant: " + time +
|
||||
" got: " + lastModifiedTime.toMillis());
|
||||
}
|
||||
if (ze.getTime() != time) {
|
||||
throw new RuntimeException("getTime after setTime, expected: " +
|
||||
time + " got: " + ze.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check(ZipEntry ze, byte[] extra) {
|
||||
if (extra != null) {
|
||||
byte[] extra1 = ze.getExtra();
|
||||
if (extra1 == null || extra1.length < extra.length ||
|
||||
!Arrays.equals(Arrays.copyOfRange(extra1,
|
||||
extra1.length - extra.length,
|
||||
extra1.length),
|
||||
extra)) {
|
||||
throw new RuntimeException("Timestamp: storing extra field failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testTagOnlyHandling() throws Throwable {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] extra = new byte[] { 0x0a, 0, 4, 0, 0, 0, 0, 0 };
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
ZipEntry ze = new ZipEntry("TestExtraTime.java");
|
||||
ze.setExtra(extra);
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(new byte[] { 1,2 ,3, 4});
|
||||
}
|
||||
try (ZipInputStream zis = new ZipInputStream(
|
||||
new ByteArrayInputStream(baos.toByteArray()))) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
check(ze, extra);
|
||||
}
|
||||
Path zpath = Paths.get(System.getProperty("test.dir", "."),
|
||||
"TestExtraTime.zip");
|
||||
Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath);
|
||||
try (ZipFile zf = new ZipFile(zpath.toFile())) {
|
||||
ZipEntry ze = zf.getEntry("TestExtraTime.java");
|
||||
check(ze, extra);
|
||||
} finally {
|
||||
Files.delete(zpath);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkLastModifiedTimeDOS(FileTime mtime, ZipEntry ze) {
|
||||
FileTime lmt = ze.getLastModifiedTime();
|
||||
if ((lmt.to(TimeUnit.SECONDS) >>> 1) != (mtime.to(TimeUnit.SECONDS) >>> 1) ||
|
||||
lmt.to(TimeUnit.MILLISECONDS) != ze.getTime() ||
|
||||
lmt.to(TimeUnit.MILLISECONDS) % 1000 != 0) {
|
||||
throw new RuntimeException("Timestamp: storing mtime in dos format failed!");
|
||||
}
|
||||
}
|
||||
|
||||
static void testNullMtime() throws Throwable {
|
||||
Instant now = Instant.now();
|
||||
FileTime ctime = FileTime.from(now);
|
||||
FileTime atime = FileTime.from(now.plusSeconds(7));
|
||||
FileTime mtime = FileTime.from(now.plusSeconds(13));
|
||||
System.out.printf("--------------------%nTesting: [%s]/[%s]/[%s]%n",
|
||||
mtime, atime, ctime);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
ZipEntry ze = new ZipEntry("TestExtraTime.java");
|
||||
ze.setCreationTime(ctime);
|
||||
ze.setLastAccessTime(atime);
|
||||
// ze.setLastModifiedTime(now);
|
||||
ze.setTime(mtime.toMillis());
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(new byte[] { 1,2 ,3, 4});
|
||||
}
|
||||
|
||||
try (ZipInputStream zis = new ZipInputStream(
|
||||
new ByteArrayInputStream(baos.toByteArray()))) {
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
// check LOC
|
||||
check(null, atime, ctime, ze, null);
|
||||
checkLastModifiedTimeDOS(mtime, ze);
|
||||
}
|
||||
|
||||
Path zpath = Paths.get(System.getProperty("test.dir", "."),
|
||||
"TestExtraTime.zip");
|
||||
Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath);
|
||||
try (ZipFile zf = new ZipFile(zpath.toFile())) {
|
||||
ZipEntry ze = zf.getEntry("TestExtraTime.java");
|
||||
// check CEN
|
||||
checkLastModifiedTimeDOS(mtime, ze);
|
||||
} finally {
|
||||
Files.delete(zpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
145
test/jdk/java/util/zip/TestLocalTime.java
Normal file
145
test/jdk/java/util/zip/TestLocalTime.java
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2016, 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.
|
||||
*
|
||||
* 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 8075526 8135108 8155616 8161942
|
||||
* @summary Test timestamp via ZipEntry.get/setTimeLocal()
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class TestLocalTime {
|
||||
private static TimeZone tz0 = TimeZone.getDefault();
|
||||
|
||||
public static void main(String[] args) throws Throwable{
|
||||
try {
|
||||
LocalDateTime ldt = LocalDateTime.now();
|
||||
test(ldt); // now
|
||||
test(ldt.withYear(1968));
|
||||
test(ldt.withYear(1970));
|
||||
test(ldt.withYear(1982));
|
||||
test(ldt.withYear(2037));
|
||||
test(ldt.withYear(2100));
|
||||
test(ldt.withYear(2106));
|
||||
|
||||
TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
|
||||
// dos time does not support < 1980, have to use
|
||||
// utc in mtime.
|
||||
testWithTZ(tz, ldt.withYear(1982));
|
||||
testWithTZ(tz, ldt.withYear(2037));
|
||||
testWithTZ(tz, ldt.withYear(2100));
|
||||
testWithTZ(tz, ldt.withYear(2106));
|
||||
|
||||
// for #8135108
|
||||
test(LocalDateTime.of(2100, 12, 06, 12, 34, 34, 973));
|
||||
test(LocalDateTime.of(2106, 12, 06, 12, 34, 34, 973));
|
||||
|
||||
// for #8155616
|
||||
test(LocalDateTime.of(2016, 03, 13, 2, 50, 00)); // gap
|
||||
test(LocalDateTime.of(2015, 11, 1, 1, 30, 00)); // overlap
|
||||
test(LocalDateTime.of(1968, 04, 28, 2, 51, 25));
|
||||
test(LocalDateTime.of(1970, 04, 26, 2, 31, 52));
|
||||
|
||||
// for #8161942
|
||||
test(LocalDateTime.of(2200, 04, 26, 2, 31, 52)); // unix 2038
|
||||
|
||||
} finally {
|
||||
TimeZone.setDefault(tz0);
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] getBytes(LocalDateTime mtime) throws Throwable {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos);
|
||||
ZipEntry ze = new ZipEntry("TestLocalTime.java");
|
||||
ze.setTimeLocal(mtime);
|
||||
check(ze, mtime);
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(new byte[] { 1, 2, 3, 4});
|
||||
zos.close();
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
static void testWithTZ(TimeZone tz, LocalDateTime ldt) throws Throwable {
|
||||
TimeZone.setDefault(tz);
|
||||
byte[] zbytes = getBytes(ldt);
|
||||
TimeZone.setDefault(tz0);
|
||||
test(zbytes, ldt);
|
||||
}
|
||||
|
||||
static void test(LocalDateTime ldt) throws Throwable {
|
||||
test(getBytes(ldt), ldt);
|
||||
}
|
||||
|
||||
static void test(byte[] zbytes, LocalDateTime expected) throws Throwable {
|
||||
System.out.printf("--------------------%nTesting: [%s]%n", expected);
|
||||
// ZipInputStream
|
||||
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zbytes));
|
||||
ZipEntry ze = zis.getNextEntry();
|
||||
zis.close();
|
||||
check(ze, expected);
|
||||
|
||||
// ZipFile
|
||||
Path zpath = Paths.get(System.getProperty("test.dir", "."),
|
||||
"TestLocalTime.zip");
|
||||
try {
|
||||
Files.copy(new ByteArrayInputStream(zbytes), zpath);
|
||||
ZipFile zf = new ZipFile(zpath.toFile());
|
||||
ze = zf.getEntry("TestLocalTime.java");
|
||||
check(ze, expected);
|
||||
zf.close();
|
||||
} finally {
|
||||
Files.deleteIfExists(zpath);
|
||||
}
|
||||
}
|
||||
|
||||
static void check(ZipEntry ze, LocalDateTime expected) {
|
||||
LocalDateTime ldt = ze.getTimeLocal();
|
||||
if (ldt.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1
|
||||
!= expected.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1) {
|
||||
// if the LDT is out of the range of the standard ms-dos date-time
|
||||
// format ( < 1980 ) AND the date-time is within the daylight saving
|
||||
// time gap (which means the LDT is actually "invalid"), the LDT will
|
||||
// be adjusted accordingly when ZipEntry.setTimeLocal() converts the
|
||||
// date-time via ldt -> zdt -> Instant -> FileTime.
|
||||
// See ZonedDateTime.of(LocalDateTime, ZoneId) for more details.
|
||||
if (ldt.getYear() < 1980 || ldt.getYear() > (1980 + 0x7f)) {
|
||||
System.out.println(" Non-MSDOS ldt : " + ldt);
|
||||
System.out.println(" expected : " + expected);
|
||||
// try to adjust the "expected", assume daylight saving gap
|
||||
expected = ZonedDateTime.of(expected, ZoneId.systemDefault())
|
||||
.toLocalDateTime();
|
||||
if (ldt.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1
|
||||
== expected.atOffset(ZoneOffset.UTC).toEpochSecond() >> 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Timestamp: storing mtime failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
206
test/jdk/java/util/zip/TimeChecksum.java
Normal file
206
test/jdk/java/util/zip/TimeChecksum.java
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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 7109837
|
||||
* @summary Test Adler32/CRC32.update(ByteBuffer)
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.nio.*;
|
||||
|
||||
public class TimeChecksum {
|
||||
|
||||
static long time(Adler32 adler32, byte[] data, int iters, int len) {
|
||||
long start_t = System.nanoTime();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
adler32.reset();
|
||||
adler32.update(data, 0, len);
|
||||
}
|
||||
long t = System.nanoTime() - start_t;
|
||||
System.out.printf("%,12d", t / len);
|
||||
return t;
|
||||
}
|
||||
|
||||
static long time(Adler32 adler32, ByteBuffer buf, int iters) {
|
||||
long start_t = System.nanoTime();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
adler32.reset();
|
||||
buf.mark();
|
||||
adler32.update(buf);
|
||||
buf.reset();
|
||||
}
|
||||
long t = System.nanoTime() - start_t;
|
||||
System.out.printf("%,12d", t / buf.remaining());
|
||||
return t;
|
||||
}
|
||||
|
||||
static void testPosLimit(Adler32 adler32, ByteBuffer buf) {
|
||||
int pos = buf.position();
|
||||
int limit = buf.limit();
|
||||
adler32.update(buf);
|
||||
if (limit != buf.position() || limit != buf.limit()) {
|
||||
System.out.printf("%nFAILED: pos,limit=(%d, %d), expected (%d, %d)%n",
|
||||
buf.position(), buf.limit(), limit, limit);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
buf.position(pos);
|
||||
}
|
||||
|
||||
static long time(CRC32 crc32, byte[] data, int iters, int len) {
|
||||
long start_t = System.nanoTime();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc32.reset();
|
||||
crc32.update(data, 0, len);
|
||||
}
|
||||
long t = System.nanoTime() - start_t;
|
||||
System.out.printf("%,12d", t / len);
|
||||
return t;
|
||||
}
|
||||
|
||||
static long time(CRC32 crc32, ByteBuffer buf, int iters) {
|
||||
long start_t = System.nanoTime();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc32.reset();
|
||||
buf.mark();
|
||||
crc32.update(buf);
|
||||
buf.reset();
|
||||
}
|
||||
long t = System.nanoTime() - start_t;
|
||||
System.out.printf("%,12d", t / buf.remaining());
|
||||
return t;
|
||||
}
|
||||
|
||||
static void testPosLimit(CRC32 crc32, ByteBuffer buf) {
|
||||
int pos = buf.position();
|
||||
int limit = buf.limit();
|
||||
crc32.update(buf);
|
||||
if (limit != buf.position() || limit != buf.limit()) {
|
||||
System.out.printf("%nFAILED: pos,limit=(%d, %d), expected (%d, %d)%n",
|
||||
buf.position(), buf.limit(), limit, limit);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
buf.position(pos);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int len = 1024 * 32;
|
||||
int iters = 1;
|
||||
if (args.length != 0 && "-benchmark".equals(args[0]))
|
||||
iters = 100000;
|
||||
Adler32 adler32 = new Adler32();
|
||||
CRC32 crc32 = new CRC32();
|
||||
Random rdm = new Random();
|
||||
byte[] data = new byte[len];
|
||||
new Random().nextBytes(data);
|
||||
ByteBuffer buf;
|
||||
|
||||
System.out.println("---------- Adler32 ----------");
|
||||
System.out.print("Warmup...");
|
||||
time(adler32, data, iters, len);
|
||||
time(adler32, ByteBuffer.wrap(data), iters);
|
||||
buf = ByteBuffer.allocateDirect(len);
|
||||
buf.put(data, 0, len);
|
||||
buf.flip();
|
||||
time(adler32, buf, iters);
|
||||
System.out.println("\n");
|
||||
|
||||
System.out.println("Length byte[](ns/len) ByteBuffer(direct) ByteBuffer");
|
||||
for (int testlen = 1; testlen < data.length; testlen <<= 1) {
|
||||
System.out.print(testlen + "\t");
|
||||
long baT = time(adler32, data, iters, testlen);
|
||||
long baV = adler32.getValue();
|
||||
System.out.print("\t");
|
||||
|
||||
buf = ByteBuffer.allocateDirect(testlen);
|
||||
buf.put(data, 0, testlen);
|
||||
buf.flip();
|
||||
long bbdT = time(adler32, buf, iters);
|
||||
long bbdV = adler32.getValue();
|
||||
if (baV != bbdV) {
|
||||
System.out.printf("%nFAILED: baV=%x,bbdV=%x%n", baV, bbdV);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
System.out.printf(" (%.2f)", (float)bbdT/baT);
|
||||
testPosLimit(adler32, buf);
|
||||
|
||||
buf = ByteBuffer.allocate(testlen);
|
||||
buf.put(data, 0, testlen);
|
||||
buf.flip();
|
||||
long bbT = time(adler32, buf, iters);
|
||||
long bbV = adler32.getValue();
|
||||
if (baV != bbV) {
|
||||
System.out.printf("%nFAILED: baV=%x,bbV=%x%n", baV, bbV);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
testPosLimit(adler32, buf);
|
||||
System.out.printf(" (%.2f) checksum=%x%n", (float)bbT/baT, bbV);
|
||||
}
|
||||
|
||||
System.out.println("\n---------- CRC32 ----------");
|
||||
System.out.print("Warmup...");
|
||||
time(crc32, data, iters, len);
|
||||
time(crc32, ByteBuffer.wrap(data), iters);
|
||||
buf = ByteBuffer.allocateDirect(len);
|
||||
buf.put(data, 0, len);
|
||||
buf.flip();
|
||||
time(crc32, buf, iters);
|
||||
System.out.println("\n");
|
||||
|
||||
|
||||
System.out.println("Length byte[](ns/len) ByteBuffer(direct) ByteBuffer");
|
||||
for (int testlen = 1; testlen < data.length; testlen <<= 1) {
|
||||
System.out.print(testlen + "\t");
|
||||
long baT = time(crc32, data, iters, testlen);
|
||||
long baV = crc32.getValue();
|
||||
System.out.print("\t");
|
||||
|
||||
buf = ByteBuffer.allocateDirect(testlen);
|
||||
buf.put(data, 0, testlen);
|
||||
buf.flip();
|
||||
long bbdT = time(crc32, buf, iters);
|
||||
long bbdV = crc32.getValue();
|
||||
if (baV != bbdV) {
|
||||
System.out.printf("%nFAILED: baV=%x,bbdV=%x%n", baV, bbdV);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
System.out.printf(" (%.2f)", (float)bbdT/baT);
|
||||
testPosLimit(crc32, buf);
|
||||
|
||||
buf = ByteBuffer.allocate(testlen);
|
||||
buf.put(data, 0, testlen);
|
||||
buf.flip();
|
||||
long bbT = time(crc32, buf, iters);
|
||||
long bbV = crc32.getValue();
|
||||
if (baV != bbV) {
|
||||
System.out.printf("%nFAILED: baV=%x,bbV=%x%n", baV, bbV);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
testPosLimit(crc32, buf);
|
||||
System.out.printf(" (%.2f) checksum=%x%n", (float)bbT / baT, bbV);
|
||||
}
|
||||
}
|
||||
}
|
||||
97
test/jdk/java/util/zip/TotalInOut.java
Normal file
97
test/jdk/java/util/zip/TotalInOut.java
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2025, 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.
|
||||
*
|
||||
* 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 7188852
|
||||
* @summary Test De/Inflater.getBytesRead/Written()
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
|
||||
public class TotalInOut {
|
||||
static final int BUF_SIZE= 1 * 1024 * 1024;
|
||||
|
||||
static void realMain (String[] args) throws Throwable {
|
||||
long dataSize = 128L * 1024L * 1024L; // 128MB
|
||||
if (args.length > 0 && "large".equals(args[0]))
|
||||
dataSize = 5L * 1024L * 1024L * 1024L; // 5GB
|
||||
|
||||
try (final Deflater deflater = new Deflater();
|
||||
final Inflater inflater = new Inflater()) {
|
||||
|
||||
byte[] dataIn = new byte[BUF_SIZE];
|
||||
byte[] dataOut = new byte[BUF_SIZE];
|
||||
byte[] tmp = new byte[BUF_SIZE];
|
||||
|
||||
Random r = new Random();
|
||||
r.nextBytes(dataIn);
|
||||
long bytesReadDef = 0;
|
||||
long bytesWrittenDef = 0;
|
||||
long bytesReadInf = 0;
|
||||
long bytesWrittenInf = 0;
|
||||
|
||||
deflater.setInput(dataIn, 0, dataIn.length);
|
||||
while (bytesReadDef < dataSize || bytesWrittenInf < dataSize) {
|
||||
int len = r.nextInt(BUF_SIZE / 2) + BUF_SIZE / 2;
|
||||
if (deflater.needsInput()) {
|
||||
bytesReadDef += dataIn.length;
|
||||
check(bytesReadDef == deflater.getBytesRead());
|
||||
deflater.setInput(dataIn, 0, dataIn.length);
|
||||
}
|
||||
int n = deflater.deflate(tmp, 0, len);
|
||||
bytesWrittenDef += n;
|
||||
check(bytesWrittenDef == deflater.getBytesWritten());
|
||||
|
||||
inflater.setInput(tmp, 0, n);
|
||||
bytesReadInf += n;
|
||||
while (!inflater.needsInput()) {
|
||||
bytesWrittenInf += inflater.inflate(dataOut, 0, dataOut.length);
|
||||
check(bytesWrittenInf == inflater.getBytesWritten());
|
||||
}
|
||||
check(bytesReadInf == inflater.getBytesRead());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- 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;}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
207
test/jdk/java/util/zip/ZipCoding.java
Normal file
207
test/jdk/java/util/zip/ZipCoding.java
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2024, 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.
|
||||
*
|
||||
* 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 4244499 4532049 4700978 4820807 4980042 7009069 8322802
|
||||
* @summary Test ZipInputStream, ZipOutputStream and ZipFile with non-UTF8 encoding
|
||||
* @modules jdk.charsets
|
||||
* @run junit ZipCoding
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ZipCoding {
|
||||
|
||||
// The data to write to ZIP entries in this test
|
||||
private static byte[] ENTRY_DATA = "German Umlaut \u00fc in entry data"
|
||||
.getBytes(StandardCharsets.ISO_8859_1);
|
||||
|
||||
/**
|
||||
* Provide arguments used for parameterized tests
|
||||
* @return a stream of argument lists
|
||||
*/
|
||||
public static Stream<Arguments> charsetsAndNames() {
|
||||
// Arguments are: Write charset, read charset, entry name, comment
|
||||
return Stream.of(
|
||||
// MS code page 932 for the Japanese language
|
||||
Arguments.of("MS932", "MS932",
|
||||
"\u4e00\u4e01",
|
||||
"\uff67\uff68\uff69\uff6a\uff6b\uff6c"),
|
||||
|
||||
// Code page for the IBM PC
|
||||
Arguments.of("ibm437", "ibm437",
|
||||
"\u00e4\u00fc",
|
||||
"German Umlaut \u00fc in comment"),
|
||||
|
||||
// UTF-8 with Japanese characters
|
||||
Arguments.of("utf-8", "utf-8",
|
||||
"\u4e00\u4e01",
|
||||
"\uff67\uff68\uff69\uff6a\uff6b\uff6c"),
|
||||
|
||||
// UTF-8 with characters in the Latin1 range
|
||||
Arguments.of("utf-8", "utf-8",
|
||||
"\u00e4\u00fc",
|
||||
"German Umlaut \u00fc in comment"),
|
||||
|
||||
// UTF-8 with surrogate pairs
|
||||
Arguments.of("utf-8", "utf-8",
|
||||
"Surrogate\ud801\udc01",
|
||||
"Surrogates \ud800\udc00 in comment"),
|
||||
|
||||
// ZipOutputStream sets the 'Language encoding flag' when writing using UTF-8
|
||||
// UTF-8 should be used for decoding, regardless of the opening charset
|
||||
|
||||
// UTF-8 with Japanese characters, opened with MS932
|
||||
Arguments.of("utf-8", "MS932",
|
||||
"\u4e00\u4e01",
|
||||
"\uff67\uff68\uff69\uff6a\uff6b\uff6c"),
|
||||
|
||||
// UTF-8 with characters in latin1 range, opened with iso-8859-1
|
||||
Arguments.of("utf-8", "iso-8859-1",
|
||||
"\u00e4\u00fc",
|
||||
"German Umlaut \u00fc in comment"),
|
||||
// UTF-8 with surrogate pairs, opened with MS932
|
||||
Arguments.of("utf-8", "MS932",
|
||||
"Surrogate\ud801\udc01",
|
||||
"Surrogates \ud800\udc00 in comment")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipInputStream decodes entry names and comments
|
||||
* using the charset provided to its constructor, or that it decodes
|
||||
* using UTF-8 when the 'Language encoding flag' is set
|
||||
*
|
||||
* @param writeCharset the charset to use for ZipOutputStream when producing the ZIP
|
||||
* @param readCharset the charset to use when opening the ZipInputStream
|
||||
* @param name the entry name
|
||||
* @param comment the entry comment (not read by ZipInputStream)
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("charsetsAndNames")
|
||||
public void testZipInputStream(String writeCharset,
|
||||
String readCharset,
|
||||
String name,
|
||||
String comment) throws IOException {
|
||||
|
||||
byte[] zip = createZIP(writeCharset, name, comment);
|
||||
|
||||
try (InputStream in = new ByteArrayInputStream(zip);
|
||||
ZipInputStream zis = new ZipInputStream(in, Charset.forName(readCharset))) {
|
||||
ZipEntry e = zis.getNextEntry();
|
||||
assertNotNull(e);
|
||||
assertEquals(name, e.getName(),
|
||||
"ZipInputStream.getNextEntry() returned unexpected entry name");
|
||||
assertNull(e.getComment()); // No comment in the LOC header
|
||||
assertArrayEquals(ENTRY_DATA, zis.readAllBytes(), "Unexpected ZIP entry data");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile decodes entry names and comments
|
||||
* using the charset provided to its constructor, or that it decodes
|
||||
* using UTF-8 when the 'Language encoding flag' is set
|
||||
*
|
||||
* @param writeCharset the charset to use for ZipOutputStream when producing the ZIP
|
||||
* @param readCharset the charset to use when opening the ZipFile
|
||||
* @param name the name of the entry
|
||||
* @param comment the comment of the entry
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("charsetsAndNames")
|
||||
public void testZipFile(String writeCharset,
|
||||
String readCharset,
|
||||
String name,
|
||||
String comment) throws IOException {
|
||||
|
||||
byte[] zip = createZIP(writeCharset, name, comment);
|
||||
|
||||
Path f = Path.of("zfcoding.zip");
|
||||
Files.write(f, zip);
|
||||
|
||||
try (ZipFile zf = new ZipFile(f.toFile(), Charset.forName(readCharset))) {
|
||||
// Test using ZipFile.entries
|
||||
Enumeration<? extends ZipEntry> zes = zf.entries();
|
||||
ZipEntry e = (ZipEntry)zes.nextElement();
|
||||
assertNotNull(e);
|
||||
assertEquals(name, e.getName(), "ZipFile.entries() returned unexpected entry name");
|
||||
assertEquals(comment, e.getComment(), "ZipFile.entries() returned unexpected entry comment");
|
||||
|
||||
// Test using ZipFile.getEntry
|
||||
e = zf.getEntry(name);
|
||||
assertNotNull(e,
|
||||
String.format("Entry lookup failed on ZIP encoded with %s and opened with %s",
|
||||
writeCharset, readCharset));
|
||||
assertEquals(name, e.getName(), "ZipFile.getEntry() returned unexpected entry name");
|
||||
assertEquals(comment, e.getComment(), "ZipFile.getEntry() returned unexpected entry comment");
|
||||
try (InputStream is = zf.getInputStream(e)) {
|
||||
assertNotNull(is);
|
||||
assertArrayEquals(ENTRY_DATA, is.readAllBytes(), "Unexpected ZIP entry data");
|
||||
}
|
||||
}
|
||||
|
||||
Files.deleteIfExists(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ZIP file containing an entry with the given name
|
||||
* and comment, encoded using the given charset.
|
||||
* Note that if the charset is UTF-8, ZipOutputStream will
|
||||
* set the 'Language encoding flag' for the entry.
|
||||
*
|
||||
* @param charset the charset passed to the ZipOutputStream constructor
|
||||
* @param name the name of the entry to add
|
||||
* @param comment the comment of the entry to add
|
||||
* @return a byte array containing the ZIP file
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
private byte[] createZIP(String charset, String name, String comment) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos, Charset.forName(charset))) {
|
||||
ZipEntry e = new ZipEntry(name);
|
||||
e.setComment(comment);
|
||||
zos.putNextEntry(e);
|
||||
zos.write(ENTRY_DATA);
|
||||
zos.closeEntry();
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
40
test/jdk/java/util/zip/ZipEntry/Clone.java
Normal file
40
test/jdk/java/util/zip/ZipEntry/Clone.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 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.
|
||||
*
|
||||
* 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 4134526
|
||||
@summary Test if ZipEntry.clone() works when the extra field is null.
|
||||
*/
|
||||
|
||||
import java.util.zip.*;
|
||||
import java.io.*;
|
||||
|
||||
public class Clone {
|
||||
|
||||
public static void main(String argv[]) throws Exception {
|
||||
ZipFile zf = new ZipFile(new File(System.getProperty("test.src"),
|
||||
"input.jar"));
|
||||
ZipEntry e = new ZipEntry("foo");
|
||||
e.clone();
|
||||
}
|
||||
}
|
||||
39
test/jdk/java/util/zip/ZipEntry/Constructor.java
Normal file
39
test/jdk/java/util/zip/ZipEntry/Constructor.java
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 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.
|
||||
*
|
||||
* 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 4243169
|
||||
@summary Make sure ZipEntry static initializer will load the
|
||||
zip library.
|
||||
*/
|
||||
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.io.*;
|
||||
|
||||
public class Constructor {
|
||||
public static void main(String argv[]) throws Exception {
|
||||
ZipEntry e1 = new ZipEntry("foo");
|
||||
JarEntry e2 = new JarEntry("bar");
|
||||
}
|
||||
}
|
||||
174
test/jdk/java/util/zip/ZipEntry/MaxZipEntryFieldSizeTest.java
Normal file
174
test/jdk/java/util/zip/ZipEntry/MaxZipEntryFieldSizeTest.java
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*
|
||||
* 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 8340553
|
||||
* @summary Verify that ZipEntry(String), ZipEntry::setComment, and
|
||||
* ZipEntry::setExtra throws a IllegalArgumentException when the
|
||||
* combined length of the fields, including the size of the CEN Header,
|
||||
* exceeds 65,535 bytes
|
||||
* @run junit MaxZipEntryFieldSizeTest
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class MaxZipEntryFieldSizeTest {
|
||||
|
||||
// CEN header size + name length + comment length + extra length
|
||||
// should not exceed 65,535 bytes per the PKWare APP.NOTE
|
||||
// 4.4.10, 4.4.11, & 4.4.12.
|
||||
static final int MAX_COMBINED_CEN_HEADER_SIZE = 0xFFFF;
|
||||
// Maximum possible size of name length + comment length + extra length
|
||||
// for entries in order to not exceed 65,489 bytes
|
||||
static final int MAX_NAME_COMMENT_EXTRA_SIZE =
|
||||
MAX_COMBINED_CEN_HEADER_SIZE - ZipFile.CENHDR;
|
||||
// Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings'
|
||||
static final short UNKNOWN_ZIP_TAG = (short) 0x9902;
|
||||
// Zip Entry name used by tests
|
||||
static final String ENTRY_NAME = "EntryName";
|
||||
// Max length minus the size of the ENTRY_NAME or ENTRY_COMMENT
|
||||
static final int MAX_FIELD_LEN_MINUS_ENTRY_NAME =
|
||||
MAX_NAME_COMMENT_EXTRA_SIZE - 9;
|
||||
|
||||
/**
|
||||
* Validate an IllegalArgumentException is thrown when the
|
||||
* combined length of the entry name, entry comment, entry extra data,
|
||||
* and CEN Header size exceeds 65,535 bytes.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {30000, 35000})
|
||||
void combinedLengthTest(int length) {
|
||||
String comment = "a".repeat(length);
|
||||
byte[] bytes = creatExtraData(length);
|
||||
int combinedLength = ENTRY_NAME.length() + comment.length() + bytes.length;
|
||||
boolean expectException = combinedLength > MAX_COMBINED_CEN_HEADER_SIZE;
|
||||
System.out.printf("Combined Len= %s, exception: %s%n", combinedLength, expectException);
|
||||
ZipEntry zipEntry = new ZipEntry(ENTRY_NAME);
|
||||
zipEntry.setComment(comment);
|
||||
// The extra data length will trigger the IllegalArgumentException
|
||||
if (expectException) {
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
zipEntry.setExtra(bytes));
|
||||
} else {
|
||||
zipEntry.setExtra(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an IllegalArgumentException is thrown when the comment
|
||||
* length exceeds 65,489 bytes.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE,
|
||||
MAX_NAME_COMMENT_EXTRA_SIZE,
|
||||
MAX_NAME_COMMENT_EXTRA_SIZE + 1,
|
||||
MAX_FIELD_LEN_MINUS_ENTRY_NAME,
|
||||
MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1})
|
||||
void setCommentLengthTest(int length) {
|
||||
boolean expectException = length >= MAX_NAME_COMMENT_EXTRA_SIZE;
|
||||
ZipEntry zipEntry = new ZipEntry(ENTRY_NAME);
|
||||
String comment = "a".repeat(length);
|
||||
System.out.printf("Comment Len= %s, exception: %s%n", comment.length(), expectException);
|
||||
// The comment length will trigger the IllegalArgumentException
|
||||
if (expectException) {
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
zipEntry.setComment(comment));
|
||||
} else {
|
||||
zipEntry.setComment(comment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an IllegalArgumentException is thrown when the name
|
||||
* length exceeds 65,489 bytes.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE,
|
||||
MAX_NAME_COMMENT_EXTRA_SIZE,
|
||||
MAX_NAME_COMMENT_EXTRA_SIZE + 1,
|
||||
MAX_FIELD_LEN_MINUS_ENTRY_NAME,
|
||||
MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1})
|
||||
void nameLengthTest(int length) {
|
||||
boolean expectException = length > MAX_NAME_COMMENT_EXTRA_SIZE;
|
||||
String name = "a".repeat(length);
|
||||
System.out.printf("name Len= %s, exception: %s%n", name.length(), expectException);
|
||||
// The name length will trigger the IllegalArgumentException
|
||||
if (expectException) {
|
||||
assertThrows(IllegalArgumentException.class, () -> new ZipEntry(name));
|
||||
} else {
|
||||
new ZipEntry(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an IllegalArgumentException is thrown when the extra data
|
||||
* length exceeds 65,489 bytes.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE,
|
||||
MAX_NAME_COMMENT_EXTRA_SIZE,
|
||||
MAX_NAME_COMMENT_EXTRA_SIZE + 1,
|
||||
MAX_FIELD_LEN_MINUS_ENTRY_NAME,
|
||||
MAX_FIELD_LEN_MINUS_ENTRY_NAME - 1})
|
||||
void setExtraLengthTest(int length) {
|
||||
boolean expectException = length >= MAX_NAME_COMMENT_EXTRA_SIZE;
|
||||
byte[] bytes = creatExtraData(length);
|
||||
ZipEntry zipEntry = new ZipEntry(ENTRY_NAME);
|
||||
System.out.printf("extra Len= %s, exception: %s%n", bytes.length, expectException);
|
||||
// The extra data length will trigger the IllegalArgumentException
|
||||
if (expectException) {
|
||||
assertThrows(IllegalArgumentException.class, () -> zipEntry.setExtra(bytes));
|
||||
} else {
|
||||
zipEntry.setExtra(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the extra field data which will be passed to ZipEntry::setExtra
|
||||
* @param length size of the extra data
|
||||
* @return byte array containing the extra data
|
||||
*/
|
||||
private static byte[] creatExtraData(int length) {
|
||||
byte[] bytes = new byte[length];
|
||||
// Little-endian ByteBuffer for updating the header fields
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
// We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings'
|
||||
buffer.putShort(UNKNOWN_ZIP_TAG);
|
||||
// Size of the actual (empty) data
|
||||
buffer.putShort((short) (length - 2 * Short.BYTES));
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
BIN
test/jdk/java/util/zip/ZipEntry/input.jar
Normal file
BIN
test/jdk/java/util/zip/ZipEntry/input.jar
Normal file
Binary file not shown.
331
test/jdk/java/util/zip/ZipFile/Assortment.java
Normal file
331
test/jdk/java/util/zip/ZipFile/Assortment.java
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, 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.
|
||||
*
|
||||
* 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 4770745 6234507 6303183 8048990
|
||||
* @summary test a variety of zip file entries
|
||||
* @author Martin Buchholz
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.util.jar.*;
|
||||
import java.io.*;
|
||||
|
||||
public class Assortment {
|
||||
static int passed = 0, failed = 0;
|
||||
|
||||
static void fail(String msg) {
|
||||
failed++;
|
||||
new Exception(msg).printStackTrace();
|
||||
}
|
||||
|
||||
static void unexpected(Throwable t) {
|
||||
failed++;
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
static void check(boolean condition, String msg) {
|
||||
if (! condition)
|
||||
fail(msg);
|
||||
}
|
||||
|
||||
static void check(boolean condition) {
|
||||
check(condition, "Something's wrong");
|
||||
}
|
||||
|
||||
static final int get16(byte b[], int off) {
|
||||
return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
|
||||
}
|
||||
|
||||
// check if all "expected" extra fields equal to their
|
||||
// corresponding fields in "extra". The "extra" might have
|
||||
// timestamp fields added by ZOS.
|
||||
static boolean equalsExtraData(byte[] expected, byte[] extra) {
|
||||
if (expected == null)
|
||||
return true;
|
||||
int off = 0;
|
||||
int len = expected.length;
|
||||
while (off + 4 < len) {
|
||||
int tag = get16(expected, off);
|
||||
int sz = get16(expected, off + 2);
|
||||
int off0 = 0;
|
||||
int len0 = extra.length;
|
||||
boolean matched = false;
|
||||
while (off0 + 4 < len0) {
|
||||
int tag0 = get16(extra, off0);
|
||||
int sz0 = get16(extra, off0 + 2);
|
||||
if (tag == tag0 && sz == sz0) {
|
||||
matched = true;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
if (expected[off + i] != extra[off0 +i])
|
||||
matched = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
off0 += (4 + sz0);
|
||||
}
|
||||
if (!matched)
|
||||
return false;
|
||||
off += (4 + sz);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class Entry {
|
||||
private String name;
|
||||
private int method;
|
||||
private byte[] data;
|
||||
private byte[] extra;
|
||||
private String comment;
|
||||
|
||||
Entry(String name,
|
||||
int method,
|
||||
byte[] data,
|
||||
byte[] extra,
|
||||
String comment) {
|
||||
this.name = name;
|
||||
this.method = method;
|
||||
this.data = data;
|
||||
this.extra = extra;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
void write(ZipOutputStream s) throws Exception {
|
||||
ZipEntry e = new ZipEntry(name);
|
||||
CRC32 crc32 = new CRC32();
|
||||
e.setMethod(method);
|
||||
if (method == ZipEntry.STORED) {
|
||||
e.setSize(data == null ? 0 : data.length);
|
||||
crc32.reset();
|
||||
if (data != null) crc32.update(data);
|
||||
e.setCrc(crc32.getValue());
|
||||
} else {
|
||||
e.setSize(0);
|
||||
e.setCrc(0);
|
||||
}
|
||||
if (comment != null) e.setComment(comment);
|
||||
if (extra != null) e.setExtra(extra);
|
||||
s.putNextEntry(e);
|
||||
if (data != null) s.write(data);
|
||||
}
|
||||
|
||||
byte[] getData(ZipFile f, ZipEntry e) throws Exception {
|
||||
byte[] fdata = new byte[(int)e.getSize()];
|
||||
InputStream is = f.getInputStream(e);
|
||||
is.read(fdata);
|
||||
return fdata;
|
||||
}
|
||||
|
||||
void verify(ZipFile f, ZipEntry e) throws Exception {
|
||||
verify(e, getData(f, e));
|
||||
}
|
||||
|
||||
void verify(ZipEntry e, byte[] eData) throws Exception {
|
||||
byte[] data = (this.data == null) ? new byte[]{} : this.data;
|
||||
byte[] extra = (this.extra != null && this.extra.length == 0) ?
|
||||
null : this.extra;
|
||||
check(name.equals(e.getName()));
|
||||
check(method == e.getMethod());
|
||||
check((((comment == null) || comment.equals(""))
|
||||
&& (e.getComment() == null))
|
||||
|| comment.equals(e.getComment()));
|
||||
check(equalsExtraData(extra, e.getExtra()));
|
||||
check(Arrays.equals(data, eData));
|
||||
check(e.getSize() == data.length);
|
||||
check((method == ZipEntry.DEFLATED) ||
|
||||
(e.getCompressedSize() == data.length));
|
||||
}
|
||||
|
||||
void verify(ZipFile f) throws Exception {
|
||||
ZipEntry e = f.getEntry(name);
|
||||
verify(e, getData(f, e));
|
||||
}
|
||||
|
||||
void verifyZipInputStream(ZipInputStream s) throws Exception {
|
||||
ZipEntry e = s.getNextEntry();
|
||||
|
||||
byte[] data = (this.data == null) ? new byte[]{} : this.data;
|
||||
byte[] otherData = new byte[data.length];
|
||||
s.read(otherData);
|
||||
check(Arrays.equals(data, otherData));
|
||||
|
||||
byte[] extra = (this.extra != null && this.extra.length == 0) ?
|
||||
null : this.extra;
|
||||
check(equalsExtraData(extra, e.getExtra()));
|
||||
check(name.equals(e.getName()));
|
||||
check(method == e.getMethod());
|
||||
check(e.getSize() == -1 || e.getSize() == data.length);
|
||||
check((method == ZipEntry.DEFLATED) ||
|
||||
(e.getCompressedSize() == data.length));
|
||||
}
|
||||
|
||||
void verifyJarInputStream(JarInputStream s) throws Exception {
|
||||
// JarInputStream "automatically" reads the manifest
|
||||
if (name.equals("meta-iNf/ManIfEst.Mf"))
|
||||
return;
|
||||
|
||||
verifyZipInputStream(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static int uniquifier = 86;
|
||||
private static String uniquify(String name) {
|
||||
return name + (uniquifier++);
|
||||
}
|
||||
|
||||
private static byte[] toBytes(String s) throws Exception {
|
||||
return s.getBytes("UTF-8");
|
||||
}
|
||||
|
||||
private static byte[] toExtra(byte[] bytes) throws Exception {
|
||||
if (bytes == null) return null;
|
||||
// Construct a fake extra field with valid header length
|
||||
byte[] v = new byte[bytes.length + 4];
|
||||
v[0] = (byte) 0x47;
|
||||
v[1] = (byte) 0xff;
|
||||
v[2] = (byte) bytes.length;
|
||||
v[3] = (byte) (bytes.length << 8);
|
||||
System.arraycopy(bytes, 0, v, 4, bytes.length);
|
||||
return v;
|
||||
}
|
||||
|
||||
private static Random random = new Random();
|
||||
|
||||
private static String makeName(int length) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
sb.append((char)(random.nextInt(10000)+1));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
File zipName = new File("x.zip");
|
||||
int[] methods = {ZipEntry.STORED, ZipEntry.DEFLATED};
|
||||
String[] names = {makeName(1), makeName(160), makeName(9000)};
|
||||
byte[][] datas = {null, new byte[]{}, new byte[]{'d'}};
|
||||
byte[][] extras = {null, new byte[]{}, new byte[]{'e'}};
|
||||
String[] comments = {null, "", "c"};
|
||||
|
||||
List<Entry> entries = new ArrayList<Entry>();
|
||||
|
||||
// Highly unusual manifest
|
||||
entries.add(new Entry("meta-iNf/ManIfEst.Mf",
|
||||
ZipEntry.STORED,
|
||||
toBytes("maNiFest-VeRsIon: 1.0\n"),
|
||||
toExtra(toBytes("Can manifests have extra??")),
|
||||
"Can manifests have comments??"));
|
||||
|
||||
// The emptiest possible entry
|
||||
entries.add(new Entry("", ZipEntry.STORED, null, null, ""));
|
||||
|
||||
for (String name : names)
|
||||
for (int method : methods)
|
||||
for (byte[] data : datas) // datae??
|
||||
for (byte[] extra : extras)
|
||||
for (String comment : comments)
|
||||
entries.add(new Entry(uniquify(name), method, data,
|
||||
toExtra(extra), comment));
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Write zip file using ZipOutputStream
|
||||
//----------------------------------------------------------------
|
||||
try (FileOutputStream fos = new FileOutputStream(zipName);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos))
|
||||
{
|
||||
for (Entry e : entries)
|
||||
e.write(zos);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using ZipFile.getEntry()
|
||||
//----------------------------------------------------------------
|
||||
try (ZipFile f = new ZipFile(zipName)) {
|
||||
for (Entry e : entries)
|
||||
e.verify(f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using JarFile.getEntry()
|
||||
//----------------------------------------------------------------
|
||||
try (JarFile f = new JarFile(zipName)) {
|
||||
check(f.getManifest() != null);
|
||||
for (Entry e : entries)
|
||||
e.verify(f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using ZipFile.entries()
|
||||
//----------------------------------------------------------------
|
||||
try (ZipFile f = new ZipFile(zipName)) {
|
||||
Enumeration<? extends ZipEntry> en = f.entries();
|
||||
for (Entry e : entries)
|
||||
e.verify(f, en.nextElement());
|
||||
|
||||
check(!en.hasMoreElements());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using JarFile.entries()
|
||||
//----------------------------------------------------------------
|
||||
try (JarFile f = new JarFile(zipName)) {
|
||||
Enumeration<? extends ZipEntry> en = f.entries();
|
||||
for (Entry e : entries)
|
||||
e.verify(f, en.nextElement());
|
||||
|
||||
check(!en.hasMoreElements());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using ZipInputStream class
|
||||
//----------------------------------------------------------------
|
||||
try (FileInputStream fis = new FileInputStream(zipName);
|
||||
ZipInputStream s = new ZipInputStream(fis)) {
|
||||
|
||||
for (Entry e : entries)
|
||||
e.verifyZipInputStream(s);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using JarInputStream class
|
||||
//----------------------------------------------------------------
|
||||
try (FileInputStream fis = new FileInputStream(zipName);
|
||||
JarInputStream s = new JarInputStream(fis)) {
|
||||
|
||||
// JarInputStream "automatically" reads the manifest
|
||||
check(s.getManifest() != null);
|
||||
|
||||
for (Entry e : entries)
|
||||
e.verifyJarInputStream(s);
|
||||
}
|
||||
|
||||
// String cmd = "unzip -t " + zipName.getPath() + " >/dev/tty";
|
||||
// new ProcessBuilder(new String[]{"/bin/sh", "-c", cmd}).start().waitFor();
|
||||
|
||||
zipName.deleteOnExit();
|
||||
|
||||
System.out.printf("passed = %d, failed = %d%n", passed, failed);
|
||||
if (failed > 0) throw new Exception("Some tests failed");
|
||||
}
|
||||
}
|
||||
246
test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java
Normal file
246
test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2024, 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.
|
||||
*
|
||||
* 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 8341595
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @summary Verify that ZipFile can read from a ZIP file with a maximally large CEN size
|
||||
* @run junit/othervm/manual -Xmx2500M CenSizeMaximum
|
||||
*/
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CenSizeMaximum {
|
||||
|
||||
// Maximum allowed CEN size allowed by the ZipFile implementation
|
||||
static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH;
|
||||
|
||||
/**
|
||||
* From the APPNOTE.txt specification:
|
||||
* 4.4.10 file name length: (2 bytes)
|
||||
* 4.4.11 extra field length: (2 bytes)
|
||||
* 4.4.12 file comment length: (2 bytes)
|
||||
*
|
||||
* The length of the file name, extra field, and comment
|
||||
* fields respectively. The combined length of any
|
||||
* directory record and these three fields SHOULD NOT
|
||||
* generally exceed 65,535 bytes.
|
||||
*.
|
||||
* Create a maximum extra field which does not exceed 65,535 bytes
|
||||
*/
|
||||
static final int MAX_EXTRA_FIELD_SIZE = 65_535 - ZipFile.CENHDR;
|
||||
|
||||
// Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings'
|
||||
static final short UNKNOWN_ZIP_TAG = (short) 0x9902;
|
||||
|
||||
// The size of one CEN header, including the name and the extra field
|
||||
static final int CEN_HEADER_SIZE = ZipFile.CENHDR + MAX_EXTRA_FIELD_SIZE;
|
||||
|
||||
// The size of the extra data field header (tag id + data block length)
|
||||
static final int EXTRA_FIELD_HEADER_SIZE = 2 * Short.BYTES;
|
||||
|
||||
// Zip file to create for testing
|
||||
private Path hugeZipFile = Path.of("cen-size-on-limit.zip");
|
||||
|
||||
/**
|
||||
* Clean up ZIP file created in this test
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
//Files.deleteIfExists(hugeZipFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that ZipFile opens a ZIP file with a CEN size close
|
||||
* to the {@link #MAX_CEN_SIZE} implementation limit.
|
||||
*
|
||||
* @throws IOException if an unexpected IO error occurs
|
||||
*/
|
||||
@Test
|
||||
public void maximumCenSize() throws IOException {
|
||||
int numCenHeaders = zipWithWithExactCenSize(MAX_CEN_SIZE, true, false);
|
||||
try (var zf = new ZipFile(hugeZipFile.toFile())) {
|
||||
assertEquals(numCenHeaders, zf.size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that ZipFile rejects a ZIP where the last CEN record
|
||||
* overflows the CEN size and the END header CENTOT field is smaller
|
||||
* than the actual number of headers
|
||||
*
|
||||
* @throws IOException if an unexpected IO error occurs
|
||||
*/
|
||||
@Test
|
||||
public void lastCENHeaderBadSize() throws IOException {
|
||||
int numCenHeaders = zipWithWithExactCenSize(1024, true, true);
|
||||
ZipException zipException = assertThrows(ZipException.class, () -> {
|
||||
try (var zf = new ZipFile(hugeZipFile.toFile())) {
|
||||
assertEquals(numCenHeaders, zf.size());
|
||||
}
|
||||
});
|
||||
assertEquals("invalid CEN header (bad header size)", zipException.getMessage());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a ZIP file with an exact CEN size. To minimize the number of CEN headers
|
||||
* written, maximally large, empty extra data blocks are written sparsely.
|
||||
*
|
||||
* @param cenSize the exact CEN size of the ZIP file to produce
|
||||
* @param invalidateEndTotal whether to decrement the END header's TOT field by one
|
||||
* @return the number of CEN headers produced
|
||||
* @throws IOException if an unexpected IO error occurs
|
||||
*/
|
||||
private int zipWithWithExactCenSize(long cenSize, boolean invalidateEndTotal, boolean overflowLastCEN)
|
||||
throws IOException {
|
||||
// Sanity check
|
||||
assertTrue(cenSize <= MAX_CEN_SIZE);
|
||||
|
||||
// The number of CEN headers we need to write
|
||||
int numCenHeaders = (int) (cenSize / CEN_HEADER_SIZE) + 1;
|
||||
// Size if all extra data fields were of maximum size
|
||||
long overSized = numCenHeaders * (long) CEN_HEADER_SIZE;
|
||||
// Length to trim from the first CEN's extra data
|
||||
int negativPadding = (int) (overSized - cenSize);
|
||||
int firstExtraSize = MAX_EXTRA_FIELD_SIZE - negativPadding;
|
||||
|
||||
// Sanity check
|
||||
long computedCenSize = (numCenHeaders -1L ) * CEN_HEADER_SIZE + ZipEntry.CENHDR + firstExtraSize;
|
||||
assertEquals(computedCenSize, cenSize);
|
||||
|
||||
// A CEN header, followed by the four-bytes extra data header
|
||||
ByteBuffer cenHeader = createCENHeader();
|
||||
// An END header
|
||||
ByteBuffer endHeader = createENDHeader();
|
||||
// Update the END header
|
||||
if (invalidateEndTotal) {
|
||||
// To trigger countCENHeaders
|
||||
endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders -1 & 0xFFFF));
|
||||
} else {
|
||||
endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders & 0xFFFF));
|
||||
}
|
||||
// Update CEN size and offset fields
|
||||
endHeader.putInt(ZipEntry.ENDSIZ, (int) (cenSize & 0xFFFFFFFFL));
|
||||
endHeader.putInt(ZipEntry.ENDOFF, 0);
|
||||
|
||||
// When creating a sparse file, the file must not already exit
|
||||
Files.deleteIfExists(hugeZipFile);
|
||||
|
||||
// Open a FileChannel for writing a sparse file
|
||||
EnumSet<StandardOpenOption> options = EnumSet.of(StandardOpenOption.CREATE_NEW,
|
||||
StandardOpenOption.WRITE,
|
||||
StandardOpenOption.SPARSE);
|
||||
|
||||
try (FileChannel channel = FileChannel.open(hugeZipFile, options)) {
|
||||
// Write CEN headers
|
||||
for (int i = 0; i < numCenHeaders; i++) {
|
||||
// The first CEN header has trimmed extra data
|
||||
int extraSize = i == 0 ? firstExtraSize : MAX_EXTRA_FIELD_SIZE;
|
||||
if (overflowLastCEN && i == numCenHeaders - 1) {
|
||||
// make last CEN header overflow the CEN size
|
||||
cenHeader.putShort(ZipEntry.CENNAM, Short.MAX_VALUE);
|
||||
}
|
||||
// update elen field
|
||||
cenHeader.putShort(ZipEntry.CENEXT, (short) (extraSize & 0xFFFF));
|
||||
// update data block len of the extra field header
|
||||
short dlen = (short) ((extraSize - EXTRA_FIELD_HEADER_SIZE) & 0xFFFF);
|
||||
cenHeader.putShort(ZipEntry.CENHDR + Short.BYTES, dlen);
|
||||
// Write the CEN header plus the four-byte extra header
|
||||
channel.write(cenHeader.rewind());
|
||||
// Sparse "write" of the extra data block
|
||||
channel.position(channel.position() + extraSize - EXTRA_FIELD_HEADER_SIZE);
|
||||
}
|
||||
// Sanity check
|
||||
assertEquals(cenSize, channel.position());
|
||||
// Write the END header
|
||||
channel.write(endHeader.rewind());
|
||||
}
|
||||
return numCenHeaders;
|
||||
}
|
||||
|
||||
// Creates a ByteBuffer representing a CEN header with a trailing extra field header
|
||||
private ByteBuffer createCENHeader() throws IOException {
|
||||
byte[] bytes = smallZipfile();
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
int endOff = bytes.length - ZipEntry.ENDHDR;
|
||||
int cenSize = buf.getInt(endOff + ZipEntry.ENDSIZ);
|
||||
int cenOff = buf.getInt(endOff + ZipEntry.ENDOFF);
|
||||
return ByteBuffer.wrap(
|
||||
Arrays.copyOfRange(bytes, cenOff, cenOff + ZipEntry.CENHDR + EXTRA_FIELD_HEADER_SIZE)
|
||||
).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
// Creates a ByteBuffer representing an END header
|
||||
private ByteBuffer createENDHeader() throws IOException {
|
||||
byte[] bytes = smallZipfile();
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
int endOff = bytes.length - ZipEntry.ENDHDR;
|
||||
return ByteBuffer.wrap(
|
||||
Arrays.copyOfRange(bytes, endOff, endOff + ZipEntry.ENDHDR)
|
||||
).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
// Create a byte array with a minimal ZIP file
|
||||
private static byte[] smallZipfile() throws IOException {
|
||||
var out = new ByteArrayOutputStream();
|
||||
try (var zo = new ZipOutputStream(out)) {
|
||||
ZipEntry entry = new ZipEntry("");
|
||||
entry.setExtra(makeDummyExtraField());
|
||||
zo.putNextEntry(entry);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
// Create a minimally sized extra field
|
||||
private static byte[] makeDummyExtraField() {
|
||||
byte[] extra = new byte[EXTRA_FIELD_HEADER_SIZE];
|
||||
// Little-endian ByteBuffer for updating the header fields
|
||||
ByteBuffer buffer = ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings'
|
||||
buffer.putShort(UNKNOWN_ZIP_TAG);
|
||||
|
||||
// Size of the actual (empty) data
|
||||
buffer.putShort((short) 0);
|
||||
return extra;
|
||||
}
|
||||
}
|
||||
221
test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java
Normal file
221
test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2024, 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.
|
||||
*
|
||||
* 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 8272746
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @summary Verify that ZipFile rejects a ZIP with a CEN size which does not fit in a Java byte array
|
||||
* @run junit CenSizeTooLarge
|
||||
*/
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class CenSizeTooLarge {
|
||||
|
||||
// Entry names produced in this test are fixed-length
|
||||
public static final int NAME_LENGTH = 10;
|
||||
|
||||
// Maximum allowed CEN size allowed by the ZipFile implementation
|
||||
static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH;
|
||||
|
||||
/**
|
||||
* From the APPNOTE.txt specification:
|
||||
* 4.4.10 file name length: (2 bytes)
|
||||
* 4.4.11 extra field length: (2 bytes)
|
||||
* 4.4.12 file comment length: (2 bytes)
|
||||
*
|
||||
* The length of the file name, extra field, and comment
|
||||
* fields respectively. The combined length of any
|
||||
* directory record and these three fields SHOULD NOT
|
||||
* generally exceed 65,535 bytes.
|
||||
*.
|
||||
* Create a maximum extra field which does not exceed 65,535 bytes
|
||||
*/
|
||||
static final int MAX_EXTRA_FIELD_SIZE = 65_535 - ZipFile.CENHDR - NAME_LENGTH;
|
||||
|
||||
// Data size (unsigned short)
|
||||
// Field size minus the leading header 'tag' and 'data size' fields (2 bytes each)
|
||||
static final short MAX_DATA_SIZE = (short) (MAX_EXTRA_FIELD_SIZE - 2 * Short.BYTES);
|
||||
|
||||
// Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings'
|
||||
static final short UNKNOWN_ZIP_TAG = (short) 0x9902;
|
||||
|
||||
// Use a shared LocalDateTime on all entries to save processing time
|
||||
static final LocalDateTime TIME_LOCAL = LocalDateTime.now();
|
||||
|
||||
// The size of one CEN header, including the name and the extra field
|
||||
static final int CEN_HEADER_SIZE = ZipFile.CENHDR + NAME_LENGTH + MAX_EXTRA_FIELD_SIZE;
|
||||
|
||||
// The number of entries needed to exceed the MAX_CEN_SIZE
|
||||
static final int NUM_ENTRIES = (MAX_CEN_SIZE / CEN_HEADER_SIZE) + 1;
|
||||
|
||||
// Expected ZipException message when the CEN does not fit in a Java byte array
|
||||
private static final String CEN_TOO_LARGE_MESSAGE = "invalid END header (central directory size too large)";
|
||||
|
||||
// Zip file to create for testing
|
||||
private File hugeZipFile;
|
||||
|
||||
private static final byte[] EXTRA_BYTES = makeLargeExtraField();
|
||||
// Helps SparseOutputStream detect write of the last CEN entry
|
||||
private static final byte[] LAST_EXTRA_BYTES = makeLargeExtraField();
|
||||
|
||||
/**
|
||||
* Create a zip file with a CEN size which does not fit within a Java byte array
|
||||
*/
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
hugeZipFile = new File("cen-too-large.zip");
|
||||
hugeZipFile.deleteOnExit();
|
||||
|
||||
try (OutputStream out = new SparseOutputStream(new FileOutputStream(hugeZipFile));
|
||||
ZipOutputStream zip = new ZipOutputStream(out)) {
|
||||
|
||||
// Keep track of entries so we can update extra data before the CEN is written
|
||||
ZipEntry[] entries = new ZipEntry[NUM_ENTRIES];
|
||||
|
||||
// Add entries until MAX_CEN_SIZE is reached
|
||||
for (int i = 0; i < NUM_ENTRIES; i++) {
|
||||
// Create a fixed-length name for the entry
|
||||
String name = Integer.toString(i);
|
||||
name = "0".repeat(NAME_LENGTH - name.length()) + name;
|
||||
|
||||
// Create and track the entry
|
||||
ZipEntry entry = entries[i] = new ZipEntry(name);
|
||||
|
||||
// Use STORED for faster processing
|
||||
entry.setMethod(ZipEntry.STORED);
|
||||
entry.setSize(0);
|
||||
entry.setCrc(0);
|
||||
|
||||
// Set the time/date field for faster processing
|
||||
entry.setTimeLocal(TIME_LOCAL);
|
||||
|
||||
// Add the entry
|
||||
zip.putNextEntry(entry);
|
||||
}
|
||||
// Finish writing the last entry
|
||||
zip.closeEntry();
|
||||
|
||||
// Before the CEN headers are written, set the extra data on each entry
|
||||
for (ZipEntry entry : entries) {
|
||||
entry.setExtra(EXTRA_BYTES);
|
||||
}
|
||||
// Help SparseOutputSream detect the last entry
|
||||
entries[entries.length-1].setExtra(LAST_EXTRA_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a ZipException is thrown with the expected message when
|
||||
* the ZipFile is initialized with a ZIP whose CEN exeeds {@link #MAX_CEN_SIZE}
|
||||
*/
|
||||
@Test
|
||||
public void centralDirectoryTooLargeToFitInByteArray() {
|
||||
ZipException ex = assertThrows(ZipException.class, () -> new ZipFile(hugeZipFile));
|
||||
assertEquals(CEN_TOO_LARGE_MESSAGE, ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* We can reduce the number of written CEN headers by making each CEN header maximally large.
|
||||
* We do this by adding the extra field produced by this method to each CEN header.
|
||||
* <p>
|
||||
* The structure of an extra field is as follows:
|
||||
* <p>
|
||||
* Header ID (Two bytes, describes the type of the field, also called 'tag')
|
||||
* Data Size (Two byte short)
|
||||
* Data Block (Contents depend on field type)
|
||||
*/
|
||||
private static byte[] makeLargeExtraField() {
|
||||
// Make a maximally sized extra field
|
||||
byte[] extra = new byte[MAX_EXTRA_FIELD_SIZE];
|
||||
// Little-endian ByteBuffer for updating the header fields
|
||||
ByteBuffer buffer = ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings'
|
||||
buffer.putShort(UNKNOWN_ZIP_TAG);
|
||||
|
||||
// Size of the actual (empty) data
|
||||
buffer.putShort(MAX_DATA_SIZE);
|
||||
return extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* By writing sparse 'holes' until the last CEN is detected, we can save disk space
|
||||
* used by this test from ~2GB to ~4K. Instances of this class should be passed
|
||||
* directly to the ZipOutputStream constructor, without any buffering. Otherwise,
|
||||
* writes from ZipOutputStream may not be detected correctly.
|
||||
*/
|
||||
private static class SparseOutputStream extends FilterOutputStream {
|
||||
private final FileChannel channel;
|
||||
private boolean sparse = true; // True until the last CEN is written
|
||||
private long position = 0;
|
||||
|
||||
public SparseOutputStream(FileOutputStream fos) {
|
||||
super(fos);
|
||||
this.channel = fos.getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
position += len;
|
||||
if (sparse) {
|
||||
// Until finding the last CEN, we don't actually write anything,
|
||||
// but instead simply advance the position, creating a sparse file
|
||||
channel.position(position);
|
||||
// Check for last CEN record
|
||||
if (b == LAST_EXTRA_BYTES) {
|
||||
// From here on, write actual bytes
|
||||
sparse = false;
|
||||
}
|
||||
} else {
|
||||
// Regular write
|
||||
out.write(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
position++;
|
||||
if (sparse) {
|
||||
channel.position(position);
|
||||
} else {
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 2011 IBM Corporation
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7031076
|
||||
* @summary Allow stale InputStreams from ZipFiles to be GC'd
|
||||
* @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
|
||||
* @key randomness
|
||||
*/
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class ClearStaleZipFileInputStreams {
|
||||
private static final int ZIP_ENTRY_NUM = 5;
|
||||
|
||||
private static final byte[][] data;
|
||||
|
||||
static {
|
||||
data = new byte[ZIP_ENTRY_NUM][];
|
||||
Random r = new Random();
|
||||
for (int i = 0; i < ZIP_ENTRY_NUM; i++) {
|
||||
data[i] = new byte[1000];
|
||||
r.nextBytes(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static File createTestFile(int compression) throws Exception {
|
||||
File tempZipFile =
|
||||
File.createTempFile("test-data" + compression, ".zip");
|
||||
tempZipFile.deleteOnExit();
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(tempZipFile);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos)) {
|
||||
zos.setLevel(compression);
|
||||
for (int i = 0; i < ZIP_ENTRY_NUM; i++) {
|
||||
String text = "Entry" + i;
|
||||
ZipEntry entry = new ZipEntry(text);
|
||||
zos.putNextEntry(entry);
|
||||
try {
|
||||
zos.write(data[i], 0, data[i].length);
|
||||
} finally {
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tempZipFile;
|
||||
}
|
||||
|
||||
private static final class GcInducingThread extends Thread {
|
||||
private final int sleepMillis;
|
||||
private boolean keepRunning = true;
|
||||
|
||||
public GcInducingThread(final int sleepMillis) {
|
||||
this.sleepMillis = sleepMillis;
|
||||
}
|
||||
|
||||
public synchronized void run() {
|
||||
while (keepRunning) {
|
||||
System.gc();
|
||||
try {
|
||||
wait(sleepMillis);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("GCing thread unexpectedly interrupted");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void shutDown() {
|
||||
keepRunning = false;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
GcInducingThread gcThread = new GcInducingThread(500);
|
||||
gcThread.start();
|
||||
try {
|
||||
runTest(ZipOutputStream.DEFLATED);
|
||||
runTest(ZipOutputStream.STORED);
|
||||
} finally {
|
||||
gcThread.shutDown();
|
||||
gcThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTest(int compression) throws Exception {
|
||||
ReferenceQueue<InputStream> rq = new ReferenceQueue<>();
|
||||
|
||||
System.out.println("Testing with a zip file with compression level = "
|
||||
+ compression);
|
||||
File f = createTestFile(compression);
|
||||
try (ZipFile zf = new ZipFile(f)) {
|
||||
Set<Object> refSet = createTransientInputStreams(zf, rq);
|
||||
|
||||
System.out.println("Waiting for 'stale' input streams from ZipFile to be GC'd ...");
|
||||
System.out.println("(The test will hang on failure)");
|
||||
while (false == refSet.isEmpty()) {
|
||||
refSet.remove(rq.remove());
|
||||
}
|
||||
System.out.println("Test PASSED.");
|
||||
System.out.println();
|
||||
} finally {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<Object> createTransientInputStreams(ZipFile zf,
|
||||
ReferenceQueue<InputStream> rq) throws Exception {
|
||||
Enumeration<? extends ZipEntry> zfe = zf.entries();
|
||||
Set<Object> refSet = new HashSet<>();
|
||||
|
||||
while (zfe.hasMoreElements()) {
|
||||
InputStream is = zf.getInputStream(zfe.nextElement());
|
||||
refSet.add(new WeakReference<InputStream>(is, rq));
|
||||
}
|
||||
|
||||
return refSet;
|
||||
}
|
||||
}
|
||||
113
test/jdk/java/util/zip/ZipFile/Comment.java
Normal file
113
test/jdk/java/util/zip/ZipFile/Comment.java
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2011, 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.
|
||||
*
|
||||
* 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 4334846
|
||||
@summary Make sure zip file comments of various sizes can be written.
|
||||
@author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class Comment {
|
||||
private static final String entryName = "entryName";
|
||||
private static final String entryContents = "entryContents";
|
||||
private static final int commentMaxLength = 0xFFFF;
|
||||
private static final int [] commentLengths
|
||||
= { 0, 1, 32768, commentMaxLength - 1, commentMaxLength };
|
||||
|
||||
public static void main(String argv[])
|
||||
throws Exception
|
||||
{
|
||||
for (int i = 0; i < commentLengths.length; ++i) {
|
||||
int commentLength = commentLengths[i];
|
||||
String comment = buildComment(commentLength);
|
||||
String name = "Test" + commentLength + ".zip";
|
||||
writeZipFile(name, comment);
|
||||
verifyZipFile(name, comment);
|
||||
new File(name).delete();
|
||||
System.out.println(commentLength + ": successful");
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeZipFile(String name, String comment)
|
||||
throws IOException
|
||||
{
|
||||
try (FileOutputStream fos = new FileOutputStream(name);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos))
|
||||
{
|
||||
zos.setComment(comment);
|
||||
ZipEntry ze = new ZipEntry(entryName);
|
||||
ze.setMethod(ZipEntry.DEFLATED);
|
||||
zos.putNextEntry(ze);
|
||||
new DataOutputStream(zos).writeUTF(entryContents);
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyZipFile(String name, String comment)
|
||||
throws Exception
|
||||
{
|
||||
// Check that Zip entry was correctly written.
|
||||
try (ZipFile zipFile = new ZipFile(name)) {
|
||||
ZipEntry zipEntry = zipFile.getEntry(entryName);
|
||||
InputStream is = zipFile.getInputStream(zipEntry);
|
||||
String result = new DataInputStream(is).readUTF();
|
||||
if (!result.equals(entryContents))
|
||||
throw new Exception("Entry contents corrupted");
|
||||
}
|
||||
|
||||
try (RandomAccessFile file = new RandomAccessFile(name, "r")) {
|
||||
// Check that comment length was correctly written.
|
||||
file.seek(file.length() - comment.length()
|
||||
- ZipFile.ENDHDR + ZipFile.ENDCOM);
|
||||
int b1 = file.readUnsignedByte();
|
||||
int b2 = file.readUnsignedByte();
|
||||
if (b1 + (b2 << 8) != comment.length())
|
||||
throw new Exception("Zip file comment length corrupted");
|
||||
|
||||
// Check that comment was correctly written.
|
||||
file.seek(file.length() - comment.length());
|
||||
byte [] bytes = new byte [comment.length()];
|
||||
file.readFully(bytes);
|
||||
if (! comment.equals(new String(bytes, "UTF8")))
|
||||
throw new Exception("Zip file comment corrupted");
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildComment(int length) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
while (result.length() < length) {
|
||||
/* Endhdr is 22 bytes long, so this pattern makes it easy
|
||||
* to see if it is copied correctly */
|
||||
result.append("abcdefghijklmnopqrstuvABCDEFGHIJKLMNOPQRSTUV");
|
||||
}
|
||||
String string = result.toString();
|
||||
string = string.substring(string.length() - length);
|
||||
return string;
|
||||
}
|
||||
}
|
||||
61
test/jdk/java/util/zip/ZipFile/Constructor.java
Normal file
61
test/jdk/java/util/zip/ZipFile/Constructor.java
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 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.
|
||||
*
|
||||
* 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 4842702
|
||||
* @summary Check that constructors throw specified exceptions
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.util.zip.ZipFile;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Constructor {
|
||||
private static void Unreached (Object o)
|
||||
throws Exception
|
||||
{
|
||||
// Should never get here
|
||||
throw new Exception ("Expected exception was not thrown");
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
try { Unreached (new ZipFile ((File) null, ZipFile.OPEN_READ)); }
|
||||
catch (NullPointerException e) {}
|
||||
|
||||
try { Unreached (new ZipFile ((File) null)); }
|
||||
catch (NullPointerException e) {}
|
||||
|
||||
try { Unreached (new ZipFile ((String) null)); }
|
||||
catch (NullPointerException e) {}
|
||||
|
||||
try { Unreached (new ZipFile ("NoSuchZip.zip")); }
|
||||
catch (IOException e) {}
|
||||
|
||||
try { Unreached (new ZipFile (new File ("NoSuchZip.zip"))); }
|
||||
catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
332
test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java
Normal file
332
test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2023, 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.
|
||||
*
|
||||
* 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 4770745 6218846 6218848 6237956 8313765 8316141
|
||||
* @summary test for correct detection and reporting of corrupted zip files
|
||||
* @author Martin Buchholz
|
||||
* @run junit CorruptedZipFiles
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static java.util.zip.ZipFile.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CorruptedZipFiles {
|
||||
|
||||
/*
|
||||
* Byte array holding a valid template ZIP.
|
||||
*
|
||||
* The 'good' ZIP file has the following structure:
|
||||
*
|
||||
* 0000 LOCAL HEADER #1 04034B50
|
||||
* 0004 Extract Zip Spec 14 '2.0'
|
||||
* 0005 Extract OS 00 'MS-DOS'
|
||||
* 0006 General Purpose Flag 0808
|
||||
* [Bits 1-2] 0 'Normal Compression'
|
||||
* [Bit 3] 1 'Streamed'
|
||||
* [Bit 11] 1 'Language Encoding'
|
||||
* 0008 Compression Method 0008 'Deflated'
|
||||
* 000A Last Mod Time 567F7D07 'Fri Mar 31 15:40:14 2023'
|
||||
* 000E CRC 00000000
|
||||
* 0012 Compressed Length 00000000
|
||||
* 0016 Uncompressed Length 00000000
|
||||
* 001A Filename Length 0001
|
||||
* 001C Extra Length 0000
|
||||
* 001E Filename 'x'
|
||||
* 001F PAYLOAD ...
|
||||
*
|
||||
* 0022 STREAMING DATA HEADER 08074B50
|
||||
* 0026 CRC 8CDC1683
|
||||
* 002A Compressed Length 00000003
|
||||
* 002E Uncompressed Length 00000001
|
||||
*
|
||||
* 0032 CENTRAL HEADER #1 02014B50
|
||||
* 0036 Created Zip Spec 14 '2.0'
|
||||
* 0037 Created OS 00 'MS-DOS'
|
||||
* 0038 Extract Zip Spec 14 '2.0'
|
||||
* 0039 Extract OS 00 'MS-DOS'
|
||||
* 003A General Purpose Flag 0808
|
||||
* [Bits 1-2] 0 'Normal Compression'
|
||||
* [Bit 3] 1 'Streamed'
|
||||
* [Bit 11] 1 'Language Encoding'
|
||||
* 003C Compression Method 0008 'Deflated'
|
||||
* 003E Last Mod Time 567F7D07 'Fri Mar 31 15:40:14 2023'
|
||||
* 0042 CRC 8CDC1683
|
||||
* 0046 Compressed Length 00000003
|
||||
* 004A Uncompressed Length 00000001
|
||||
* 004E Filename Length 0001
|
||||
* 0050 Extra Length 0000
|
||||
* 0052 Comment Length 0000
|
||||
* 0054 Disk Start 0000
|
||||
* 0056 Int File Attributes 0000
|
||||
* [Bit 0] 0 'Binary Data'
|
||||
* 0058 Ext File Attributes 00000000
|
||||
* 005C Local Header Offset 00000000
|
||||
* 0060 Filename 'x'
|
||||
*
|
||||
* 0061 END CENTRAL HEADER 06054B50
|
||||
* 0065 Number of this disk 0000
|
||||
* 0067 Central Dir Disk no 0000
|
||||
* 0069 Entries in this disk 0001
|
||||
* 006B Total Entries 0001
|
||||
* 006D Size of Central Dir 0000002F
|
||||
* 0071 Offset to Central Dir 00000032
|
||||
* 0075 Comment Length 0000
|
||||
*
|
||||
*/
|
||||
private static byte[] template;
|
||||
|
||||
// Copy of the template ZIP for modification by each test
|
||||
private byte[] copy;
|
||||
|
||||
// Litte-endian ByteBuffer for manipulating the ZIP copy
|
||||
private ByteBuffer buffer;
|
||||
|
||||
// Some well-known locations in the ZIP
|
||||
private static int endpos, cenpos, locpos;
|
||||
|
||||
// The path used when reading/writing the corrupted ZIP to disk
|
||||
private Path zip = Path.of("corrupted.zip");
|
||||
|
||||
/*
|
||||
* Make a sample ZIP and calculate some known offsets into this ZIP
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
// Make a ZIP with a single entry
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(out)) {
|
||||
ZipEntry e = new ZipEntry("x");
|
||||
zos.putNextEntry(e);
|
||||
zos.write((int)'x');
|
||||
}
|
||||
template = out.toByteArray();
|
||||
// ByteBuffer for reading fields from the ZIP
|
||||
ByteBuffer buffer = ByteBuffer.wrap(template).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// Calculate the offset of the End of central directory record
|
||||
endpos = template.length - ENDHDR;
|
||||
// Look up the offet of the Central directory header
|
||||
cenpos = buffer.getShort(endpos + ENDOFF);
|
||||
// Look up the offset of the corresponding Local file header
|
||||
locpos = buffer.getShort(cenpos + CENOFF);
|
||||
|
||||
// Run some sanity checks on the valid ZIP:
|
||||
assertEquals(ENDSIG, buffer.getInt(endpos),"Where's ENDSIG?");
|
||||
assertEquals(CENSIG, buffer.getInt(cenpos),"Where's CENSIG?");
|
||||
assertEquals(LOCSIG, buffer.getInt(locpos),"Where's LOCSIG?");
|
||||
assertEquals(buffer.getShort(cenpos+CENNAM),
|
||||
buffer.getShort(locpos+LOCNAM),
|
||||
"Name field length mismatch");
|
||||
assertEquals(buffer.getShort(cenpos+CENEXT),
|
||||
buffer.getShort( locpos+LOCEXT),
|
||||
"Extra field length mismatch");
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a copy safe to modify by each test
|
||||
*/
|
||||
@BeforeEach
|
||||
public void makeCopy() {
|
||||
copy = template.clone();
|
||||
buffer = ByteBuffer.wrap(copy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete the ZIP file produced after each test method
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when the 'End of Central Directory'
|
||||
* (END) header has a CEN size exceeding past the offset of the END record
|
||||
*/
|
||||
@Test
|
||||
public void excessiveCENSize() throws IOException {
|
||||
buffer.putInt(endpos+ENDSIZ, 0xff000000);
|
||||
assertZipException(".*bad central directory size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when the 'End of Central Directory'
|
||||
* (END) header has a CEN offset with an invalid value.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveCENOffset() throws IOException {
|
||||
buffer.putInt(endpos+ENDOFF, 0xff000000);
|
||||
assertZipException(".*bad central directory offset.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has an unexpected signature
|
||||
*/
|
||||
@Test
|
||||
public void invalidCENSignature() throws IOException {
|
||||
int existingSignature = buffer.getInt(cenpos);
|
||||
buffer.putInt(cenpos, existingSignature +1);
|
||||
assertZipException(".*bad signature.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has the
|
||||
* 'general purpose bit flag 0' ('encrypted') set.
|
||||
*/
|
||||
@Test
|
||||
public void encryptedEntry() throws IOException {
|
||||
copy[cenpos+CENFLG] |= 1;
|
||||
assertZipException(".*encrypted entry.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has a file name
|
||||
* length which makes the CEN header overflow into the
|
||||
* 'End of central directory' record.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveFileNameLength() throws IOException {
|
||||
short existingNameLength = buffer.getShort(cenpos + CENNAM);
|
||||
buffer.putShort(cenpos+CENNAM, (short) (existingNameLength + 1));
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has a
|
||||
* file name length which makes the CEN header overflow into the
|
||||
* 'End of central directory' record.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveFileNameLength2() throws IOException {
|
||||
buffer.putShort(cenpos + CENNAM, (short) 0xfdfd);
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown if the last CEN header is not immediately
|
||||
* followed by the start of the 'End of central directory' record
|
||||
*/
|
||||
@Test
|
||||
public void insufficientFilenameLength() throws IOException {
|
||||
short existingNameLength = buffer.getShort(cenpos + CENNAM);
|
||||
buffer.putShort(cenpos+CENNAM, (short) (existingNameLength - 1));
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown if a CEN header has an
|
||||
* extra field length which makes the CEN header overflow into the
|
||||
* End of central directory record.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveExtraFieldLength() throws IOException {
|
||||
buffer.put(cenpos+CENEXT, (byte) 0xff);
|
||||
buffer.put(cenpos+CENEXT+1, (byte) 0xff);
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown if a CEN header has an
|
||||
* extra field length which makes the CEN header overflow into the
|
||||
* End of central directory record.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveExtraFieldLength2() throws IOException {
|
||||
buffer.putShort(cenpos+CENEXT, (short) 0xfdfd);
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has a comment length
|
||||
* which overflows into the 'End of central directory' record
|
||||
*/
|
||||
@Test
|
||||
public void excessiveCommentLength() throws IOException {
|
||||
short existingCommentLength = buffer.getShort(cenpos + CENCOM);
|
||||
buffer.putShort(cenpos+CENCOM, (short) (existingCommentLength + 1));
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has a
|
||||
* compression method field which is unsupported by the implementation
|
||||
*/
|
||||
@Test
|
||||
public void unsupportedCompressionMethod() throws IOException {
|
||||
copy[cenpos+CENHOW] = 2;
|
||||
assertZipException(".*bad compression method.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a LOC header has an unexpected signature
|
||||
*/
|
||||
@Test
|
||||
public void invalidLOCSignature() throws IOException {
|
||||
int existingSignatur = buffer.getInt(locpos);
|
||||
buffer.putInt(locpos, existingSignatur +1);
|
||||
assertZipException(".*bad signature.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* Assert that opening a ZIP file and consuming the entry's
|
||||
* InputStream using the ZipFile API fails with a ZipException
|
||||
* with a message matching the given pattern.
|
||||
*
|
||||
* The ZIP file opened is the contents of the 'copy' byte array.
|
||||
*/
|
||||
void assertZipException(String msgPattern) throws IOException {
|
||||
|
||||
Files.write(zip, copy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
try (InputStream is = zf.getInputStream(new ZipEntry("x"))) {
|
||||
is.transferTo(OutputStream.nullOutputStream());
|
||||
}
|
||||
}
|
||||
});
|
||||
assertTrue(ex.getMessage().matches(msgPattern),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
|
||||
}
|
||||
}
|
||||
103
test/jdk/java/util/zip/ZipFile/DeleteTempJar.java
Normal file
103
test/jdk/java/util/zip/ZipFile/DeleteTempJar.java
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2022, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
|
||||
public class DeleteTempJar
|
||||
{
|
||||
public static void realMain(String args[]) throws Exception
|
||||
{
|
||||
final File zf = File.createTempFile("deletetemp", ".jar");
|
||||
zf.deleteOnExit();
|
||||
try (FileOutputStream fos = new FileOutputStream(zf);
|
||||
JarOutputStream jos = new JarOutputStream(fos))
|
||||
{
|
||||
JarEntry je = new JarEntry("entry");
|
||||
jos.putNextEntry(je);
|
||||
jos.write("hello, world".getBytes("ASCII"));
|
||||
}
|
||||
|
||||
HttpServer server = HttpServer.create(
|
||||
new InetSocketAddress((InetAddress) null, 0), 0);
|
||||
HttpContext context = server.createContext("/",
|
||||
new HttpHandler() {
|
||||
public void handle(HttpExchange e) {
|
||||
try (FileInputStream fis = new FileInputStream(zf)) {
|
||||
e.sendResponseHeaders(200, zf.length());
|
||||
OutputStream os = e.getResponseBody();
|
||||
byte[] buf = new byte[1024];
|
||||
int count = 0;
|
||||
while ((count = fis.read(buf)) != -1) {
|
||||
os.write(buf, 0, count);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
unexpected(ex);
|
||||
} finally {
|
||||
e.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.start();
|
||||
try {
|
||||
URL url = new URL("jar:http://localhost:"
|
||||
+ new Integer(server.getAddress().getPort()).toString()
|
||||
+ "/deletetemp.jar!/");
|
||||
JarURLConnection c = (JarURLConnection)url.openConnection();
|
||||
JarFile f = c.getJarFile();
|
||||
check(f.getEntry("entry") != null);
|
||||
System.out.println(f.getName());
|
||||
} finally {
|
||||
server.stop(0);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static boolean pass() {passed++; return true;}
|
||||
static boolean fail() {failed++; Thread.dumpStack(); return false;}
|
||||
static boolean fail(String msg) {System.out.println(msg); return fail();}
|
||||
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
||||
static boolean equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) return pass();
|
||||
else return fail(x + " not equal to " + y);}
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
||||
51
test/jdk/java/util/zip/ZipFile/DeleteTempJarTest.java
Normal file
51
test/jdk/java/util/zip/ZipFile/DeleteTempJarTest.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2024, 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.
|
||||
*
|
||||
* 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 4166799
|
||||
* @summary Make sure URL-downloaded jar files (jar_cache files)
|
||||
* will be deleted when VM exits.
|
||||
* @modules jdk.httpserver
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.process.*
|
||||
* DeleteTempJar
|
||||
* @run main DeleteTempJarTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
public class DeleteTempJarTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String tmpFile = ProcessTools.executeTestJava(DeleteTempJar.class.getName())
|
||||
.shouldHaveExitValue(0)
|
||||
.getStdout();
|
||||
|
||||
Asserts.assertFalse(Files.exists(Paths.get(tmpFile.trim())));
|
||||
}
|
||||
}
|
||||
216
test/jdk/java/util/zip/ZipFile/DupEntriesGetInputStream.java
Normal file
216
test/jdk/java/util/zip/ZipFile/DupEntriesGetInputStream.java
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HexFormat;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8349914
|
||||
* @summary Validate ZipFile::getFileInputStream returns the correct data when
|
||||
* there are multiple entries with the same filename
|
||||
* @run junit DupEntriesGetInputStream
|
||||
*/
|
||||
class DupEntriesGetInputStream {
|
||||
|
||||
// created through a call to createNormalZIP()
|
||||
private static final String NORMAL_ZIP_CONTENT_HEX = """
|
||||
504b03041400080808009195c35a00000000000000000000000006000000456e747279310bc9c8
|
||||
2c560022d7bc92a24a054300504b07089bc0e55b0f0000000f000000504b030414000808080091
|
||||
95c35a00000000000000000000000006000000456e747279320bc9c82c560022d7bc92a24a85bc
|
||||
d2dca4d4228590f27c00504b0708ebda8deb1800000018000000504b03041400080808009195c3
|
||||
5a00000000000000000000000006000000456e747279330bc9c82c560022d7bc92a24a05650563
|
||||
00504b0708d1eafe7d1100000011000000504b010214001400080808009195c35a9bc0e55b0f00
|
||||
00000f000000060000000000000000000000000000000000456e74727931504b01021400140008
|
||||
0808009195c35aebda8deb1800000018000000060000000000000000000000000043000000456e
|
||||
74727932504b010214001400080808009195c35ad1eafe7d110000001100000006000000000000
|
||||
000000000000008f000000456e74727933504b050600000000030003009c000000d40000000000
|
||||
""";
|
||||
|
||||
// intentionally unused but left here to allow for constructing newer/updated
|
||||
// NORMAL_ZIP_CONTENT_HEX, when necessary
|
||||
private static String createNormalZIP() throws IOException {
|
||||
final ByteArrayOutputStream zipContent = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(zipContent)) {
|
||||
zos.putNextEntry(new ZipEntry(ENTRY1_NAME));
|
||||
zos.write(ENTRY1.getBytes(US_ASCII));
|
||||
zos.putNextEntry(new ZipEntry(ENTRY2_NAME));
|
||||
zos.write(ENTRY2.getBytes(US_ASCII));
|
||||
zos.putNextEntry(new ZipEntry(ENTRY3_NAME));
|
||||
zos.write(ENTRY3.getBytes(US_ASCII));
|
||||
}
|
||||
return HexFormat.of().formatHex(zipContent.toByteArray());
|
||||
}
|
||||
|
||||
// Entry Names and their data to be added to the ZIP File
|
||||
private static final String ENTRY1_NAME = "Entry1";
|
||||
private static final String ENTRY1 = "This is Entry 1";
|
||||
|
||||
private static final String ENTRY2_NAME = "Entry2";
|
||||
private static final String ENTRY2 = "This is Entry number Two";
|
||||
|
||||
private static final String ENTRY3_NAME = "Entry3";
|
||||
private static final String ENTRY3 = "This is Entry # 3";
|
||||
|
||||
// ZIP entry and its expected data
|
||||
record ZIP_ENTRY(String entryName, String data) {
|
||||
}
|
||||
|
||||
private static final ZIP_ENTRY[] ZIP_ENTRIES = new ZIP_ENTRY[]{
|
||||
new ZIP_ENTRY(ENTRY1_NAME, ENTRY1),
|
||||
new ZIP_ENTRY(ENTRY2_NAME, ENTRY2),
|
||||
new ZIP_ENTRY(ENTRY1_NAME, ENTRY3)
|
||||
};
|
||||
|
||||
private static Path dupEntriesZipFile;
|
||||
|
||||
// 008F LOCAL HEADER #3 04034B50
|
||||
// ...
|
||||
// 00A1 Compressed Length 00000000
|
||||
// 00A5 Uncompressed Length 00000000
|
||||
// 00A9 Filename Length 0006
|
||||
// ...
|
||||
// 00AD Filename 'Entry3'
|
||||
private static final int ENTRY3_FILENAME_LOC_OFFSET = 0x00AD;
|
||||
|
||||
// 013C CENTRAL HEADER #3 02014B50
|
||||
// ...
|
||||
// 0150 Compressed Length 00000011
|
||||
// 0154 Uncompressed Length 00000011
|
||||
// 0158 Filename Length 0006
|
||||
// ...
|
||||
// 016A Filename 'Entry3'
|
||||
private static final int ENTRY3_FILENAME_CEN_OFFSET = 0x016A;
|
||||
|
||||
@BeforeAll
|
||||
static void createDupEntriesZIP() throws Exception {
|
||||
final byte[] originalZIPContent = HexFormat.of().parseHex(
|
||||
NORMAL_ZIP_CONTENT_HEX.replace("\n", ""));
|
||||
final ByteBuffer buf = ByteBuffer.wrap(originalZIPContent).order(LITTLE_ENDIAN);
|
||||
// replace the file name literal "Entry3" with the literal "Entry1", both in the
|
||||
// LOC header and the CEN of Entry3
|
||||
final int locEntry3LastCharOffset = ENTRY3_FILENAME_LOC_OFFSET + ENTRY3_NAME.length() - 1;
|
||||
buf.put(locEntry3LastCharOffset, (byte) 49); // 49 represents the character "1"
|
||||
final int cenEntry3LastCharOffset = ENTRY3_FILENAME_CEN_OFFSET + ENTRY3_NAME.length() - 1;
|
||||
buf.put(cenEntry3LastCharOffset, (byte) 49); // 49 represents the character "1"
|
||||
buf.rewind();
|
||||
// write out the manipulated ZIP content, containing duplicate entries, into a file
|
||||
// so that it can be read using ZipFile
|
||||
dupEntriesZipFile = Files.createTempFile(Path.of("."), "8349914-", ".zip");
|
||||
Files.write(dupEntriesZipFile, buf.array());
|
||||
System.out.println("created ZIP file with duplicate entries at " + dupEntriesZipFile);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the correct ZipEntry data is returned when a List is used
|
||||
* to access entries returned from ZipFile::entries
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testUsingListEntries() throws IOException {
|
||||
System.out.println("Processing entries via Collections.list()");
|
||||
try (ZipFile zf = new ZipFile(dupEntriesZipFile.toFile())) {
|
||||
var entryNumber = 0;
|
||||
for (var e : Collections.list(zf.entries())) {
|
||||
verifyEntry(entryNumber++, zf, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the correct ZipEntry data is returned when a ZipEntryIterator
|
||||
* is used to access entries returned from ZipFile::entries
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testUsingZipEntryIterator() throws IOException {
|
||||
System.out.println("Processing entries via a ZipEntryIterator");
|
||||
try (ZipFile zf = new ZipFile(dupEntriesZipFile.toFile())) {
|
||||
Enumeration<? extends ZipEntry> entries = zf.entries();
|
||||
var entryNumber = 0;
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
verifyEntry(entryNumber++, zf, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the correct ZipEntry data is returned when a EntrySpliterator
|
||||
* is used to access entries returned from ZipFile::stream
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testUsingEntrySpliterator() throws IOException {
|
||||
System.out.println("Processing entries via a EntrySpliterator");
|
||||
AtomicInteger eNumber = new AtomicInteger(0);
|
||||
try (ZipFile zf = new ZipFile(dupEntriesZipFile.toFile())) {
|
||||
zf.stream().forEach(e -> {
|
||||
try {
|
||||
verifyEntry(eNumber.getAndIncrement(), zf, e);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the ZipEntry returned matches what is expected
|
||||
*
|
||||
* @param entryNumber offset into ZIP_ENTRIES containing the expected value
|
||||
* to be returned
|
||||
* @param zf ZipFile containing the entry
|
||||
* @param e ZipEntry to validate
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void verifyEntry(int entryNumber, ZipFile zf, ZipEntry e) throws IOException {
|
||||
System.out.println("Validating Entry: " + entryNumber);
|
||||
assertEquals(ZIP_ENTRIES[entryNumber].entryName(), e.getName());
|
||||
try (var in = zf.getInputStream(e)) {
|
||||
var entryData = new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertEquals(ZIP_ENTRIES[entryNumber].data(), entryData);
|
||||
}
|
||||
}
|
||||
}
|
||||
151
test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java
Normal file
151
test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2026, 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.
|
||||
*
|
||||
* 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 8272746
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @summary Verify that ZipFile rejects files with CEN sizes exceeding the implementation limit
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.util.ZipUtils
|
||||
* @run junit/othervm EndOfCenValidation
|
||||
*/
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static jdk.test.lib.util.ZipUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* This test augments {@link TestTooManyEntries}. It creates sparse ZIPs where
|
||||
* the CEN size is inflated to the desired value. This helps this test run
|
||||
* fast with much less resources.
|
||||
*
|
||||
* While the CEN in these files are zero-filled and the produced ZIPs are technically
|
||||
* invalid, the CEN is never actually read by ZipFile since it does
|
||||
* 'End of central directory record' (END header) validation before reading the CEN.
|
||||
*/
|
||||
public class EndOfCenValidation {
|
||||
|
||||
// Zip files produced by this test
|
||||
static final Path CEN_TOO_LARGE_ZIP = Path.of("cen-size-too-large.zip");
|
||||
static final Path INVALID_CEN_SIZE = Path.of("invalid-zen-size.zip");
|
||||
static final Path BAD_CEN_OFFSET_ZIP = Path.of("bad-cen-offset.zip");
|
||||
static final Path BAD_ENTRY_COUNT_ZIP = Path.of("bad-entry-count.zip");
|
||||
|
||||
// Maximum allowed CEN size allowed by ZipFile
|
||||
static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH;
|
||||
|
||||
/**
|
||||
* Delete big files after test, in case the file system did not support sparse files.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(CEN_TOO_LARGE_ZIP);
|
||||
Files.deleteIfExists(INVALID_CEN_SIZE);
|
||||
Files.deleteIfExists(BAD_CEN_OFFSET_ZIP);
|
||||
Files.deleteIfExists(BAD_ENTRY_COUNT_ZIP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that an 'End of central directory record' (END header) with a CEN
|
||||
* length exceeding {@link #MAX_CEN_SIZE} limit is rejected
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectTooLargeCenSize() throws IOException {
|
||||
int size = MAX_CEN_SIZE + 1;
|
||||
Path zip = zipWithModifiedEndRecord(size, true, 0, CEN_TOO_LARGE_ZIP);
|
||||
verifyRejection(zip, INVALID_CEN_SIZE_TOO_LARGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an 'End of central directory record' (END header)
|
||||
* where the value of the CEN size field exceeds the position of
|
||||
* the END header is rejected.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectInvalidCenSize() throws IOException {
|
||||
int size = MAX_CEN_SIZE;
|
||||
Path zip = zipWithModifiedEndRecord(size, false, 0, INVALID_CEN_SIZE);
|
||||
verifyRejection(zip, INVALID_CEN_BAD_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an 'End of central directory record' (the END header)
|
||||
* where the value of the CEN offset field is larger than the position
|
||||
* of the END header minus the CEN size is rejected
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectInvalidCenOffset() throws IOException {
|
||||
int size = MAX_CEN_SIZE;
|
||||
Path zip = zipWithModifiedEndRecord(size, true, 100, BAD_CEN_OFFSET_ZIP);
|
||||
verifyRejection(zip, INVALID_CEN_BAD_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a 'Zip64 End of Central Directory' record (the END header)
|
||||
* where the value of the 'total entries' field is larger than what fits
|
||||
* in the CEN size is rejected.
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {
|
||||
-1, // Negative
|
||||
Long.MIN_VALUE, // Very negative
|
||||
0x3B / 3L - 1, // Cannot fit in test ZIP's CEN
|
||||
MAX_CEN_SIZE / 3 + 1, // Too large to allocate int[] entries array
|
||||
Long.MAX_VALUE // Unreasonably large
|
||||
})
|
||||
public void shouldRejectBadTotalEntries(long totalEntries) throws IOException {
|
||||
Path zip = zip64WithModifiedTotalEntries(BAD_ENTRY_COUNT_ZIP, totalEntries);
|
||||
verifyRejection(zip, INVALID_BAD_ENTRY_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile rejects the ZIP file with a ZipException
|
||||
* with the given message
|
||||
* @param zip ZIP file to open
|
||||
* @param msg exception message to expect
|
||||
*/
|
||||
private static void verifyRejection(Path zip, String msg) {
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
new ZipFile(zip.toFile());
|
||||
});
|
||||
assertEquals(msg, ex.getMessage());
|
||||
}
|
||||
}
|
||||
94
test/jdk/java/util/zip/ZipFile/EnumerateAfterClose.java
Normal file
94
test/jdk/java/util/zip/ZipFile/EnumerateAfterClose.java
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2024, 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.
|
||||
*
|
||||
* 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 4290060
|
||||
@summary Check if the zip file is closed before access any
|
||||
elements in the Enumeration.
|
||||
@run junit EnumerateAfterClose
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class EnumerateAfterClose {
|
||||
|
||||
// ZIP file used in this test
|
||||
private Path zip = Path.of("enum-after-close.zip");
|
||||
|
||||
/**
|
||||
* Create a sample ZIP file for use by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempting to using a ZipEntry Enumeration after its backing
|
||||
* ZipFile is closed should throw IllegalStateException.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void enumeratingAfterCloseShouldThrowISE() throws IOException {
|
||||
// Retain a reference to an enumeration backed by a closed ZipFile
|
||||
Enumeration e;
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
e = zf.entries();
|
||||
}
|
||||
// Using the enumeration after the ZipFile is closed should throw ISE
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
if (e.hasMoreElements()) {
|
||||
ZipEntry ze = (ZipEntry)e.nextElement();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
113
test/jdk/java/util/zip/ZipFile/FinalizeInflater.java
Normal file
113
test/jdk/java/util/zip/ZipFile/FinalizeInflater.java
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2024, 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.
|
||||
*
|
||||
* 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 7003462
|
||||
@summary Make sure cached Inflater does not get finalized.
|
||||
@run junit FinalizeInflater
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class FinalizeInflater {
|
||||
|
||||
// ZIP file produced by this test
|
||||
private Path zip = Path.of("finalize-inflater.zip");
|
||||
|
||||
/**
|
||||
* Create the sample ZIP used in this test
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
byte[] hello = "hello".getBytes(StandardCharsets.UTF_8);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
zo.write(hello);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced by this test
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* A cached Inflater should not be made invalid by finalization
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotFinalizeInflaterInPool() throws IOException {
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry ze = zf.getEntry("file.txt");
|
||||
read(zf.getInputStream(ze));
|
||||
System.gc();
|
||||
System.runFinalization();
|
||||
System.gc();
|
||||
// read again
|
||||
read(zf.getInputStream(ze));
|
||||
}
|
||||
}
|
||||
|
||||
private static void read(InputStream is)
|
||||
throws IOException
|
||||
{
|
||||
Wrapper wrapper = new Wrapper(is);
|
||||
is.readAllBytes();
|
||||
}
|
||||
|
||||
static class Wrapper {
|
||||
InputStream is;
|
||||
public Wrapper(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
1068
test/jdk/java/util/zip/ZipFile/GetInputStreamNPETest.java
Normal file
1068
test/jdk/java/util/zip/ZipFile/GetInputStreamNPETest.java
Normal file
File diff suppressed because it is too large
Load diff
117
test/jdk/java/util/zip/ZipFile/IncorrectEndTot.java
Normal file
117
test/jdk/java/util/zip/ZipFile/IncorrectEndTot.java
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2026, 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.
|
||||
*
|
||||
* 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
|
||||
* @summary Verify that ZipFile::size reports the actual number of entries
|
||||
* even with an incorrect ENDTOT field
|
||||
* @run junit IncorrectEndTot
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class IncorrectEndTot {
|
||||
|
||||
// File to use for this test
|
||||
File file = new File("incorrect-end-centot.zip");
|
||||
|
||||
// Return scenarios for correct and incorrect ENDTOT fields
|
||||
public static Stream<Arguments> scenarios() {
|
||||
return Stream.of(
|
||||
Arguments.of(10, 10), // CEN agrees with ENDTOT
|
||||
Arguments.of(10, 11), // CEN has one less than ENDTOT
|
||||
Arguments.of(11, 10), // CEN has one more than ENDTOT
|
||||
Arguments.of(0, 0), // Empty ZIP, correct ENDTOT
|
||||
Arguments.of(0, 10) // Empty ZIP, incorrect ENDTOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the file used by this test
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() {
|
||||
file.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile::size reports the actual number of CEN records,
|
||||
* regardless of the ENDTOT field.
|
||||
*
|
||||
* @param actual number of entries in the ZIP file
|
||||
* @param reported number reported in ENDTOT
|
||||
* @throws IOException if an unexpected error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("scenarios")
|
||||
public void shouldCountActualEntries(int actual, int reported) throws IOException {
|
||||
createZip(file, actual, reported);
|
||||
try (ZipFile zf = new ZipFile(file)) {
|
||||
assertEquals(actual, zf.size());
|
||||
assertEquals(actual, Collections.list(zf.entries()).size());
|
||||
assertEquals(actual, zf.stream().count());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ZIP file with a number of entries, possibly reporting an incorrect number in
|
||||
* the ENDTOT field
|
||||
* @param file the file to write to
|
||||
* @param numEntries the number of entries to generate
|
||||
* @param reported the number of entries to report in the END header's ENDTOT field
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void createZip(File file, int numEntries, int reported) throws IOException {
|
||||
// Create a ZIP
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
zo.putNextEntry(new ZipEntry("entry_" + i));
|
||||
}
|
||||
}
|
||||
byte[] bytes = out.toByteArray();
|
||||
|
||||
// Update the ENDTOT field to report a possibly incorrect number
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.putShort(bytes.length - ZipFile.ENDHDR + ZipFile.ENDTOT, (short) reported);
|
||||
|
||||
// Write to disk
|
||||
Files.write(file.toPath(), bytes);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8301873 8321156
|
||||
* @summary Validate that a ZipException is thrown when a ZIP file with
|
||||
* invalid UTF-8 byte sequences in the name or comment fields is opened via
|
||||
* ZipFile or traversed via ZipInputStream.
|
||||
* Also validate that ZipFile::getComment will return null with invalid UTF-8
|
||||
* byte sequences in the ZIP file comment
|
||||
* @run junit InvalidBytesInEntryNameOrComment
|
||||
*/
|
||||
public class InvalidBytesInEntryNameOrComment {
|
||||
// Zip file that is created and used by the test
|
||||
public static final Path ZIP_FILE = Path.of("BadName.zip");
|
||||
// Example invalid UTF-8 byte sequence
|
||||
private static final byte[] INVALID_UTF8_BYTE_SEQUENCE = {(byte) 0xF0, (byte) 0xA4, (byte) 0xAD};
|
||||
// Expected error message when an invalid entry name or entry comment is
|
||||
// encountered when accessing a CEN Header
|
||||
private static final String CEN_BAD_ENTRY_NAME_OR_COMMENT = "invalid CEN header (bad entry name or comment)";
|
||||
|
||||
// Expected error message when an invalid entry name is encountered when
|
||||
// accessing a LOC Header
|
||||
private static final String LOC_HEADER_BAD_ENTRY_NAME = "invalid LOC header (bad entry name)";
|
||||
// Zip file comment starting offset
|
||||
private static final int ZIP_FILE_COMMENT_OFFSET = 0x93;
|
||||
// CEN Header offset for the entry comment to be modified
|
||||
private static final int CEN_FILE_HEADER_FILE_COMMENT_STARTING_OFFSET = 0x6D;
|
||||
// CEN Header offset for the entry name to be modified
|
||||
private static final int CEN_FILE_HEADER_FILENAME_STARTING_OFFSET = 0x66;
|
||||
// LOC Header offset for the entry name to be modified
|
||||
private static final int LOC_FILE_HEADER_FILENAME_STARTING_OFFSET = 0x1e;
|
||||
// CEN Entry comment
|
||||
public static final String ENTRY_COMMENT = "entryComment";
|
||||
// Entry name to be modified/validated
|
||||
public static final String ENTRY_NAME = "entryName";
|
||||
// Zip file comment to be modified/validated
|
||||
public static final String ZIP_FILE_COMMENT = "ZipFileComment";
|
||||
// Buffer used to massage the byte array containing the Zip File
|
||||
private ByteBuffer buffer;
|
||||
// Array used to copy VALID_ZIP into prior to each test run
|
||||
private byte[] zipArray;
|
||||
|
||||
/**
|
||||
* Byte array representing a valid Zip file prior modifying the CEN/LOC
|
||||
* entry name, CEN entry comment or Zip file comment with an invalid
|
||||
* UTF-8 byte sequence.
|
||||
* See the createZipByteArray method which was used to create the original
|
||||
* Zip file
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x3a: Signature : 0x02014b50
|
||||
* 0x3e: Created Zip Spec : 0x14 [2.0]
|
||||
* 0x3f: Created OS : 0x0 [MS-DOS]
|
||||
* 0x40: VerMadeby : 0x14 [0, 2.0]
|
||||
* 0x41: VerExtract : 0x14 [2.0]
|
||||
* 0x42: Flag : 0x808
|
||||
* 0x44: Method : 0x8 [DEFLATED]
|
||||
* 0x46: Last Mod Time : 0x58506664 [Fri Feb 16 12:51:08 EST 2024]
|
||||
* 0x4a: CRC : 0xd202ef8d
|
||||
* 0x4e: Compressed Size : 0x3
|
||||
* 0x52: Uncompressed Size: 0x1
|
||||
* 0x56: Name Length : 0x9
|
||||
* 0x58: Extra Length : 0x0
|
||||
* 0x5a: Comment Length : 0xc
|
||||
* 0x5c: Disk Start : 0x0
|
||||
* 0x5e: Attrs : 0x0
|
||||
* 0x60: AttrsEx : 0x0
|
||||
* 0x64: Loc Header Offset: 0x0
|
||||
* 0x68: File Name : entryName
|
||||
* 0x71: Comment : [entryComment]
|
||||
* [Local File Header]
|
||||
* 0x0: Signature : 0x04034b50
|
||||
* 0x4: Version : 0x14 [2.0]
|
||||
* 0x6: Flag : 0x808
|
||||
* 0x8: Method : 0x8 [DEFLATED]
|
||||
* 0xa: LastMTime : 0x58506664 [Fri Feb 16 12:51:08 EST 2024]
|
||||
* 0xe: CRC : 0x0
|
||||
* 0x12: CSize : 0x0
|
||||
* 0x16: Size : 0x0
|
||||
* 0x1a: Name Length : 0x9 [entryName]
|
||||
* 0x1c: ExtraLength : 0x0
|
||||
* 0x1e: File Name : [entryName]
|
||||
* [End Central Directory Header]
|
||||
* 0x7d: Signature : 0x06054b50
|
||||
* 0x85: Disk Entries: 0x1
|
||||
* 0x87: Total Entries: 0x1
|
||||
* 0x89: CEN Size : 0x43
|
||||
* 0x8d: Offset CEN : 0x3a
|
||||
* 0x91: Comment Len : 0xe
|
||||
* 0x93: Comment : [ZipFileComment]
|
||||
*/
|
||||
public static byte[] VALID_ZIP = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x7d, (byte) 0x6f, (byte) 0x50, (byte) 0x58, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x4e, (byte) 0x61, (byte) 0x6d, (byte) 0x65, (byte) 0x63,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x8d, (byte) 0xef,
|
||||
(byte) 0x2, (byte) 0xd2, (byte) 0x3, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x7d, (byte) 0x6f,
|
||||
(byte) 0x50, (byte) 0x58, (byte) 0x8d, (byte) 0xef, (byte) 0x2, (byte) 0xd2, (byte) 0x3, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x4e, (byte) 0x61, (byte) 0x6d,
|
||||
(byte) 0x65, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x43, (byte) 0x6f,
|
||||
(byte) 0x6d, (byte) 0x6d, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x5,
|
||||
(byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3a, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0xe, (byte) 0x0, (byte) 0x5a, (byte) 0x69, (byte) 0x70, (byte) 0x46, (byte) 0x69,
|
||||
(byte) 0x6c, (byte) 0x65, (byte) 0x43, (byte) 0x6f, (byte) 0x6d, (byte) 0x6d, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x74,
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete the Zip file if it exists prior to each run and create a copy
|
||||
* of the byte array representing a valid ZIP file to be used by each test run
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setupTest() throws IOException {
|
||||
Files.deleteIfExists(ZIP_FILE);
|
||||
zipArray = Arrays.copyOf(VALID_ZIP, VALID_ZIP.length);
|
||||
buffer = ByteBuffer.wrap(zipArray).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* The MethodSource of CEN offsets to modify with an invalid UTF-8 byte
|
||||
* sequence
|
||||
*
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> CENCommentOffsets() {
|
||||
return Stream.of(
|
||||
// Entry's name starting offset
|
||||
Arguments.of(CEN_FILE_HEADER_FILENAME_STARTING_OFFSET),
|
||||
// Entry's comment starting offset
|
||||
Arguments.of(CEN_FILE_HEADER_FILE_COMMENT_STARTING_OFFSET)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the original Zip file can be opened via ZipFile.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testValidEntryNameAndComment() throws IOException {
|
||||
Files.write(ZIP_FILE, zipArray);
|
||||
try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {
|
||||
var comment = zf.getComment();
|
||||
assertEquals(ZIP_FILE_COMMENT, comment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the original Zip file can be opened and traversed via
|
||||
* ZipinputStream::getNextEntry.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void traverseZipWithZipInputStreamTest() throws IOException {
|
||||
Files.write(ZIP_FILE, zipArray);
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(ZIP_FILE.toFile()))) {
|
||||
ZipEntry ze;
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
assertEquals(ENTRY_NAME, ze.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ZipException is thrown when an entry name or entry comment
|
||||
* within a CEN file header contains an invalid UTF-8 byte sequence.
|
||||
*
|
||||
* @param offset the offset to the file name or file comment within the CEN
|
||||
* file header
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("CENCommentOffsets")
|
||||
public void testInValidEntryNameOrComment(int offset)
|
||||
throws IOException {
|
||||
createInvalidUTFEntryInZipFile(offset);
|
||||
Throwable ex = assertThrows(ZipException.class, () ->
|
||||
{
|
||||
try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {};
|
||||
}
|
||||
);
|
||||
assertEquals(CEN_BAD_ENTRY_NAME_OR_COMMENT, ex.getMessage());
|
||||
}
|
||||
/**
|
||||
* Validate that a null is returned from ZipFile::getComment when the
|
||||
* comment contains an invalid UTF-8 byte sequence.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testInValidZipFileComment() throws IOException {
|
||||
createInvalidUTFEntryInZipFile(ZIP_FILE_COMMENT_OFFSET);
|
||||
try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {
|
||||
assertNull(zf.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ZipException is thrown when an entry name
|
||||
* within a LOC file header contains an invalid UTF-8 byte sequence.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void invalidZipInputStreamTest() throws IOException {
|
||||
createInvalidUTFEntryInZipFile(LOC_FILE_HEADER_FILENAME_STARTING_OFFSET);
|
||||
Throwable ex = assertThrows(ZipException.class, () ->
|
||||
{
|
||||
try (ZipInputStream zis =
|
||||
new ZipInputStream(new FileInputStream(ZIP_FILE.toFile()))) {
|
||||
zis.getNextEntry();
|
||||
};
|
||||
});
|
||||
assertEquals(LOC_HEADER_BAD_ENTRY_NAME, ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method which modifies a Zip file starting at the specified
|
||||
* offset to include an invalid UTF-8 byte sequence.
|
||||
*
|
||||
* @param offset starting offset within the Zip file to modify
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private void createInvalidUTFEntryInZipFile(int offset) throws IOException {
|
||||
buffer.put(offset, INVALID_UTF8_BYTE_SEQUENCE, 0,
|
||||
INVALID_UTF8_BYTE_SEQUENCE.length);
|
||||
Files.write(ZIP_FILE, zipArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method which creates the Zip file used by the tests and
|
||||
* converts Zip file to byte array declaration.
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private void createZipByteArray() throws IOException {
|
||||
ZipOutputStream zos = new ZipOutputStream(
|
||||
new FileOutputStream(ZIP_FILE.toFile()));
|
||||
zos.setComment(ZIP_FILE_COMMENT);
|
||||
ZipEntry entry = new ZipEntry(ENTRY_NAME);
|
||||
entry.setComment(ENTRY_COMMENT);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write(new byte[1]);
|
||||
zos.closeEntry();
|
||||
zos.close();
|
||||
// Now create the byte array entry declaration
|
||||
var fooJar = Files.readAllBytes(ZIP_FILE);
|
||||
var result = createByteArray(fooJar, "VALID_ZIP");
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method which takes a byte array and converts to byte array
|
||||
* declaration. For example:
|
||||
* {@snippet :
|
||||
* var fooJar = Files.readAllBytes(Path.of("foo.jar"));
|
||||
* var result = createByteArray(fooJar,"FOOBYTES");
|
||||
* System.out.println(result);
|
||||
* }
|
||||
*
|
||||
* @param bytes A byte array used to create a byte array declaration
|
||||
* @param name Name to be used in the byte array declaration
|
||||
* @return The formatted byte array declaration
|
||||
*/
|
||||
public static String createByteArray(byte[] bytes, String name) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 5);
|
||||
Formatter fmt = new Formatter(sb);
|
||||
fmt.format(" public static byte[] %s = {", name);
|
||||
final int linelen = 8;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
if (i % linelen == 0) {
|
||||
fmt.format("%n ");
|
||||
}
|
||||
fmt.format(" (byte) 0x%x,", bytes[i] & 0xff);
|
||||
}
|
||||
fmt.format("%n };%n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
348
test/jdk/java/util/zip/ZipFile/InvalidCommentLengthTest.java
Normal file
348
test/jdk/java/util/zip/ZipFile/InvalidCommentLengthTest.java
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8280404
|
||||
* @summary Validate that Zip/JarFile will throw a ZipException when the CEN
|
||||
* comment length field contains an incorrect value
|
||||
* @run junit/othervm InvalidCommentLengthTest
|
||||
*/
|
||||
public class InvalidCommentLengthTest {
|
||||
|
||||
// Name used to create a JAR with an invalid comment length
|
||||
public static final Path INVALID_CEN_COMMENT_LENGTH_JAR =
|
||||
Path.of("Invalid-CEN-Comment-Length.jar");
|
||||
// Name used to create a JAR with a valid comment length
|
||||
public static final Path VALID_CEN_COMMENT_LENGTH_JAR =
|
||||
Path.of("Valid-CEN-Comment-Length.jar");
|
||||
// Zip/Jar CEN file header entry that will be modified
|
||||
public static final String META_INF_MANIFEST_MF = "META-INF/MANIFEST.MF";
|
||||
// Expected ZipException message when the comment length corrupts the
|
||||
// Zip/Jar file
|
||||
public static final String INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT =
|
||||
"invalid CEN header (bad entry name or comment)";
|
||||
|
||||
/**
|
||||
* Byte array representing a valid jar file prior modifying the comment length
|
||||
* entry in a CEN file header.
|
||||
* The "Valid-CEN-Comment-Length.jar" jar file was created via:
|
||||
* <pre>
|
||||
* {@code
|
||||
* jar cvf Valid-CEN-Comment-Length.jar Hello.txt Tennis.txt BruceWayne.txt
|
||||
* added manifest
|
||||
* adding: Hello.txt(in = 12) (out= 14)(deflated -16%)
|
||||
* adding: Tennis.txt(in = 53) (out= 53)(deflated 0%)
|
||||
* adding: BruceWayne.txt(in = 12) (out= 14)(deflated -16%)
|
||||
* }
|
||||
* </pre>
|
||||
* Its contents are:
|
||||
* <pre>
|
||||
* {@code
|
||||
* jar tvf Valid-CEN-Comment-Length.jar
|
||||
* 0 Wed Mar 02 06:39:24 EST 2022 META-INF/
|
||||
* 66 Wed Mar 02 06:39:24 EST 2022 META-INF/MANIFEST.MF
|
||||
* 12 Wed Mar 02 06:39:06 EST 2022 Hello.txt
|
||||
* 53 Wed Mar 02 13:04:48 EST 2022 Tennis.txt
|
||||
* 12 Wed Mar 02 15:15:34 EST 2022 BruceWayne.txt
|
||||
* }
|
||||
* </pre>
|
||||
* The ByteArray was created by:
|
||||
* <pre>
|
||||
* {@code
|
||||
* var jar = Files.readAllBytes("Valid-CEN-Comment-Length.jar");
|
||||
* var validEntryName = createByteArray(fooJar,
|
||||
* "VALID_ZIP_WITH_NO_COMMENTS_BYTES");
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public static byte[] VALID_ZIP_WITH_NO_COMMENTS_BYTES = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x4, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d,
|
||||
(byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0xfe,
|
||||
(byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41,
|
||||
(byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46,
|
||||
(byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d,
|
||||
(byte) 0x46, (byte) 0xf3, (byte) 0x4d, (byte) 0xcc, (byte) 0xcb,
|
||||
(byte) 0x4c, (byte) 0x4b, (byte) 0x2d, (byte) 0x2e, (byte) 0xd1,
|
||||
(byte) 0xd, (byte) 0x4b, (byte) 0x2d, (byte) 0x2a, (byte) 0xce,
|
||||
(byte) 0xcc, (byte) 0xcf, (byte) 0xb3, (byte) 0x52, (byte) 0x30,
|
||||
(byte) 0xd4, (byte) 0x33, (byte) 0xe0, (byte) 0xe5, (byte) 0x72,
|
||||
(byte) 0x2e, (byte) 0x4a, (byte) 0x4d, (byte) 0x2c, (byte) 0x49,
|
||||
(byte) 0x4d, (byte) 0xd1, (byte) 0x75, (byte) 0xaa, (byte) 0x4,
|
||||
(byte) 0xa, (byte) 0x98, (byte) 0xe8, (byte) 0x19, (byte) 0xe8,
|
||||
(byte) 0x19, (byte) 0x2a, (byte) 0x68, (byte) 0xf8, (byte) 0x17,
|
||||
(byte) 0x25, (byte) 0x26, (byte) 0xe7, (byte) 0xa4, (byte) 0x2a,
|
||||
(byte) 0x38, (byte) 0xe7, (byte) 0x17, (byte) 0x15, (byte) 0xe4,
|
||||
(byte) 0x17, (byte) 0x25, (byte) 0x96, (byte) 0x0, (byte) 0x15,
|
||||
(byte) 0x6b, (byte) 0xf2, (byte) 0x72, (byte) 0xf1, (byte) 0x72,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xf4, (byte) 0x59, (byte) 0xdc, (byte) 0xa6,
|
||||
(byte) 0x42, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x42,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xe3, (byte) 0x34,
|
||||
(byte) 0x62, (byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74,
|
||||
(byte) 0x78, (byte) 0x74, (byte) 0xf3, (byte) 0x48, (byte) 0xcd,
|
||||
(byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x28, (byte) 0xcf,
|
||||
(byte) 0x2f, (byte) 0xca, (byte) 0x49, (byte) 0xe1, (byte) 0x2,
|
||||
(byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8,
|
||||
(byte) 0xd5, (byte) 0xe0, (byte) 0x39, (byte) 0xb7, (byte) 0xe,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3,
|
||||
(byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x98, (byte) 0x68, (byte) 0x62,
|
||||
(byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x54, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x6e, (byte) 0x69, (byte) 0x73, (byte) 0x2e, (byte) 0x74,
|
||||
(byte) 0x78, (byte) 0x74, (byte) 0x73, (byte) 0xf2, (byte) 0xb,
|
||||
(byte) 0x50, (byte) 0x8, (byte) 0x48, (byte) 0x2c, (byte) 0xca,
|
||||
(byte) 0x4c, (byte) 0x4a, (byte) 0x2c, (byte) 0x56, (byte) 0xf0,
|
||||
(byte) 0x2f, (byte) 0x48, (byte) 0xcd, (byte) 0x53, (byte) 0xc8,
|
||||
(byte) 0x2c, (byte) 0x56, (byte) 0x48, (byte) 0x54, (byte) 0x48,
|
||||
(byte) 0x2b, (byte) 0xcd, (byte) 0x53, (byte) 0x8, (byte) 0x49,
|
||||
(byte) 0xcd, (byte) 0xcb, (byte) 0x3, (byte) 0x72, (byte) 0x42,
|
||||
(byte) 0xf2, (byte) 0x4b, (byte) 0x8b, (byte) 0xf2, (byte) 0x12,
|
||||
(byte) 0x73, (byte) 0x53, (byte) 0xf3, (byte) 0x4a, (byte) 0x14,
|
||||
(byte) 0x4a, (byte) 0xf2, (byte) 0x15, (byte) 0xca, (byte) 0x13,
|
||||
(byte) 0x4b, (byte) 0x92, (byte) 0x33, (byte) 0xb8, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0xaa,
|
||||
(byte) 0xad, (byte) 0x14, (byte) 0xd, (byte) 0x35, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x35, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xf1, (byte) 0x79, (byte) 0x62, (byte) 0x54,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xe, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x42, (byte) 0x72, (byte) 0x75, (byte) 0x63,
|
||||
(byte) 0x65, (byte) 0x57, (byte) 0x61, (byte) 0x79, (byte) 0x6e,
|
||||
(byte) 0x65, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74,
|
||||
(byte) 0xf3, (byte) 0x54, (byte) 0x48, (byte) 0xcc, (byte) 0x55,
|
||||
(byte) 0x70, (byte) 0x4a, (byte) 0x2c, (byte) 0xc9, (byte) 0x4d,
|
||||
(byte) 0xcc, (byte) 0xe3, (byte) 0x2, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x6c, (byte) 0x70,
|
||||
(byte) 0x60, (byte) 0xbd, (byte) 0xe, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62,
|
||||
(byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0,
|
||||
(byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41,
|
||||
(byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54,
|
||||
(byte) 0xf4, (byte) 0x59, (byte) 0xdc, (byte) 0xa6, (byte) 0x42,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x42, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x3d, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d,
|
||||
(byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d,
|
||||
(byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45,
|
||||
(byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d, (byte) 0x46,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xe3, (byte) 0x34, (byte) 0x62,
|
||||
(byte) 0x54, (byte) 0xd5, (byte) 0xe0, (byte) 0x39, (byte) 0xb7,
|
||||
(byte) 0xe, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xc1, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c,
|
||||
(byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x98, (byte) 0x68, (byte) 0x62,
|
||||
(byte) 0x54, (byte) 0xaa, (byte) 0xad, (byte) 0x14, (byte) 0xd,
|
||||
(byte) 0x35, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x35,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x54, (byte) 0x65, (byte) 0x6e, (byte) 0x6e,
|
||||
(byte) 0x69, (byte) 0x73, (byte) 0x2e, (byte) 0x74, (byte) 0x78,
|
||||
(byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xf1, (byte) 0x79,
|
||||
(byte) 0x62, (byte) 0x54, (byte) 0x6c, (byte) 0x70, (byte) 0x60,
|
||||
(byte) 0xbd, (byte) 0xe, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xe,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x73, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x42, (byte) 0x72, (byte) 0x75,
|
||||
(byte) 0x63, (byte) 0x65, (byte) 0x57, (byte) 0x61, (byte) 0x79,
|
||||
(byte) 0x6e, (byte) 0x65, (byte) 0x2e, (byte) 0x74, (byte) 0x78,
|
||||
(byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5,
|
||||
(byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x28, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xbd, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Jar files used by the tests.
|
||||
* The {@code byte} array {@code VALID_ZIP_WITH_NO_COMMENTS_BYTES} is written
|
||||
* to disk to create the jar file: {@code Valid-CEN-Comment-Length.jar}.
|
||||
*
|
||||
* The jar file {@code InValid-CEN-Comment-Length.jar} is created by copying
|
||||
* the {@code byte} array {@code VALID_ZIP_WITH_NO_COMMENTS_BYTES} and modifying
|
||||
* the CEN file header comment length entry for "META-INF/MANIFEST.MF" so that
|
||||
* new comment length will forward the CEN to a subsequent CEN file header
|
||||
* entry.
|
||||
*
|
||||
* For {@code InValid-CEN-Comment-Length.jar}, the comment length is changed
|
||||
* from {@code 0x0} to the {@code 0x37}.
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
Files.deleteIfExists(VALID_CEN_COMMENT_LENGTH_JAR);
|
||||
Files.deleteIfExists(INVALID_CEN_COMMENT_LENGTH_JAR);
|
||||
// Create the valid jar
|
||||
Files.write(VALID_CEN_COMMENT_LENGTH_JAR, VALID_ZIP_WITH_NO_COMMENTS_BYTES);
|
||||
// Now create an invalid jar
|
||||
byte[] invalid_bytes = Arrays.copyOf(VALID_ZIP_WITH_NO_COMMENTS_BYTES,
|
||||
VALID_ZIP_WITH_NO_COMMENTS_BYTES.length);
|
||||
// Change CEN file Header comment length so that the length will
|
||||
// result in the offset pointing to a subsequent CEN file header
|
||||
// resulting in an invalid comment
|
||||
invalid_bytes[536] = 55;
|
||||
Files.write(INVALID_CEN_COMMENT_LENGTH_JAR, invalid_bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up after the test run
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@AfterAll
|
||||
public static void cleanup() throws IOException {
|
||||
Files.deleteIfExists(VALID_CEN_COMMENT_LENGTH_JAR);
|
||||
Files.deleteIfExists(INVALID_CEN_COMMENT_LENGTH_JAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the original(valid) Jar file can be opened by {@code ZipFile}
|
||||
* and the expected Zip entry can be found
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void ZipFileValidCommentLengthTest() throws IOException {
|
||||
try (ZipFile jf = new ZipFile(VALID_CEN_COMMENT_LENGTH_JAR.toFile())) {
|
||||
ZipEntry ze = jf.getEntry(META_INF_MANIFEST_MF);
|
||||
assertNotNull(ze);
|
||||
assertEquals(META_INF_MANIFEST_MF, ze.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the original(valid) Jar file can be opened by {@code JarFile}
|
||||
* and the expected Zip entry can be found
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void JarFileValidCommentLengthTest() throws IOException {
|
||||
try (JarFile jf = new JarFile(VALID_CEN_COMMENT_LENGTH_JAR.toFile())) {
|
||||
ZipEntry ze = jf.getEntry(META_INF_MANIFEST_MF);
|
||||
assertNotNull(ze);
|
||||
assertEquals(META_INF_MANIFEST_MF, ze.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ZipException is thrown when the CEN file header comment
|
||||
* length is non-zero and the CEN entry does not contain a comment when
|
||||
* the Jar file is opened by {@code ZipFile}
|
||||
*/
|
||||
@Test
|
||||
public void ZipFileInValidCommentLengthTest() {
|
||||
var ex= assertThrows(ZipException.class,
|
||||
() -> new ZipFile(INVALID_CEN_COMMENT_LENGTH_JAR.toFile()));
|
||||
assertEquals(INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT, ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ZipException is thrown when the CEN file header comment
|
||||
* length is non-zero and the CEN entry does not contain a comment when
|
||||
* the Jar file is opened by {@code JarFile}
|
||||
*/
|
||||
@Test
|
||||
public void JarFileInValidCommentLengthTest() {
|
||||
var ex= assertThrows(ZipException.class,
|
||||
() -> new JarFile(INVALID_CEN_COMMENT_LENGTH_JAR.toFile()));
|
||||
assertEquals(INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT, ex.getMessage());
|
||||
}
|
||||
}
|
||||
124
test/jdk/java/util/zip/ZipFile/InvalidCompressedSizeTest.java
Normal file
124
test/jdk/java/util/zip/ZipFile/InvalidCompressedSizeTest.java
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HexFormat;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8358456
|
||||
* @summary verify that ZipFile.getInputStream(ZipFile) doesn't throw an unspecified exception
|
||||
* for invalid compressed size of an entry
|
||||
* @run junit InvalidCompressedSizeTest
|
||||
*/
|
||||
class InvalidCompressedSizeTest {
|
||||
|
||||
private static final String ENTRY_NAME = "foo-bar";
|
||||
private static final byte[] ENTRY_CONTENT = new byte[]{0x42, 0x42};
|
||||
|
||||
// created through a call to createZIPContent()
|
||||
private static final String ZIP_CONTENT_HEX = """
|
||||
504b03041400080808005053c35a00000000000000000000000007000000666f6f2d6261727
|
||||
3720200504b0708c41f441b0400000002000000504b010214001400080808005053c35ac41f
|
||||
441b0400000002000000070000000000000000000000000000000000666f6f2d626172504b0
|
||||
506000000000100010035000000390000000000
|
||||
""";
|
||||
|
||||
|
||||
// 0039 CENTRAL HEADER #1 02014B50
|
||||
// ...
|
||||
// 0043 Compression Method 0008 'Deflated'
|
||||
// ...
|
||||
// 004D Compressed Length 00000004
|
||||
// 0051 Uncompressed Length 00000002
|
||||
// ...
|
||||
// 0067 Filename 'foo-bar'
|
||||
// this is the offset in the ZIP content stream for the compressed size field
|
||||
// for the entry of interest
|
||||
private static final int COMP_SIZE_OFFSET = 0x004D;
|
||||
|
||||
// intentionally unused but left here to allow for constructing newer/updated
|
||||
// ZIP_CONTENT_HEX, when necessary
|
||||
private static String createZIPContent() throws IOException {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (final ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
final ZipEntry ze = new ZipEntry(ENTRY_NAME);
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(ENTRY_CONTENT);
|
||||
zos.closeEntry();
|
||||
}
|
||||
return HexFormat.of().formatHex(baos.toByteArray());
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls ZipFile.getInputStream(ZipEntry) on a ZIP entry whose compressed size is
|
||||
* intentionally set to 0. The test then verifies that the call to getInputStream()
|
||||
* doesn't throw an unspecified exception.
|
||||
*/
|
||||
@Test
|
||||
void testInvalidCompressedSize() throws Exception {
|
||||
final byte[] originalZIPContent = HexFormat.of().parseHex(ZIP_CONTENT_HEX.replace("\n", ""));
|
||||
final ByteBuffer zipContent = ByteBuffer.wrap(originalZIPContent).order(LITTLE_ENDIAN);
|
||||
|
||||
// overwrite the compressed size value in the entry's CEN to an invalid value of 0
|
||||
zipContent.position(COMP_SIZE_OFFSET);
|
||||
final int invalidCompressedSize = 0;
|
||||
zipContent.putInt(invalidCompressedSize);
|
||||
zipContent.rewind();
|
||||
|
||||
// write out the ZIP content so that it can be read through ZipFile
|
||||
final Path zip = Files.createTempFile(Path.of("."), "8358456-", ".zip");
|
||||
Files.write(zip, zipContent.array());
|
||||
System.out.println("created ZIP " + zip + " with an invalid compressed size for entry");
|
||||
|
||||
try (final ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
final ZipEntry entry = zf.getEntry(ENTRY_NAME);
|
||||
assertNotNull(entry, "missing entry " + ENTRY_NAME + " in ZIP file " + zip);
|
||||
// verify that we are indeed testing a ZIP file with an invalid
|
||||
// compressed size for the entry
|
||||
assertEquals(0, entry.getCompressedSize(), "unexpected compressed size");
|
||||
// merely open and close the InputStream to exercise the code which
|
||||
// would incorrectly raise an exception. we don't read the contents
|
||||
// of the stream because we have (intentionally) corrupted the metadata
|
||||
// of the ZIP and that will cause the reading to fail.
|
||||
try (final InputStream is = zf.getInputStream(entry)) {
|
||||
System.out.println("successfully opened input stream " + is
|
||||
+ " for entry " + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
159
test/jdk/java/util/zip/ZipFile/LargeZipFile.java
Normal file
159
test/jdk/java/util/zip/ZipFile/LargeZipFile.java
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class LargeZipFile {
|
||||
// If true, don't delete large ZIP file created for test.
|
||||
static final boolean debug = System.getProperty("debug") != null;
|
||||
|
||||
static final int DATA_LEN = 1024 * 1024;
|
||||
static final int DATA_SIZE = 8;
|
||||
|
||||
static long fileSize = 3L * 1024L * 1024L * 1024L; // 3GB
|
||||
|
||||
static boolean userFile = false;
|
||||
|
||||
static byte[] data;
|
||||
static File largeFile;
|
||||
static String lastEntryName;
|
||||
|
||||
/* args can be empty, in which case check a 3 GB file which is created for
|
||||
* this test (and then deleted). Or it can be a number, in which case
|
||||
* that designates the size of the file that's created for this test (and
|
||||
* then deleted). Or it can be the name of a file to use for the test, in
|
||||
* which case it is *not* deleted. Note that in this last case, the data
|
||||
* comparison might fail.
|
||||
*/
|
||||
static void realMain (String[] args) throws Throwable {
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
fileSize = Long.parseLong(args[0]);
|
||||
System.out.println("Testing with file of size " + fileSize);
|
||||
} catch (NumberFormatException ex) {
|
||||
largeFile = new File(args[0]);
|
||||
if (!largeFile.exists()) {
|
||||
throw new Exception("Specified file " + args[0] + " does not exist");
|
||||
}
|
||||
userFile = true;
|
||||
System.out.println("Testing with user-provided file " + largeFile);
|
||||
}
|
||||
}
|
||||
File testDir = null;
|
||||
if (largeFile == null) {
|
||||
testDir = new File(System.getProperty("test.scratch", "."),
|
||||
"LargeZip");
|
||||
if (testDir.exists()) {
|
||||
if (!testDir.delete()) {
|
||||
throw new Exception("Cannot delete already-existing test directory");
|
||||
}
|
||||
}
|
||||
check(!testDir.exists() && testDir.mkdirs());
|
||||
largeFile = new File(testDir, "largezip.zip");
|
||||
createLargeZip();
|
||||
}
|
||||
|
||||
readLargeZip();
|
||||
|
||||
if (!userFile && !debug) {
|
||||
check(largeFile.delete());
|
||||
check(testDir.delete());
|
||||
}
|
||||
}
|
||||
|
||||
static void createLargeZip() throws Throwable {
|
||||
int iterations = DATA_LEN / DATA_SIZE;
|
||||
ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
bb.putDouble(0, Math.random());
|
||||
baos.write(bb.array(), 0, DATA_SIZE);
|
||||
}
|
||||
data = baos.toByteArray();
|
||||
try (FileOutputStream fos = new FileOutputStream(largeFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos))
|
||||
{
|
||||
long length = 0;
|
||||
while (length < fileSize) {
|
||||
ZipEntry ze = new ZipEntry("entry-" + length);
|
||||
lastEntryName = ze.getName();
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(data, 0, data.length);
|
||||
zos.closeEntry();
|
||||
length = largeFile.length();
|
||||
}
|
||||
System.out.println("Last entry written is " + lastEntryName);
|
||||
}
|
||||
}
|
||||
|
||||
static void readLargeZip() throws Throwable {
|
||||
try (ZipFile zipFile = new ZipFile(largeFile)) {
|
||||
ZipEntry entry = null;
|
||||
String entryName = null;
|
||||
int count = 0;
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
entry = entries.nextElement();
|
||||
entryName = entry.getName();
|
||||
count++;
|
||||
}
|
||||
System.out.println("Number of entries read: " + count);
|
||||
System.out.println("Last entry read is " + entryName);
|
||||
check(!entry.isDirectory());
|
||||
if (check(entryName.equals(lastEntryName))) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = zipFile.getInputStream(entry);
|
||||
byte buf[] = new byte[4096];
|
||||
int len;
|
||||
while ((len = is.read(buf)) >= 0) {
|
||||
baos.write(buf, 0, len);
|
||||
}
|
||||
baos.close();
|
||||
is.close();
|
||||
check(Arrays.equals(data, baos.toByteArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- 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;}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
108
test/jdk/java/util/zip/ZipFile/ManyEntries.java
Normal file
108
test/jdk/java/util/zip/ZipFile/ManyEntries.java
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2011, 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.
|
||||
*
|
||||
* 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 4770745 4828461
|
||||
* @summary open zip files with more than 64k entries
|
||||
* @run main/timeout=600 ManyEntries
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.io.*;
|
||||
|
||||
public class ManyEntries {
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean runMoreTests = args.length > 0;
|
||||
int[] sizes = (runMoreTests ?
|
||||
new int[]{1, 2, 42, 65534, 65535, 65536, 65537, 68000} :
|
||||
new int[]{1, 2, 42, 68000});
|
||||
int[] methods = {ZipEntry.STORED, ZipEntry.DEFLATED};
|
||||
|
||||
for (int size : sizes)
|
||||
for (int method : methods)
|
||||
test(size, method);
|
||||
}
|
||||
|
||||
// JDK doesn't like having zip file contents changed at runtime
|
||||
static int uniquifier = 42;
|
||||
|
||||
static void test(int N, int method) throws Exception {
|
||||
System.out.println("N="+N+", method="+method);
|
||||
long time = System.currentTimeMillis() / 2000 * 2000;
|
||||
CRC32 crc32 = new CRC32();
|
||||
File zipFile = new File(++uniquifier + ".zip");
|
||||
try {
|
||||
zipFile.delete();
|
||||
try (FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos))
|
||||
{
|
||||
for (int i = 0; i < N; i++) {
|
||||
ZipEntry e = new ZipEntry("DIR/"+i);
|
||||
e.setMethod(method);
|
||||
e.setTime(time);
|
||||
if (method == ZipEntry.STORED) {
|
||||
e.setSize(1);
|
||||
crc32.reset();
|
||||
crc32.update((byte)i);
|
||||
e.setCrc(crc32.getValue());
|
||||
} else {
|
||||
e.setSize(0);
|
||||
e.setCrc(0);
|
||||
}
|
||||
zos.putNextEntry(e);
|
||||
zos.write(i);
|
||||
}
|
||||
}
|
||||
|
||||
try (ZipFile zip = new ZipFile(zipFile)) {
|
||||
if (! (zip.size() == N))
|
||||
throw new Exception("Bad ZipFile size: " + zip.size());
|
||||
Enumeration entries = zip.entries();
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (i % 1000 == 0) {System.gc(); System.runFinalization();}
|
||||
if (! (entries.hasMoreElements()))
|
||||
throw new Exception("only " + i + " elements");
|
||||
ZipEntry e = (ZipEntry)entries.nextElement();
|
||||
if (! (e.getSize() == 1))
|
||||
throw new Exception("bad size: " + e.getSize());
|
||||
if (! (e.getName().equals("DIR/" + i)))
|
||||
throw new Exception("bad name: " + i);
|
||||
if (! (e.getMethod() == method))
|
||||
throw new Exception("getMethod="+e.getMethod()+", method=" + method);
|
||||
if (! (e.getTime() == time))
|
||||
throw new Exception("getTime="+e.getTime()+", time=" + time);
|
||||
if (! (zip.getInputStream(e).read() == (i & 0xff)))
|
||||
throw new Exception("Bad file contents: " + i);
|
||||
}
|
||||
if (entries.hasMoreElements())
|
||||
throw new Exception("too many elements");
|
||||
}
|
||||
} finally {
|
||||
zipFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
139
test/jdk/java/util/zip/ZipFile/ManyZipFiles.java
Normal file
139
test/jdk/java/util/zip/ZipFile/ManyZipFiles.java
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2012, 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.
|
||||
*
|
||||
* 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 6423026
|
||||
* @summary Check that it is possible to open more than 2,048 zip files on
|
||||
* Windows.
|
||||
*/
|
||||
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class ManyZipFiles {
|
||||
static final int numFiles = 3000;
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
// Linux does not yet allow opening this many files; Solaris
|
||||
// 8 requires an explicit allocation of more file descriptors
|
||||
// to succeed. Since this test is written to check for a
|
||||
// Windows capability it is much simpler to only run it
|
||||
// on that platform.
|
||||
String osName = System.getProperty("os.name");
|
||||
if (!(osName.startsWith("Windows"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create some zip data
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
ZipEntry ze = new ZipEntry("test");
|
||||
zos.putNextEntry(ze);
|
||||
byte[] hello = "hello, world".getBytes("ASCII");
|
||||
zos.write(hello, 0, hello.length);
|
||||
zos.closeEntry();
|
||||
zos.finish();
|
||||
}
|
||||
byte[] data = baos.toByteArray();
|
||||
|
||||
ZipFile zips[] = new ZipFile[numFiles];
|
||||
|
||||
try {
|
||||
// Create a directory for zip files created below
|
||||
File tmpdir = new File(
|
||||
System.getProperty("java.io.tmpdir")
|
||||
+ File.separator + "ManyZipFiles");
|
||||
if (tmpdir.exists() && !tmpdir.isDirectory()) {
|
||||
fail(tmpdir.getAbsolutePath()
|
||||
+ " already exists but is not a directory");
|
||||
return;
|
||||
}
|
||||
if (!tmpdir.exists()) {
|
||||
if (!tmpdir.mkdirs()) {
|
||||
fail("Couldn't create directory "
|
||||
+ tmpdir.getAbsolutePath() + " for test files");
|
||||
return;
|
||||
}
|
||||
} else if (!tmpdir.canWrite()) {
|
||||
fail("Don't have write access for directory "
|
||||
+ tmpdir.getAbsolutePath() + " for test files");
|
||||
return;
|
||||
}
|
||||
tmpdir.deleteOnExit();
|
||||
|
||||
// Create and then open a large number of zip files
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
File f = File.createTempFile("test", ".zip", tmpdir);
|
||||
f.deleteOnExit();
|
||||
try (FileOutputStream fos = new FileOutputStream(f)) {
|
||||
fos.write(data, 0, data.length);
|
||||
}
|
||||
try {
|
||||
zips[i] = new ZipFile(f);
|
||||
} catch (Throwable t) {
|
||||
fail("Failed to open zip file #" + i + " named "
|
||||
+ zips[i].getName());
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// This finally block is due to bug 4171239. On Windows, if the
|
||||
// file is still open at the end of the VM, deleteOnExit won't
|
||||
// take place. "new ZipFile(...)" opens the zip file, so we have
|
||||
// to explicitly close those opened above. This finally block can
|
||||
// be removed when 4171239 is fixed. See also 6357433, against which
|
||||
// 4171239 was closed as a duplicate.
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
if (zips[i] != null) {
|
||||
try {
|
||||
zips[i].close();
|
||||
} catch (Throwable t) {
|
||||
fail("At zip[" + i + "] named " + zips[i].getName()
|
||||
+ " caught " + t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pass();
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {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 check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
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");}
|
||||
}
|
||||
816
test/jdk/java/util/zip/ZipFile/MissingZIP64EntriesTest.java
Normal file
816
test/jdk/java/util/zip/ZipFile/MissingZIP64EntriesTest.java
Normal file
|
|
@ -0,0 +1,816 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/* @test
|
||||
* @bug 8314891
|
||||
* @summary Validate that a ZipException is thrown when the extra len is 0
|
||||
* and the CEN size, csize,LOC offset fields are set to 0xFFFFFFFF, the disk
|
||||
* starting number is set to 0xFFFF or when we have a valid Zip64 Extra header
|
||||
* size but missing the expected header fields.
|
||||
* @run junit MissingZIP64EntriesTest
|
||||
*/
|
||||
public class MissingZIP64EntriesTest {
|
||||
|
||||
/*
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with only the size field.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x57116922 [Thu Aug 17 13:09:04 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0x16
|
||||
* 0x65: Uncompressed Size: 0xffffffff
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0xc
|
||||
* Extra data:[01, 00, 08, 00, 14, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=8]
|
||||
* ->ZIP64: size *0x14
|
||||
* [data= 14 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0x0
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZIP64_EXTRAHDR_SIZE_ONLY_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x22, (byte) 0x69, (byte) 0x11, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x22, (byte) 0x69, (byte) 0x11, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a Zip file with no extra header fields
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x2f: Signature : 0x02014b50
|
||||
* 0x33: Created Zip Spec : 0x14 [2.0]
|
||||
* 0x34: Created OS : 0x3 [UNIX]
|
||||
* 0x35: VerMadeby : 0x314 [3, 2.0]
|
||||
* 0x36: VerExtract : 0x14 [2.0]
|
||||
* 0x37: Flag : 0x2
|
||||
* 0x39: Method : 0x8 [DEFLATED]
|
||||
* 0x3b: Last Mod Time : 0x57039c0d [Thu Aug 03 19:32:26 EDT 2023]
|
||||
* 0x3f: CRC : 0x31963516
|
||||
* 0x43: Compressed Size : 0x8
|
||||
* 0x47: Uncompressed Size: 0x6
|
||||
* 0x4b: Name Length : 0x9
|
||||
* 0x4d: Extra Length : 0x0
|
||||
* 0x4f: Comment Length : 0x0
|
||||
* 0x51: Disk Start : 0x0
|
||||
* 0x53: Attrs : 0x1
|
||||
* 0x55: AttrsEx : 0x81a40000
|
||||
* 0x59: Loc Header Offset: 0x0
|
||||
* 0x5d: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x2, (byte) 0x0,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xd, (byte) 0x9c, (byte) 0x3, (byte) 0x57, (byte) 0x16, (byte) 0x35,
|
||||
(byte) 0x96, (byte) 0x31, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0xe7, (byte) 0x2, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x3, (byte) 0x14, (byte) 0x0, (byte) 0x2,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0xd, (byte) 0x9c, (byte) 0x3, (byte) 0x57, (byte) 0x16,
|
||||
(byte) 0x35, (byte) 0x96, (byte) 0x31, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa4,
|
||||
(byte) 0x81, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c,
|
||||
(byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x37, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2f, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with only the LOC offset field.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x572d69c5 [Wed Sep 13 13:14:10 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0x16
|
||||
* 0x65: Uncompressed Size: 0x14
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0xc
|
||||
* Extra data:[01, 00, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=8]
|
||||
* ->ZIP64: LOC Off *0x0
|
||||
* [data= 00 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0xffffffff
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZIP64_EXTRAHDR_LOC_ONLY_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xc5, (byte) 0x69, (byte) 0x2d, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xc5, (byte) 0x69, (byte) 0x2d, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with only the compressed size field.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x572d6960 [Wed Sep 13 13:11:00 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0xffffffff
|
||||
* 0x65: Uncompressed Size: 0x14
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0xc
|
||||
* Extra data:[01, 00, 08, 00, 16, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=8]
|
||||
* ->ZIP64: csize *0x16
|
||||
* [data= 16 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0x0
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZIP64_EXTRAHDR_CSIZE_ONLY_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x69, (byte) 0x2d, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x60, (byte) 0x69, (byte) 0x2d, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x14, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a Zip file with a zero length ZIP64 Extra Header
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x43: Signature : 0x02014b50
|
||||
* 0x47: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x48: Created OS : 0x3 [UNIX]
|
||||
* 0x49: VerMadeby : 0x32d [3, 4.5]
|
||||
* 0x4a: VerExtract : 0x2d [4.5]
|
||||
* 0x4b: Flag : 0x800
|
||||
* 0x4d: Method : 0x8 [DEFLATED]
|
||||
* 0x4f: Last Mod Time : 0x572c3477 [Tue Sep 12 06:35:46 EDT 2023]
|
||||
* 0x53: CRC : 0x31963516
|
||||
* 0x57: Compressed Size : 0x8
|
||||
* 0x5b: Uncompressed Size: 0x6
|
||||
* 0x5f: Name Length : 0x9
|
||||
* 0x61: Extra Length : 0x4
|
||||
* Extra data:[01, 00, 00, 00]
|
||||
* [tag=0x0001, sz=0]
|
||||
* ->ZIP64:
|
||||
* 0x63: Comment Length : 0x0
|
||||
* 0x65: Disk Start : 0x0
|
||||
* 0x67: Attrs : 0x0
|
||||
* 0x69: AttrsEx : 0x81a40000
|
||||
* 0x6d: Loc Header Offset: 0x0
|
||||
* 0x71: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZEROLEN_ZIP64_EXTRAHDR_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x77, (byte) 0x34, (byte) 0x2c, (byte) 0x57, (byte) 0x16, (byte) 0x35,
|
||||
(byte) 0x96, (byte) 0x31, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xf3, (byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9,
|
||||
(byte) 0xe7, (byte) 0x2, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d,
|
||||
(byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x77,
|
||||
(byte) 0x34, (byte) 0x2c, (byte) 0x57, (byte) 0x16, (byte) 0x35, (byte) 0x96, (byte) 0x31, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9,
|
||||
(byte) 0x0, (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa4, (byte) 0x81, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74,
|
||||
(byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x6, (byte) 0x6, (byte) 0x2c, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3b, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x43, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x6, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x7e, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x3b, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with the size and csize fields.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x572c6445 [Tue Sep 12 12:34:10 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0xffffffff
|
||||
* 0x65: Uncompressed Size: 0xffffffff
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0x14
|
||||
* Extra data:[01, 00, 10, 00, 14, 00, 00, 00, 00, 00, 00, 00, 16, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=16]
|
||||
* ->ZIP64: size *0x14 csize *0x16
|
||||
* [data= 14 00 00 00 00 00 00 00 16 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0x0
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_TWO_ZIP64_HEADER_ENTRIES_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x45, (byte) 0x64, (byte) 0x2c, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x45, (byte) 0x64, (byte) 0x2c, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x4b, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with the size,csize, and LOC offset fields.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x572d7214 [Wed Sep 13 14:16:40 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0xffffffff
|
||||
* 0x65: Uncompressed Size: 0xffffffff
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0x1c
|
||||
* Extra data:[01, 00, 18, 00, 14, 00, 00, 00, 00, 00, 00, 00, 16, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=24]
|
||||
* ->ZIP64: size *0x14 csize *0x16 LOC Off *0x0
|
||||
* [data= 14 00 00 00 00 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0xffffffff
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZIP64_EXTRAHDR_ALL_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x14, (byte) 0x72, (byte) 0x2d, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x72, (byte) 0x2d, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x1c, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x18, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x53, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable debug output
|
||||
*/
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Name of the Zip file that we create from the byte array
|
||||
*/
|
||||
public static final String ZIPFILE_NAME = "validZipFile.zip";
|
||||
|
||||
/**
|
||||
* Name of the Zip file that we modify/corrupt
|
||||
*/
|
||||
public static final String BAD_ZIP_NAME = "zipWithInvalidZip64ExtraField.zip";
|
||||
|
||||
/**
|
||||
* Zip file entry that will be accessed by some the tests
|
||||
*/
|
||||
private static final String ZIP_FILE_ENTRY_NAME = "Hello.txt";
|
||||
|
||||
/**
|
||||
* Expected Error messages
|
||||
*/
|
||||
private static final String INVALID_EXTRA_LENGTH =
|
||||
"Invalid CEN header (invalid zip64 extra len size)";
|
||||
|
||||
private static final String INVALID_ZIP64_EXTRAHDR_SIZE =
|
||||
"Invalid CEN header (invalid zip64 extra data field size)";
|
||||
|
||||
/**
|
||||
* Disk starting number offset for the Zip file created from the
|
||||
* ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY array
|
||||
*/
|
||||
private static final int DISKNO_OFFSET_ZIP_NO_EXTRA_LEN = 0x51;
|
||||
|
||||
/**
|
||||
* Value to set the size, csize, or LOC offset CEN fields to when their
|
||||
* actual value is stored in the Zip64 Extra Header
|
||||
*/
|
||||
private static final long ZIP64_MAGICVAL = 0xFFFFFFFFL;
|
||||
|
||||
/**
|
||||
* Value to set the Disk Start number offset CEN field to when the
|
||||
* actual value is stored in the Zip64 Extra Header
|
||||
*/
|
||||
private static final int ZIP64_MAGICCOUNT = 0xFFFF;
|
||||
|
||||
/**
|
||||
* Copy of the byte array for the ZIP to be modified by a given test run
|
||||
*/
|
||||
private byte[] zipArrayCopy;
|
||||
|
||||
/**
|
||||
* Little-endian ByteBuffer for manipulating the ZIP copy
|
||||
*/
|
||||
private ByteBuffer buffer;
|
||||
|
||||
/**
|
||||
* The MethodSource returning a byte array representing the Zip file,
|
||||
* CEN offsets to set to 0xFFFFFFFF and the expected
|
||||
* ZipException error message when there are missing Zip64 Extra header fields
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> InvalidZip64MagicValues() {
|
||||
return Stream.of(
|
||||
// Byte array representing the Zip file, compressed size offset,
|
||||
// and expected ZipException Message
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_SIZE_ONLY_BYTEARRAY,
|
||||
0x61, INVALID_ZIP64_EXTRAHDR_SIZE),
|
||||
// Byte array representing the Zip file, LOC offset and expected ZipException Message
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_SIZE_ONLY_BYTEARRAY,
|
||||
0x77, INVALID_ZIP64_EXTRAHDR_SIZE),
|
||||
// Byte array representing the Zip file, LOC offset and expected ZipException Message
|
||||
Arguments.of(ZIP_WITH_TWO_ZIP64_HEADER_ENTRIES_BYTEARRAY,
|
||||
0x77, INVALID_ZIP64_EXTRAHDR_SIZE)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The MethodSource of CEN offsets to set to 0xFFFFFFFF or 0xFFFF when the Extra Length
|
||||
* size is 0 for the Zip file created using ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> MissingZip64ExtraFieldEntries() {
|
||||
return Stream.of(
|
||||
// Compressed size offset
|
||||
Arguments.of(0x43),
|
||||
// Size offset
|
||||
Arguments.of(0x47),
|
||||
// Disk start number offset
|
||||
Arguments.of(DISKNO_OFFSET_ZIP_NO_EXTRA_LEN),
|
||||
// LOC offset
|
||||
Arguments.of(0x59)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The MethodSource of CEN offsets to set to 0xFFFFFFFF when the ZIP64 extra header
|
||||
* Length size is 0 for the Zip file created using
|
||||
* ZIP_WITH_ZEROLEN_ZIP64_EXTRAHDR_BYTEARRAY
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> zip64ZeroLenHeaderExtraFieldEntries() {
|
||||
return Stream.of(
|
||||
// Compressed size offset
|
||||
Arguments.of(0x57),
|
||||
// Size offset
|
||||
Arguments.of(0x5b),
|
||||
// LOC offset
|
||||
Arguments.of(0x6d)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The MethodSource which will return a byte array representing a
|
||||
* valid Zip file and the expected content for the Zip file entry 'Hello.txt'.
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> validZipFiles() {
|
||||
return Stream.of(
|
||||
// Byte array representing the Zip file, and the expected entry content
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_SIZE_ONLY_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_TWO_ZIP64_HEADER_ENTRIES_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_LOC_ONLY_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_CSIZE_ONLY_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_ALL_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY,
|
||||
"Hello\n")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial test setup
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
Files.deleteIfExists(Path.of(ZIPFILE_NAME));
|
||||
Files.deleteIfExists(Path.of(BAD_ZIP_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the Zip file that will be modified by each test
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void beforeEachTestRun() throws IOException {
|
||||
Files.deleteIfExists(Path.of(ZIPFILE_NAME));
|
||||
Files.deleteIfExists(Path.of(BAD_ZIP_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a ZipException is thrown by ZipFile if the Zip64 header
|
||||
* does not contain the required field
|
||||
* @param zipArray Byte array representing the Zip file
|
||||
* @param offset Offset of the CEN Header field to set to 0xFFFFFFFF
|
||||
* @param errorMessage Expected ZipException error message
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("InvalidZip64MagicValues")
|
||||
public void invalidZip64ExtraHeaderZipFileTest(byte[] zipArray, int offset,
|
||||
String errorMessage) throws IOException {
|
||||
// Set the CEN csize or LOC offset field to 0xFFFFFFFF. There will not
|
||||
// be the expected Zip64 Extra Header field resulting in a ZipException
|
||||
// being thrown
|
||||
zipArrayCopy = zipArray.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFile(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(errorMessage),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a ZipException is thrown by Zip FS if the Zip64 header
|
||||
* does not contain the required field
|
||||
* @param zipArray Byte array representing the Zip file
|
||||
* @param offset Offset of the CEN Header field to set to 0xFFFFFFFF
|
||||
* @param errorMessage Expected ZipException error message
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("InvalidZip64MagicValues")
|
||||
public void invalidZip64ExtraHeaderZipFSTest(byte[] zipArray, int offset,
|
||||
String errorMessage) throws IOException {
|
||||
// Set the CEN csize or LOC offset field to 0xFFFFFFFF. There will not
|
||||
// be the expected Zip64 Extra Header field resulting in a ZipException
|
||||
// being thrown
|
||||
zipArrayCopy = zipArray.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(offset, (int)ZIP64_MAGICVAL);
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFS(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(errorMessage),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile will throw a ZipException if the CEN
|
||||
* Extra length is 0 and the CEN size, csize, LOC offset field is set to
|
||||
* 0xFFFFFFFF or the disk starting number is set to 0xFFFF
|
||||
* @param offset Offset of the CEN Header field to set to 0xFFFFFFFF or 0xFFFF
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("MissingZip64ExtraFieldEntries")
|
||||
public void zipFileBadExtraLength(int offset) throws IOException {
|
||||
zipArrayCopy = ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
if (offset == DISKNO_OFFSET_ZIP_NO_EXTRA_LEN) {
|
||||
buffer.putShort(offset, (short) ZIP64_MAGICCOUNT);
|
||||
} else {
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
}
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFile(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(INVALID_EXTRA_LENGTH),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFS will throw a ZipException if the CEN
|
||||
* Extra length is 0 and the CEN size, csize, LOC offset field is set to
|
||||
* 0xFFFFFFFF or the disk starting number is set to 0xFFFF
|
||||
* @param offset the offset of the CEN Header field to set to 0xFFFFFFFF or 0xFFFF
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("MissingZip64ExtraFieldEntries")
|
||||
public void zipFSBadExtraLength(int offset) throws IOException {
|
||||
zipArrayCopy = ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
if (offset == DISKNO_OFFSET_ZIP_NO_EXTRA_LEN) {
|
||||
buffer.putShort(offset, (short) ZIP64_MAGICCOUNT);
|
||||
} else {
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
}
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFS(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(INVALID_EXTRA_LENGTH),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile will throw a ZipException if the ZIP64 extra header
|
||||
* has a size of 0 and the CEN size, csize, or the LOC offset field is set to
|
||||
* 0xFFFFFFFF
|
||||
* @param offset the offset of the CEN Header field to set to 0xFFFFFFFF
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("zip64ZeroLenHeaderExtraFieldEntries")
|
||||
public void zipFileZeroLenExtraHeader(int offset) throws IOException {
|
||||
zipArrayCopy = ZIP_WITH_ZEROLEN_ZIP64_EXTRAHDR_BYTEARRAY.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFile(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(INVALID_ZIP64_EXTRAHDR_SIZE),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFS will throw a ZipException if the ZIP64 extra header
|
||||
* has a size of 0 and the CEN size, csize, or the LOC offset field is set to
|
||||
* 0xFFFFFFFF
|
||||
* @param offset the offset of the CEN Header field to set to 0xFFFFFFFF
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("zip64ZeroLenHeaderExtraFieldEntries")
|
||||
public void zipFSZeroLenExtraHeader(int offset) throws IOException {
|
||||
zipArrayCopy = ZIP_WITH_ZEROLEN_ZIP64_EXTRAHDR_BYTEARRAY.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFS(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(INVALID_ZIP64_EXTRAHDR_SIZE),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile will read the Zip files created from the
|
||||
* byte arrays prior to modifying the arrays to check that the
|
||||
* expected ZipException is thrown.
|
||||
* @param zipFile the byte array which represents the Zip file that should
|
||||
* be opened and read successfully.
|
||||
* @param message the expected text contained within the Zip entry
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("validZipFiles")
|
||||
public void readValidZipFile(byte[] zipFile, String message) throws IOException {
|
||||
// Write out the Zip file from the byte array
|
||||
Files.write(Path.of(ZIPFILE_NAME), zipFile);
|
||||
openWithZipFile(ZIPFILE_NAME, ZIP_FILE_ENTRY_NAME, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFS will read the Zip files created from the
|
||||
* byte arrays prior to modifying the arrays to check that the
|
||||
* expected ZipException is thrown.
|
||||
* @param zipFile the byte array which represents the Zip file that should
|
||||
* be opened and read successfully.
|
||||
* @param message the expected text contained within the Zip entry
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("validZipFiles")
|
||||
public void readValidZipFileWithZipFs(byte[] zipFile, String message)
|
||||
throws IOException {
|
||||
// Write out the Zip file from the byte array
|
||||
Files.write(Path.of(ZIPFILE_NAME), zipFile);
|
||||
openWithZipFS(ZIPFILE_NAME, ZIP_FILE_ENTRY_NAME, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used to open a Zip file using ZipFile by the tests.
|
||||
* @param zipFile name of the Zip file to open
|
||||
* @param entryName Zip entry to read when the Zip file is expected to be
|
||||
* able to be opened
|
||||
* @param entryContents the expected contents for the Zip entry
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private static void openWithZipFile(String zipFile, String entryName,
|
||||
String entryContents) throws IOException {
|
||||
try (ZipFile zf = new ZipFile(zipFile)) {
|
||||
ZipEntry ze = zf.getEntry(entryName);
|
||||
try (InputStream is = zf.getInputStream(ze)) {
|
||||
String result = new String(is.readAllBytes());
|
||||
if (DEBUG) {
|
||||
var hx = HexFormat.ofDelimiter(", ").withPrefix("0x");
|
||||
System.out.printf("Error: Zip File read :%s%n[%s]%n", result,
|
||||
hx.formatHex(result.getBytes()));
|
||||
}
|
||||
// entryContents will be null when an exception is expected
|
||||
if (entryContents != null) {
|
||||
assertEquals(entryContents, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used to open a Zip file using ZipFS by the tests.
|
||||
* @param zipFile name of the Zip file to open
|
||||
* @param entryName Zip entry to read when the Zip file is expected to be
|
||||
* able to be opened
|
||||
* @param entryContents the expected contents for the Zip entry
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private static void openWithZipFS(String zipFile, String entryName,
|
||||
String entryContents) throws IOException {
|
||||
try (FileSystem fs = FileSystems.newFileSystem(
|
||||
Path.of(zipFile), Map.of())) {
|
||||
Path p = fs.getPath(entryName);
|
||||
String result = new String(Files.readAllBytes(p));
|
||||
if (DEBUG) {
|
||||
var hx = HexFormat.ofDelimiter(", ").withPrefix("0x");
|
||||
System.out.printf("Error: Zip FS read :%s%n[%s]%n", result,
|
||||
hx.formatHex(result.getBytes()));
|
||||
}
|
||||
// entryContents will be null when an exception is expected
|
||||
if (entryContents != null) {
|
||||
assertEquals(entryContents, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
103
test/jdk/java/util/zip/ZipFile/MultiThreadedReadTest.java
Normal file
103
test/jdk/java/util/zip/ZipFile/MultiThreadedReadTest.java
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2019, 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.
|
||||
*
|
||||
* 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 8038491
|
||||
* @summary Crash in ZipFile.read() when ZipFileInputStream is shared between threads
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Platform
|
||||
* jdk.test.lib.util.FileUtils
|
||||
* @run main MultiThreadedReadTest
|
||||
*/
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import jdk.test.lib.util.FileUtils;
|
||||
|
||||
public class MultiThreadedReadTest extends Thread {
|
||||
|
||||
private static final int NUM_THREADS = 10;
|
||||
private static final String ZIPFILE_NAME =
|
||||
System.currentTimeMillis() + "-bug8038491-tmp.large.zip";
|
||||
private static final String ZIPENTRY_NAME = "random.txt";
|
||||
private static InputStream is = null;
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
createZipFile();
|
||||
try (ZipFile zf = new ZipFile(new File(ZIPFILE_NAME))) {
|
||||
is = zf.getInputStream(zf.getEntry(ZIPENTRY_NAME));
|
||||
Thread[] threadArray = new Thread[NUM_THREADS];
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i] = new MultiThreadedReadTest();
|
||||
}
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i].start();
|
||||
}
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i].join();
|
||||
}
|
||||
} finally {
|
||||
long t = System.currentTimeMillis();
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(ZIPFILE_NAME));
|
||||
System.out.println("Deleting zip file took:" +
|
||||
(System.currentTimeMillis() - t) + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
private static void createZipFile() throws Exception {
|
||||
CRC32 crc32 = new CRC32();
|
||||
long t = System.currentTimeMillis();
|
||||
File zipFile = new File(ZIPFILE_NAME);
|
||||
try (FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos)) {
|
||||
ZipEntry e = new ZipEntry(ZIPENTRY_NAME);
|
||||
e.setMethod(ZipEntry.STORED);
|
||||
byte[] toWrite = "BLAH".repeat(10_000).getBytes();
|
||||
e.setTime(t);
|
||||
e.setSize(toWrite.length);
|
||||
crc32.reset();
|
||||
crc32.update(toWrite);
|
||||
e.setCrc(crc32.getValue());
|
||||
zos.putNextEntry(e);
|
||||
zos.write(toWrite);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (is.read() != -1) { }
|
||||
} catch (Exception e) {
|
||||
System.out.println("read exception:" + e);
|
||||
// Swallow any Exceptions (which are expected) - we're only interested in the crash
|
||||
}
|
||||
}
|
||||
}
|
||||
128
test/jdk/java/util/zip/ZipFile/ReadAfterClose.java
Normal file
128
test/jdk/java/util/zip/ZipFile/ReadAfterClose.java
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*
|
||||
* 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 8340684
|
||||
@summary Verify unspecified, but long-standing behavior when reading
|
||||
from an input stream obtained using ZipFile::getInputStream after
|
||||
the ZipFile has been closed.
|
||||
@run junit ReadAfterClose
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class ReadAfterClose {
|
||||
|
||||
// ZIP file used in this test
|
||||
private Path zip = Path.of("read-after-close.zip");
|
||||
|
||||
/**
|
||||
* Create a sample ZIP file for use by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
byte[] content = "hello".repeat(1000).getBytes(StandardCharsets.UTF_8);
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
{
|
||||
zo.putNextEntry(new ZipEntry("deflated.txt"));
|
||||
zo.write(content);
|
||||
}
|
||||
{
|
||||
ZipEntry entry = new ZipEntry("stored.txt");
|
||||
entry.setMethod(ZipEntry.STORED);
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(content);
|
||||
entry.setCrc(crc.getValue());
|
||||
entry.setSize(content.length);
|
||||
zo.putNextEntry(entry);
|
||||
zo.write(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce arguments with a variation of stored / deflated entries,
|
||||
* and read behavior before closing the ZipFile.
|
||||
* @return
|
||||
*/
|
||||
public static Stream<Arguments> arguments() {
|
||||
return Stream.of(
|
||||
Arguments.of("stored.txt", true),
|
||||
Arguments.of("stored.txt", false),
|
||||
Arguments.of("deflated.txt", true),
|
||||
Arguments.of("deflated.txt", false)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Attempting to read from an InputStream obtained by ZipFile.getInputStream
|
||||
* after the backing ZipFile is closed should throw IOException
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("arguments")
|
||||
public void readAfterClose(String entryName, boolean readFirst) throws IOException {
|
||||
// Retain a reference to an input stream backed by a closed ZipFile
|
||||
InputStream in;
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
in = zf.getInputStream(new ZipEntry(entryName));
|
||||
// Optionally consume a single byte from the stream before closing
|
||||
if (readFirst) {
|
||||
in.read();
|
||||
}
|
||||
}
|
||||
|
||||
assertThrows(IOException.class, () -> {
|
||||
in.read();
|
||||
});
|
||||
}
|
||||
}
|
||||
100
test/jdk/java/util/zip/ZipFile/ReadLongZipFileName.java
Normal file
100
test/jdk/java/util/zip/ZipFile/ReadLongZipFileName.java
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2024, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6374379
|
||||
* @summary Verify that we can read zip file names > 255 chars long
|
||||
* @run junit ReadLongZipFileName
|
||||
*/
|
||||
public class ReadLongZipFileName {
|
||||
private static final String ENTRY_NAME = "testFile.txt";
|
||||
private static final String LONG_DIR_NAME = "abcdefghijklmnopqrstuvwx"; // 24 chars
|
||||
private static final String JAR_FILE_NAME = "areallylargejarfilename.jar"; // 27 chars
|
||||
|
||||
/*
|
||||
* Creates a jar file at a path whose path name length and jar file name length
|
||||
* combined is large. Then use the java.util.jar.JarFile APIs to open and read the jar file
|
||||
* to verify the APIs work against those jar/zip files.
|
||||
*/
|
||||
@Test
|
||||
public void testOpenAndReadJarFile() throws Exception {
|
||||
int minRequiredPathLength = 600; // long enough to definitely fail.
|
||||
Path tmpDir = Files.createTempDirectory(Path.of("."), "ReadLongZipFileName-test")
|
||||
.normalize().toAbsolutePath();
|
||||
// Create a directory structure long enough that the filename will
|
||||
// put us over the minRequiredLength.
|
||||
int currentPathLength = 0;
|
||||
Path jarFileDir = tmpDir;
|
||||
do {
|
||||
jarFileDir = jarFileDir.resolve(LONG_DIR_NAME);
|
||||
Files.createDirectories(jarFileDir);
|
||||
currentPathLength = jarFileDir.toFile().getCanonicalPath().length();
|
||||
} while (currentPathLength < (minRequiredPathLength - JAR_FILE_NAME.length()));
|
||||
|
||||
// Create a new Jar file: use jar instead of zip to make sure long
|
||||
// names work for both zip and jar subclass.
|
||||
Path jarFilePath = jarFileDir.resolve(JAR_FILE_NAME);
|
||||
System.out.println("creating a jar file at " + jarFilePath);
|
||||
try (JarOutputStream out = new JarOutputStream(
|
||||
new BufferedOutputStream(Files.newOutputStream(jarFilePath)))) {
|
||||
out.putNextEntry(new JarEntry(ENTRY_NAME));
|
||||
out.write(1);
|
||||
}
|
||||
assertTrue(Files.isRegularFile(jarFilePath),
|
||||
"jar file " + jarFilePath + " does not exist or is not a file");
|
||||
|
||||
try (JarFile readJarFile = new JarFile(jarFilePath.toFile())) {
|
||||
JarEntry je = readJarFile.getJarEntry(ENTRY_NAME);
|
||||
assertNotNull(je, "missing jar entry: " + ENTRY_NAME + " in jar file " + jarFilePath);
|
||||
DataInputStream dis = new DataInputStream(readJarFile.getInputStream(je));
|
||||
byte val = dis.readByte();
|
||||
assertEquals(1, val, "unexpected byte " + val + " read from entry " + ENTRY_NAME);
|
||||
try {
|
||||
dis.readByte();
|
||||
Assertions.fail("Read past expected EOF");
|
||||
} catch (IOException e) {
|
||||
// expected
|
||||
System.out.println("received the expected exception: " + e);
|
||||
}
|
||||
}
|
||||
System.out.println("Successfully opened and read contents from a jar file with a name "
|
||||
+ jarFilePath.toFile().getCanonicalPath().length() + " characters long");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,934 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Formatter;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/* @test
|
||||
* @bug 8313765
|
||||
* @summary Validate that a Zip File with an Extra Header with a data size
|
||||
* of 0 can be read.
|
||||
* @run junit ReadNonStandardExtraHeadersTest
|
||||
*/
|
||||
public class ReadNonStandardExtraHeadersTest {
|
||||
|
||||
/*
|
||||
* Byte array holding a ZIP file which contains an
|
||||
* Extra field header which has a data size of 0.
|
||||
*
|
||||
* ---------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x664: Signature : 0x02014b50
|
||||
* 0x668: Created Zip Spec : 0xa [1.0]
|
||||
* 0x669: Created OS : 0x0 [MS-DOS]
|
||||
* 0x66a: VerMadeby : 0xa [0, 1.0]
|
||||
* 0x66b: VerExtract : 0xa [1.0]
|
||||
* 0x66c: Flag : 0x800
|
||||
* 0x66e: Method : 0x0 [STORED]
|
||||
* 0x670: Last Mod Time : 0x385ca437 [Thu Feb 28 20:33:46 EST 2008]
|
||||
* 0x674: CRC : 0x694c6952
|
||||
* 0x678: Compressed Size : 0x624
|
||||
* 0x67c: Uncompressed Size: 0x624
|
||||
* 0x680: Name Length : 0x1b
|
||||
* 0x682: Extra Length : 0x7
|
||||
* ->[tag=cafe, size=0]
|
||||
* 0x684: Comment Length : 0x0
|
||||
* 0x686: Disk Start : 0x0
|
||||
* 0x688: Attrs : 0x0
|
||||
* 0x68a: AttrsEx : 0x0
|
||||
* 0x68e: Loc Header Offset: 0x0
|
||||
* 0x692: File Name : res/drawable/size_48x48.jpg
|
||||
*
|
||||
* [Local File Header]
|
||||
* 0x0: Signature : 0x04034b50
|
||||
* 0x4: Version : 0xa [1.0]
|
||||
* 0x6: Flag : 0x800
|
||||
* 0x8: Method : 0x0 [STORED]
|
||||
* 0xa: LastMTime : 0x385ca437 [Thu Feb 28 20:33:46 EST 2008]
|
||||
* 0xe: CRC : 0x694c6952
|
||||
* 0x12: CSize : 0x624
|
||||
* 0x16: Size : 0x624
|
||||
* 0x1a: Name Length : 0x1b [res/drawable/size_48x48.jpg]
|
||||
* 0x1c: ExtraLength : 0x7
|
||||
* ->[tag=cafe, size=0]
|
||||
* 0x1e: File Name : [res/drawable/size_48x48.jpg]
|
||||
* [End Central Directory Header]
|
||||
* Signature : 0x06054b50
|
||||
* ENDCEN Off : 0x6b4
|
||||
* Disk Entries: 0x1
|
||||
* Total Entries: 0x1
|
||||
* CEN Size : 0x50
|
||||
* Offset CEN : 0x664
|
||||
* Comment Len : 0x0 []
|
||||
*/
|
||||
public static byte[] VALID_APK_FILE = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0xa, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x37, (byte) 0xa4, (byte) 0x5c, (byte) 0x38, (byte) 0x52, (byte) 0x69,
|
||||
(byte) 0x4c, (byte) 0x69, (byte) 0x24, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x24, (byte) 0x6,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x1b, (byte) 0x0, (byte) 0x7, (byte) 0x0, (byte) 0x72, (byte) 0x65,
|
||||
(byte) 0x73, (byte) 0x2f, (byte) 0x64, (byte) 0x72, (byte) 0x61, (byte) 0x77, (byte) 0x61, (byte) 0x62,
|
||||
(byte) 0x6c, (byte) 0x65, (byte) 0x2f, (byte) 0x73, (byte) 0x69, (byte) 0x7a, (byte) 0x65, (byte) 0x5f,
|
||||
(byte) 0x34, (byte) 0x38, (byte) 0x78, (byte) 0x34, (byte) 0x38, (byte) 0x2e, (byte) 0x6a, (byte) 0x70,
|
||||
(byte) 0x67, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xff, (byte) 0xd8, (byte) 0xff, (byte) 0xe0, (byte) 0x0, (byte) 0x10, (byte) 0x4a, (byte) 0x46,
|
||||
(byte) 0x49, (byte) 0x46, (byte) 0x0, (byte) 0x1, (byte) 0x1, (byte) 0x1, (byte) 0x0, (byte) 0x48,
|
||||
(byte) 0x0, (byte) 0x48, (byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xfe, (byte) 0x0, (byte) 0x16,
|
||||
(byte) 0x28, (byte) 0x63, (byte) 0x29, (byte) 0x20, (byte) 0x32, (byte) 0x30, (byte) 0x30, (byte) 0x37,
|
||||
(byte) 0x20, (byte) 0x50, (byte) 0x68, (byte) 0x69, (byte) 0x6c, (byte) 0x20, (byte) 0x44, (byte) 0x75,
|
||||
(byte) 0x62, (byte) 0x61, (byte) 0x63, (byte) 0x68, (byte) 0xff, (byte) 0xdb, (byte) 0x0, (byte) 0x43,
|
||||
(byte) 0x0, (byte) 0x6, (byte) 0x4, (byte) 0x5, (byte) 0x6, (byte) 0x5, (byte) 0x4, (byte) 0x6,
|
||||
(byte) 0x6, (byte) 0x5, (byte) 0x6, (byte) 0x7, (byte) 0x7, (byte) 0x6, (byte) 0x8, (byte) 0xa,
|
||||
(byte) 0x10, (byte) 0xa, (byte) 0xa, (byte) 0x9, (byte) 0x9, (byte) 0xa, (byte) 0x14, (byte) 0xe,
|
||||
(byte) 0xf, (byte) 0xc, (byte) 0x10, (byte) 0x17, (byte) 0x14, (byte) 0x18, (byte) 0x18, (byte) 0x17,
|
||||
(byte) 0x14, (byte) 0x16, (byte) 0x16, (byte) 0x1a, (byte) 0x1d, (byte) 0x25, (byte) 0x1f, (byte) 0x1a,
|
||||
(byte) 0x1b, (byte) 0x23, (byte) 0x1c, (byte) 0x16, (byte) 0x16, (byte) 0x20, (byte) 0x2c, (byte) 0x20,
|
||||
(byte) 0x23, (byte) 0x26, (byte) 0x27, (byte) 0x29, (byte) 0x2a, (byte) 0x29, (byte) 0x19, (byte) 0x1f,
|
||||
(byte) 0x2d, (byte) 0x30, (byte) 0x2d, (byte) 0x28, (byte) 0x30, (byte) 0x25, (byte) 0x28, (byte) 0x29,
|
||||
(byte) 0x28, (byte) 0xff, (byte) 0xdb, (byte) 0x0, (byte) 0x43, (byte) 0x1, (byte) 0x7, (byte) 0x7,
|
||||
(byte) 0x7, (byte) 0xa, (byte) 0x8, (byte) 0xa, (byte) 0x13, (byte) 0xa, (byte) 0xa, (byte) 0x13,
|
||||
(byte) 0x28, (byte) 0x1a, (byte) 0x16, (byte) 0x1a, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0xff, (byte) 0xc0,
|
||||
(byte) 0x0, (byte) 0x11, (byte) 0x8, (byte) 0x0, (byte) 0x30, (byte) 0x0, (byte) 0x30, (byte) 0x3,
|
||||
(byte) 0x1, (byte) 0x11, (byte) 0x0, (byte) 0x2, (byte) 0x11, (byte) 0x1, (byte) 0x3, (byte) 0x11,
|
||||
(byte) 0x1, (byte) 0xff, (byte) 0xc4, (byte) 0x0, (byte) 0x1b, (byte) 0x0, (byte) 0x0, (byte) 0x2,
|
||||
(byte) 0x2, (byte) 0x3, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4, (byte) 0x5,
|
||||
(byte) 0x6, (byte) 0x7, (byte) 0x1, (byte) 0x3, (byte) 0x8, (byte) 0x2, (byte) 0xff, (byte) 0xc4,
|
||||
(byte) 0x0, (byte) 0x2e, (byte) 0x10, (byte) 0x0, (byte) 0x2, (byte) 0x2, (byte) 0x1, (byte) 0x2,
|
||||
(byte) 0x4, (byte) 0x4, (byte) 0x5, (byte) 0x4, (byte) 0x3, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x2, (byte) 0x3, (byte) 0x4, (byte) 0x11,
|
||||
(byte) 0x0, (byte) 0x5, (byte) 0x6, (byte) 0x12, (byte) 0x21, (byte) 0x31, (byte) 0x41, (byte) 0x51,
|
||||
(byte) 0x61, (byte) 0x71, (byte) 0x7, (byte) 0x13, (byte) 0x22, (byte) 0x42, (byte) 0x91, (byte) 0x33,
|
||||
(byte) 0x62, (byte) 0x81, (byte) 0xa1, (byte) 0x52, (byte) 0xd1, (byte) 0xf0, (byte) 0xff, (byte) 0xc4,
|
||||
(byte) 0x0, (byte) 0x1b, (byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x5, (byte) 0x1, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x2, (byte) 0x3, (byte) 0x4, (byte) 0x5,
|
||||
(byte) 0x7, (byte) 0x1, (byte) 0x0, (byte) 0xff, (byte) 0xc4, (byte) 0x0, (byte) 0x33, (byte) 0x11,
|
||||
(byte) 0x0, (byte) 0x1, (byte) 0x3, (byte) 0x2, (byte) 0x4, (byte) 0x4, (byte) 0x4, (byte) 0x4,
|
||||
(byte) 0x5, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x2, (byte) 0x3, (byte) 0x4, (byte) 0x11, (byte) 0x5, (byte) 0x12,
|
||||
(byte) 0x21, (byte) 0x31, (byte) 0x13, (byte) 0x51, (byte) 0x61, (byte) 0x71, (byte) 0x6, (byte) 0x32,
|
||||
(byte) 0x41, (byte) 0x81, (byte) 0x91, (byte) 0xa1, (byte) 0xb1, (byte) 0xc1, (byte) 0x7, (byte) 0x14,
|
||||
(byte) 0x42, (byte) 0xd1, (byte) 0xf0, (byte) 0x22, (byte) 0x33, (byte) 0x62, (byte) 0xa2, (byte) 0xf1,
|
||||
(byte) 0xff, (byte) 0xda, (byte) 0x0, (byte) 0xc, (byte) 0x3, (byte) 0x1, (byte) 0x0, (byte) 0x2,
|
||||
(byte) 0x11, (byte) 0x3, (byte) 0x11, (byte) 0x0, (byte) 0x3f, (byte) 0x0, (byte) 0xb4, (byte) 0x11,
|
||||
(byte) 0xf4, (byte) 0x4c, (byte) 0xa, (byte) 0x12, (byte) 0x7b, (byte) 0x16, (byte) 0x2e, (byte) 0x5d,
|
||||
(byte) 0xaf, (byte) 0x46, (byte) 0xac, (byte) 0x96, (byte) 0x6e, (byte) 0xcf, (byte) 0x1c, (byte) 0x10,
|
||||
(byte) 0x46, (byte) 0x32, (byte) 0xd2, (byte) 0x48, (byte) 0xd8, (byte) 0x3, (byte) 0x48, (byte) 0x96,
|
||||
(byte) 0x46, (byte) 0x44, (byte) 0xd2, (byte) 0xf7, (byte) 0x9b, (byte) 0x0, (byte) 0x91, (byte) 0x5,
|
||||
(byte) 0x24, (byte) 0xd5, (byte) 0x52, (byte) 0x8, (byte) 0x60, (byte) 0x69, (byte) 0x73, (byte) 0x8e,
|
||||
(byte) 0xc0, (byte) 0x6f, (byte) 0xfc, (byte) 0xfa, (byte) 0x28, (byte) 0x26, (byte) 0xe5, (byte) 0xf1,
|
||||
(byte) 0x5f, (byte) 0x6b, (byte) 0x82, (byte) 0x52, (byte) 0x9b, (byte) 0x7d, (byte) 0x3b, (byte) 0x17,
|
||||
(byte) 0x0, (byte) 0x38, (byte) 0xe7, (byte) 0x62, (byte) 0x22, (byte) 0x53, (byte) 0xea, (byte) 0x32,
|
||||
(byte) 0x9, (byte) 0xfc, (byte) 0x81, (byte) 0xaa, (byte) 0x19, (byte) 0xfc, (byte) 0x43, (byte) 0x13,
|
||||
(byte) 0xd, (byte) 0xa3, (byte) 0x69, (byte) 0x77, (byte) 0xcb, (byte) 0xf7, (byte) 0x47, (byte) 0xb4,
|
||||
(byte) 0x1f, (byte) 0x86, (byte) 0x95, (byte) 0xd3, (byte) 0xb7, (byte) 0x35, (byte) 0x4c, (byte) 0xad,
|
||||
(byte) 0x8f, (byte) 0xa5, (byte) 0xb3, (byte) 0x1f, (byte) 0x7d, (byte) 0x40, (byte) 0xf8, (byte) 0x12,
|
||||
(byte) 0x8a, (byte) 0xd9, (byte) 0x7e, (byte) 0x26, (byte) 0x6d, (byte) 0xb7, (byte) 0x98, (byte) 0x8b,
|
||||
(byte) 0x95, (byte) 0x2c, (byte) 0xd3, (byte) 0x3, (byte) 0xbc, (byte) 0x9f, (byte) 0xaa, (byte) 0x8b,
|
||||
(byte) 0xee, (byte) 0x40, (byte) 0xc8, (byte) 0xfc, (byte) 0x6b, (byte) 0xb4, (byte) 0xf8, (byte) 0xfc,
|
||||
(byte) 0x52, (byte) 0x7f, (byte) 0x71, (byte) 0xa5, (byte) 0xbd, (byte) 0x77, (byte) 0x1e, (byte) 0xff,
|
||||
(byte) 0x0, (byte) 0xf1, (byte) 0x7b, (byte) 0x10, (byte) 0xfc, (byte) 0x34, (byte) 0xc4, (byte) 0x29,
|
||||
(byte) 0x9b, (byte) 0x9e, (byte) 0x9a, (byte) 0x46, (byte) 0xcb, (byte) 0xd3, (byte) 0xca, (byte) 0xef,
|
||||
(byte) 0x6b, (byte) 0x92, (byte) 0xf, (byte) 0xc4, (byte) 0x29, (byte) 0xd4, (byte) 0x13, (byte) 0x47,
|
||||
(byte) 0x62, (byte) 0x14, (byte) 0x9a, (byte) 0x9, (byte) 0x12, (byte) 0x58, (byte) 0x9c, (byte) 0x73,
|
||||
(byte) 0x2b, (byte) 0xa1, (byte) 0x4, (byte) 0x30, (byte) 0xf3, (byte) 0x7, (byte) 0x57, (byte) 0xac,
|
||||
(byte) 0x7b, (byte) 0x5e, (byte) 0xd0, (byte) 0xe6, (byte) 0x9b, (byte) 0x82, (byte) 0x80, (byte) 0x24,
|
||||
(byte) 0x82, (byte) 0x48, (byte) 0x1e, (byte) 0x62, (byte) 0x95, (byte) 0xa5, (byte) 0xae, (byte) 0x1a,
|
||||
(byte) 0x10, (byte) 0x45, (byte) 0x88, (byte) 0x3d, (byte) 0x42, (byte) 0xf7, (byte) 0x83, (byte) 0xae,
|
||||
(byte) 0xdd, (byte) 0x75, (byte) 0xa1, (byte) 0x2, (byte) 0xd2, (byte) 0x47, (byte) 0x1a, (byte) 0x33,
|
||||
(byte) 0xbb, (byte) 0x5, (byte) 0x45, (byte) 0x5, (byte) 0x99, (byte) 0x89, (byte) 0xc0, (byte) 0x0,
|
||||
(byte) 0x77, (byte) 0x27, (byte) 0x49, (byte) 0xce, (byte) 0x0, (byte) 0xb9, (byte) 0x53, (byte) 0xcc,
|
||||
(byte) 0x2e, (byte) 0x71, (byte) 0xb0, (byte) 0x17, (byte) 0x25, (byte) 0x73, (byte) 0xff, (byte) 0x0,
|
||||
(byte) 0x1d, (byte) 0x71, (byte) 0x54, (byte) 0xfc, (byte) 0x4f, (byte) 0xba, (byte) 0x30, (byte) 0x46,
|
||||
(byte) 0x64, (byte) 0xdb, (byte) 0x21, (byte) 0x62, (byte) 0x2b, (byte) 0xc5, (byte) 0xdb, (byte) 0x3f,
|
||||
(byte) 0xbd, (byte) 0x87, (byte) 0xf9, (byte) 0x1f, (byte) 0xe8, (byte) 0x74, (byte) 0xf3, (byte) 0xc8,
|
||||
(byte) 0x46, (byte) 0x25, (byte) 0x5e, (byte) 0xea, (byte) 0xb9, (byte) 0x3f, (byte) 0xc4, (byte) 0x6c,
|
||||
(byte) 0x3e, (byte) 0xeb, (byte) 0x6d, (byte) 0xf0, (byte) 0xbf, (byte) 0x87, (byte) 0xa3, (byte) 0xc2,
|
||||
(byte) 0xa0, (byte) 0x5, (byte) 0xc2, (byte) 0xf2, (byte) 0xbb, (byte) 0xcc, (byte) 0x7e, (byte) 0xc3,
|
||||
(byte) 0xa0, (byte) 0xf9, (byte) 0x9d, (byte) 0x79, (byte) 0x59, (byte) 0xa, (byte) 0x2e, (byte) 0x7,
|
||||
(byte) 0x4d, (byte) 0x54, (byte) 0x92, (byte) 0x8c, (byte) 0xd8, (byte) 0xdb, (byte) 0x29, (byte) 0x1f,
|
||||
(byte) 0xe, (byte) 0x55, (byte) 0xbc, (byte) 0x86, (byte) 0x69, (byte) 0xea, (byte) 0x30, (byte) 0xc,
|
||||
(byte) 0x22, (byte) 0x62, (byte) 0x63, (byte) 0x75, (byte) 0x24, (byte) 0x48, (byte) 0x83, (byte) 0xbe,
|
||||
(byte) 0x7d, (byte) 0x3b, (byte) 0x75, (byte) 0x3e, (byte) 0x24, (byte) 0xe, (byte) 0xe4, (byte) 0x69,
|
||||
(byte) 0xe8, (byte) 0xc, (byte) 0x8c, (byte) 0xbb, (byte) 0xd8, (byte) 0xa2, (byte) 0x56, (byte) 0x54,
|
||||
(byte) 0xd3, (byte) 0x87, (byte) 0x32, (byte) 0x9, (byte) 0x4e, (byte) 0xae, (byte) 0x3a, (byte) 0x5b,
|
||||
(byte) 0xd3, (byte) 0xaa, (byte) 0x7f, (byte) 0xc0, (byte) 0x7c, (byte) 0x5e, (byte) 0xdb, (byte) 0x2d,
|
||||
(byte) 0xd1, (byte) 0x5, (byte) 0xd9, (byte) 0x11, (byte) 0x36, (byte) 0xb9, (byte) 0x64, (byte) 0xc3,
|
||||
(byte) 0x87, (byte) 0x6c, (byte) 0x8, (byte) 0x89, (byte) 0xfb, (byte) 0x86, (byte) 0x7b, (byte) 0xf,
|
||||
(byte) 0x3d, (byte) 0x59, (byte) 0xe1, (byte) 0x38, (byte) 0x8b, (byte) 0xa0, (byte) 0x7e, (byte) 0x43,
|
||||
(byte) 0xe5, (byte) 0x3e, (byte) 0x9c, (byte) 0xba, (byte) 0xa1, (byte) 0x6f, (byte) 0x1b, (byte) 0x78,
|
||||
(byte) 0x6e, (byte) 0x9a, (byte) 0xbe, (byte) 0x98, (byte) 0xd5, (byte) 0x5c, (byte) 0x36, (byte) 0x66,
|
||||
(byte) 0xd, (byte) 0x9, (byte) 0xb0, (byte) 0xcd, (byte) 0x6f, (byte) 0xd2, (byte) 0x6f, (byte) 0xfe,
|
||||
(byte) 0xbc, (byte) 0x8f, (byte) 0x4b, (byte) 0xab, (byte) 0xa6, (byte) 0xad, (byte) 0x9a, (byte) 0xf7,
|
||||
(byte) 0x2b, (byte) 0xa4, (byte) 0xf4, (byte) 0xe7, (byte) 0x86, (byte) 0xc4, (byte) 0xf, (byte) 0xd5,
|
||||
(byte) 0x65, (byte) 0x85, (byte) 0xc3, (byte) 0xab, (byte) 0x7b, (byte) 0x11, (byte) 0xd0, (byte) 0xe8,
|
||||
(byte) 0xc5, (byte) 0xaf, (byte) 0xe, (byte) 0x17, (byte) 0x69, (byte) 0xba, (byte) 0xc2, (byte) 0xf2,
|
||||
(byte) 0x16, (byte) 0x9b, (byte) 0x38, (byte) 0x59, (byte) 0x40, (byte) 0x78, (byte) 0xd6, (byte) 0xf3,
|
||||
(byte) 0xa7, (byte) 0x8, (byte) 0xee, (byte) 0xe6, (byte) 0x33, (byte) 0xf5, (byte) 0x1a, (byte) 0xec,
|
||||
(byte) 0xbd, (byte) 0x3c, (byte) 0x8f, (byte) 0x43, (byte) 0xfd, (byte) 0x13, (byte) 0xaa, (byte) 0xea,
|
||||
(byte) 0xd9, (byte) 0x4f, (byte) 0x1, (byte) 0xe0, (byte) 0x72, (byte) 0x45, (byte) 0x78, (byte) 0x4c,
|
||||
(byte) 0x2d, (byte) 0xfc, (byte) 0xf4, (byte) 0x39, (byte) 0xb6, (byte) 0xcc, (byte) 0x3e, (byte) 0x5b,
|
||||
(byte) 0x7c, (byte) 0xd5, (byte) 0xb, (byte) 0x59, (byte) 0xb3, (byte) 0xa0, (byte) 0xd7, (byte) 0x85,
|
||||
(byte) 0xb5, (byte) 0x53, (byte) 0x3e, (byte) 0xe9, (byte) 0xe6, (byte) 0xc6, (byte) 0x6a, (byte) 0x35,
|
||||
(byte) 0xe4, (byte) 0x5d, (byte) 0xc1, (byte) 0x9d, (byte) 0x6b, (byte) 0xb0, (byte) 0x21, (byte) 0x9a,
|
||||
(byte) 0x3c, (byte) 0x64, (byte) 0x7a, (byte) 0x8c, (byte) 0xe9, (byte) 0xa6, (byte) 0xe5, (byte) 0x7,
|
||||
(byte) 0xfa, (byte) 0xb6, (byte) 0x53, (byte) 0xe5, (byte) 0x74, (byte) 0x9c, (byte) 0x33, (byte) 0xc2,
|
||||
(byte) 0xf3, (byte) 0x75, (byte) 0x5b, (byte) 0xa5, (byte) 0xdf, (byte) 0x61, (byte) 0xda, (byte) 0x4f,
|
||||
(byte) 0xc9, (byte) 0xb7, (byte) 0x3d, (byte) 0xc6, (byte) 0x4b, (byte) 0x32, (byte) 0x34, (byte) 0xb,
|
||||
(byte) 0x65, (byte) 0x47, (byte) 0x53, (byte) 0x0, (byte) 0xc1, (byte) 0x18, (byte) 0xcf, (byte) 0x7f,
|
||||
(byte) 0xbb, (byte) 0xa7, (byte) 0x99, (byte) 0xf5, (byte) 0x3a, (byte) 0x71, (byte) 0xb1, (byte) 0x49,
|
||||
(byte) 0x35, (byte) 0xf2, (byte) 0x1d, (byte) 0x96, (byte) 0x6f, (byte) 0x8d, (byte) 0x62, (byte) 0x2f,
|
||||
(byte) 0xa2, (byte) 0xc5, (byte) 0x44, (byte) 0xf1, (byte) 0x58, (byte) 0x90, (byte) 0xdb, (byte) 0x5b,
|
||||
(byte) 0x70, (byte) 0xe, (byte) 0xbb, (byte) 0xf5, (byte) 0x6, (byte) 0xc5, (byte) 0x19, (byte) 0xc5,
|
||||
(byte) 0xd4, (byte) 0xf6, (byte) 0xad, (byte) 0xbe, (byte) 0x18, (byte) 0x2d, (byte) 0x52, (byte) 0x13,
|
||||
(byte) 0xd9, (byte) 0x2e, (byte) 0x3, (byte) 0x27, (byte) 0x2c, (byte) 0x79, (byte) 0x3c, (byte) 0x84,
|
||||
(byte) 0x2, (byte) 0xf, (byte) 0x29, (byte) 0x39, (byte) 0xd, (byte) 0xea, (byte) 0x7d, (byte) 0x3b,
|
||||
(byte) 0x75, (byte) 0xcb, (byte) 0x70, (byte) 0xe7, (byte) 0x75, (byte) 0xe2, (byte) 0x6, (byte) 0xdc,
|
||||
(byte) 0xfd, (byte) 0x2, (byte) 0x8d, (byte) 0x84, (byte) 0xe2, (byte) 0x74, (byte) 0xfc, (byte) 0x73,
|
||||
(byte) 0x55, (byte) 0x5d, (byte) 0x1b, (byte) 0xa6, (byte) 0x94, (byte) 0xed, (byte) 0xb1, (byte) 0xb7,
|
||||
(byte) 0x60, (byte) 0x4f, (byte) 0xc3, (byte) 0x4d, (byte) 0x3d, (byte) 0x2, (byte) 0xb9, (byte) 0xf8,
|
||||
(byte) 0x3, (byte) 0x88, (byte) 0xdb, (byte) 0x88, (byte) 0xf6, (byte) 0x48, (byte) 0x67, (byte) 0x6d,
|
||||
(byte) 0xaf, (byte) 0x72, (byte) 0xa5, (byte) 0xcb, (byte) 0x1a, (byte) 0xab, (byte) 0x49, (byte) 0x6e,
|
||||
(byte) 0x25, (byte) 0x45, (byte) 0x99, (byte) 0x80, (byte) 0xc3, (byte) 0x14, (byte) 0xc3, (byte) 0x12,
|
||||
(byte) 0x46, (byte) 0x41, (byte) 0xee, (byte) 0x6, (byte) 0x8f, (byte) 0x68, (byte) 0xe7, (byte) 0x32,
|
||||
(byte) 0xc4, (byte) 0xd2, (byte) 0x79, (byte) 0x6f, (byte) 0xe8, (byte) 0x4a, (byte) 0x2, (byte) 0xc5,
|
||||
(byte) 0x29, (byte) 0x44, (byte) 0x15, (byte) 0x52, (byte) 0x34, (byte) 0x2, (byte) 0xd1, (byte) 0x72,
|
||||
(byte) 0x43, (byte) 0x48, (byte) 0xb1, (byte) 0x0, (byte) 0xea, (byte) 0x1, (byte) 0x1d, (byte) 0x88,
|
||||
(byte) 0x49, (byte) 0xae, (byte) 0xc0, (byte) 0x96, (byte) 0xea, (byte) 0x4f, (byte) 0x5a, (byte) 0x6f,
|
||||
(byte) 0xd2, (byte) 0x9a, (byte) 0x36, (byte) 0x8d, (byte) 0xbd, (byte) 0x88, (byte) 0xc1, (byte) 0xd4,
|
||||
(byte) 0x77, (byte) 0x8c, (byte) 0xcd, (byte) 0x2d, (byte) 0x3e, (byte) 0xaa, (byte) 0xce, (byte) 0x37,
|
||||
(byte) 0x18, (byte) 0x9e, (byte) 0x24, (byte) 0x6e, (byte) 0xe0, (byte) 0xdf, (byte) 0xe0, (byte) 0xb9,
|
||||
(byte) 0xfa, (byte) 0x4a, (byte) 0xf3, (byte) 0x50, (byte) 0xbd, (byte) 0x3d, (byte) 0x4b, (byte) 0x0,
|
||||
(byte) 0xac, (byte) 0xd0, (byte) 0xb9, (byte) 0x46, (byte) 0x1e, (byte) 0xa3, (byte) 0xc7, (byte) 0xdb,
|
||||
(byte) 0x42, (byte) 0xd3, (byte) 0x30, (byte) 0xb4, (byte) 0x90, (byte) 0x56, (byte) 0xaf, (byte) 0x86,
|
||||
(byte) 0xd4, (byte) 0x89, (byte) 0x58, (byte) 0x1e, (byte) 0xd3, (byte) 0xa1, (byte) 0x4c, (byte) 0x76,
|
||||
(byte) 0xe1, (byte) 0x1b, (byte) 0xdc, (byte) 0x84, (byte) 0xd9, (byte) 0x23, (byte) 0xe4, (byte) 0x2b,
|
||||
(byte) 0x7, (byte) 0x91, (byte) 0x73, (byte) 0x8e, (byte) 0x65, (byte) 0x1d, (byte) 0x48, (byte) 0xf7,
|
||||
(byte) 0x20, (byte) 0x11, (byte) 0xfc, (byte) 0xea, (byte) 0x31, (byte) 0xd1, (byte) 0x59, (byte) 0x55,
|
||||
(byte) 0x36, (byte) 0x69, (byte) 0x20, (byte) 0x73, (byte) 0x62, (byte) 0x75, (byte) 0x9c, (byte) 0x74,
|
||||
(byte) 0x1d, (byte) 0x2f, (byte) 0xa5, (byte) 0xfd, (byte) 0xb7, (byte) 0xf6, (byte) 0x52, (byte) 0x7b,
|
||||
(byte) 0xd3, (byte) 0x52, (byte) 0xde, (byte) 0x52, (byte) 0x2b, (byte) 0x97, (byte) 0xab, (byte) 0x6,
|
||||
(byte) 0x44, (byte) 0x95, (byte) 0x5a, (byte) 0x34, (byte) 0xce, (byte) 0x3e, (byte) 0x5a, (byte) 0x82,
|
||||
(byte) 0xa0, (byte) 0x9f, (byte) 0xe, (byte) 0xfd, (byte) 0x7d, (byte) 0x87, (byte) 0xe7, (byte) 0x4c,
|
||||
(byte) 0xc, (byte) 0xf1, (byte) 0x13, (byte) 0xc2, (byte) 0x36, (byte) 0xb8, (byte) 0x59, (byte) 0xdc,
|
||||
(byte) 0xf8, (byte) 0x23, (byte) 0xdd, (byte) 0x59, (byte) 0x25, (byte) 0x2d, (byte) 0x35, (byte) 0xdd,
|
||||
(byte) 0xc3, (byte) 0x0, (byte) 0x9e, (byte) 0xa7, (byte) 0x7b, (byte) 0x77, (byte) 0x20, (byte) 0xe9,
|
||||
(byte) 0xd9, (byte) 0x1, (byte) 0x7e, (byte) 0xed, (byte) 0xcd, (byte) 0xd4, (byte) 0xc5, (byte) 0x16,
|
||||
(byte) 0xcc, (byte) 0xcb, (byte) 0x60, (byte) 0xca, (byte) 0xe1, (byte) 0xd, (byte) 0x76, (byte) 0x24,
|
||||
(byte) 0x16, (byte) 0x70, (byte) 0x70, (byte) 0x1, (byte) 0xfd, (byte) 0xd8, (byte) 0xc7, (byte) 0x5f,
|
||||
(byte) 0x51, (byte) 0x9e, (byte) 0xd8, (byte) 0xd3, (byte) 0xd1, (byte) 0x42, (byte) 0x1, (byte) 0x11,
|
||||
(byte) 0xbe, (byte) 0xf7, (byte) 0x3c, (byte) 0xb9, (byte) 0xfd, (byte) 0xd5, (byte) 0x9e, (byte) 0xd,
|
||||
(byte) 0x1d, (byte) 0x4c, (byte) 0x14, (byte) 0xe7, (byte) 0x10, (byte) 0xa0, (byte) 0x94, (byte) 0x59,
|
||||
(byte) 0xb7, (byte) 0xce, (byte) 0xc7, (byte) 0xed, (byte) 0xa6, (byte) 0xfa, (byte) 0xfa, (byte) 0x5c,
|
||||
(byte) 0x6b, (byte) 0xe9, (byte) 0xd4, (byte) 0x9b, (byte) 0x2b, (byte) 0xe3, (byte) 0x82, (byte) 0x23,
|
||||
(byte) 0x9a, (byte) 0xaf, (byte) 0xc, (byte) 0xd1, (byte) 0xa9, (byte) 0x6a, (byte) 0x8c, (byte) 0xd4,
|
||||
(byte) 0x6c, (byte) 0x57, (byte) 0x4f, (byte) 0x97, (byte) 0x24, (byte) 0x32, (byte) 0xb2, (byte) 0x3f,
|
||||
(byte) 0xd5, (byte) 0xdc, (byte) 0xb0, (byte) 0x64, (byte) 0x24, (byte) 0x15, (byte) 0x24, (byte) 0x92,
|
||||
(byte) 0xe, (byte) 0x7f, (byte) 0x81, (byte) 0xa3, (byte) 0x8a, (byte) 0x48, (byte) 0xf8, (byte) 0x10,
|
||||
(byte) 0xb6, (byte) 0x2e, (byte) 0x4b, (byte) 0x3c, (byte) 0xc5, (byte) 0xaa, (byte) 0xce, (byte) 0x21,
|
||||
(byte) 0x5b, (byte) 0x25, (byte) 0x5b, (byte) 0xbf, (byte) 0x59, (byte) 0xbf, (byte) 0x61, (byte) 0xb0,
|
||||
(byte) 0x1e, (byte) 0xc0, (byte) 0x4, (byte) 0xbe, (byte) 0x6a, (byte) 0xf9, (byte) 0xce, (byte) 0x35,
|
||||
(byte) 0xe7, (byte) 0x35, (byte) 0x4b, (byte) 0x50, (byte) 0xe, (byte) 0x3c, (byte) 0xe1, (byte) 0x64,
|
||||
(byte) 0xdc, (byte) 0xe5, (byte) 0x4b, (byte) 0x35, (byte) 0xf1, (byte) 0x15, (byte) 0xe0, (byte) 0x30,
|
||||
(byte) 0x5b, (byte) 0xc2, (byte) 0x41, (byte) 0xe0, (byte) 0x1b, (byte) 0xfd, (byte) 0xff, (byte) 0x0,
|
||||
(byte) 0xc2, (byte) 0xae, (byte) 0xae, (byte) 0x97, (byte) 0x89, (byte) 0xa8, (byte) 0xdd, (byte) 0x5d,
|
||||
(byte) 0x61, (byte) 0x38, (byte) 0xb3, (byte) 0xa8, (byte) 0x8e, (byte) 0x57, (byte) 0x6a, (byte) 0xcf,
|
||||
(byte) 0xa7, (byte) 0x6f, (byte) 0xd9, (byte) 0x40, (byte) 0xdf, (byte) 0x68, (byte) 0xdc, (byte) 0xab,
|
||||
(byte) 0x37, (byte) 0x24, (byte) 0xd4, (byte) 0xa6, (byte) 0x38, (byte) 0xf1, (byte) 0x45, (byte) 0xe7,
|
||||
(byte) 0x1f, (byte) 0x91, (byte) 0xaa, (byte) 0x39, (byte) 0x29, (byte) 0x65, (byte) 0x6e, (byte) 0xed,
|
||||
(byte) 0x5a, (byte) 0x15, (byte) 0x1e, (byte) 0x37, (byte) 0x47, (byte) 0x30, (byte) 0xd2, (byte) 0x40,
|
||||
(byte) 0x3b, (byte) 0x9b, (byte) 0x7d, (byte) 0x53, (byte) 0x3d, (byte) 0xaf, (byte) 0x67, (byte) 0xdd,
|
||||
(byte) 0xf7, (byte) 0x14, (byte) 0x58, (byte) 0xaa, (byte) 0xd1, (byte) 0x9d, (byte) 0xd5, (byte) 0x49,
|
||||
(byte) 0xc1, (byte) 0x65, (byte) 0xe5, (byte) 0x51, (byte) 0x9c, (byte) 0x7d, (byte) 0xc7, (byte) 0x3,
|
||||
(byte) 0xc3, (byte) 0x4d, (byte) 0xb2, (byte) 0x92, (byte) 0x69, (byte) 0x8d, (byte) 0x98, (byte) 0xd2,
|
||||
(byte) 0xa4, (byte) 0x49, (byte) 0x89, (byte) 0x61, (byte) 0x94, (byte) 0xf, (byte) 0x7d, (byte) 0x44,
|
||||
(byte) 0x92, (byte) 0x0, (byte) 0xe7, (byte) 0xda, (byte) 0xfa, (byte) 0xdc, (byte) 0x9b, (byte) 0x6d,
|
||||
(byte) 0xa0, (byte) 0xb9, (byte) 0x56, (byte) 0x47, (byte) 0x5, (byte) 0xf0, (byte) 0x2c, (byte) 0x5b,
|
||||
(byte) 0x4d, (byte) 0x94, (byte) 0xdc, (byte) 0x37, (byte) 0x7, (byte) 0xf9, (byte) 0x97, (byte) 0x81,
|
||||
(byte) 0xe6, (byte) 0x54, (byte) 0x89, (byte) 0x8a, (byte) 0xa2, (byte) 0x1f, (byte) 0x33, (byte) 0x8c,
|
||||
(byte) 0x73, (byte) 0x1f, (byte) 0x7e, (byte) 0x9d, (byte) 0x4f, (byte) 0x7d, (byte) 0x5f, (byte) 0xd1,
|
||||
(byte) 0x61, (byte) 0xdc, (byte) 0x1b, (byte) 0x3e, (byte) 0x53, (byte) 0x72, (byte) 0x36, (byte) 0x1c,
|
||||
(byte) 0xbf, (byte) 0x9f, (byte) 0xe, (byte) 0xeb, (byte) 0x3a, (byte) 0xc7, (byte) 0xf1, (byte) 0xf8,
|
||||
(byte) 0xab, (byte) 0x9e, (byte) 0xf6, (byte) 0xd1, (byte) 0x47, (byte) 0x90, (byte) 0x3b, (byte) 0xcc,
|
||||
(byte) 0xed, (byte) 0x8b, (byte) 0xfb, (byte) 0x81, (byte) 0xa5, (byte) 0xbb, (byte) 0xdc, (byte) 0xf6,
|
||||
(byte) 0xd4, (byte) 0x2b, (byte) 0x1e, (byte) 0x26, (byte) 0xe6, (byte) 0x41, (byte) 0x9e, (byte) 0xfa,
|
||||
(byte) 0xb8, (byte) 0xe, (byte) 0xb8, (byte) 0x41, (byte) 0xce, (byte) 0x65, (byte) 0x8a, (byte) 0x5,
|
||||
(byte) 0xea, (byte) 0x83, (byte) 0xe1, (byte) 0xa7, (byte) 0x4b, (byte) 0x41, (byte) 0x56, (byte) 0x65,
|
||||
(byte) 0x2d, (byte) 0xbb, (byte) 0xb7, (byte) 0x7, (byte) 0x90, (byte) 0x12, (byte) 0x3c, (byte) 0x34,
|
||||
(byte) 0xc3, (byte) 0xa3, (byte) 0xd5, (byte) 0x26, (byte) 0xeb, (byte) 0x4c, (byte) 0x5b, (byte) 0x6c,
|
||||
(byte) 0x68, (byte) 0x73, (byte) 0xca, (byte) 0x33, (byte) 0xa4, (byte) 0xf0, (byte) 0xc0, (byte) 0x49,
|
||||
(byte) 0x25, (byte) 0x1f, (byte) 0x14, (byte) 0x41, (byte) 0x40, (byte) 0xd7, (byte) 0x53, (byte) 0x64,
|
||||
(byte) 0x22, (byte) 0x54, (byte) 0x79, (byte) 0x69, (byte) 0x4, (byte) 0xaf, (byte) 0x6, (byte) 0xa2,
|
||||
(byte) 0xe2, (byte) 0xfa, (byte) 0x53, (byte) 0xd7, (byte) 0x5d, (byte) 0x1a, (byte) 0x4, (byte) 0xd3,
|
||||
(byte) 0x85, (byte) 0xca, (byte) 0xff, (byte) 0xd9, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2,
|
||||
(byte) 0xa, (byte) 0x0, (byte) 0xa, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x37, (byte) 0xa4, (byte) 0x5c, (byte) 0x38, (byte) 0x52, (byte) 0x69, (byte) 0x4c, (byte) 0x69,
|
||||
(byte) 0x24, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x24, (byte) 0x6, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1b, (byte) 0x0, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x2f, (byte) 0x64, (byte) 0x72,
|
||||
(byte) 0x61, (byte) 0x77, (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65, (byte) 0x2f, (byte) 0x73,
|
||||
(byte) 0x69, (byte) 0x7a, (byte) 0x65, (byte) 0x5f, (byte) 0x34, (byte) 0x38, (byte) 0x78, (byte) 0x34,
|
||||
(byte) 0x38, (byte) 0x2e, (byte) 0x6a, (byte) 0x70, (byte) 0x67, (byte) 0xfe, (byte) 0xca, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x64, (byte) 0x6, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Jar file created by Apache Commons-Compress which creates
|
||||
* a CEN entry with a Zip64 extra header entry with a size of 0
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x52b: Signature : 0x02014b50
|
||||
* 0x52f: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x530: Created OS : 0x3 [UNIX]
|
||||
* 0x531: VerMadeby : 0x32d [3, 4.5]
|
||||
* 0x532: VerExtract : 0x2d [4.5]
|
||||
* 0x533: Flag : 0x800
|
||||
* 0x535: Method : 0x0 [STORED]
|
||||
* 0x537: Last Mod Time : 0x570169c0 [Tue Aug 01 13:14:00 EDT 2023]
|
||||
* 0x53b: CRC : 0x0
|
||||
* 0x53f: Compressed Size : 0x0
|
||||
* 0x543: Uncompressed Size: 0x0
|
||||
* 0x547: Name Length : 0x9
|
||||
* 0x549: Extra Length : 0x8
|
||||
* [tag=0x0001, sz=0, data= ]
|
||||
* ->ZIP64:
|
||||
* [tag=0xcafe, sz=0, data= ]
|
||||
* ->[tag=cafe, size=0]
|
||||
* 0x54b: Comment Length : 0x0
|
||||
* 0x54d: Disk Start : 0x0
|
||||
* 0x54f: Attrs : 0x0
|
||||
* 0x551: AttrsEx : 0x41ed0010
|
||||
* 0x555: Loc Header Offset: 0x0
|
||||
* 0x559: File Name : META-INF/
|
||||
*/
|
||||
public static byte[] COMMONS_COMPRESS_JAR = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xc0, (byte) 0x69, (byte) 0x1, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x18, (byte) 0x0, (byte) 0x4d, (byte) 0x45,
|
||||
(byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xbd, (byte) 0x69, (byte) 0x1, (byte) 0x57, (byte) 0x71, (byte) 0xa7, (byte) 0x16,
|
||||
(byte) 0x53, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54,
|
||||
(byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d, (byte) 0x41,
|
||||
(byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d,
|
||||
(byte) 0x46, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x68, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5b, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xf3, (byte) 0x4d, (byte) 0xcc,
|
||||
(byte) 0xcb, (byte) 0x4c, (byte) 0x4b, (byte) 0x2d, (byte) 0x2e, (byte) 0xd1, (byte) 0xd, (byte) 0x4b,
|
||||
(byte) 0x2d, (byte) 0x2a, (byte) 0xce, (byte) 0xcc, (byte) 0xcf, (byte) 0xb3, (byte) 0x52, (byte) 0x30,
|
||||
(byte) 0xd4, (byte) 0x33, (byte) 0xe0, (byte) 0xe5, (byte) 0x72, (byte) 0xcc, (byte) 0x43, (byte) 0x12,
|
||||
(byte) 0x71, (byte) 0x2c, (byte) 0x48, (byte) 0x4c, (byte) 0xce, (byte) 0x48, (byte) 0x55, (byte) 0x0,
|
||||
(byte) 0x8a, (byte) 0x1, (byte) 0x25, (byte) 0xd, (byte) 0xd, (byte) 0xf4, (byte) 0x2c, (byte) 0x78,
|
||||
(byte) 0xb9, (byte) 0x9c, (byte) 0x8b, (byte) 0x52, (byte) 0x13, (byte) 0x4b, (byte) 0x52, (byte) 0x53,
|
||||
(byte) 0x74, (byte) 0x9d, (byte) 0x2a, (byte) 0x81, (byte) 0x1a, (byte) 0x2c, (byte) 0xf4, (byte) 0xc,
|
||||
(byte) 0xf4, (byte) 0x80, (byte) 0x12, (byte) 0xda, (byte) 0x46, (byte) 0xba, (byte) 0x66, (byte) 0xa,
|
||||
(byte) 0x1a, (byte) 0xfe, (byte) 0x45, (byte) 0x89, (byte) 0xc9, (byte) 0x39, (byte) 0xa9, (byte) 0xa,
|
||||
(byte) 0xce, (byte) 0xf9, (byte) 0x45, (byte) 0x5, (byte) 0xf9, (byte) 0x45, (byte) 0x89, (byte) 0x25,
|
||||
(byte) 0x40, (byte) 0x3, (byte) 0x34, (byte) 0x79, (byte) 0xb9, (byte) 0x78, (byte) 0xb9, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x61, (byte) 0x69, (byte) 0x1, (byte) 0x57, (byte) 0x16, (byte) 0x64,
|
||||
(byte) 0x9c, (byte) 0xc5, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x19, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x5a, (byte) 0x69,
|
||||
(byte) 0x70, (byte) 0x46, (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x50, (byte) 0x72, (byte) 0x6f,
|
||||
(byte) 0x70, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x79, (byte) 0x54, (byte) 0x65, (byte) 0x73,
|
||||
(byte) 0x74, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xf, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x85, (byte) 0x55, (byte) 0xcf, (byte) 0x53, (byte) 0xdb,
|
||||
(byte) 0x46, (byte) 0x14, (byte) 0xfe, (byte) 0xd6, (byte) 0x3f, (byte) 0x90, (byte) 0x2d, (byte) 0x8b,
|
||||
(byte) 0x38, (byte) 0x36, (byte) 0x21, (byte) 0xc1, (byte) 0x34, (byte) 0x4, (byte) 0x12, (byte) 0x70,
|
||||
(byte) 0x63, (byte) 0xb0, (byte) 0x8d, (byte) 0xdb, (byte) 0x42, (byte) 0xd3, (byte) 0x36, (byte) 0xa6,
|
||||
(byte) 0xf9, (byte) 0x45, (byte) 0x42, (byte) 0xb, (byte) 0x35, (byte) 0xe0, (byte) 0x62, (byte) 0x87,
|
||||
(byte) 0xd4, (byte) 0xa4, (byte) 0x6d, (byte) 0x22, (byte) 0xdb, (byte) 0x4a, (byte) 0x22, (byte) 0x2a,
|
||||
(byte) 0x4b, (byte) 0x1a, (byte) 0x49, (byte) 0x2e, (byte) 0x49, (byte) 0x67, (byte) 0x7a, (byte) 0xe8,
|
||||
(byte) 0x4c, (byte) 0xcf, (byte) 0x9d, (byte) 0x69, (byte) 0xfe, (byte) 0x82, (byte) 0xde, (byte) 0x38,
|
||||
(byte) 0xf5, (byte) 0x40, (byte) 0xe, (byte) 0x86, (byte) 0x94, (byte) 0x49, (byte) 0x73, (byte) 0xcb,
|
||||
(byte) 0x21, (byte) 0xff, (byte) 0x51, (byte) 0x2f, (byte) 0xa5, (byte) 0x6f, (byte) 0x25, (byte) 0xc0,
|
||||
(byte) 0x86, (byte) 0x98, (byte) 0x29, (byte) 0xcc, (byte) 0x68, (byte) 0x77, (byte) 0xdf, (byte) 0xee,
|
||||
(byte) 0xf7, (byte) 0xbd, (byte) 0xf7, (byte) 0xbe, (byte) 0xf7, (byte) 0x76, (byte) 0xfd, (byte) 0xf6,
|
||||
(byte) 0xdf, (byte) 0xbf, (byte) 0xfe, (byte) 0x6, (byte) 0x70, (byte) 0xb, (byte) 0xf, (byte) 0x45,
|
||||
(byte) 0xf8, (byte) 0xe0, (byte) 0x17, (byte) 0x10, (byte) 0x90, (byte) 0x10, (byte) 0x44, (byte) 0xf,
|
||||
(byte) 0xc3, (byte) 0xe9, (byte) 0x75, (byte) 0xf9, (byte) 0x47, (byte) 0x39, (byte) 0xa7, (byte) 0xc9,
|
||||
(byte) 0xfa, (byte) 0xe3, (byte) 0xdc, (byte) 0x72, (byte) 0x75, (byte) 0x5d, (byte) 0xa9, (byte) 0x39,
|
||||
(byte) 0xc, (byte) 0x3d, (byte) 0x33, (byte) 0xaa, (byte) 0xae, (byte) 0x3a, (byte) 0xd7, (byte) 0x18,
|
||||
(byte) 0xfc, (byte) 0xa9, (byte) 0xf1, (byte) 0x55, (byte) 0x1, (byte) 0x21, (byte) 0x86, (byte) 0xbe,
|
||||
(byte) 0x35, (byte) 0xd5, (byte) 0x9c, (byte) 0x53, (byte) 0x35, (byte) 0xa5, (byte) 0x68, (byte) 0x19,
|
||||
(byte) 0xa6, (byte) 0x62, (byte) 0x39, (byte) 0xcf, (byte) 0xca, (byte) 0x8a, (byte) 0xed, (byte) 0x88,
|
||||
(byte) 0x10, (byte) 0xe0, (byte) 0xe7, (byte) 0x9f, (byte) 0x88, (byte) 0x4, (byte) 0x89, (byte) 0x33,
|
||||
(byte) 0x9d, (byte) 0xb2, (byte) 0x14, (byte) 0xb9, (byte) 0x5e, (byte) 0x52, (byte) 0xf5, (byte) 0xc7,
|
||||
(byte) 0x9a, (byte) 0xc2, (byte) 0xcf, (byte) 0xa, (byte) 0x38, (byte) 0xc5, (byte) 0xd0, (byte) 0xef,
|
||||
(byte) 0xb2, (byte) 0x37, (byte) 0x1d, (byte) 0x55, (byte) 0xcb, (byte) 0xfd, (byte) 0xa4, (byte) 0x9a,
|
||||
(byte) 0xb9, (byte) 0x7d, (byte) 0x9a, (byte) 0x10, (byte) 0x4e, (byte) 0x33, (byte) 0x64, (byte) 0x72,
|
||||
(byte) 0x77, (byte) 0x6d, (byte) 0xc5, (byte) 0xb2, (byte) 0x73, (byte) 0xda, (byte) 0xba, (byte) 0xac,
|
||||
(byte) 0xd7, (byte) 0xf9, (byte) 0xe4, (byte) 0xb6, (byte) 0xb1, (byte) 0xa1, (byte) 0x6b, (byte) 0x86,
|
||||
(byte) 0x5c, (byte) 0xb7, (byte) 0x73, (byte) 0x1b, (byte) 0xb5, (byte) 0x29, (byte) 0xab, (byte) 0x6e,
|
||||
(byte) 0xca, (byte) 0xe4, (byte) 0x48, (byte) 0x53, (byte) 0xab, (byte) 0xf6, (byte) 0xe4, (byte) 0xba,
|
||||
(byte) 0x6c, (byte) 0x89, (byte) 0xe8, (byte) 0x45, (byte) 0x9c, (byte) 0x47, (byte) 0xdc, (byte) 0x47,
|
||||
(byte) 0x9c, (byte) 0xa9, (byte) 0x42, (byte) 0x3b, (byte) 0xe6, (byte) 0x92, (byte) 0x63, (byte) 0x91,
|
||||
(byte) 0xc7, (byte) 0xfc, (byte) 0xf8, (byte) 0x6a, (byte) 0x18, (byte) 0xfd, (byte) 0x38, (byte) 0x2b,
|
||||
(byte) 0xe0, (byte) 0x9c, (byte) 0x84, (byte) 0x1, (byte) 0x24, (byte) 0x8e, (byte) 0xa4, (byte) 0x55,
|
||||
(byte) 0x7a, (byte) 0x66, (byte) 0x3b, (byte) 0x4a, (byte) 0x83, (byte) 0xb2, (byte) 0x31, (byte) 0x9a,
|
||||
(byte) 0x94, (byte) 0x5c, (byte) 0xbf, (byte) 0x7, (byte) 0x56, (byte) 0x8d, (byte) 0x5c, (byte) 0x91,
|
||||
(byte) 0x90, (byte) 0xe, (byte) 0xe1, (byte) 0x15, (byte) 0xb9, (byte) 0x91, (byte) 0xf, (byte) 0xe1,
|
||||
(byte) 0x3d, (byte) 0xc2, (byte) 0xf0, (byte) 0xd8, (byte) 0x46, (byte) 0x92, (byte) 0xf6, (byte) 0x8,
|
||||
(byte) 0x25, (byte) 0xa9, (byte) 0x2b, (byte) 0xf5, (byte) 0xa4, (byte) 0x2e, (byte) 0x62, (byte) 0x8,
|
||||
(byte) 0x17, (byte) 0x4, (byte) 0xc, (byte) 0x4b, (byte) 0x18, (byte) 0xc1, (byte) 0x45, (byte) 0x52,
|
||||
(byte) 0xa1, (byte) 0xb, (byte) 0x92, (byte) 0xd4, (byte) 0x32, (byte) 0xf9, (byte) 0xea, (byte) 0x11,
|
||||
(byte) 0xc3, (byte) 0x4c, (byte) 0x97, (byte) 0xb8, (byte) 0xee, (byte) 0x17, (byte) 0x8e, (byte) 0xcb,
|
||||
(byte) 0x9b, (byte) 0x1f, (byte) 0xef, (byte) 0x1a, (byte) 0x0, (byte) 0x4f, (byte) 0x70, (byte) 0x54,
|
||||
(byte) 0xc2, (byte) 0x18, (byte) 0x17, (byte) 0x32, (byte) 0x58, (byte) 0xd3, (byte) 0xc, (byte) 0x9b,
|
||||
(byte) 0xf4, (byte) 0x7b, (byte) 0xff, (byte) 0xc0, (byte) 0xa5, (byte) 0xb, (byte) 0x2f, (byte) 0x3f,
|
||||
(byte) 0xb1, (byte) 0x8c, (byte) 0xd, (byte) 0xb9, (byte) 0xaa, (byte) 0x29, (byte) 0x22, (byte) 0x92,
|
||||
(byte) 0x48, (byte) 0x49, (byte) 0x18, (byte) 0xc7, (byte) 0x4, (byte) 0x43, (byte) 0xaf, (byte) 0x5c,
|
||||
(byte) 0xaf, (byte) 0x97, (byte) 0x9a, (byte) 0xa6, (byte) 0x69, (byte) 0x29, (byte) 0xb6, (byte) 0xad,
|
||||
(byte) 0xd4, (byte) 0x19, (byte) 0x6, (byte) 0x3a, (byte) 0x63, (byte) 0x38, (byte) 0x44, (byte) 0xe4,
|
||||
(byte) 0x79, (byte) 0x19, (byte) 0x33, (byte) 0x1d, (byte) 0x9, (byte) 0xcc, (byte) 0x2f, (byte) 0xdf,
|
||||
(byte) 0x79, (byte) 0x5a, (byte) 0x53, (byte) 0x4c, (byte) 0x47, (byte) 0x35, (byte) 0x74, (byte) 0x1,
|
||||
(byte) 0x93, (byte) 0xc, (byte) 0x83, (byte) 0x6d, (byte) 0xd0, (byte) 0x4a, (byte) 0x53, (byte) 0x77,
|
||||
(byte) 0xd4, (byte) 0x86, (byte) 0x72, (byte) 0xb8, (byte) 0x2f, (byte) 0x22, (byte) 0x8b, (byte) 0xf,
|
||||
(byte) 0xb8, (byte) 0xf2, (byte) 0x13, (byte) 0x2, (byte) 0x3e, (byte) 0x3a, (byte) 0xaa, (byte) 0xab,
|
||||
(byte) 0x9b, (byte) 0x62, (byte) 0x4, (byte) 0xd3, (byte) 0xf8, (byte) 0x58, (byte) 0xc0, (byte) 0x15,
|
||||
(byte) 0x9, (byte) 0x9f, (byte) 0xe0, (byte) 0x53, (byte) 0x86, (byte) 0xb8, (byte) 0xbb, (byte) 0xaf,
|
||||
(byte) 0x93, (byte) 0x8f, (byte) 0x47, (byte) 0x24, (byte) 0x66, (byte) 0xae, (byte) 0x28, (byte) 0x3b,
|
||||
(byte) 0x4f, (byte) 0x18, (byte) 0x7c, (byte) 0x6, (byte) 0xc9, (byte) 0x93, (byte) 0xff, (byte) 0x1f,
|
||||
(byte) 0x79, (byte) 0xe, (byte) 0x2a, (byte) 0x59, (byte) 0x78, (byte) 0x97, (byte) 0x21, (byte) 0x1f,
|
||||
(byte) 0xc1, (byte) 0x55, (byte) 0xe4, (byte) 0x5, (byte) 0xcc, (byte) 0x70, (byte) 0x27, (byte) 0x9f,
|
||||
(byte) 0x53, (byte) 0xd6, (byte) 0xed, (byte) 0xae, (byte) 0x5a, (byte) 0x94, (byte) 0x4d, (byte) 0x86,
|
||||
(byte) 0x58, (byte) 0x6a, (byte) 0x1f, (byte) 0x75, (byte) 0x60, (byte) 0x22, (byte) 0x39, (byte) 0xaf,
|
||||
(byte) 0xe3, (byte) 0x86, (byte) 0x80, (byte) 0x9b, (byte) 0x12, (byte) 0x75, (byte) 0xfc, (byte) 0x2c,
|
||||
(byte) 0x43, (byte) 0xe2, (byte) 0x28, (byte) 0x27, (byte) 0xaf, (byte) 0xb3, (byte) 0xd7, (byte) 0x15,
|
||||
(byte) 0x36, (byte) 0x91, (byte) 0xe9, (byte) 0xca, (byte) 0x46, (byte) 0xdb, (byte) 0xc0, (byte) 0x70,
|
||||
(byte) 0x3d, (byte) 0xd5, (byte) 0x2d, (byte) 0x82, (byte) 0x63, (byte) 0xfc, (byte) 0xc7, (byte) 0xa3,
|
||||
(byte) 0x6c, (byte) 0x13, (byte) 0x50, (byte) 0x2b, (byte) 0xdd, (byte) 0x61, (byte) 0x88, (byte) 0x74,
|
||||
(byte) 0x74, (byte) 0x11, (byte) 0x57, (byte) 0xe8, (byte) 0xb, (byte) 0x9, (byte) 0x5f, (byte) 0x62,
|
||||
(byte) 0x9e, (byte) 0xee, (byte) 0x88, (byte) 0x63, (byte) 0xdc, (byte) 0xac, (byte) 0xda, (byte) 0x86,
|
||||
(byte) 0xd6, (byte) 0x74, (byte) 0x14, (byte) 0x4f, (byte) 0x9a, (byte) 0xb3, (byte) 0xa9, (byte) 0x13,
|
||||
(byte) 0x12, (byte) 0x9e, (byte) 0xc6, (byte) 0x57, (byte) 0x12, (byte) 0xa, (byte) 0x58, (byte) 0x64,
|
||||
(byte) 0x8, (byte) 0x39, (byte) 0x86, (byte) 0xa7, (byte) 0xd, (byte) 0xc3, (byte) 0x99, (byte) 0x83,
|
||||
(byte) 0xd3, (byte) 0x9d, (byte) 0x8a, (byte) 0x89, (byte) 0x58, (byte) 0xc6, (byte) 0xa8, (byte) 0x80,
|
||||
(byte) 0x22, (byte) 0x55, (byte) 0xff, (byte) 0xa4, (byte) 0xa0, (byte) 0x42, (byte) 0x58, (byte) 0xa1,
|
||||
(byte) 0x22, (byte) 0x27, (byte) 0x75, (byte) 0xfe, (byte) 0x3f, (byte) 0x46, (byte) 0x7f, (byte) 0xbc,
|
||||
(byte) 0xc9, (byte) 0x97, (byte) 0x96, (byte) 0xcb, (byte) 0x1d, (byte) 0x8d, (byte) 0x9e, (byte) 0x46,
|
||||
(byte) 0x59, (byte) 0xc2, (byte) 0x5d, (byte) 0xde, (byte) 0x7d, (byte) 0x51, (byte) 0xd3, (byte) 0x6b,
|
||||
(byte) 0x4b, (byte) 0xb9, (byte) 0xf6, (byte) 0x43, (byte) 0xd9, (byte) 0x92, (byte) 0x6b, (byte) 0xa,
|
||||
(byte) 0x5, (byte) 0xb0, (byte) 0x36, (byte) 0x5f, (byte) 0x7c, (byte) 0x30, (byte) 0x37, (byte) 0x5f,
|
||||
(byte) 0xa0, (byte) 0xbc, (byte) 0xe2, (byte) 0xef, (byte) 0xba, (byte) 0x27, (byte) 0x5, (byte) 0x67,
|
||||
(byte) 0xd, (byte) 0xdd, (byte) 0x76, (byte) 0x64, (byte) 0xdd, (byte) 0x59, (byte) 0x95, (byte) 0xb5,
|
||||
(byte) 0x26, (byte) 0x9d, (byte) 0xf, (byte) 0xcc, (byte) 0x1a, (byte) 0x75, (byte) 0x1a, (byte) 0xa2,
|
||||
(byte) 0x5, (byte) 0x55, (byte) 0x57, (byte) 0x96, (byte) 0x9a, (byte) 0x8d, (byte) 0xaa, (byte) 0x62,
|
||||
(byte) 0x95, (byte) 0x79, (byte) 0x17, (byte) 0xd2, (byte) 0x46, (byte) 0x43, (byte) 0x56, (byte) 0x75,
|
||||
(byte) 0x9e, (byte) 0x73, (byte) 0xb7, (byte) 0xba, (byte) 0xaf, (byte) 0x12, (byte) 0x91, (byte) 0xeb,
|
||||
(byte) 0x95, (byte) 0xf4, (byte) 0xdd, (byte) 0x3f, (byte) 0x2f, (byte) 0x96, (byte) 0x8c, (byte) 0xa6,
|
||||
(byte) 0x55, (byte) 0x73, (byte) 0x5f, (byte) 0x13, (byte) 0x4a, (byte) 0xae, (byte) 0xcb, (byte) 0x1b,
|
||||
(byte) 0x34, (byte) 0xc9, (byte) 0x69, (byte) 0x70, (byte) 0x91, (byte) 0x1e, (byte) 0x21, (byte) 0x1f,
|
||||
(byte) 0x3d, (byte) 0x6e, (byte) 0x54, (byte) 0x67, (byte) 0xac, (byte) 0xe2, (byte) 0x1e, (byte) 0x8d,
|
||||
(byte) 0xdf, (byte) 0xd0, (byte) 0xca, (byte) 0x87, (byte) 0x28, (byte) 0xfc, (byte) 0x34, (byte) 0xa7,
|
||||
(byte) 0x57, (byte) 0x8e, (byte) 0xbe, (byte) 0x15, (byte) 0xb2, (byte) 0xc, (byte) 0xd1, (byte) 0xc8,
|
||||
(byte) 0x68, (byte) 0xc, (byte) 0x4e, (byte) 0x6c, (byte) 0x83, (byte) 0x6d, (byte) 0xb9, (byte) 0x80,
|
||||
(byte) 0x35, (byte) 0xfa, (byte) 0xf6, (byte) 0xb8, (byte) 0xc6, (byte) 0x10, (byte) 0xc2, (byte) 0xb8,
|
||||
(byte) 0x8f, (byte) 0x6f, (byte) 0xf7, (byte) 0x8f, (byte) 0x5e, (byte) 0x26, (byte) 0x38, (byte) 0xb7,
|
||||
(byte) 0x46, (byte) 0x76, (byte) 0x21, (byte) 0x54, (byte) 0xb6, (byte) 0x11, (byte) 0x6e, (byte) 0x41,
|
||||
(byte) 0x6c, (byte) 0x3, (byte) 0x44, (byte) 0xd7, (byte) 0x9b, (byte) 0x4, (byte) 0x7e, (byte) 0x67,
|
||||
(byte) 0x7d, (byte) 0xfc, (byte) 0xed, (byte) 0xf3, (byte) 0x40, (byte) 0xec, (byte) 0xf, (byte) 0x9a,
|
||||
(byte) 0x5, (byte) 0x69, (byte) 0xe7, (byte) 0xc5, (byte) 0x2e, (byte) 0x7a, (byte) 0x2b, (byte) 0xf1,
|
||||
(byte) 0xe8, (byte) 0x36, (byte) 0x62, (byte) 0x85, (byte) 0x17, (byte) 0x38, (byte) 0x13, (byte) 0x1f,
|
||||
(byte) 0xc, (byte) 0xbc, (byte) 0x82, (byte) 0xaf, (byte) 0xe2, (byte) 0x8f, (byte) 0x47, (byte) 0x4b,
|
||||
(byte) 0x2d, (byte) 0x9c, (byte) 0xbf, (byte) 0x97, (byte) 0x6e, (byte) 0xe1, (byte) 0xd2, (byte) 0x26,
|
||||
(byte) 0xfa, (byte) 0x16, (byte) 0xbd, (byte) 0x31, (byte) 0xbc, (byte) 0x94, (byte) 0xc9, (byte) 0xb6,
|
||||
(byte) 0x70, (byte) 0x39, (byte) 0xf3, (byte) 0x7a, (byte) 0x13, (byte) 0xbd, (byte) 0x85, (byte) 0x5d,
|
||||
(byte) 0x64, (byte) 0x2b, (byte) 0xe9, (byte) 0x6d, (byte) 0xe4, (byte) 0x5e, (byte) 0xc7, (byte) 0xa3,
|
||||
(byte) 0xfe, (byte) 0x57, (byte) 0xf8, (byte) 0x70, (byte) 0x7, (byte) 0x53, (byte) 0x85, (byte) 0xf4,
|
||||
(byte) 0xe, (byte) 0x3e, (byte) 0xdb, (byte) 0xc1, (byte) 0xb5, (byte) 0x45, (byte) 0xce, (byte) 0x73,
|
||||
(byte) 0xdb, (byte) 0xe3, (byte) 0x49, (byte) 0xbf, (byte) 0xc4, (byte) 0x1c, (byte) 0xc3, (byte) 0x4b,
|
||||
(byte) 0x2c, (byte) 0x30, (byte) 0xb8, (byte) 0x84, (byte) 0x99, (byte) 0x37, (byte) 0x18, (byte) 0xc9,
|
||||
(byte) 0xb4, (byte) 0xb0, (byte) 0xb4, (byte) 0x89, (byte) 0xc4, (byte) 0x12, (byte) 0xcd, (byte) 0xe3,
|
||||
(byte) 0xde, (byte) 0x3c, (byte) 0x72, (byte) 0x35, (byte) 0x90, (byte) 0x4d, (byte) 0x4, (byte) 0x88,
|
||||
(byte) 0x3a, (byte) 0x4b, (byte) 0xd4, (byte) 0xa3, (byte) 0x2e, (byte) 0xfe, (byte) 0xeb, (byte) 0x13,
|
||||
(byte) 0xf0, (byte) 0x2d, (byte) 0x94, (byte) 0xb6, (byte) 0x28, (byte) 0x72, (byte) 0x11, (byte) 0xe7,
|
||||
(byte) 0x31, (byte) 0x4a, (byte) 0x4f, (byte) 0xcb, (byte) 0x18, (byte) 0x52, (byte) 0xd4, (byte) 0xd,
|
||||
(byte) 0x49, (byte) 0xca, (byte) 0x63, (byte) 0xa, (byte) 0x57, (byte) 0x68, (byte) 0xb6, (byte) 0x82,
|
||||
(byte) 0x6, (byte) 0x9e, (byte) 0xd2, (byte) 0xfa, (byte) 0x67, (byte) 0xfc, (byte) 0x82, (byte) 0x5f,
|
||||
(byte) 0x69, (byte) 0x5c, (byte) 0xc0, (byte) 0x6f, (byte) 0xf8, (byte) 0x9d, (byte) 0xec, (byte) 0x3e,
|
||||
(byte) 0x57, (byte) 0x8b, (byte) 0x39, (byte) 0xc4, (byte) 0xe8, (byte) 0x1b, (byte) 0x23, (byte) 0xf4,
|
||||
(byte) 0x39, (byte) 0xc2, (byte) 0xf, (byte) 0x10, (byte) 0x43, (byte) 0x8c, (byte) 0x70, (byte) 0x83,
|
||||
(byte) 0x84, (byte) 0x1c, (byte) 0xa0, (byte) 0xbb, (byte) 0x9a, (byte) 0xc0, (byte) 0xd, (byte) 0xb2,
|
||||
(byte) 0x2e, (byte) 0x90, (byte) 0xf2, (byte) 0x2b, (byte) 0xb8, (byte) 0x40, (byte) 0x3c, (byte) 0xc3,
|
||||
(byte) 0xc4, (byte) 0x34, (byte) 0x44, (byte) 0xf8, (byte) 0x4b, (byte) 0xc4, (byte) 0x30, (byte) 0x8c,
|
||||
(byte) 0xe7, (byte) 0xf4, (byte) 0xac, (byte) 0xfe, (byte) 0x49, (byte) 0xd5, (byte) 0xdb, (byte) 0x22,
|
||||
(byte) 0xd4, (byte) 0x77, (byte) 0xc4, (byte) 0xf2, (byte) 0x10, (byte) 0xd2, (byte) 0x1e, (byte) 0x4d,
|
||||
(byte) 0x7d, (byte) 0x2, (byte) 0x4, (byte) 0x81, (byte) 0xa4, (byte) 0x65, (byte) 0x2, (byte) 0x92,
|
||||
(byte) 0x7b, (byte) 0xfc, (byte) 0x47, (byte) 0xc6, (byte) 0x5b, (byte) 0xd3, (byte) 0xca, (byte) 0x35,
|
||||
(byte) 0x5, (byte) 0xff, (byte) 0x1, (byte) 0xbb, (byte) 0x25, (byte) 0x20, (byte) 0x1d, (byte) 0xde,
|
||||
(byte) 0x23, (byte) 0x7, (byte) 0xde, (byte) 0xde, (byte) 0xb4, (byte) 0x40, (byte) 0x57, (byte) 0xc0,
|
||||
(byte) 0x3b, (byte) 0x1e, (byte) 0x41, (byte) 0xe0, (byte) 0xd0, (byte) 0x74, (byte) 0x80, (byte) 0x10,
|
||||
(byte) 0xf6, (byte) 0x11, (byte) 0xc3, (byte) 0x54, (byte) 0xa7, (byte) 0xef, (byte) 0xdd, (byte) 0xce,
|
||||
(byte) 0x78, (byte) 0xf0, (byte) 0x1f, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d,
|
||||
(byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0xc0,
|
||||
(byte) 0x69, (byte) 0x1, (byte) 0x57, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xed, (byte) 0x41, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e,
|
||||
(byte) 0x46, (byte) 0x2f, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xfe, (byte) 0xca,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3,
|
||||
(byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xbd, (byte) 0x69,
|
||||
(byte) 0x1, (byte) 0x57, (byte) 0x71, (byte) 0xa7, (byte) 0x16, (byte) 0x53, (byte) 0x5b, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x68, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0,
|
||||
(byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xa4, (byte) 0x81, (byte) 0x3f, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46,
|
||||
(byte) 0x2f, (byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53,
|
||||
(byte) 0x54, (byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3, (byte) 0x2d, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x61, (byte) 0x69, (byte) 0x1, (byte) 0x57,
|
||||
(byte) 0x16, (byte) 0x64, (byte) 0x9c, (byte) 0xc5, (byte) 0x0, (byte) 0x4, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xf, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x19, (byte) 0x0, (byte) 0x4, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xa4, (byte) 0x81, (byte) 0xe0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5a, (byte) 0x69,
|
||||
(byte) 0x70, (byte) 0x46, (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x50, (byte) 0x72, (byte) 0x6f,
|
||||
(byte) 0x70, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x79, (byte) 0x54, (byte) 0x65, (byte) 0x73,
|
||||
(byte) 0x74, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x6, (byte) 0x6, (byte) 0x2c,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2d,
|
||||
(byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xd0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2b, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x6, (byte) 0x7, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xfb, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3,
|
||||
(byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0xd0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2b,
|
||||
(byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Jar file created by Ant specifying zip64mode="always" and createUnicodeExtraFields="always"
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x51b: Signature : 0x02014b50
|
||||
* 0x51f: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x520: Created OS : 0x3 [UNIX]
|
||||
* 0x521: VerMadeby : 0x32d [3, 4.5]
|
||||
* 0x522: VerExtract : 0x2d [4.5]
|
||||
* 0x523: Flag : 0x800
|
||||
* 0x525: Method : 0x8 [DEFLATED]
|
||||
* 0x527: Last Mod Time : 0x570b3767 [Fri Aug 11 06:59:14 EDT 2023]
|
||||
* 0x52b: CRC : 0x5e4fa53f
|
||||
* 0x52f: Compressed Size : 0xffffffff
|
||||
* 0x533: Uncompressed Size: 0xffffffff
|
||||
* 0x537: Name Length : 0x10
|
||||
* 0x539: Extra Length : 0x35
|
||||
* Extra data:[01, 00, 18, 00, 87, 04, 00, 00, 00, 00, 00, 00, c7, 02, 00, 00, 00, 00, 00, 00, 15, 01, 00, 00, 00, 00, 00, 00, 75, 70, 15, 00, 01, 94, 82, 60, 61, 52, 65, 61, 64, 41, 6e, 74, 4a, 61, 72, 2e, 63, 6c, 61, 73, 73]
|
||||
* [tag=0x0001, sz=24]
|
||||
* ->ZIP64: size *0x487 csize *0x2c7 LOC Off *0x115
|
||||
* [data= 87 04 00 00 00 00 00 00 c7 02 00 00 00 00 00 00 15 01 00 00 00 00 00 00 ]
|
||||
* [tag=0x7075, sz=21]
|
||||
* ->[Unknown tag]
|
||||
* [data= 01 94 82 60 61 52 65 61 64 41 6e 74 4a 61 72 2e 63 6c 61 73 73 ]
|
||||
* 0x53b: Comment Length : 0x0
|
||||
* 0x53d: Disk Start : 0x0
|
||||
* 0x53f: Attrs : 0x0
|
||||
* 0x541: AttrsEx : 0x81a40000
|
||||
* 0x545: Loc Header Offset: 0xffffffff
|
||||
* 0x549: File Name : ReadAntJar.class
|
||||
*/
|
||||
public static byte[] ANT_ZIP64_UNICODE_EXTRA_JAR = {
|
||||
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x18, (byte) 0x7e, (byte) 0xe, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x2a, (byte) 0x0, (byte) 0x4d, (byte) 0x45,
|
||||
(byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x75,
|
||||
(byte) 0x70, (byte) 0xe, (byte) 0x0, (byte) 0x1, (byte) 0x8, (byte) 0xa1, (byte) 0x8c, (byte) 0x13,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46,
|
||||
(byte) 0x2f, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x17, (byte) 0x7e, (byte) 0xe, (byte) 0x57, (byte) 0x31,
|
||||
(byte) 0x59, (byte) 0x76, (byte) 0x4d, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x14, (byte) 0x0, (byte) 0x31, (byte) 0x0, (byte) 0x4d,
|
||||
(byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54,
|
||||
(byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x6e,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x61,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75,
|
||||
(byte) 0x70, (byte) 0x19, (byte) 0x0, (byte) 0x1, (byte) 0x85, (byte) 0x85, (byte) 0x84, (byte) 0x2,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46,
|
||||
(byte) 0x2f, (byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53,
|
||||
(byte) 0x54, (byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0xf3, (byte) 0x4d, (byte) 0xcc, (byte) 0xcb,
|
||||
(byte) 0x4c, (byte) 0x4b, (byte) 0x2d, (byte) 0x2e, (byte) 0xd1, (byte) 0xd, (byte) 0x4b, (byte) 0x2d,
|
||||
(byte) 0x2a, (byte) 0xce, (byte) 0xcc, (byte) 0xcf, (byte) 0xb3, (byte) 0x52, (byte) 0x30, (byte) 0xd4,
|
||||
(byte) 0x33, (byte) 0xe0, (byte) 0xe5, (byte) 0x72, (byte) 0xcc, (byte) 0x43, (byte) 0x12, (byte) 0x71,
|
||||
(byte) 0x2c, (byte) 0x48, (byte) 0x4c, (byte) 0xce, (byte) 0x48, (byte) 0x55, (byte) 0x0, (byte) 0x8a,
|
||||
(byte) 0x1, (byte) 0x25, (byte) 0xd, (byte) 0xd, (byte) 0xf4, (byte) 0xc, (byte) 0x4d, (byte) 0x12,
|
||||
(byte) 0x73, (byte) 0xa, (byte) 0x32, (byte) 0x12, (byte) 0x79, (byte) 0xb9, (byte) 0x9c, (byte) 0x8b,
|
||||
(byte) 0x52, (byte) 0x13, (byte) 0x4b, (byte) 0x52, (byte) 0x53, (byte) 0x74, (byte) 0x9d, (byte) 0x2a,
|
||||
(byte) 0x81, (byte) 0xda, (byte) 0x2c, (byte) 0xf4, (byte) 0x80, (byte) 0x32, (byte) 0x7a, (byte) 0x86,
|
||||
(byte) 0xda, (byte) 0x46, (byte) 0xba, (byte) 0x66, (byte) 0xa, (byte) 0x1a, (byte) 0xfe, (byte) 0x45,
|
||||
(byte) 0x89, (byte) 0xc9, (byte) 0x39, (byte) 0xa9, (byte) 0xa, (byte) 0xce, (byte) 0xf9, (byte) 0x45,
|
||||
(byte) 0x5, (byte) 0xf9, (byte) 0x45, (byte) 0x89, (byte) 0x25, (byte) 0x40, (byte) 0x63, (byte) 0x34,
|
||||
(byte) 0x79, (byte) 0xb9, (byte) 0x78, (byte) 0xb9, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3,
|
||||
(byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x67,
|
||||
(byte) 0x37, (byte) 0xb, (byte) 0x57, (byte) 0x3f, (byte) 0xa5, (byte) 0x4f, (byte) 0x5e, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x10,
|
||||
(byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x41,
|
||||
(byte) 0x6e, (byte) 0x74, (byte) 0x4a, (byte) 0x61, (byte) 0x72, (byte) 0x2e, (byte) 0x63, (byte) 0x6c,
|
||||
(byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x87,
|
||||
(byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc7,
|
||||
(byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75,
|
||||
(byte) 0x70, (byte) 0x15, (byte) 0x0, (byte) 0x1, (byte) 0x94, (byte) 0x82, (byte) 0x60, (byte) 0x61,
|
||||
(byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x41, (byte) 0x6e, (byte) 0x74, (byte) 0x4a,
|
||||
(byte) 0x61, (byte) 0x72, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73,
|
||||
(byte) 0x75, (byte) 0x53, (byte) 0x5b, (byte) 0x57, (byte) 0x12, (byte) 0x51, (byte) 0x18, (byte) 0xdd,
|
||||
(byte) 0x3, (byte) 0xc3, (byte) 0x1c, (byte) 0x18, (byte) 0x47, (byte) 0x41, (byte) 0xcc, (byte) 0xb,
|
||||
(byte) 0x96, (byte) 0x89, (byte) 0x25, (byte) 0x89, (byte) 0x17, (byte) 0xa0, (byte) 0x8b, (byte) 0x76,
|
||||
(byte) 0x41, (byte) 0x33, (byte) 0xab, (byte) 0x95, (byte) 0x99, (byte) 0x21, (byte) 0xb4, (byte) 0x84,
|
||||
(byte) 0x65, (byte) 0x8b, (byte) 0x7a, (byte) 0x1a, (byte) 0x61, (byte) 0xb2, (byte) 0x51, (byte) 0x98,
|
||||
(byte) 0x99, (byte) 0x35, (byte) 0xc, (byte) 0x76, (byte) 0x79, (byte) 0xea, (byte) 0xa1, (byte) 0x7e,
|
||||
(byte) 0x8b, (byte) 0xcf, (byte) 0xf6, (byte) 0x80, (byte) 0x6b, (byte) 0xe5, (byte) 0x2a, (byte) 0xdf,
|
||||
(byte) 0x7c, (byte) 0xe8, (byte) 0x47, (byte) 0x65, (byte) 0xdf, (byte) 0x19, (byte) 0x50, (byte) 0xb0,
|
||||
(byte) 0x65, (byte) 0x33, (byte) 0x8b, (byte) 0xef, (byte) 0x70, (byte) 0xbe, (byte) 0xb3, (byte) 0xf7,
|
||||
(byte) 0xfe, (byte) 0x6e, (byte) 0x73, (byte) 0x7e, (byte) 0xff, (byte) 0xf9, (byte) 0xf1, (byte) 0xb,
|
||||
(byte) 0xc0, (byte) 0x2c, (byte) 0x1e, (byte) 0xc9, (byte) 0x90, (byte) 0x31, (byte) 0xc6, (byte) 0x70,
|
||||
(byte) 0x4d, (byte) 0x86, (byte) 0x7, (byte) 0x63, (byte) 0xdc, (byte) 0x5c, (byte) 0xf7, (byte) 0x63,
|
||||
(byte) 0x9c, (byte) 0x21, (byte) 0x26, (byte) 0x43, (byte) 0xc2, (byte) 0x8d, (byte) 0x0, (byte) 0x26,
|
||||
(byte) 0x10, (byte) 0xf7, (byte) 0x63, (byte) 0x92, (byte) 0x61, (byte) 0x4a, (byte) 0xc6, (byte) 0x34,
|
||||
(byte) 0x66, (byte) 0xb8, (byte) 0x33, (byte) 0xc1, (byte) 0x90, (byte) 0x94, (byte) 0xd1, (byte) 0x8d,
|
||||
(byte) 0x14, (byte) 0xc3, (byte) 0x4d, (byte) 0x3f, (byte) 0x6e, (byte) 0xc9, (byte) 0x8, (byte) 0xe2,
|
||||
(byte) 0xb6, (byte) 0x0, (byte) 0x69, (byte) 0x41, (byte) 0x37, (byte) 0x74, (byte) 0x67, (byte) 0x51,
|
||||
(byte) 0x80, (byte) 0x37, (byte) 0x3e, (byte) 0xb9, (byte) 0x21, (byte) 0x40, (byte) 0x7c, (byte) 0x6a,
|
||||
(byte) 0x96, (byte) 0x35, (byte) 0x1, (byte) 0xc1, (byte) 0x8c, (byte) 0x6e, (byte) 0x68, (byte) 0xd9,
|
||||
(byte) 0x7a, (byte) 0x75, (byte) 0x53, (byte) 0xb3, (byte) 0xb, (byte) 0xea, (byte) 0x66, (byte) 0x85,
|
||||
(byte) 0x3c, (byte) 0x62, (byte) 0x55, (byte) 0xd5, (byte) 0xd, (byte) 0x1, (byte) 0x3, (byte) 0xf1,
|
||||
(byte) 0xb7, (byte) 0x99, (byte) 0x6d, (byte) 0x75, (byte) 0x57, (byte) 0x4d, (byte) 0x55, (byte) 0x54,
|
||||
(byte) 0x63, (byte) 0x2b, (byte) 0x95, (byte) 0x77, (byte) 0x6c, (byte) 0xdd, (byte) 0xd8, (byte) 0x9a,
|
||||
(byte) 0xe7, (byte) 0x44, (byte) 0xbf, (byte) 0xad, (byte) 0xa9, (byte) 0xe5, (byte) 0x55, (byte) 0xd5,
|
||||
(byte) 0xae, (byte) 0x9, (byte) 0xe8, (byte) 0xce, (byte) 0x3b, (byte) 0x6a, (byte) 0x69, (byte) 0x67,
|
||||
(byte) 0x4d, (byte) 0xb5, (byte) 0x5c, (byte) 0x2a, (byte) 0xa5, (byte) 0xc8, (byte) 0x70, (byte) 0x87,
|
||||
(byte) 0x12, (byte) 0xa3, (byte) 0xf0, (byte) 0x14, (byte) 0x59, (byte) 0x80, (byte) 0x9c, (byte) 0x37,
|
||||
(byte) 0xeb, (byte) 0x76, (byte) 0x49, (byte) 0x5b, (byte) 0xd6, (byte) 0xb9, (byte) 0x6c, (byte) 0x70,
|
||||
(byte) 0x9d, (byte) 0x68, (byte) 0x8f, (byte) 0xd, (byte) 0x87, (byte) 0x98, (byte) 0x49, (byte) 0xae,
|
||||
(byte) 0xab, (byte) 0x20, (byte) 0x8c, (byte) 0x3e, (byte) 0xc2, (byte) 0xb4, (byte) 0xdd, (byte) 0xa,
|
||||
(byte) 0x86, (byte) 0xb8, (byte) 0xa7, (byte) 0x47, (byte) 0x35, (byte) 0x9c, (byte) 0x6d, (byte) 0xd5,
|
||||
(byte) 0x76, (byte) 0xb4, (byte) 0x9a, (byte) 0x43, (byte) 0x40, (byte) 0x5b, (byte) 0x40, (byte) 0xbf,
|
||||
(byte) 0x9b, (byte) 0x46, (byte) 0xdd, (byte) 0xd1, (byte) 0x2b, (byte) 0xa9, (byte) 0xcf, (byte) 0xba,
|
||||
(byte) 0x95, (byte) 0x7a, (byte) 0xa3, (byte) 0x5b, (byte) 0x5c, (byte) 0x91, (byte) 0xf3, (byte) 0x67,
|
||||
(byte) 0x19, (byte) 0xe6, (byte) 0x14, (byte) 0xdc, (byte) 0xc5, (byte) 0x3d, (byte) 0x1, (byte) 0x83,
|
||||
(byte) 0xb1, (byte) 0x5a, (byte) 0xd4, (byte) 0xb4, (byte) 0x34, (byte) 0x43, (byte) 0x2b, (byte) 0x47,
|
||||
(byte) 0x77, (byte) 0x75, (byte) 0x35, (byte) 0xda, (byte) 0x2, (byte) 0xc5, (byte) 0xa8, (byte) 0x90,
|
||||
(byte) 0x50, (byte) 0xbb, (byte) 0x8a, (byte) 0xdc, (byte) 0xe6, (byte) 0xb6, (byte) 0x56, (byte) 0x72,
|
||||
(byte) 0x18, (byte) 0xee, (byte) 0x2b, (byte) 0x78, (byte) 0x80, (byte) 0xb4, (byte) 0x82, (byte) 0x79,
|
||||
(byte) 0x1e, (byte) 0xaf, (byte) 0xaf, (byte) 0x7d, (byte) 0x5e, (byte) 0x78, (byte) 0x6f, (byte) 0x9b,
|
||||
(byte) 0x1f, (byte) 0x78, (byte) 0x29, (byte) 0xa, (byte) 0x16, (byte) 0xf0, (byte) 0xf0, (byte) 0xf4,
|
||||
(byte) 0x48, (byte) 0x37, (byte) 0x53, (byte) 0x2f, (byte) 0x72, (byte) 0xcf, (byte) 0x3e, (byte) 0x96,
|
||||
(byte) 0x34, (byte) 0xcb, (byte) 0xd1, (byte) 0x4d, (byte) 0x12, (byte) 0x1c, (byte) 0x8e, (byte) 0x19,
|
||||
(byte) 0xfc, (byte) 0x1d, (byte) 0xa7, (byte) 0x27, (byte) 0x4a, (byte) 0x51, (byte) 0xb3, (byte) 0xb9,
|
||||
(byte) 0x42, (byte) 0x2b, (byte) 0x72, (byte) 0xcc, (byte) 0x50, (byte) 0xb0, (byte) 0xc8, (byte) 0x25,
|
||||
(byte) 0x43, (byte) 0xff, (byte) 0x36, (byte) 0x8e, (byte) 0x8a, (byte) 0x88, (byte) 0x5f, (byte) 0xdc,
|
||||
(byte) 0xcd, (byte) 0x4e, (byte) 0xe8, (byte) 0xa7, (byte) 0x9a, (byte) 0xa3, (byte) 0x55, (byte) 0x69,
|
||||
(byte) 0x3e, (byte) 0x66, (byte) 0xdd, (byte) 0x21, (byte) 0x42, (byte) 0xe6, (byte) 0x34, (byte) 0xf8,
|
||||
(byte) 0x2b, (byte) 0x2, (byte) 0x3b, (byte) 0x44, (byte) 0xd1, (byte) 0xd4, (byte) 0xea, (byte) 0x7c,
|
||||
(byte) 0x47, (byte) 0x4e, (byte) 0x1d, (byte) 0x6e, (byte) 0x1a, (byte) 0xae, (byte) 0xc5, (byte) 0x77,
|
||||
(byte) 0xef, (byte) 0x4, (byte) 0x2c, (byte) 0x5c, (byte) 0x10, (byte) 0xa7, (byte) 0x73, (byte) 0x90,
|
||||
(byte) 0xcd, (byte) 0x16, (byte) 0xcc, (byte) 0x4f, (byte) 0xfe, (byte) 0x47, (byte) 0xdd, (byte) 0x57,
|
||||
(byte) 0xaa, (byte) 0x98, (byte) 0x35, (byte) 0x9a, (byte) 0x56, (byte) 0xb7, (byte) 0x5a, (byte) 0x2e,
|
||||
(byte) 0xe7, (byte) 0xeb, (byte) 0x96, (byte) 0x65, (byte) 0x6b, (byte) 0xb5, (byte) 0x9a, (byte) 0x56,
|
||||
(byte) 0x16, (byte) 0x30, (byte) 0xd4, (byte) 0x29, (byte) 0x7b, (byte) 0xd6, (byte) 0x26, (byte) 0xb7,
|
||||
(byte) 0x82, (byte) 0xa0, (byte) 0xd5, (byte) 0x54, (byte) 0xa0, (byte) 0x2f, (byte) 0xa1, (byte) 0x60,
|
||||
(byte) 0xab, (byte) 0x25, (byte) 0xd, (byte) 0x63, (byte) 0xf4, (byte) 0x89, (byte) 0xca, (byte) 0xe0,
|
||||
(byte) 0x8f, (byte) 0x17, (byte) 0x2, (byte) 0x9f, (byte) 0x32, (byte) 0xd9, (byte) 0x4b, (byte) 0xb4,
|
||||
(byte) 0x1b, (byte) 0xa1, (byte) 0x55, (byte) 0xa0, (byte) 0xd5, (byte) 0x37, (byte) 0x75, (byte) 0x0,
|
||||
(byte) 0x61, (byte) 0x9f, (byte) 0xfe, (byte) 0x50, (byte) 0x91, (byte) 0x64, (byte) 0x25, (byte) 0xd7,
|
||||
(byte) 0x29, (byte) 0x21, (byte) 0x80, (byte) 0x1, (byte) 0xc, (byte) 0xb6, (byte) 0xa0, (byte) 0x13,
|
||||
(byte) 0x24, (byte) 0xc1, (byte) 0xbd, (byte) 0x5d, (byte) 0x87, (byte) 0xf0, (byte) 0x14, (byte) 0xf,
|
||||
(byte) 0xe0, (byte) 0x6d, (byte) 0x40, (byte) 0x6c, (byte) 0x13, (byte) 0xf8, (byte) 0x15, (byte) 0x0,
|
||||
(byte) 0xfc, (byte) 0xb4, (byte) 0x6, (byte) 0xc8, (byte) 0x33, (byte) 0x74, (byte) 0xaa, (byte) 0x2f,
|
||||
(byte) 0xac, (byte) 0x92, (byte) 0x8, (byte) 0xa3, (byte) 0x93, (byte) 0x6f, (byte) 0x61, (byte) 0x5f,
|
||||
(byte) 0xe6, (byte) 0x10, (byte) 0x52, (byte) 0x71, (byte) 0xfa, (byte) 0x0, (byte) 0x6c, (byte) 0x4d,
|
||||
(byte) 0xc8, (byte) 0x7e, (byte) 0x87, (byte) 0x3f, (byte) 0x1c, (byte) 0x10, (byte) 0x7f, (byte) 0x42,
|
||||
(byte) 0x2e, (byte) 0x7a, (byte) 0xa7, (byte) 0xf3, (byte) 0xd, (byte) 0x74, (byte) 0xbd, (byte) 0x9e,
|
||||
(byte) 0x39, (byte) 0xc6, (byte) 0xcb, (byte) 0xc4, (byte) 0x31, (byte) 0xfa, (byte) 0x67, (byte) 0x1a,
|
||||
(byte) 0x50, (byte) 0xf6, (byte) 0xb0, (byte) 0x94, (byte) 0x16, (byte) 0x13, (byte) 0x11, (byte) 0xb1,
|
||||
(byte) 0x81, (byte) 0x9e, (byte) 0x3d, (byte) 0xcc, (byte) 0x35, (byte) 0x3d, (byte) 0xc9, (byte) 0xb4,
|
||||
(byte) 0x18, (byte) 0x11, (byte) 0xb3, (byte) 0x11, (byte) 0xf1, (byte) 0x28, (byte) 0xed, (byte) 0x23,
|
||||
(byte) 0xe8, (byte) 0x48, (byte) 0x1b, (byte) 0x1a, (byte) 0x4e, (byte) 0x4b, (byte) 0x89, (byte) 0x88,
|
||||
(byte) 0xe4, (byte) 0x42, (byte) 0x19, (byte) 0xf7, (byte) 0x44, (byte) 0x7c, (byte) 0x47, (byte) 0x7b,
|
||||
(byte) 0x88, (byte) 0xac, (byte) 0xf1, (byte) 0x0, (byte) 0xa1, (byte) 0x73, (byte) 0x1, (byte) 0x1a,
|
||||
(byte) 0xe8, (byte) 0xdd, (byte) 0xa7, (byte) 0x64, (byte) 0x26, (byte) 0xe8, (byte) 0x42, (byte) 0x26,
|
||||
(byte) 0xe9, (byte) 0x1e, (byte) 0xf6, (byte) 0x60, (byte) 0x14, (byte) 0x4b, (byte) 0xad, (byte) 0x75,
|
||||
(byte) 0x85, (byte) 0x12, (byte) 0x5c, (byte) 0xc7, (byte) 0x6, (byte) 0x8a, (byte) 0xb4, (byte) 0x5f,
|
||||
(byte) 0xc2, (byte) 0xaa, (byte) 0xbb, (byte) 0xf7, (byte) 0x62, (byte) 0x7, (byte) 0x6, (byte) 0x5d,
|
||||
(byte) 0x52, (byte) 0x8f, (byte) 0x5b, (byte) 0x5e, (byte) 0x12, (byte) 0x5d, (byte) 0x64, (byte) 0x15,
|
||||
(byte) 0xf2, (byte) 0x72, (byte) 0x6, (byte) 0xe7, (byte) 0x4, (byte) 0x5d, (byte) 0xf6, (byte) 0xa,
|
||||
(byte) 0xad, (byte) 0x3b, (byte) 0xd4, (byte) 0x4e, (byte) 0x8e, (byte) 0x34, (byte) 0x11, (byte) 0xc2,
|
||||
(byte) 0x17, (byte) 0xf4, (byte) 0xe2, (byte) 0x2b, (byte) 0x15, (byte) 0x1e, (byte) 0x21, (byte) 0x74,
|
||||
(byte) 0xe, (byte) 0xf2, (byte) 0x9, (byte) 0x11, (byte) 0x45, (byte) 0x86, (byte) 0x61, (byte) 0x86,
|
||||
(byte) 0xcb, (byte) 0xc, (byte) 0x57, (byte) 0x18, (byte) 0xef, (byte) 0x36, (byte) 0x19, (byte) 0x79,
|
||||
(byte) 0x99, (byte) 0xcc, (byte) 0x73, (byte) 0xfa, (byte) 0x9d, (byte) 0x10, (byte) 0x43, (byte) 0x3a,
|
||||
(byte) 0x77, (byte) 0x7c, (byte) 0x6, (byte) 0xf1, (byte) 0x9e, (byte) 0x50, (byte) 0x64, (byte) 0x4f,
|
||||
(byte) 0xf3, (byte) 0xc, (byte) 0x78, (byte) 0xc2, (byte) 0x70, (byte) 0xb5, (byte) 0x9f, (byte) 0x3a,
|
||||
(byte) 0x3a, (byte) 0x4a, (byte) 0xb2, (byte) 0x1e, (byte) 0x44, (byte) 0xff, (byte) 0x2, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x18, (byte) 0x7e, (byte) 0xe, (byte) 0x57, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x32, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xed,
|
||||
(byte) 0x41, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x4d, (byte) 0x45, (byte) 0x54,
|
||||
(byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x18, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x75, (byte) 0x70,
|
||||
(byte) 0xe, (byte) 0x0, (byte) 0x1, (byte) 0x8, (byte) 0xa1, (byte) 0x8c, (byte) 0x13, (byte) 0x4d,
|
||||
(byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3, (byte) 0x2d, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x17, (byte) 0x7e, (byte) 0xe, (byte) 0x57,
|
||||
(byte) 0x31, (byte) 0x59, (byte) 0x76, (byte) 0x4d, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x14, (byte) 0x0, (byte) 0x39, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xa4, (byte) 0x81, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x4d, (byte) 0x45,
|
||||
(byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d,
|
||||
(byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2e,
|
||||
(byte) 0x4d, (byte) 0x46, (byte) 0x1, (byte) 0x0, (byte) 0x18, (byte) 0x0, (byte) 0x6e, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x61, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x51, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75, (byte) 0x70,
|
||||
(byte) 0x19, (byte) 0x0, (byte) 0x1, (byte) 0x85, (byte) 0x85, (byte) 0x84, (byte) 0x2, (byte) 0x4d,
|
||||
(byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54,
|
||||
(byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d,
|
||||
(byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x67,
|
||||
(byte) 0x37, (byte) 0xb, (byte) 0x57, (byte) 0x3f, (byte) 0xa5, (byte) 0x4f, (byte) 0x5e, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x10,
|
||||
(byte) 0x0, (byte) 0x35, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa4, (byte) 0x81, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x41, (byte) 0x6e, (byte) 0x74,
|
||||
(byte) 0x4a, (byte) 0x61, (byte) 0x72, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73,
|
||||
(byte) 0x73, (byte) 0x1, (byte) 0x0, (byte) 0x18, (byte) 0x0, (byte) 0x87, (byte) 0x4, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc7, (byte) 0x2, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x15, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75, (byte) 0x70, (byte) 0x15,
|
||||
(byte) 0x0, (byte) 0x1, (byte) 0x94, (byte) 0x82, (byte) 0x60, (byte) 0x61, (byte) 0x52, (byte) 0x65,
|
||||
(byte) 0x61, (byte) 0x64, (byte) 0x41, (byte) 0x6e, (byte) 0x74, (byte) 0x4a, (byte) 0x61, (byte) 0x72,
|
||||
(byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x6, (byte) 0x6, (byte) 0x2c, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x57, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x37, (byte) 0x4,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x6, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8e, (byte) 0x5,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x57, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x37, (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/*
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x47: Signature : 0x02014b50
|
||||
* 0x4b: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x4c: Created OS : 0x3 [UNIX]
|
||||
* 0x4d: VerMadeby : 0x32d [3, 4.5]
|
||||
* 0x4e: VerExtract : 0x2d [4.5]
|
||||
* 0x4f: Flag : 0x800
|
||||
* 0x51: Method : 0x8 [DEFLATED]
|
||||
* 0x53: Last Mod Time : 0x570375bc [Thu Aug 03 14:45:56 EDT 2023]
|
||||
* 0x57: CRC : 0x0
|
||||
* 0x5b: Compressed Size : 0x2
|
||||
* 0x5f: Uncompressed Size: 0x0
|
||||
* * 0x63: Name Length : 0x5
|
||||
* 0x65: Extra Length : 0x12
|
||||
* Extra data:[01, 00, 00, 00, 75, 70, 0a, 00, 01, ba, f7, eb, c1, 61, 2e, 74, 78, 74]
|
||||
* [tag=0x0001, sz=0]
|
||||
* ->ZIP64:
|
||||
* [tag=0x7075, sz=10]
|
||||
* ->[Unknown tag]
|
||||
* [data= 01 ba f7 eb c1 61 2e 74 78 74 ]
|
||||
* 0x67: Comment Length : 0x0
|
||||
* 0x69: Disk Start : 0x0
|
||||
* 0x6b: Attrs : 0x0
|
||||
* 0x6d: AttrsEx : 0x81a40000
|
||||
* 0x71: Loc Header Offset: 0x0
|
||||
* 0x75: File Name : a.txt
|
||||
*/
|
||||
public static byte[] ANT_ZIP64_UNICODE_EXTRA_ZIP= {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xbc, (byte) 0x75, (byte) 0x3, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x5, (byte) 0x0, (byte) 0x22, (byte) 0x0, (byte) 0x61, (byte) 0x2e,
|
||||
(byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75,
|
||||
(byte) 0x70, (byte) 0xa, (byte) 0x0, (byte) 0x1, (byte) 0xba, (byte) 0xf7, (byte) 0xeb, (byte) 0xc1,
|
||||
(byte) 0x61, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x3, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xbc, (byte) 0x75, (byte) 0x3, (byte) 0x57, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x12, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa4,
|
||||
(byte) 0x81, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x61, (byte) 0x2e, (byte) 0x74,
|
||||
(byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75, (byte) 0x70,
|
||||
(byte) 0xa, (byte) 0x0, (byte) 0x1, (byte) 0xba, (byte) 0xf7, (byte) 0xeb, (byte) 0xc1, (byte) 0x61,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x6, (byte) 0x6,
|
||||
(byte) 0x2c, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x45, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x47, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x6, (byte) 0x7,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8c, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x45, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x47, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
// Name of Zip file and Jar File used by the test
|
||||
public static final Path VALID_APK = Path.of("working-apk.zip");
|
||||
public static final Path VALID_APACHE_COMPRESS_JAR =
|
||||
Path.of("valid-apache-compress.jar");
|
||||
public static final Path VALID_ANT_JAR =
|
||||
Path.of("valid-ant-zip64-unicode-extrafields.jar");
|
||||
public static final Path VALID_ANT_ZIP =
|
||||
Path.of("valid-ant-zip64-unicode-extrafields.zip");
|
||||
/**
|
||||
* Setup method used to create the Zip and Jar files used by the test
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
Files.deleteIfExists(VALID_APK);
|
||||
Files.deleteIfExists(VALID_APACHE_COMPRESS_JAR);
|
||||
Files.deleteIfExists(VALID_ANT_JAR);
|
||||
Files.deleteIfExists(VALID_ANT_ZIP);
|
||||
|
||||
// Create the Zip file to read
|
||||
Files.write(VALID_APK, VALID_APK_FILE);
|
||||
Files.write(VALID_APACHE_COMPRESS_JAR, COMMONS_COMPRESS_JAR);
|
||||
Files.write(VALID_ANT_JAR, ANT_ZIP64_UNICODE_EXTRA_JAR);
|
||||
Files.write(VALID_ANT_ZIP, ANT_ZIP64_UNICODE_EXTRA_ZIP);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip and Jars files to validate we can open
|
||||
*/
|
||||
private static Stream<Path> zipFilesToTest() {
|
||||
return Stream.of(VALID_APK, VALID_APACHE_COMPRESS_JAR, VALID_ANT_JAR, VALID_ANT_ZIP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a Zip file which contains an extra header with a data size
|
||||
* 0f 0 can be opened using ZipFile
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("zipFilesToTest")
|
||||
public void zipFilesToTest(Path jar) throws IOException {
|
||||
try (ZipFile zf = new ZipFile(jar.toFile())) {
|
||||
System.out.printf("%s opened%n", jar.toAbsolutePath());
|
||||
} catch (IOException ie) {
|
||||
System.out.printf("%n%n%n$$$$ %s NOT opened%n", jar.toAbsolutePath());
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a Zip file which contains an extra header with a data size
|
||||
* 0f 0 can be opened using ZipFS
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("zipFilesToTest")
|
||||
public void readZipFSTest(Path jar) throws IOException {
|
||||
try (FileSystem fs = FileSystems.newFileSystem(jar, Map.of())) {
|
||||
System.out.printf("%s opened%n", jar.toAbsolutePath());
|
||||
} catch (IOException ie) {
|
||||
System.out.printf("%n%n%n$$$$ %s NOT opened%n", jar.toAbsolutePath());
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Utility method which takes a byte array and converts to byte array
|
||||
* declaration. For example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* var fooJar = Files.readAllBytes(Path.of("foo.jar"));
|
||||
* var result = createByteArray(fooJar, "FOOBYTES");
|
||||
* System.out.println(result);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param bytes A byte array used to create a byte array declaration
|
||||
* @param name Name to be used in the byte array declaration
|
||||
* @return The formatted byte array declaration
|
||||
*/
|
||||
public static String createByteArray(byte[] bytes, String name) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 5);
|
||||
Formatter fmt = new Formatter(sb);
|
||||
fmt.format(" public static byte[] %s = {", name);
|
||||
final int linelen = 8;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
if (i % linelen == 0) {
|
||||
fmt.format("%n ");
|
||||
}
|
||||
fmt.format(" (byte) 0x%x,", bytes[i] & 0xff);
|
||||
}
|
||||
fmt.format("%n };%n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
380
test/jdk/java/util/zip/ZipFile/ReadZip.java
Normal file
380
test/jdk/java/util/zip/ZipFile/ReadZip.java
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2024, 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.
|
||||
*
|
||||
* 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 4241361 4842702 4985614 6646605 5032358 6923692 6233323 8144977 8186464 4401122 8322830
|
||||
@summary Make sure we can read a zip file.
|
||||
@modules jdk.zipfs
|
||||
@run junit ReadZip
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ReadZip {
|
||||
|
||||
// ZIP file produced during tests
|
||||
private Path zip = Path.of("read-zip.zip");
|
||||
|
||||
/**
|
||||
* Create a sample ZIP file for use by tests
|
||||
* @param name name of the ZIP file to create
|
||||
* @return a sample ZIP file
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
private Path createZip(String name) throws IOException {
|
||||
Path zip = Path.of(name);
|
||||
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
return zip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced after each test method
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we throw NPE when calling getEntry or getInputStream with null params
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void nullPointerExceptionOnNullParams() throws IOException {
|
||||
zip = createZip("null-params.zip");
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
|
||||
assertThrows(NullPointerException.class, () -> zf.getEntry(null));
|
||||
assertThrows(NullPointerException.class, () -> zf.getInputStream(null));
|
||||
|
||||
// Sanity check that we can still read an entry
|
||||
ZipEntry ze = zf.getEntry("file.txt");
|
||||
assertNotNull(ze, "cannot read from zip file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the zip file that has some garbage bytes padded at the end
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void bytesPaddedAtEnd() throws IOException {
|
||||
|
||||
zip = createZip("bytes-padded.zip");
|
||||
|
||||
// pad some bytes
|
||||
try (OutputStream os = Files.newOutputStream(zip,
|
||||
StandardOpenOption.APPEND)) {
|
||||
os.write(1);
|
||||
os.write(3);
|
||||
os.write(5);
|
||||
os.write(7);
|
||||
}
|
||||
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry ze = zf.getEntry("file.txt");
|
||||
assertNotNull(ze, "cannot read from zip file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that we can read a comment from the ZIP
|
||||
* file's 'End of Central Directory' header
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readZipFileComment() throws IOException {
|
||||
|
||||
// Create a zip file with a comment in the 'End of Central Directory' header
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zos = new ZipOutputStream(out)) {
|
||||
ZipEntry ze = new ZipEntry("ZipEntry");
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(1);
|
||||
zos.write(2);
|
||||
zos.write(3);
|
||||
zos.write(4);
|
||||
zos.closeEntry();
|
||||
zos.setComment("This is the comment for testing");
|
||||
}
|
||||
|
||||
// Read zip file comment
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry ze = zf.getEntry("ZipEntry");
|
||||
assertNotNull(ze, "cannot read entry from zip file");
|
||||
assertEquals("This is the comment for testing", zf.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a directory entry can be found using the
|
||||
* name 'directory/' as well as 'directory/'
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readDirectoryEntries() throws IOException {
|
||||
|
||||
// Create a ZIP containing some directory entries
|
||||
try (OutputStream fos = Files.newOutputStream(zip);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos)) {
|
||||
// Add a META-INF directory with STORED compression type
|
||||
ZipEntry metaInf = new ZipEntry("META-INF/");
|
||||
metaInf.setMethod(ZipEntry.STORED);
|
||||
metaInf.setSize(0);
|
||||
metaInf.setCrc(0);
|
||||
zos.putNextEntry(metaInf);
|
||||
|
||||
// Add a regular directory
|
||||
ZipEntry dir = new ZipEntry("directory/");
|
||||
zos.putNextEntry(dir);
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
// Verify directory lookups
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
// Look up 'directory/' using the full name
|
||||
ZipEntry ze = zf.getEntry("directory/");
|
||||
assertNotNull(ze, "read entry \"directory/\" failed");
|
||||
assertTrue(ze.isDirectory(), "read entry \"directory/\" failed");
|
||||
assertEquals("directory/", ze.getName());
|
||||
|
||||
try (InputStream is = zf.getInputStream(ze)) {
|
||||
is.available();
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
|
||||
// Look up 'directory/' without the trailing slash
|
||||
ze = zf.getEntry("directory");
|
||||
assertNotNull(ze, "read entry \"directory\" failed");
|
||||
assertTrue(ze.isDirectory(), "read entry \"directory\" failed");
|
||||
assertEquals("directory/", ze.getName());
|
||||
|
||||
try (InputStream is = zf.getInputStream(ze)) {
|
||||
is.available();
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
// Sanity check that also META-INF/ can be looked up with or without the trailing slash
|
||||
assertNotNull(zf.getEntry("META-INF"));
|
||||
assertNotNull(zf.getEntry("META-INF/"));
|
||||
assertEquals(zf.getEntry("META-INF").getName(),
|
||||
zf.getEntry("META-INF/").getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw a NoSuchFileException exception when reading a non-existing zip file
|
||||
*/
|
||||
@Test
|
||||
public void nonExistingFile() {
|
||||
File nonExistingFile = new File("non-existing-file-f6804460f.zip");
|
||||
assertThrows(NoSuchFileException.class, () ->
|
||||
new ZipFile(nonExistingFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a Zip file with a 'Zip64 End of Central Directory header' which was created
|
||||
* using ZipFileSystem with the 'forceZIP64End' option.
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readZip64EndZipFs() throws IOException {
|
||||
|
||||
// Create zip file with Zip64 end
|
||||
Map<String, Object> env = Map.of("create", "true", "forceZIP64End", "true");
|
||||
try (FileSystem fs = FileSystems.newFileSystem(zip, env)) {
|
||||
Files.write(fs.getPath("hello"), "hello".getBytes());
|
||||
}
|
||||
// Read using ZipFile
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
try (InputStream in = zf.getInputStream(zf.getEntry("hello"))) {
|
||||
assertEquals("hello", new String(in.readAllBytes(), StandardCharsets.US_ASCII));
|
||||
}
|
||||
}
|
||||
// Read using ZipFileSystem
|
||||
try (FileSystem fs = FileSystems.newFileSystem(zip, Map.of())) {
|
||||
assertEquals("hello", new String(Files.readAllBytes(fs.getPath("hello"))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a zip file created via Info-ZIP in streaming mode,
|
||||
* which includes a 'Zip64 End of Central Directory header'.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
* @throws InterruptedException if an unexpected InterruptedException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readZip64EndInfoZIPStreaming() throws IOException, InterruptedException {
|
||||
// ZIP created using: "echo -n hello | zip zip64.zip -"
|
||||
// Hex encoded using: "cat zip64.zip | xxd -ps"
|
||||
byte[] zipBytes = HexFormat.of().parseHex("""
|
||||
504b03042d0000000000c441295886a61036ffffffffffffffff01001400
|
||||
2d010010000500000000000000050000000000000068656c6c6f504b0102
|
||||
1e032d0000000000c441295886a610360500000005000000010000000000
|
||||
000001000000b011000000002d504b06062c000000000000001e032d0000
|
||||
00000000000000010000000000000001000000000000002f000000000000
|
||||
003800000000000000504b06070000000067000000000000000100000050
|
||||
4b050600000000010001002f000000380000000000
|
||||
""".replaceAll("\n","")
|
||||
);
|
||||
|
||||
Files.write(zip, zipBytes);
|
||||
|
||||
try (ZipFile zf = new ZipFile(this.zip.toFile())) {
|
||||
try (InputStream in = zf.getInputStream(zf.getEntry("-"))) {
|
||||
String contents = new String(in.readAllBytes(), StandardCharsets.US_ASCII);
|
||||
assertEquals("hello", contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the available() method overriden by the input stream returned by
|
||||
* ZipFile.getInputStream correctly returns the number of remaining uncompressed bytes
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void availableShouldReturnRemainingUncompressedBytes() throws IOException {
|
||||
// The number of uncompressed bytes to write to the sample ZIP entry
|
||||
final int expectedBytes = 512;
|
||||
|
||||
// Create a sample ZIP with deflated entry of a known uncompressed size
|
||||
try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write(new byte[expectedBytes]);
|
||||
}
|
||||
|
||||
// Verify the behavior of ZipFileInflaterInputStream.available()
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry e = zf.getEntry("file.txt");
|
||||
try (InputStream in = zf.getInputStream(e)) {
|
||||
// Initially, available() should return the full uncompressed size of the entry
|
||||
assertEquals(expectedBytes, in.available(),
|
||||
"wrong initial return value of available");
|
||||
|
||||
// Reading a few bytes should reduce the number of available bytes accordingly
|
||||
int bytesToRead = 10;
|
||||
in.read(new byte[bytesToRead]);
|
||||
assertEquals(expectedBytes - bytesToRead, in.available());
|
||||
|
||||
// Reading all remaining bytes should reduce the number of available bytes to zero
|
||||
in.transferTo(OutputStream.nullOutputStream());
|
||||
assertEquals(0, in.available());
|
||||
|
||||
// available on a closed input stream should return zero
|
||||
in.close();
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that reading an InputStream from a closed ZipFile
|
||||
* throws IOException as expected and does not crash the VM.
|
||||
* See bugs: 4528128 6846616
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readAfterClose() throws IOException {
|
||||
zip = createZip("read-after-close.zip");
|
||||
InputStream in;
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry zent = zf.getEntry("file.txt");
|
||||
in = zf.getInputStream(zent);
|
||||
}
|
||||
|
||||
// zf is closed at this point
|
||||
assertThrows(IOException.class, () -> {
|
||||
in.read();
|
||||
});
|
||||
assertThrows(IOException.class, () -> {
|
||||
in.read(new byte[10]);
|
||||
});
|
||||
assertThrows(IOException.class, () -> {
|
||||
byte[] buf = new byte[10];
|
||||
in.read(buf, 0, buf.length);
|
||||
});
|
||||
assertThrows(IOException.class, () -> {
|
||||
in.readAllBytes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile can open a ZIP file with zero entries
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void noEntries() throws IOException {
|
||||
// Create a ZIP file with no entries
|
||||
try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
}
|
||||
|
||||
// Open the "empty" ZIP file
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
// Verify size
|
||||
assertEquals(0, zf.size());
|
||||
|
||||
// Verify entry lookup using ZipFile.getEntry()
|
||||
assertNull(zf.getEntry("file.txt"));
|
||||
|
||||
// Verify iteration using ZipFile.entries()
|
||||
assertEquals(Collections.emptyList(), Collections.list(zf.entries()));
|
||||
|
||||
// Verify iteration using ZipFile.stream()
|
||||
assertEquals(Collections.emptyList(), zf.stream().toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
98
test/jdk/java/util/zip/ZipFile/ReleaseInflater.java
Normal file
98
test/jdk/java/util/zip/ZipFile/ReleaseInflater.java
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2024, 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.
|
||||
*
|
||||
* 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 4214795
|
||||
* @summary Make sure the same inflater will only be recycled
|
||||
* once.
|
||||
* @run junit ReleaseInflater
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ReleaseInflater {
|
||||
|
||||
// ZIP file produced in this test
|
||||
private Path zip = Path.of("release-inflater.zip");
|
||||
|
||||
/**
|
||||
* Create a sample ZIP file for use by tests
|
||||
* @param name name of the ZIP file to create
|
||||
* @return a sample ZIP file
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("helloworld".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP and JAR files produced after each test method
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the same Inflater is not recycled across input streams
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void recycleInflaterOnlyOnce() throws IOException {
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry e = zf.getEntry("file.txt");
|
||||
|
||||
InputStream in1 = zf.getInputStream(e);
|
||||
// close the stream, the inflater will be released
|
||||
in1.close();
|
||||
// close the stream again, should be no-op
|
||||
in1.close();
|
||||
|
||||
// create two new streams, allocating inflaters
|
||||
InputStream in2 = zf.getInputStream(e);
|
||||
InputStream in3 = zf.getInputStream(e);
|
||||
|
||||
// check to see if they influence each other
|
||||
assertEquals(in2.read(), in3.read(), "Stream is corrupted!");
|
||||
}
|
||||
}
|
||||
}
|
||||
66
test/jdk/java/util/zip/ZipFile/ShortRead.java
Normal file
66
test/jdk/java/util/zip/ZipFile/ShortRead.java
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2011, 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.
|
||||
*
|
||||
* 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 6285124
|
||||
* @summary Small compressed zip entries should be read in one read() operation
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class ShortRead {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final File zFile = new File("abc.zip");
|
||||
try {
|
||||
final String entryName = "abc";
|
||||
final String data = "Data disponible";
|
||||
try (FileOutputStream fos = new FileOutputStream(zFile);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos))
|
||||
{
|
||||
zos.putNextEntry(new ZipEntry(entryName));
|
||||
zos.write(data.getBytes("ASCII"));
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
try (ZipFile zipFile = new ZipFile(zFile)) {
|
||||
final ZipEntry zentry = zipFile.getEntry(entryName);
|
||||
final InputStream inputStream = zipFile.getInputStream(zentry);
|
||||
System.out.printf("size=%d csize=%d available=%d%n",
|
||||
zentry.getSize(),
|
||||
zentry.getCompressedSize(),
|
||||
inputStream.available());
|
||||
byte[] buf = new byte[data.length()];
|
||||
final int count = inputStream.read(buf);
|
||||
if (! new String(buf, "ASCII").equals(data) ||
|
||||
count != data.length())
|
||||
throw new Exception("short read?");
|
||||
}
|
||||
} finally {
|
||||
zFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
191
test/jdk/java/util/zip/ZipFile/StreamZipEntriesTest.java
Normal file
191
test/jdk/java/util/zip/ZipFile/StreamZipEntriesTest.java
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2024, 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.
|
||||
*
|
||||
* 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
|
||||
* @run junit StreamZipEntriesTest
|
||||
* @summary Make sure we can stream entries of a zip file.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
||||
public class StreamZipEntriesTest {
|
||||
|
||||
// ZIP file produced in this test
|
||||
private Path zip = Path.of("stream.zip");
|
||||
// JAR file produced in this test
|
||||
private Path jar = Path.of("stream.jar");
|
||||
|
||||
/**
|
||||
* Create sample ZIP and JAR files used in in this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
zo.putNextEntry(new ZipEntry("entry1.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
zo.putNextEntry(new ZipEntry("entry2.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
try (OutputStream out = Files.newOutputStream(jar);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
// A JAR file may start with a META-INF/ directory before the manifest
|
||||
zo.putNextEntry(new ZipEntry("META-INF/"));
|
||||
// Write the manifest
|
||||
zo.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
|
||||
new Manifest().write(zo);
|
||||
|
||||
// Write two regular entries
|
||||
zo.putNextEntry(new ZipEntry("entry1.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
zo.putNextEntry(new ZipEntry("entry2.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced after each test method
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
Files.deleteIfExists(jar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile.stream() produces the expected entries
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void testStreamZip() throws IOException {
|
||||
Set<String> names = new HashSet<>(Set.of("entry1.txt", "entry2.txt"));
|
||||
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
zf.stream().forEach(e -> {
|
||||
assertTrue(e instanceof ZipEntry);
|
||||
String name = e.getName();
|
||||
assertNotNull(names.remove(name));
|
||||
String toString = e.toString();
|
||||
assertEquals(name, toString);
|
||||
});
|
||||
|
||||
// Check that all expected names were processed
|
||||
assertTrue(names.isEmpty());
|
||||
|
||||
// Check that Stream.toArray produces the expected result
|
||||
Object elements[] = zf.stream().toArray();
|
||||
assertEquals(2, elements.length);
|
||||
assertEquals(elements[0].toString(), "entry1.txt");
|
||||
assertEquals(elements[1].toString(), "entry2.txt");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarFile.stream() produces the expected entries
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void testStreamJar() throws IOException {
|
||||
try (JarFile jf = new JarFile(jar.toFile())) {
|
||||
Set<String> names = new HashSet<>(Set.of(
|
||||
"META-INF/",
|
||||
"META-INF/MANIFEST.MF",
|
||||
"entry1.txt",
|
||||
"entry2.txt"
|
||||
));
|
||||
|
||||
jf.stream().forEach(e -> {
|
||||
assertTrue(e instanceof JarEntry);
|
||||
String name = e.getName();
|
||||
assertNotNull(names.remove(name));
|
||||
String toString = e.toString();
|
||||
assertEquals(name, toString);
|
||||
}
|
||||
);
|
||||
|
||||
// Check that all expected names were processed
|
||||
assertTrue(names.isEmpty(), "Unprocessed entries: " + names);
|
||||
|
||||
|
||||
// Check that Stream.toArray produces the expected result
|
||||
Object elements[] = jf.stream().toArray();
|
||||
assertEquals(4, elements.length);
|
||||
assertEquals(elements[0].toString(), "META-INF/");
|
||||
assertEquals(elements[1].toString(), "META-INF/MANIFEST.MF");
|
||||
assertEquals(elements[2].toString(), "entry1.txt");
|
||||
assertEquals(elements[3].toString(), "entry2.txt");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling ZipFile.stream() on a closed ZipFile should throw ISE
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void testClosedZipFile() throws IOException {
|
||||
ZipFile zf = new ZipFile(zip.toFile());
|
||||
zf.close();
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
Stream s = zf.stream();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling JarFile.stream() on a closed JarFile should throw ISE
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void testClosedJarFile() throws IOException {
|
||||
JarFile jf = new JarFile(jar.toFile());
|
||||
jf.close();
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
Stream s = jf.stream();
|
||||
});
|
||||
}
|
||||
}
|
||||
166
test/jdk/java/util/zip/ZipFile/TestCleaner.java
Normal file
166
test/jdk/java/util/zip/ZipFile/TestCleaner.java
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2025, 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.
|
||||
*
|
||||
* 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 8185582 8197989
|
||||
* @summary Check the resources of Inflater, Deflater and ZipFile are always
|
||||
* cleaned/released when the instance is not unreachable
|
||||
* @modules java.base/java.util.zip:open java.base/jdk.internal.vm.annotation
|
||||
* @library /test/lib
|
||||
* @comment The test relies on the Cleaner to invoke the cleaning actions. So
|
||||
* we use "othervm" to prevent any Cleaner delays that could be contributed by any
|
||||
* other tests or code that might have executed on the agentvm prior to this test
|
||||
* execution
|
||||
* @run main/othervm TestCleaner
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.zip.*;
|
||||
import jdk.internal.vm.annotation.DontInline;
|
||||
import jdk.test.lib.util.ForceGC;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
public class TestCleaner {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
testDeInflater();
|
||||
testZipFile();
|
||||
}
|
||||
|
||||
private static long addrOf(Object obj) {
|
||||
try {
|
||||
Field addr = obj.getClass().getDeclaredField("address");
|
||||
if (!addr.trySetAccessible()) {
|
||||
return -1;
|
||||
}
|
||||
return addr.getLong(obj);
|
||||
} catch (Exception x) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// verify the "native resource" of In/Deflater has been cleaned
|
||||
private static void testDeInflater() throws Throwable {
|
||||
Field zsRefDef = Deflater.class.getDeclaredField("zsRef");
|
||||
Field zsRefInf = Inflater.class.getDeclaredField("zsRef");
|
||||
if (!zsRefDef.trySetAccessible() || !zsRefInf.trySetAccessible()) {
|
||||
throw new RuntimeException("'zsRef' is not accessible");
|
||||
}
|
||||
if (addrOf(zsRefDef.get(new Deflater())) == -1 ||
|
||||
addrOf(zsRefInf.get(new Inflater())) == -1) {
|
||||
throw new RuntimeException("'addr' is not accessible");
|
||||
}
|
||||
List<Object> list = new ArrayList<>();
|
||||
byte[] buf1 = new byte[1024];
|
||||
byte[] buf2 = new byte[1024];
|
||||
for (int i = 0; i < 10; i++) {
|
||||
var def = new Deflater();
|
||||
list.add(zsRefDef.get(def));
|
||||
def.setInput("hello".getBytes());
|
||||
def.finish();
|
||||
int n = def.deflate(buf1);
|
||||
|
||||
var inf = new Inflater();
|
||||
list.add(zsRefInf.get(inf));
|
||||
inf.setInput(buf1, 0, n);
|
||||
n = inf.inflate(buf2);
|
||||
if (!"hello".equals(new String(buf2, 0, n))) {
|
||||
throw new RuntimeException("compression/decompression failed");
|
||||
}
|
||||
}
|
||||
|
||||
final AtomicLong numNotYetCleaned = new AtomicLong();
|
||||
// trigger GC
|
||||
final boolean resourcesCleaned = ForceGC.wait(() -> {
|
||||
final long remaining = list.stream().filter(o -> addrOf(o) != 0).count();
|
||||
numNotYetCleaned.set(remaining);
|
||||
return remaining == 0;
|
||||
});
|
||||
if (!resourcesCleaned) {
|
||||
throw new RuntimeException(numNotYetCleaned.get()
|
||||
+ " resources haven't yet been cleaned");
|
||||
}
|
||||
}
|
||||
|
||||
@DontInline
|
||||
private static Object openAndCloseZipFile(File zip) throws Throwable {
|
||||
try {
|
||||
try (var fos = new FileOutputStream(zip);
|
||||
var zos = new ZipOutputStream(fos)) {
|
||||
zos.putNextEntry(new ZipEntry("hello"));
|
||||
zos.write("hello".getBytes(US_ASCII));
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
var zf = new ZipFile(zip);
|
||||
var es = zf.entries();
|
||||
while (es.hasMoreElements()) {
|
||||
zf.getInputStream(es.nextElement()).read();
|
||||
}
|
||||
|
||||
Field fieldRes = ZipFile.class.getDeclaredField("res");
|
||||
if (!fieldRes.trySetAccessible()) {
|
||||
throw new RuntimeException("'ZipFile.res' is not accesible");
|
||||
}
|
||||
Object zfRes = fieldRes.get(zf);
|
||||
if (zfRes == null) {
|
||||
throw new RuntimeException("'ZipFile.res' is null");
|
||||
}
|
||||
Field fieldZsrc = zfRes.getClass().getDeclaredField("zsrc");
|
||||
if (!fieldZsrc.trySetAccessible()) {
|
||||
throw new RuntimeException("'ZipFile.zsrc' is not accesible");
|
||||
}
|
||||
return fieldZsrc.get(zfRes);
|
||||
} finally {
|
||||
zip.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void testZipFile() throws Throwable {
|
||||
File dir = new File(System.getProperty("test.dir", "."));
|
||||
File zip = File.createTempFile("testzf", "zip", dir);
|
||||
|
||||
Object zsrc = openAndCloseZipFile(zip);
|
||||
if (zsrc != null) {
|
||||
Field zfileField = zsrc.getClass().getDeclaredField("zfile");
|
||||
if (!zfileField.trySetAccessible()) {
|
||||
throw new RuntimeException("'ZipFile.Source.zfile' is not accessible");
|
||||
}
|
||||
final boolean resourceCleaned = ForceGC.wait(() -> {
|
||||
try {
|
||||
return zfileField.get(zsrc) == null;
|
||||
} catch (IllegalAccessException e) {
|
||||
// shouldn't happen
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
if (!resourceCleaned) {
|
||||
throw new RuntimeException("cleaner failed to clean zipfile " + zip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
358
test/jdk/java/util/zip/ZipFile/TestZipFile.java
Normal file
358
test/jdk/java/util/zip/ZipFile/TestZipFile.java
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2020, 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.
|
||||
*
|
||||
* 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 8146431
|
||||
* @modules java.base/java.util.zip:open
|
||||
* @summary Tests various ZipFile apis
|
||||
* @run main/manual TestZipFile
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class TestZipFile {
|
||||
|
||||
private static final Random r = new Random();
|
||||
private static final int N = 50;
|
||||
private static final int NN = 10;
|
||||
private static final int ENUM = 10000;
|
||||
private static final int ESZ = 10000;
|
||||
private static ExecutorService executor = Executors.newFixedThreadPool(20);
|
||||
private static final Set<Path> paths = new HashSet<>();
|
||||
private static final boolean isWindows = System.getProperty("os.name")
|
||||
.startsWith("Windows");
|
||||
|
||||
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);
|
||||
}
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(10, TimeUnit.MINUTES);
|
||||
executor = Executors.newFixedThreadPool(20);
|
||||
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);
|
||||
if(!isWindows) {
|
||||
testCachedDelete();
|
||||
testCachedOverwrite();
|
||||
}
|
||||
}
|
||||
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 = "test-" + 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 = "testDelete-" + 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 = "testCachedDelete-" + 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 = "testCachedOverWrite-" + 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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, is.readAllBytes())) {
|
||||
//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 {
|
||||
// (0) check zero-length entry name, no AIOOBE
|
||||
try {
|
||||
check(zf.getEntry("") == null);
|
||||
} catch (Throwable t) {
|
||||
unexpected(t);
|
||||
}
|
||||
|
||||
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, is.readAllBytes()));
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Zip {
|
||||
final String name;
|
||||
final 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 new 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, method, 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 new RuntimeException(x);
|
||||
}
|
||||
try {
|
||||
this.attrs = Files.readAttributes(Paths.get(name), BasicFileAttributes.class);
|
||||
this.lastModified = new File(name).lastModified();
|
||||
} catch (Exception x) {
|
||||
throw new 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 boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
||||
System.out.println("\nPassed = " + passed + " failed = " + failed);
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
||||
339
test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java
Normal file
339
test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2026, 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.
|
||||
*
|
||||
* 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 8243254
|
||||
* @summary Tests a simple set of operations on Zip files in various encodings
|
||||
* focusing on ensuring metadata is properly encoded and read.
|
||||
* @run junit/timeout=480 TestZipFileEncodings
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TestZipFileEncodings {
|
||||
|
||||
private static int NUM_ENTRIES = 100;
|
||||
private static int METAINF_ENTRIES = 5;
|
||||
private static int ENTRY_SIZE = 100;
|
||||
|
||||
private static final AtomicInteger SEQUENCE = new AtomicInteger(0);
|
||||
|
||||
private static Set<Path> paths = new HashSet<>();
|
||||
|
||||
private static Random random() {
|
||||
return ThreadLocalRandom.current();
|
||||
}
|
||||
|
||||
public static Stream<String> nonUnicodeCharsets() {
|
||||
return Stream.of(
|
||||
"ISO-8859-1",
|
||||
"IBM01149",
|
||||
"IBM037",
|
||||
"IBM-Thai"
|
||||
);
|
||||
}
|
||||
|
||||
public static Stream<String> unicodeCharsets() {
|
||||
return Stream.of(
|
||||
"UTF-8",
|
||||
"UTF-16",
|
||||
"UTF-16LE",
|
||||
"UTF-16BE",
|
||||
"UTF-32"
|
||||
);
|
||||
}
|
||||
|
||||
public static Stream<String> allCharsets() {
|
||||
return Stream.concat(nonUnicodeCharsets(), unicodeCharsets());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("nonUnicodeCharsets")
|
||||
public void testNonUnicode(String charsetName) throws Throwable {
|
||||
test(NUM_ENTRIES, 100 + random().nextInt(ENTRY_SIZE), false, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("unicodeCharsets")
|
||||
public void testUnicode(String charsetName) throws Throwable {
|
||||
test(NUM_ENTRIES, 100 + random().nextInt(ENTRY_SIZE), true, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("nonUnicodeCharsets")
|
||||
public void testNonUnicodeManyEntries(String charsetName) throws Throwable {
|
||||
test(70000, 10, false, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("unicodeCharsets")
|
||||
public void testUnicodeManyEntries(String charsetName) throws Throwable {
|
||||
test(70000, 10, true, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* This test was added to catch a regression where UTFZipCoder incorrectly
|
||||
* treated latin1-encoded Strings as UTF8-compatible, while this actually only
|
||||
* holds for ASCII strings.
|
||||
*
|
||||
* The implementation of UTFZipCoder.compare was later changed to not depend on
|
||||
* the String's coder. Let's keep this test around anyway, since it provokes
|
||||
* a corner case which could be easily missed.
|
||||
*/
|
||||
@Test
|
||||
public void latin1NotAscii() throws IOException {
|
||||
|
||||
Path zip = Path.of("latin1-not-ascii.zip");
|
||||
|
||||
// latin1, but not ASCII
|
||||
String entryName = "smörgåsbord";
|
||||
|
||||
try (ZipOutputStream z = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
z.putNextEntry(new ZipEntry(entryName));
|
||||
}
|
||||
|
||||
try (ZipFile z = new ZipFile(zip.toFile())) {
|
||||
assertNotNull(z.getEntry(entryName));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This test was added to catch a regression where ZipCoder.compare did not
|
||||
* properly verify that the lookup name is a prefix of the entry name. Because of
|
||||
* this regression, any candidate name with identical lengths and a trailing
|
||||
* '/' would be incorrectly considered a "directory match".
|
||||
*
|
||||
* Since this regression depends on both a hash collision and that the length of names
|
||||
* are equal, it is rarely found in the wild. Let's keep this test around
|
||||
* since it explicity provokes this rare condition.
|
||||
*
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("allCharsets")
|
||||
public void sameHashAndLengthDirLookup(String charsetName) throws IOException {
|
||||
// Two directory names with colliding hash codes and same length
|
||||
// (found in a brute force search)
|
||||
String one = "_____1637461950/";
|
||||
String two = "_____-408231241/";
|
||||
|
||||
// Create a ZIP containing the two directories
|
||||
Charset charset = Charset.forName(charsetName);
|
||||
Path zip = Path.of("hash-collision-slashmatch-utf16.zip");
|
||||
try (ZipOutputStream z = new ZipOutputStream(Files.newOutputStream(zip), charset)) {
|
||||
|
||||
// Give the names different comments so they we can distinguish them
|
||||
ZipEntry first = new ZipEntry(one);
|
||||
first.setComment("Entry one");
|
||||
z.putNextEntry(first);
|
||||
|
||||
ZipEntry second = new ZipEntry(two);
|
||||
second.setComment("Entry two");
|
||||
z.putNextEntry(second);
|
||||
}
|
||||
|
||||
// Assert that "slashless" lookups returns the correct entry even
|
||||
// when the directory names have colliding hash codes and equal lengths
|
||||
try (ZipFile z = new ZipFile(zip.toFile(), charset)) {
|
||||
|
||||
ZipEntry second = z.getEntry("_____-408231241");
|
||||
assertEquals("Entry two", second.getComment());
|
||||
|
||||
ZipEntry first = z.getEntry("_____1637461950");
|
||||
assertEquals("Entry one", first.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() {
|
||||
for (Path path : paths) {
|
||||
path.toFile().deleteOnExit();
|
||||
}
|
||||
}
|
||||
|
||||
static void test(int numEntry, int szMax, boolean unicode, Charset cs) throws Throwable {
|
||||
String name = "zfenc-" + SEQUENCE.incrementAndGet() + ".zip";
|
||||
Zip zip = new Zip(name, numEntry, szMax, unicode, cs);
|
||||
doTest(zip);
|
||||
}
|
||||
|
||||
static void checkEqual(ZipEntry x, ZipEntry y) {
|
||||
assertEquals(y.getName(), x.getName());
|
||||
assertEquals(y.isDirectory(), x.isDirectory());
|
||||
assertEquals(y.getMethod(), x.getMethod());
|
||||
assertEquals(y.getTime() / 2000, (x.getTime() / 2000));
|
||||
assertEquals(y.getSize(), x.getSize());
|
||||
assertEquals(y.getCompressedSize(), x.getCompressedSize());
|
||||
assertEquals(y.getCrc(), x.getCrc());
|
||||
assertEquals(y.getComment(), x.getComment());
|
||||
}
|
||||
|
||||
static void doTest(Zip zip) throws Throwable {
|
||||
try (ZipFile zf = new ZipFile(zip.name, zip.cs)) {
|
||||
doTest0(zip, zf);
|
||||
}
|
||||
}
|
||||
|
||||
static void doTest0(Zip zip, ZipFile zf) throws Throwable {
|
||||
// (0) check zero-length entry name, no AIOOBE
|
||||
assertEquals(null, zf.getEntry(""));
|
||||
|
||||
List<ZipEntry> list = new ArrayList(zip.entries.keySet());
|
||||
// check each entry and its bytes
|
||||
for (ZipEntry ze : list) {
|
||||
byte[] data = zip.entries.get(ze);
|
||||
String name = ze.getName();
|
||||
ZipEntry e = zf.getEntry(name);
|
||||
checkEqual(e, ze);
|
||||
if (!e.isDirectory()) {
|
||||
// check with readAllBytes
|
||||
try (InputStream is = zf.getInputStream(e)) {
|
||||
assertArrayEquals(is.readAllBytes(), data);
|
||||
}
|
||||
int slash = name.indexOf('/');
|
||||
if (slash > 0) {
|
||||
ZipEntry dir1 = zf.getEntry(name.substring(0, slash));
|
||||
ZipEntry dir2 = zf.getEntry(name.substring(0, slash + 1));
|
||||
assertNotNull(dir1);
|
||||
assertNotNull(dir2);
|
||||
assertTrue(dir1.isDirectory());
|
||||
assertTrue(dir2.isDirectory());
|
||||
checkEqual(dir1, dir2);
|
||||
}
|
||||
} else {
|
||||
ZipEntry unslashLookup = zf.getEntry(name.substring(0, name.length() - 1));
|
||||
checkEqual(e, unslashLookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Zip {
|
||||
String name;
|
||||
Charset cs;
|
||||
Map<ZipEntry, byte[]> entries;
|
||||
BasicFileAttributes attrs;
|
||||
long lastModified;
|
||||
|
||||
Zip(String name, int num, int szMax, boolean unicode, Charset cs) {
|
||||
this.cs = cs;
|
||||
this.name = name;
|
||||
entries = new LinkedHashMap<>(num);
|
||||
try {
|
||||
Path p = Paths.get(name);
|
||||
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, cs))
|
||||
{
|
||||
CRC32 crc = new CRC32();
|
||||
for (int i = 0; i < num; i++) {
|
||||
String ename = "entry-" + i + "-name-" + random().nextLong();
|
||||
if (unicode) {
|
||||
// Provokes compatibility issue with slash handling for
|
||||
// non-ASCII compatible Unicode encodings
|
||||
ename = ename + '\u2F2F';
|
||||
zos.putNextEntry(new ZipEntry(ename + '/'));
|
||||
ename = ename + '/' + ename;
|
||||
}
|
||||
ZipEntry ze = new ZipEntry(ename);
|
||||
assertTrue(!ze.isDirectory());
|
||||
writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
|
||||
}
|
||||
// add some manifest entries
|
||||
zos.putNextEntry(new ZipEntry("META-INF/"));
|
||||
for (int i = 0; i < METAINF_ENTRIES; i++) {
|
||||
String meta = "META-INF/" + "entry-" + i + "-metainf-" + random().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[random().nextInt(szMax + 1)];
|
||||
random().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);
|
||||
}
|
||||
}
|
||||
}
|
||||
126
test/jdk/java/util/zip/ZipFile/ZeroDate.java
Normal file
126
test/jdk/java/util/zip/ZipFile/ZeroDate.java
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2024, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import static java.util.zip.ZipFile.CENOFF;
|
||||
import static java.util.zip.ZipFile.CENTIM;
|
||||
import static java.util.zip.ZipFile.ENDHDR;
|
||||
import static java.util.zip.ZipFile.ENDOFF;
|
||||
import static java.util.zip.ZipFile.LOCTIM;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
/* @test
|
||||
* @bug 8184940 8188869
|
||||
* @summary JDK 9 rejects zip files where the modified day or month is 0
|
||||
* or otherwise represent an invalid date, such as 1980-02-30 24:60:60
|
||||
* @author Liam Miller-Cushon
|
||||
* @library /test/lib
|
||||
*/
|
||||
public class ZeroDate {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// create a zip file, and read it in as a byte array
|
||||
Path path = Utils.createTempFile("bad", ".zip");
|
||||
try {
|
||||
try (OutputStream os = Files.newOutputStream(path);
|
||||
ZipOutputStream zos = new ZipOutputStream(os)) {
|
||||
ZipEntry e = new ZipEntry("x");
|
||||
zos.putNextEntry(e);
|
||||
zos.write((int) 'x');
|
||||
}
|
||||
int len = (int) Files.size(path);
|
||||
byte[] data = new byte[len];
|
||||
try (InputStream is = Files.newInputStream(path)) {
|
||||
is.read(data);
|
||||
}
|
||||
|
||||
// year, month, day are zero
|
||||
testDate(data.clone(), 0, LocalDate.of(1979, 11, 30).atStartOfDay());
|
||||
// only year is zero
|
||||
testDate(data.clone(), 0 << 25 | 4 << 21 | 5 << 16, LocalDate.of(1980, 4, 5).atStartOfDay());
|
||||
// month is greater than 12
|
||||
testDate(data.clone(), 0 << 25 | 13 << 21 | 1 << 16, LocalDate.of(1981, 1, 1).atStartOfDay());
|
||||
// 30th of February
|
||||
testDate(data.clone(), 0 << 25 | 2 << 21 | 30 << 16, LocalDate.of(1980, 3, 1).atStartOfDay());
|
||||
// 30th of February, 24:60:60
|
||||
testDate(data.clone(), 0 << 25 | 2 << 21 | 30 << 16 | 24 << 11 | 60 << 5 | 60 >> 1,
|
||||
LocalDateTime.of(1980, 3, 2, 1, 1, 0));
|
||||
} finally {
|
||||
Files.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testDate(byte[] data, int date, LocalDateTime expected) throws IOException {
|
||||
// set the datetime
|
||||
int endpos = data.length - ENDHDR;
|
||||
int cenpos = u16(data, endpos + ENDOFF);
|
||||
int locpos = u16(data, cenpos + CENOFF);
|
||||
writeU32(data, cenpos + CENTIM, date);
|
||||
writeU32(data, locpos + LOCTIM, date);
|
||||
|
||||
// ensure that the archive is still readable, and the date is 1979-11-30
|
||||
Path path = Utils.createTempFile("out", ".zip");
|
||||
try (OutputStream os = Files.newOutputStream(path)) {
|
||||
os.write(data);
|
||||
}
|
||||
try (ZipFile zf = new ZipFile(path.toFile())) {
|
||||
ZipEntry ze = zf.entries().nextElement();
|
||||
Instant actualInstant = ze.getLastModifiedTime().toInstant();
|
||||
Instant expectedInstant = expected.atZone(ZoneId.systemDefault()).toInstant();
|
||||
if (!actualInstant.equals(expectedInstant)) {
|
||||
throw new AssertionError(
|
||||
String.format("actual: %s, expected: %s", actualInstant, expectedInstant));
|
||||
}
|
||||
} finally {
|
||||
Files.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
static int u8(byte[] data, int offset) {
|
||||
return data[offset] & 0xff;
|
||||
}
|
||||
|
||||
static int u16(byte[] data, int offset) {
|
||||
return u8(data, offset) + (u8(data, offset + 1) << 8);
|
||||
}
|
||||
|
||||
private static void writeU32(byte[] data, int pos, int value) {
|
||||
data[pos] = (byte) (value & 0xff);
|
||||
data[pos + 1] = (byte) ((value >> 8) & 0xff);
|
||||
data[pos + 2] = (byte) ((value >> 16) & 0xff);
|
||||
data[pos + 3] = (byte) ((value >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
211
test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java
Normal file
211
test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2024, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8226530 8303891
|
||||
* @summary Verify that ZipFile reads size fields using the Zip64 extra
|
||||
* field when only the 'uncompressed size' field has the ZIP64 "magic value" 0xFFFFFFFF
|
||||
* @compile Zip64SizeTest.java
|
||||
* @run junit Zip64SizeTest
|
||||
*/
|
||||
public class Zip64SizeTest {
|
||||
// ZIP file to create
|
||||
private static final Path ZIP_FILE = Path.of("Zip64SizeTest.zip");
|
||||
// Contents to write to ZIP entries
|
||||
private static final byte[] CONTENT = "Hello".getBytes(StandardCharsets.UTF_8);
|
||||
// This opaque tag will be ignored by ZipEntry.setExtra0
|
||||
private static final int UNKNOWN_TAG = 0x9902;
|
||||
// Tag used when converting the extra field to a real ZIP64 extra field
|
||||
private static final short ZIP64_TAG = 0x1;
|
||||
// Marker value to indicate that the actual value is stored in the ZIP64 extra field
|
||||
private static final int ZIP64_MAGIC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
/**
|
||||
* Validate that if the 'uncompressed size' of a ZIP CEN header is 0xFFFFFFFF, then the
|
||||
* actual size is retrieved from the corresponding ZIP64 Extended information field.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void validateZipEntrySizes() throws IOException {
|
||||
createZipFile();
|
||||
System.out.println("Validating Zip Entry Sizes");
|
||||
try (ZipFile zip = new ZipFile(ZIP_FILE.toFile())) {
|
||||
ZipEntry ze = zip.getEntry("first");
|
||||
System.out.printf("Entry: %s, size= %s%n", ze.getName(), ze.getSize());
|
||||
assertEquals(CONTENT.length, ze.getSize());
|
||||
ze = zip.getEntry("second");
|
||||
System.out.printf("Entry: %s, size= %s%n", ze.getName(), ze.getSize());
|
||||
assertEquals(CONTENT.length, ze.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ZIP file with a CEN entry where the 'uncompressed size' is stored in
|
||||
* the ZIP64 field, but the 'compressed size' is in the CEN field. This makes the
|
||||
* ZIP64 data block 8 bytes long, which triggers the regression described in 8226530.
|
||||
*
|
||||
* The CEN entry for the "first" entry will have the following structure:
|
||||
* (Note the CEN 'Uncompressed Length' being 0xFFFFFFFF and the ZIP64
|
||||
* 'Uncompressed Size' being 5)
|
||||
*
|
||||
* 0081 CENTRAL HEADER #1 02014B50
|
||||
* 0085 Created Zip Spec 14 '2.0'
|
||||
* 0086 Created OS 00 'MS-DOS'
|
||||
* [...] Omitted for brevity
|
||||
* 0091 CRC F7D18982
|
||||
* 0095 Compressed Length 00000007
|
||||
* 0099 Uncompressed Length FFFFFFFF
|
||||
* [...] Omitted for brevity
|
||||
* 00AF Filename 'first'
|
||||
* 00B4 Extra ID #0001 0001 'ZIP64'
|
||||
* 00B6 Length 0008
|
||||
* 00B8 Uncompressed Size 0000000000000005
|
||||
*
|
||||
* @throws IOException if an error occurs creating the ZIP File
|
||||
*/
|
||||
private static void createZipFile() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
|
||||
// The 'first' entry will store 'uncompressed size' in the Zip64 format
|
||||
ZipEntry e1 = new ZipEntry("first");
|
||||
|
||||
// Make an extra field with the correct size for an 8-byte 'uncompressed size'
|
||||
// Zip64 field. Temporarily use the 'unknown' tag 0x9902 to make
|
||||
// ZipEntry.setExtra0 skip parsing this as a Zip64.
|
||||
// See APPNOTE.TXT, 4.6.1 Third Party Mappings
|
||||
byte[] opaqueExtra = createBlankExtra((short) UNKNOWN_TAG, (short) Long.BYTES);
|
||||
e1.setExtra(opaqueExtra);
|
||||
|
||||
zos.putNextEntry(e1);
|
||||
zos.write(CONTENT);
|
||||
|
||||
// A second entry, not in Zip64 format
|
||||
ZipEntry e2 = new ZipEntry("second");
|
||||
zos.putNextEntry(e2);
|
||||
zos.write(CONTENT);
|
||||
}
|
||||
|
||||
byte[] zip = baos.toByteArray();
|
||||
|
||||
// Update the CEN of 'first' to use the Zip64 format
|
||||
updateCENHeaderToZip64(zip);
|
||||
Files.write(ZIP_FILE, zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the CEN entry of the "first" entry to use ZIP64 format for the
|
||||
* 'uncompressed size' field. The updated extra field will have the following
|
||||
* structure:
|
||||
*
|
||||
* 00B4 Extra ID #0001 0001 'ZIP64'
|
||||
* 00B6 Length 0008
|
||||
* 00B8 Uncompressed Size 0000000000000005
|
||||
*
|
||||
* @param zip the ZIP file to update to ZIP64
|
||||
*/
|
||||
private static void updateCENHeaderToZip64(byte[] zip) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(zip).order(ByteOrder.LITTLE_ENDIAN);
|
||||
// Find the offset of the first CEN header
|
||||
int cenOffset = buffer.getInt(zip.length- ZipFile.ENDHDR + ZipFile.ENDOFF);
|
||||
// Find the offset of the extra field
|
||||
int nlen = buffer.getShort(cenOffset + ZipFile.CENNAM);
|
||||
int extraOffset = cenOffset + ZipFile.CENHDR + nlen;
|
||||
|
||||
// Change the header ID from 'unknown' to ZIP64
|
||||
buffer.putShort(extraOffset, ZIP64_TAG);
|
||||
// Update the 'uncompressed size' ZIP64 value to the actual uncompressed length
|
||||
int fieldOffset = extraOffset
|
||||
+ Short.BYTES // TAG
|
||||
+ Short.BYTES; // data size
|
||||
buffer.putLong(fieldOffset, CONTENT.length);
|
||||
|
||||
// Set the 'uncompressed size' field of the CEN to 0xFFFFFFFF
|
||||
buffer.putInt(cenOffset + ZipFile.CENLEN, ZIP64_MAGIC_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an extra field with the given tag and data block size, and a
|
||||
* blank data block.
|
||||
* @return an extra field with the specified tag and size
|
||||
* @param tag the header id of the extra field
|
||||
* @param blockSize the size of the extra field's data block
|
||||
*/
|
||||
private static byte[] createBlankExtra(short tag, short blockSize) {
|
||||
int size = Short.BYTES // tag
|
||||
+ Short.BYTES // data block size
|
||||
+ blockSize; // data block;
|
||||
|
||||
byte[] extra = new byte[size];
|
||||
ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN)
|
||||
.putShort(0, tag)
|
||||
.putShort(Short.BYTES, blockSize);
|
||||
return extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the needed test files do not exist prior to executing the test
|
||||
* @throws IOException
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
deleteFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the files created for the test
|
||||
* @throws IOException
|
||||
*/
|
||||
@AfterEach
|
||||
public void tearDown() throws IOException {
|
||||
deleteFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the files created for use by the test
|
||||
* @throws IOException if an error occurs deleting the files
|
||||
*/
|
||||
private static void deleteFiles() throws IOException {
|
||||
Files.deleteIfExists(ZIP_FILE);
|
||||
}
|
||||
}
|
||||
131
test/jdk/java/util/zip/ZipFile/ZipEntryFreeTest.java
Normal file
131
test/jdk/java/util/zip/ZipFile/ZipEntryFreeTest.java
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2017, 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.
|
||||
*
|
||||
* 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 6907252
|
||||
* @summary ZipFileInputStream Not Thread-Safe
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Platform
|
||||
* jdk.test.lib.util.FileUtils
|
||||
* @run main ZipEntryFreeTest
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.zip.*;
|
||||
import jdk.test.lib.util.FileUtils;
|
||||
|
||||
public class ZipEntryFreeTest extends Thread {
|
||||
|
||||
private static final int NUM_THREADS = 5;
|
||||
private static final int TEST_ITERATIONS = 5;
|
||||
private static final String ZIPFILE_NAME = "large.zip";
|
||||
private static final String ZIPENTRY_NAME = "random.txt";
|
||||
private static InputStream is = null;
|
||||
final Timer timer = new Timer();
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
createZipFile();
|
||||
try {
|
||||
for (int i = 0; i < TEST_ITERATIONS; i++) {
|
||||
runTest();
|
||||
}
|
||||
} finally {
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(ZIPFILE_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTest() throws Exception {
|
||||
try (ZipFile zf = new ZipFile(new File(ZIPFILE_NAME))) {
|
||||
is = zf.getInputStream(zf.getEntry(ZIPENTRY_NAME + "_0"));
|
||||
Thread[] threadArray = new Thread[NUM_THREADS];
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i] = new ZipEntryFreeTest();
|
||||
}
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i].start();
|
||||
}
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i].join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createZipFile() throws Exception {
|
||||
Random rnd = new Random(1000L);
|
||||
byte[] contents = new byte[2_000_000];
|
||||
ZipEntry ze = null;
|
||||
|
||||
try (ZipOutputStream zos =
|
||||
new ZipOutputStream(new FileOutputStream(ZIPFILE_NAME))) {
|
||||
// uncompressed mode seemed to tickle the crash
|
||||
zos.setMethod(ZipOutputStream.STORED);
|
||||
for (int ze_count = 0; ze_count < 10; ze_count++) {
|
||||
rnd.nextBytes(contents);
|
||||
ze = createZipEntry(contents, ze_count);
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(contents, 0, contents.length);
|
||||
}
|
||||
zos.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private static ZipEntry createZipEntry(byte[] b, int i) {
|
||||
ZipEntry ze = new ZipEntry(ZIPENTRY_NAME + "_" + i);
|
||||
ze.setCompressedSize(b.length);
|
||||
ze.setSize(b.length);
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(b);
|
||||
ze.setCrc(crc.getValue());
|
||||
return ze;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int iteration = 0;
|
||||
TimerTask tt = (new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
});
|
||||
timer.schedule(tt, 50);
|
||||
while (is.read() != -1 && iteration++ < 1_000) { }
|
||||
} catch (ZipException ze) {
|
||||
// ZipException now expected instead of ZIP_Read crash
|
||||
System.out.println(ze);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
timer.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
152
test/jdk/java/util/zip/ZipFile/ZipEntryTimeBounds.java
Normal file
152
test/jdk/java/util/zip/ZipFile/ZipEntryTimeBounds.java
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
/* @test
|
||||
* @bug 8246129
|
||||
* @summary JDK add metadata to zip files with entries timestamped at the
|
||||
* lower bound of the DOS time epoch, i.e., 1980-01-01T00:00:00Z
|
||||
* @run junit/othervm ZipEntryTimeBounds
|
||||
*/
|
||||
public class ZipEntryTimeBounds {
|
||||
|
||||
@Test
|
||||
public void testFilesWithEntryAtLowerTimeBoundAreEqual() throws Exception {
|
||||
|
||||
// Ensure that entries that end up being exactly at the start of the
|
||||
// DOS epoch, java.util.zip.ZipEntry.DOSTIME_BEFORE_1980, or
|
||||
// 1980-01-01 00:00:00 are written without any extra timestamp metadata
|
||||
// being written
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT-01"));
|
||||
File f1 = createTempFile();
|
||||
makeZip(f1, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 0).getTimeInMillis());
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
File f2 = createTempFile();
|
||||
makeZip(f2, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 0).getTimeInMillis());
|
||||
assertEquals(-1L, Files.mismatch(f1.toPath(), f2.toPath()));
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+01"));
|
||||
File f3 = createTempFile();
|
||||
makeZip(f3, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 0).getTimeInMillis());
|
||||
assertEquals(-1L, Files.mismatch(f1.toPath(), f3.toPath()));
|
||||
|
||||
// Check that the milliseconds part of the time is exactly preserved
|
||||
assertEquals(0, new ZipFile(f1).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(0, new ZipFile(f2).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(0, new ZipFile(f3).getEntry("entry.txt").getTime() % 60000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilesWithEntryAfterLowerTimeBoundAreEqual() throws Exception {
|
||||
// Ensure files written using different timezone with entries set
|
||||
// shortly after 1980-01-01 00:00:00 produce exactly identical files
|
||||
// without metadata
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT-01"));
|
||||
File f1 = createTempFile();
|
||||
makeZip(f1, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 1).getTimeInMillis());
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
File f2 = createTempFile();
|
||||
makeZip(f2, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 1).getTimeInMillis());
|
||||
assertEquals(-1L, Files.mismatch(f1.toPath(), f2.toPath()));
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+01"));
|
||||
File f3 = createTempFile();
|
||||
makeZip(f3, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 1).getTimeInMillis() + 999);
|
||||
assertEquals(-1L, Files.mismatch(f1.toPath(), f3.toPath()));
|
||||
|
||||
// Check that the seconds part of the time is lossily preserved,
|
||||
// rounding down to the previous 2s step since epoch
|
||||
assertEquals(0, new ZipFile(f1).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(0, new ZipFile(f2).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(0, new ZipFile(f3).getEntry("entry.txt").getTime() % 60000);
|
||||
|
||||
File f4 = createTempFile();
|
||||
makeZip(f4, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 2).getTimeInMillis());
|
||||
assertEquals(2000, new ZipFile(f4).getEntry("entry.txt").getTime() % 60000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilesWithEntryBeforeLowerTimeBoundAreNotEqual() throws Exception {
|
||||
// Files written using different timezone with entries set shortly
|
||||
// before 1980-01-01 00:00:00 will produce files which add timestamp
|
||||
// metadata that make the files turn up not equal
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT-01"));
|
||||
File f1 = createTempFile();
|
||||
makeZip(f1, new GregorianCalendar(1979, Calendar.DECEMBER, 31, 23, 59, 59).getTimeInMillis());
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
File f2 = createTempFile();
|
||||
makeZip(f2, new GregorianCalendar(1979, Calendar.DECEMBER, 31, 23, 59, 59).getTimeInMillis());
|
||||
assertNotEquals(-1L, Files.mismatch(f1.toPath(), f2.toPath()));
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+01"));
|
||||
File f3 = createTempFile();
|
||||
makeZip(f3, new GregorianCalendar(1979, Calendar.DECEMBER, 31, 23, 59, 59).getTimeInMillis() + 500);
|
||||
assertNotEquals(-1L, Files.mismatch(f1.toPath(), f3.toPath()));
|
||||
|
||||
// Check that the time is preserved at second precision, no rounding
|
||||
// to 2s
|
||||
assertEquals(59000, new ZipFile(f1).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(59000, new ZipFile(f2).getEntry("entry.txt").getTime() % 60000);
|
||||
// Milliseconds are discarded even when storing entries with extended
|
||||
// time metadata
|
||||
assertEquals(59000, new ZipFile(f3).getEntry("entry.txt").getTime() % 60000);
|
||||
}
|
||||
|
||||
private static void makeZip(File f, long time) throws Exception {
|
||||
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f))) {
|
||||
ZipEntry e = new ZipEntry("entry.txt");
|
||||
e.setTime(time);
|
||||
out.putNextEntry(e);
|
||||
out.write(new byte[] { 0, 1, 2, 3 });
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private static File createTempFile() throws IOException {
|
||||
File file = File.createTempFile("out", "zip");
|
||||
file.deleteOnExit();
|
||||
return file;
|
||||
}
|
||||
}
|
||||
125
test/jdk/java/util/zip/ZipFile/ZipFileCharsetTest.java
Normal file
125
test/jdk/java/util/zip/ZipFile/ZipFileCharsetTest.java
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8355975
|
||||
* @summary verify that the internal ZIP structure caching in java.util.zip.ZipFile
|
||||
* uses the correct Charset when parsing the ZIP structure of a ZIP file
|
||||
* @run junit ZipFileCharsetTest
|
||||
*/
|
||||
public class ZipFileCharsetTest {
|
||||
|
||||
private static final String ISO_8859_15_NAME = "ISO-8859-15";
|
||||
|
||||
/**
|
||||
* The internal implementation of java.util.zip.ZipFile maintains a cache
|
||||
* of the ZIP structure of each ZIP file that's currently open. This cache
|
||||
* helps prevent repeat parsing of the ZIP structure of the same underlying
|
||||
* ZIP file, every time a ZipFile instance is created for the same ZIP file.
|
||||
* The cache uses an internal key to map a ZIP file to the corresponding
|
||||
* ZIP structure that's cached.
|
||||
* A ZipFile can be constructed by passing a Charset which will be used to
|
||||
* decode the entry names (and comment) in a ZIP file.
|
||||
* The test verifies that when multiple ZipFile instances are
|
||||
* constructed using different Charsets but the same underlying ZIP file,
|
||||
* then the internal caching implementation of ZipFile doesn't end up using
|
||||
* a wrong Charset for parsing the ZIP structure of the ZIP file.
|
||||
*/
|
||||
@Test
|
||||
void testCachedZipFileSource() throws Exception {
|
||||
// ISO-8859-15 is not a standard charset in Java. We skip this test
|
||||
// when it is unavailable
|
||||
assumeTrue(Charset.availableCharsets().containsKey(ISO_8859_15_NAME),
|
||||
"skipping test since " + ISO_8859_15_NAME + " charset isn't available");
|
||||
|
||||
// We choose the byte 0xA4 for entry name in the ZIP file.
|
||||
// 0xA4 is "Euro sign" in ISO-8859-15 charset and
|
||||
// "Currency sign (generic)" in ISO-8859-1 charset.
|
||||
final byte[] entryNameBytes = new byte[]{(byte) 0xA4}; // intentional cast
|
||||
final Charset euroSignCharset = Charset.forName(ISO_8859_15_NAME);
|
||||
final Charset currencySignCharset = ISO_8859_1;
|
||||
|
||||
final String euroSign = new String(entryNameBytes, euroSignCharset);
|
||||
final String currencySign = new String(entryNameBytes, currencySignCharset);
|
||||
|
||||
// create a ZIP file whose entry name is encoded using ISO-8859-15 charset
|
||||
final Path zip = createZIP("euro", euroSignCharset, entryNameBytes);
|
||||
|
||||
// Construct a ZipFile instance using the (incorrect) charset ISO-8859-1.
|
||||
// While that ZipFile instance is still open (and the ZIP file structure
|
||||
// still cached), construct another instance for the same ZIP file, using
|
||||
// the (correct) charset ISO-8859-15.
|
||||
try (ZipFile incorrect = new ZipFile(zip.toFile(), currencySignCharset);
|
||||
ZipFile correct = new ZipFile(zip.toFile(), euroSignCharset)) {
|
||||
|
||||
// correct encoding should resolve the entry name to euro sign
|
||||
// and the entry should be thus be located
|
||||
assertNotNull(correct.getEntry(euroSign), "euro sign entry missing in " + correct);
|
||||
// correct encoding should not be able to find an entry name
|
||||
// with the currency sign
|
||||
assertNull(correct.getEntry(currencySign), "currency sign entry unexpectedly found in "
|
||||
+ correct);
|
||||
|
||||
// incorrect encoding should resolve the entry name to currency sign
|
||||
// and the entry should be thus be located by the currency sign name
|
||||
assertNotNull(incorrect.getEntry(currencySign), "currency sign entry missing in "
|
||||
+ incorrect);
|
||||
// incorrect encoding should not be able to find an entry name
|
||||
// with the euro sign
|
||||
assertNull(incorrect.getEntry(euroSign), "euro sign entry unexpectedly found in "
|
||||
+ incorrect);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and return ZIP file whose entry names are encoded using the given {@code charset}
|
||||
*/
|
||||
private static Path createZIP(final String fileNamePrefix, final Charset charset,
|
||||
final byte[] entryNameBytes) throws IOException {
|
||||
final Path zip = Files.createTempFile(Path.of("."), fileNamePrefix, ".zip");
|
||||
// create a ZIP file whose entry name(s) use the given charset
|
||||
try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(zip), charset)) {
|
||||
zos.putNextEntry(new ZipEntry(new String(entryNameBytes, charset)));
|
||||
final byte[] entryContent = "doesnotmatter".getBytes(US_ASCII);
|
||||
zos.write(entryContent);
|
||||
zos.closeEntry();
|
||||
}
|
||||
return zip;
|
||||
}
|
||||
}
|
||||
587
test/jdk/java/util/zip/ZipFile/ZipFileDuplicateEntryTest.java
Normal file
587
test/jdk/java/util/zip/ZipFile/ZipFileDuplicateEntryTest.java
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8276123
|
||||
* @summary ZipFile::getEntry will not return a file entry when there is a
|
||||
* directory entry of the same name within a Zip File
|
||||
* @run junit/othervm ZipFileDuplicateEntryTest
|
||||
*/
|
||||
public class ZipFileDuplicateEntryTest {
|
||||
|
||||
/**
|
||||
* Name to use for creating Zip entries
|
||||
*/
|
||||
private static final String ENTRY_NAME = "entry";
|
||||
|
||||
/**
|
||||
* Zip and Jar files to be created
|
||||
*/
|
||||
private static final Path ZIP_FILE = Paths.get("fileDirEntry.zip");
|
||||
private static final Path ZIP_FILE2 = Paths.get("OnlyDirEntry.zip");
|
||||
private static final Path DUPLICATE_FILE_ENTRY_FILE = Paths.get("DupFIleEntry.zip");
|
||||
private static final Path TEST_JAR = Paths.get("fileDirEntry.jar");
|
||||
|
||||
/**
|
||||
* Directory entry added to the Zip File.
|
||||
*/
|
||||
private static final Entry DIR_ENTRY =
|
||||
Entry.of(ENTRY_NAME + "/", ZipEntry.DEFLATED,
|
||||
"I am a Directory");
|
||||
|
||||
/**
|
||||
* File entry added to the Zip File.
|
||||
*/
|
||||
private static final Entry FILE_ENTRY =
|
||||
Entry.of(ENTRY_NAME, ZipEntry.DEFLATED, "I am a File");
|
||||
|
||||
/**
|
||||
* Duplicate File entry added to the Zip file. This is the 2nd entry added
|
||||
* to the Zip file and is expected to be returned.
|
||||
*/
|
||||
private static final Entry DUPLICATE_FILE_ENTRY =
|
||||
Entry.of(ENTRY_NAME, ZipEntry.DEFLATED, "Yet another File");
|
||||
/**
|
||||
* Entries expected to be returned via ZipFile::stream
|
||||
*/
|
||||
private static final List<String> EXPECTED_ENTRIES =
|
||||
Arrays.asList(FILE_ENTRY.name, DIR_ENTRY.name);
|
||||
|
||||
/**
|
||||
* Max buffer size for readAllBytes method which can be used when
|
||||
* InputStream::readAllBytes is not available
|
||||
*/
|
||||
private static final int MAX_BUFFER_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* Flag to enable test output
|
||||
*/
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Array representing a Jar File with the entries:
|
||||
* Name: entry, contents: "I am a File"
|
||||
* Name: entry, contents: "Yet another File"
|
||||
* See createByteArray()
|
||||
*/
|
||||
private static final byte[] DUPLICATE_ENTRY_JAR_BYTES = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53, (byte) 0x8e, (byte) 0x39,
|
||||
(byte) 0x14, (byte) 0x49, (byte) 0xd, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xb, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xb,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xd,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xf3,
|
||||
(byte) 0x54, (byte) 0x48, (byte) 0xcc, (byte) 0x55, (byte) 0x48, (byte) 0x54, (byte) 0x70, (byte) 0xcb,
|
||||
(byte) 0xcc, (byte) 0x49, (byte) 0x5, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59,
|
||||
(byte) 0x55, (byte) 0x53, (byte) 0xe1, (byte) 0x4c, (byte) 0x29, (byte) 0xa4, (byte) 0x12, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x12, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8b, (byte) 0x4c, (byte) 0x2d, (byte) 0x51, (byte) 0x48,
|
||||
(byte) 0xcc, (byte) 0xcb, (byte) 0x2f, (byte) 0xc9, (byte) 0x48, (byte) 0x2d, (byte) 0x52, (byte) 0x70,
|
||||
(byte) 0xcb, (byte) 0xcc, (byte) 0x49, (byte) 0x5, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53, (byte) 0x8e, (byte) 0x39, (byte) 0x14,
|
||||
(byte) 0x49, (byte) 0xd, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xb, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53,
|
||||
(byte) 0xe1, (byte) 0x4c, (byte) 0x29, (byte) 0xa4, (byte) 0x12, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x44, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x66,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Zip files used by the tests.
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
|
||||
/**
|
||||
* Zip contains two entries named "entry" and "entry/"
|
||||
*/
|
||||
Files.deleteIfExists(ZIP_FILE);
|
||||
try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(ZIP_FILE))) {
|
||||
zos.putNextEntry(new ZipEntry(FILE_ENTRY.name));
|
||||
zos.write(FILE_ENTRY.bytes);
|
||||
zos.closeEntry();
|
||||
zos.putNextEntry(new ZipEntry(DIR_ENTRY.name));
|
||||
zos.write(DIR_ENTRY.bytes);
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Jar contains two entries named "entry" and "entry/"
|
||||
*/
|
||||
Files.deleteIfExists(TEST_JAR);
|
||||
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(TEST_JAR))) {
|
||||
jos.putNextEntry(new JarEntry(FILE_ENTRY.name));
|
||||
jos.write(FILE_ENTRY.bytes);
|
||||
jos.closeEntry();
|
||||
jos.putNextEntry(new JarEntry(DIR_ENTRY.name));
|
||||
jos.write(DIR_ENTRY.bytes);
|
||||
jos.closeEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip contains the entry "entry/"
|
||||
*/
|
||||
Files.deleteIfExists(ZIP_FILE2);
|
||||
try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(ZIP_FILE2))) {
|
||||
zos.putNextEntry(new ZipEntry(DIR_ENTRY.name));
|
||||
zos.write(DIR_ENTRY.bytes);
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Jar that contains two entries named "entry"
|
||||
*/
|
||||
Files.deleteIfExists(DUPLICATE_FILE_ENTRY_FILE);
|
||||
Files.write(DUPLICATE_FILE_ENTRY_FILE, DUPLICATE_ENTRY_JAR_BYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up after the test run
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@AfterAll
|
||||
public static void cleanup() throws IOException {
|
||||
Files.deleteIfExists(ZIP_FILE);
|
||||
Files.deleteIfExists(ZIP_FILE2);
|
||||
Files.deleteIfExists(DUPLICATE_FILE_ENTRY_FILE);
|
||||
Files.deleteIfExists(TEST_JAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* MethodSource used to specify the Zip entries to use
|
||||
*
|
||||
* @return Stream that indicates which Entry to use within the test
|
||||
*/
|
||||
public static Stream<Entry> entries() {
|
||||
return Stream.of(FILE_ENTRY, DIR_ENTRY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether ZipFile::getEntry can find a directory entry within a Zip
|
||||
* file specifying "name" vs "name/"
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void readDirWithoutSlash() throws IOException {
|
||||
System.out.printf("%n%n**** readDirWithoutSlash ***%n");
|
||||
try (ZipFile zip = new ZipFile(ZIP_FILE2.toString())) {
|
||||
ZipEntry ze = zip.getEntry(ENTRY_NAME);
|
||||
if (DEBUG) {
|
||||
System.out.printf(" Entry:%s, found:%s%n", ENTRY_NAME, ze != null);
|
||||
}
|
||||
assertNotNull(ze);
|
||||
assertTrue(ze.isDirectory());
|
||||
try (InputStream in = zip.getInputStream(ze)) {
|
||||
byte[] bytes = in.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf("name: %s, isDirectory: %s, payload= %s%n",
|
||||
ze.getName(), ze.isDirectory(), new String(bytes));
|
||||
}
|
||||
assertArrayEquals(DIR_ENTRY.bytes, bytes,
|
||||
String.format("Expected payload: %s",
|
||||
new String(DIR_ENTRY.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that ZipFile::getEntry will return the correct entry when a file
|
||||
* and directory have the same name
|
||||
*
|
||||
* @param entry The entry to search for
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("entries")
|
||||
public void testSameFileDirEntryName(Entry entry) throws IOException {
|
||||
System.out.printf("%n%n**** testSameFileDirEntryName ***%n");
|
||||
|
||||
try (ZipFile zip = new ZipFile(ZIP_FILE.toString())) {
|
||||
ZipEntry ze = zip.getEntry(entry.name);
|
||||
if (DEBUG) {
|
||||
System.out.printf(" Entry:%s, found:%s%n", entry.name, ze != null);
|
||||
}
|
||||
assertNotNull(ze);
|
||||
try (InputStream in = zip.getInputStream(ze)) {
|
||||
byte[] bytes = in.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf("name: %s, isDirectory: %s, payload= %s%n",
|
||||
ze.getName(), ze.isDirectory(), new String(bytes));
|
||||
}
|
||||
assertArrayEquals(entry.bytes, bytes,
|
||||
String.format("Expected payload: %s", new String(entry.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that ZipFile::getEntry will return the correct entry, which
|
||||
* is the second entry, when there are duplicate entries within the Zip file.
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void DupFileEntryTest() throws IOException {
|
||||
System.out.printf("%n%n**** DupFileEntryTest ***%n");
|
||||
try (ZipFile zip =
|
||||
new ZipFile(DUPLICATE_FILE_ENTRY_FILE.toString())) {
|
||||
ZipEntry ze = zip.getEntry(ENTRY_NAME);
|
||||
if (DEBUG) {
|
||||
System.out.printf(" Entry:%s, found:%s%n", ENTRY_NAME, ze != null);
|
||||
}
|
||||
assertNotNull(ze);
|
||||
try (InputStream in = zip.getInputStream(ze)) {
|
||||
byte[] bytes = in.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf("name: %s, isDirectory: %s, payload= %s%n",
|
||||
ze.getName(), ze.isDirectory(), new String(bytes));
|
||||
}
|
||||
assertArrayEquals(DUPLICATE_FILE_ENTRY.bytes, bytes,
|
||||
String.format("Expected payload: %s", new String(DUPLICATE_FILE_ENTRY.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipInputStream can be used to read all Zip entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void ZipInputStreamTest() throws IOException {
|
||||
System.out.printf("%n%n**** ZipInputStreamTest ***%n");
|
||||
try (ZipInputStream zis = new ZipInputStream(
|
||||
new FileInputStream(ZIP_FILE.toFile()))) {
|
||||
ZipEntry zipEntry = zis.getNextEntry();
|
||||
assertNotNull(zipEntry);
|
||||
while (zipEntry != null) {
|
||||
Entry e;
|
||||
if (zipEntry.getName().equals(FILE_ENTRY.name)) {
|
||||
e = FILE_ENTRY;
|
||||
} else if (zipEntry.getName().equals(DIR_ENTRY.name)) {
|
||||
e = DIR_ENTRY;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
String.format("Invalid Zip entry: %s", zipEntry.getName()));
|
||||
}
|
||||
assertEquals(e.method, zipEntry.getMethod());
|
||||
assertArrayEquals(e.bytes, zis.readAllBytes(),
|
||||
String.format("Expected payload: %s", new String(e.bytes)));
|
||||
zipEntry = zis.getNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile::stream returns all Zip entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void ZipFileStreamTest() throws IOException {
|
||||
System.out.printf("%n%n**** ZipFileStreamTest ***%n");
|
||||
try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {
|
||||
List<? extends ZipEntry> entries = zf.stream().collect(Collectors.toList());
|
||||
assertEquals(EXPECTED_ENTRIES.size(), entries.size());
|
||||
for (ZipEntry e : entries) {
|
||||
assertTrue(EXPECTED_ENTRIES.contains(e.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarFile can be used to read all the entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @param entry The entry to validate
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("entries")
|
||||
public void JarFileInputStreamTest(Entry entry) throws IOException {
|
||||
System.out.printf("%n%n**** JarFileInputStreamTest ***%n");
|
||||
try (JarFile jarFile = new JarFile(TEST_JAR.toFile())) {
|
||||
JarEntry je = jarFile.getJarEntry(entry.name);
|
||||
assertNotNull(je);
|
||||
if (DEBUG) {
|
||||
System.out.printf("Entry Name: %s, method: %s, Expected Method: %s%n",
|
||||
entry.name, je.getMethod(), entry.method);
|
||||
}
|
||||
assertEquals(entry.method, je.getMethod());
|
||||
try (InputStream in = jarFile.getInputStream(je)) {
|
||||
byte[] bytes = in.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf("bytes= %s, expected=%s%n",
|
||||
new String(bytes), new String(entry.bytes));
|
||||
}
|
||||
assertArrayEquals(entry.bytes, bytes,
|
||||
String.format("Expected payload: %s", new String(entry.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarInputStream can be used to read all entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void JarInputStreamTest() throws IOException {
|
||||
System.out.printf("%n%n**** JarInputStreamTest ***%n");
|
||||
try (JarInputStream jis = new JarInputStream(
|
||||
new FileInputStream(TEST_JAR.toFile()))) {
|
||||
JarEntry jarEntry = jis.getNextJarEntry();
|
||||
assertNotNull(jarEntry);
|
||||
while (jarEntry != null) {
|
||||
Entry e;
|
||||
if (jarEntry.getName().equals(FILE_ENTRY.name)) {
|
||||
e = FILE_ENTRY;
|
||||
} else if (jarEntry.getName().equals(DIR_ENTRY.name)) {
|
||||
e = DIR_ENTRY;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
String.format("Invalid Jar entry: %s", jarEntry.getName()));
|
||||
}
|
||||
assertEquals(e.method, jarEntry.getMethod());
|
||||
assertArrayEquals(e.bytes, jis.readAllBytes(),
|
||||
String.format("Expected payload: %s", new String(e.bytes)));
|
||||
jarEntry = jis.getNextJarEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarURLConnection can be used to access all the entries including
|
||||
* a file and directory entry with the same name within a jar file
|
||||
*
|
||||
* @param entry The entry to validate
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("entries")
|
||||
public void JarURLConnectionTest(Entry entry) throws Exception {
|
||||
System.out.printf("%n%n**** JarURLConnectionTest ***%n");
|
||||
URL url = new URL("jar:" + TEST_JAR.toUri().toURL() + "!/" + entry.name);
|
||||
if (DEBUG) {
|
||||
System.out.printf("URL=%s%n", url);
|
||||
}
|
||||
JarURLConnection con = (JarURLConnection) url.openConnection();
|
||||
con.connect();
|
||||
JarEntry je = con.getJarEntry();
|
||||
try (JarFile jarFile = con.getJarFile()) {
|
||||
assertNotNull(je);
|
||||
assertNotNull(jarFile);
|
||||
assertNull(con.getAttributes());
|
||||
assertNull(con.getMainAttributes());
|
||||
assertNull(con.getManifest());
|
||||
assertEquals(entry.name, je.getName());
|
||||
assertEquals(entry.name, con.getEntryName());
|
||||
assertEquals(entry.method, je.getMethod());
|
||||
assertEquals(TEST_JAR.toUri().toURL(), con.getJarFileURL());
|
||||
if (DEBUG) {
|
||||
System.out.printf(" getEntryName: %s, getJarFileURL:%s%n",
|
||||
con.getEntryName(), con.getJarFileURL());
|
||||
System.out.printf(" Jar Entry= %s, size= %s%n", je.getName(), je.getSize());
|
||||
}
|
||||
|
||||
try (InputStream is = jarFile.getInputStream(je)) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf(" Bytes read:%s%n", new String(bytes));
|
||||
}
|
||||
assertArrayEquals(entry.bytes, bytes,
|
||||
String.format("Expected payload: %s", new String(entry.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarFile::stream returns all entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void JarFileStreamTest() throws IOException {
|
||||
System.out.printf("%n%n**** JarFileStreamTest ***%n");
|
||||
try (JarFile jf = new JarFile(TEST_JAR.toFile())) {
|
||||
List<? extends JarEntry> entries = jf.stream().collect(Collectors.toList());
|
||||
assertEquals(EXPECTED_ENTRIES.size(), jf.size());
|
||||
for (JarEntry e : entries) {
|
||||
assertTrue(EXPECTED_ENTRIES.contains(e.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to read the bytes from an InputStream. This method is
|
||||
* here so that the test could be backported to JDK 8 if needed as
|
||||
* InputStream::readAllBytes() does not exist
|
||||
*
|
||||
* @param is The InputStream to read from
|
||||
* @return The byte array representing bytes read from the InputStream
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
public static byte[] readAllBytes(InputStream is) throws IOException {
|
||||
byte[] data = new byte[MAX_BUFFER_SIZE];
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int len;
|
||||
while ((len = is.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, len);
|
||||
}
|
||||
buffer.flush();
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to create a byte[] representing a Jar file with
|
||||
* duplicate file entries. This uses ZipArchiveOutputStream as ZipOutputStream
|
||||
* will fail with a "java.util.zip.ZipException: duplicate entry".
|
||||
*/
|
||||
// public static void createJarWithDuplicateFileEntries() throws IOException {
|
||||
// Files.deleteIfExists(DUPFILE_ENTRY_FILE);
|
||||
// try (ZipArchiveOutputStream zos =
|
||||
// new ZipArchiveOutputStream(DUPFILE_ENTRY_FILE.toFile())) {
|
||||
// zos.putArchiveEntry(new ZipArchiveEntry(FILE_ENTRY.name));
|
||||
// zos.write(FILE_ENTRY.bytes);
|
||||
// zos.putArchiveEntry(new ZipArchiveEntry(FILE_ENTRY.name));
|
||||
// zos.write("Yet another File".getBytes(StandardCharsets.UTF_8));
|
||||
// zos.closeArchiveEntry();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// byte[] jarBytes = Files.readAllBytes(DUPFILE_ENTRY_FILE);
|
||||
// String result = createByteArray(jarBytes, "DUPLICATE_ENTRY_JAR_BYTES");
|
||||
// System.out.println(result);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Utility method which takes a byte array and converts to byte array
|
||||
* declaration. For example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* var fooJar = Files.readAllBytes(Path.of("foo.jar"));
|
||||
* var result = createByteArray(fooJar, "FOOBYTES");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param bytes A byte array used to create a byte array declaration
|
||||
* @param name Name to be used in the byte array declaration
|
||||
* @return The formatted byte array declaration
|
||||
*/
|
||||
public static String createByteArray(byte[] bytes, String name) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 5);
|
||||
Formatter fmt = new Formatter(sb);
|
||||
fmt.format(" public static byte[] %s = {", name);
|
||||
final int linelen = 8;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
if (i % linelen == 0) {
|
||||
fmt.format("%n ");
|
||||
}
|
||||
fmt.format(" (byte) 0x%x,", bytes[i] & 0xff);
|
||||
}
|
||||
fmt.format("%n };%n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entry in a Zip file. An entry encapsulates a name, a
|
||||
* compression method, and its contents/data.
|
||||
*/
|
||||
public static class Entry {
|
||||
public final String name;
|
||||
public final int method;
|
||||
public final byte[] bytes;
|
||||
|
||||
public Entry(String name, int method, String contents) {
|
||||
this.name = name;
|
||||
this.method = method;
|
||||
this.bytes = contents.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static Entry of(String name, int method, String contents) {
|
||||
return new Entry(name, method, contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
294
test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java
Normal file
294
test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8231451
|
||||
* @summary Basic tests for ZipFileInputStream::skip
|
||||
* @modules jdk.zipfs
|
||||
* @run junit/othervm ZipFileInputStreamSkipTest
|
||||
*/
|
||||
public class ZipFileInputStreamSkipTest {
|
||||
|
||||
// Stored and Deflated Zip File paths used by the tests
|
||||
private static final Path STORED_ZIPFILE = Path.of("skipStoredEntries.zip");
|
||||
private static final Path DEFLATED_ZIPFILE = Path.of("skipDeflatedEntries.zip");
|
||||
|
||||
// Saved Entries added to the relevant Zip file
|
||||
private static final HashMap<String, Entry> STORED_ZIP_ENTRIES = new HashMap<>();
|
||||
private static final HashMap<String, Entry> DEFLATED_ZIP_ENTRIES = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create the Zip Files used by the tests
|
||||
*
|
||||
* @throws IOException If an error occurs creating the Zip Files
|
||||
*/
|
||||
@BeforeAll
|
||||
static void createZip() throws IOException {
|
||||
Entry e0 = Entry.of("Entry-0", ZipEntry.STORED, "Tennis Pro");
|
||||
Entry e1 = Entry.of("Entry-1", ZipEntry.STORED,
|
||||
"United States Tennis Association");
|
||||
Entry e2 = Entry.of("Entry-2", ZipEntry.DEFLATED, "Cardio Tennis");
|
||||
Entry e3 = Entry.of("Entry-3", ZipEntry.DEFLATED, "USTA League Championships");
|
||||
|
||||
// Add entries
|
||||
STORED_ZIP_ENTRIES.put(e0.name, e0);
|
||||
STORED_ZIP_ENTRIES.put(e1.name, e1);
|
||||
DEFLATED_ZIP_ENTRIES.put(e2.name, e2);
|
||||
DEFLATED_ZIP_ENTRIES.put(e3.name, e3);
|
||||
|
||||
Files.deleteIfExists(STORED_ZIPFILE);
|
||||
Files.deleteIfExists(DEFLATED_ZIPFILE);
|
||||
|
||||
createZipFile(STORED_ZIPFILE,
|
||||
Map.of("create", "true", "noCompression", "true"),
|
||||
e0, e1);
|
||||
|
||||
createZipFile(DEFLATED_ZIPFILE, Map.of("create", "true"), e2, e3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Zip Files created for the test
|
||||
*
|
||||
* @throws IOException If an error occurs during cleanup
|
||||
*/
|
||||
@AfterAll
|
||||
static void cleanUp() throws IOException {
|
||||
Files.deleteIfExists(STORED_ZIPFILE);
|
||||
Files.deleteIfExists(DEFLATED_ZIPFILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that you can skip forward within a STORED entry
|
||||
* and then read the expected data for the entry
|
||||
*
|
||||
* @throws Exception If an error occurs during the test
|
||||
*/
|
||||
@Test
|
||||
public void testStoredSkip() throws Exception {
|
||||
|
||||
try (ZipFile zf = new ZipFile(STORED_ZIPFILE.toFile())) {
|
||||
var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
var entrySize = entry.getSize();
|
||||
long midpoint = entrySize / 2;
|
||||
Entry expected = STORED_ZIP_ENTRIES.get(entry.getName());
|
||||
assertNotNull(expected);
|
||||
try (InputStream in = zf.getInputStream(entry)) {
|
||||
|
||||
// Check that if we specify 0, that we return the correct
|
||||
// skip value value
|
||||
assertEquals(0, in.skip(0));
|
||||
|
||||
// Try to skip past EOF and should return remaining bytes
|
||||
assertEquals(entrySize, in.skip(entrySize + 100));
|
||||
|
||||
// Return to BOF and then specify a value which would
|
||||
// overflow the projected skip value and return the
|
||||
// number of bytes moved to reach EOF
|
||||
assertEquals(-entrySize, in.skip(-entrySize));
|
||||
assertEquals(entrySize, in.skip(Long.MAX_VALUE));
|
||||
|
||||
// From midpoint, try to skip past EOF and then skip back
|
||||
// to BOF
|
||||
assertEquals(-entrySize, in.skip(-entrySize));
|
||||
assertEquals(midpoint, in.skip(midpoint));
|
||||
assertEquals(entrySize - midpoint, in.skip(1000));
|
||||
assertEquals(-entrySize, in.skip(-entrySize));
|
||||
|
||||
// Read remaining bytes and validate against expected bytes
|
||||
byte[] bytes = in.readAllBytes();
|
||||
assertArrayEquals(expected.bytes, bytes);
|
||||
assertEquals(expected.bytes.length, bytes.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that you can skip backwards within a STORED entry
|
||||
* and then read the expected data for the entry
|
||||
*
|
||||
* @throws Exception If an error occurs during the test
|
||||
*/
|
||||
@Test
|
||||
public void testStoredNegativeSkip() throws Exception {
|
||||
|
||||
try (ZipFile zf = new ZipFile(STORED_ZIPFILE.toFile())) {
|
||||
var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
var entrySize = entry.getSize();
|
||||
var midpoint = entrySize / 2;
|
||||
Entry expected = STORED_ZIP_ENTRIES.get(entry.getName());
|
||||
assertNotNull(expected);
|
||||
try (InputStream in = zf.getInputStream(entry)) {
|
||||
|
||||
// Check that if you try to move past BOF
|
||||
// that we return the correct value
|
||||
assertEquals(0, in.skip(-1));
|
||||
assertEquals(0, in.skip(-100));
|
||||
assertEquals(0, in.skip(Long.MIN_VALUE));
|
||||
|
||||
// Go to midpoint in file; then specify a value before
|
||||
// BOF which should result in the number of
|
||||
// bytes to BOF returned
|
||||
assertEquals(midpoint, in.skip(midpoint));
|
||||
assertEquals(-midpoint, in.skip(-(midpoint + 10)));
|
||||
|
||||
// From midpoint, move back a couple of bytes
|
||||
assertEquals(midpoint, in.skip(midpoint));
|
||||
assertEquals(-2, in.skip(-2));
|
||||
|
||||
// Read the remaining bytes and compare to the expected bytes
|
||||
byte[] bytes = in.readAllBytes();
|
||||
assertArrayEquals(Arrays.copyOfRange(expected.bytes,
|
||||
(int)midpoint - 2, (int) entrySize), bytes);
|
||||
assertEquals(entrySize - midpoint + 2, bytes.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that you can skip forward within a DEFLATED entry
|
||||
* and then read the expected data for the entry
|
||||
*
|
||||
* @throws Exception If an error occurs during the test
|
||||
*/
|
||||
@Test
|
||||
public void testDeflatedSkip() throws Exception {
|
||||
try (ZipFile zf = new ZipFile(DEFLATED_ZIPFILE.toFile())) {
|
||||
var toSkip = 5; // Bytes to Skip
|
||||
var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
Entry expected = DEFLATED_ZIP_ENTRIES.get(entry.getName());
|
||||
assertNotNull(expected);
|
||||
try (InputStream in = zf.getInputStream(entry)) {
|
||||
assertEquals(toSkip, in.skip(toSkip));
|
||||
byte[] bytes = in.readAllBytes();
|
||||
var ebytes = Arrays.copyOfRange(expected.bytes,
|
||||
toSkip, expected.bytes.length);
|
||||
assertArrayEquals(ebytes, bytes);
|
||||
assertEquals(expected.bytes.length - toSkip, bytes.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an IllegalArgumentException is thrown if you specify
|
||||
* a negative skip value for a DEFLATED entry.
|
||||
*
|
||||
* @throws Exception If an unexpected error occurs during the test
|
||||
*/
|
||||
@Test
|
||||
public void testDeflatedIOException() throws Exception {
|
||||
try (ZipFile zf = new ZipFile(DEFLATED_ZIPFILE.toFile())) {
|
||||
var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
assertNotNull(entry);
|
||||
try (InputStream in = zf.getInputStream(entry)) {
|
||||
// Cannot specify a negative value
|
||||
assertThrows(IllegalArgumentException.class, () -> in.skip((-1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Zip File System using the specified properties and a Zip file
|
||||
* with the specified number of entries
|
||||
*
|
||||
* @param zipFile Path to the Zip File to create
|
||||
* @param env Properties used for creating the Zip Filesystem
|
||||
* @param entries The entries to add to the Zip File
|
||||
* @throws IOException If an error occurs while creating the Zip file
|
||||
*/
|
||||
private static void createZipFile(Path zipFile, Map<String, String> env,
|
||||
Entry... entries) throws IOException {
|
||||
try (FileSystem zipfs =
|
||||
FileSystems.newFileSystem(zipFile, env)) {
|
||||
for (Entry e : entries) {
|
||||
Files.writeString(zipfs.getPath(e.name), new String(e.bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entry in a Zip file. An entry encapsulates a name, a
|
||||
* compression method, and its contents/data.
|
||||
*/
|
||||
static class Entry {
|
||||
private final String name;
|
||||
private final int method;
|
||||
private final byte[] bytes;
|
||||
|
||||
Entry(String name, int method, String contents) {
|
||||
this.name = name;
|
||||
this.method = method;
|
||||
this.bytes = contents.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
static Entry of(String name, int method, String contents) {
|
||||
return new Entry(name, method, contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new Entry with the same name and compression method as this
|
||||
* Entry but with the given content.
|
||||
*/
|
||||
Entry content(String contents) {
|
||||
return new Entry(name, method, contents);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
137
test/jdk/java/util/zip/ZipFile/ZipFileSharedSourceTest.java
Normal file
137
test/jdk/java/util/zip/ZipFile/ZipFileSharedSourceTest.java
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8347712
|
||||
* @summary verify that different instances of java.util.zip.ZipFile do not share
|
||||
* the same instance of (non-thread-safe) java.nio.charset.CharsetEncoder/CharsetDecoder
|
||||
* @run junit ZipFileSharedSourceTest
|
||||
*/
|
||||
public class ZipFileSharedSourceTest {
|
||||
|
||||
static Path createZipFile(final Charset charset) throws Exception {
|
||||
final Path zipFilePath = Files.createTempFile(Path.of("."), "8347712", ".zip");
|
||||
try (OutputStream os = Files.newOutputStream(zipFilePath);
|
||||
ZipOutputStream zos = new ZipOutputStream(os, charset)) {
|
||||
final int numEntries = 10240;
|
||||
for (int i = 1; i <= numEntries; i++) {
|
||||
final ZipEntry entry = new ZipEntry("entry-" + i);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write("foo bar".getBytes(US_ASCII));
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
return zipFilePath;
|
||||
}
|
||||
|
||||
static List<Arguments> charsets() {
|
||||
return List.of(
|
||||
Arguments.of(StandardCharsets.UTF_8),
|
||||
Arguments.of(StandardCharsets.ISO_8859_1),
|
||||
Arguments.of(US_ASCII)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* In this test, multiple concurrent threads each create an instance of java.util.zip.ZipFile
|
||||
* with the given {@code charset} for the same underlying ZIP file. Each of the threads
|
||||
* then iterate over the entries of their ZipFile instance. The test verifies that such access,
|
||||
* where each thread is accessing an independent ZipFile instance corresponding to the same
|
||||
* underlying ZIP file, doesn't lead to unexpected failures contributed by concurrent
|
||||
* threads.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("charsets")
|
||||
void testMultipleZipFileInstances(final Charset charset) throws Exception {
|
||||
final Path zipFilePath = createZipFile(charset);
|
||||
final int numTasks = 200;
|
||||
final CountDownLatch startLatch = new CountDownLatch(numTasks);
|
||||
final List<Future<Void>> results = new ArrayList<>();
|
||||
try (final ExecutorService executor =
|
||||
Executors.newThreadPerTaskExecutor(Thread.ofPlatform().factory())) {
|
||||
for (int i = 0; i < numTasks; i++) {
|
||||
final var task = new ZipEntryIteratingTask(zipFilePath, charset,
|
||||
startLatch);
|
||||
results.add(executor.submit(task));
|
||||
}
|
||||
System.out.println(numTasks + " tasks submitted, waiting for them to complete");
|
||||
for (final Future<Void> f : results) {
|
||||
f.get();
|
||||
}
|
||||
}
|
||||
System.out.println("All " + numTasks + " tasks completed successfully");
|
||||
}
|
||||
|
||||
private static final class ZipEntryIteratingTask implements Callable<Void> {
|
||||
private final Path file;
|
||||
private final Charset charset;
|
||||
private final CountDownLatch startLatch;
|
||||
|
||||
private ZipEntryIteratingTask(final Path file, final Charset charset,
|
||||
final CountDownLatch startLatch) {
|
||||
this.file = file;
|
||||
this.charset = charset;
|
||||
this.startLatch = startLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
// let other tasks know we are ready to run
|
||||
this.startLatch.countDown();
|
||||
// wait for other tasks to be ready to run
|
||||
this.startLatch.await();
|
||||
// create a new instance of ZipFile and iterate over the entries
|
||||
try (final ZipFile zf = new ZipFile(this.file.toFile(), this.charset)) {
|
||||
final var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final ZipEntry ze = entries.nextElement();
|
||||
// additionally exercise the ZipFile.getEntry() method
|
||||
zf.getEntry(ze.getName());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
164
test/jdk/java/util/zip/ZipFile/ZipSourceCache.java
Normal file
164
test/jdk/java/util/zip/ZipFile/ZipSourceCache.java
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*
|
||||
* 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 8317678
|
||||
* @modules java.base/java.util.zip:open
|
||||
* @summary Fix up hashCode() for ZipFile.Source.Key
|
||||
* @library /test/lib
|
||||
* @run junit/othervm ZipSourceCache
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import jdk.test.lib.util.FileUtils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ZipSourceCache {
|
||||
|
||||
private static final String ZIPFILE_NAME =
|
||||
System.currentTimeMillis() + "-bug8317678.zip";
|
||||
private static final String ZIPENTRY_NAME = "random.txt";
|
||||
private static final String INVALID_LOC_EXCEPTION =
|
||||
"ZipFile invalid LOC header (bad signature)";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static File relativeFile = new File(ZIPFILE_NAME);
|
||||
private static File absoluteFile = new File(ZIPFILE_NAME).getAbsoluteFile();
|
||||
private static boolean hasfileKeySupport;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws Exception {
|
||||
createZipFile("test1");
|
||||
var attrs = Files.readAttributes(relativeFile.toPath(), BasicFileAttributes.class);
|
||||
hasfileKeySupport = (attrs.fileKey() != null);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void cleanup() throws IOException {
|
||||
FileUtils.deleteFileIfExistsWithRetry(Path.of(ZIPFILE_NAME));
|
||||
}
|
||||
|
||||
/*
|
||||
* Monitor the internal "files" HashMap to ensure that we only
|
||||
* create one <Key, Source> mapping per unique zip file.
|
||||
*
|
||||
* This test also ensures that a new <Key, Source> mapping is created
|
||||
* if an update to an existing zip file is detected.
|
||||
*/
|
||||
@Test
|
||||
public void testKeySourceMapping() throws Exception {
|
||||
ZipFile absoluteZipFile;
|
||||
HashMap internalMap;
|
||||
int numSources;
|
||||
try (ZipFile zipFile = new ZipFile(relativeFile)) {
|
||||
Class source = Class.forName("java.util.zip.ZipFile$Source");
|
||||
Field filesMap = source.getDeclaredField("files");
|
||||
filesMap.setAccessible(true);
|
||||
internalMap = (HashMap) filesMap.get(zipFile);
|
||||
numSources = internalMap.size();
|
||||
// opening of same zip file shouldn't cause new Source
|
||||
// to be constructed on filesystems which support fileKey()
|
||||
absoluteZipFile = new ZipFile(absoluteFile);
|
||||
if (hasfileKeySupport) {
|
||||
assertEquals(numSources, internalMap.size());
|
||||
} else {
|
||||
assertEquals(++numSources, internalMap.size());
|
||||
}
|
||||
|
||||
// update the zip file, should expect a new Source Object
|
||||
// ignore this part of test if file can't be updated (can't overwrite)
|
||||
if (createZipFile("differentContent")) {
|
||||
ZipFile z = new ZipFile(relativeFile);
|
||||
// update of file should trigger new <Key, Source> mapping
|
||||
assertEquals(++numSources, internalMap.size());
|
||||
// new Source created, CEN structure should map fine
|
||||
readZipFileContents(z);
|
||||
// the old Source in use for old file, should no longer map correctly
|
||||
IOException ioe = assertThrows(IOException.class, () -> readZipFileContents(absoluteZipFile));
|
||||
assertEquals(INVALID_LOC_EXCEPTION, ioe.getMessage());
|
||||
z.close();
|
||||
assertEquals(--numSources, internalMap.size());
|
||||
}
|
||||
}
|
||||
// with fileKey() support, the close() call shouldn't remove the
|
||||
// Source entry just yet since we still have one reference to the file
|
||||
if (hasfileKeySupport) {
|
||||
assertEquals(numSources, internalMap.size());
|
||||
} else {
|
||||
assertEquals(--numSources, internalMap.size());
|
||||
}
|
||||
if (absoluteZipFile != null) {
|
||||
absoluteZipFile.close();
|
||||
}
|
||||
// now, the Source entry key should be removed
|
||||
assertEquals(--numSources, internalMap.size());
|
||||
}
|
||||
|
||||
private static void readZipFileContents(ZipFile zf) throws IOException {
|
||||
var e = zf.entries();
|
||||
while (e.hasMoreElements()) {
|
||||
InputStream is = zf.getInputStream(e.nextElement());
|
||||
String s = new String(is.readAllBytes());
|
||||
if (DEBUG) System.err.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean createZipFile(String content) {
|
||||
CRC32 crc32 = new CRC32();
|
||||
long t = System.currentTimeMillis();
|
||||
// let's have at least 2 entries created to ensure
|
||||
// that a bad zip structure is detected if file is updated
|
||||
int numEntries = new Random().nextInt(10) + 2;
|
||||
File zipFile = new File(ZIPFILE_NAME);
|
||||
try (FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos)) {
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
ZipEntry e = new ZipEntry(ZIPENTRY_NAME + i);
|
||||
e.setMethod(ZipEntry.STORED);
|
||||
byte[] toWrite = content.repeat(i+1).getBytes();
|
||||
e.setTime(t);
|
||||
e.setSize(toWrite.length);
|
||||
crc32.reset();
|
||||
crc32.update(toWrite);
|
||||
e.setCrc(crc32.getValue());
|
||||
zos.putNextEntry(e);
|
||||
zos.write(toWrite);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// some systems mightn't allow file to be updated while open
|
||||
System.err.println("error updating file. " + e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
40
test/jdk/java/util/zip/ZipInputStream/Constructor.java
Normal file
40
test/jdk/java/util/zip/ZipInputStream/Constructor.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 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.
|
||||
*
|
||||
* 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 4174691
|
||||
@summary Test if the constructor will check for null input.
|
||||
*/
|
||||
|
||||
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class Constructor {
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
ZipInputStream in = new ZipInputStream(null);
|
||||
throw new Exception("Constructor did not check the null argument");
|
||||
} catch (NullPointerException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
44
test/jdk/java/util/zip/ZipInputStream/Skip.java
Normal file
44
test/jdk/java/util/zip/ZipInputStream/Skip.java
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 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.
|
||||
*
|
||||
* 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 4029427
|
||||
@summary Make sure ZipInputStream.skip(n) will check
|
||||
for negative n.
|
||||
*/
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class Skip {
|
||||
public static void main(String[] args) throws Exception {
|
||||
ZipInputStream z = new ZipInputStream(System.in);
|
||||
|
||||
try {
|
||||
z.skip(-1);
|
||||
throw new Exception("Skip allowed negative value");
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
282
test/jdk/java/util/zip/ZipInputStream/Zip64DataDescriptor.java
Normal file
282
test/jdk/java/util/zip/ZipInputStream/Zip64DataDescriptor.java
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*
|
||||
* 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 8303866
|
||||
* @summary ZipInputStream should read 8-byte data descriptors if the LOC has
|
||||
* a ZIP64 extended information extra field
|
||||
* @run junit Zip64DataDescriptor
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HexFormat;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class Zip64DataDescriptor {
|
||||
|
||||
// A byte array holding a small-sized Zip64 ZIP file, described below
|
||||
private byte[] zip64File;
|
||||
|
||||
// A byte array holding a ZIP used for testing invalid Zip64 extra fields
|
||||
private byte[] invalidZip64;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws IOException {
|
||||
/*
|
||||
* Structure of the ZIP64 file used below . Note the presence
|
||||
* of a Zip64 extended information extra field and the
|
||||
* Data Descriptor having 8-byte values for csize and size.
|
||||
*
|
||||
* The file was produced using the zip command on MacOS
|
||||
* (zip 3.0, by Info-ZIP), in streamming mode (to enable Zip64),
|
||||
* using the -fd option (to force the use of data descriptors)
|
||||
*
|
||||
* The following command was used:
|
||||
* <pre>echo hello | zip -fd > hello.zip</pre>
|
||||
*
|
||||
* ------ Local File Header ------
|
||||
* 000000 signature 0x04034b50
|
||||
* 000004 version 45
|
||||
* 000006 flags 0x0008
|
||||
* 000008 method 8 Deflated
|
||||
* 000010 time 0xb180 22:12
|
||||
* 000012 date 0x565c 2023-02-28
|
||||
* 000014 crc 0x00000000
|
||||
* 000018 csize -1
|
||||
* 000022 size -1
|
||||
* 000026 nlen 1
|
||||
* 000028 elen 20
|
||||
* 000030 name 1 bytes '-'
|
||||
* 000031 ext id 0x0001 Zip64 extended information extra field
|
||||
* 000033 ext size 16
|
||||
* 000035 z64 size 0
|
||||
* 000043 z64 csize 0
|
||||
*
|
||||
* ------ File Data ------
|
||||
* 000051 data 8 bytes
|
||||
*
|
||||
* ------ Data Desciptor ------
|
||||
* 000059 signature 0x08074b50
|
||||
* 000063 crc 0x363a3020
|
||||
* 000067 csize 8
|
||||
* 000075 size 6
|
||||
* 000083 ...
|
||||
*/
|
||||
|
||||
String hex = """
|
||||
504b03042d000800080080b15c5600000000ffffffffffffffff01001400
|
||||
2d0100100000000000000000000000000000000000cb48cdc9c9e7020050
|
||||
4b070820303a3608000000000000000600000000000000504b01021e032d
|
||||
000800080080b15c5620303a360800000006000000010000000000000001
|
||||
000000b011000000002d504b050600000000010001002f00000053000000
|
||||
0000""";
|
||||
|
||||
zip64File = HexFormat.of().parseHex(hex.replaceAll("\n", ""));
|
||||
|
||||
// Create the ZIP file used for testing that invalid Zip64 extra fields are ignored
|
||||
// This ZIP has the regular 4-bit data descriptor
|
||||
|
||||
byte[] extra = new byte[Long.BYTES + Long.BYTES + Short.BYTES * 2]; // Size of a regular Zip64 extra field
|
||||
ByteBuffer buffer = ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putShort(0, (short) 123); // Not processed by ZipEntry.setExtra
|
||||
buffer.putShort(Short.BYTES, (short) (extra.length - 4));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zo = new ZipOutputStream(baos)) {
|
||||
ZipEntry ze = new ZipEntry("-");
|
||||
ze.setExtra(extra);
|
||||
zo.putNextEntry(ze);
|
||||
zo.write("hello\n".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
invalidZip64 = baos.toByteArray();
|
||||
|
||||
// Set Zip64 magic values on compressed and uncompressed size fields
|
||||
ByteBuffer.wrap(invalidZip64).order(ByteOrder.LITTLE_ENDIAN)
|
||||
.putInt(ZipFile.LOCSIZ, 0xFFFFFFFF)
|
||||
.putInt(ZipFile.LOCLEN, 0xFFFFFFFF);
|
||||
|
||||
// Set the Zip64 header ID 0x1 on the extra field in the invalid file
|
||||
setExtraHeaderId((short) 0x1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that small-sized Zip64 entries can be parsed by ZipInputStream
|
||||
*/
|
||||
@Test
|
||||
public void shouldReadZip64Descriptor() throws IOException {
|
||||
readZipInputStream(zip64File);
|
||||
}
|
||||
|
||||
/*
|
||||
* For maximal backward compatibility when reading Zip64 descriptors, invalid
|
||||
* Zip64 extra data sizes should be ignored
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnoreInvalidExtraSize() throws IOException {
|
||||
setExtraSize((short) 42);
|
||||
readZipInputStream(invalidZip64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Files with Zip64 magic values but no Zip64 field should be ignored
|
||||
* when considering 8 byte data descriptors
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnoreNoZip64Header() throws IOException {
|
||||
setExtraSize((short) 123);
|
||||
readZipInputStream(invalidZip64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Theoretically, ZIP files may exist with ZIP64 format, but with 4-byte
|
||||
* data descriptors. Such files will fail to parse, as demonstrated by this test.
|
||||
*/
|
||||
@Test
|
||||
public void shouldFailParsingZip64With4ByteDataDescriptor() throws IOException {
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
readZipInputStream(invalidZip64);
|
||||
});
|
||||
|
||||
String msg = String.format("Expected exeption message to contain 'invalid entry size', was %s",
|
||||
ex.getMessage());
|
||||
assertTrue(ex.getMessage().contains("invalid entry size"), msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that an extra data size exceeding the length of the extra field is ignored
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnoreExcessiveExtraSize() throws IOException {
|
||||
|
||||
setExtraSize(Short.MAX_VALUE);
|
||||
|
||||
|
||||
readZipInputStream(invalidZip64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the Data Descriptor is read with 32-bit fields if neither the
|
||||
* LOC's 'uncompressed size' or 'compressed size' fields have the Zip64 magic value,
|
||||
* even when there is a Zip64 field in the extra field.
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnoreNoMagicMarkers() throws IOException {
|
||||
// Set compressed and uncompressed size fields to zero
|
||||
ByteBuffer.wrap(invalidZip64).order(ByteOrder.LITTLE_ENDIAN)
|
||||
.putInt(ZipFile.LOCSIZ, 0)
|
||||
.putInt(ZipFile.LOCLEN, 0);
|
||||
|
||||
|
||||
readZipInputStream(invalidZip64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that an extra data size exceeding the length of the extra field is ignored
|
||||
*/
|
||||
@Test
|
||||
public void shouldIgnoreTrucatedZip64Extra() throws IOException {
|
||||
|
||||
truncateZip64();
|
||||
|
||||
readZipInputStream(invalidZip64);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the Extra field header ID of the invalid file
|
||||
*/
|
||||
private void setExtraHeaderId(short id) {
|
||||
// Set the header ID on the extra field
|
||||
ByteBuffer buffer = ByteBuffer.wrap(invalidZip64).order(ByteOrder.LITTLE_ENDIAN);
|
||||
int nlen = buffer.getShort(ZipFile.LOCNAM);
|
||||
buffer.putShort(ZipFile.LOCHDR + nlen, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the 16-bit 'data size' field of the Zip64 extended information field,
|
||||
* potentially to an invalid value.
|
||||
* @param size the value to set in the 'data size' field.
|
||||
*/
|
||||
private void setExtraSize(short size) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(invalidZip64).order(ByteOrder.LITTLE_ENDIAN);
|
||||
// Compute the offset to the Zip64 data block size field
|
||||
short nlen = buffer.getShort(ZipFile.LOCNAM);
|
||||
int dataSizeOffset = ZipFile.LOCHDR + nlen + Short.BYTES;
|
||||
buffer.putShort(dataSizeOffset, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a truncated Zip64 field (just the tag) at the end of the LOC extra field.
|
||||
* The beginning of the extra field is filled with a generic extra field containing
|
||||
* just zeros.
|
||||
*/
|
||||
private void truncateZip64() {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(invalidZip64).order(ByteOrder.LITTLE_ENDIAN);
|
||||
// Get the LOC name and extra sizes
|
||||
short nlen = buffer.getShort(ZipFile.LOCNAM);
|
||||
short elen = buffer.getShort(ZipFile.LOCEXT);
|
||||
int cenOffset = ZipFile.LOCHDR + nlen + elen;
|
||||
|
||||
// Zero out the extra field
|
||||
int estart = ZipFile.LOCHDR + nlen;
|
||||
buffer.put(estart, new byte[elen]);
|
||||
// Put a generic extra field in the start
|
||||
buffer.putShort(estart, (short) 42);
|
||||
buffer.putShort(estart + Short.BYTES, (short) (elen - 4 - 2));
|
||||
// Put a truncated (just the tag) Zip64 field at the end
|
||||
buffer.putShort(cenOffset - Short.BYTES, (short) 0x0001);
|
||||
}
|
||||
|
||||
/*
|
||||
* Consume and verify the ZIP file using ZipInputStream
|
||||
*/
|
||||
private void readZipInputStream(byte[] zip) throws IOException {
|
||||
try (ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(zip))) {
|
||||
// Read the ZIP entry, this calls readLOC
|
||||
ZipEntry e = in.getNextEntry();
|
||||
|
||||
// Sanity check the zip entry
|
||||
assertNotNull(e, "Missing zip entry");
|
||||
assertEquals("-", e.getName());
|
||||
|
||||
// Read the entry data, this causes readEND to parse the data descriptor
|
||||
assertEquals("hello\n", new String(in.readAllBytes(), StandardCharsets.UTF_8));
|
||||
|
||||
// There should only be a single zip entry
|
||||
assertNull(in.getNextEntry(), "Unexpected additional zip entry");
|
||||
}
|
||||
}
|
||||
}
|
||||
261
test/jdk/java/util/zip/ZipOutputStream/CloseWrappedStream.java
Normal file
261
test/jdk/java/util/zip/ZipOutputStream/CloseWrappedStream.java
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*
|
||||
* 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 8313739
|
||||
@summary Verify that ZipOutputStream closes the wrapped stream even after failed writes
|
||||
@run junit CloseWrappedStream
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CloseWrappedStream {
|
||||
|
||||
/**
|
||||
* Verify that closing a ZipOutputStream closes the wrapped output stream,
|
||||
* also when the wrapped stream throws while remaining data is flushed
|
||||
*/
|
||||
@Test
|
||||
public void exceptionDuringFinish() {
|
||||
// A wrapped stream which should be closed even after a write failure
|
||||
WrappedOutputStream wrappedStream = new WrappedOutputStream();
|
||||
|
||||
IOException exception = assertThrows(IOException.class, () -> {
|
||||
try (ZipOutputStream zo = new ZipOutputStream(wrappedStream)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
// Make finish() throw IOException
|
||||
wrappedStream.failOnWrite = true;
|
||||
} // Close throws when deflated data is flushed to wrapped stream
|
||||
});
|
||||
|
||||
// Check that we failed with the expected message
|
||||
assertEquals(WrappedOutputStream.WRITE_MSG, exception.getMessage());
|
||||
|
||||
// Verify that the wrapped stream was closed once
|
||||
assertEquals(1, wrappedStream.timesClosed,
|
||||
"Expected wrapped output stream to be closed once");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanity check that the wrapped stream is closed also for the
|
||||
* normal case where the wrapped stream does not throw
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void noExceptions() throws IOException {
|
||||
|
||||
WrappedOutputStream wrappedStream = new WrappedOutputStream();
|
||||
|
||||
try (ZipOutputStream zo = new ZipOutputStream(wrappedStream)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
// Verify that the wrapped stream was closed once
|
||||
assertEquals(1, wrappedStream.timesClosed,
|
||||
"Expected wrapped output stream to be closed once");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that an exception thrown while closing the wrapped
|
||||
* stream is propagated to the caller without any suppressed exceptions
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void exceptionDuringClose() throws IOException {
|
||||
|
||||
WrappedOutputStream wrappedStream = new WrappedOutputStream();
|
||||
|
||||
IOException exception = assertThrows(IOException.class, () -> {
|
||||
try (ZipOutputStream zo = new ZipOutputStream(wrappedStream)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
wrappedStream.failOnClose = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Check that we failed with the expected message
|
||||
assertEquals(WrappedOutputStream.CLOSE_MSG, exception.getMessage());
|
||||
|
||||
// There should be no suppressed exceptions
|
||||
assertEquals(0, exception.getSuppressed().length);
|
||||
|
||||
// Verify that the wrapped stream was closed once
|
||||
assertEquals(1, wrappedStream.timesClosed,
|
||||
"Expected wrapped output stream to be closed once");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that if an exception is thrown while closing the wrapped stream,
|
||||
* then later close attempts will not close the wrapped stream again
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void doubleCloseShouldCloseWrappedStreamOnce() throws IOException {
|
||||
|
||||
WrappedOutputStream wrappedStream = new WrappedOutputStream();
|
||||
|
||||
// Keep a reference so we can double-close
|
||||
AtomicReference<ZipOutputStream> ref = new AtomicReference<>();
|
||||
|
||||
IOException exception = assertThrows(IOException.class, () -> {
|
||||
try (ZipOutputStream zo = new ZipOutputStream(wrappedStream)) {
|
||||
ref.set(zo);
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
wrappedStream.failOnClose = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Double-closing the ZipOutputStream should have no effect
|
||||
ref.get().close();
|
||||
|
||||
// Check that we failed with the expected message
|
||||
assertEquals(WrappedOutputStream.CLOSE_MSG, exception.getMessage());
|
||||
|
||||
// There should be no suppressed exceptions
|
||||
assertEquals(0, exception.getSuppressed().length);
|
||||
|
||||
// Verify that the wrapped stream was closed once
|
||||
assertEquals(1, wrappedStream.timesClosed,
|
||||
"Expected wrapped output stream to be closed once");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that when the wrapped stream throws while calling finish
|
||||
* AND while being closed, then the propagated exception is the one
|
||||
* from the close operation, with the exception thrown during finish
|
||||
* added as a suppressed exception.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void exceptionDuringFinishAndClose() throws IOException {
|
||||
|
||||
WrappedOutputStream wrappedStream = new WrappedOutputStream();
|
||||
|
||||
IOException exception = assertThrows(IOException.class, () -> {
|
||||
try (ZipOutputStream zo = new ZipOutputStream(wrappedStream)) {
|
||||
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
// Will cause wrapped stream to throw during finish()
|
||||
wrappedStream.failOnWrite = true;
|
||||
// Will cause wrapped stream to throw during close()
|
||||
wrappedStream.failOnClose = true;
|
||||
}
|
||||
});
|
||||
|
||||
// We expect the top-level exception to be from the close operation
|
||||
assertEquals(WrappedOutputStream.CLOSE_MSG, exception.getMessage());
|
||||
|
||||
// The exception from the finish operation should be suppressed
|
||||
assertEquals(1, exception.getSuppressed().length, "Expected suppressed exception");
|
||||
assertEquals(WrappedOutputStream.WRITE_MSG, exception.getSuppressed()[0].getMessage());
|
||||
|
||||
// Verify that the wrapped stream was closed once
|
||||
assertEquals(1, wrappedStream.timesClosed,
|
||||
"Expected wrapped output stream to be closed once");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that when the wrapped stream throws the same IOException
|
||||
* (identical instance) for write and close operations, then no attempt
|
||||
* is made to add the exception instance to itself as a suppressed exception.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void sameExceptionDuringFinishAndClose() throws IOException {
|
||||
|
||||
WrappedOutputStream wrappedStream = new WrappedOutputStream();
|
||||
|
||||
IOException exception = assertThrows(IOException.class, () -> {
|
||||
try (ZipOutputStream zo = new ZipOutputStream(wrappedStream)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
// Make operations fail with the same exception instance
|
||||
wrappedStream.failException = new IOException("same fail");
|
||||
wrappedStream.failOnWrite = true;
|
||||
wrappedStream.failOnClose = true;
|
||||
}
|
||||
});
|
||||
// We expect the top-level exception to be from the close operation
|
||||
assertSame(wrappedStream.failException, exception);
|
||||
|
||||
// The exception should not suppress itself
|
||||
assertEquals(0, exception.getSuppressed().length, "Expected no suppressed exception");
|
||||
|
||||
// Verify that the wrapped stream was closed once
|
||||
assertEquals(1, wrappedStream.timesClosed,
|
||||
"Expected wrapped output stream to be closed once");
|
||||
}
|
||||
|
||||
/**
|
||||
* Output stream which conditionally throws IOException on writes
|
||||
* and tracks its close status.
|
||||
*/
|
||||
static class WrappedOutputStream extends FilterOutputStream {
|
||||
static final String WRITE_MSG = "fail during write";
|
||||
static final String CLOSE_MSG = "fail during close";
|
||||
boolean failOnWrite = false;
|
||||
boolean failOnClose = false;
|
||||
IOException failException = null;
|
||||
int timesClosed = 0;
|
||||
|
||||
public WrappedOutputStream() {
|
||||
super(new ByteArrayOutputStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(byte[] b, int off, int len) throws IOException{
|
||||
if (failOnWrite) {
|
||||
throw failException != null ? failException : new IOException(WRITE_MSG);
|
||||
} else {
|
||||
super.write(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
timesClosed++;
|
||||
if (failOnClose) {
|
||||
throw failException != null ? failException : new IOException(CLOSE_MSG);
|
||||
} else {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
114
test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java
Normal file
114
test/jdk/java/util/zip/ZipOutputStream/EmptyComment.java
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||
* Copyright (c) 2026, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8277087
|
||||
* @summary Verifies various use cases when the zip comment should be empty
|
||||
* @run junit EmptyComment
|
||||
*/
|
||||
public final class EmptyComment {
|
||||
|
||||
static IntStream longLengths() {
|
||||
return IntStream.of(0xFFFF + 1, 0xFFFF + 2, 0xFFFF * 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overflow, the text is too long to be stored as a comment.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("longLengths")
|
||||
void testOverflow(int length) throws Exception {
|
||||
test(zos -> assertThrows(IllegalArgumentException.class, () -> {
|
||||
zos.setComment("X".repeat(length));
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple cases where the comment is set to the empty text.
|
||||
*/
|
||||
@Test
|
||||
void testSimpleCases() throws Exception {
|
||||
test(zos -> {/* do nothing */});
|
||||
test(zos -> zos.setComment(null));
|
||||
test(zos -> zos.setComment(""));
|
||||
test(zos -> {
|
||||
zos.setComment("");
|
||||
zos.setComment(null);
|
||||
});
|
||||
test(zos -> {
|
||||
zos.setComment(null);
|
||||
zos.setComment("");
|
||||
});
|
||||
test(zos -> {
|
||||
zos.setComment("Comment");
|
||||
zos.setComment(null);
|
||||
});
|
||||
test(zos -> {
|
||||
zos.setComment("Comment");
|
||||
zos.setComment("");
|
||||
});
|
||||
}
|
||||
|
||||
private static void test(Consumer<ZipOutputStream> test) throws Exception {
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
|
||||
test.accept(zos);
|
||||
|
||||
zos.putNextEntry(new ZipEntry("x"));
|
||||
zos.finish();
|
||||
|
||||
byte[] data = baos.toByteArray();
|
||||
|
||||
if (data.length > 0xFFFF) { // just in case
|
||||
throw new RuntimeException("data is too big: " + data.length);
|
||||
}
|
||||
int pk = data.length - ZipFile.ENDHDR;
|
||||
if (data[pk] != 'P' || data[pk + 1] != 'K') {
|
||||
throw new RuntimeException("PK is not found");
|
||||
}
|
||||
// Since the comment is empty this will be two last bytes
|
||||
int pos = data.length - ZipFile.ENDHDR + ZipFile.ENDCOM;
|
||||
|
||||
int len = (data[pos] & 0xFF) + ((data[pos + 1] & 0xFF) << 8);
|
||||
if (len != 0) {
|
||||
throw new RuntimeException("zip comment is not empty: " + len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue