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:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View 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");
}
}

View 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;
}
}

View 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);
}
}
}
}

View file

@ -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;
}
}

View 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;
}
}

View 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) {}
}
}

View 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());
}
}

View 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");}
}

View 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())));
}
}

View 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);
}
}
}

View 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());
}
}

View 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();
}
});
}
}

View 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();
}
}
}

File diff suppressed because it is too large Load diff

View 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);
}
}

View file

@ -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();
}
}

View 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());
}
}

View 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());
}
}
}
}

View 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");}
}

View 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();
}
}
}

View 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");}
}

View 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);
}
}
}
}

View 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
}
}
}

View 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();
});
}
}

View 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");
}
}

View file

@ -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();
}
}

View 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());
}
}
}

View 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!");
}
}
}

View 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();
}
}
}

View 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();
});
}
}

View 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);
}
}
}
}

View 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");}
}

View 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);
}
}
}

View 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);
}
}

View 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);
}
}

View 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();
}
}
}

View 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;
}
}

View 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;
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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;
}
}