undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
331
test/jdk/java/util/zip/ZipFile/Assortment.java
Normal file
331
test/jdk/java/util/zip/ZipFile/Assortment.java
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 4770745 6234507 6303183 8048990
|
||||
* @summary test a variety of zip file entries
|
||||
* @author Martin Buchholz
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.util.jar.*;
|
||||
import java.io.*;
|
||||
|
||||
public class Assortment {
|
||||
static int passed = 0, failed = 0;
|
||||
|
||||
static void fail(String msg) {
|
||||
failed++;
|
||||
new Exception(msg).printStackTrace();
|
||||
}
|
||||
|
||||
static void unexpected(Throwable t) {
|
||||
failed++;
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
static void check(boolean condition, String msg) {
|
||||
if (! condition)
|
||||
fail(msg);
|
||||
}
|
||||
|
||||
static void check(boolean condition) {
|
||||
check(condition, "Something's wrong");
|
||||
}
|
||||
|
||||
static final int get16(byte b[], int off) {
|
||||
return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
|
||||
}
|
||||
|
||||
// check if all "expected" extra fields equal to their
|
||||
// corresponding fields in "extra". The "extra" might have
|
||||
// timestamp fields added by ZOS.
|
||||
static boolean equalsExtraData(byte[] expected, byte[] extra) {
|
||||
if (expected == null)
|
||||
return true;
|
||||
int off = 0;
|
||||
int len = expected.length;
|
||||
while (off + 4 < len) {
|
||||
int tag = get16(expected, off);
|
||||
int sz = get16(expected, off + 2);
|
||||
int off0 = 0;
|
||||
int len0 = extra.length;
|
||||
boolean matched = false;
|
||||
while (off0 + 4 < len0) {
|
||||
int tag0 = get16(extra, off0);
|
||||
int sz0 = get16(extra, off0 + 2);
|
||||
if (tag == tag0 && sz == sz0) {
|
||||
matched = true;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
if (expected[off + i] != extra[off0 +i])
|
||||
matched = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
off0 += (4 + sz0);
|
||||
}
|
||||
if (!matched)
|
||||
return false;
|
||||
off += (4 + sz);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class Entry {
|
||||
private String name;
|
||||
private int method;
|
||||
private byte[] data;
|
||||
private byte[] extra;
|
||||
private String comment;
|
||||
|
||||
Entry(String name,
|
||||
int method,
|
||||
byte[] data,
|
||||
byte[] extra,
|
||||
String comment) {
|
||||
this.name = name;
|
||||
this.method = method;
|
||||
this.data = data;
|
||||
this.extra = extra;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
void write(ZipOutputStream s) throws Exception {
|
||||
ZipEntry e = new ZipEntry(name);
|
||||
CRC32 crc32 = new CRC32();
|
||||
e.setMethod(method);
|
||||
if (method == ZipEntry.STORED) {
|
||||
e.setSize(data == null ? 0 : data.length);
|
||||
crc32.reset();
|
||||
if (data != null) crc32.update(data);
|
||||
e.setCrc(crc32.getValue());
|
||||
} else {
|
||||
e.setSize(0);
|
||||
e.setCrc(0);
|
||||
}
|
||||
if (comment != null) e.setComment(comment);
|
||||
if (extra != null) e.setExtra(extra);
|
||||
s.putNextEntry(e);
|
||||
if (data != null) s.write(data);
|
||||
}
|
||||
|
||||
byte[] getData(ZipFile f, ZipEntry e) throws Exception {
|
||||
byte[] fdata = new byte[(int)e.getSize()];
|
||||
InputStream is = f.getInputStream(e);
|
||||
is.read(fdata);
|
||||
return fdata;
|
||||
}
|
||||
|
||||
void verify(ZipFile f, ZipEntry e) throws Exception {
|
||||
verify(e, getData(f, e));
|
||||
}
|
||||
|
||||
void verify(ZipEntry e, byte[] eData) throws Exception {
|
||||
byte[] data = (this.data == null) ? new byte[]{} : this.data;
|
||||
byte[] extra = (this.extra != null && this.extra.length == 0) ?
|
||||
null : this.extra;
|
||||
check(name.equals(e.getName()));
|
||||
check(method == e.getMethod());
|
||||
check((((comment == null) || comment.equals(""))
|
||||
&& (e.getComment() == null))
|
||||
|| comment.equals(e.getComment()));
|
||||
check(equalsExtraData(extra, e.getExtra()));
|
||||
check(Arrays.equals(data, eData));
|
||||
check(e.getSize() == data.length);
|
||||
check((method == ZipEntry.DEFLATED) ||
|
||||
(e.getCompressedSize() == data.length));
|
||||
}
|
||||
|
||||
void verify(ZipFile f) throws Exception {
|
||||
ZipEntry e = f.getEntry(name);
|
||||
verify(e, getData(f, e));
|
||||
}
|
||||
|
||||
void verifyZipInputStream(ZipInputStream s) throws Exception {
|
||||
ZipEntry e = s.getNextEntry();
|
||||
|
||||
byte[] data = (this.data == null) ? new byte[]{} : this.data;
|
||||
byte[] otherData = new byte[data.length];
|
||||
s.read(otherData);
|
||||
check(Arrays.equals(data, otherData));
|
||||
|
||||
byte[] extra = (this.extra != null && this.extra.length == 0) ?
|
||||
null : this.extra;
|
||||
check(equalsExtraData(extra, e.getExtra()));
|
||||
check(name.equals(e.getName()));
|
||||
check(method == e.getMethod());
|
||||
check(e.getSize() == -1 || e.getSize() == data.length);
|
||||
check((method == ZipEntry.DEFLATED) ||
|
||||
(e.getCompressedSize() == data.length));
|
||||
}
|
||||
|
||||
void verifyJarInputStream(JarInputStream s) throws Exception {
|
||||
// JarInputStream "automatically" reads the manifest
|
||||
if (name.equals("meta-iNf/ManIfEst.Mf"))
|
||||
return;
|
||||
|
||||
verifyZipInputStream(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static int uniquifier = 86;
|
||||
private static String uniquify(String name) {
|
||||
return name + (uniquifier++);
|
||||
}
|
||||
|
||||
private static byte[] toBytes(String s) throws Exception {
|
||||
return s.getBytes("UTF-8");
|
||||
}
|
||||
|
||||
private static byte[] toExtra(byte[] bytes) throws Exception {
|
||||
if (bytes == null) return null;
|
||||
// Construct a fake extra field with valid header length
|
||||
byte[] v = new byte[bytes.length + 4];
|
||||
v[0] = (byte) 0x47;
|
||||
v[1] = (byte) 0xff;
|
||||
v[2] = (byte) bytes.length;
|
||||
v[3] = (byte) (bytes.length << 8);
|
||||
System.arraycopy(bytes, 0, v, 4, bytes.length);
|
||||
return v;
|
||||
}
|
||||
|
||||
private static Random random = new Random();
|
||||
|
||||
private static String makeName(int length) {
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
sb.append((char)(random.nextInt(10000)+1));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
File zipName = new File("x.zip");
|
||||
int[] methods = {ZipEntry.STORED, ZipEntry.DEFLATED};
|
||||
String[] names = {makeName(1), makeName(160), makeName(9000)};
|
||||
byte[][] datas = {null, new byte[]{}, new byte[]{'d'}};
|
||||
byte[][] extras = {null, new byte[]{}, new byte[]{'e'}};
|
||||
String[] comments = {null, "", "c"};
|
||||
|
||||
List<Entry> entries = new ArrayList<Entry>();
|
||||
|
||||
// Highly unusual manifest
|
||||
entries.add(new Entry("meta-iNf/ManIfEst.Mf",
|
||||
ZipEntry.STORED,
|
||||
toBytes("maNiFest-VeRsIon: 1.0\n"),
|
||||
toExtra(toBytes("Can manifests have extra??")),
|
||||
"Can manifests have comments??"));
|
||||
|
||||
// The emptiest possible entry
|
||||
entries.add(new Entry("", ZipEntry.STORED, null, null, ""));
|
||||
|
||||
for (String name : names)
|
||||
for (int method : methods)
|
||||
for (byte[] data : datas) // datae??
|
||||
for (byte[] extra : extras)
|
||||
for (String comment : comments)
|
||||
entries.add(new Entry(uniquify(name), method, data,
|
||||
toExtra(extra), comment));
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Write zip file using ZipOutputStream
|
||||
//----------------------------------------------------------------
|
||||
try (FileOutputStream fos = new FileOutputStream(zipName);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos))
|
||||
{
|
||||
for (Entry e : entries)
|
||||
e.write(zos);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using ZipFile.getEntry()
|
||||
//----------------------------------------------------------------
|
||||
try (ZipFile f = new ZipFile(zipName)) {
|
||||
for (Entry e : entries)
|
||||
e.verify(f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using JarFile.getEntry()
|
||||
//----------------------------------------------------------------
|
||||
try (JarFile f = new JarFile(zipName)) {
|
||||
check(f.getManifest() != null);
|
||||
for (Entry e : entries)
|
||||
e.verify(f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using ZipFile.entries()
|
||||
//----------------------------------------------------------------
|
||||
try (ZipFile f = new ZipFile(zipName)) {
|
||||
Enumeration<? extends ZipEntry> en = f.entries();
|
||||
for (Entry e : entries)
|
||||
e.verify(f, en.nextElement());
|
||||
|
||||
check(!en.hasMoreElements());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using JarFile.entries()
|
||||
//----------------------------------------------------------------
|
||||
try (JarFile f = new JarFile(zipName)) {
|
||||
Enumeration<? extends ZipEntry> en = f.entries();
|
||||
for (Entry e : entries)
|
||||
e.verify(f, en.nextElement());
|
||||
|
||||
check(!en.hasMoreElements());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using ZipInputStream class
|
||||
//----------------------------------------------------------------
|
||||
try (FileInputStream fis = new FileInputStream(zipName);
|
||||
ZipInputStream s = new ZipInputStream(fis)) {
|
||||
|
||||
for (Entry e : entries)
|
||||
e.verifyZipInputStream(s);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// Verify zip file contents using JarInputStream class
|
||||
//----------------------------------------------------------------
|
||||
try (FileInputStream fis = new FileInputStream(zipName);
|
||||
JarInputStream s = new JarInputStream(fis)) {
|
||||
|
||||
// JarInputStream "automatically" reads the manifest
|
||||
check(s.getManifest() != null);
|
||||
|
||||
for (Entry e : entries)
|
||||
e.verifyJarInputStream(s);
|
||||
}
|
||||
|
||||
// String cmd = "unzip -t " + zipName.getPath() + " >/dev/tty";
|
||||
// new ProcessBuilder(new String[]{"/bin/sh", "-c", cmd}).start().waitFor();
|
||||
|
||||
zipName.deleteOnExit();
|
||||
|
||||
System.out.printf("passed = %d, failed = %d%n", passed, failed);
|
||||
if (failed > 0) throw new Exception("Some tests failed");
|
||||
}
|
||||
}
|
||||
246
test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java
Normal file
246
test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8341595
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @summary Verify that ZipFile can read from a ZIP file with a maximally large CEN size
|
||||
* @run junit/othervm/manual -Xmx2500M CenSizeMaximum
|
||||
*/
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CenSizeMaximum {
|
||||
|
||||
// Maximum allowed CEN size allowed by the ZipFile implementation
|
||||
static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH;
|
||||
|
||||
/**
|
||||
* From the APPNOTE.txt specification:
|
||||
* 4.4.10 file name length: (2 bytes)
|
||||
* 4.4.11 extra field length: (2 bytes)
|
||||
* 4.4.12 file comment length: (2 bytes)
|
||||
*
|
||||
* The length of the file name, extra field, and comment
|
||||
* fields respectively. The combined length of any
|
||||
* directory record and these three fields SHOULD NOT
|
||||
* generally exceed 65,535 bytes.
|
||||
*.
|
||||
* Create a maximum extra field which does not exceed 65,535 bytes
|
||||
*/
|
||||
static final int MAX_EXTRA_FIELD_SIZE = 65_535 - ZipFile.CENHDR;
|
||||
|
||||
// Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings'
|
||||
static final short UNKNOWN_ZIP_TAG = (short) 0x9902;
|
||||
|
||||
// The size of one CEN header, including the name and the extra field
|
||||
static final int CEN_HEADER_SIZE = ZipFile.CENHDR + MAX_EXTRA_FIELD_SIZE;
|
||||
|
||||
// The size of the extra data field header (tag id + data block length)
|
||||
static final int EXTRA_FIELD_HEADER_SIZE = 2 * Short.BYTES;
|
||||
|
||||
// Zip file to create for testing
|
||||
private Path hugeZipFile = Path.of("cen-size-on-limit.zip");
|
||||
|
||||
/**
|
||||
* Clean up ZIP file created in this test
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
//Files.deleteIfExists(hugeZipFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that ZipFile opens a ZIP file with a CEN size close
|
||||
* to the {@link #MAX_CEN_SIZE} implementation limit.
|
||||
*
|
||||
* @throws IOException if an unexpected IO error occurs
|
||||
*/
|
||||
@Test
|
||||
public void maximumCenSize() throws IOException {
|
||||
int numCenHeaders = zipWithWithExactCenSize(MAX_CEN_SIZE, true, false);
|
||||
try (var zf = new ZipFile(hugeZipFile.toFile())) {
|
||||
assertEquals(numCenHeaders, zf.size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that ZipFile rejects a ZIP where the last CEN record
|
||||
* overflows the CEN size and the END header CENTOT field is smaller
|
||||
* than the actual number of headers
|
||||
*
|
||||
* @throws IOException if an unexpected IO error occurs
|
||||
*/
|
||||
@Test
|
||||
public void lastCENHeaderBadSize() throws IOException {
|
||||
int numCenHeaders = zipWithWithExactCenSize(1024, true, true);
|
||||
ZipException zipException = assertThrows(ZipException.class, () -> {
|
||||
try (var zf = new ZipFile(hugeZipFile.toFile())) {
|
||||
assertEquals(numCenHeaders, zf.size());
|
||||
}
|
||||
});
|
||||
assertEquals("invalid CEN header (bad header size)", zipException.getMessage());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a ZIP file with an exact CEN size. To minimize the number of CEN headers
|
||||
* written, maximally large, empty extra data blocks are written sparsely.
|
||||
*
|
||||
* @param cenSize the exact CEN size of the ZIP file to produce
|
||||
* @param invalidateEndTotal whether to decrement the END header's TOT field by one
|
||||
* @return the number of CEN headers produced
|
||||
* @throws IOException if an unexpected IO error occurs
|
||||
*/
|
||||
private int zipWithWithExactCenSize(long cenSize, boolean invalidateEndTotal, boolean overflowLastCEN)
|
||||
throws IOException {
|
||||
// Sanity check
|
||||
assertTrue(cenSize <= MAX_CEN_SIZE);
|
||||
|
||||
// The number of CEN headers we need to write
|
||||
int numCenHeaders = (int) (cenSize / CEN_HEADER_SIZE) + 1;
|
||||
// Size if all extra data fields were of maximum size
|
||||
long overSized = numCenHeaders * (long) CEN_HEADER_SIZE;
|
||||
// Length to trim from the first CEN's extra data
|
||||
int negativPadding = (int) (overSized - cenSize);
|
||||
int firstExtraSize = MAX_EXTRA_FIELD_SIZE - negativPadding;
|
||||
|
||||
// Sanity check
|
||||
long computedCenSize = (numCenHeaders -1L ) * CEN_HEADER_SIZE + ZipEntry.CENHDR + firstExtraSize;
|
||||
assertEquals(computedCenSize, cenSize);
|
||||
|
||||
// A CEN header, followed by the four-bytes extra data header
|
||||
ByteBuffer cenHeader = createCENHeader();
|
||||
// An END header
|
||||
ByteBuffer endHeader = createENDHeader();
|
||||
// Update the END header
|
||||
if (invalidateEndTotal) {
|
||||
// To trigger countCENHeaders
|
||||
endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders -1 & 0xFFFF));
|
||||
} else {
|
||||
endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders & 0xFFFF));
|
||||
}
|
||||
// Update CEN size and offset fields
|
||||
endHeader.putInt(ZipEntry.ENDSIZ, (int) (cenSize & 0xFFFFFFFFL));
|
||||
endHeader.putInt(ZipEntry.ENDOFF, 0);
|
||||
|
||||
// When creating a sparse file, the file must not already exit
|
||||
Files.deleteIfExists(hugeZipFile);
|
||||
|
||||
// Open a FileChannel for writing a sparse file
|
||||
EnumSet<StandardOpenOption> options = EnumSet.of(StandardOpenOption.CREATE_NEW,
|
||||
StandardOpenOption.WRITE,
|
||||
StandardOpenOption.SPARSE);
|
||||
|
||||
try (FileChannel channel = FileChannel.open(hugeZipFile, options)) {
|
||||
// Write CEN headers
|
||||
for (int i = 0; i < numCenHeaders; i++) {
|
||||
// The first CEN header has trimmed extra data
|
||||
int extraSize = i == 0 ? firstExtraSize : MAX_EXTRA_FIELD_SIZE;
|
||||
if (overflowLastCEN && i == numCenHeaders - 1) {
|
||||
// make last CEN header overflow the CEN size
|
||||
cenHeader.putShort(ZipEntry.CENNAM, Short.MAX_VALUE);
|
||||
}
|
||||
// update elen field
|
||||
cenHeader.putShort(ZipEntry.CENEXT, (short) (extraSize & 0xFFFF));
|
||||
// update data block len of the extra field header
|
||||
short dlen = (short) ((extraSize - EXTRA_FIELD_HEADER_SIZE) & 0xFFFF);
|
||||
cenHeader.putShort(ZipEntry.CENHDR + Short.BYTES, dlen);
|
||||
// Write the CEN header plus the four-byte extra header
|
||||
channel.write(cenHeader.rewind());
|
||||
// Sparse "write" of the extra data block
|
||||
channel.position(channel.position() + extraSize - EXTRA_FIELD_HEADER_SIZE);
|
||||
}
|
||||
// Sanity check
|
||||
assertEquals(cenSize, channel.position());
|
||||
// Write the END header
|
||||
channel.write(endHeader.rewind());
|
||||
}
|
||||
return numCenHeaders;
|
||||
}
|
||||
|
||||
// Creates a ByteBuffer representing a CEN header with a trailing extra field header
|
||||
private ByteBuffer createCENHeader() throws IOException {
|
||||
byte[] bytes = smallZipfile();
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
int endOff = bytes.length - ZipEntry.ENDHDR;
|
||||
int cenSize = buf.getInt(endOff + ZipEntry.ENDSIZ);
|
||||
int cenOff = buf.getInt(endOff + ZipEntry.ENDOFF);
|
||||
return ByteBuffer.wrap(
|
||||
Arrays.copyOfRange(bytes, cenOff, cenOff + ZipEntry.CENHDR + EXTRA_FIELD_HEADER_SIZE)
|
||||
).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
// Creates a ByteBuffer representing an END header
|
||||
private ByteBuffer createENDHeader() throws IOException {
|
||||
byte[] bytes = smallZipfile();
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
int endOff = bytes.length - ZipEntry.ENDHDR;
|
||||
return ByteBuffer.wrap(
|
||||
Arrays.copyOfRange(bytes, endOff, endOff + ZipEntry.ENDHDR)
|
||||
).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
// Create a byte array with a minimal ZIP file
|
||||
private static byte[] smallZipfile() throws IOException {
|
||||
var out = new ByteArrayOutputStream();
|
||||
try (var zo = new ZipOutputStream(out)) {
|
||||
ZipEntry entry = new ZipEntry("");
|
||||
entry.setExtra(makeDummyExtraField());
|
||||
zo.putNextEntry(entry);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
// Create a minimally sized extra field
|
||||
private static byte[] makeDummyExtraField() {
|
||||
byte[] extra = new byte[EXTRA_FIELD_HEADER_SIZE];
|
||||
// Little-endian ByteBuffer for updating the header fields
|
||||
ByteBuffer buffer = ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings'
|
||||
buffer.putShort(UNKNOWN_ZIP_TAG);
|
||||
|
||||
// Size of the actual (empty) data
|
||||
buffer.putShort((short) 0);
|
||||
return extra;
|
||||
}
|
||||
}
|
||||
221
test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java
Normal file
221
test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8272746
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @summary Verify that ZipFile rejects a ZIP with a CEN size which does not fit in a Java byte array
|
||||
* @run junit CenSizeTooLarge
|
||||
*/
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class CenSizeTooLarge {
|
||||
|
||||
// Entry names produced in this test are fixed-length
|
||||
public static final int NAME_LENGTH = 10;
|
||||
|
||||
// Maximum allowed CEN size allowed by the ZipFile implementation
|
||||
static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH;
|
||||
|
||||
/**
|
||||
* From the APPNOTE.txt specification:
|
||||
* 4.4.10 file name length: (2 bytes)
|
||||
* 4.4.11 extra field length: (2 bytes)
|
||||
* 4.4.12 file comment length: (2 bytes)
|
||||
*
|
||||
* The length of the file name, extra field, and comment
|
||||
* fields respectively. The combined length of any
|
||||
* directory record and these three fields SHOULD NOT
|
||||
* generally exceed 65,535 bytes.
|
||||
*.
|
||||
* Create a maximum extra field which does not exceed 65,535 bytes
|
||||
*/
|
||||
static final int MAX_EXTRA_FIELD_SIZE = 65_535 - ZipFile.CENHDR - NAME_LENGTH;
|
||||
|
||||
// Data size (unsigned short)
|
||||
// Field size minus the leading header 'tag' and 'data size' fields (2 bytes each)
|
||||
static final short MAX_DATA_SIZE = (short) (MAX_EXTRA_FIELD_SIZE - 2 * Short.BYTES);
|
||||
|
||||
// Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings'
|
||||
static final short UNKNOWN_ZIP_TAG = (short) 0x9902;
|
||||
|
||||
// Use a shared LocalDateTime on all entries to save processing time
|
||||
static final LocalDateTime TIME_LOCAL = LocalDateTime.now();
|
||||
|
||||
// The size of one CEN header, including the name and the extra field
|
||||
static final int CEN_HEADER_SIZE = ZipFile.CENHDR + NAME_LENGTH + MAX_EXTRA_FIELD_SIZE;
|
||||
|
||||
// The number of entries needed to exceed the MAX_CEN_SIZE
|
||||
static final int NUM_ENTRIES = (MAX_CEN_SIZE / CEN_HEADER_SIZE) + 1;
|
||||
|
||||
// Expected ZipException message when the CEN does not fit in a Java byte array
|
||||
private static final String CEN_TOO_LARGE_MESSAGE = "invalid END header (central directory size too large)";
|
||||
|
||||
// Zip file to create for testing
|
||||
private File hugeZipFile;
|
||||
|
||||
private static final byte[] EXTRA_BYTES = makeLargeExtraField();
|
||||
// Helps SparseOutputStream detect write of the last CEN entry
|
||||
private static final byte[] LAST_EXTRA_BYTES = makeLargeExtraField();
|
||||
|
||||
/**
|
||||
* Create a zip file with a CEN size which does not fit within a Java byte array
|
||||
*/
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
hugeZipFile = new File("cen-too-large.zip");
|
||||
hugeZipFile.deleteOnExit();
|
||||
|
||||
try (OutputStream out = new SparseOutputStream(new FileOutputStream(hugeZipFile));
|
||||
ZipOutputStream zip = new ZipOutputStream(out)) {
|
||||
|
||||
// Keep track of entries so we can update extra data before the CEN is written
|
||||
ZipEntry[] entries = new ZipEntry[NUM_ENTRIES];
|
||||
|
||||
// Add entries until MAX_CEN_SIZE is reached
|
||||
for (int i = 0; i < NUM_ENTRIES; i++) {
|
||||
// Create a fixed-length name for the entry
|
||||
String name = Integer.toString(i);
|
||||
name = "0".repeat(NAME_LENGTH - name.length()) + name;
|
||||
|
||||
// Create and track the entry
|
||||
ZipEntry entry = entries[i] = new ZipEntry(name);
|
||||
|
||||
// Use STORED for faster processing
|
||||
entry.setMethod(ZipEntry.STORED);
|
||||
entry.setSize(0);
|
||||
entry.setCrc(0);
|
||||
|
||||
// Set the time/date field for faster processing
|
||||
entry.setTimeLocal(TIME_LOCAL);
|
||||
|
||||
// Add the entry
|
||||
zip.putNextEntry(entry);
|
||||
}
|
||||
// Finish writing the last entry
|
||||
zip.closeEntry();
|
||||
|
||||
// Before the CEN headers are written, set the extra data on each entry
|
||||
for (ZipEntry entry : entries) {
|
||||
entry.setExtra(EXTRA_BYTES);
|
||||
}
|
||||
// Help SparseOutputSream detect the last entry
|
||||
entries[entries.length-1].setExtra(LAST_EXTRA_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a ZipException is thrown with the expected message when
|
||||
* the ZipFile is initialized with a ZIP whose CEN exeeds {@link #MAX_CEN_SIZE}
|
||||
*/
|
||||
@Test
|
||||
public void centralDirectoryTooLargeToFitInByteArray() {
|
||||
ZipException ex = assertThrows(ZipException.class, () -> new ZipFile(hugeZipFile));
|
||||
assertEquals(CEN_TOO_LARGE_MESSAGE, ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* We can reduce the number of written CEN headers by making each CEN header maximally large.
|
||||
* We do this by adding the extra field produced by this method to each CEN header.
|
||||
* <p>
|
||||
* The structure of an extra field is as follows:
|
||||
* <p>
|
||||
* Header ID (Two bytes, describes the type of the field, also called 'tag')
|
||||
* Data Size (Two byte short)
|
||||
* Data Block (Contents depend on field type)
|
||||
*/
|
||||
private static byte[] makeLargeExtraField() {
|
||||
// Make a maximally sized extra field
|
||||
byte[] extra = new byte[MAX_EXTRA_FIELD_SIZE];
|
||||
// Little-endian ByteBuffer for updating the header fields
|
||||
ByteBuffer buffer = ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings'
|
||||
buffer.putShort(UNKNOWN_ZIP_TAG);
|
||||
|
||||
// Size of the actual (empty) data
|
||||
buffer.putShort(MAX_DATA_SIZE);
|
||||
return extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* By writing sparse 'holes' until the last CEN is detected, we can save disk space
|
||||
* used by this test from ~2GB to ~4K. Instances of this class should be passed
|
||||
* directly to the ZipOutputStream constructor, without any buffering. Otherwise,
|
||||
* writes from ZipOutputStream may not be detected correctly.
|
||||
*/
|
||||
private static class SparseOutputStream extends FilterOutputStream {
|
||||
private final FileChannel channel;
|
||||
private boolean sparse = true; // True until the last CEN is written
|
||||
private long position = 0;
|
||||
|
||||
public SparseOutputStream(FileOutputStream fos) {
|
||||
super(fos);
|
||||
this.channel = fos.getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
position += len;
|
||||
if (sparse) {
|
||||
// Until finding the last CEN, we don't actually write anything,
|
||||
// but instead simply advance the position, creating a sparse file
|
||||
channel.position(position);
|
||||
// Check for last CEN record
|
||||
if (b == LAST_EXTRA_BYTES) {
|
||||
// From here on, write actual bytes
|
||||
sparse = false;
|
||||
}
|
||||
} else {
|
||||
// Regular write
|
||||
out.write(b, off, len);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
position++;
|
||||
if (sparse) {
|
||||
channel.position(position);
|
||||
} else {
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 2011 IBM Corporation
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7031076
|
||||
* @summary Allow stale InputStreams from ZipFiles to be GC'd
|
||||
* @author Neil Richards <neil.richards@ngmr.net>, <neil_richards@uk.ibm.com>
|
||||
* @key randomness
|
||||
*/
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class ClearStaleZipFileInputStreams {
|
||||
private static final int ZIP_ENTRY_NUM = 5;
|
||||
|
||||
private static final byte[][] data;
|
||||
|
||||
static {
|
||||
data = new byte[ZIP_ENTRY_NUM][];
|
||||
Random r = new Random();
|
||||
for (int i = 0; i < ZIP_ENTRY_NUM; i++) {
|
||||
data[i] = new byte[1000];
|
||||
r.nextBytes(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static File createTestFile(int compression) throws Exception {
|
||||
File tempZipFile =
|
||||
File.createTempFile("test-data" + compression, ".zip");
|
||||
tempZipFile.deleteOnExit();
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(tempZipFile);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos)) {
|
||||
zos.setLevel(compression);
|
||||
for (int i = 0; i < ZIP_ENTRY_NUM; i++) {
|
||||
String text = "Entry" + i;
|
||||
ZipEntry entry = new ZipEntry(text);
|
||||
zos.putNextEntry(entry);
|
||||
try {
|
||||
zos.write(data[i], 0, data[i].length);
|
||||
} finally {
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tempZipFile;
|
||||
}
|
||||
|
||||
private static final class GcInducingThread extends Thread {
|
||||
private final int sleepMillis;
|
||||
private boolean keepRunning = true;
|
||||
|
||||
public GcInducingThread(final int sleepMillis) {
|
||||
this.sleepMillis = sleepMillis;
|
||||
}
|
||||
|
||||
public synchronized void run() {
|
||||
while (keepRunning) {
|
||||
System.gc();
|
||||
try {
|
||||
wait(sleepMillis);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("GCing thread unexpectedly interrupted");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void shutDown() {
|
||||
keepRunning = false;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
GcInducingThread gcThread = new GcInducingThread(500);
|
||||
gcThread.start();
|
||||
try {
|
||||
runTest(ZipOutputStream.DEFLATED);
|
||||
runTest(ZipOutputStream.STORED);
|
||||
} finally {
|
||||
gcThread.shutDown();
|
||||
gcThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTest(int compression) throws Exception {
|
||||
ReferenceQueue<InputStream> rq = new ReferenceQueue<>();
|
||||
|
||||
System.out.println("Testing with a zip file with compression level = "
|
||||
+ compression);
|
||||
File f = createTestFile(compression);
|
||||
try (ZipFile zf = new ZipFile(f)) {
|
||||
Set<Object> refSet = createTransientInputStreams(zf, rq);
|
||||
|
||||
System.out.println("Waiting for 'stale' input streams from ZipFile to be GC'd ...");
|
||||
System.out.println("(The test will hang on failure)");
|
||||
while (false == refSet.isEmpty()) {
|
||||
refSet.remove(rq.remove());
|
||||
}
|
||||
System.out.println("Test PASSED.");
|
||||
System.out.println();
|
||||
} finally {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<Object> createTransientInputStreams(ZipFile zf,
|
||||
ReferenceQueue<InputStream> rq) throws Exception {
|
||||
Enumeration<? extends ZipEntry> zfe = zf.entries();
|
||||
Set<Object> refSet = new HashSet<>();
|
||||
|
||||
while (zfe.hasMoreElements()) {
|
||||
InputStream is = zf.getInputStream(zfe.nextElement());
|
||||
refSet.add(new WeakReference<InputStream>(is, rq));
|
||||
}
|
||||
|
||||
return refSet;
|
||||
}
|
||||
}
|
||||
113
test/jdk/java/util/zip/ZipFile/Comment.java
Normal file
113
test/jdk/java/util/zip/ZipFile/Comment.java
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
@bug 4334846
|
||||
@summary Make sure zip file comments of various sizes can be written.
|
||||
@author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class Comment {
|
||||
private static final String entryName = "entryName";
|
||||
private static final String entryContents = "entryContents";
|
||||
private static final int commentMaxLength = 0xFFFF;
|
||||
private static final int [] commentLengths
|
||||
= { 0, 1, 32768, commentMaxLength - 1, commentMaxLength };
|
||||
|
||||
public static void main(String argv[])
|
||||
throws Exception
|
||||
{
|
||||
for (int i = 0; i < commentLengths.length; ++i) {
|
||||
int commentLength = commentLengths[i];
|
||||
String comment = buildComment(commentLength);
|
||||
String name = "Test" + commentLength + ".zip";
|
||||
writeZipFile(name, comment);
|
||||
verifyZipFile(name, comment);
|
||||
new File(name).delete();
|
||||
System.out.println(commentLength + ": successful");
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeZipFile(String name, String comment)
|
||||
throws IOException
|
||||
{
|
||||
try (FileOutputStream fos = new FileOutputStream(name);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos))
|
||||
{
|
||||
zos.setComment(comment);
|
||||
ZipEntry ze = new ZipEntry(entryName);
|
||||
ze.setMethod(ZipEntry.DEFLATED);
|
||||
zos.putNextEntry(ze);
|
||||
new DataOutputStream(zos).writeUTF(entryContents);
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyZipFile(String name, String comment)
|
||||
throws Exception
|
||||
{
|
||||
// Check that Zip entry was correctly written.
|
||||
try (ZipFile zipFile = new ZipFile(name)) {
|
||||
ZipEntry zipEntry = zipFile.getEntry(entryName);
|
||||
InputStream is = zipFile.getInputStream(zipEntry);
|
||||
String result = new DataInputStream(is).readUTF();
|
||||
if (!result.equals(entryContents))
|
||||
throw new Exception("Entry contents corrupted");
|
||||
}
|
||||
|
||||
try (RandomAccessFile file = new RandomAccessFile(name, "r")) {
|
||||
// Check that comment length was correctly written.
|
||||
file.seek(file.length() - comment.length()
|
||||
- ZipFile.ENDHDR + ZipFile.ENDCOM);
|
||||
int b1 = file.readUnsignedByte();
|
||||
int b2 = file.readUnsignedByte();
|
||||
if (b1 + (b2 << 8) != comment.length())
|
||||
throw new Exception("Zip file comment length corrupted");
|
||||
|
||||
// Check that comment was correctly written.
|
||||
file.seek(file.length() - comment.length());
|
||||
byte [] bytes = new byte [comment.length()];
|
||||
file.readFully(bytes);
|
||||
if (! comment.equals(new String(bytes, "UTF8")))
|
||||
throw new Exception("Zip file comment corrupted");
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildComment(int length) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
while (result.length() < length) {
|
||||
/* Endhdr is 22 bytes long, so this pattern makes it easy
|
||||
* to see if it is copied correctly */
|
||||
result.append("abcdefghijklmnopqrstuvABCDEFGHIJKLMNOPQRSTUV");
|
||||
}
|
||||
String string = result.toString();
|
||||
string = string.substring(string.length() - length);
|
||||
return string;
|
||||
}
|
||||
}
|
||||
61
test/jdk/java/util/zip/ZipFile/Constructor.java
Normal file
61
test/jdk/java/util/zip/ZipFile/Constructor.java
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 4842702
|
||||
* @summary Check that constructors throw specified exceptions
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.util.zip.ZipFile;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class Constructor {
|
||||
private static void Unreached (Object o)
|
||||
throws Exception
|
||||
{
|
||||
// Should never get here
|
||||
throw new Exception ("Expected exception was not thrown");
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
try { Unreached (new ZipFile ((File) null, ZipFile.OPEN_READ)); }
|
||||
catch (NullPointerException e) {}
|
||||
|
||||
try { Unreached (new ZipFile ((File) null)); }
|
||||
catch (NullPointerException e) {}
|
||||
|
||||
try { Unreached (new ZipFile ((String) null)); }
|
||||
catch (NullPointerException e) {}
|
||||
|
||||
try { Unreached (new ZipFile ("NoSuchZip.zip")); }
|
||||
catch (IOException e) {}
|
||||
|
||||
try { Unreached (new ZipFile (new File ("NoSuchZip.zip"))); }
|
||||
catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
332
test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java
Normal file
332
test/jdk/java/util/zip/ZipFile/CorruptedZipFiles.java
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 4770745 6218846 6218848 6237956 8313765 8316141
|
||||
* @summary test for correct detection and reporting of corrupted zip files
|
||||
* @author Martin Buchholz
|
||||
* @run junit CorruptedZipFiles
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static java.util.zip.ZipFile.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class CorruptedZipFiles {
|
||||
|
||||
/*
|
||||
* Byte array holding a valid template ZIP.
|
||||
*
|
||||
* The 'good' ZIP file has the following structure:
|
||||
*
|
||||
* 0000 LOCAL HEADER #1 04034B50
|
||||
* 0004 Extract Zip Spec 14 '2.0'
|
||||
* 0005 Extract OS 00 'MS-DOS'
|
||||
* 0006 General Purpose Flag 0808
|
||||
* [Bits 1-2] 0 'Normal Compression'
|
||||
* [Bit 3] 1 'Streamed'
|
||||
* [Bit 11] 1 'Language Encoding'
|
||||
* 0008 Compression Method 0008 'Deflated'
|
||||
* 000A Last Mod Time 567F7D07 'Fri Mar 31 15:40:14 2023'
|
||||
* 000E CRC 00000000
|
||||
* 0012 Compressed Length 00000000
|
||||
* 0016 Uncompressed Length 00000000
|
||||
* 001A Filename Length 0001
|
||||
* 001C Extra Length 0000
|
||||
* 001E Filename 'x'
|
||||
* 001F PAYLOAD ...
|
||||
*
|
||||
* 0022 STREAMING DATA HEADER 08074B50
|
||||
* 0026 CRC 8CDC1683
|
||||
* 002A Compressed Length 00000003
|
||||
* 002E Uncompressed Length 00000001
|
||||
*
|
||||
* 0032 CENTRAL HEADER #1 02014B50
|
||||
* 0036 Created Zip Spec 14 '2.0'
|
||||
* 0037 Created OS 00 'MS-DOS'
|
||||
* 0038 Extract Zip Spec 14 '2.0'
|
||||
* 0039 Extract OS 00 'MS-DOS'
|
||||
* 003A General Purpose Flag 0808
|
||||
* [Bits 1-2] 0 'Normal Compression'
|
||||
* [Bit 3] 1 'Streamed'
|
||||
* [Bit 11] 1 'Language Encoding'
|
||||
* 003C Compression Method 0008 'Deflated'
|
||||
* 003E Last Mod Time 567F7D07 'Fri Mar 31 15:40:14 2023'
|
||||
* 0042 CRC 8CDC1683
|
||||
* 0046 Compressed Length 00000003
|
||||
* 004A Uncompressed Length 00000001
|
||||
* 004E Filename Length 0001
|
||||
* 0050 Extra Length 0000
|
||||
* 0052 Comment Length 0000
|
||||
* 0054 Disk Start 0000
|
||||
* 0056 Int File Attributes 0000
|
||||
* [Bit 0] 0 'Binary Data'
|
||||
* 0058 Ext File Attributes 00000000
|
||||
* 005C Local Header Offset 00000000
|
||||
* 0060 Filename 'x'
|
||||
*
|
||||
* 0061 END CENTRAL HEADER 06054B50
|
||||
* 0065 Number of this disk 0000
|
||||
* 0067 Central Dir Disk no 0000
|
||||
* 0069 Entries in this disk 0001
|
||||
* 006B Total Entries 0001
|
||||
* 006D Size of Central Dir 0000002F
|
||||
* 0071 Offset to Central Dir 00000032
|
||||
* 0075 Comment Length 0000
|
||||
*
|
||||
*/
|
||||
private static byte[] template;
|
||||
|
||||
// Copy of the template ZIP for modification by each test
|
||||
private byte[] copy;
|
||||
|
||||
// Litte-endian ByteBuffer for manipulating the ZIP copy
|
||||
private ByteBuffer buffer;
|
||||
|
||||
// Some well-known locations in the ZIP
|
||||
private static int endpos, cenpos, locpos;
|
||||
|
||||
// The path used when reading/writing the corrupted ZIP to disk
|
||||
private Path zip = Path.of("corrupted.zip");
|
||||
|
||||
/*
|
||||
* Make a sample ZIP and calculate some known offsets into this ZIP
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
// Make a ZIP with a single entry
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(out)) {
|
||||
ZipEntry e = new ZipEntry("x");
|
||||
zos.putNextEntry(e);
|
||||
zos.write((int)'x');
|
||||
}
|
||||
template = out.toByteArray();
|
||||
// ByteBuffer for reading fields from the ZIP
|
||||
ByteBuffer buffer = ByteBuffer.wrap(template).order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// Calculate the offset of the End of central directory record
|
||||
endpos = template.length - ENDHDR;
|
||||
// Look up the offet of the Central directory header
|
||||
cenpos = buffer.getShort(endpos + ENDOFF);
|
||||
// Look up the offset of the corresponding Local file header
|
||||
locpos = buffer.getShort(cenpos + CENOFF);
|
||||
|
||||
// Run some sanity checks on the valid ZIP:
|
||||
assertEquals(ENDSIG, buffer.getInt(endpos),"Where's ENDSIG?");
|
||||
assertEquals(CENSIG, buffer.getInt(cenpos),"Where's CENSIG?");
|
||||
assertEquals(LOCSIG, buffer.getInt(locpos),"Where's LOCSIG?");
|
||||
assertEquals(buffer.getShort(cenpos+CENNAM),
|
||||
buffer.getShort(locpos+LOCNAM),
|
||||
"Name field length mismatch");
|
||||
assertEquals(buffer.getShort(cenpos+CENEXT),
|
||||
buffer.getShort( locpos+LOCEXT),
|
||||
"Extra field length mismatch");
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a copy safe to modify by each test
|
||||
*/
|
||||
@BeforeEach
|
||||
public void makeCopy() {
|
||||
copy = template.clone();
|
||||
buffer = ByteBuffer.wrap(copy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete the ZIP file produced after each test method
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when the 'End of Central Directory'
|
||||
* (END) header has a CEN size exceeding past the offset of the END record
|
||||
*/
|
||||
@Test
|
||||
public void excessiveCENSize() throws IOException {
|
||||
buffer.putInt(endpos+ENDSIZ, 0xff000000);
|
||||
assertZipException(".*bad central directory size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when the 'End of Central Directory'
|
||||
* (END) header has a CEN offset with an invalid value.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveCENOffset() throws IOException {
|
||||
buffer.putInt(endpos+ENDOFF, 0xff000000);
|
||||
assertZipException(".*bad central directory offset.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has an unexpected signature
|
||||
*/
|
||||
@Test
|
||||
public void invalidCENSignature() throws IOException {
|
||||
int existingSignature = buffer.getInt(cenpos);
|
||||
buffer.putInt(cenpos, existingSignature +1);
|
||||
assertZipException(".*bad signature.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has the
|
||||
* 'general purpose bit flag 0' ('encrypted') set.
|
||||
*/
|
||||
@Test
|
||||
public void encryptedEntry() throws IOException {
|
||||
copy[cenpos+CENFLG] |= 1;
|
||||
assertZipException(".*encrypted entry.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has a file name
|
||||
* length which makes the CEN header overflow into the
|
||||
* 'End of central directory' record.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveFileNameLength() throws IOException {
|
||||
short existingNameLength = buffer.getShort(cenpos + CENNAM);
|
||||
buffer.putShort(cenpos+CENNAM, (short) (existingNameLength + 1));
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has a
|
||||
* file name length which makes the CEN header overflow into the
|
||||
* 'End of central directory' record.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveFileNameLength2() throws IOException {
|
||||
buffer.putShort(cenpos + CENNAM, (short) 0xfdfd);
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown if the last CEN header is not immediately
|
||||
* followed by the start of the 'End of central directory' record
|
||||
*/
|
||||
@Test
|
||||
public void insufficientFilenameLength() throws IOException {
|
||||
short existingNameLength = buffer.getShort(cenpos + CENNAM);
|
||||
buffer.putShort(cenpos+CENNAM, (short) (existingNameLength - 1));
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown if a CEN header has an
|
||||
* extra field length which makes the CEN header overflow into the
|
||||
* End of central directory record.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveExtraFieldLength() throws IOException {
|
||||
buffer.put(cenpos+CENEXT, (byte) 0xff);
|
||||
buffer.put(cenpos+CENEXT+1, (byte) 0xff);
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown if a CEN header has an
|
||||
* extra field length which makes the CEN header overflow into the
|
||||
* End of central directory record.
|
||||
*/
|
||||
@Test
|
||||
public void excessiveExtraFieldLength2() throws IOException {
|
||||
buffer.putShort(cenpos+CENEXT, (short) 0xfdfd);
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has a comment length
|
||||
* which overflows into the 'End of central directory' record
|
||||
*/
|
||||
@Test
|
||||
public void excessiveCommentLength() throws IOException {
|
||||
short existingCommentLength = buffer.getShort(cenpos + CENCOM);
|
||||
buffer.putShort(cenpos+CENCOM, (short) (existingCommentLength + 1));
|
||||
assertZipException(".*bad header size.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a CEN header has a
|
||||
* compression method field which is unsupported by the implementation
|
||||
*/
|
||||
@Test
|
||||
public void unsupportedCompressionMethod() throws IOException {
|
||||
copy[cenpos+CENHOW] = 2;
|
||||
assertZipException(".*bad compression method.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* A ZipException is thrown when a LOC header has an unexpected signature
|
||||
*/
|
||||
@Test
|
||||
public void invalidLOCSignature() throws IOException {
|
||||
int existingSignatur = buffer.getInt(locpos);
|
||||
buffer.putInt(locpos, existingSignatur +1);
|
||||
assertZipException(".*bad signature.*");
|
||||
}
|
||||
|
||||
/*
|
||||
* Assert that opening a ZIP file and consuming the entry's
|
||||
* InputStream using the ZipFile API fails with a ZipException
|
||||
* with a message matching the given pattern.
|
||||
*
|
||||
* The ZIP file opened is the contents of the 'copy' byte array.
|
||||
*/
|
||||
void assertZipException(String msgPattern) throws IOException {
|
||||
|
||||
Files.write(zip, copy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
try (InputStream is = zf.getInputStream(new ZipEntry("x"))) {
|
||||
is.transferTo(OutputStream.nullOutputStream());
|
||||
}
|
||||
}
|
||||
});
|
||||
assertTrue(ex.getMessage().matches(msgPattern),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
|
||||
}
|
||||
}
|
||||
103
test/jdk/java/util/zip/ZipFile/DeleteTempJar.java
Normal file
103
test/jdk/java/util/zip/ZipFile/DeleteTempJar.java
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import com.sun.net.httpserver.*;
|
||||
|
||||
|
||||
public class DeleteTempJar
|
||||
{
|
||||
public static void realMain(String args[]) throws Exception
|
||||
{
|
||||
final File zf = File.createTempFile("deletetemp", ".jar");
|
||||
zf.deleteOnExit();
|
||||
try (FileOutputStream fos = new FileOutputStream(zf);
|
||||
JarOutputStream jos = new JarOutputStream(fos))
|
||||
{
|
||||
JarEntry je = new JarEntry("entry");
|
||||
jos.putNextEntry(je);
|
||||
jos.write("hello, world".getBytes("ASCII"));
|
||||
}
|
||||
|
||||
HttpServer server = HttpServer.create(
|
||||
new InetSocketAddress((InetAddress) null, 0), 0);
|
||||
HttpContext context = server.createContext("/",
|
||||
new HttpHandler() {
|
||||
public void handle(HttpExchange e) {
|
||||
try (FileInputStream fis = new FileInputStream(zf)) {
|
||||
e.sendResponseHeaders(200, zf.length());
|
||||
OutputStream os = e.getResponseBody();
|
||||
byte[] buf = new byte[1024];
|
||||
int count = 0;
|
||||
while ((count = fis.read(buf)) != -1) {
|
||||
os.write(buf, 0, count);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
unexpected(ex);
|
||||
} finally {
|
||||
e.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.start();
|
||||
try {
|
||||
URL url = new URL("jar:http://localhost:"
|
||||
+ new Integer(server.getAddress().getPort()).toString()
|
||||
+ "/deletetemp.jar!/");
|
||||
JarURLConnection c = (JarURLConnection)url.openConnection();
|
||||
JarFile f = c.getJarFile();
|
||||
check(f.getEntry("entry") != null);
|
||||
System.out.println(f.getName());
|
||||
} finally {
|
||||
server.stop(0);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static boolean pass() {passed++; return true;}
|
||||
static boolean fail() {failed++; Thread.dumpStack(); return false;}
|
||||
static boolean fail(String msg) {System.out.println(msg); return fail();}
|
||||
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
||||
static boolean equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) return pass();
|
||||
else return fail(x + " not equal to " + y);}
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
||||
51
test/jdk/java/util/zip/ZipFile/DeleteTempJarTest.java
Normal file
51
test/jdk/java/util/zip/ZipFile/DeleteTempJarTest.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 4166799
|
||||
* @summary Make sure URL-downloaded jar files (jar_cache files)
|
||||
* will be deleted when VM exits.
|
||||
* @modules jdk.httpserver
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.process.*
|
||||
* DeleteTempJar
|
||||
* @run main DeleteTempJarTest
|
||||
*/
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
public class DeleteTempJarTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String tmpFile = ProcessTools.executeTestJava(DeleteTempJar.class.getName())
|
||||
.shouldHaveExitValue(0)
|
||||
.getStdout();
|
||||
|
||||
Asserts.assertFalse(Files.exists(Paths.get(tmpFile.trim())));
|
||||
}
|
||||
}
|
||||
216
test/jdk/java/util/zip/ZipFile/DupEntriesGetInputStream.java
Normal file
216
test/jdk/java/util/zip/ZipFile/DupEntriesGetInputStream.java
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HexFormat;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8349914
|
||||
* @summary Validate ZipFile::getFileInputStream returns the correct data when
|
||||
* there are multiple entries with the same filename
|
||||
* @run junit DupEntriesGetInputStream
|
||||
*/
|
||||
class DupEntriesGetInputStream {
|
||||
|
||||
// created through a call to createNormalZIP()
|
||||
private static final String NORMAL_ZIP_CONTENT_HEX = """
|
||||
504b03041400080808009195c35a00000000000000000000000006000000456e747279310bc9c8
|
||||
2c560022d7bc92a24a054300504b07089bc0e55b0f0000000f000000504b030414000808080091
|
||||
95c35a00000000000000000000000006000000456e747279320bc9c82c560022d7bc92a24a85bc
|
||||
d2dca4d4228590f27c00504b0708ebda8deb1800000018000000504b03041400080808009195c3
|
||||
5a00000000000000000000000006000000456e747279330bc9c82c560022d7bc92a24a05650563
|
||||
00504b0708d1eafe7d1100000011000000504b010214001400080808009195c35a9bc0e55b0f00
|
||||
00000f000000060000000000000000000000000000000000456e74727931504b01021400140008
|
||||
0808009195c35aebda8deb1800000018000000060000000000000000000000000043000000456e
|
||||
74727932504b010214001400080808009195c35ad1eafe7d110000001100000006000000000000
|
||||
000000000000008f000000456e74727933504b050600000000030003009c000000d40000000000
|
||||
""";
|
||||
|
||||
// intentionally unused but left here to allow for constructing newer/updated
|
||||
// NORMAL_ZIP_CONTENT_HEX, when necessary
|
||||
private static String createNormalZIP() throws IOException {
|
||||
final ByteArrayOutputStream zipContent = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(zipContent)) {
|
||||
zos.putNextEntry(new ZipEntry(ENTRY1_NAME));
|
||||
zos.write(ENTRY1.getBytes(US_ASCII));
|
||||
zos.putNextEntry(new ZipEntry(ENTRY2_NAME));
|
||||
zos.write(ENTRY2.getBytes(US_ASCII));
|
||||
zos.putNextEntry(new ZipEntry(ENTRY3_NAME));
|
||||
zos.write(ENTRY3.getBytes(US_ASCII));
|
||||
}
|
||||
return HexFormat.of().formatHex(zipContent.toByteArray());
|
||||
}
|
||||
|
||||
// Entry Names and their data to be added to the ZIP File
|
||||
private static final String ENTRY1_NAME = "Entry1";
|
||||
private static final String ENTRY1 = "This is Entry 1";
|
||||
|
||||
private static final String ENTRY2_NAME = "Entry2";
|
||||
private static final String ENTRY2 = "This is Entry number Two";
|
||||
|
||||
private static final String ENTRY3_NAME = "Entry3";
|
||||
private static final String ENTRY3 = "This is Entry # 3";
|
||||
|
||||
// ZIP entry and its expected data
|
||||
record ZIP_ENTRY(String entryName, String data) {
|
||||
}
|
||||
|
||||
private static final ZIP_ENTRY[] ZIP_ENTRIES = new ZIP_ENTRY[]{
|
||||
new ZIP_ENTRY(ENTRY1_NAME, ENTRY1),
|
||||
new ZIP_ENTRY(ENTRY2_NAME, ENTRY2),
|
||||
new ZIP_ENTRY(ENTRY1_NAME, ENTRY3)
|
||||
};
|
||||
|
||||
private static Path dupEntriesZipFile;
|
||||
|
||||
// 008F LOCAL HEADER #3 04034B50
|
||||
// ...
|
||||
// 00A1 Compressed Length 00000000
|
||||
// 00A5 Uncompressed Length 00000000
|
||||
// 00A9 Filename Length 0006
|
||||
// ...
|
||||
// 00AD Filename 'Entry3'
|
||||
private static final int ENTRY3_FILENAME_LOC_OFFSET = 0x00AD;
|
||||
|
||||
// 013C CENTRAL HEADER #3 02014B50
|
||||
// ...
|
||||
// 0150 Compressed Length 00000011
|
||||
// 0154 Uncompressed Length 00000011
|
||||
// 0158 Filename Length 0006
|
||||
// ...
|
||||
// 016A Filename 'Entry3'
|
||||
private static final int ENTRY3_FILENAME_CEN_OFFSET = 0x016A;
|
||||
|
||||
@BeforeAll
|
||||
static void createDupEntriesZIP() throws Exception {
|
||||
final byte[] originalZIPContent = HexFormat.of().parseHex(
|
||||
NORMAL_ZIP_CONTENT_HEX.replace("\n", ""));
|
||||
final ByteBuffer buf = ByteBuffer.wrap(originalZIPContent).order(LITTLE_ENDIAN);
|
||||
// replace the file name literal "Entry3" with the literal "Entry1", both in the
|
||||
// LOC header and the CEN of Entry3
|
||||
final int locEntry3LastCharOffset = ENTRY3_FILENAME_LOC_OFFSET + ENTRY3_NAME.length() - 1;
|
||||
buf.put(locEntry3LastCharOffset, (byte) 49); // 49 represents the character "1"
|
||||
final int cenEntry3LastCharOffset = ENTRY3_FILENAME_CEN_OFFSET + ENTRY3_NAME.length() - 1;
|
||||
buf.put(cenEntry3LastCharOffset, (byte) 49); // 49 represents the character "1"
|
||||
buf.rewind();
|
||||
// write out the manipulated ZIP content, containing duplicate entries, into a file
|
||||
// so that it can be read using ZipFile
|
||||
dupEntriesZipFile = Files.createTempFile(Path.of("."), "8349914-", ".zip");
|
||||
Files.write(dupEntriesZipFile, buf.array());
|
||||
System.out.println("created ZIP file with duplicate entries at " + dupEntriesZipFile);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the correct ZipEntry data is returned when a List is used
|
||||
* to access entries returned from ZipFile::entries
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testUsingListEntries() throws IOException {
|
||||
System.out.println("Processing entries via Collections.list()");
|
||||
try (ZipFile zf = new ZipFile(dupEntriesZipFile.toFile())) {
|
||||
var entryNumber = 0;
|
||||
for (var e : Collections.list(zf.entries())) {
|
||||
verifyEntry(entryNumber++, zf, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the correct ZipEntry data is returned when a ZipEntryIterator
|
||||
* is used to access entries returned from ZipFile::entries
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testUsingZipEntryIterator() throws IOException {
|
||||
System.out.println("Processing entries via a ZipEntryIterator");
|
||||
try (ZipFile zf = new ZipFile(dupEntriesZipFile.toFile())) {
|
||||
Enumeration<? extends ZipEntry> entries = zf.entries();
|
||||
var entryNumber = 0;
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
verifyEntry(entryNumber++, zf, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that the correct ZipEntry data is returned when a EntrySpliterator
|
||||
* is used to access entries returned from ZipFile::stream
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testUsingEntrySpliterator() throws IOException {
|
||||
System.out.println("Processing entries via a EntrySpliterator");
|
||||
AtomicInteger eNumber = new AtomicInteger(0);
|
||||
try (ZipFile zf = new ZipFile(dupEntriesZipFile.toFile())) {
|
||||
zf.stream().forEach(e -> {
|
||||
try {
|
||||
verifyEntry(eNumber.getAndIncrement(), zf, e);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the ZipEntry returned matches what is expected
|
||||
*
|
||||
* @param entryNumber offset into ZIP_ENTRIES containing the expected value
|
||||
* to be returned
|
||||
* @param zf ZipFile containing the entry
|
||||
* @param e ZipEntry to validate
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void verifyEntry(int entryNumber, ZipFile zf, ZipEntry e) throws IOException {
|
||||
System.out.println("Validating Entry: " + entryNumber);
|
||||
assertEquals(ZIP_ENTRIES[entryNumber].entryName(), e.getName());
|
||||
try (var in = zf.getInputStream(e)) {
|
||||
var entryData = new String(in.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertEquals(ZIP_ENTRIES[entryNumber].data(), entryData);
|
||||
}
|
||||
}
|
||||
}
|
||||
151
test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java
Normal file
151
test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8272746
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @summary Verify that ZipFile rejects files with CEN sizes exceeding the implementation limit
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.util.ZipUtils
|
||||
* @run junit/othervm EndOfCenValidation
|
||||
*/
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static jdk.test.lib.util.ZipUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* This test augments {@link TestTooManyEntries}. It creates sparse ZIPs where
|
||||
* the CEN size is inflated to the desired value. This helps this test run
|
||||
* fast with much less resources.
|
||||
*
|
||||
* While the CEN in these files are zero-filled and the produced ZIPs are technically
|
||||
* invalid, the CEN is never actually read by ZipFile since it does
|
||||
* 'End of central directory record' (END header) validation before reading the CEN.
|
||||
*/
|
||||
public class EndOfCenValidation {
|
||||
|
||||
// Zip files produced by this test
|
||||
static final Path CEN_TOO_LARGE_ZIP = Path.of("cen-size-too-large.zip");
|
||||
static final Path INVALID_CEN_SIZE = Path.of("invalid-zen-size.zip");
|
||||
static final Path BAD_CEN_OFFSET_ZIP = Path.of("bad-cen-offset.zip");
|
||||
static final Path BAD_ENTRY_COUNT_ZIP = Path.of("bad-entry-count.zip");
|
||||
|
||||
// Maximum allowed CEN size allowed by ZipFile
|
||||
static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH;
|
||||
|
||||
/**
|
||||
* Delete big files after test, in case the file system did not support sparse files.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(CEN_TOO_LARGE_ZIP);
|
||||
Files.deleteIfExists(INVALID_CEN_SIZE);
|
||||
Files.deleteIfExists(BAD_CEN_OFFSET_ZIP);
|
||||
Files.deleteIfExists(BAD_ENTRY_COUNT_ZIP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that an 'End of central directory record' (END header) with a CEN
|
||||
* length exceeding {@link #MAX_CEN_SIZE} limit is rejected
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectTooLargeCenSize() throws IOException {
|
||||
int size = MAX_CEN_SIZE + 1;
|
||||
Path zip = zipWithModifiedEndRecord(size, true, 0, CEN_TOO_LARGE_ZIP);
|
||||
verifyRejection(zip, INVALID_CEN_SIZE_TOO_LARGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an 'End of central directory record' (END header)
|
||||
* where the value of the CEN size field exceeds the position of
|
||||
* the END header is rejected.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectInvalidCenSize() throws IOException {
|
||||
int size = MAX_CEN_SIZE;
|
||||
Path zip = zipWithModifiedEndRecord(size, false, 0, INVALID_CEN_SIZE);
|
||||
verifyRejection(zip, INVALID_CEN_BAD_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an 'End of central directory record' (the END header)
|
||||
* where the value of the CEN offset field is larger than the position
|
||||
* of the END header minus the CEN size is rejected
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectInvalidCenOffset() throws IOException {
|
||||
int size = MAX_CEN_SIZE;
|
||||
Path zip = zipWithModifiedEndRecord(size, true, 100, BAD_CEN_OFFSET_ZIP);
|
||||
verifyRejection(zip, INVALID_CEN_BAD_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a 'Zip64 End of Central Directory' record (the END header)
|
||||
* where the value of the 'total entries' field is larger than what fits
|
||||
* in the CEN size is rejected.
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {
|
||||
-1, // Negative
|
||||
Long.MIN_VALUE, // Very negative
|
||||
0x3B / 3L - 1, // Cannot fit in test ZIP's CEN
|
||||
MAX_CEN_SIZE / 3 + 1, // Too large to allocate int[] entries array
|
||||
Long.MAX_VALUE // Unreasonably large
|
||||
})
|
||||
public void shouldRejectBadTotalEntries(long totalEntries) throws IOException {
|
||||
Path zip = zip64WithModifiedTotalEntries(BAD_ENTRY_COUNT_ZIP, totalEntries);
|
||||
verifyRejection(zip, INVALID_BAD_ENTRY_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile rejects the ZIP file with a ZipException
|
||||
* with the given message
|
||||
* @param zip ZIP file to open
|
||||
* @param msg exception message to expect
|
||||
*/
|
||||
private static void verifyRejection(Path zip, String msg) {
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
new ZipFile(zip.toFile());
|
||||
});
|
||||
assertEquals(msg, ex.getMessage());
|
||||
}
|
||||
}
|
||||
94
test/jdk/java/util/zip/ZipFile/EnumerateAfterClose.java
Normal file
94
test/jdk/java/util/zip/ZipFile/EnumerateAfterClose.java
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
@bug 4290060
|
||||
@summary Check if the zip file is closed before access any
|
||||
elements in the Enumeration.
|
||||
@run junit EnumerateAfterClose
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class EnumerateAfterClose {
|
||||
|
||||
// ZIP file used in this test
|
||||
private Path zip = Path.of("enum-after-close.zip");
|
||||
|
||||
/**
|
||||
* Create a sample ZIP file for use by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempting to using a ZipEntry Enumeration after its backing
|
||||
* ZipFile is closed should throw IllegalStateException.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void enumeratingAfterCloseShouldThrowISE() throws IOException {
|
||||
// Retain a reference to an enumeration backed by a closed ZipFile
|
||||
Enumeration e;
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
e = zf.entries();
|
||||
}
|
||||
// Using the enumeration after the ZipFile is closed should throw ISE
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
if (e.hasMoreElements()) {
|
||||
ZipEntry ze = (ZipEntry)e.nextElement();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
113
test/jdk/java/util/zip/ZipFile/FinalizeInflater.java
Normal file
113
test/jdk/java/util/zip/ZipFile/FinalizeInflater.java
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
@bug 7003462
|
||||
@summary Make sure cached Inflater does not get finalized.
|
||||
@run junit FinalizeInflater
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class FinalizeInflater {
|
||||
|
||||
// ZIP file produced by this test
|
||||
private Path zip = Path.of("finalize-inflater.zip");
|
||||
|
||||
/**
|
||||
* Create the sample ZIP used in this test
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
byte[] hello = "hello".getBytes(StandardCharsets.UTF_8);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
zo.write(hello);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced by this test
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* A cached Inflater should not be made invalid by finalization
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void shouldNotFinalizeInflaterInPool() throws IOException {
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry ze = zf.getEntry("file.txt");
|
||||
read(zf.getInputStream(ze));
|
||||
System.gc();
|
||||
System.runFinalization();
|
||||
System.gc();
|
||||
// read again
|
||||
read(zf.getInputStream(ze));
|
||||
}
|
||||
}
|
||||
|
||||
private static void read(InputStream is)
|
||||
throws IOException
|
||||
{
|
||||
Wrapper wrapper = new Wrapper(is);
|
||||
is.readAllBytes();
|
||||
}
|
||||
|
||||
static class Wrapper {
|
||||
InputStream is;
|
||||
public Wrapper(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
1068
test/jdk/java/util/zip/ZipFile/GetInputStreamNPETest.java
Normal file
1068
test/jdk/java/util/zip/ZipFile/GetInputStreamNPETest.java
Normal file
File diff suppressed because it is too large
Load diff
117
test/jdk/java/util/zip/ZipFile/IncorrectEndTot.java
Normal file
117
test/jdk/java/util/zip/ZipFile/IncorrectEndTot.java
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @summary Verify that ZipFile::size reports the actual number of entries
|
||||
* even with an incorrect ENDTOT field
|
||||
* @run junit IncorrectEndTot
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class IncorrectEndTot {
|
||||
|
||||
// File to use for this test
|
||||
File file = new File("incorrect-end-centot.zip");
|
||||
|
||||
// Return scenarios for correct and incorrect ENDTOT fields
|
||||
public static Stream<Arguments> scenarios() {
|
||||
return Stream.of(
|
||||
Arguments.of(10, 10), // CEN agrees with ENDTOT
|
||||
Arguments.of(10, 11), // CEN has one less than ENDTOT
|
||||
Arguments.of(11, 10), // CEN has one more than ENDTOT
|
||||
Arguments.of(0, 0), // Empty ZIP, correct ENDTOT
|
||||
Arguments.of(0, 10) // Empty ZIP, incorrect ENDTOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the file used by this test
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() {
|
||||
file.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile::size reports the actual number of CEN records,
|
||||
* regardless of the ENDTOT field.
|
||||
*
|
||||
* @param actual number of entries in the ZIP file
|
||||
* @param reported number reported in ENDTOT
|
||||
* @throws IOException if an unexpected error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("scenarios")
|
||||
public void shouldCountActualEntries(int actual, int reported) throws IOException {
|
||||
createZip(file, actual, reported);
|
||||
try (ZipFile zf = new ZipFile(file)) {
|
||||
assertEquals(actual, zf.size());
|
||||
assertEquals(actual, Collections.list(zf.entries()).size());
|
||||
assertEquals(actual, zf.stream().count());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ZIP file with a number of entries, possibly reporting an incorrect number in
|
||||
* the ENDTOT field
|
||||
* @param file the file to write to
|
||||
* @param numEntries the number of entries to generate
|
||||
* @param reported the number of entries to report in the END header's ENDTOT field
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void createZip(File file, int numEntries, int reported) throws IOException {
|
||||
// Create a ZIP
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
zo.putNextEntry(new ZipEntry("entry_" + i));
|
||||
}
|
||||
}
|
||||
byte[] bytes = out.toByteArray();
|
||||
|
||||
// Update the ENDTOT field to report a possibly incorrect number
|
||||
ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buf.putShort(bytes.length - ZipFile.ENDHDR + ZipFile.ENDTOT, (short) reported);
|
||||
|
||||
// Write to disk
|
||||
Files.write(file.toPath(), bytes);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8301873 8321156
|
||||
* @summary Validate that a ZipException is thrown when a ZIP file with
|
||||
* invalid UTF-8 byte sequences in the name or comment fields is opened via
|
||||
* ZipFile or traversed via ZipInputStream.
|
||||
* Also validate that ZipFile::getComment will return null with invalid UTF-8
|
||||
* byte sequences in the ZIP file comment
|
||||
* @run junit InvalidBytesInEntryNameOrComment
|
||||
*/
|
||||
public class InvalidBytesInEntryNameOrComment {
|
||||
// Zip file that is created and used by the test
|
||||
public static final Path ZIP_FILE = Path.of("BadName.zip");
|
||||
// Example invalid UTF-8 byte sequence
|
||||
private static final byte[] INVALID_UTF8_BYTE_SEQUENCE = {(byte) 0xF0, (byte) 0xA4, (byte) 0xAD};
|
||||
// Expected error message when an invalid entry name or entry comment is
|
||||
// encountered when accessing a CEN Header
|
||||
private static final String CEN_BAD_ENTRY_NAME_OR_COMMENT = "invalid CEN header (bad entry name or comment)";
|
||||
|
||||
// Expected error message when an invalid entry name is encountered when
|
||||
// accessing a LOC Header
|
||||
private static final String LOC_HEADER_BAD_ENTRY_NAME = "invalid LOC header (bad entry name)";
|
||||
// Zip file comment starting offset
|
||||
private static final int ZIP_FILE_COMMENT_OFFSET = 0x93;
|
||||
// CEN Header offset for the entry comment to be modified
|
||||
private static final int CEN_FILE_HEADER_FILE_COMMENT_STARTING_OFFSET = 0x6D;
|
||||
// CEN Header offset for the entry name to be modified
|
||||
private static final int CEN_FILE_HEADER_FILENAME_STARTING_OFFSET = 0x66;
|
||||
// LOC Header offset for the entry name to be modified
|
||||
private static final int LOC_FILE_HEADER_FILENAME_STARTING_OFFSET = 0x1e;
|
||||
// CEN Entry comment
|
||||
public static final String ENTRY_COMMENT = "entryComment";
|
||||
// Entry name to be modified/validated
|
||||
public static final String ENTRY_NAME = "entryName";
|
||||
// Zip file comment to be modified/validated
|
||||
public static final String ZIP_FILE_COMMENT = "ZipFileComment";
|
||||
// Buffer used to massage the byte array containing the Zip File
|
||||
private ByteBuffer buffer;
|
||||
// Array used to copy VALID_ZIP into prior to each test run
|
||||
private byte[] zipArray;
|
||||
|
||||
/**
|
||||
* Byte array representing a valid Zip file prior modifying the CEN/LOC
|
||||
* entry name, CEN entry comment or Zip file comment with an invalid
|
||||
* UTF-8 byte sequence.
|
||||
* See the createZipByteArray method which was used to create the original
|
||||
* Zip file
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x3a: Signature : 0x02014b50
|
||||
* 0x3e: Created Zip Spec : 0x14 [2.0]
|
||||
* 0x3f: Created OS : 0x0 [MS-DOS]
|
||||
* 0x40: VerMadeby : 0x14 [0, 2.0]
|
||||
* 0x41: VerExtract : 0x14 [2.0]
|
||||
* 0x42: Flag : 0x808
|
||||
* 0x44: Method : 0x8 [DEFLATED]
|
||||
* 0x46: Last Mod Time : 0x58506664 [Fri Feb 16 12:51:08 EST 2024]
|
||||
* 0x4a: CRC : 0xd202ef8d
|
||||
* 0x4e: Compressed Size : 0x3
|
||||
* 0x52: Uncompressed Size: 0x1
|
||||
* 0x56: Name Length : 0x9
|
||||
* 0x58: Extra Length : 0x0
|
||||
* 0x5a: Comment Length : 0xc
|
||||
* 0x5c: Disk Start : 0x0
|
||||
* 0x5e: Attrs : 0x0
|
||||
* 0x60: AttrsEx : 0x0
|
||||
* 0x64: Loc Header Offset: 0x0
|
||||
* 0x68: File Name : entryName
|
||||
* 0x71: Comment : [entryComment]
|
||||
* [Local File Header]
|
||||
* 0x0: Signature : 0x04034b50
|
||||
* 0x4: Version : 0x14 [2.0]
|
||||
* 0x6: Flag : 0x808
|
||||
* 0x8: Method : 0x8 [DEFLATED]
|
||||
* 0xa: LastMTime : 0x58506664 [Fri Feb 16 12:51:08 EST 2024]
|
||||
* 0xe: CRC : 0x0
|
||||
* 0x12: CSize : 0x0
|
||||
* 0x16: Size : 0x0
|
||||
* 0x1a: Name Length : 0x9 [entryName]
|
||||
* 0x1c: ExtraLength : 0x0
|
||||
* 0x1e: File Name : [entryName]
|
||||
* [End Central Directory Header]
|
||||
* 0x7d: Signature : 0x06054b50
|
||||
* 0x85: Disk Entries: 0x1
|
||||
* 0x87: Total Entries: 0x1
|
||||
* 0x89: CEN Size : 0x43
|
||||
* 0x8d: Offset CEN : 0x3a
|
||||
* 0x91: Comment Len : 0xe
|
||||
* 0x93: Comment : [ZipFileComment]
|
||||
*/
|
||||
public static byte[] VALID_ZIP = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x7d, (byte) 0x6f, (byte) 0x50, (byte) 0x58, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x4e, (byte) 0x61, (byte) 0x6d, (byte) 0x65, (byte) 0x63,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x8d, (byte) 0xef,
|
||||
(byte) 0x2, (byte) 0xd2, (byte) 0x3, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x7d, (byte) 0x6f,
|
||||
(byte) 0x50, (byte) 0x58, (byte) 0x8d, (byte) 0xef, (byte) 0x2, (byte) 0xd2, (byte) 0x3, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x4e, (byte) 0x61, (byte) 0x6d,
|
||||
(byte) 0x65, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x43, (byte) 0x6f,
|
||||
(byte) 0x6d, (byte) 0x6d, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x5,
|
||||
(byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3a, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0xe, (byte) 0x0, (byte) 0x5a, (byte) 0x69, (byte) 0x70, (byte) 0x46, (byte) 0x69,
|
||||
(byte) 0x6c, (byte) 0x65, (byte) 0x43, (byte) 0x6f, (byte) 0x6d, (byte) 0x6d, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x74,
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete the Zip file if it exists prior to each run and create a copy
|
||||
* of the byte array representing a valid ZIP file to be used by each test run
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setupTest() throws IOException {
|
||||
Files.deleteIfExists(ZIP_FILE);
|
||||
zipArray = Arrays.copyOf(VALID_ZIP, VALID_ZIP.length);
|
||||
buffer = ByteBuffer.wrap(zipArray).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* The MethodSource of CEN offsets to modify with an invalid UTF-8 byte
|
||||
* sequence
|
||||
*
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> CENCommentOffsets() {
|
||||
return Stream.of(
|
||||
// Entry's name starting offset
|
||||
Arguments.of(CEN_FILE_HEADER_FILENAME_STARTING_OFFSET),
|
||||
// Entry's comment starting offset
|
||||
Arguments.of(CEN_FILE_HEADER_FILE_COMMENT_STARTING_OFFSET)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the original Zip file can be opened via ZipFile.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testValidEntryNameAndComment() throws IOException {
|
||||
Files.write(ZIP_FILE, zipArray);
|
||||
try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {
|
||||
var comment = zf.getComment();
|
||||
assertEquals(ZIP_FILE_COMMENT, comment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the original Zip file can be opened and traversed via
|
||||
* ZipinputStream::getNextEntry.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void traverseZipWithZipInputStreamTest() throws IOException {
|
||||
Files.write(ZIP_FILE, zipArray);
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(ZIP_FILE.toFile()))) {
|
||||
ZipEntry ze;
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
assertEquals(ENTRY_NAME, ze.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ZipException is thrown when an entry name or entry comment
|
||||
* within a CEN file header contains an invalid UTF-8 byte sequence.
|
||||
*
|
||||
* @param offset the offset to the file name or file comment within the CEN
|
||||
* file header
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("CENCommentOffsets")
|
||||
public void testInValidEntryNameOrComment(int offset)
|
||||
throws IOException {
|
||||
createInvalidUTFEntryInZipFile(offset);
|
||||
Throwable ex = assertThrows(ZipException.class, () ->
|
||||
{
|
||||
try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {};
|
||||
}
|
||||
);
|
||||
assertEquals(CEN_BAD_ENTRY_NAME_OR_COMMENT, ex.getMessage());
|
||||
}
|
||||
/**
|
||||
* Validate that a null is returned from ZipFile::getComment when the
|
||||
* comment contains an invalid UTF-8 byte sequence.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void testInValidZipFileComment() throws IOException {
|
||||
createInvalidUTFEntryInZipFile(ZIP_FILE_COMMENT_OFFSET);
|
||||
try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {
|
||||
assertNull(zf.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ZipException is thrown when an entry name
|
||||
* within a LOC file header contains an invalid UTF-8 byte sequence.
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void invalidZipInputStreamTest() throws IOException {
|
||||
createInvalidUTFEntryInZipFile(LOC_FILE_HEADER_FILENAME_STARTING_OFFSET);
|
||||
Throwable ex = assertThrows(ZipException.class, () ->
|
||||
{
|
||||
try (ZipInputStream zis =
|
||||
new ZipInputStream(new FileInputStream(ZIP_FILE.toFile()))) {
|
||||
zis.getNextEntry();
|
||||
};
|
||||
});
|
||||
assertEquals(LOC_HEADER_BAD_ENTRY_NAME, ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method which modifies a Zip file starting at the specified
|
||||
* offset to include an invalid UTF-8 byte sequence.
|
||||
*
|
||||
* @param offset starting offset within the Zip file to modify
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private void createInvalidUTFEntryInZipFile(int offset) throws IOException {
|
||||
buffer.put(offset, INVALID_UTF8_BYTE_SEQUENCE, 0,
|
||||
INVALID_UTF8_BYTE_SEQUENCE.length);
|
||||
Files.write(ZIP_FILE, zipArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method which creates the Zip file used by the tests and
|
||||
* converts Zip file to byte array declaration.
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private void createZipByteArray() throws IOException {
|
||||
ZipOutputStream zos = new ZipOutputStream(
|
||||
new FileOutputStream(ZIP_FILE.toFile()));
|
||||
zos.setComment(ZIP_FILE_COMMENT);
|
||||
ZipEntry entry = new ZipEntry(ENTRY_NAME);
|
||||
entry.setComment(ENTRY_COMMENT);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write(new byte[1]);
|
||||
zos.closeEntry();
|
||||
zos.close();
|
||||
// Now create the byte array entry declaration
|
||||
var fooJar = Files.readAllBytes(ZIP_FILE);
|
||||
var result = createByteArray(fooJar, "VALID_ZIP");
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method which takes a byte array and converts to byte array
|
||||
* declaration. For example:
|
||||
* {@snippet :
|
||||
* var fooJar = Files.readAllBytes(Path.of("foo.jar"));
|
||||
* var result = createByteArray(fooJar,"FOOBYTES");
|
||||
* System.out.println(result);
|
||||
* }
|
||||
*
|
||||
* @param bytes A byte array used to create a byte array declaration
|
||||
* @param name Name to be used in the byte array declaration
|
||||
* @return The formatted byte array declaration
|
||||
*/
|
||||
public static String createByteArray(byte[] bytes, String name) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 5);
|
||||
Formatter fmt = new Formatter(sb);
|
||||
fmt.format(" public static byte[] %s = {", name);
|
||||
final int linelen = 8;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
if (i % linelen == 0) {
|
||||
fmt.format("%n ");
|
||||
}
|
||||
fmt.format(" (byte) 0x%x,", bytes[i] & 0xff);
|
||||
}
|
||||
fmt.format("%n };%n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
348
test/jdk/java/util/zip/ZipFile/InvalidCommentLengthTest.java
Normal file
348
test/jdk/java/util/zip/ZipFile/InvalidCommentLengthTest.java
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8280404
|
||||
* @summary Validate that Zip/JarFile will throw a ZipException when the CEN
|
||||
* comment length field contains an incorrect value
|
||||
* @run junit/othervm InvalidCommentLengthTest
|
||||
*/
|
||||
public class InvalidCommentLengthTest {
|
||||
|
||||
// Name used to create a JAR with an invalid comment length
|
||||
public static final Path INVALID_CEN_COMMENT_LENGTH_JAR =
|
||||
Path.of("Invalid-CEN-Comment-Length.jar");
|
||||
// Name used to create a JAR with a valid comment length
|
||||
public static final Path VALID_CEN_COMMENT_LENGTH_JAR =
|
||||
Path.of("Valid-CEN-Comment-Length.jar");
|
||||
// Zip/Jar CEN file header entry that will be modified
|
||||
public static final String META_INF_MANIFEST_MF = "META-INF/MANIFEST.MF";
|
||||
// Expected ZipException message when the comment length corrupts the
|
||||
// Zip/Jar file
|
||||
public static final String INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT =
|
||||
"invalid CEN header (bad entry name or comment)";
|
||||
|
||||
/**
|
||||
* Byte array representing a valid jar file prior modifying the comment length
|
||||
* entry in a CEN file header.
|
||||
* The "Valid-CEN-Comment-Length.jar" jar file was created via:
|
||||
* <pre>
|
||||
* {@code
|
||||
* jar cvf Valid-CEN-Comment-Length.jar Hello.txt Tennis.txt BruceWayne.txt
|
||||
* added manifest
|
||||
* adding: Hello.txt(in = 12) (out= 14)(deflated -16%)
|
||||
* adding: Tennis.txt(in = 53) (out= 53)(deflated 0%)
|
||||
* adding: BruceWayne.txt(in = 12) (out= 14)(deflated -16%)
|
||||
* }
|
||||
* </pre>
|
||||
* Its contents are:
|
||||
* <pre>
|
||||
* {@code
|
||||
* jar tvf Valid-CEN-Comment-Length.jar
|
||||
* 0 Wed Mar 02 06:39:24 EST 2022 META-INF/
|
||||
* 66 Wed Mar 02 06:39:24 EST 2022 META-INF/MANIFEST.MF
|
||||
* 12 Wed Mar 02 06:39:06 EST 2022 Hello.txt
|
||||
* 53 Wed Mar 02 13:04:48 EST 2022 Tennis.txt
|
||||
* 12 Wed Mar 02 15:15:34 EST 2022 BruceWayne.txt
|
||||
* }
|
||||
* </pre>
|
||||
* The ByteArray was created by:
|
||||
* <pre>
|
||||
* {@code
|
||||
* var jar = Files.readAllBytes("Valid-CEN-Comment-Length.jar");
|
||||
* var validEntryName = createByteArray(fooJar,
|
||||
* "VALID_ZIP_WITH_NO_COMMENTS_BYTES");
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public static byte[] VALID_ZIP_WITH_NO_COMMENTS_BYTES = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x4, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d,
|
||||
(byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0xfe,
|
||||
(byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41,
|
||||
(byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46,
|
||||
(byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d,
|
||||
(byte) 0x46, (byte) 0xf3, (byte) 0x4d, (byte) 0xcc, (byte) 0xcb,
|
||||
(byte) 0x4c, (byte) 0x4b, (byte) 0x2d, (byte) 0x2e, (byte) 0xd1,
|
||||
(byte) 0xd, (byte) 0x4b, (byte) 0x2d, (byte) 0x2a, (byte) 0xce,
|
||||
(byte) 0xcc, (byte) 0xcf, (byte) 0xb3, (byte) 0x52, (byte) 0x30,
|
||||
(byte) 0xd4, (byte) 0x33, (byte) 0xe0, (byte) 0xe5, (byte) 0x72,
|
||||
(byte) 0x2e, (byte) 0x4a, (byte) 0x4d, (byte) 0x2c, (byte) 0x49,
|
||||
(byte) 0x4d, (byte) 0xd1, (byte) 0x75, (byte) 0xaa, (byte) 0x4,
|
||||
(byte) 0xa, (byte) 0x98, (byte) 0xe8, (byte) 0x19, (byte) 0xe8,
|
||||
(byte) 0x19, (byte) 0x2a, (byte) 0x68, (byte) 0xf8, (byte) 0x17,
|
||||
(byte) 0x25, (byte) 0x26, (byte) 0xe7, (byte) 0xa4, (byte) 0x2a,
|
||||
(byte) 0x38, (byte) 0xe7, (byte) 0x17, (byte) 0x15, (byte) 0xe4,
|
||||
(byte) 0x17, (byte) 0x25, (byte) 0x96, (byte) 0x0, (byte) 0x15,
|
||||
(byte) 0x6b, (byte) 0xf2, (byte) 0x72, (byte) 0xf1, (byte) 0x72,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xf4, (byte) 0x59, (byte) 0xdc, (byte) 0xa6,
|
||||
(byte) 0x42, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x42,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xe3, (byte) 0x34,
|
||||
(byte) 0x62, (byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74,
|
||||
(byte) 0x78, (byte) 0x74, (byte) 0xf3, (byte) 0x48, (byte) 0xcd,
|
||||
(byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x28, (byte) 0xcf,
|
||||
(byte) 0x2f, (byte) 0xca, (byte) 0x49, (byte) 0xe1, (byte) 0x2,
|
||||
(byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8,
|
||||
(byte) 0xd5, (byte) 0xe0, (byte) 0x39, (byte) 0xb7, (byte) 0xe,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3,
|
||||
(byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x98, (byte) 0x68, (byte) 0x62,
|
||||
(byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x54, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x6e, (byte) 0x69, (byte) 0x73, (byte) 0x2e, (byte) 0x74,
|
||||
(byte) 0x78, (byte) 0x74, (byte) 0x73, (byte) 0xf2, (byte) 0xb,
|
||||
(byte) 0x50, (byte) 0x8, (byte) 0x48, (byte) 0x2c, (byte) 0xca,
|
||||
(byte) 0x4c, (byte) 0x4a, (byte) 0x2c, (byte) 0x56, (byte) 0xf0,
|
||||
(byte) 0x2f, (byte) 0x48, (byte) 0xcd, (byte) 0x53, (byte) 0xc8,
|
||||
(byte) 0x2c, (byte) 0x56, (byte) 0x48, (byte) 0x54, (byte) 0x48,
|
||||
(byte) 0x2b, (byte) 0xcd, (byte) 0x53, (byte) 0x8, (byte) 0x49,
|
||||
(byte) 0xcd, (byte) 0xcb, (byte) 0x3, (byte) 0x72, (byte) 0x42,
|
||||
(byte) 0xf2, (byte) 0x4b, (byte) 0x8b, (byte) 0xf2, (byte) 0x12,
|
||||
(byte) 0x73, (byte) 0x53, (byte) 0xf3, (byte) 0x4a, (byte) 0x14,
|
||||
(byte) 0x4a, (byte) 0xf2, (byte) 0x15, (byte) 0xca, (byte) 0x13,
|
||||
(byte) 0x4b, (byte) 0x92, (byte) 0x33, (byte) 0xb8, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0xaa,
|
||||
(byte) 0xad, (byte) 0x14, (byte) 0xd, (byte) 0x35, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x35, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xf1, (byte) 0x79, (byte) 0x62, (byte) 0x54,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xe, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x42, (byte) 0x72, (byte) 0x75, (byte) 0x63,
|
||||
(byte) 0x65, (byte) 0x57, (byte) 0x61, (byte) 0x79, (byte) 0x6e,
|
||||
(byte) 0x65, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74,
|
||||
(byte) 0xf3, (byte) 0x54, (byte) 0x48, (byte) 0xcc, (byte) 0x55,
|
||||
(byte) 0x70, (byte) 0x4a, (byte) 0x2c, (byte) 0xc9, (byte) 0x4d,
|
||||
(byte) 0xcc, (byte) 0xe3, (byte) 0x2, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x7, (byte) 0x8, (byte) 0x6c, (byte) 0x70,
|
||||
(byte) 0x60, (byte) 0xbd, (byte) 0xe, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62,
|
||||
(byte) 0x54, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0,
|
||||
(byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41,
|
||||
(byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xec, (byte) 0x34, (byte) 0x62, (byte) 0x54,
|
||||
(byte) 0xf4, (byte) 0x59, (byte) 0xdc, (byte) 0xa6, (byte) 0x42,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x42, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x3d, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d,
|
||||
(byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d,
|
||||
(byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45,
|
||||
(byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d, (byte) 0x46,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xe3, (byte) 0x34, (byte) 0x62,
|
||||
(byte) 0x54, (byte) 0xd5, (byte) 0xe0, (byte) 0x39, (byte) 0xb7,
|
||||
(byte) 0xe, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xc1, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c,
|
||||
(byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x98, (byte) 0x68, (byte) 0x62,
|
||||
(byte) 0x54, (byte) 0xaa, (byte) 0xad, (byte) 0x14, (byte) 0xd,
|
||||
(byte) 0x35, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x35,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x54, (byte) 0x65, (byte) 0x6e, (byte) 0x6e,
|
||||
(byte) 0x69, (byte) 0x73, (byte) 0x2e, (byte) 0x74, (byte) 0x78,
|
||||
(byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xf1, (byte) 0x79,
|
||||
(byte) 0x62, (byte) 0x54, (byte) 0x6c, (byte) 0x70, (byte) 0x60,
|
||||
(byte) 0xbd, (byte) 0xe, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xe,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x73, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x42, (byte) 0x72, (byte) 0x75,
|
||||
(byte) 0x63, (byte) 0x65, (byte) 0x57, (byte) 0x61, (byte) 0x79,
|
||||
(byte) 0x6e, (byte) 0x65, (byte) 0x2e, (byte) 0x74, (byte) 0x78,
|
||||
(byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5,
|
||||
(byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x28, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xbd, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Jar files used by the tests.
|
||||
* The {@code byte} array {@code VALID_ZIP_WITH_NO_COMMENTS_BYTES} is written
|
||||
* to disk to create the jar file: {@code Valid-CEN-Comment-Length.jar}.
|
||||
*
|
||||
* The jar file {@code InValid-CEN-Comment-Length.jar} is created by copying
|
||||
* the {@code byte} array {@code VALID_ZIP_WITH_NO_COMMENTS_BYTES} and modifying
|
||||
* the CEN file header comment length entry for "META-INF/MANIFEST.MF" so that
|
||||
* new comment length will forward the CEN to a subsequent CEN file header
|
||||
* entry.
|
||||
*
|
||||
* For {@code InValid-CEN-Comment-Length.jar}, the comment length is changed
|
||||
* from {@code 0x0} to the {@code 0x37}.
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
Files.deleteIfExists(VALID_CEN_COMMENT_LENGTH_JAR);
|
||||
Files.deleteIfExists(INVALID_CEN_COMMENT_LENGTH_JAR);
|
||||
// Create the valid jar
|
||||
Files.write(VALID_CEN_COMMENT_LENGTH_JAR, VALID_ZIP_WITH_NO_COMMENTS_BYTES);
|
||||
// Now create an invalid jar
|
||||
byte[] invalid_bytes = Arrays.copyOf(VALID_ZIP_WITH_NO_COMMENTS_BYTES,
|
||||
VALID_ZIP_WITH_NO_COMMENTS_BYTES.length);
|
||||
// Change CEN file Header comment length so that the length will
|
||||
// result in the offset pointing to a subsequent CEN file header
|
||||
// resulting in an invalid comment
|
||||
invalid_bytes[536] = 55;
|
||||
Files.write(INVALID_CEN_COMMENT_LENGTH_JAR, invalid_bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up after the test run
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@AfterAll
|
||||
public static void cleanup() throws IOException {
|
||||
Files.deleteIfExists(VALID_CEN_COMMENT_LENGTH_JAR);
|
||||
Files.deleteIfExists(INVALID_CEN_COMMENT_LENGTH_JAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the original(valid) Jar file can be opened by {@code ZipFile}
|
||||
* and the expected Zip entry can be found
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void ZipFileValidCommentLengthTest() throws IOException {
|
||||
try (ZipFile jf = new ZipFile(VALID_CEN_COMMENT_LENGTH_JAR.toFile())) {
|
||||
ZipEntry ze = jf.getEntry(META_INF_MANIFEST_MF);
|
||||
assertNotNull(ze);
|
||||
assertEquals(META_INF_MANIFEST_MF, ze.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the original(valid) Jar file can be opened by {@code JarFile}
|
||||
* and the expected Zip entry can be found
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void JarFileValidCommentLengthTest() throws IOException {
|
||||
try (JarFile jf = new JarFile(VALID_CEN_COMMENT_LENGTH_JAR.toFile())) {
|
||||
ZipEntry ze = jf.getEntry(META_INF_MANIFEST_MF);
|
||||
assertNotNull(ze);
|
||||
assertEquals(META_INF_MANIFEST_MF, ze.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ZipException is thrown when the CEN file header comment
|
||||
* length is non-zero and the CEN entry does not contain a comment when
|
||||
* the Jar file is opened by {@code ZipFile}
|
||||
*/
|
||||
@Test
|
||||
public void ZipFileInValidCommentLengthTest() {
|
||||
var ex= assertThrows(ZipException.class,
|
||||
() -> new ZipFile(INVALID_CEN_COMMENT_LENGTH_JAR.toFile()));
|
||||
assertEquals(INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT, ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a ZipException is thrown when the CEN file header comment
|
||||
* length is non-zero and the CEN entry does not contain a comment when
|
||||
* the Jar file is opened by {@code JarFile}
|
||||
*/
|
||||
@Test
|
||||
public void JarFileInValidCommentLengthTest() {
|
||||
var ex= assertThrows(ZipException.class,
|
||||
() -> new JarFile(INVALID_CEN_COMMENT_LENGTH_JAR.toFile()));
|
||||
assertEquals(INVALID_CEN_HEADER_BAD_ENTRY_NAME_OR_COMMENT, ex.getMessage());
|
||||
}
|
||||
}
|
||||
124
test/jdk/java/util/zip/ZipFile/InvalidCompressedSizeTest.java
Normal file
124
test/jdk/java/util/zip/ZipFile/InvalidCompressedSizeTest.java
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HexFormat;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static java.nio.ByteOrder.LITTLE_ENDIAN;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8358456
|
||||
* @summary verify that ZipFile.getInputStream(ZipFile) doesn't throw an unspecified exception
|
||||
* for invalid compressed size of an entry
|
||||
* @run junit InvalidCompressedSizeTest
|
||||
*/
|
||||
class InvalidCompressedSizeTest {
|
||||
|
||||
private static final String ENTRY_NAME = "foo-bar";
|
||||
private static final byte[] ENTRY_CONTENT = new byte[]{0x42, 0x42};
|
||||
|
||||
// created through a call to createZIPContent()
|
||||
private static final String ZIP_CONTENT_HEX = """
|
||||
504b03041400080808005053c35a00000000000000000000000007000000666f6f2d6261727
|
||||
3720200504b0708c41f441b0400000002000000504b010214001400080808005053c35ac41f
|
||||
441b0400000002000000070000000000000000000000000000000000666f6f2d626172504b0
|
||||
506000000000100010035000000390000000000
|
||||
""";
|
||||
|
||||
|
||||
// 0039 CENTRAL HEADER #1 02014B50
|
||||
// ...
|
||||
// 0043 Compression Method 0008 'Deflated'
|
||||
// ...
|
||||
// 004D Compressed Length 00000004
|
||||
// 0051 Uncompressed Length 00000002
|
||||
// ...
|
||||
// 0067 Filename 'foo-bar'
|
||||
// this is the offset in the ZIP content stream for the compressed size field
|
||||
// for the entry of interest
|
||||
private static final int COMP_SIZE_OFFSET = 0x004D;
|
||||
|
||||
// intentionally unused but left here to allow for constructing newer/updated
|
||||
// ZIP_CONTENT_HEX, when necessary
|
||||
private static String createZIPContent() throws IOException {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (final ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
final ZipEntry ze = new ZipEntry(ENTRY_NAME);
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(ENTRY_CONTENT);
|
||||
zos.closeEntry();
|
||||
}
|
||||
return HexFormat.of().formatHex(baos.toByteArray());
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls ZipFile.getInputStream(ZipEntry) on a ZIP entry whose compressed size is
|
||||
* intentionally set to 0. The test then verifies that the call to getInputStream()
|
||||
* doesn't throw an unspecified exception.
|
||||
*/
|
||||
@Test
|
||||
void testInvalidCompressedSize() throws Exception {
|
||||
final byte[] originalZIPContent = HexFormat.of().parseHex(ZIP_CONTENT_HEX.replace("\n", ""));
|
||||
final ByteBuffer zipContent = ByteBuffer.wrap(originalZIPContent).order(LITTLE_ENDIAN);
|
||||
|
||||
// overwrite the compressed size value in the entry's CEN to an invalid value of 0
|
||||
zipContent.position(COMP_SIZE_OFFSET);
|
||||
final int invalidCompressedSize = 0;
|
||||
zipContent.putInt(invalidCompressedSize);
|
||||
zipContent.rewind();
|
||||
|
||||
// write out the ZIP content so that it can be read through ZipFile
|
||||
final Path zip = Files.createTempFile(Path.of("."), "8358456-", ".zip");
|
||||
Files.write(zip, zipContent.array());
|
||||
System.out.println("created ZIP " + zip + " with an invalid compressed size for entry");
|
||||
|
||||
try (final ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
final ZipEntry entry = zf.getEntry(ENTRY_NAME);
|
||||
assertNotNull(entry, "missing entry " + ENTRY_NAME + " in ZIP file " + zip);
|
||||
// verify that we are indeed testing a ZIP file with an invalid
|
||||
// compressed size for the entry
|
||||
assertEquals(0, entry.getCompressedSize(), "unexpected compressed size");
|
||||
// merely open and close the InputStream to exercise the code which
|
||||
// would incorrectly raise an exception. we don't read the contents
|
||||
// of the stream because we have (intentionally) corrupted the metadata
|
||||
// of the ZIP and that will cause the reading to fail.
|
||||
try (final InputStream is = zf.getInputStream(entry)) {
|
||||
System.out.println("successfully opened input stream " + is
|
||||
+ " for entry " + entry.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
159
test/jdk/java/util/zip/ZipFile/LargeZipFile.java
Normal file
159
test/jdk/java/util/zip/ZipFile/LargeZipFile.java
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class LargeZipFile {
|
||||
// If true, don't delete large ZIP file created for test.
|
||||
static final boolean debug = System.getProperty("debug") != null;
|
||||
|
||||
static final int DATA_LEN = 1024 * 1024;
|
||||
static final int DATA_SIZE = 8;
|
||||
|
||||
static long fileSize = 3L * 1024L * 1024L * 1024L; // 3GB
|
||||
|
||||
static boolean userFile = false;
|
||||
|
||||
static byte[] data;
|
||||
static File largeFile;
|
||||
static String lastEntryName;
|
||||
|
||||
/* args can be empty, in which case check a 3 GB file which is created for
|
||||
* this test (and then deleted). Or it can be a number, in which case
|
||||
* that designates the size of the file that's created for this test (and
|
||||
* then deleted). Or it can be the name of a file to use for the test, in
|
||||
* which case it is *not* deleted. Note that in this last case, the data
|
||||
* comparison might fail.
|
||||
*/
|
||||
static void realMain (String[] args) throws Throwable {
|
||||
if (args.length > 0) {
|
||||
try {
|
||||
fileSize = Long.parseLong(args[0]);
|
||||
System.out.println("Testing with file of size " + fileSize);
|
||||
} catch (NumberFormatException ex) {
|
||||
largeFile = new File(args[0]);
|
||||
if (!largeFile.exists()) {
|
||||
throw new Exception("Specified file " + args[0] + " does not exist");
|
||||
}
|
||||
userFile = true;
|
||||
System.out.println("Testing with user-provided file " + largeFile);
|
||||
}
|
||||
}
|
||||
File testDir = null;
|
||||
if (largeFile == null) {
|
||||
testDir = new File(System.getProperty("test.scratch", "."),
|
||||
"LargeZip");
|
||||
if (testDir.exists()) {
|
||||
if (!testDir.delete()) {
|
||||
throw new Exception("Cannot delete already-existing test directory");
|
||||
}
|
||||
}
|
||||
check(!testDir.exists() && testDir.mkdirs());
|
||||
largeFile = new File(testDir, "largezip.zip");
|
||||
createLargeZip();
|
||||
}
|
||||
|
||||
readLargeZip();
|
||||
|
||||
if (!userFile && !debug) {
|
||||
check(largeFile.delete());
|
||||
check(testDir.delete());
|
||||
}
|
||||
}
|
||||
|
||||
static void createLargeZip() throws Throwable {
|
||||
int iterations = DATA_LEN / DATA_SIZE;
|
||||
ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
bb.putDouble(0, Math.random());
|
||||
baos.write(bb.array(), 0, DATA_SIZE);
|
||||
}
|
||||
data = baos.toByteArray();
|
||||
try (FileOutputStream fos = new FileOutputStream(largeFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos))
|
||||
{
|
||||
long length = 0;
|
||||
while (length < fileSize) {
|
||||
ZipEntry ze = new ZipEntry("entry-" + length);
|
||||
lastEntryName = ze.getName();
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(data, 0, data.length);
|
||||
zos.closeEntry();
|
||||
length = largeFile.length();
|
||||
}
|
||||
System.out.println("Last entry written is " + lastEntryName);
|
||||
}
|
||||
}
|
||||
|
||||
static void readLargeZip() throws Throwable {
|
||||
try (ZipFile zipFile = new ZipFile(largeFile)) {
|
||||
ZipEntry entry = null;
|
||||
String entryName = null;
|
||||
int count = 0;
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
entry = entries.nextElement();
|
||||
entryName = entry.getName();
|
||||
count++;
|
||||
}
|
||||
System.out.println("Number of entries read: " + count);
|
||||
System.out.println("Last entry read is " + entryName);
|
||||
check(!entry.isDirectory());
|
||||
if (check(entryName.equals(lastEntryName))) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = zipFile.getInputStream(entry);
|
||||
byte buf[] = new byte[4096];
|
||||
int len;
|
||||
while ((len = is.read(buf)) >= 0) {
|
||||
baos.write(buf, 0, len);
|
||||
}
|
||||
baos.close();
|
||||
is.close();
|
||||
check(Arrays.equals(data, baos.toByteArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {passed++;}
|
||||
static void pass(String msg) {System.out.println(msg); passed++;}
|
||||
static void fail() {failed++; Thread.dumpStack();}
|
||||
static void fail(String msg) {System.out.println(msg); fail();}
|
||||
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
static void unexpected(Throwable t, String msg) {
|
||||
System.out.println(msg); failed++; t.printStackTrace();}
|
||||
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
||||
System.out.println("\nPassed = " + passed + " failed = " + failed);
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
||||
108
test/jdk/java/util/zip/ZipFile/ManyEntries.java
Normal file
108
test/jdk/java/util/zip/ZipFile/ManyEntries.java
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 4770745 4828461
|
||||
* @summary open zip files with more than 64k entries
|
||||
* @run main/timeout=600 ManyEntries
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.io.*;
|
||||
|
||||
public class ManyEntries {
|
||||
public static void main(String[] args) throws Exception {
|
||||
boolean runMoreTests = args.length > 0;
|
||||
int[] sizes = (runMoreTests ?
|
||||
new int[]{1, 2, 42, 65534, 65535, 65536, 65537, 68000} :
|
||||
new int[]{1, 2, 42, 68000});
|
||||
int[] methods = {ZipEntry.STORED, ZipEntry.DEFLATED};
|
||||
|
||||
for (int size : sizes)
|
||||
for (int method : methods)
|
||||
test(size, method);
|
||||
}
|
||||
|
||||
// JDK doesn't like having zip file contents changed at runtime
|
||||
static int uniquifier = 42;
|
||||
|
||||
static void test(int N, int method) throws Exception {
|
||||
System.out.println("N="+N+", method="+method);
|
||||
long time = System.currentTimeMillis() / 2000 * 2000;
|
||||
CRC32 crc32 = new CRC32();
|
||||
File zipFile = new File(++uniquifier + ".zip");
|
||||
try {
|
||||
zipFile.delete();
|
||||
try (FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos))
|
||||
{
|
||||
for (int i = 0; i < N; i++) {
|
||||
ZipEntry e = new ZipEntry("DIR/"+i);
|
||||
e.setMethod(method);
|
||||
e.setTime(time);
|
||||
if (method == ZipEntry.STORED) {
|
||||
e.setSize(1);
|
||||
crc32.reset();
|
||||
crc32.update((byte)i);
|
||||
e.setCrc(crc32.getValue());
|
||||
} else {
|
||||
e.setSize(0);
|
||||
e.setCrc(0);
|
||||
}
|
||||
zos.putNextEntry(e);
|
||||
zos.write(i);
|
||||
}
|
||||
}
|
||||
|
||||
try (ZipFile zip = new ZipFile(zipFile)) {
|
||||
if (! (zip.size() == N))
|
||||
throw new Exception("Bad ZipFile size: " + zip.size());
|
||||
Enumeration entries = zip.entries();
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (i % 1000 == 0) {System.gc(); System.runFinalization();}
|
||||
if (! (entries.hasMoreElements()))
|
||||
throw new Exception("only " + i + " elements");
|
||||
ZipEntry e = (ZipEntry)entries.nextElement();
|
||||
if (! (e.getSize() == 1))
|
||||
throw new Exception("bad size: " + e.getSize());
|
||||
if (! (e.getName().equals("DIR/" + i)))
|
||||
throw new Exception("bad name: " + i);
|
||||
if (! (e.getMethod() == method))
|
||||
throw new Exception("getMethod="+e.getMethod()+", method=" + method);
|
||||
if (! (e.getTime() == time))
|
||||
throw new Exception("getTime="+e.getTime()+", time=" + time);
|
||||
if (! (zip.getInputStream(e).read() == (i & 0xff)))
|
||||
throw new Exception("Bad file contents: " + i);
|
||||
}
|
||||
if (entries.hasMoreElements())
|
||||
throw new Exception("too many elements");
|
||||
}
|
||||
} finally {
|
||||
zipFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
139
test/jdk/java/util/zip/ZipFile/ManyZipFiles.java
Normal file
139
test/jdk/java/util/zip/ZipFile/ManyZipFiles.java
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 6423026
|
||||
* @summary Check that it is possible to open more than 2,048 zip files on
|
||||
* Windows.
|
||||
*/
|
||||
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class ManyZipFiles {
|
||||
static final int numFiles = 3000;
|
||||
|
||||
public static void realMain(String[] args) throws Throwable {
|
||||
// Linux does not yet allow opening this many files; Solaris
|
||||
// 8 requires an explicit allocation of more file descriptors
|
||||
// to succeed. Since this test is written to check for a
|
||||
// Windows capability it is much simpler to only run it
|
||||
// on that platform.
|
||||
String osName = System.getProperty("os.name");
|
||||
if (!(osName.startsWith("Windows"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create some zip data
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
ZipEntry ze = new ZipEntry("test");
|
||||
zos.putNextEntry(ze);
|
||||
byte[] hello = "hello, world".getBytes("ASCII");
|
||||
zos.write(hello, 0, hello.length);
|
||||
zos.closeEntry();
|
||||
zos.finish();
|
||||
}
|
||||
byte[] data = baos.toByteArray();
|
||||
|
||||
ZipFile zips[] = new ZipFile[numFiles];
|
||||
|
||||
try {
|
||||
// Create a directory for zip files created below
|
||||
File tmpdir = new File(
|
||||
System.getProperty("java.io.tmpdir")
|
||||
+ File.separator + "ManyZipFiles");
|
||||
if (tmpdir.exists() && !tmpdir.isDirectory()) {
|
||||
fail(tmpdir.getAbsolutePath()
|
||||
+ " already exists but is not a directory");
|
||||
return;
|
||||
}
|
||||
if (!tmpdir.exists()) {
|
||||
if (!tmpdir.mkdirs()) {
|
||||
fail("Couldn't create directory "
|
||||
+ tmpdir.getAbsolutePath() + " for test files");
|
||||
return;
|
||||
}
|
||||
} else if (!tmpdir.canWrite()) {
|
||||
fail("Don't have write access for directory "
|
||||
+ tmpdir.getAbsolutePath() + " for test files");
|
||||
return;
|
||||
}
|
||||
tmpdir.deleteOnExit();
|
||||
|
||||
// Create and then open a large number of zip files
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
File f = File.createTempFile("test", ".zip", tmpdir);
|
||||
f.deleteOnExit();
|
||||
try (FileOutputStream fos = new FileOutputStream(f)) {
|
||||
fos.write(data, 0, data.length);
|
||||
}
|
||||
try {
|
||||
zips[i] = new ZipFile(f);
|
||||
} catch (Throwable t) {
|
||||
fail("Failed to open zip file #" + i + " named "
|
||||
+ zips[i].getName());
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// This finally block is due to bug 4171239. On Windows, if the
|
||||
// file is still open at the end of the VM, deleteOnExit won't
|
||||
// take place. "new ZipFile(...)" opens the zip file, so we have
|
||||
// to explicitly close those opened above. This finally block can
|
||||
// be removed when 4171239 is fixed. See also 6357433, against which
|
||||
// 4171239 was closed as a duplicate.
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
if (zips[i] != null) {
|
||||
try {
|
||||
zips[i].close();
|
||||
} catch (Throwable t) {
|
||||
fail("At zip[" + i + "] named " + zips[i].getName()
|
||||
+ " caught " + t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pass();
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {passed++;}
|
||||
static void fail() {failed++; Thread.dumpStack();}
|
||||
static void fail(String msg) {System.out.println(msg); fail();}
|
||||
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
static void check(boolean cond) {if (cond) pass(); else fail();}
|
||||
static void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
||||
System.out.println("\nPassed = " + passed + " failed = " + failed);
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
||||
816
test/jdk/java/util/zip/ZipFile/MissingZIP64EntriesTest.java
Normal file
816
test/jdk/java/util/zip/ZipFile/MissingZIP64EntriesTest.java
Normal file
|
|
@ -0,0 +1,816 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/* @test
|
||||
* @bug 8314891
|
||||
* @summary Validate that a ZipException is thrown when the extra len is 0
|
||||
* and the CEN size, csize,LOC offset fields are set to 0xFFFFFFFF, the disk
|
||||
* starting number is set to 0xFFFF or when we have a valid Zip64 Extra header
|
||||
* size but missing the expected header fields.
|
||||
* @run junit MissingZIP64EntriesTest
|
||||
*/
|
||||
public class MissingZIP64EntriesTest {
|
||||
|
||||
/*
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with only the size field.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x57116922 [Thu Aug 17 13:09:04 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0x16
|
||||
* 0x65: Uncompressed Size: 0xffffffff
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0xc
|
||||
* Extra data:[01, 00, 08, 00, 14, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=8]
|
||||
* ->ZIP64: size *0x14
|
||||
* [data= 14 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0x0
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZIP64_EXTRAHDR_SIZE_ONLY_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x22, (byte) 0x69, (byte) 0x11, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x22, (byte) 0x69, (byte) 0x11, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a Zip file with no extra header fields
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x2f: Signature : 0x02014b50
|
||||
* 0x33: Created Zip Spec : 0x14 [2.0]
|
||||
* 0x34: Created OS : 0x3 [UNIX]
|
||||
* 0x35: VerMadeby : 0x314 [3, 2.0]
|
||||
* 0x36: VerExtract : 0x14 [2.0]
|
||||
* 0x37: Flag : 0x2
|
||||
* 0x39: Method : 0x8 [DEFLATED]
|
||||
* 0x3b: Last Mod Time : 0x57039c0d [Thu Aug 03 19:32:26 EDT 2023]
|
||||
* 0x3f: CRC : 0x31963516
|
||||
* 0x43: Compressed Size : 0x8
|
||||
* 0x47: Uncompressed Size: 0x6
|
||||
* 0x4b: Name Length : 0x9
|
||||
* 0x4d: Extra Length : 0x0
|
||||
* 0x4f: Comment Length : 0x0
|
||||
* 0x51: Disk Start : 0x0
|
||||
* 0x53: Attrs : 0x1
|
||||
* 0x55: AttrsEx : 0x81a40000
|
||||
* 0x59: Loc Header Offset: 0x0
|
||||
* 0x5d: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x2, (byte) 0x0,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xd, (byte) 0x9c, (byte) 0x3, (byte) 0x57, (byte) 0x16, (byte) 0x35,
|
||||
(byte) 0x96, (byte) 0x31, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0xe7, (byte) 0x2, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x3, (byte) 0x14, (byte) 0x0, (byte) 0x2,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0xd, (byte) 0x9c, (byte) 0x3, (byte) 0x57, (byte) 0x16,
|
||||
(byte) 0x35, (byte) 0x96, (byte) 0x31, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa4,
|
||||
(byte) 0x81, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c,
|
||||
(byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x37, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2f, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with only the LOC offset field.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x572d69c5 [Wed Sep 13 13:14:10 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0x16
|
||||
* 0x65: Uncompressed Size: 0x14
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0xc
|
||||
* Extra data:[01, 00, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=8]
|
||||
* ->ZIP64: LOC Off *0x0
|
||||
* [data= 00 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0xffffffff
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZIP64_EXTRAHDR_LOC_ONLY_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xc5, (byte) 0x69, (byte) 0x2d, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xc5, (byte) 0x69, (byte) 0x2d, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with only the compressed size field.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x572d6960 [Wed Sep 13 13:11:00 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0xffffffff
|
||||
* 0x65: Uncompressed Size: 0x14
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0xc
|
||||
* Extra data:[01, 00, 08, 00, 16, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=8]
|
||||
* ->ZIP64: csize *0x16
|
||||
* [data= 16 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0x0
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZIP64_EXTRAHDR_CSIZE_ONLY_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x69, (byte) 0x2d, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x60, (byte) 0x69, (byte) 0x2d, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x14, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0xc, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x8, (byte) 0x0,
|
||||
(byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a Zip file with a zero length ZIP64 Extra Header
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x43: Signature : 0x02014b50
|
||||
* 0x47: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x48: Created OS : 0x3 [UNIX]
|
||||
* 0x49: VerMadeby : 0x32d [3, 4.5]
|
||||
* 0x4a: VerExtract : 0x2d [4.5]
|
||||
* 0x4b: Flag : 0x800
|
||||
* 0x4d: Method : 0x8 [DEFLATED]
|
||||
* 0x4f: Last Mod Time : 0x572c3477 [Tue Sep 12 06:35:46 EDT 2023]
|
||||
* 0x53: CRC : 0x31963516
|
||||
* 0x57: Compressed Size : 0x8
|
||||
* 0x5b: Uncompressed Size: 0x6
|
||||
* 0x5f: Name Length : 0x9
|
||||
* 0x61: Extra Length : 0x4
|
||||
* Extra data:[01, 00, 00, 00]
|
||||
* [tag=0x0001, sz=0]
|
||||
* ->ZIP64:
|
||||
* 0x63: Comment Length : 0x0
|
||||
* 0x65: Disk Start : 0x0
|
||||
* 0x67: Attrs : 0x0
|
||||
* 0x69: AttrsEx : 0x81a40000
|
||||
* 0x6d: Loc Header Offset: 0x0
|
||||
* 0x71: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZEROLEN_ZIP64_EXTRAHDR_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x77, (byte) 0x34, (byte) 0x2c, (byte) 0x57, (byte) 0x16, (byte) 0x35,
|
||||
(byte) 0x96, (byte) 0x31, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xf3, (byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9,
|
||||
(byte) 0xe7, (byte) 0x2, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d,
|
||||
(byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x77,
|
||||
(byte) 0x34, (byte) 0x2c, (byte) 0x57, (byte) 0x16, (byte) 0x35, (byte) 0x96, (byte) 0x31, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9,
|
||||
(byte) 0x0, (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa4, (byte) 0x81, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74,
|
||||
(byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x6, (byte) 0x6, (byte) 0x2c, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3b, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x43, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x6, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x7e, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x3b, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x43, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with the size and csize fields.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x572c6445 [Tue Sep 12 12:34:10 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0xffffffff
|
||||
* 0x65: Uncompressed Size: 0xffffffff
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0x14
|
||||
* Extra data:[01, 00, 10, 00, 14, 00, 00, 00, 00, 00, 00, 00, 16, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=16]
|
||||
* ->ZIP64: size *0x14 csize *0x16
|
||||
* [data= 14 00 00 00 00 00 00 00 16 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0x0
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_TWO_ZIP64_HEADER_ENTRIES_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x45, (byte) 0x64, (byte) 0x2c, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x45, (byte) 0x64, (byte) 0x2c, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x4b, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Byte array representing a ZIP file which contains a
|
||||
* Zip64 Extra Header with the size,csize, and LOC offset fields.
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x4d: Signature : 0x02014b50
|
||||
* 0x51: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x52: Created OS : 0x0 [MS-DOS]
|
||||
* 0x53: VerMadeby : 0x2d [0, 4.5]
|
||||
* 0x54: VerExtract : 0x2d [4.5]
|
||||
* 0x55: Flag : 0x808
|
||||
* 0x57: Method : 0x8 [DEFLATED]
|
||||
* 0x59: Last Mod Time : 0x572d7214 [Wed Sep 13 14:16:40 EDT 2023]
|
||||
* 0x5d: CRC : 0x57de98d2
|
||||
* 0x61: Compressed Size : 0xffffffff
|
||||
* 0x65: Uncompressed Size: 0xffffffff
|
||||
* 0x69: Name Length : 0x9
|
||||
* 0x6b: Extra Length : 0x1c
|
||||
* Extra data:[01, 00, 18, 00, 14, 00, 00, 00, 00, 00, 00, 00, 16, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00]
|
||||
* [tag=0x0001, sz=24]
|
||||
* ->ZIP64: size *0x14 csize *0x16 LOC Off *0x0
|
||||
* [data= 14 00 00 00 00 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
|
||||
* 0x6d: Comment Length : 0x0
|
||||
* 0x6f: Disk Start : 0x0
|
||||
* 0x71: Attrs : 0x0
|
||||
* 0x73: AttrsEx : 0x0
|
||||
* 0x77: Loc Header Offset: 0xffffffff
|
||||
* 0x7b: File Name : Hello.txt
|
||||
*/
|
||||
public static byte[] ZIP_WITH_ZIP64_EXTRAHDR_ALL_BYTEARRAY = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x14, (byte) 0x72, (byte) 0x2d, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x9, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x48, (byte) 0x65,
|
||||
(byte) 0x6c, (byte) 0x6c, (byte) 0x6f, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0xf3,
|
||||
(byte) 0x48, (byte) 0xcd, (byte) 0xc9, (byte) 0xc9, (byte) 0x57, (byte) 0x8, (byte) 0x49, (byte) 0xcd,
|
||||
(byte) 0xcb, (byte) 0xcb, (byte) 0x2c, (byte) 0x56, (byte) 0x8, (byte) 0xc8, (byte) 0x49, (byte) 0xac,
|
||||
(byte) 0x4c, (byte) 0x2d, (byte) 0x2a, (byte) 0x6, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x7,
|
||||
(byte) 0x8, (byte) 0xd2, (byte) 0x98, (byte) 0xde, (byte) 0x57, (byte) 0x16, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x14, (byte) 0x72, (byte) 0x2d, (byte) 0x57, (byte) 0xd2, (byte) 0x98, (byte) 0xde,
|
||||
(byte) 0x57, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x1c, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x48, (byte) 0x65, (byte) 0x6c, (byte) 0x6c, (byte) 0x6f,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x18, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x16, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x53, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable debug output
|
||||
*/
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Name of the Zip file that we create from the byte array
|
||||
*/
|
||||
public static final String ZIPFILE_NAME = "validZipFile.zip";
|
||||
|
||||
/**
|
||||
* Name of the Zip file that we modify/corrupt
|
||||
*/
|
||||
public static final String BAD_ZIP_NAME = "zipWithInvalidZip64ExtraField.zip";
|
||||
|
||||
/**
|
||||
* Zip file entry that will be accessed by some the tests
|
||||
*/
|
||||
private static final String ZIP_FILE_ENTRY_NAME = "Hello.txt";
|
||||
|
||||
/**
|
||||
* Expected Error messages
|
||||
*/
|
||||
private static final String INVALID_EXTRA_LENGTH =
|
||||
"Invalid CEN header (invalid zip64 extra len size)";
|
||||
|
||||
private static final String INVALID_ZIP64_EXTRAHDR_SIZE =
|
||||
"Invalid CEN header (invalid zip64 extra data field size)";
|
||||
|
||||
/**
|
||||
* Disk starting number offset for the Zip file created from the
|
||||
* ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY array
|
||||
*/
|
||||
private static final int DISKNO_OFFSET_ZIP_NO_EXTRA_LEN = 0x51;
|
||||
|
||||
/**
|
||||
* Value to set the size, csize, or LOC offset CEN fields to when their
|
||||
* actual value is stored in the Zip64 Extra Header
|
||||
*/
|
||||
private static final long ZIP64_MAGICVAL = 0xFFFFFFFFL;
|
||||
|
||||
/**
|
||||
* Value to set the Disk Start number offset CEN field to when the
|
||||
* actual value is stored in the Zip64 Extra Header
|
||||
*/
|
||||
private static final int ZIP64_MAGICCOUNT = 0xFFFF;
|
||||
|
||||
/**
|
||||
* Copy of the byte array for the ZIP to be modified by a given test run
|
||||
*/
|
||||
private byte[] zipArrayCopy;
|
||||
|
||||
/**
|
||||
* Little-endian ByteBuffer for manipulating the ZIP copy
|
||||
*/
|
||||
private ByteBuffer buffer;
|
||||
|
||||
/**
|
||||
* The MethodSource returning a byte array representing the Zip file,
|
||||
* CEN offsets to set to 0xFFFFFFFF and the expected
|
||||
* ZipException error message when there are missing Zip64 Extra header fields
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> InvalidZip64MagicValues() {
|
||||
return Stream.of(
|
||||
// Byte array representing the Zip file, compressed size offset,
|
||||
// and expected ZipException Message
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_SIZE_ONLY_BYTEARRAY,
|
||||
0x61, INVALID_ZIP64_EXTRAHDR_SIZE),
|
||||
// Byte array representing the Zip file, LOC offset and expected ZipException Message
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_SIZE_ONLY_BYTEARRAY,
|
||||
0x77, INVALID_ZIP64_EXTRAHDR_SIZE),
|
||||
// Byte array representing the Zip file, LOC offset and expected ZipException Message
|
||||
Arguments.of(ZIP_WITH_TWO_ZIP64_HEADER_ENTRIES_BYTEARRAY,
|
||||
0x77, INVALID_ZIP64_EXTRAHDR_SIZE)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The MethodSource of CEN offsets to set to 0xFFFFFFFF or 0xFFFF when the Extra Length
|
||||
* size is 0 for the Zip file created using ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> MissingZip64ExtraFieldEntries() {
|
||||
return Stream.of(
|
||||
// Compressed size offset
|
||||
Arguments.of(0x43),
|
||||
// Size offset
|
||||
Arguments.of(0x47),
|
||||
// Disk start number offset
|
||||
Arguments.of(DISKNO_OFFSET_ZIP_NO_EXTRA_LEN),
|
||||
// LOC offset
|
||||
Arguments.of(0x59)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The MethodSource of CEN offsets to set to 0xFFFFFFFF when the ZIP64 extra header
|
||||
* Length size is 0 for the Zip file created using
|
||||
* ZIP_WITH_ZEROLEN_ZIP64_EXTRAHDR_BYTEARRAY
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> zip64ZeroLenHeaderExtraFieldEntries() {
|
||||
return Stream.of(
|
||||
// Compressed size offset
|
||||
Arguments.of(0x57),
|
||||
// Size offset
|
||||
Arguments.of(0x5b),
|
||||
// LOC offset
|
||||
Arguments.of(0x6d)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The MethodSource which will return a byte array representing a
|
||||
* valid Zip file and the expected content for the Zip file entry 'Hello.txt'.
|
||||
* @return Arguments used in each test run
|
||||
*/
|
||||
private static Stream<Arguments> validZipFiles() {
|
||||
return Stream.of(
|
||||
// Byte array representing the Zip file, and the expected entry content
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_SIZE_ONLY_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_TWO_ZIP64_HEADER_ENTRIES_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_LOC_ONLY_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_CSIZE_ONLY_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_ZIP64_EXTRAHDR_ALL_BYTEARRAY,
|
||||
"Hello Tennis Players"),
|
||||
Arguments.of(ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY,
|
||||
"Hello\n")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial test setup
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
Files.deleteIfExists(Path.of(ZIPFILE_NAME));
|
||||
Files.deleteIfExists(Path.of(BAD_ZIP_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the Zip file that will be modified by each test
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void beforeEachTestRun() throws IOException {
|
||||
Files.deleteIfExists(Path.of(ZIPFILE_NAME));
|
||||
Files.deleteIfExists(Path.of(BAD_ZIP_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a ZipException is thrown by ZipFile if the Zip64 header
|
||||
* does not contain the required field
|
||||
* @param zipArray Byte array representing the Zip file
|
||||
* @param offset Offset of the CEN Header field to set to 0xFFFFFFFF
|
||||
* @param errorMessage Expected ZipException error message
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("InvalidZip64MagicValues")
|
||||
public void invalidZip64ExtraHeaderZipFileTest(byte[] zipArray, int offset,
|
||||
String errorMessage) throws IOException {
|
||||
// Set the CEN csize or LOC offset field to 0xFFFFFFFF. There will not
|
||||
// be the expected Zip64 Extra Header field resulting in a ZipException
|
||||
// being thrown
|
||||
zipArrayCopy = zipArray.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFile(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(errorMessage),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a ZipException is thrown by Zip FS if the Zip64 header
|
||||
* does not contain the required field
|
||||
* @param zipArray Byte array representing the Zip file
|
||||
* @param offset Offset of the CEN Header field to set to 0xFFFFFFFF
|
||||
* @param errorMessage Expected ZipException error message
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("InvalidZip64MagicValues")
|
||||
public void invalidZip64ExtraHeaderZipFSTest(byte[] zipArray, int offset,
|
||||
String errorMessage) throws IOException {
|
||||
// Set the CEN csize or LOC offset field to 0xFFFFFFFF. There will not
|
||||
// be the expected Zip64 Extra Header field resulting in a ZipException
|
||||
// being thrown
|
||||
zipArrayCopy = zipArray.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(offset, (int)ZIP64_MAGICVAL);
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFS(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(errorMessage),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile will throw a ZipException if the CEN
|
||||
* Extra length is 0 and the CEN size, csize, LOC offset field is set to
|
||||
* 0xFFFFFFFF or the disk starting number is set to 0xFFFF
|
||||
* @param offset Offset of the CEN Header field to set to 0xFFFFFFFF or 0xFFFF
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("MissingZip64ExtraFieldEntries")
|
||||
public void zipFileBadExtraLength(int offset) throws IOException {
|
||||
zipArrayCopy = ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
if (offset == DISKNO_OFFSET_ZIP_NO_EXTRA_LEN) {
|
||||
buffer.putShort(offset, (short) ZIP64_MAGICCOUNT);
|
||||
} else {
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
}
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFile(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(INVALID_EXTRA_LENGTH),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFS will throw a ZipException if the CEN
|
||||
* Extra length is 0 and the CEN size, csize, LOC offset field is set to
|
||||
* 0xFFFFFFFF or the disk starting number is set to 0xFFFF
|
||||
* @param offset the offset of the CEN Header field to set to 0xFFFFFFFF or 0xFFFF
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("MissingZip64ExtraFieldEntries")
|
||||
public void zipFSBadExtraLength(int offset) throws IOException {
|
||||
zipArrayCopy = ZIP_WITH_NO_EXTRA_LEN_BYTEARRAY.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
if (offset == DISKNO_OFFSET_ZIP_NO_EXTRA_LEN) {
|
||||
buffer.putShort(offset, (short) ZIP64_MAGICCOUNT);
|
||||
} else {
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
}
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFS(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(INVALID_EXTRA_LENGTH),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile will throw a ZipException if the ZIP64 extra header
|
||||
* has a size of 0 and the CEN size, csize, or the LOC offset field is set to
|
||||
* 0xFFFFFFFF
|
||||
* @param offset the offset of the CEN Header field to set to 0xFFFFFFFF
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("zip64ZeroLenHeaderExtraFieldEntries")
|
||||
public void zipFileZeroLenExtraHeader(int offset) throws IOException {
|
||||
zipArrayCopy = ZIP_WITH_ZEROLEN_ZIP64_EXTRAHDR_BYTEARRAY.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFile(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(INVALID_ZIP64_EXTRAHDR_SIZE),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFS will throw a ZipException if the ZIP64 extra header
|
||||
* has a size of 0 and the CEN size, csize, or the LOC offset field is set to
|
||||
* 0xFFFFFFFF
|
||||
* @param offset the offset of the CEN Header field to set to 0xFFFFFFFF
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("zip64ZeroLenHeaderExtraFieldEntries")
|
||||
public void zipFSZeroLenExtraHeader(int offset) throws IOException {
|
||||
zipArrayCopy = ZIP_WITH_ZEROLEN_ZIP64_EXTRAHDR_BYTEARRAY.clone();
|
||||
buffer = ByteBuffer.wrap(zipArrayCopy).order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(offset, (int) ZIP64_MAGICVAL);
|
||||
Files.write(Path.of(BAD_ZIP_NAME), zipArrayCopy);
|
||||
ZipException ex = assertThrows(ZipException.class, () -> {
|
||||
openWithZipFS(BAD_ZIP_NAME, ZIP_FILE_ENTRY_NAME, null);
|
||||
});
|
||||
assertTrue(ex.getMessage().equals(INVALID_ZIP64_EXTRAHDR_SIZE),
|
||||
"Unexpected ZipException message: " + ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile will read the Zip files created from the
|
||||
* byte arrays prior to modifying the arrays to check that the
|
||||
* expected ZipException is thrown.
|
||||
* @param zipFile the byte array which represents the Zip file that should
|
||||
* be opened and read successfully.
|
||||
* @param message the expected text contained within the Zip entry
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("validZipFiles")
|
||||
public void readValidZipFile(byte[] zipFile, String message) throws IOException {
|
||||
// Write out the Zip file from the byte array
|
||||
Files.write(Path.of(ZIPFILE_NAME), zipFile);
|
||||
openWithZipFile(ZIPFILE_NAME, ZIP_FILE_ENTRY_NAME, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFS will read the Zip files created from the
|
||||
* byte arrays prior to modifying the arrays to check that the
|
||||
* expected ZipException is thrown.
|
||||
* @param zipFile the byte array which represents the Zip file that should
|
||||
* be opened and read successfully.
|
||||
* @param message the expected text contained within the Zip entry
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("validZipFiles")
|
||||
public void readValidZipFileWithZipFs(byte[] zipFile, String message)
|
||||
throws IOException {
|
||||
// Write out the Zip file from the byte array
|
||||
Files.write(Path.of(ZIPFILE_NAME), zipFile);
|
||||
openWithZipFS(ZIPFILE_NAME, ZIP_FILE_ENTRY_NAME, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used to open a Zip file using ZipFile by the tests.
|
||||
* @param zipFile name of the Zip file to open
|
||||
* @param entryName Zip entry to read when the Zip file is expected to be
|
||||
* able to be opened
|
||||
* @param entryContents the expected contents for the Zip entry
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private static void openWithZipFile(String zipFile, String entryName,
|
||||
String entryContents) throws IOException {
|
||||
try (ZipFile zf = new ZipFile(zipFile)) {
|
||||
ZipEntry ze = zf.getEntry(entryName);
|
||||
try (InputStream is = zf.getInputStream(ze)) {
|
||||
String result = new String(is.readAllBytes());
|
||||
if (DEBUG) {
|
||||
var hx = HexFormat.ofDelimiter(", ").withPrefix("0x");
|
||||
System.out.printf("Error: Zip File read :%s%n[%s]%n", result,
|
||||
hx.formatHex(result.getBytes()));
|
||||
}
|
||||
// entryContents will be null when an exception is expected
|
||||
if (entryContents != null) {
|
||||
assertEquals(entryContents, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used to open a Zip file using ZipFS by the tests.
|
||||
* @param zipFile name of the Zip file to open
|
||||
* @param entryName Zip entry to read when the Zip file is expected to be
|
||||
* able to be opened
|
||||
* @param entryContents the expected contents for the Zip entry
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private static void openWithZipFS(String zipFile, String entryName,
|
||||
String entryContents) throws IOException {
|
||||
try (FileSystem fs = FileSystems.newFileSystem(
|
||||
Path.of(zipFile), Map.of())) {
|
||||
Path p = fs.getPath(entryName);
|
||||
String result = new String(Files.readAllBytes(p));
|
||||
if (DEBUG) {
|
||||
var hx = HexFormat.ofDelimiter(", ").withPrefix("0x");
|
||||
System.out.printf("Error: Zip FS read :%s%n[%s]%n", result,
|
||||
hx.formatHex(result.getBytes()));
|
||||
}
|
||||
// entryContents will be null when an exception is expected
|
||||
if (entryContents != null) {
|
||||
assertEquals(entryContents, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
103
test/jdk/java/util/zip/ZipFile/MultiThreadedReadTest.java
Normal file
103
test/jdk/java/util/zip/ZipFile/MultiThreadedReadTest.java
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8038491
|
||||
* @summary Crash in ZipFile.read() when ZipFileInputStream is shared between threads
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Platform
|
||||
* jdk.test.lib.util.FileUtils
|
||||
* @run main MultiThreadedReadTest
|
||||
*/
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import jdk.test.lib.util.FileUtils;
|
||||
|
||||
public class MultiThreadedReadTest extends Thread {
|
||||
|
||||
private static final int NUM_THREADS = 10;
|
||||
private static final String ZIPFILE_NAME =
|
||||
System.currentTimeMillis() + "-bug8038491-tmp.large.zip";
|
||||
private static final String ZIPENTRY_NAME = "random.txt";
|
||||
private static InputStream is = null;
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
createZipFile();
|
||||
try (ZipFile zf = new ZipFile(new File(ZIPFILE_NAME))) {
|
||||
is = zf.getInputStream(zf.getEntry(ZIPENTRY_NAME));
|
||||
Thread[] threadArray = new Thread[NUM_THREADS];
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i] = new MultiThreadedReadTest();
|
||||
}
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i].start();
|
||||
}
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i].join();
|
||||
}
|
||||
} finally {
|
||||
long t = System.currentTimeMillis();
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(ZIPFILE_NAME));
|
||||
System.out.println("Deleting zip file took:" +
|
||||
(System.currentTimeMillis() - t) + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
private static void createZipFile() throws Exception {
|
||||
CRC32 crc32 = new CRC32();
|
||||
long t = System.currentTimeMillis();
|
||||
File zipFile = new File(ZIPFILE_NAME);
|
||||
try (FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos)) {
|
||||
ZipEntry e = new ZipEntry(ZIPENTRY_NAME);
|
||||
e.setMethod(ZipEntry.STORED);
|
||||
byte[] toWrite = "BLAH".repeat(10_000).getBytes();
|
||||
e.setTime(t);
|
||||
e.setSize(toWrite.length);
|
||||
crc32.reset();
|
||||
crc32.update(toWrite);
|
||||
e.setCrc(crc32.getValue());
|
||||
zos.putNextEntry(e);
|
||||
zos.write(toWrite);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (is.read() != -1) { }
|
||||
} catch (Exception e) {
|
||||
System.out.println("read exception:" + e);
|
||||
// Swallow any Exceptions (which are expected) - we're only interested in the crash
|
||||
}
|
||||
}
|
||||
}
|
||||
128
test/jdk/java/util/zip/ZipFile/ReadAfterClose.java
Normal file
128
test/jdk/java/util/zip/ZipFile/ReadAfterClose.java
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
@bug 8340684
|
||||
@summary Verify unspecified, but long-standing behavior when reading
|
||||
from an input stream obtained using ZipFile::getInputStream after
|
||||
the ZipFile has been closed.
|
||||
@run junit ReadAfterClose
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class ReadAfterClose {
|
||||
|
||||
// ZIP file used in this test
|
||||
private Path zip = Path.of("read-after-close.zip");
|
||||
|
||||
/**
|
||||
* Create a sample ZIP file for use by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
byte[] content = "hello".repeat(1000).getBytes(StandardCharsets.UTF_8);
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
{
|
||||
zo.putNextEntry(new ZipEntry("deflated.txt"));
|
||||
zo.write(content);
|
||||
}
|
||||
{
|
||||
ZipEntry entry = new ZipEntry("stored.txt");
|
||||
entry.setMethod(ZipEntry.STORED);
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(content);
|
||||
entry.setCrc(crc.getValue());
|
||||
entry.setSize(content.length);
|
||||
zo.putNextEntry(entry);
|
||||
zo.write(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced by this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce arguments with a variation of stored / deflated entries,
|
||||
* and read behavior before closing the ZipFile.
|
||||
* @return
|
||||
*/
|
||||
public static Stream<Arguments> arguments() {
|
||||
return Stream.of(
|
||||
Arguments.of("stored.txt", true),
|
||||
Arguments.of("stored.txt", false),
|
||||
Arguments.of("deflated.txt", true),
|
||||
Arguments.of("deflated.txt", false)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Attempting to read from an InputStream obtained by ZipFile.getInputStream
|
||||
* after the backing ZipFile is closed should throw IOException
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("arguments")
|
||||
public void readAfterClose(String entryName, boolean readFirst) throws IOException {
|
||||
// Retain a reference to an input stream backed by a closed ZipFile
|
||||
InputStream in;
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
in = zf.getInputStream(new ZipEntry(entryName));
|
||||
// Optionally consume a single byte from the stream before closing
|
||||
if (readFirst) {
|
||||
in.read();
|
||||
}
|
||||
}
|
||||
|
||||
assertThrows(IOException.class, () -> {
|
||||
in.read();
|
||||
});
|
||||
}
|
||||
}
|
||||
100
test/jdk/java/util/zip/ZipFile/ReadLongZipFileName.java
Normal file
100
test/jdk/java/util/zip/ZipFile/ReadLongZipFileName.java
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6374379
|
||||
* @summary Verify that we can read zip file names > 255 chars long
|
||||
* @run junit ReadLongZipFileName
|
||||
*/
|
||||
public class ReadLongZipFileName {
|
||||
private static final String ENTRY_NAME = "testFile.txt";
|
||||
private static final String LONG_DIR_NAME = "abcdefghijklmnopqrstuvwx"; // 24 chars
|
||||
private static final String JAR_FILE_NAME = "areallylargejarfilename.jar"; // 27 chars
|
||||
|
||||
/*
|
||||
* Creates a jar file at a path whose path name length and jar file name length
|
||||
* combined is large. Then use the java.util.jar.JarFile APIs to open and read the jar file
|
||||
* to verify the APIs work against those jar/zip files.
|
||||
*/
|
||||
@Test
|
||||
public void testOpenAndReadJarFile() throws Exception {
|
||||
int minRequiredPathLength = 600; // long enough to definitely fail.
|
||||
Path tmpDir = Files.createTempDirectory(Path.of("."), "ReadLongZipFileName-test")
|
||||
.normalize().toAbsolutePath();
|
||||
// Create a directory structure long enough that the filename will
|
||||
// put us over the minRequiredLength.
|
||||
int currentPathLength = 0;
|
||||
Path jarFileDir = tmpDir;
|
||||
do {
|
||||
jarFileDir = jarFileDir.resolve(LONG_DIR_NAME);
|
||||
Files.createDirectories(jarFileDir);
|
||||
currentPathLength = jarFileDir.toFile().getCanonicalPath().length();
|
||||
} while (currentPathLength < (minRequiredPathLength - JAR_FILE_NAME.length()));
|
||||
|
||||
// Create a new Jar file: use jar instead of zip to make sure long
|
||||
// names work for both zip and jar subclass.
|
||||
Path jarFilePath = jarFileDir.resolve(JAR_FILE_NAME);
|
||||
System.out.println("creating a jar file at " + jarFilePath);
|
||||
try (JarOutputStream out = new JarOutputStream(
|
||||
new BufferedOutputStream(Files.newOutputStream(jarFilePath)))) {
|
||||
out.putNextEntry(new JarEntry(ENTRY_NAME));
|
||||
out.write(1);
|
||||
}
|
||||
assertTrue(Files.isRegularFile(jarFilePath),
|
||||
"jar file " + jarFilePath + " does not exist or is not a file");
|
||||
|
||||
try (JarFile readJarFile = new JarFile(jarFilePath.toFile())) {
|
||||
JarEntry je = readJarFile.getJarEntry(ENTRY_NAME);
|
||||
assertNotNull(je, "missing jar entry: " + ENTRY_NAME + " in jar file " + jarFilePath);
|
||||
DataInputStream dis = new DataInputStream(readJarFile.getInputStream(je));
|
||||
byte val = dis.readByte();
|
||||
assertEquals(1, val, "unexpected byte " + val + " read from entry " + ENTRY_NAME);
|
||||
try {
|
||||
dis.readByte();
|
||||
Assertions.fail("Read past expected EOF");
|
||||
} catch (IOException e) {
|
||||
// expected
|
||||
System.out.println("received the expected exception: " + e);
|
||||
}
|
||||
}
|
||||
System.out.println("Successfully opened and read contents from a jar file with a name "
|
||||
+ jarFilePath.toFile().getCanonicalPath().length() + " characters long");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,934 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Formatter;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/* @test
|
||||
* @bug 8313765
|
||||
* @summary Validate that a Zip File with an Extra Header with a data size
|
||||
* of 0 can be read.
|
||||
* @run junit ReadNonStandardExtraHeadersTest
|
||||
*/
|
||||
public class ReadNonStandardExtraHeadersTest {
|
||||
|
||||
/*
|
||||
* Byte array holding a ZIP file which contains an
|
||||
* Extra field header which has a data size of 0.
|
||||
*
|
||||
* ---------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x664: Signature : 0x02014b50
|
||||
* 0x668: Created Zip Spec : 0xa [1.0]
|
||||
* 0x669: Created OS : 0x0 [MS-DOS]
|
||||
* 0x66a: VerMadeby : 0xa [0, 1.0]
|
||||
* 0x66b: VerExtract : 0xa [1.0]
|
||||
* 0x66c: Flag : 0x800
|
||||
* 0x66e: Method : 0x0 [STORED]
|
||||
* 0x670: Last Mod Time : 0x385ca437 [Thu Feb 28 20:33:46 EST 2008]
|
||||
* 0x674: CRC : 0x694c6952
|
||||
* 0x678: Compressed Size : 0x624
|
||||
* 0x67c: Uncompressed Size: 0x624
|
||||
* 0x680: Name Length : 0x1b
|
||||
* 0x682: Extra Length : 0x7
|
||||
* ->[tag=cafe, size=0]
|
||||
* 0x684: Comment Length : 0x0
|
||||
* 0x686: Disk Start : 0x0
|
||||
* 0x688: Attrs : 0x0
|
||||
* 0x68a: AttrsEx : 0x0
|
||||
* 0x68e: Loc Header Offset: 0x0
|
||||
* 0x692: File Name : res/drawable/size_48x48.jpg
|
||||
*
|
||||
* [Local File Header]
|
||||
* 0x0: Signature : 0x04034b50
|
||||
* 0x4: Version : 0xa [1.0]
|
||||
* 0x6: Flag : 0x800
|
||||
* 0x8: Method : 0x0 [STORED]
|
||||
* 0xa: LastMTime : 0x385ca437 [Thu Feb 28 20:33:46 EST 2008]
|
||||
* 0xe: CRC : 0x694c6952
|
||||
* 0x12: CSize : 0x624
|
||||
* 0x16: Size : 0x624
|
||||
* 0x1a: Name Length : 0x1b [res/drawable/size_48x48.jpg]
|
||||
* 0x1c: ExtraLength : 0x7
|
||||
* ->[tag=cafe, size=0]
|
||||
* 0x1e: File Name : [res/drawable/size_48x48.jpg]
|
||||
* [End Central Directory Header]
|
||||
* Signature : 0x06054b50
|
||||
* ENDCEN Off : 0x6b4
|
||||
* Disk Entries: 0x1
|
||||
* Total Entries: 0x1
|
||||
* CEN Size : 0x50
|
||||
* Offset CEN : 0x664
|
||||
* Comment Len : 0x0 []
|
||||
*/
|
||||
public static byte[] VALID_APK_FILE = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0xa, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x37, (byte) 0xa4, (byte) 0x5c, (byte) 0x38, (byte) 0x52, (byte) 0x69,
|
||||
(byte) 0x4c, (byte) 0x69, (byte) 0x24, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x24, (byte) 0x6,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x1b, (byte) 0x0, (byte) 0x7, (byte) 0x0, (byte) 0x72, (byte) 0x65,
|
||||
(byte) 0x73, (byte) 0x2f, (byte) 0x64, (byte) 0x72, (byte) 0x61, (byte) 0x77, (byte) 0x61, (byte) 0x62,
|
||||
(byte) 0x6c, (byte) 0x65, (byte) 0x2f, (byte) 0x73, (byte) 0x69, (byte) 0x7a, (byte) 0x65, (byte) 0x5f,
|
||||
(byte) 0x34, (byte) 0x38, (byte) 0x78, (byte) 0x34, (byte) 0x38, (byte) 0x2e, (byte) 0x6a, (byte) 0x70,
|
||||
(byte) 0x67, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xff, (byte) 0xd8, (byte) 0xff, (byte) 0xe0, (byte) 0x0, (byte) 0x10, (byte) 0x4a, (byte) 0x46,
|
||||
(byte) 0x49, (byte) 0x46, (byte) 0x0, (byte) 0x1, (byte) 0x1, (byte) 0x1, (byte) 0x0, (byte) 0x48,
|
||||
(byte) 0x0, (byte) 0x48, (byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xfe, (byte) 0x0, (byte) 0x16,
|
||||
(byte) 0x28, (byte) 0x63, (byte) 0x29, (byte) 0x20, (byte) 0x32, (byte) 0x30, (byte) 0x30, (byte) 0x37,
|
||||
(byte) 0x20, (byte) 0x50, (byte) 0x68, (byte) 0x69, (byte) 0x6c, (byte) 0x20, (byte) 0x44, (byte) 0x75,
|
||||
(byte) 0x62, (byte) 0x61, (byte) 0x63, (byte) 0x68, (byte) 0xff, (byte) 0xdb, (byte) 0x0, (byte) 0x43,
|
||||
(byte) 0x0, (byte) 0x6, (byte) 0x4, (byte) 0x5, (byte) 0x6, (byte) 0x5, (byte) 0x4, (byte) 0x6,
|
||||
(byte) 0x6, (byte) 0x5, (byte) 0x6, (byte) 0x7, (byte) 0x7, (byte) 0x6, (byte) 0x8, (byte) 0xa,
|
||||
(byte) 0x10, (byte) 0xa, (byte) 0xa, (byte) 0x9, (byte) 0x9, (byte) 0xa, (byte) 0x14, (byte) 0xe,
|
||||
(byte) 0xf, (byte) 0xc, (byte) 0x10, (byte) 0x17, (byte) 0x14, (byte) 0x18, (byte) 0x18, (byte) 0x17,
|
||||
(byte) 0x14, (byte) 0x16, (byte) 0x16, (byte) 0x1a, (byte) 0x1d, (byte) 0x25, (byte) 0x1f, (byte) 0x1a,
|
||||
(byte) 0x1b, (byte) 0x23, (byte) 0x1c, (byte) 0x16, (byte) 0x16, (byte) 0x20, (byte) 0x2c, (byte) 0x20,
|
||||
(byte) 0x23, (byte) 0x26, (byte) 0x27, (byte) 0x29, (byte) 0x2a, (byte) 0x29, (byte) 0x19, (byte) 0x1f,
|
||||
(byte) 0x2d, (byte) 0x30, (byte) 0x2d, (byte) 0x28, (byte) 0x30, (byte) 0x25, (byte) 0x28, (byte) 0x29,
|
||||
(byte) 0x28, (byte) 0xff, (byte) 0xdb, (byte) 0x0, (byte) 0x43, (byte) 0x1, (byte) 0x7, (byte) 0x7,
|
||||
(byte) 0x7, (byte) 0xa, (byte) 0x8, (byte) 0xa, (byte) 0x13, (byte) 0xa, (byte) 0xa, (byte) 0x13,
|
||||
(byte) 0x28, (byte) 0x1a, (byte) 0x16, (byte) 0x1a, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28,
|
||||
(byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0x28, (byte) 0xff, (byte) 0xc0,
|
||||
(byte) 0x0, (byte) 0x11, (byte) 0x8, (byte) 0x0, (byte) 0x30, (byte) 0x0, (byte) 0x30, (byte) 0x3,
|
||||
(byte) 0x1, (byte) 0x11, (byte) 0x0, (byte) 0x2, (byte) 0x11, (byte) 0x1, (byte) 0x3, (byte) 0x11,
|
||||
(byte) 0x1, (byte) 0xff, (byte) 0xc4, (byte) 0x0, (byte) 0x1b, (byte) 0x0, (byte) 0x0, (byte) 0x2,
|
||||
(byte) 0x2, (byte) 0x3, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4, (byte) 0x5,
|
||||
(byte) 0x6, (byte) 0x7, (byte) 0x1, (byte) 0x3, (byte) 0x8, (byte) 0x2, (byte) 0xff, (byte) 0xc4,
|
||||
(byte) 0x0, (byte) 0x2e, (byte) 0x10, (byte) 0x0, (byte) 0x2, (byte) 0x2, (byte) 0x1, (byte) 0x2,
|
||||
(byte) 0x4, (byte) 0x4, (byte) 0x5, (byte) 0x4, (byte) 0x3, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x2, (byte) 0x3, (byte) 0x4, (byte) 0x11,
|
||||
(byte) 0x0, (byte) 0x5, (byte) 0x6, (byte) 0x12, (byte) 0x21, (byte) 0x31, (byte) 0x41, (byte) 0x51,
|
||||
(byte) 0x61, (byte) 0x71, (byte) 0x7, (byte) 0x13, (byte) 0x22, (byte) 0x42, (byte) 0x91, (byte) 0x33,
|
||||
(byte) 0x62, (byte) 0x81, (byte) 0xa1, (byte) 0x52, (byte) 0xd1, (byte) 0xf0, (byte) 0xff, (byte) 0xc4,
|
||||
(byte) 0x0, (byte) 0x1b, (byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x5, (byte) 0x1, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x6, (byte) 0x2, (byte) 0x3, (byte) 0x4, (byte) 0x5,
|
||||
(byte) 0x7, (byte) 0x1, (byte) 0x0, (byte) 0xff, (byte) 0xc4, (byte) 0x0, (byte) 0x33, (byte) 0x11,
|
||||
(byte) 0x0, (byte) 0x1, (byte) 0x3, (byte) 0x2, (byte) 0x4, (byte) 0x4, (byte) 0x4, (byte) 0x4,
|
||||
(byte) 0x5, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x2, (byte) 0x3, (byte) 0x4, (byte) 0x11, (byte) 0x5, (byte) 0x12,
|
||||
(byte) 0x21, (byte) 0x31, (byte) 0x13, (byte) 0x51, (byte) 0x61, (byte) 0x71, (byte) 0x6, (byte) 0x32,
|
||||
(byte) 0x41, (byte) 0x81, (byte) 0x91, (byte) 0xa1, (byte) 0xb1, (byte) 0xc1, (byte) 0x7, (byte) 0x14,
|
||||
(byte) 0x42, (byte) 0xd1, (byte) 0xf0, (byte) 0x22, (byte) 0x33, (byte) 0x62, (byte) 0xa2, (byte) 0xf1,
|
||||
(byte) 0xff, (byte) 0xda, (byte) 0x0, (byte) 0xc, (byte) 0x3, (byte) 0x1, (byte) 0x0, (byte) 0x2,
|
||||
(byte) 0x11, (byte) 0x3, (byte) 0x11, (byte) 0x0, (byte) 0x3f, (byte) 0x0, (byte) 0xb4, (byte) 0x11,
|
||||
(byte) 0xf4, (byte) 0x4c, (byte) 0xa, (byte) 0x12, (byte) 0x7b, (byte) 0x16, (byte) 0x2e, (byte) 0x5d,
|
||||
(byte) 0xaf, (byte) 0x46, (byte) 0xac, (byte) 0x96, (byte) 0x6e, (byte) 0xcf, (byte) 0x1c, (byte) 0x10,
|
||||
(byte) 0x46, (byte) 0x32, (byte) 0xd2, (byte) 0x48, (byte) 0xd8, (byte) 0x3, (byte) 0x48, (byte) 0x96,
|
||||
(byte) 0x46, (byte) 0x44, (byte) 0xd2, (byte) 0xf7, (byte) 0x9b, (byte) 0x0, (byte) 0x91, (byte) 0x5,
|
||||
(byte) 0x24, (byte) 0xd5, (byte) 0x52, (byte) 0x8, (byte) 0x60, (byte) 0x69, (byte) 0x73, (byte) 0x8e,
|
||||
(byte) 0xc0, (byte) 0x6f, (byte) 0xfc, (byte) 0xfa, (byte) 0x28, (byte) 0x26, (byte) 0xe5, (byte) 0xf1,
|
||||
(byte) 0x5f, (byte) 0x6b, (byte) 0x82, (byte) 0x52, (byte) 0x9b, (byte) 0x7d, (byte) 0x3b, (byte) 0x17,
|
||||
(byte) 0x0, (byte) 0x38, (byte) 0xe7, (byte) 0x62, (byte) 0x22, (byte) 0x53, (byte) 0xea, (byte) 0x32,
|
||||
(byte) 0x9, (byte) 0xfc, (byte) 0x81, (byte) 0xaa, (byte) 0x19, (byte) 0xfc, (byte) 0x43, (byte) 0x13,
|
||||
(byte) 0xd, (byte) 0xa3, (byte) 0x69, (byte) 0x77, (byte) 0xcb, (byte) 0xf7, (byte) 0x47, (byte) 0xb4,
|
||||
(byte) 0x1f, (byte) 0x86, (byte) 0x95, (byte) 0xd3, (byte) 0xb7, (byte) 0x35, (byte) 0x4c, (byte) 0xad,
|
||||
(byte) 0x8f, (byte) 0xa5, (byte) 0xb3, (byte) 0x1f, (byte) 0x7d, (byte) 0x40, (byte) 0xf8, (byte) 0x12,
|
||||
(byte) 0x8a, (byte) 0xd9, (byte) 0x7e, (byte) 0x26, (byte) 0x6d, (byte) 0xb7, (byte) 0x98, (byte) 0x8b,
|
||||
(byte) 0x95, (byte) 0x2c, (byte) 0xd3, (byte) 0x3, (byte) 0xbc, (byte) 0x9f, (byte) 0xaa, (byte) 0x8b,
|
||||
(byte) 0xee, (byte) 0x40, (byte) 0xc8, (byte) 0xfc, (byte) 0x6b, (byte) 0xb4, (byte) 0xf8, (byte) 0xfc,
|
||||
(byte) 0x52, (byte) 0x7f, (byte) 0x71, (byte) 0xa5, (byte) 0xbd, (byte) 0x77, (byte) 0x1e, (byte) 0xff,
|
||||
(byte) 0x0, (byte) 0xf1, (byte) 0x7b, (byte) 0x10, (byte) 0xfc, (byte) 0x34, (byte) 0xc4, (byte) 0x29,
|
||||
(byte) 0x9b, (byte) 0x9e, (byte) 0x9a, (byte) 0x46, (byte) 0xcb, (byte) 0xd3, (byte) 0xca, (byte) 0xef,
|
||||
(byte) 0x6b, (byte) 0x92, (byte) 0xf, (byte) 0xc4, (byte) 0x29, (byte) 0xd4, (byte) 0x13, (byte) 0x47,
|
||||
(byte) 0x62, (byte) 0x14, (byte) 0x9a, (byte) 0x9, (byte) 0x12, (byte) 0x58, (byte) 0x9c, (byte) 0x73,
|
||||
(byte) 0x2b, (byte) 0xa1, (byte) 0x4, (byte) 0x30, (byte) 0xf3, (byte) 0x7, (byte) 0x57, (byte) 0xac,
|
||||
(byte) 0x7b, (byte) 0x5e, (byte) 0xd0, (byte) 0xe6, (byte) 0x9b, (byte) 0x82, (byte) 0x80, (byte) 0x24,
|
||||
(byte) 0x82, (byte) 0x48, (byte) 0x1e, (byte) 0x62, (byte) 0x95, (byte) 0xa5, (byte) 0xae, (byte) 0x1a,
|
||||
(byte) 0x10, (byte) 0x45, (byte) 0x88, (byte) 0x3d, (byte) 0x42, (byte) 0xf7, (byte) 0x83, (byte) 0xae,
|
||||
(byte) 0xdd, (byte) 0x75, (byte) 0xa1, (byte) 0x2, (byte) 0xd2, (byte) 0x47, (byte) 0x1a, (byte) 0x33,
|
||||
(byte) 0xbb, (byte) 0x5, (byte) 0x45, (byte) 0x5, (byte) 0x99, (byte) 0x89, (byte) 0xc0, (byte) 0x0,
|
||||
(byte) 0x77, (byte) 0x27, (byte) 0x49, (byte) 0xce, (byte) 0x0, (byte) 0xb9, (byte) 0x53, (byte) 0xcc,
|
||||
(byte) 0x2e, (byte) 0x71, (byte) 0xb0, (byte) 0x17, (byte) 0x25, (byte) 0x73, (byte) 0xff, (byte) 0x0,
|
||||
(byte) 0x1d, (byte) 0x71, (byte) 0x54, (byte) 0xfc, (byte) 0x4f, (byte) 0xba, (byte) 0x30, (byte) 0x46,
|
||||
(byte) 0x64, (byte) 0xdb, (byte) 0x21, (byte) 0x62, (byte) 0x2b, (byte) 0xc5, (byte) 0xdb, (byte) 0x3f,
|
||||
(byte) 0xbd, (byte) 0x87, (byte) 0xf9, (byte) 0x1f, (byte) 0xe8, (byte) 0x74, (byte) 0xf3, (byte) 0xc8,
|
||||
(byte) 0x46, (byte) 0x25, (byte) 0x5e, (byte) 0xea, (byte) 0xb9, (byte) 0x3f, (byte) 0xc4, (byte) 0x6c,
|
||||
(byte) 0x3e, (byte) 0xeb, (byte) 0x6d, (byte) 0xf0, (byte) 0xbf, (byte) 0x87, (byte) 0xa3, (byte) 0xc2,
|
||||
(byte) 0xa0, (byte) 0x5, (byte) 0xc2, (byte) 0xf2, (byte) 0xbb, (byte) 0xcc, (byte) 0x7e, (byte) 0xc3,
|
||||
(byte) 0xa0, (byte) 0xf9, (byte) 0x9d, (byte) 0x79, (byte) 0x59, (byte) 0xa, (byte) 0x2e, (byte) 0x7,
|
||||
(byte) 0x4d, (byte) 0x54, (byte) 0x92, (byte) 0x8c, (byte) 0xd8, (byte) 0xdb, (byte) 0x29, (byte) 0x1f,
|
||||
(byte) 0xe, (byte) 0x55, (byte) 0xbc, (byte) 0x86, (byte) 0x69, (byte) 0xea, (byte) 0x30, (byte) 0xc,
|
||||
(byte) 0x22, (byte) 0x62, (byte) 0x63, (byte) 0x75, (byte) 0x24, (byte) 0x48, (byte) 0x83, (byte) 0xbe,
|
||||
(byte) 0x7d, (byte) 0x3b, (byte) 0x75, (byte) 0x3e, (byte) 0x24, (byte) 0xe, (byte) 0xe4, (byte) 0x69,
|
||||
(byte) 0xe8, (byte) 0xc, (byte) 0x8c, (byte) 0xbb, (byte) 0xd8, (byte) 0xa2, (byte) 0x56, (byte) 0x54,
|
||||
(byte) 0xd3, (byte) 0x87, (byte) 0x32, (byte) 0x9, (byte) 0x4e, (byte) 0xae, (byte) 0x3a, (byte) 0x5b,
|
||||
(byte) 0xd3, (byte) 0xaa, (byte) 0x7f, (byte) 0xc0, (byte) 0x7c, (byte) 0x5e, (byte) 0xdb, (byte) 0x2d,
|
||||
(byte) 0xd1, (byte) 0x5, (byte) 0xd9, (byte) 0x11, (byte) 0x36, (byte) 0xb9, (byte) 0x64, (byte) 0xc3,
|
||||
(byte) 0x87, (byte) 0x6c, (byte) 0x8, (byte) 0x89, (byte) 0xfb, (byte) 0x86, (byte) 0x7b, (byte) 0xf,
|
||||
(byte) 0x3d, (byte) 0x59, (byte) 0xe1, (byte) 0x38, (byte) 0x8b, (byte) 0xa0, (byte) 0x7e, (byte) 0x43,
|
||||
(byte) 0xe5, (byte) 0x3e, (byte) 0x9c, (byte) 0xba, (byte) 0xa1, (byte) 0x6f, (byte) 0x1b, (byte) 0x78,
|
||||
(byte) 0x6e, (byte) 0x9a, (byte) 0xbe, (byte) 0x98, (byte) 0xd5, (byte) 0x5c, (byte) 0x36, (byte) 0x66,
|
||||
(byte) 0xd, (byte) 0x9, (byte) 0xb0, (byte) 0xcd, (byte) 0x6f, (byte) 0xd2, (byte) 0x6f, (byte) 0xfe,
|
||||
(byte) 0xbc, (byte) 0x8f, (byte) 0x4b, (byte) 0xab, (byte) 0xa6, (byte) 0xad, (byte) 0x9a, (byte) 0xf7,
|
||||
(byte) 0x2b, (byte) 0xa4, (byte) 0xf4, (byte) 0xe7, (byte) 0x86, (byte) 0xc4, (byte) 0xf, (byte) 0xd5,
|
||||
(byte) 0x65, (byte) 0x85, (byte) 0xc3, (byte) 0xab, (byte) 0x7b, (byte) 0x11, (byte) 0xd0, (byte) 0xe8,
|
||||
(byte) 0xc5, (byte) 0xaf, (byte) 0xe, (byte) 0x17, (byte) 0x69, (byte) 0xba, (byte) 0xc2, (byte) 0xf2,
|
||||
(byte) 0x16, (byte) 0x9b, (byte) 0x38, (byte) 0x59, (byte) 0x40, (byte) 0x78, (byte) 0xd6, (byte) 0xf3,
|
||||
(byte) 0xa7, (byte) 0x8, (byte) 0xee, (byte) 0xe6, (byte) 0x33, (byte) 0xf5, (byte) 0x1a, (byte) 0xec,
|
||||
(byte) 0xbd, (byte) 0x3c, (byte) 0x8f, (byte) 0x43, (byte) 0xfd, (byte) 0x13, (byte) 0xaa, (byte) 0xea,
|
||||
(byte) 0xd9, (byte) 0x4f, (byte) 0x1, (byte) 0xe0, (byte) 0x72, (byte) 0x45, (byte) 0x78, (byte) 0x4c,
|
||||
(byte) 0x2d, (byte) 0xfc, (byte) 0xf4, (byte) 0x39, (byte) 0xb6, (byte) 0xcc, (byte) 0x3e, (byte) 0x5b,
|
||||
(byte) 0x7c, (byte) 0xd5, (byte) 0xb, (byte) 0x59, (byte) 0xb3, (byte) 0xa0, (byte) 0xd7, (byte) 0x85,
|
||||
(byte) 0xb5, (byte) 0x53, (byte) 0x3e, (byte) 0xe9, (byte) 0xe6, (byte) 0xc6, (byte) 0x6a, (byte) 0x35,
|
||||
(byte) 0xe4, (byte) 0x5d, (byte) 0xc1, (byte) 0x9d, (byte) 0x6b, (byte) 0xb0, (byte) 0x21, (byte) 0x9a,
|
||||
(byte) 0x3c, (byte) 0x64, (byte) 0x7a, (byte) 0x8c, (byte) 0xe9, (byte) 0xa6, (byte) 0xe5, (byte) 0x7,
|
||||
(byte) 0xfa, (byte) 0xb6, (byte) 0x53, (byte) 0xe5, (byte) 0x74, (byte) 0x9c, (byte) 0x33, (byte) 0xc2,
|
||||
(byte) 0xf3, (byte) 0x75, (byte) 0x5b, (byte) 0xa5, (byte) 0xdf, (byte) 0x61, (byte) 0xda, (byte) 0x4f,
|
||||
(byte) 0xc9, (byte) 0xb7, (byte) 0x3d, (byte) 0xc6, (byte) 0x4b, (byte) 0x32, (byte) 0x34, (byte) 0xb,
|
||||
(byte) 0x65, (byte) 0x47, (byte) 0x53, (byte) 0x0, (byte) 0xc1, (byte) 0x18, (byte) 0xcf, (byte) 0x7f,
|
||||
(byte) 0xbb, (byte) 0xa7, (byte) 0x99, (byte) 0xf5, (byte) 0x3a, (byte) 0x71, (byte) 0xb1, (byte) 0x49,
|
||||
(byte) 0x35, (byte) 0xf2, (byte) 0x1d, (byte) 0x96, (byte) 0x6f, (byte) 0x8d, (byte) 0x62, (byte) 0x2f,
|
||||
(byte) 0xa2, (byte) 0xc5, (byte) 0x44, (byte) 0xf1, (byte) 0x58, (byte) 0x90, (byte) 0xdb, (byte) 0x5b,
|
||||
(byte) 0x70, (byte) 0xe, (byte) 0xbb, (byte) 0xf5, (byte) 0x6, (byte) 0xc5, (byte) 0x19, (byte) 0xc5,
|
||||
(byte) 0xd4, (byte) 0xf6, (byte) 0xad, (byte) 0xbe, (byte) 0x18, (byte) 0x2d, (byte) 0x52, (byte) 0x13,
|
||||
(byte) 0xd9, (byte) 0x2e, (byte) 0x3, (byte) 0x27, (byte) 0x2c, (byte) 0x79, (byte) 0x3c, (byte) 0x84,
|
||||
(byte) 0x2, (byte) 0xf, (byte) 0x29, (byte) 0x39, (byte) 0xd, (byte) 0xea, (byte) 0x7d, (byte) 0x3b,
|
||||
(byte) 0x75, (byte) 0xcb, (byte) 0x70, (byte) 0xe7, (byte) 0x75, (byte) 0xe2, (byte) 0x6, (byte) 0xdc,
|
||||
(byte) 0xfd, (byte) 0x2, (byte) 0x8d, (byte) 0x84, (byte) 0xe2, (byte) 0x74, (byte) 0xfc, (byte) 0x73,
|
||||
(byte) 0x55, (byte) 0x5d, (byte) 0x1b, (byte) 0xa6, (byte) 0x94, (byte) 0xed, (byte) 0xb1, (byte) 0xb7,
|
||||
(byte) 0x60, (byte) 0x4f, (byte) 0xc3, (byte) 0x4d, (byte) 0x3d, (byte) 0x2, (byte) 0xb9, (byte) 0xf8,
|
||||
(byte) 0x3, (byte) 0x88, (byte) 0xdb, (byte) 0x88, (byte) 0xf6, (byte) 0x48, (byte) 0x67, (byte) 0x6d,
|
||||
(byte) 0xaf, (byte) 0x72, (byte) 0xa5, (byte) 0xcb, (byte) 0x1a, (byte) 0xab, (byte) 0x49, (byte) 0x6e,
|
||||
(byte) 0x25, (byte) 0x45, (byte) 0x99, (byte) 0x80, (byte) 0xc3, (byte) 0x14, (byte) 0xc3, (byte) 0x12,
|
||||
(byte) 0x46, (byte) 0x41, (byte) 0xee, (byte) 0x6, (byte) 0x8f, (byte) 0x68, (byte) 0xe7, (byte) 0x32,
|
||||
(byte) 0xc4, (byte) 0xd2, (byte) 0x79, (byte) 0x6f, (byte) 0xe8, (byte) 0x4a, (byte) 0x2, (byte) 0xc5,
|
||||
(byte) 0x29, (byte) 0x44, (byte) 0x15, (byte) 0x52, (byte) 0x34, (byte) 0x2, (byte) 0xd1, (byte) 0x72,
|
||||
(byte) 0x43, (byte) 0x48, (byte) 0xb1, (byte) 0x0, (byte) 0xea, (byte) 0x1, (byte) 0x1d, (byte) 0x88,
|
||||
(byte) 0x49, (byte) 0xae, (byte) 0xc0, (byte) 0x96, (byte) 0xea, (byte) 0x4f, (byte) 0x5a, (byte) 0x6f,
|
||||
(byte) 0xd2, (byte) 0x9a, (byte) 0x36, (byte) 0x8d, (byte) 0xbd, (byte) 0x88, (byte) 0xc1, (byte) 0xd4,
|
||||
(byte) 0x77, (byte) 0x8c, (byte) 0xcd, (byte) 0x2d, (byte) 0x3e, (byte) 0xaa, (byte) 0xce, (byte) 0x37,
|
||||
(byte) 0x18, (byte) 0x9e, (byte) 0x24, (byte) 0x6e, (byte) 0xe0, (byte) 0xdf, (byte) 0xe0, (byte) 0xb9,
|
||||
(byte) 0xfa, (byte) 0x4a, (byte) 0xf3, (byte) 0x50, (byte) 0xbd, (byte) 0x3d, (byte) 0x4b, (byte) 0x0,
|
||||
(byte) 0xac, (byte) 0xd0, (byte) 0xb9, (byte) 0x46, (byte) 0x1e, (byte) 0xa3, (byte) 0xc7, (byte) 0xdb,
|
||||
(byte) 0x42, (byte) 0xd3, (byte) 0x30, (byte) 0xb4, (byte) 0x90, (byte) 0x56, (byte) 0xaf, (byte) 0x86,
|
||||
(byte) 0xd4, (byte) 0x89, (byte) 0x58, (byte) 0x1e, (byte) 0xd3, (byte) 0xa1, (byte) 0x4c, (byte) 0x76,
|
||||
(byte) 0xe1, (byte) 0x1b, (byte) 0xdc, (byte) 0x84, (byte) 0xd9, (byte) 0x23, (byte) 0xe4, (byte) 0x2b,
|
||||
(byte) 0x7, (byte) 0x91, (byte) 0x73, (byte) 0x8e, (byte) 0x65, (byte) 0x1d, (byte) 0x48, (byte) 0xf7,
|
||||
(byte) 0x20, (byte) 0x11, (byte) 0xfc, (byte) 0xea, (byte) 0x31, (byte) 0xd1, (byte) 0x59, (byte) 0x55,
|
||||
(byte) 0x36, (byte) 0x69, (byte) 0x20, (byte) 0x73, (byte) 0x62, (byte) 0x75, (byte) 0x9c, (byte) 0x74,
|
||||
(byte) 0x1d, (byte) 0x2f, (byte) 0xa5, (byte) 0xfd, (byte) 0xb7, (byte) 0xf6, (byte) 0x52, (byte) 0x7b,
|
||||
(byte) 0xd3, (byte) 0x52, (byte) 0xde, (byte) 0x52, (byte) 0x2b, (byte) 0x97, (byte) 0xab, (byte) 0x6,
|
||||
(byte) 0x44, (byte) 0x95, (byte) 0x5a, (byte) 0x34, (byte) 0xce, (byte) 0x3e, (byte) 0x5a, (byte) 0x82,
|
||||
(byte) 0xa0, (byte) 0x9f, (byte) 0xe, (byte) 0xfd, (byte) 0x7d, (byte) 0x87, (byte) 0xe7, (byte) 0x4c,
|
||||
(byte) 0xc, (byte) 0xf1, (byte) 0x13, (byte) 0xc2, (byte) 0x36, (byte) 0xb8, (byte) 0x59, (byte) 0xdc,
|
||||
(byte) 0xf8, (byte) 0x23, (byte) 0xdd, (byte) 0x59, (byte) 0x25, (byte) 0x2d, (byte) 0x35, (byte) 0xdd,
|
||||
(byte) 0xc3, (byte) 0x0, (byte) 0x9e, (byte) 0xa7, (byte) 0x7b, (byte) 0x77, (byte) 0x20, (byte) 0xe9,
|
||||
(byte) 0xd9, (byte) 0x1, (byte) 0x7e, (byte) 0xed, (byte) 0xcd, (byte) 0xd4, (byte) 0xc5, (byte) 0x16,
|
||||
(byte) 0xcc, (byte) 0xcb, (byte) 0x60, (byte) 0xca, (byte) 0xe1, (byte) 0xd, (byte) 0x76, (byte) 0x24,
|
||||
(byte) 0x16, (byte) 0x70, (byte) 0x70, (byte) 0x1, (byte) 0xfd, (byte) 0xd8, (byte) 0xc7, (byte) 0x5f,
|
||||
(byte) 0x51, (byte) 0x9e, (byte) 0xd8, (byte) 0xd3, (byte) 0xd1, (byte) 0x42, (byte) 0x1, (byte) 0x11,
|
||||
(byte) 0xbe, (byte) 0xf7, (byte) 0x3c, (byte) 0xb9, (byte) 0xfd, (byte) 0xd5, (byte) 0x9e, (byte) 0xd,
|
||||
(byte) 0x1d, (byte) 0x4c, (byte) 0x14, (byte) 0xe7, (byte) 0x10, (byte) 0xa0, (byte) 0x94, (byte) 0x59,
|
||||
(byte) 0xb7, (byte) 0xce, (byte) 0xc7, (byte) 0xed, (byte) 0xa6, (byte) 0xfa, (byte) 0xfa, (byte) 0x5c,
|
||||
(byte) 0x6b, (byte) 0xe9, (byte) 0xd4, (byte) 0x9b, (byte) 0x2b, (byte) 0xe3, (byte) 0x82, (byte) 0x23,
|
||||
(byte) 0x9a, (byte) 0xaf, (byte) 0xc, (byte) 0xd1, (byte) 0xa9, (byte) 0x6a, (byte) 0x8c, (byte) 0xd4,
|
||||
(byte) 0x6c, (byte) 0x57, (byte) 0x4f, (byte) 0x97, (byte) 0x24, (byte) 0x32, (byte) 0xb2, (byte) 0x3f,
|
||||
(byte) 0xd5, (byte) 0xdc, (byte) 0xb0, (byte) 0x64, (byte) 0x24, (byte) 0x15, (byte) 0x24, (byte) 0x92,
|
||||
(byte) 0xe, (byte) 0x7f, (byte) 0x81, (byte) 0xa3, (byte) 0x8a, (byte) 0x48, (byte) 0xf8, (byte) 0x10,
|
||||
(byte) 0xb6, (byte) 0x2e, (byte) 0x4b, (byte) 0x3c, (byte) 0xc5, (byte) 0xaa, (byte) 0xce, (byte) 0x21,
|
||||
(byte) 0x5b, (byte) 0x25, (byte) 0x5b, (byte) 0xbf, (byte) 0x59, (byte) 0xbf, (byte) 0x61, (byte) 0xb0,
|
||||
(byte) 0x1e, (byte) 0xc0, (byte) 0x4, (byte) 0xbe, (byte) 0x6a, (byte) 0xf9, (byte) 0xce, (byte) 0x35,
|
||||
(byte) 0xe7, (byte) 0x35, (byte) 0x4b, (byte) 0x50, (byte) 0xe, (byte) 0x3c, (byte) 0xe1, (byte) 0x64,
|
||||
(byte) 0xdc, (byte) 0xe5, (byte) 0x4b, (byte) 0x35, (byte) 0xf1, (byte) 0x15, (byte) 0xe0, (byte) 0x30,
|
||||
(byte) 0x5b, (byte) 0xc2, (byte) 0x41, (byte) 0xe0, (byte) 0x1b, (byte) 0xfd, (byte) 0xff, (byte) 0x0,
|
||||
(byte) 0xc2, (byte) 0xae, (byte) 0xae, (byte) 0x97, (byte) 0x89, (byte) 0xa8, (byte) 0xdd, (byte) 0x5d,
|
||||
(byte) 0x61, (byte) 0x38, (byte) 0xb3, (byte) 0xa8, (byte) 0x8e, (byte) 0x57, (byte) 0x6a, (byte) 0xcf,
|
||||
(byte) 0xa7, (byte) 0x6f, (byte) 0xd9, (byte) 0x40, (byte) 0xdf, (byte) 0x68, (byte) 0xdc, (byte) 0xab,
|
||||
(byte) 0x37, (byte) 0x24, (byte) 0xd4, (byte) 0xa6, (byte) 0x38, (byte) 0xf1, (byte) 0x45, (byte) 0xe7,
|
||||
(byte) 0x1f, (byte) 0x91, (byte) 0xaa, (byte) 0x39, (byte) 0x29, (byte) 0x65, (byte) 0x6e, (byte) 0xed,
|
||||
(byte) 0x5a, (byte) 0x15, (byte) 0x1e, (byte) 0x37, (byte) 0x47, (byte) 0x30, (byte) 0xd2, (byte) 0x40,
|
||||
(byte) 0x3b, (byte) 0x9b, (byte) 0x7d, (byte) 0x53, (byte) 0x3d, (byte) 0xaf, (byte) 0x67, (byte) 0xdd,
|
||||
(byte) 0xf7, (byte) 0x14, (byte) 0x58, (byte) 0xaa, (byte) 0xd1, (byte) 0x9d, (byte) 0xd5, (byte) 0x49,
|
||||
(byte) 0xc1, (byte) 0x65, (byte) 0xe5, (byte) 0x51, (byte) 0x9c, (byte) 0x7d, (byte) 0xc7, (byte) 0x3,
|
||||
(byte) 0xc3, (byte) 0x4d, (byte) 0xb2, (byte) 0x92, (byte) 0x69, (byte) 0x8d, (byte) 0x98, (byte) 0xd2,
|
||||
(byte) 0xa4, (byte) 0x49, (byte) 0x89, (byte) 0x61, (byte) 0x94, (byte) 0xf, (byte) 0x7d, (byte) 0x44,
|
||||
(byte) 0x92, (byte) 0x0, (byte) 0xe7, (byte) 0xda, (byte) 0xfa, (byte) 0xdc, (byte) 0x9b, (byte) 0x6d,
|
||||
(byte) 0xa0, (byte) 0xb9, (byte) 0x56, (byte) 0x47, (byte) 0x5, (byte) 0xf0, (byte) 0x2c, (byte) 0x5b,
|
||||
(byte) 0x4d, (byte) 0x94, (byte) 0xdc, (byte) 0x37, (byte) 0x7, (byte) 0xf9, (byte) 0x97, (byte) 0x81,
|
||||
(byte) 0xe6, (byte) 0x54, (byte) 0x89, (byte) 0x8a, (byte) 0xa2, (byte) 0x1f, (byte) 0x33, (byte) 0x8c,
|
||||
(byte) 0x73, (byte) 0x1f, (byte) 0x7e, (byte) 0x9d, (byte) 0x4f, (byte) 0x7d, (byte) 0x5f, (byte) 0xd1,
|
||||
(byte) 0x61, (byte) 0xdc, (byte) 0x1b, (byte) 0x3e, (byte) 0x53, (byte) 0x72, (byte) 0x36, (byte) 0x1c,
|
||||
(byte) 0xbf, (byte) 0x9f, (byte) 0xe, (byte) 0xeb, (byte) 0x3a, (byte) 0xc7, (byte) 0xf1, (byte) 0xf8,
|
||||
(byte) 0xab, (byte) 0x9e, (byte) 0xf6, (byte) 0xd1, (byte) 0x47, (byte) 0x90, (byte) 0x3b, (byte) 0xcc,
|
||||
(byte) 0xed, (byte) 0x8b, (byte) 0xfb, (byte) 0x81, (byte) 0xa5, (byte) 0xbb, (byte) 0xdc, (byte) 0xf6,
|
||||
(byte) 0xd4, (byte) 0x2b, (byte) 0x1e, (byte) 0x26, (byte) 0xe6, (byte) 0x41, (byte) 0x9e, (byte) 0xfa,
|
||||
(byte) 0xb8, (byte) 0xe, (byte) 0xb8, (byte) 0x41, (byte) 0xce, (byte) 0x65, (byte) 0x8a, (byte) 0x5,
|
||||
(byte) 0xea, (byte) 0x83, (byte) 0xe1, (byte) 0xa7, (byte) 0x4b, (byte) 0x41, (byte) 0x56, (byte) 0x65,
|
||||
(byte) 0x2d, (byte) 0xbb, (byte) 0xb7, (byte) 0x7, (byte) 0x90, (byte) 0x12, (byte) 0x3c, (byte) 0x34,
|
||||
(byte) 0xc3, (byte) 0xa3, (byte) 0xd5, (byte) 0x26, (byte) 0xeb, (byte) 0x4c, (byte) 0x5b, (byte) 0x6c,
|
||||
(byte) 0x68, (byte) 0x73, (byte) 0xca, (byte) 0x33, (byte) 0xa4, (byte) 0xf0, (byte) 0xc0, (byte) 0x49,
|
||||
(byte) 0x25, (byte) 0x1f, (byte) 0x14, (byte) 0x41, (byte) 0x40, (byte) 0xd7, (byte) 0x53, (byte) 0x64,
|
||||
(byte) 0x22, (byte) 0x54, (byte) 0x79, (byte) 0x69, (byte) 0x4, (byte) 0xaf, (byte) 0x6, (byte) 0xa2,
|
||||
(byte) 0xe2, (byte) 0xfa, (byte) 0x53, (byte) 0xd7, (byte) 0x5d, (byte) 0x1a, (byte) 0x4, (byte) 0xd3,
|
||||
(byte) 0x85, (byte) 0xca, (byte) 0xff, (byte) 0xd9, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2,
|
||||
(byte) 0xa, (byte) 0x0, (byte) 0xa, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x37, (byte) 0xa4, (byte) 0x5c, (byte) 0x38, (byte) 0x52, (byte) 0x69, (byte) 0x4c, (byte) 0x69,
|
||||
(byte) 0x24, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x24, (byte) 0x6, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1b, (byte) 0x0, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x72, (byte) 0x65, (byte) 0x73, (byte) 0x2f, (byte) 0x64, (byte) 0x72,
|
||||
(byte) 0x61, (byte) 0x77, (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65, (byte) 0x2f, (byte) 0x73,
|
||||
(byte) 0x69, (byte) 0x7a, (byte) 0x65, (byte) 0x5f, (byte) 0x34, (byte) 0x38, (byte) 0x78, (byte) 0x34,
|
||||
(byte) 0x38, (byte) 0x2e, (byte) 0x6a, (byte) 0x70, (byte) 0x67, (byte) 0xfe, (byte) 0xca, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x64, (byte) 0x6, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Jar file created by Apache Commons-Compress which creates
|
||||
* a CEN entry with a Zip64 extra header entry with a size of 0
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x52b: Signature : 0x02014b50
|
||||
* 0x52f: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x530: Created OS : 0x3 [UNIX]
|
||||
* 0x531: VerMadeby : 0x32d [3, 4.5]
|
||||
* 0x532: VerExtract : 0x2d [4.5]
|
||||
* 0x533: Flag : 0x800
|
||||
* 0x535: Method : 0x0 [STORED]
|
||||
* 0x537: Last Mod Time : 0x570169c0 [Tue Aug 01 13:14:00 EDT 2023]
|
||||
* 0x53b: CRC : 0x0
|
||||
* 0x53f: Compressed Size : 0x0
|
||||
* 0x543: Uncompressed Size: 0x0
|
||||
* 0x547: Name Length : 0x9
|
||||
* 0x549: Extra Length : 0x8
|
||||
* [tag=0x0001, sz=0, data= ]
|
||||
* ->ZIP64:
|
||||
* [tag=0xcafe, sz=0, data= ]
|
||||
* ->[tag=cafe, size=0]
|
||||
* 0x54b: Comment Length : 0x0
|
||||
* 0x54d: Disk Start : 0x0
|
||||
* 0x54f: Attrs : 0x0
|
||||
* 0x551: AttrsEx : 0x41ed0010
|
||||
* 0x555: Loc Header Offset: 0x0
|
||||
* 0x559: File Name : META-INF/
|
||||
*/
|
||||
public static byte[] COMMONS_COMPRESS_JAR = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xc0, (byte) 0x69, (byte) 0x1, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x18, (byte) 0x0, (byte) 0x4d, (byte) 0x45,
|
||||
(byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0xbd, (byte) 0x69, (byte) 0x1, (byte) 0x57, (byte) 0x71, (byte) 0xa7, (byte) 0x16,
|
||||
(byte) 0x53, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54,
|
||||
(byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d, (byte) 0x41,
|
||||
(byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2e, (byte) 0x4d,
|
||||
(byte) 0x46, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x68, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5b, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xf3, (byte) 0x4d, (byte) 0xcc,
|
||||
(byte) 0xcb, (byte) 0x4c, (byte) 0x4b, (byte) 0x2d, (byte) 0x2e, (byte) 0xd1, (byte) 0xd, (byte) 0x4b,
|
||||
(byte) 0x2d, (byte) 0x2a, (byte) 0xce, (byte) 0xcc, (byte) 0xcf, (byte) 0xb3, (byte) 0x52, (byte) 0x30,
|
||||
(byte) 0xd4, (byte) 0x33, (byte) 0xe0, (byte) 0xe5, (byte) 0x72, (byte) 0xcc, (byte) 0x43, (byte) 0x12,
|
||||
(byte) 0x71, (byte) 0x2c, (byte) 0x48, (byte) 0x4c, (byte) 0xce, (byte) 0x48, (byte) 0x55, (byte) 0x0,
|
||||
(byte) 0x8a, (byte) 0x1, (byte) 0x25, (byte) 0xd, (byte) 0xd, (byte) 0xf4, (byte) 0x2c, (byte) 0x78,
|
||||
(byte) 0xb9, (byte) 0x9c, (byte) 0x8b, (byte) 0x52, (byte) 0x13, (byte) 0x4b, (byte) 0x52, (byte) 0x53,
|
||||
(byte) 0x74, (byte) 0x9d, (byte) 0x2a, (byte) 0x81, (byte) 0x1a, (byte) 0x2c, (byte) 0xf4, (byte) 0xc,
|
||||
(byte) 0xf4, (byte) 0x80, (byte) 0x12, (byte) 0xda, (byte) 0x46, (byte) 0xba, (byte) 0x66, (byte) 0xa,
|
||||
(byte) 0x1a, (byte) 0xfe, (byte) 0x45, (byte) 0x89, (byte) 0xc9, (byte) 0x39, (byte) 0xa9, (byte) 0xa,
|
||||
(byte) 0xce, (byte) 0xf9, (byte) 0x45, (byte) 0x5, (byte) 0xf9, (byte) 0x45, (byte) 0x89, (byte) 0x25,
|
||||
(byte) 0x40, (byte) 0x3, (byte) 0x34, (byte) 0x79, (byte) 0xb9, (byte) 0x78, (byte) 0xb9, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x61, (byte) 0x69, (byte) 0x1, (byte) 0x57, (byte) 0x16, (byte) 0x64,
|
||||
(byte) 0x9c, (byte) 0xc5, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x19, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x5a, (byte) 0x69,
|
||||
(byte) 0x70, (byte) 0x46, (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x50, (byte) 0x72, (byte) 0x6f,
|
||||
(byte) 0x70, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x79, (byte) 0x54, (byte) 0x65, (byte) 0x73,
|
||||
(byte) 0x74, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xf, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x85, (byte) 0x55, (byte) 0xcf, (byte) 0x53, (byte) 0xdb,
|
||||
(byte) 0x46, (byte) 0x14, (byte) 0xfe, (byte) 0xd6, (byte) 0x3f, (byte) 0x90, (byte) 0x2d, (byte) 0x8b,
|
||||
(byte) 0x38, (byte) 0x36, (byte) 0x21, (byte) 0xc1, (byte) 0x34, (byte) 0x4, (byte) 0x12, (byte) 0x70,
|
||||
(byte) 0x63, (byte) 0xb0, (byte) 0x8d, (byte) 0xdb, (byte) 0x42, (byte) 0xd3, (byte) 0x36, (byte) 0xa6,
|
||||
(byte) 0xf9, (byte) 0x45, (byte) 0x42, (byte) 0xb, (byte) 0x35, (byte) 0xe0, (byte) 0x62, (byte) 0x87,
|
||||
(byte) 0xd4, (byte) 0xa4, (byte) 0x6d, (byte) 0x22, (byte) 0xdb, (byte) 0x4a, (byte) 0x22, (byte) 0x2a,
|
||||
(byte) 0x4b, (byte) 0x1a, (byte) 0x49, (byte) 0x2e, (byte) 0x49, (byte) 0x67, (byte) 0x7a, (byte) 0xe8,
|
||||
(byte) 0x4c, (byte) 0xcf, (byte) 0x9d, (byte) 0x69, (byte) 0xfe, (byte) 0x82, (byte) 0xde, (byte) 0x38,
|
||||
(byte) 0xf5, (byte) 0x40, (byte) 0xe, (byte) 0x86, (byte) 0x94, (byte) 0x49, (byte) 0x73, (byte) 0xcb,
|
||||
(byte) 0x21, (byte) 0xff, (byte) 0x51, (byte) 0x2f, (byte) 0xa5, (byte) 0x6f, (byte) 0x25, (byte) 0xc0,
|
||||
(byte) 0x86, (byte) 0x98, (byte) 0x29, (byte) 0xcc, (byte) 0x68, (byte) 0x77, (byte) 0xdf, (byte) 0xee,
|
||||
(byte) 0xf7, (byte) 0xbd, (byte) 0xf7, (byte) 0xbe, (byte) 0xf7, (byte) 0x76, (byte) 0xfd, (byte) 0xf6,
|
||||
(byte) 0xdf, (byte) 0xbf, (byte) 0xfe, (byte) 0x6, (byte) 0x70, (byte) 0xb, (byte) 0xf, (byte) 0x45,
|
||||
(byte) 0xf8, (byte) 0xe0, (byte) 0x17, (byte) 0x10, (byte) 0x90, (byte) 0x10, (byte) 0x44, (byte) 0xf,
|
||||
(byte) 0xc3, (byte) 0xe9, (byte) 0x75, (byte) 0xf9, (byte) 0x47, (byte) 0x39, (byte) 0xa7, (byte) 0xc9,
|
||||
(byte) 0xfa, (byte) 0xe3, (byte) 0xdc, (byte) 0x72, (byte) 0x75, (byte) 0x5d, (byte) 0xa9, (byte) 0x39,
|
||||
(byte) 0xc, (byte) 0x3d, (byte) 0x33, (byte) 0xaa, (byte) 0xae, (byte) 0x3a, (byte) 0xd7, (byte) 0x18,
|
||||
(byte) 0xfc, (byte) 0xa9, (byte) 0xf1, (byte) 0x55, (byte) 0x1, (byte) 0x21, (byte) 0x86, (byte) 0xbe,
|
||||
(byte) 0x35, (byte) 0xd5, (byte) 0x9c, (byte) 0x53, (byte) 0x35, (byte) 0xa5, (byte) 0x68, (byte) 0x19,
|
||||
(byte) 0xa6, (byte) 0x62, (byte) 0x39, (byte) 0xcf, (byte) 0xca, (byte) 0x8a, (byte) 0xed, (byte) 0x88,
|
||||
(byte) 0x10, (byte) 0xe0, (byte) 0xe7, (byte) 0x9f, (byte) 0x88, (byte) 0x4, (byte) 0x89, (byte) 0x33,
|
||||
(byte) 0x9d, (byte) 0xb2, (byte) 0x14, (byte) 0xb9, (byte) 0x5e, (byte) 0x52, (byte) 0xf5, (byte) 0xc7,
|
||||
(byte) 0x9a, (byte) 0xc2, (byte) 0xcf, (byte) 0xa, (byte) 0x38, (byte) 0xc5, (byte) 0xd0, (byte) 0xef,
|
||||
(byte) 0xb2, (byte) 0x37, (byte) 0x1d, (byte) 0x55, (byte) 0xcb, (byte) 0xfd, (byte) 0xa4, (byte) 0x9a,
|
||||
(byte) 0xb9, (byte) 0x7d, (byte) 0x9a, (byte) 0x10, (byte) 0x4e, (byte) 0x33, (byte) 0x64, (byte) 0x72,
|
||||
(byte) 0x77, (byte) 0x6d, (byte) 0xc5, (byte) 0xb2, (byte) 0x73, (byte) 0xda, (byte) 0xba, (byte) 0xac,
|
||||
(byte) 0xd7, (byte) 0xf9, (byte) 0xe4, (byte) 0xb6, (byte) 0xb1, (byte) 0xa1, (byte) 0x6b, (byte) 0x86,
|
||||
(byte) 0x5c, (byte) 0xb7, (byte) 0x73, (byte) 0x1b, (byte) 0xb5, (byte) 0x29, (byte) 0xab, (byte) 0x6e,
|
||||
(byte) 0xca, (byte) 0xe4, (byte) 0x48, (byte) 0x53, (byte) 0xab, (byte) 0xf6, (byte) 0xe4, (byte) 0xba,
|
||||
(byte) 0x6c, (byte) 0x89, (byte) 0xe8, (byte) 0x45, (byte) 0x9c, (byte) 0x47, (byte) 0xdc, (byte) 0x47,
|
||||
(byte) 0x9c, (byte) 0xa9, (byte) 0x42, (byte) 0x3b, (byte) 0xe6, (byte) 0x92, (byte) 0x63, (byte) 0x91,
|
||||
(byte) 0xc7, (byte) 0xfc, (byte) 0xf8, (byte) 0x6a, (byte) 0x18, (byte) 0xfd, (byte) 0x38, (byte) 0x2b,
|
||||
(byte) 0xe0, (byte) 0x9c, (byte) 0x84, (byte) 0x1, (byte) 0x24, (byte) 0x8e, (byte) 0xa4, (byte) 0x55,
|
||||
(byte) 0x7a, (byte) 0x66, (byte) 0x3b, (byte) 0x4a, (byte) 0x83, (byte) 0xb2, (byte) 0x31, (byte) 0x9a,
|
||||
(byte) 0x94, (byte) 0x5c, (byte) 0xbf, (byte) 0x7, (byte) 0x56, (byte) 0x8d, (byte) 0x5c, (byte) 0x91,
|
||||
(byte) 0x90, (byte) 0xe, (byte) 0xe1, (byte) 0x15, (byte) 0xb9, (byte) 0x91, (byte) 0xf, (byte) 0xe1,
|
||||
(byte) 0x3d, (byte) 0xc2, (byte) 0xf0, (byte) 0xd8, (byte) 0x46, (byte) 0x92, (byte) 0xf6, (byte) 0x8,
|
||||
(byte) 0x25, (byte) 0xa9, (byte) 0x2b, (byte) 0xf5, (byte) 0xa4, (byte) 0x2e, (byte) 0x62, (byte) 0x8,
|
||||
(byte) 0x17, (byte) 0x4, (byte) 0xc, (byte) 0x4b, (byte) 0x18, (byte) 0xc1, (byte) 0x45, (byte) 0x52,
|
||||
(byte) 0xa1, (byte) 0xb, (byte) 0x92, (byte) 0xd4, (byte) 0x32, (byte) 0xf9, (byte) 0xea, (byte) 0x11,
|
||||
(byte) 0xc3, (byte) 0x4c, (byte) 0x97, (byte) 0xb8, (byte) 0xee, (byte) 0x17, (byte) 0x8e, (byte) 0xcb,
|
||||
(byte) 0x9b, (byte) 0x1f, (byte) 0xef, (byte) 0x1a, (byte) 0x0, (byte) 0x4f, (byte) 0x70, (byte) 0x54,
|
||||
(byte) 0xc2, (byte) 0x18, (byte) 0x17, (byte) 0x32, (byte) 0x58, (byte) 0xd3, (byte) 0xc, (byte) 0x9b,
|
||||
(byte) 0xf4, (byte) 0x7b, (byte) 0xff, (byte) 0xc0, (byte) 0xa5, (byte) 0xb, (byte) 0x2f, (byte) 0x3f,
|
||||
(byte) 0xb1, (byte) 0x8c, (byte) 0xd, (byte) 0xb9, (byte) 0xaa, (byte) 0x29, (byte) 0x22, (byte) 0x92,
|
||||
(byte) 0x48, (byte) 0x49, (byte) 0x18, (byte) 0xc7, (byte) 0x4, (byte) 0x43, (byte) 0xaf, (byte) 0x5c,
|
||||
(byte) 0xaf, (byte) 0x97, (byte) 0x9a, (byte) 0xa6, (byte) 0x69, (byte) 0x29, (byte) 0xb6, (byte) 0xad,
|
||||
(byte) 0xd4, (byte) 0x19, (byte) 0x6, (byte) 0x3a, (byte) 0x63, (byte) 0x38, (byte) 0x44, (byte) 0xe4,
|
||||
(byte) 0x79, (byte) 0x19, (byte) 0x33, (byte) 0x1d, (byte) 0x9, (byte) 0xcc, (byte) 0x2f, (byte) 0xdf,
|
||||
(byte) 0x79, (byte) 0x5a, (byte) 0x53, (byte) 0x4c, (byte) 0x47, (byte) 0x35, (byte) 0x74, (byte) 0x1,
|
||||
(byte) 0x93, (byte) 0xc, (byte) 0x83, (byte) 0x6d, (byte) 0xd0, (byte) 0x4a, (byte) 0x53, (byte) 0x77,
|
||||
(byte) 0xd4, (byte) 0x86, (byte) 0x72, (byte) 0xb8, (byte) 0x2f, (byte) 0x22, (byte) 0x8b, (byte) 0xf,
|
||||
(byte) 0xb8, (byte) 0xf2, (byte) 0x13, (byte) 0x2, (byte) 0x3e, (byte) 0x3a, (byte) 0xaa, (byte) 0xab,
|
||||
(byte) 0x9b, (byte) 0x62, (byte) 0x4, (byte) 0xd3, (byte) 0xf8, (byte) 0x58, (byte) 0xc0, (byte) 0x15,
|
||||
(byte) 0x9, (byte) 0x9f, (byte) 0xe0, (byte) 0x53, (byte) 0x86, (byte) 0xb8, (byte) 0xbb, (byte) 0xaf,
|
||||
(byte) 0x93, (byte) 0x8f, (byte) 0x47, (byte) 0x24, (byte) 0x66, (byte) 0xae, (byte) 0x28, (byte) 0x3b,
|
||||
(byte) 0x4f, (byte) 0x18, (byte) 0x7c, (byte) 0x6, (byte) 0xc9, (byte) 0x93, (byte) 0xff, (byte) 0x1f,
|
||||
(byte) 0x79, (byte) 0xe, (byte) 0x2a, (byte) 0x59, (byte) 0x78, (byte) 0x97, (byte) 0x21, (byte) 0x1f,
|
||||
(byte) 0xc1, (byte) 0x55, (byte) 0xe4, (byte) 0x5, (byte) 0xcc, (byte) 0x70, (byte) 0x27, (byte) 0x9f,
|
||||
(byte) 0x53, (byte) 0xd6, (byte) 0xed, (byte) 0xae, (byte) 0x5a, (byte) 0x94, (byte) 0x4d, (byte) 0x86,
|
||||
(byte) 0x58, (byte) 0x6a, (byte) 0x1f, (byte) 0x75, (byte) 0x60, (byte) 0x22, (byte) 0x39, (byte) 0xaf,
|
||||
(byte) 0xe3, (byte) 0x86, (byte) 0x80, (byte) 0x9b, (byte) 0x12, (byte) 0x75, (byte) 0xfc, (byte) 0x2c,
|
||||
(byte) 0x43, (byte) 0xe2, (byte) 0x28, (byte) 0x27, (byte) 0xaf, (byte) 0xb3, (byte) 0xd7, (byte) 0x15,
|
||||
(byte) 0x36, (byte) 0x91, (byte) 0xe9, (byte) 0xca, (byte) 0x46, (byte) 0xdb, (byte) 0xc0, (byte) 0x70,
|
||||
(byte) 0x3d, (byte) 0xd5, (byte) 0x2d, (byte) 0x82, (byte) 0x63, (byte) 0xfc, (byte) 0xc7, (byte) 0xa3,
|
||||
(byte) 0x6c, (byte) 0x13, (byte) 0x50, (byte) 0x2b, (byte) 0xdd, (byte) 0x61, (byte) 0x88, (byte) 0x74,
|
||||
(byte) 0x74, (byte) 0x11, (byte) 0x57, (byte) 0xe8, (byte) 0xb, (byte) 0x9, (byte) 0x5f, (byte) 0x62,
|
||||
(byte) 0x9e, (byte) 0xee, (byte) 0x88, (byte) 0x63, (byte) 0xdc, (byte) 0xac, (byte) 0xda, (byte) 0x86,
|
||||
(byte) 0xd6, (byte) 0x74, (byte) 0x14, (byte) 0x4f, (byte) 0x9a, (byte) 0xb3, (byte) 0xa9, (byte) 0x13,
|
||||
(byte) 0x12, (byte) 0x9e, (byte) 0xc6, (byte) 0x57, (byte) 0x12, (byte) 0xa, (byte) 0x58, (byte) 0x64,
|
||||
(byte) 0x8, (byte) 0x39, (byte) 0x86, (byte) 0xa7, (byte) 0xd, (byte) 0xc3, (byte) 0x99, (byte) 0x83,
|
||||
(byte) 0xd3, (byte) 0x9d, (byte) 0x8a, (byte) 0x89, (byte) 0x58, (byte) 0xc6, (byte) 0xa8, (byte) 0x80,
|
||||
(byte) 0x22, (byte) 0x55, (byte) 0xff, (byte) 0xa4, (byte) 0xa0, (byte) 0x42, (byte) 0x58, (byte) 0xa1,
|
||||
(byte) 0x22, (byte) 0x27, (byte) 0x75, (byte) 0xfe, (byte) 0x3f, (byte) 0x46, (byte) 0x7f, (byte) 0xbc,
|
||||
(byte) 0xc9, (byte) 0x97, (byte) 0x96, (byte) 0xcb, (byte) 0x1d, (byte) 0x8d, (byte) 0x9e, (byte) 0x46,
|
||||
(byte) 0x59, (byte) 0xc2, (byte) 0x5d, (byte) 0xde, (byte) 0x7d, (byte) 0x51, (byte) 0xd3, (byte) 0x6b,
|
||||
(byte) 0x4b, (byte) 0xb9, (byte) 0xf6, (byte) 0x43, (byte) 0xd9, (byte) 0x92, (byte) 0x6b, (byte) 0xa,
|
||||
(byte) 0x5, (byte) 0xb0, (byte) 0x36, (byte) 0x5f, (byte) 0x7c, (byte) 0x30, (byte) 0x37, (byte) 0x5f,
|
||||
(byte) 0xa0, (byte) 0xbc, (byte) 0xe2, (byte) 0xef, (byte) 0xba, (byte) 0x27, (byte) 0x5, (byte) 0x67,
|
||||
(byte) 0xd, (byte) 0xdd, (byte) 0x76, (byte) 0x64, (byte) 0xdd, (byte) 0x59, (byte) 0x95, (byte) 0xb5,
|
||||
(byte) 0x26, (byte) 0x9d, (byte) 0xf, (byte) 0xcc, (byte) 0x1a, (byte) 0x75, (byte) 0x1a, (byte) 0xa2,
|
||||
(byte) 0x5, (byte) 0x55, (byte) 0x57, (byte) 0x96, (byte) 0x9a, (byte) 0x8d, (byte) 0xaa, (byte) 0x62,
|
||||
(byte) 0x95, (byte) 0x79, (byte) 0x17, (byte) 0xd2, (byte) 0x46, (byte) 0x43, (byte) 0x56, (byte) 0x75,
|
||||
(byte) 0x9e, (byte) 0x73, (byte) 0xb7, (byte) 0xba, (byte) 0xaf, (byte) 0x12, (byte) 0x91, (byte) 0xeb,
|
||||
(byte) 0x95, (byte) 0xf4, (byte) 0xdd, (byte) 0x3f, (byte) 0x2f, (byte) 0x96, (byte) 0x8c, (byte) 0xa6,
|
||||
(byte) 0x55, (byte) 0x73, (byte) 0x5f, (byte) 0x13, (byte) 0x4a, (byte) 0xae, (byte) 0xcb, (byte) 0x1b,
|
||||
(byte) 0x34, (byte) 0xc9, (byte) 0x69, (byte) 0x70, (byte) 0x91, (byte) 0x1e, (byte) 0x21, (byte) 0x1f,
|
||||
(byte) 0x3d, (byte) 0x6e, (byte) 0x54, (byte) 0x67, (byte) 0xac, (byte) 0xe2, (byte) 0x1e, (byte) 0x8d,
|
||||
(byte) 0xdf, (byte) 0xd0, (byte) 0xca, (byte) 0x87, (byte) 0x28, (byte) 0xfc, (byte) 0x34, (byte) 0xa7,
|
||||
(byte) 0x57, (byte) 0x8e, (byte) 0xbe, (byte) 0x15, (byte) 0xb2, (byte) 0xc, (byte) 0xd1, (byte) 0xc8,
|
||||
(byte) 0x68, (byte) 0xc, (byte) 0x4e, (byte) 0x6c, (byte) 0x83, (byte) 0x6d, (byte) 0xb9, (byte) 0x80,
|
||||
(byte) 0x35, (byte) 0xfa, (byte) 0xf6, (byte) 0xb8, (byte) 0xc6, (byte) 0x10, (byte) 0xc2, (byte) 0xb8,
|
||||
(byte) 0x8f, (byte) 0x6f, (byte) 0xf7, (byte) 0x8f, (byte) 0x5e, (byte) 0x26, (byte) 0x38, (byte) 0xb7,
|
||||
(byte) 0x46, (byte) 0x76, (byte) 0x21, (byte) 0x54, (byte) 0xb6, (byte) 0x11, (byte) 0x6e, (byte) 0x41,
|
||||
(byte) 0x6c, (byte) 0x3, (byte) 0x44, (byte) 0xd7, (byte) 0x9b, (byte) 0x4, (byte) 0x7e, (byte) 0x67,
|
||||
(byte) 0x7d, (byte) 0xfc, (byte) 0xed, (byte) 0xf3, (byte) 0x40, (byte) 0xec, (byte) 0xf, (byte) 0x9a,
|
||||
(byte) 0x5, (byte) 0x69, (byte) 0xe7, (byte) 0xc5, (byte) 0x2e, (byte) 0x7a, (byte) 0x2b, (byte) 0xf1,
|
||||
(byte) 0xe8, (byte) 0x36, (byte) 0x62, (byte) 0x85, (byte) 0x17, (byte) 0x38, (byte) 0x13, (byte) 0x1f,
|
||||
(byte) 0xc, (byte) 0xbc, (byte) 0x82, (byte) 0xaf, (byte) 0xe2, (byte) 0x8f, (byte) 0x47, (byte) 0x4b,
|
||||
(byte) 0x2d, (byte) 0x9c, (byte) 0xbf, (byte) 0x97, (byte) 0x6e, (byte) 0xe1, (byte) 0xd2, (byte) 0x26,
|
||||
(byte) 0xfa, (byte) 0x16, (byte) 0xbd, (byte) 0x31, (byte) 0xbc, (byte) 0x94, (byte) 0xc9, (byte) 0xb6,
|
||||
(byte) 0x70, (byte) 0x39, (byte) 0xf3, (byte) 0x7a, (byte) 0x13, (byte) 0xbd, (byte) 0x85, (byte) 0x5d,
|
||||
(byte) 0x64, (byte) 0x2b, (byte) 0xe9, (byte) 0x6d, (byte) 0xe4, (byte) 0x5e, (byte) 0xc7, (byte) 0xa3,
|
||||
(byte) 0xfe, (byte) 0x57, (byte) 0xf8, (byte) 0x70, (byte) 0x7, (byte) 0x53, (byte) 0x85, (byte) 0xf4,
|
||||
(byte) 0xe, (byte) 0x3e, (byte) 0xdb, (byte) 0xc1, (byte) 0xb5, (byte) 0x45, (byte) 0xce, (byte) 0x73,
|
||||
(byte) 0xdb, (byte) 0xe3, (byte) 0x49, (byte) 0xbf, (byte) 0xc4, (byte) 0x1c, (byte) 0xc3, (byte) 0x4b,
|
||||
(byte) 0x2c, (byte) 0x30, (byte) 0xb8, (byte) 0x84, (byte) 0x99, (byte) 0x37, (byte) 0x18, (byte) 0xc9,
|
||||
(byte) 0xb4, (byte) 0xb0, (byte) 0xb4, (byte) 0x89, (byte) 0xc4, (byte) 0x12, (byte) 0xcd, (byte) 0xe3,
|
||||
(byte) 0xde, (byte) 0x3c, (byte) 0x72, (byte) 0x35, (byte) 0x90, (byte) 0x4d, (byte) 0x4, (byte) 0x88,
|
||||
(byte) 0x3a, (byte) 0x4b, (byte) 0xd4, (byte) 0xa3, (byte) 0x2e, (byte) 0xfe, (byte) 0xeb, (byte) 0x13,
|
||||
(byte) 0xf0, (byte) 0x2d, (byte) 0x94, (byte) 0xb6, (byte) 0x28, (byte) 0x72, (byte) 0x11, (byte) 0xe7,
|
||||
(byte) 0x31, (byte) 0x4a, (byte) 0x4f, (byte) 0xcb, (byte) 0x18, (byte) 0x52, (byte) 0xd4, (byte) 0xd,
|
||||
(byte) 0x49, (byte) 0xca, (byte) 0x63, (byte) 0xa, (byte) 0x57, (byte) 0x68, (byte) 0xb6, (byte) 0x82,
|
||||
(byte) 0x6, (byte) 0x9e, (byte) 0xd2, (byte) 0xfa, (byte) 0x67, (byte) 0xfc, (byte) 0x82, (byte) 0x5f,
|
||||
(byte) 0x69, (byte) 0x5c, (byte) 0xc0, (byte) 0x6f, (byte) 0xf8, (byte) 0x9d, (byte) 0xec, (byte) 0x3e,
|
||||
(byte) 0x57, (byte) 0x8b, (byte) 0x39, (byte) 0xc4, (byte) 0xe8, (byte) 0x1b, (byte) 0x23, (byte) 0xf4,
|
||||
(byte) 0x39, (byte) 0xc2, (byte) 0xf, (byte) 0x10, (byte) 0x43, (byte) 0x8c, (byte) 0x70, (byte) 0x83,
|
||||
(byte) 0x84, (byte) 0x1c, (byte) 0xa0, (byte) 0xbb, (byte) 0x9a, (byte) 0xc0, (byte) 0xd, (byte) 0xb2,
|
||||
(byte) 0x2e, (byte) 0x90, (byte) 0xf2, (byte) 0x2b, (byte) 0xb8, (byte) 0x40, (byte) 0x3c, (byte) 0xc3,
|
||||
(byte) 0xc4, (byte) 0x34, (byte) 0x44, (byte) 0xf8, (byte) 0x4b, (byte) 0xc4, (byte) 0x30, (byte) 0x8c,
|
||||
(byte) 0xe7, (byte) 0xf4, (byte) 0xac, (byte) 0xfe, (byte) 0x49, (byte) 0xd5, (byte) 0xdb, (byte) 0x22,
|
||||
(byte) 0xd4, (byte) 0x77, (byte) 0xc4, (byte) 0xf2, (byte) 0x10, (byte) 0xd2, (byte) 0x1e, (byte) 0x4d,
|
||||
(byte) 0x7d, (byte) 0x2, (byte) 0x4, (byte) 0x81, (byte) 0xa4, (byte) 0x65, (byte) 0x2, (byte) 0x92,
|
||||
(byte) 0x7b, (byte) 0xfc, (byte) 0x47, (byte) 0xc6, (byte) 0x5b, (byte) 0xd3, (byte) 0xca, (byte) 0x35,
|
||||
(byte) 0x5, (byte) 0xff, (byte) 0x1, (byte) 0xbb, (byte) 0x25, (byte) 0x20, (byte) 0x1d, (byte) 0xde,
|
||||
(byte) 0x23, (byte) 0x7, (byte) 0xde, (byte) 0xde, (byte) 0xb4, (byte) 0x40, (byte) 0x57, (byte) 0xc0,
|
||||
(byte) 0x3b, (byte) 0x1e, (byte) 0x41, (byte) 0xe0, (byte) 0xd0, (byte) 0x74, (byte) 0x80, (byte) 0x10,
|
||||
(byte) 0xf6, (byte) 0x11, (byte) 0xc3, (byte) 0x54, (byte) 0xa7, (byte) 0xef, (byte) 0xdd, (byte) 0xce,
|
||||
(byte) 0x78, (byte) 0xf0, (byte) 0x1f, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d,
|
||||
(byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0xc0,
|
||||
(byte) 0x69, (byte) 0x1, (byte) 0x57, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x9,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xed, (byte) 0x41, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e,
|
||||
(byte) 0x46, (byte) 0x2f, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xfe, (byte) 0xca,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3,
|
||||
(byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xbd, (byte) 0x69,
|
||||
(byte) 0x1, (byte) 0x57, (byte) 0x71, (byte) 0xa7, (byte) 0x16, (byte) 0x53, (byte) 0x5b, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x68, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x14, (byte) 0x0,
|
||||
(byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xa4, (byte) 0x81, (byte) 0x3f, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46,
|
||||
(byte) 0x2f, (byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53,
|
||||
(byte) 0x54, (byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3, (byte) 0x2d, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x61, (byte) 0x69, (byte) 0x1, (byte) 0x57,
|
||||
(byte) 0x16, (byte) 0x64, (byte) 0x9c, (byte) 0xc5, (byte) 0x0, (byte) 0x4, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xf, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x19, (byte) 0x0, (byte) 0x4, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xa4, (byte) 0x81, (byte) 0xe0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5a, (byte) 0x69,
|
||||
(byte) 0x70, (byte) 0x46, (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x50, (byte) 0x72, (byte) 0x6f,
|
||||
(byte) 0x70, (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x79, (byte) 0x54, (byte) 0x65, (byte) 0x73,
|
||||
(byte) 0x74, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x6, (byte) 0x6, (byte) 0x2c,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2d,
|
||||
(byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xd0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2b, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x6, (byte) 0x7, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xfb, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3,
|
||||
(byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0xd0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2b,
|
||||
(byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Jar file created by Ant specifying zip64mode="always" and createUnicodeExtraFields="always"
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x51b: Signature : 0x02014b50
|
||||
* 0x51f: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x520: Created OS : 0x3 [UNIX]
|
||||
* 0x521: VerMadeby : 0x32d [3, 4.5]
|
||||
* 0x522: VerExtract : 0x2d [4.5]
|
||||
* 0x523: Flag : 0x800
|
||||
* 0x525: Method : 0x8 [DEFLATED]
|
||||
* 0x527: Last Mod Time : 0x570b3767 [Fri Aug 11 06:59:14 EDT 2023]
|
||||
* 0x52b: CRC : 0x5e4fa53f
|
||||
* 0x52f: Compressed Size : 0xffffffff
|
||||
* 0x533: Uncompressed Size: 0xffffffff
|
||||
* 0x537: Name Length : 0x10
|
||||
* 0x539: Extra Length : 0x35
|
||||
* Extra data:[01, 00, 18, 00, 87, 04, 00, 00, 00, 00, 00, 00, c7, 02, 00, 00, 00, 00, 00, 00, 15, 01, 00, 00, 00, 00, 00, 00, 75, 70, 15, 00, 01, 94, 82, 60, 61, 52, 65, 61, 64, 41, 6e, 74, 4a, 61, 72, 2e, 63, 6c, 61, 73, 73]
|
||||
* [tag=0x0001, sz=24]
|
||||
* ->ZIP64: size *0x487 csize *0x2c7 LOC Off *0x115
|
||||
* [data= 87 04 00 00 00 00 00 00 c7 02 00 00 00 00 00 00 15 01 00 00 00 00 00 00 ]
|
||||
* [tag=0x7075, sz=21]
|
||||
* ->[Unknown tag]
|
||||
* [data= 01 94 82 60 61 52 65 61 64 41 6e 74 4a 61 72 2e 63 6c 61 73 73 ]
|
||||
* 0x53b: Comment Length : 0x0
|
||||
* 0x53d: Disk Start : 0x0
|
||||
* 0x53f: Attrs : 0x0
|
||||
* 0x541: AttrsEx : 0x81a40000
|
||||
* 0x545: Loc Header Offset: 0xffffffff
|
||||
* 0x549: File Name : ReadAntJar.class
|
||||
*/
|
||||
public static byte[] ANT_ZIP64_UNICODE_EXTRA_JAR = {
|
||||
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x18, (byte) 0x7e, (byte) 0xe, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x2a, (byte) 0x0, (byte) 0x4d, (byte) 0x45,
|
||||
(byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x75,
|
||||
(byte) 0x70, (byte) 0xe, (byte) 0x0, (byte) 0x1, (byte) 0x8, (byte) 0xa1, (byte) 0x8c, (byte) 0x13,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46,
|
||||
(byte) 0x2f, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x17, (byte) 0x7e, (byte) 0xe, (byte) 0x57, (byte) 0x31,
|
||||
(byte) 0x59, (byte) 0x76, (byte) 0x4d, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x14, (byte) 0x0, (byte) 0x31, (byte) 0x0, (byte) 0x4d,
|
||||
(byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54,
|
||||
(byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x6e,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x61,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75,
|
||||
(byte) 0x70, (byte) 0x19, (byte) 0x0, (byte) 0x1, (byte) 0x85, (byte) 0x85, (byte) 0x84, (byte) 0x2,
|
||||
(byte) 0x4d, (byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46,
|
||||
(byte) 0x2f, (byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53,
|
||||
(byte) 0x54, (byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0xf3, (byte) 0x4d, (byte) 0xcc, (byte) 0xcb,
|
||||
(byte) 0x4c, (byte) 0x4b, (byte) 0x2d, (byte) 0x2e, (byte) 0xd1, (byte) 0xd, (byte) 0x4b, (byte) 0x2d,
|
||||
(byte) 0x2a, (byte) 0xce, (byte) 0xcc, (byte) 0xcf, (byte) 0xb3, (byte) 0x52, (byte) 0x30, (byte) 0xd4,
|
||||
(byte) 0x33, (byte) 0xe0, (byte) 0xe5, (byte) 0x72, (byte) 0xcc, (byte) 0x43, (byte) 0x12, (byte) 0x71,
|
||||
(byte) 0x2c, (byte) 0x48, (byte) 0x4c, (byte) 0xce, (byte) 0x48, (byte) 0x55, (byte) 0x0, (byte) 0x8a,
|
||||
(byte) 0x1, (byte) 0x25, (byte) 0xd, (byte) 0xd, (byte) 0xf4, (byte) 0xc, (byte) 0x4d, (byte) 0x12,
|
||||
(byte) 0x73, (byte) 0xa, (byte) 0x32, (byte) 0x12, (byte) 0x79, (byte) 0xb9, (byte) 0x9c, (byte) 0x8b,
|
||||
(byte) 0x52, (byte) 0x13, (byte) 0x4b, (byte) 0x52, (byte) 0x53, (byte) 0x74, (byte) 0x9d, (byte) 0x2a,
|
||||
(byte) 0x81, (byte) 0xda, (byte) 0x2c, (byte) 0xf4, (byte) 0x80, (byte) 0x32, (byte) 0x7a, (byte) 0x86,
|
||||
(byte) 0xda, (byte) 0x46, (byte) 0xba, (byte) 0x66, (byte) 0xa, (byte) 0x1a, (byte) 0xfe, (byte) 0x45,
|
||||
(byte) 0x89, (byte) 0xc9, (byte) 0x39, (byte) 0xa9, (byte) 0xa, (byte) 0xce, (byte) 0xf9, (byte) 0x45,
|
||||
(byte) 0x5, (byte) 0xf9, (byte) 0x45, (byte) 0x89, (byte) 0x25, (byte) 0x40, (byte) 0x63, (byte) 0x34,
|
||||
(byte) 0x79, (byte) 0xb9, (byte) 0x78, (byte) 0xb9, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3,
|
||||
(byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x67,
|
||||
(byte) 0x37, (byte) 0xb, (byte) 0x57, (byte) 0x3f, (byte) 0xa5, (byte) 0x4f, (byte) 0x5e, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x10,
|
||||
(byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x41,
|
||||
(byte) 0x6e, (byte) 0x74, (byte) 0x4a, (byte) 0x61, (byte) 0x72, (byte) 0x2e, (byte) 0x63, (byte) 0x6c,
|
||||
(byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x87,
|
||||
(byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc7,
|
||||
(byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75,
|
||||
(byte) 0x70, (byte) 0x15, (byte) 0x0, (byte) 0x1, (byte) 0x94, (byte) 0x82, (byte) 0x60, (byte) 0x61,
|
||||
(byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x41, (byte) 0x6e, (byte) 0x74, (byte) 0x4a,
|
||||
(byte) 0x61, (byte) 0x72, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73,
|
||||
(byte) 0x75, (byte) 0x53, (byte) 0x5b, (byte) 0x57, (byte) 0x12, (byte) 0x51, (byte) 0x18, (byte) 0xdd,
|
||||
(byte) 0x3, (byte) 0xc3, (byte) 0x1c, (byte) 0x18, (byte) 0x47, (byte) 0x41, (byte) 0xcc, (byte) 0xb,
|
||||
(byte) 0x96, (byte) 0x89, (byte) 0x25, (byte) 0x89, (byte) 0x17, (byte) 0xa0, (byte) 0x8b, (byte) 0x76,
|
||||
(byte) 0x41, (byte) 0x33, (byte) 0xab, (byte) 0x95, (byte) 0x99, (byte) 0x21, (byte) 0xb4, (byte) 0x84,
|
||||
(byte) 0x65, (byte) 0x8b, (byte) 0x7a, (byte) 0x1a, (byte) 0x61, (byte) 0xb2, (byte) 0x51, (byte) 0x98,
|
||||
(byte) 0x99, (byte) 0x35, (byte) 0xc, (byte) 0x76, (byte) 0x79, (byte) 0xea, (byte) 0xa1, (byte) 0x7e,
|
||||
(byte) 0x8b, (byte) 0xcf, (byte) 0xf6, (byte) 0x80, (byte) 0x6b, (byte) 0xe5, (byte) 0x2a, (byte) 0xdf,
|
||||
(byte) 0x7c, (byte) 0xe8, (byte) 0x47, (byte) 0x65, (byte) 0xdf, (byte) 0x19, (byte) 0x50, (byte) 0xb0,
|
||||
(byte) 0x65, (byte) 0x33, (byte) 0x8b, (byte) 0xef, (byte) 0x70, (byte) 0xbe, (byte) 0xb3, (byte) 0xf7,
|
||||
(byte) 0xfe, (byte) 0x6e, (byte) 0x73, (byte) 0x7e, (byte) 0xff, (byte) 0xf9, (byte) 0xf1, (byte) 0xb,
|
||||
(byte) 0xc0, (byte) 0x2c, (byte) 0x1e, (byte) 0xc9, (byte) 0x90, (byte) 0x31, (byte) 0xc6, (byte) 0x70,
|
||||
(byte) 0x4d, (byte) 0x86, (byte) 0x7, (byte) 0x63, (byte) 0xdc, (byte) 0x5c, (byte) 0xf7, (byte) 0x63,
|
||||
(byte) 0x9c, (byte) 0x21, (byte) 0x26, (byte) 0x43, (byte) 0xc2, (byte) 0x8d, (byte) 0x0, (byte) 0x26,
|
||||
(byte) 0x10, (byte) 0xf7, (byte) 0x63, (byte) 0x92, (byte) 0x61, (byte) 0x4a, (byte) 0xc6, (byte) 0x34,
|
||||
(byte) 0x66, (byte) 0xb8, (byte) 0x33, (byte) 0xc1, (byte) 0x90, (byte) 0x94, (byte) 0xd1, (byte) 0x8d,
|
||||
(byte) 0x14, (byte) 0xc3, (byte) 0x4d, (byte) 0x3f, (byte) 0x6e, (byte) 0xc9, (byte) 0x8, (byte) 0xe2,
|
||||
(byte) 0xb6, (byte) 0x0, (byte) 0x69, (byte) 0x41, (byte) 0x37, (byte) 0x74, (byte) 0x67, (byte) 0x51,
|
||||
(byte) 0x80, (byte) 0x37, (byte) 0x3e, (byte) 0xb9, (byte) 0x21, (byte) 0x40, (byte) 0x7c, (byte) 0x6a,
|
||||
(byte) 0x96, (byte) 0x35, (byte) 0x1, (byte) 0xc1, (byte) 0x8c, (byte) 0x6e, (byte) 0x68, (byte) 0xd9,
|
||||
(byte) 0x7a, (byte) 0x75, (byte) 0x53, (byte) 0xb3, (byte) 0xb, (byte) 0xea, (byte) 0x66, (byte) 0x85,
|
||||
(byte) 0x3c, (byte) 0x62, (byte) 0x55, (byte) 0xd5, (byte) 0xd, (byte) 0x1, (byte) 0x3, (byte) 0xf1,
|
||||
(byte) 0xb7, (byte) 0x99, (byte) 0x6d, (byte) 0x75, (byte) 0x57, (byte) 0x4d, (byte) 0x55, (byte) 0x54,
|
||||
(byte) 0x63, (byte) 0x2b, (byte) 0x95, (byte) 0x77, (byte) 0x6c, (byte) 0xdd, (byte) 0xd8, (byte) 0x9a,
|
||||
(byte) 0xe7, (byte) 0x44, (byte) 0xbf, (byte) 0xad, (byte) 0xa9, (byte) 0xe5, (byte) 0x55, (byte) 0xd5,
|
||||
(byte) 0xae, (byte) 0x9, (byte) 0xe8, (byte) 0xce, (byte) 0x3b, (byte) 0x6a, (byte) 0x69, (byte) 0x67,
|
||||
(byte) 0x4d, (byte) 0xb5, (byte) 0x5c, (byte) 0x2a, (byte) 0xa5, (byte) 0xc8, (byte) 0x70, (byte) 0x87,
|
||||
(byte) 0x12, (byte) 0xa3, (byte) 0xf0, (byte) 0x14, (byte) 0x59, (byte) 0x80, (byte) 0x9c, (byte) 0x37,
|
||||
(byte) 0xeb, (byte) 0x76, (byte) 0x49, (byte) 0x5b, (byte) 0xd6, (byte) 0xb9, (byte) 0x6c, (byte) 0x70,
|
||||
(byte) 0x9d, (byte) 0x68, (byte) 0x8f, (byte) 0xd, (byte) 0x87, (byte) 0x98, (byte) 0x49, (byte) 0xae,
|
||||
(byte) 0xab, (byte) 0x20, (byte) 0x8c, (byte) 0x3e, (byte) 0xc2, (byte) 0xb4, (byte) 0xdd, (byte) 0xa,
|
||||
(byte) 0x86, (byte) 0xb8, (byte) 0xa7, (byte) 0x47, (byte) 0x35, (byte) 0x9c, (byte) 0x6d, (byte) 0xd5,
|
||||
(byte) 0x76, (byte) 0xb4, (byte) 0x9a, (byte) 0x43, (byte) 0x40, (byte) 0x5b, (byte) 0x40, (byte) 0xbf,
|
||||
(byte) 0x9b, (byte) 0x46, (byte) 0xdd, (byte) 0xd1, (byte) 0x2b, (byte) 0xa9, (byte) 0xcf, (byte) 0xba,
|
||||
(byte) 0x95, (byte) 0x7a, (byte) 0xa3, (byte) 0x5b, (byte) 0x5c, (byte) 0x91, (byte) 0xf3, (byte) 0x67,
|
||||
(byte) 0x19, (byte) 0xe6, (byte) 0x14, (byte) 0xdc, (byte) 0xc5, (byte) 0x3d, (byte) 0x1, (byte) 0x83,
|
||||
(byte) 0xb1, (byte) 0x5a, (byte) 0xd4, (byte) 0xb4, (byte) 0x34, (byte) 0x43, (byte) 0x2b, (byte) 0x47,
|
||||
(byte) 0x77, (byte) 0x75, (byte) 0x35, (byte) 0xda, (byte) 0x2, (byte) 0xc5, (byte) 0xa8, (byte) 0x90,
|
||||
(byte) 0x50, (byte) 0xbb, (byte) 0x8a, (byte) 0xdc, (byte) 0xe6, (byte) 0xb6, (byte) 0x56, (byte) 0x72,
|
||||
(byte) 0x18, (byte) 0xee, (byte) 0x2b, (byte) 0x78, (byte) 0x80, (byte) 0xb4, (byte) 0x82, (byte) 0x79,
|
||||
(byte) 0x1e, (byte) 0xaf, (byte) 0xaf, (byte) 0x7d, (byte) 0x5e, (byte) 0x78, (byte) 0x6f, (byte) 0x9b,
|
||||
(byte) 0x1f, (byte) 0x78, (byte) 0x29, (byte) 0xa, (byte) 0x16, (byte) 0xf0, (byte) 0xf0, (byte) 0xf4,
|
||||
(byte) 0x48, (byte) 0x37, (byte) 0x53, (byte) 0x2f, (byte) 0x72, (byte) 0xcf, (byte) 0x3e, (byte) 0x96,
|
||||
(byte) 0x34, (byte) 0xcb, (byte) 0xd1, (byte) 0x4d, (byte) 0x12, (byte) 0x1c, (byte) 0x8e, (byte) 0x19,
|
||||
(byte) 0xfc, (byte) 0x1d, (byte) 0xa7, (byte) 0x27, (byte) 0x4a, (byte) 0x51, (byte) 0xb3, (byte) 0xb9,
|
||||
(byte) 0x42, (byte) 0x2b, (byte) 0x72, (byte) 0xcc, (byte) 0x50, (byte) 0xb0, (byte) 0xc8, (byte) 0x25,
|
||||
(byte) 0x43, (byte) 0xff, (byte) 0x36, (byte) 0x8e, (byte) 0x8a, (byte) 0x88, (byte) 0x5f, (byte) 0xdc,
|
||||
(byte) 0xcd, (byte) 0x4e, (byte) 0xe8, (byte) 0xa7, (byte) 0x9a, (byte) 0xa3, (byte) 0x55, (byte) 0x69,
|
||||
(byte) 0x3e, (byte) 0x66, (byte) 0xdd, (byte) 0x21, (byte) 0x42, (byte) 0xe6, (byte) 0x34, (byte) 0xf8,
|
||||
(byte) 0x2b, (byte) 0x2, (byte) 0x3b, (byte) 0x44, (byte) 0xd1, (byte) 0xd4, (byte) 0xea, (byte) 0x7c,
|
||||
(byte) 0x47, (byte) 0x4e, (byte) 0x1d, (byte) 0x6e, (byte) 0x1a, (byte) 0xae, (byte) 0xc5, (byte) 0x77,
|
||||
(byte) 0xef, (byte) 0x4, (byte) 0x2c, (byte) 0x5c, (byte) 0x10, (byte) 0xa7, (byte) 0x73, (byte) 0x90,
|
||||
(byte) 0xcd, (byte) 0x16, (byte) 0xcc, (byte) 0x4f, (byte) 0xfe, (byte) 0x47, (byte) 0xdd, (byte) 0x57,
|
||||
(byte) 0xaa, (byte) 0x98, (byte) 0x35, (byte) 0x9a, (byte) 0x56, (byte) 0xb7, (byte) 0x5a, (byte) 0x2e,
|
||||
(byte) 0xe7, (byte) 0xeb, (byte) 0x96, (byte) 0x65, (byte) 0x6b, (byte) 0xb5, (byte) 0x9a, (byte) 0x56,
|
||||
(byte) 0x16, (byte) 0x30, (byte) 0xd4, (byte) 0x29, (byte) 0x7b, (byte) 0xd6, (byte) 0x26, (byte) 0xb7,
|
||||
(byte) 0x82, (byte) 0xa0, (byte) 0xd5, (byte) 0x54, (byte) 0xa0, (byte) 0x2f, (byte) 0xa1, (byte) 0x60,
|
||||
(byte) 0xab, (byte) 0x25, (byte) 0xd, (byte) 0x63, (byte) 0xf4, (byte) 0x89, (byte) 0xca, (byte) 0xe0,
|
||||
(byte) 0x8f, (byte) 0x17, (byte) 0x2, (byte) 0x9f, (byte) 0x32, (byte) 0xd9, (byte) 0x4b, (byte) 0xb4,
|
||||
(byte) 0x1b, (byte) 0xa1, (byte) 0x55, (byte) 0xa0, (byte) 0xd5, (byte) 0x37, (byte) 0x75, (byte) 0x0,
|
||||
(byte) 0x61, (byte) 0x9f, (byte) 0xfe, (byte) 0x50, (byte) 0x91, (byte) 0x64, (byte) 0x25, (byte) 0xd7,
|
||||
(byte) 0x29, (byte) 0x21, (byte) 0x80, (byte) 0x1, (byte) 0xc, (byte) 0xb6, (byte) 0xa0, (byte) 0x13,
|
||||
(byte) 0x24, (byte) 0xc1, (byte) 0xbd, (byte) 0x5d, (byte) 0x87, (byte) 0xf0, (byte) 0x14, (byte) 0xf,
|
||||
(byte) 0xe0, (byte) 0x6d, (byte) 0x40, (byte) 0x6c, (byte) 0x13, (byte) 0xf8, (byte) 0x15, (byte) 0x0,
|
||||
(byte) 0xfc, (byte) 0xb4, (byte) 0x6, (byte) 0xc8, (byte) 0x33, (byte) 0x74, (byte) 0xaa, (byte) 0x2f,
|
||||
(byte) 0xac, (byte) 0x92, (byte) 0x8, (byte) 0xa3, (byte) 0x93, (byte) 0x6f, (byte) 0x61, (byte) 0x5f,
|
||||
(byte) 0xe6, (byte) 0x10, (byte) 0x52, (byte) 0x71, (byte) 0xfa, (byte) 0x0, (byte) 0x6c, (byte) 0x4d,
|
||||
(byte) 0xc8, (byte) 0x7e, (byte) 0x87, (byte) 0x3f, (byte) 0x1c, (byte) 0x10, (byte) 0x7f, (byte) 0x42,
|
||||
(byte) 0x2e, (byte) 0x7a, (byte) 0xa7, (byte) 0xf3, (byte) 0xd, (byte) 0x74, (byte) 0xbd, (byte) 0x9e,
|
||||
(byte) 0x39, (byte) 0xc6, (byte) 0xcb, (byte) 0xc4, (byte) 0x31, (byte) 0xfa, (byte) 0x67, (byte) 0x1a,
|
||||
(byte) 0x50, (byte) 0xf6, (byte) 0xb0, (byte) 0x94, (byte) 0x16, (byte) 0x13, (byte) 0x11, (byte) 0xb1,
|
||||
(byte) 0x81, (byte) 0x9e, (byte) 0x3d, (byte) 0xcc, (byte) 0x35, (byte) 0x3d, (byte) 0xc9, (byte) 0xb4,
|
||||
(byte) 0x18, (byte) 0x11, (byte) 0xb3, (byte) 0x11, (byte) 0xf1, (byte) 0x28, (byte) 0xed, (byte) 0x23,
|
||||
(byte) 0xe8, (byte) 0x48, (byte) 0x1b, (byte) 0x1a, (byte) 0x4e, (byte) 0x4b, (byte) 0x89, (byte) 0x88,
|
||||
(byte) 0xe4, (byte) 0x42, (byte) 0x19, (byte) 0xf7, (byte) 0x44, (byte) 0x7c, (byte) 0x47, (byte) 0x7b,
|
||||
(byte) 0x88, (byte) 0xac, (byte) 0xf1, (byte) 0x0, (byte) 0xa1, (byte) 0x73, (byte) 0x1, (byte) 0x1a,
|
||||
(byte) 0xe8, (byte) 0xdd, (byte) 0xa7, (byte) 0x64, (byte) 0x26, (byte) 0xe8, (byte) 0x42, (byte) 0x26,
|
||||
(byte) 0xe9, (byte) 0x1e, (byte) 0xf6, (byte) 0x60, (byte) 0x14, (byte) 0x4b, (byte) 0xad, (byte) 0x75,
|
||||
(byte) 0x85, (byte) 0x12, (byte) 0x5c, (byte) 0xc7, (byte) 0x6, (byte) 0x8a, (byte) 0xb4, (byte) 0x5f,
|
||||
(byte) 0xc2, (byte) 0xaa, (byte) 0xbb, (byte) 0xf7, (byte) 0x62, (byte) 0x7, (byte) 0x6, (byte) 0x5d,
|
||||
(byte) 0x52, (byte) 0x8f, (byte) 0x5b, (byte) 0x5e, (byte) 0x12, (byte) 0x5d, (byte) 0x64, (byte) 0x15,
|
||||
(byte) 0xf2, (byte) 0x72, (byte) 0x6, (byte) 0xe7, (byte) 0x4, (byte) 0x5d, (byte) 0xf6, (byte) 0xa,
|
||||
(byte) 0xad, (byte) 0x3b, (byte) 0xd4, (byte) 0x4e, (byte) 0x8e, (byte) 0x34, (byte) 0x11, (byte) 0xc2,
|
||||
(byte) 0x17, (byte) 0xf4, (byte) 0xe2, (byte) 0x2b, (byte) 0x15, (byte) 0x1e, (byte) 0x21, (byte) 0x74,
|
||||
(byte) 0xe, (byte) 0xf2, (byte) 0x9, (byte) 0x11, (byte) 0x45, (byte) 0x86, (byte) 0x61, (byte) 0x86,
|
||||
(byte) 0xcb, (byte) 0xc, (byte) 0x57, (byte) 0x18, (byte) 0xef, (byte) 0x36, (byte) 0x19, (byte) 0x79,
|
||||
(byte) 0x99, (byte) 0xcc, (byte) 0x73, (byte) 0xfa, (byte) 0x9d, (byte) 0x10, (byte) 0x43, (byte) 0x3a,
|
||||
(byte) 0x77, (byte) 0x7c, (byte) 0x6, (byte) 0xf1, (byte) 0x9e, (byte) 0x50, (byte) 0x64, (byte) 0x4f,
|
||||
(byte) 0xf3, (byte) 0xc, (byte) 0x78, (byte) 0xc2, (byte) 0x70, (byte) 0xb5, (byte) 0x9f, (byte) 0x3a,
|
||||
(byte) 0x3a, (byte) 0x4a, (byte) 0xb2, (byte) 0x1e, (byte) 0x44, (byte) 0xff, (byte) 0x2, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x0, (byte) 0x18, (byte) 0x7e, (byte) 0xe, (byte) 0x57, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x9, (byte) 0x0, (byte) 0x32, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xed,
|
||||
(byte) 0x41, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x4d, (byte) 0x45, (byte) 0x54,
|
||||
(byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x18, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xfe, (byte) 0xca, (byte) 0x0, (byte) 0x0, (byte) 0x75, (byte) 0x70,
|
||||
(byte) 0xe, (byte) 0x0, (byte) 0x1, (byte) 0x8, (byte) 0xa1, (byte) 0x8c, (byte) 0x13, (byte) 0x4d,
|
||||
(byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3, (byte) 0x2d, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x17, (byte) 0x7e, (byte) 0xe, (byte) 0x57,
|
||||
(byte) 0x31, (byte) 0x59, (byte) 0x76, (byte) 0x4d, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x14, (byte) 0x0, (byte) 0x39, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0xa4, (byte) 0x81, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x4d, (byte) 0x45,
|
||||
(byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f, (byte) 0x4d,
|
||||
(byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54, (byte) 0x2e,
|
||||
(byte) 0x4d, (byte) 0x46, (byte) 0x1, (byte) 0x0, (byte) 0x18, (byte) 0x0, (byte) 0x6e, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x61, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x51, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75, (byte) 0x70,
|
||||
(byte) 0x19, (byte) 0x0, (byte) 0x1, (byte) 0x85, (byte) 0x85, (byte) 0x84, (byte) 0x2, (byte) 0x4d,
|
||||
(byte) 0x45, (byte) 0x54, (byte) 0x41, (byte) 0x2d, (byte) 0x49, (byte) 0x4e, (byte) 0x46, (byte) 0x2f,
|
||||
(byte) 0x4d, (byte) 0x41, (byte) 0x4e, (byte) 0x49, (byte) 0x46, (byte) 0x45, (byte) 0x53, (byte) 0x54,
|
||||
(byte) 0x2e, (byte) 0x4d, (byte) 0x46, (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d,
|
||||
(byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x67,
|
||||
(byte) 0x37, (byte) 0xb, (byte) 0x57, (byte) 0x3f, (byte) 0xa5, (byte) 0x4f, (byte) 0x5e, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x10,
|
||||
(byte) 0x0, (byte) 0x35, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa4, (byte) 0x81, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0x52, (byte) 0x65, (byte) 0x61, (byte) 0x64, (byte) 0x41, (byte) 0x6e, (byte) 0x74,
|
||||
(byte) 0x4a, (byte) 0x61, (byte) 0x72, (byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73,
|
||||
(byte) 0x73, (byte) 0x1, (byte) 0x0, (byte) 0x18, (byte) 0x0, (byte) 0x87, (byte) 0x4, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xc7, (byte) 0x2, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x15, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75, (byte) 0x70, (byte) 0x15,
|
||||
(byte) 0x0, (byte) 0x1, (byte) 0x94, (byte) 0x82, (byte) 0x60, (byte) 0x61, (byte) 0x52, (byte) 0x65,
|
||||
(byte) 0x61, (byte) 0x64, (byte) 0x41, (byte) 0x6e, (byte) 0x74, (byte) 0x4a, (byte) 0x61, (byte) 0x72,
|
||||
(byte) 0x2e, (byte) 0x63, (byte) 0x6c, (byte) 0x61, (byte) 0x73, (byte) 0x73, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x6, (byte) 0x6, (byte) 0x2c, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x57, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x37, (byte) 0x4,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b,
|
||||
(byte) 0x6, (byte) 0x7, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8e, (byte) 0x5,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x3, (byte) 0x0, (byte) 0x57, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x37, (byte) 0x4, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
/*
|
||||
* ----------------#1--------------------
|
||||
* [Central Directory Header]
|
||||
* 0x47: Signature : 0x02014b50
|
||||
* 0x4b: Created Zip Spec : 0x2d [4.5]
|
||||
* 0x4c: Created OS : 0x3 [UNIX]
|
||||
* 0x4d: VerMadeby : 0x32d [3, 4.5]
|
||||
* 0x4e: VerExtract : 0x2d [4.5]
|
||||
* 0x4f: Flag : 0x800
|
||||
* 0x51: Method : 0x8 [DEFLATED]
|
||||
* 0x53: Last Mod Time : 0x570375bc [Thu Aug 03 14:45:56 EDT 2023]
|
||||
* 0x57: CRC : 0x0
|
||||
* 0x5b: Compressed Size : 0x2
|
||||
* 0x5f: Uncompressed Size: 0x0
|
||||
* * 0x63: Name Length : 0x5
|
||||
* 0x65: Extra Length : 0x12
|
||||
* Extra data:[01, 00, 00, 00, 75, 70, 0a, 00, 01, ba, f7, eb, c1, 61, 2e, 74, 78, 74]
|
||||
* [tag=0x0001, sz=0]
|
||||
* ->ZIP64:
|
||||
* [tag=0x7075, sz=10]
|
||||
* ->[Unknown tag]
|
||||
* [data= 01 ba f7 eb c1 61 2e 74 78 74 ]
|
||||
* 0x67: Comment Length : 0x0
|
||||
* 0x69: Disk Start : 0x0
|
||||
* 0x6b: Attrs : 0x0
|
||||
* 0x6d: AttrsEx : 0x81a40000
|
||||
* 0x71: Loc Header Offset: 0x0
|
||||
* 0x75: File Name : a.txt
|
||||
*/
|
||||
public static byte[] ANT_ZIP64_UNICODE_EXTRA_ZIP= {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0xbc, (byte) 0x75, (byte) 0x3, (byte) 0x57, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
|
||||
(byte) 0xff, (byte) 0xff, (byte) 0x5, (byte) 0x0, (byte) 0x22, (byte) 0x0, (byte) 0x61, (byte) 0x2e,
|
||||
(byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75,
|
||||
(byte) 0x70, (byte) 0xa, (byte) 0x0, (byte) 0x1, (byte) 0xba, (byte) 0xf7, (byte) 0xeb, (byte) 0xc1,
|
||||
(byte) 0x61, (byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x3, (byte) 0x0, (byte) 0x50,
|
||||
(byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x2d, (byte) 0x3, (byte) 0x2d, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0xbc, (byte) 0x75, (byte) 0x3, (byte) 0x57, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x12, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xa4,
|
||||
(byte) 0x81, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x61, (byte) 0x2e, (byte) 0x74,
|
||||
(byte) 0x78, (byte) 0x74, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x75, (byte) 0x70,
|
||||
(byte) 0xa, (byte) 0x0, (byte) 0x1, (byte) 0xba, (byte) 0xf7, (byte) 0xeb, (byte) 0xc1, (byte) 0x61,
|
||||
(byte) 0x2e, (byte) 0x74, (byte) 0x78, (byte) 0x74, (byte) 0x50, (byte) 0x4b, (byte) 0x6, (byte) 0x6,
|
||||
(byte) 0x2c, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x2d, (byte) 0x0, (byte) 0x2d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x45, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x47, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x6, (byte) 0x7,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8c, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x1, (byte) 0x0, (byte) 0x1, (byte) 0x0, (byte) 0x45, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x47, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
};
|
||||
|
||||
// Name of Zip file and Jar File used by the test
|
||||
public static final Path VALID_APK = Path.of("working-apk.zip");
|
||||
public static final Path VALID_APACHE_COMPRESS_JAR =
|
||||
Path.of("valid-apache-compress.jar");
|
||||
public static final Path VALID_ANT_JAR =
|
||||
Path.of("valid-ant-zip64-unicode-extrafields.jar");
|
||||
public static final Path VALID_ANT_ZIP =
|
||||
Path.of("valid-ant-zip64-unicode-extrafields.zip");
|
||||
/**
|
||||
* Setup method used to create the Zip and Jar files used by the test
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
Files.deleteIfExists(VALID_APK);
|
||||
Files.deleteIfExists(VALID_APACHE_COMPRESS_JAR);
|
||||
Files.deleteIfExists(VALID_ANT_JAR);
|
||||
Files.deleteIfExists(VALID_ANT_ZIP);
|
||||
|
||||
// Create the Zip file to read
|
||||
Files.write(VALID_APK, VALID_APK_FILE);
|
||||
Files.write(VALID_APACHE_COMPRESS_JAR, COMMONS_COMPRESS_JAR);
|
||||
Files.write(VALID_ANT_JAR, ANT_ZIP64_UNICODE_EXTRA_JAR);
|
||||
Files.write(VALID_ANT_ZIP, ANT_ZIP64_UNICODE_EXTRA_ZIP);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip and Jars files to validate we can open
|
||||
*/
|
||||
private static Stream<Path> zipFilesToTest() {
|
||||
return Stream.of(VALID_APK, VALID_APACHE_COMPRESS_JAR, VALID_ANT_JAR, VALID_ANT_ZIP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a Zip file which contains an extra header with a data size
|
||||
* 0f 0 can be opened using ZipFile
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("zipFilesToTest")
|
||||
public void zipFilesToTest(Path jar) throws IOException {
|
||||
try (ZipFile zf = new ZipFile(jar.toFile())) {
|
||||
System.out.printf("%s opened%n", jar.toAbsolutePath());
|
||||
} catch (IOException ie) {
|
||||
System.out.printf("%n%n%n$$$$ %s NOT opened%n", jar.toAbsolutePath());
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a Zip file which contains an extra header with a data size
|
||||
* 0f 0 can be opened using ZipFS
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("zipFilesToTest")
|
||||
public void readZipFSTest(Path jar) throws IOException {
|
||||
try (FileSystem fs = FileSystems.newFileSystem(jar, Map.of())) {
|
||||
System.out.printf("%s opened%n", jar.toAbsolutePath());
|
||||
} catch (IOException ie) {
|
||||
System.out.printf("%n%n%n$$$$ %s NOT opened%n", jar.toAbsolutePath());
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Utility method which takes a byte array and converts to byte array
|
||||
* declaration. For example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* var fooJar = Files.readAllBytes(Path.of("foo.jar"));
|
||||
* var result = createByteArray(fooJar, "FOOBYTES");
|
||||
* System.out.println(result);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param bytes A byte array used to create a byte array declaration
|
||||
* @param name Name to be used in the byte array declaration
|
||||
* @return The formatted byte array declaration
|
||||
*/
|
||||
public static String createByteArray(byte[] bytes, String name) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 5);
|
||||
Formatter fmt = new Formatter(sb);
|
||||
fmt.format(" public static byte[] %s = {", name);
|
||||
final int linelen = 8;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
if (i % linelen == 0) {
|
||||
fmt.format("%n ");
|
||||
}
|
||||
fmt.format(" (byte) 0x%x,", bytes[i] & 0xff);
|
||||
}
|
||||
fmt.format("%n };%n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
380
test/jdk/java/util/zip/ZipFile/ReadZip.java
Normal file
380
test/jdk/java/util/zip/ZipFile/ReadZip.java
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
@bug 4241361 4842702 4985614 6646605 5032358 6923692 6233323 8144977 8186464 4401122 8322830
|
||||
@summary Make sure we can read a zip file.
|
||||
@modules jdk.zipfs
|
||||
@run junit ReadZip
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ReadZip {
|
||||
|
||||
// ZIP file produced during tests
|
||||
private Path zip = Path.of("read-zip.zip");
|
||||
|
||||
/**
|
||||
* Create a sample ZIP file for use by tests
|
||||
* @param name name of the ZIP file to create
|
||||
* @return a sample ZIP file
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
private Path createZip(String name) throws IOException {
|
||||
Path zip = Path.of(name);
|
||||
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
return zip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced after each test method
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure we throw NPE when calling getEntry or getInputStream with null params
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void nullPointerExceptionOnNullParams() throws IOException {
|
||||
zip = createZip("null-params.zip");
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
|
||||
assertThrows(NullPointerException.class, () -> zf.getEntry(null));
|
||||
assertThrows(NullPointerException.class, () -> zf.getInputStream(null));
|
||||
|
||||
// Sanity check that we can still read an entry
|
||||
ZipEntry ze = zf.getEntry("file.txt");
|
||||
assertNotNull(ze, "cannot read from zip file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the zip file that has some garbage bytes padded at the end
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void bytesPaddedAtEnd() throws IOException {
|
||||
|
||||
zip = createZip("bytes-padded.zip");
|
||||
|
||||
// pad some bytes
|
||||
try (OutputStream os = Files.newOutputStream(zip,
|
||||
StandardOpenOption.APPEND)) {
|
||||
os.write(1);
|
||||
os.write(3);
|
||||
os.write(5);
|
||||
os.write(7);
|
||||
}
|
||||
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry ze = zf.getEntry("file.txt");
|
||||
assertNotNull(ze, "cannot read from zip file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that we can read a comment from the ZIP
|
||||
* file's 'End of Central Directory' header
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readZipFileComment() throws IOException {
|
||||
|
||||
// Create a zip file with a comment in the 'End of Central Directory' header
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zos = new ZipOutputStream(out)) {
|
||||
ZipEntry ze = new ZipEntry("ZipEntry");
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(1);
|
||||
zos.write(2);
|
||||
zos.write(3);
|
||||
zos.write(4);
|
||||
zos.closeEntry();
|
||||
zos.setComment("This is the comment for testing");
|
||||
}
|
||||
|
||||
// Read zip file comment
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry ze = zf.getEntry("ZipEntry");
|
||||
assertNotNull(ze, "cannot read entry from zip file");
|
||||
assertEquals("This is the comment for testing", zf.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a directory entry can be found using the
|
||||
* name 'directory/' as well as 'directory/'
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readDirectoryEntries() throws IOException {
|
||||
|
||||
// Create a ZIP containing some directory entries
|
||||
try (OutputStream fos = Files.newOutputStream(zip);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos)) {
|
||||
// Add a META-INF directory with STORED compression type
|
||||
ZipEntry metaInf = new ZipEntry("META-INF/");
|
||||
metaInf.setMethod(ZipEntry.STORED);
|
||||
metaInf.setSize(0);
|
||||
metaInf.setCrc(0);
|
||||
zos.putNextEntry(metaInf);
|
||||
|
||||
// Add a regular directory
|
||||
ZipEntry dir = new ZipEntry("directory/");
|
||||
zos.putNextEntry(dir);
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
// Verify directory lookups
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
// Look up 'directory/' using the full name
|
||||
ZipEntry ze = zf.getEntry("directory/");
|
||||
assertNotNull(ze, "read entry \"directory/\" failed");
|
||||
assertTrue(ze.isDirectory(), "read entry \"directory/\" failed");
|
||||
assertEquals("directory/", ze.getName());
|
||||
|
||||
try (InputStream is = zf.getInputStream(ze)) {
|
||||
is.available();
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
|
||||
// Look up 'directory/' without the trailing slash
|
||||
ze = zf.getEntry("directory");
|
||||
assertNotNull(ze, "read entry \"directory\" failed");
|
||||
assertTrue(ze.isDirectory(), "read entry \"directory\" failed");
|
||||
assertEquals("directory/", ze.getName());
|
||||
|
||||
try (InputStream is = zf.getInputStream(ze)) {
|
||||
is.available();
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
// Sanity check that also META-INF/ can be looked up with or without the trailing slash
|
||||
assertNotNull(zf.getEntry("META-INF"));
|
||||
assertNotNull(zf.getEntry("META-INF/"));
|
||||
assertEquals(zf.getEntry("META-INF").getName(),
|
||||
zf.getEntry("META-INF/").getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw a NoSuchFileException exception when reading a non-existing zip file
|
||||
*/
|
||||
@Test
|
||||
public void nonExistingFile() {
|
||||
File nonExistingFile = new File("non-existing-file-f6804460f.zip");
|
||||
assertThrows(NoSuchFileException.class, () ->
|
||||
new ZipFile(nonExistingFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a Zip file with a 'Zip64 End of Central Directory header' which was created
|
||||
* using ZipFileSystem with the 'forceZIP64End' option.
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readZip64EndZipFs() throws IOException {
|
||||
|
||||
// Create zip file with Zip64 end
|
||||
Map<String, Object> env = Map.of("create", "true", "forceZIP64End", "true");
|
||||
try (FileSystem fs = FileSystems.newFileSystem(zip, env)) {
|
||||
Files.write(fs.getPath("hello"), "hello".getBytes());
|
||||
}
|
||||
// Read using ZipFile
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
try (InputStream in = zf.getInputStream(zf.getEntry("hello"))) {
|
||||
assertEquals("hello", new String(in.readAllBytes(), StandardCharsets.US_ASCII));
|
||||
}
|
||||
}
|
||||
// Read using ZipFileSystem
|
||||
try (FileSystem fs = FileSystems.newFileSystem(zip, Map.of())) {
|
||||
assertEquals("hello", new String(Files.readAllBytes(fs.getPath("hello"))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a zip file created via Info-ZIP in streaming mode,
|
||||
* which includes a 'Zip64 End of Central Directory header'.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
* @throws InterruptedException if an unexpected InterruptedException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readZip64EndInfoZIPStreaming() throws IOException, InterruptedException {
|
||||
// ZIP created using: "echo -n hello | zip zip64.zip -"
|
||||
// Hex encoded using: "cat zip64.zip | xxd -ps"
|
||||
byte[] zipBytes = HexFormat.of().parseHex("""
|
||||
504b03042d0000000000c441295886a61036ffffffffffffffff01001400
|
||||
2d010010000500000000000000050000000000000068656c6c6f504b0102
|
||||
1e032d0000000000c441295886a610360500000005000000010000000000
|
||||
000001000000b011000000002d504b06062c000000000000001e032d0000
|
||||
00000000000000010000000000000001000000000000002f000000000000
|
||||
003800000000000000504b06070000000067000000000000000100000050
|
||||
4b050600000000010001002f000000380000000000
|
||||
""".replaceAll("\n","")
|
||||
);
|
||||
|
||||
Files.write(zip, zipBytes);
|
||||
|
||||
try (ZipFile zf = new ZipFile(this.zip.toFile())) {
|
||||
try (InputStream in = zf.getInputStream(zf.getEntry("-"))) {
|
||||
String contents = new String(in.readAllBytes(), StandardCharsets.US_ASCII);
|
||||
assertEquals("hello", contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the available() method overriden by the input stream returned by
|
||||
* ZipFile.getInputStream correctly returns the number of remaining uncompressed bytes
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void availableShouldReturnRemainingUncompressedBytes() throws IOException {
|
||||
// The number of uncompressed bytes to write to the sample ZIP entry
|
||||
final int expectedBytes = 512;
|
||||
|
||||
// Create a sample ZIP with deflated entry of a known uncompressed size
|
||||
try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write(new byte[expectedBytes]);
|
||||
}
|
||||
|
||||
// Verify the behavior of ZipFileInflaterInputStream.available()
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry e = zf.getEntry("file.txt");
|
||||
try (InputStream in = zf.getInputStream(e)) {
|
||||
// Initially, available() should return the full uncompressed size of the entry
|
||||
assertEquals(expectedBytes, in.available(),
|
||||
"wrong initial return value of available");
|
||||
|
||||
// Reading a few bytes should reduce the number of available bytes accordingly
|
||||
int bytesToRead = 10;
|
||||
in.read(new byte[bytesToRead]);
|
||||
assertEquals(expectedBytes - bytesToRead, in.available());
|
||||
|
||||
// Reading all remaining bytes should reduce the number of available bytes to zero
|
||||
in.transferTo(OutputStream.nullOutputStream());
|
||||
assertEquals(0, in.available());
|
||||
|
||||
// available on a closed input stream should return zero
|
||||
in.close();
|
||||
assertEquals(0, in.available());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that reading an InputStream from a closed ZipFile
|
||||
* throws IOException as expected and does not crash the VM.
|
||||
* See bugs: 4528128 6846616
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void readAfterClose() throws IOException {
|
||||
zip = createZip("read-after-close.zip");
|
||||
InputStream in;
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry zent = zf.getEntry("file.txt");
|
||||
in = zf.getInputStream(zent);
|
||||
}
|
||||
|
||||
// zf is closed at this point
|
||||
assertThrows(IOException.class, () -> {
|
||||
in.read();
|
||||
});
|
||||
assertThrows(IOException.class, () -> {
|
||||
in.read(new byte[10]);
|
||||
});
|
||||
assertThrows(IOException.class, () -> {
|
||||
byte[] buf = new byte[10];
|
||||
in.read(buf, 0, buf.length);
|
||||
});
|
||||
assertThrows(IOException.class, () -> {
|
||||
in.readAllBytes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile can open a ZIP file with zero entries
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void noEntries() throws IOException {
|
||||
// Create a ZIP file with no entries
|
||||
try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
}
|
||||
|
||||
// Open the "empty" ZIP file
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
// Verify size
|
||||
assertEquals(0, zf.size());
|
||||
|
||||
// Verify entry lookup using ZipFile.getEntry()
|
||||
assertNull(zf.getEntry("file.txt"));
|
||||
|
||||
// Verify iteration using ZipFile.entries()
|
||||
assertEquals(Collections.emptyList(), Collections.list(zf.entries()));
|
||||
|
||||
// Verify iteration using ZipFile.stream()
|
||||
assertEquals(Collections.emptyList(), zf.stream().toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
98
test/jdk/java/util/zip/ZipFile/ReleaseInflater.java
Normal file
98
test/jdk/java/util/zip/ZipFile/ReleaseInflater.java
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 4214795
|
||||
* @summary Make sure the same inflater will only be recycled
|
||||
* once.
|
||||
* @run junit ReleaseInflater
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ReleaseInflater {
|
||||
|
||||
// ZIP file produced in this test
|
||||
private Path zip = Path.of("release-inflater.zip");
|
||||
|
||||
/**
|
||||
* Create a sample ZIP file for use by tests
|
||||
* @param name name of the ZIP file to create
|
||||
* @return a sample ZIP file
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
try (ZipOutputStream zo = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
zo.putNextEntry(new ZipEntry("file.txt"));
|
||||
zo.write("helloworld".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP and JAR files produced after each test method
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the same Inflater is not recycled across input streams
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void recycleInflaterOnlyOnce() throws IOException {
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
ZipEntry e = zf.getEntry("file.txt");
|
||||
|
||||
InputStream in1 = zf.getInputStream(e);
|
||||
// close the stream, the inflater will be released
|
||||
in1.close();
|
||||
// close the stream again, should be no-op
|
||||
in1.close();
|
||||
|
||||
// create two new streams, allocating inflaters
|
||||
InputStream in2 = zf.getInputStream(e);
|
||||
InputStream in3 = zf.getInputStream(e);
|
||||
|
||||
// check to see if they influence each other
|
||||
assertEquals(in2.read(), in3.read(), "Stream is corrupted!");
|
||||
}
|
||||
}
|
||||
}
|
||||
66
test/jdk/java/util/zip/ZipFile/ShortRead.java
Normal file
66
test/jdk/java/util/zip/ZipFile/ShortRead.java
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 6285124
|
||||
* @summary Small compressed zip entries should be read in one read() operation
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
public class ShortRead {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final File zFile = new File("abc.zip");
|
||||
try {
|
||||
final String entryName = "abc";
|
||||
final String data = "Data disponible";
|
||||
try (FileOutputStream fos = new FileOutputStream(zFile);
|
||||
ZipOutputStream zos = new ZipOutputStream(fos))
|
||||
{
|
||||
zos.putNextEntry(new ZipEntry(entryName));
|
||||
zos.write(data.getBytes("ASCII"));
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
try (ZipFile zipFile = new ZipFile(zFile)) {
|
||||
final ZipEntry zentry = zipFile.getEntry(entryName);
|
||||
final InputStream inputStream = zipFile.getInputStream(zentry);
|
||||
System.out.printf("size=%d csize=%d available=%d%n",
|
||||
zentry.getSize(),
|
||||
zentry.getCompressedSize(),
|
||||
inputStream.available());
|
||||
byte[] buf = new byte[data.length()];
|
||||
final int count = inputStream.read(buf);
|
||||
if (! new String(buf, "ASCII").equals(data) ||
|
||||
count != data.length())
|
||||
throw new Exception("short read?");
|
||||
}
|
||||
} finally {
|
||||
zFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
191
test/jdk/java/util/zip/ZipFile/StreamZipEntriesTest.java
Normal file
191
test/jdk/java/util/zip/ZipFile/StreamZipEntriesTest.java
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @run junit StreamZipEntriesTest
|
||||
* @summary Make sure we can stream entries of a zip file.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
||||
public class StreamZipEntriesTest {
|
||||
|
||||
// ZIP file produced in this test
|
||||
private Path zip = Path.of("stream.zip");
|
||||
// JAR file produced in this test
|
||||
private Path jar = Path.of("stream.jar");
|
||||
|
||||
/**
|
||||
* Create sample ZIP and JAR files used in in this test
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
|
||||
try (OutputStream out = Files.newOutputStream(zip);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
zo.putNextEntry(new ZipEntry("entry1.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
zo.putNextEntry(new ZipEntry("entry2.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
try (OutputStream out = Files.newOutputStream(jar);
|
||||
ZipOutputStream zo = new ZipOutputStream(out)) {
|
||||
// A JAR file may start with a META-INF/ directory before the manifest
|
||||
zo.putNextEntry(new ZipEntry("META-INF/"));
|
||||
// Write the manifest
|
||||
zo.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
|
||||
new Manifest().write(zo);
|
||||
|
||||
// Write two regular entries
|
||||
zo.putNextEntry(new ZipEntry("entry1.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
zo.putNextEntry(new ZipEntry("entry2.txt"));
|
||||
zo.write("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the ZIP file produced after each test method
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@AfterEach
|
||||
public void cleanup() throws IOException {
|
||||
Files.deleteIfExists(zip);
|
||||
Files.deleteIfExists(jar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile.stream() produces the expected entries
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void testStreamZip() throws IOException {
|
||||
Set<String> names = new HashSet<>(Set.of("entry1.txt", "entry2.txt"));
|
||||
|
||||
try (ZipFile zf = new ZipFile(zip.toFile())) {
|
||||
zf.stream().forEach(e -> {
|
||||
assertTrue(e instanceof ZipEntry);
|
||||
String name = e.getName();
|
||||
assertNotNull(names.remove(name));
|
||||
String toString = e.toString();
|
||||
assertEquals(name, toString);
|
||||
});
|
||||
|
||||
// Check that all expected names were processed
|
||||
assertTrue(names.isEmpty());
|
||||
|
||||
// Check that Stream.toArray produces the expected result
|
||||
Object elements[] = zf.stream().toArray();
|
||||
assertEquals(2, elements.length);
|
||||
assertEquals(elements[0].toString(), "entry1.txt");
|
||||
assertEquals(elements[1].toString(), "entry2.txt");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarFile.stream() produces the expected entries
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void testStreamJar() throws IOException {
|
||||
try (JarFile jf = new JarFile(jar.toFile())) {
|
||||
Set<String> names = new HashSet<>(Set.of(
|
||||
"META-INF/",
|
||||
"META-INF/MANIFEST.MF",
|
||||
"entry1.txt",
|
||||
"entry2.txt"
|
||||
));
|
||||
|
||||
jf.stream().forEach(e -> {
|
||||
assertTrue(e instanceof JarEntry);
|
||||
String name = e.getName();
|
||||
assertNotNull(names.remove(name));
|
||||
String toString = e.toString();
|
||||
assertEquals(name, toString);
|
||||
}
|
||||
);
|
||||
|
||||
// Check that all expected names were processed
|
||||
assertTrue(names.isEmpty(), "Unprocessed entries: " + names);
|
||||
|
||||
|
||||
// Check that Stream.toArray produces the expected result
|
||||
Object elements[] = jf.stream().toArray();
|
||||
assertEquals(4, elements.length);
|
||||
assertEquals(elements[0].toString(), "META-INF/");
|
||||
assertEquals(elements[1].toString(), "META-INF/MANIFEST.MF");
|
||||
assertEquals(elements[2].toString(), "entry1.txt");
|
||||
assertEquals(elements[3].toString(), "entry2.txt");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling ZipFile.stream() on a closed ZipFile should throw ISE
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void testClosedZipFile() throws IOException {
|
||||
ZipFile zf = new ZipFile(zip.toFile());
|
||||
zf.close();
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
Stream s = zf.stream();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling JarFile.stream() on a closed JarFile should throw ISE
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void testClosedJarFile() throws IOException {
|
||||
JarFile jf = new JarFile(jar.toFile());
|
||||
jf.close();
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
Stream s = jf.stream();
|
||||
});
|
||||
}
|
||||
}
|
||||
166
test/jdk/java/util/zip/ZipFile/TestCleaner.java
Normal file
166
test/jdk/java/util/zip/ZipFile/TestCleaner.java
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8185582 8197989
|
||||
* @summary Check the resources of Inflater, Deflater and ZipFile are always
|
||||
* cleaned/released when the instance is not unreachable
|
||||
* @modules java.base/java.util.zip:open java.base/jdk.internal.vm.annotation
|
||||
* @library /test/lib
|
||||
* @comment The test relies on the Cleaner to invoke the cleaning actions. So
|
||||
* we use "othervm" to prevent any Cleaner delays that could be contributed by any
|
||||
* other tests or code that might have executed on the agentvm prior to this test
|
||||
* execution
|
||||
* @run main/othervm TestCleaner
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.zip.*;
|
||||
import jdk.internal.vm.annotation.DontInline;
|
||||
import jdk.test.lib.util.ForceGC;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
public class TestCleaner {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
testDeInflater();
|
||||
testZipFile();
|
||||
}
|
||||
|
||||
private static long addrOf(Object obj) {
|
||||
try {
|
||||
Field addr = obj.getClass().getDeclaredField("address");
|
||||
if (!addr.trySetAccessible()) {
|
||||
return -1;
|
||||
}
|
||||
return addr.getLong(obj);
|
||||
} catch (Exception x) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// verify the "native resource" of In/Deflater has been cleaned
|
||||
private static void testDeInflater() throws Throwable {
|
||||
Field zsRefDef = Deflater.class.getDeclaredField("zsRef");
|
||||
Field zsRefInf = Inflater.class.getDeclaredField("zsRef");
|
||||
if (!zsRefDef.trySetAccessible() || !zsRefInf.trySetAccessible()) {
|
||||
throw new RuntimeException("'zsRef' is not accessible");
|
||||
}
|
||||
if (addrOf(zsRefDef.get(new Deflater())) == -1 ||
|
||||
addrOf(zsRefInf.get(new Inflater())) == -1) {
|
||||
throw new RuntimeException("'addr' is not accessible");
|
||||
}
|
||||
List<Object> list = new ArrayList<>();
|
||||
byte[] buf1 = new byte[1024];
|
||||
byte[] buf2 = new byte[1024];
|
||||
for (int i = 0; i < 10; i++) {
|
||||
var def = new Deflater();
|
||||
list.add(zsRefDef.get(def));
|
||||
def.setInput("hello".getBytes());
|
||||
def.finish();
|
||||
int n = def.deflate(buf1);
|
||||
|
||||
var inf = new Inflater();
|
||||
list.add(zsRefInf.get(inf));
|
||||
inf.setInput(buf1, 0, n);
|
||||
n = inf.inflate(buf2);
|
||||
if (!"hello".equals(new String(buf2, 0, n))) {
|
||||
throw new RuntimeException("compression/decompression failed");
|
||||
}
|
||||
}
|
||||
|
||||
final AtomicLong numNotYetCleaned = new AtomicLong();
|
||||
// trigger GC
|
||||
final boolean resourcesCleaned = ForceGC.wait(() -> {
|
||||
final long remaining = list.stream().filter(o -> addrOf(o) != 0).count();
|
||||
numNotYetCleaned.set(remaining);
|
||||
return remaining == 0;
|
||||
});
|
||||
if (!resourcesCleaned) {
|
||||
throw new RuntimeException(numNotYetCleaned.get()
|
||||
+ " resources haven't yet been cleaned");
|
||||
}
|
||||
}
|
||||
|
||||
@DontInline
|
||||
private static Object openAndCloseZipFile(File zip) throws Throwable {
|
||||
try {
|
||||
try (var fos = new FileOutputStream(zip);
|
||||
var zos = new ZipOutputStream(fos)) {
|
||||
zos.putNextEntry(new ZipEntry("hello"));
|
||||
zos.write("hello".getBytes(US_ASCII));
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
var zf = new ZipFile(zip);
|
||||
var es = zf.entries();
|
||||
while (es.hasMoreElements()) {
|
||||
zf.getInputStream(es.nextElement()).read();
|
||||
}
|
||||
|
||||
Field fieldRes = ZipFile.class.getDeclaredField("res");
|
||||
if (!fieldRes.trySetAccessible()) {
|
||||
throw new RuntimeException("'ZipFile.res' is not accesible");
|
||||
}
|
||||
Object zfRes = fieldRes.get(zf);
|
||||
if (zfRes == null) {
|
||||
throw new RuntimeException("'ZipFile.res' is null");
|
||||
}
|
||||
Field fieldZsrc = zfRes.getClass().getDeclaredField("zsrc");
|
||||
if (!fieldZsrc.trySetAccessible()) {
|
||||
throw new RuntimeException("'ZipFile.zsrc' is not accesible");
|
||||
}
|
||||
return fieldZsrc.get(zfRes);
|
||||
} finally {
|
||||
zip.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void testZipFile() throws Throwable {
|
||||
File dir = new File(System.getProperty("test.dir", "."));
|
||||
File zip = File.createTempFile("testzf", "zip", dir);
|
||||
|
||||
Object zsrc = openAndCloseZipFile(zip);
|
||||
if (zsrc != null) {
|
||||
Field zfileField = zsrc.getClass().getDeclaredField("zfile");
|
||||
if (!zfileField.trySetAccessible()) {
|
||||
throw new RuntimeException("'ZipFile.Source.zfile' is not accessible");
|
||||
}
|
||||
final boolean resourceCleaned = ForceGC.wait(() -> {
|
||||
try {
|
||||
return zfileField.get(zsrc) == null;
|
||||
} catch (IllegalAccessException e) {
|
||||
// shouldn't happen
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
if (!resourceCleaned) {
|
||||
throw new RuntimeException("cleaner failed to clean zipfile " + zip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
358
test/jdk/java/util/zip/ZipFile/TestZipFile.java
Normal file
358
test/jdk/java/util/zip/ZipFile/TestZipFile.java
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8142508 8146431
|
||||
* @modules java.base/java.util.zip:open
|
||||
* @summary Tests various ZipFile apis
|
||||
* @run main/manual TestZipFile
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class TestZipFile {
|
||||
|
||||
private static final Random r = new Random();
|
||||
private static final int N = 50;
|
||||
private static final int NN = 10;
|
||||
private static final int ENUM = 10000;
|
||||
private static final int ESZ = 10000;
|
||||
private static ExecutorService executor = Executors.newFixedThreadPool(20);
|
||||
private static final Set<Path> paths = new HashSet<>();
|
||||
private static final boolean isWindows = System.getProperty("os.name")
|
||||
.startsWith("Windows");
|
||||
|
||||
static void realMain (String[] args) throws Throwable {
|
||||
try {
|
||||
for (int i = 0; i < N; i++) {
|
||||
test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||
test(r.nextInt(ENUM), r.nextInt(ESZ), true, true);
|
||||
}
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(10, TimeUnit.MINUTES);
|
||||
executor = Executors.newFixedThreadPool(20);
|
||||
for (int i = 0; i < NN; i++) {
|
||||
test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), false, true);
|
||||
test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), true, true);
|
||||
if(!isWindows) {
|
||||
testCachedDelete();
|
||||
testCachedOverwrite();
|
||||
}
|
||||
}
|
||||
test(70000, 1000, false, true); // > 65536 entry number;
|
||||
testDelete(); // OPEN_DELETE
|
||||
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(10, TimeUnit.MINUTES);
|
||||
} finally {
|
||||
for (Path path : paths) {
|
||||
Files.deleteIfExists(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test(int numEntry, int szMax, boolean addPrefix, boolean cleanOld) {
|
||||
String name = "test-" + r.nextInt() + ".zip";
|
||||
Zip zip = new Zip(name, numEntry, szMax, addPrefix, cleanOld);
|
||||
for (int i = 0; i < NN; i++) {
|
||||
executor.submit(() -> doTest(zip));
|
||||
}
|
||||
}
|
||||
|
||||
// test scenario:
|
||||
// (1) open the ZipFile(zip) with OPEN_READ | OPEN_DELETE
|
||||
// (2) test the ZipFile works correctly
|
||||
// (3) check the zip is deleted after ZipFile gets closed
|
||||
static void testDelete() throws Throwable {
|
||||
String name = "testDelete-" + r.nextInt() + ".zip";
|
||||
Zip zip = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||
try (ZipFile zf = new ZipFile(new File(zip.name),
|
||||
ZipFile.OPEN_READ | ZipFile.OPEN_DELETE ))
|
||||
{
|
||||
doTest0(zip, zf);
|
||||
}
|
||||
Path p = Paths.get(name);
|
||||
if (Files.exists(p)) {
|
||||
fail("Failed to delete " + name + " with OPEN_DELETE");
|
||||
}
|
||||
}
|
||||
|
||||
// test scenario:
|
||||
// (1) keep a ZipFile(zip1) alive (in ZipFile's cache), dont close it
|
||||
// (2) delete zip1 and create zip2 with the same name the zip1 with zip2
|
||||
// (3) zip1 tests should fail, but no crash
|
||||
// (4) zip2 tasks should all get zip2, then pass normal testing.
|
||||
static void testCachedDelete() throws Throwable {
|
||||
String name = "testCachedDelete-" + r.nextInt() + ".zip";
|
||||
Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||
|
||||
try (ZipFile zf = new ZipFile(zip1.name)) {
|
||||
for (int i = 0; i < NN; i++) {
|
||||
executor.submit(() -> verifyNoCrash(zip1));
|
||||
}
|
||||
// delete the "zip1" and create a new one to test
|
||||
Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||
/*
|
||||
System.out.println("========================================");
|
||||
System.out.printf(" zip1=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
|
||||
zip1.name, zip1.lastModified, zip1.entries.size(),
|
||||
zip1.attrs.fileKey(), zip1.attrs.size(), zip1.attrs.lastModifiedTime().toMillis());
|
||||
System.out.printf(" zip2=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
|
||||
zip2.name, zip2.lastModified, zip2.entries.size(),
|
||||
zip2.attrs.fileKey(), zip2.attrs.size(), zip2.attrs.lastModifiedTime().toMillis());
|
||||
*/
|
||||
for (int i = 0; i < NN; i++) {
|
||||
executor.submit(() -> doTest(zip2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// overwrite the "zip1" and create a new one to test. So the two zip files
|
||||
// have the same fileKey, but probably different lastModified()
|
||||
static void testCachedOverwrite() throws Throwable {
|
||||
String name = "testCachedOverWrite-" + r.nextInt() + ".zip";
|
||||
Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
|
||||
try (ZipFile zf = new ZipFile(zip1.name)) {
|
||||
for (int i = 0; i < NN; i++) {
|
||||
executor.submit(() -> verifyNoCrash(zip1));
|
||||
}
|
||||
// overwrite the "zip1" with new contents
|
||||
Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, false);
|
||||
for (int i = 0; i < NN; i++) {
|
||||
executor.submit(() -> doTest(zip2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just check the entries and contents. since the file has been either overwritten
|
||||
// or deleted/rewritten, we only care if it crahes or not.
|
||||
static void verifyNoCrash(Zip zip) throws RuntimeException {
|
||||
try (ZipFile zf = new ZipFile(zip.name)) {
|
||||
List<ZipEntry> zlist = new ArrayList<>(zip.entries.keySet());
|
||||
String[] elist = zf.stream().map(e -> e.getName()).toArray(String[]::new);
|
||||
if (!Arrays.equals(elist,
|
||||
zlist.stream().map( e -> e.getName()).toArray(String[]::new)))
|
||||
{
|
||||
//System.out.printf("++++++ LIST NG [%s] entries.len=%d, expected=%d+++++++%n",
|
||||
// zf.getName(), elist.length, zlist.size());
|
||||
return;
|
||||
}
|
||||
for (ZipEntry ze : zlist) {
|
||||
byte[] zdata = zip.entries.get(ze);
|
||||
ZipEntry e = zf.getEntry(ze.getName());
|
||||
if (e != null) {
|
||||
checkEqual(e, ze);
|
||||
if (!e.isDirectory()) {
|
||||
// check with readAllBytes
|
||||
try (InputStream is = zf.getInputStream(e)) {
|
||||
if (!Arrays.equals(zdata, is.readAllBytes())) {
|
||||
//System.out.printf("++++++ BYTES NG [%s]/[%s] ++++++++%n",
|
||||
// zf.getName(), ze.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// t.printStackTrace();
|
||||
// fail(t.toString());
|
||||
}
|
||||
}
|
||||
|
||||
static void checkEqual(ZipEntry x, ZipEntry y) {
|
||||
if (x.getName().equals(y.getName()) &&
|
||||
x.isDirectory() == y.isDirectory() &&
|
||||
x.getMethod() == y.getMethod() &&
|
||||
(x.getTime() / 2000) == y.getTime() / 2000 &&
|
||||
x.getSize() == y.getSize() &&
|
||||
x.getCompressedSize() == y.getCompressedSize() &&
|
||||
x.getCrc() == y.getCrc() &&
|
||||
x.getComment().equals(y.getComment())
|
||||
) {
|
||||
pass();
|
||||
} else {
|
||||
fail(x + " not equal to " + y);
|
||||
System.out.printf(" %s %s%n", x.getName(), y.getName());
|
||||
System.out.printf(" %d %d%n", x.getMethod(), y.getMethod());
|
||||
System.out.printf(" %d %d%n", x.getTime(), y.getTime());
|
||||
System.out.printf(" %d %d%n", x.getSize(), y.getSize());
|
||||
System.out.printf(" %d %d%n", x.getCompressedSize(), y.getCompressedSize());
|
||||
System.out.printf(" %d %d%n", x.getCrc(), y.getCrc());
|
||||
System.out.println("-----------------");
|
||||
}
|
||||
}
|
||||
|
||||
static void doTest(Zip zip) throws RuntimeException {
|
||||
//Thread me = Thread.currentThread();
|
||||
try (ZipFile zf = new ZipFile(zip.name)) {
|
||||
doTest0(zip, zf);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
|
||||
static void doTest0(Zip zip, ZipFile zf) throws Throwable {
|
||||
// (0) check zero-length entry name, no AIOOBE
|
||||
try {
|
||||
check(zf.getEntry("") == null);
|
||||
} catch (Throwable t) {
|
||||
unexpected(t);
|
||||
}
|
||||
|
||||
List<ZipEntry> list = new ArrayList<>(zip.entries.keySet());
|
||||
// (1) check entry list, in expected order
|
||||
if (!check(Arrays.equals(
|
||||
list.stream().map( e -> e.getName()).toArray(String[]::new),
|
||||
zf.stream().map( e -> e.getName()).toArray(String[]::new)))) {
|
||||
return;
|
||||
}
|
||||
// (2) shuffle, and check each entry and its bytes
|
||||
Collections.shuffle(list);
|
||||
for (ZipEntry ze : list) {
|
||||
byte[] data = zip.entries.get(ze);
|
||||
ZipEntry e = zf.getEntry(ze.getName());
|
||||
checkEqual(e, ze);
|
||||
if (!e.isDirectory()) {
|
||||
// check with readAllBytes
|
||||
try (InputStream is = zf.getInputStream(e)) {
|
||||
check(Arrays.equals(data, is.readAllBytes()));
|
||||
}
|
||||
// check with smaller sized buf
|
||||
try (InputStream is = zf.getInputStream(e)) {
|
||||
byte[] buf = new byte[(int)e.getSize()];
|
||||
int sz = r.nextInt((int)e.getSize()/4 + 1) + 1;
|
||||
int off = 0;
|
||||
int n;
|
||||
while ((n = is.read(buf, off, buf.length - off)) > 0) {
|
||||
off += n;
|
||||
}
|
||||
check(is.read() == -1);
|
||||
check(Arrays.equals(data, buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Zip {
|
||||
final String name;
|
||||
final Map<ZipEntry, byte[]> entries;
|
||||
BasicFileAttributes attrs;
|
||||
long lastModified;
|
||||
|
||||
Zip(String name, int num, int szMax, boolean prefix, boolean clean) {
|
||||
this.name = name;
|
||||
entries = new LinkedHashMap<>(num);
|
||||
try {
|
||||
Path p = Paths.get(name);
|
||||
if (clean) {
|
||||
Files.deleteIfExists(p);
|
||||
}
|
||||
paths.add(p);
|
||||
} catch (Exception x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(name);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos))
|
||||
{
|
||||
if (prefix) {
|
||||
byte[] bytes = new byte[r.nextInt(1000)];
|
||||
r.nextBytes(bytes);
|
||||
bos.write(bytes);
|
||||
}
|
||||
CRC32 crc = new CRC32();
|
||||
for (int i = 0; i < num; i++) {
|
||||
String ename = "entry-" + i + "-name-" + r.nextLong();
|
||||
ZipEntry ze = new ZipEntry(ename);
|
||||
int method = r.nextBoolean() ? ZipEntry.STORED : ZipEntry.DEFLATED;
|
||||
writeEntry(zos, crc, ze, method, szMax);
|
||||
}
|
||||
// add some manifest entries
|
||||
for (int i = 0; i < r.nextInt(20); i++) {
|
||||
String meta = "META-INF/" + "entry-" + i + "-metainf-" + r.nextLong();
|
||||
ZipEntry ze = new ZipEntry(meta);
|
||||
writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
|
||||
}
|
||||
} catch (Exception x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
try {
|
||||
this.attrs = Files.readAttributes(Paths.get(name), BasicFileAttributes.class);
|
||||
this.lastModified = new File(name).lastModified();
|
||||
} catch (Exception x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeEntry(ZipOutputStream zos, CRC32 crc,
|
||||
ZipEntry ze, int method, int szMax)
|
||||
throws IOException
|
||||
{
|
||||
ze.setMethod(method);
|
||||
byte[] data = new byte[r.nextInt(szMax + 1)];
|
||||
r.nextBytes(data);
|
||||
if (method == ZipEntry.STORED) { // must set size/csize/crc
|
||||
ze.setSize(data.length);
|
||||
ze.setCompressedSize(data.length);
|
||||
crc.reset();
|
||||
crc.update(data);
|
||||
ze.setCrc(crc.getValue());
|
||||
}
|
||||
ze.setTime(System.currentTimeMillis());
|
||||
ze.setComment(ze.getName());
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(data);
|
||||
zos.closeEntry();
|
||||
entries.put(ze, data);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
static volatile int passed = 0, failed = 0;
|
||||
static void pass() {passed++;}
|
||||
static void pass(String msg) {System.out.println(msg); passed++;}
|
||||
static void fail() {failed++; Thread.dumpStack();}
|
||||
static void fail(String msg) {System.out.println(msg); fail();}
|
||||
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
|
||||
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {realMain(args);} catch (Throwable t) {unexpected(t);}
|
||||
System.out.println("\nPassed = " + passed + " failed = " + failed);
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
||||
339
test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java
Normal file
339
test/jdk/java/util/zip/ZipFile/TestZipFileEncodings.java
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8243254
|
||||
* @summary Tests a simple set of operations on Zip files in various encodings
|
||||
* focusing on ensuring metadata is properly encoded and read.
|
||||
* @run junit/timeout=480 TestZipFileEncodings
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TestZipFileEncodings {
|
||||
|
||||
private static int NUM_ENTRIES = 100;
|
||||
private static int METAINF_ENTRIES = 5;
|
||||
private static int ENTRY_SIZE = 100;
|
||||
|
||||
private static final AtomicInteger SEQUENCE = new AtomicInteger(0);
|
||||
|
||||
private static Set<Path> paths = new HashSet<>();
|
||||
|
||||
private static Random random() {
|
||||
return ThreadLocalRandom.current();
|
||||
}
|
||||
|
||||
public static Stream<String> nonUnicodeCharsets() {
|
||||
return Stream.of(
|
||||
"ISO-8859-1",
|
||||
"IBM01149",
|
||||
"IBM037",
|
||||
"IBM-Thai"
|
||||
);
|
||||
}
|
||||
|
||||
public static Stream<String> unicodeCharsets() {
|
||||
return Stream.of(
|
||||
"UTF-8",
|
||||
"UTF-16",
|
||||
"UTF-16LE",
|
||||
"UTF-16BE",
|
||||
"UTF-32"
|
||||
);
|
||||
}
|
||||
|
||||
public static Stream<String> allCharsets() {
|
||||
return Stream.concat(nonUnicodeCharsets(), unicodeCharsets());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("nonUnicodeCharsets")
|
||||
public void testNonUnicode(String charsetName) throws Throwable {
|
||||
test(NUM_ENTRIES, 100 + random().nextInt(ENTRY_SIZE), false, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("unicodeCharsets")
|
||||
public void testUnicode(String charsetName) throws Throwable {
|
||||
test(NUM_ENTRIES, 100 + random().nextInt(ENTRY_SIZE), true, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("nonUnicodeCharsets")
|
||||
public void testNonUnicodeManyEntries(String charsetName) throws Throwable {
|
||||
test(70000, 10, false, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("unicodeCharsets")
|
||||
public void testUnicodeManyEntries(String charsetName) throws Throwable {
|
||||
test(70000, 10, true, Charset.forName(charsetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* This test was added to catch a regression where UTFZipCoder incorrectly
|
||||
* treated latin1-encoded Strings as UTF8-compatible, while this actually only
|
||||
* holds for ASCII strings.
|
||||
*
|
||||
* The implementation of UTFZipCoder.compare was later changed to not depend on
|
||||
* the String's coder. Let's keep this test around anyway, since it provokes
|
||||
* a corner case which could be easily missed.
|
||||
*/
|
||||
@Test
|
||||
public void latin1NotAscii() throws IOException {
|
||||
|
||||
Path zip = Path.of("latin1-not-ascii.zip");
|
||||
|
||||
// latin1, but not ASCII
|
||||
String entryName = "smörgåsbord";
|
||||
|
||||
try (ZipOutputStream z = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||
z.putNextEntry(new ZipEntry(entryName));
|
||||
}
|
||||
|
||||
try (ZipFile z = new ZipFile(zip.toFile())) {
|
||||
assertNotNull(z.getEntry(entryName));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This test was added to catch a regression where ZipCoder.compare did not
|
||||
* properly verify that the lookup name is a prefix of the entry name. Because of
|
||||
* this regression, any candidate name with identical lengths and a trailing
|
||||
* '/' would be incorrectly considered a "directory match".
|
||||
*
|
||||
* Since this regression depends on both a hash collision and that the length of names
|
||||
* are equal, it is rarely found in the wild. Let's keep this test around
|
||||
* since it explicity provokes this rare condition.
|
||||
*
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("allCharsets")
|
||||
public void sameHashAndLengthDirLookup(String charsetName) throws IOException {
|
||||
// Two directory names with colliding hash codes and same length
|
||||
// (found in a brute force search)
|
||||
String one = "_____1637461950/";
|
||||
String two = "_____-408231241/";
|
||||
|
||||
// Create a ZIP containing the two directories
|
||||
Charset charset = Charset.forName(charsetName);
|
||||
Path zip = Path.of("hash-collision-slashmatch-utf16.zip");
|
||||
try (ZipOutputStream z = new ZipOutputStream(Files.newOutputStream(zip), charset)) {
|
||||
|
||||
// Give the names different comments so they we can distinguish them
|
||||
ZipEntry first = new ZipEntry(one);
|
||||
first.setComment("Entry one");
|
||||
z.putNextEntry(first);
|
||||
|
||||
ZipEntry second = new ZipEntry(two);
|
||||
second.setComment("Entry two");
|
||||
z.putNextEntry(second);
|
||||
}
|
||||
|
||||
// Assert that "slashless" lookups returns the correct entry even
|
||||
// when the directory names have colliding hash codes and equal lengths
|
||||
try (ZipFile z = new ZipFile(zip.toFile(), charset)) {
|
||||
|
||||
ZipEntry second = z.getEntry("_____-408231241");
|
||||
assertEquals("Entry two", second.getComment());
|
||||
|
||||
ZipEntry first = z.getEntry("_____1637461950");
|
||||
assertEquals("Entry one", first.getComment());
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() {
|
||||
for (Path path : paths) {
|
||||
path.toFile().deleteOnExit();
|
||||
}
|
||||
}
|
||||
|
||||
static void test(int numEntry, int szMax, boolean unicode, Charset cs) throws Throwable {
|
||||
String name = "zfenc-" + SEQUENCE.incrementAndGet() + ".zip";
|
||||
Zip zip = new Zip(name, numEntry, szMax, unicode, cs);
|
||||
doTest(zip);
|
||||
}
|
||||
|
||||
static void checkEqual(ZipEntry x, ZipEntry y) {
|
||||
assertEquals(y.getName(), x.getName());
|
||||
assertEquals(y.isDirectory(), x.isDirectory());
|
||||
assertEquals(y.getMethod(), x.getMethod());
|
||||
assertEquals(y.getTime() / 2000, (x.getTime() / 2000));
|
||||
assertEquals(y.getSize(), x.getSize());
|
||||
assertEquals(y.getCompressedSize(), x.getCompressedSize());
|
||||
assertEquals(y.getCrc(), x.getCrc());
|
||||
assertEquals(y.getComment(), x.getComment());
|
||||
}
|
||||
|
||||
static void doTest(Zip zip) throws Throwable {
|
||||
try (ZipFile zf = new ZipFile(zip.name, zip.cs)) {
|
||||
doTest0(zip, zf);
|
||||
}
|
||||
}
|
||||
|
||||
static void doTest0(Zip zip, ZipFile zf) throws Throwable {
|
||||
// (0) check zero-length entry name, no AIOOBE
|
||||
assertEquals(null, zf.getEntry(""));
|
||||
|
||||
List<ZipEntry> list = new ArrayList(zip.entries.keySet());
|
||||
// check each entry and its bytes
|
||||
for (ZipEntry ze : list) {
|
||||
byte[] data = zip.entries.get(ze);
|
||||
String name = ze.getName();
|
||||
ZipEntry e = zf.getEntry(name);
|
||||
checkEqual(e, ze);
|
||||
if (!e.isDirectory()) {
|
||||
// check with readAllBytes
|
||||
try (InputStream is = zf.getInputStream(e)) {
|
||||
assertArrayEquals(is.readAllBytes(), data);
|
||||
}
|
||||
int slash = name.indexOf('/');
|
||||
if (slash > 0) {
|
||||
ZipEntry dir1 = zf.getEntry(name.substring(0, slash));
|
||||
ZipEntry dir2 = zf.getEntry(name.substring(0, slash + 1));
|
||||
assertNotNull(dir1);
|
||||
assertNotNull(dir2);
|
||||
assertTrue(dir1.isDirectory());
|
||||
assertTrue(dir2.isDirectory());
|
||||
checkEqual(dir1, dir2);
|
||||
}
|
||||
} else {
|
||||
ZipEntry unslashLookup = zf.getEntry(name.substring(0, name.length() - 1));
|
||||
checkEqual(e, unslashLookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Zip {
|
||||
String name;
|
||||
Charset cs;
|
||||
Map<ZipEntry, byte[]> entries;
|
||||
BasicFileAttributes attrs;
|
||||
long lastModified;
|
||||
|
||||
Zip(String name, int num, int szMax, boolean unicode, Charset cs) {
|
||||
this.cs = cs;
|
||||
this.name = name;
|
||||
entries = new LinkedHashMap<>(num);
|
||||
try {
|
||||
Path p = Paths.get(name);
|
||||
Files.deleteIfExists(p);
|
||||
paths.add(p);
|
||||
} catch (Exception x) {
|
||||
throw (RuntimeException)x;
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(name);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos, cs))
|
||||
{
|
||||
CRC32 crc = new CRC32();
|
||||
for (int i = 0; i < num; i++) {
|
||||
String ename = "entry-" + i + "-name-" + random().nextLong();
|
||||
if (unicode) {
|
||||
// Provokes compatibility issue with slash handling for
|
||||
// non-ASCII compatible Unicode encodings
|
||||
ename = ename + '\u2F2F';
|
||||
zos.putNextEntry(new ZipEntry(ename + '/'));
|
||||
ename = ename + '/' + ename;
|
||||
}
|
||||
ZipEntry ze = new ZipEntry(ename);
|
||||
assertTrue(!ze.isDirectory());
|
||||
writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
|
||||
}
|
||||
// add some manifest entries
|
||||
zos.putNextEntry(new ZipEntry("META-INF/"));
|
||||
for (int i = 0; i < METAINF_ENTRIES; i++) {
|
||||
String meta = "META-INF/" + "entry-" + i + "-metainf-" + random().nextLong();
|
||||
ZipEntry ze = new ZipEntry(meta);
|
||||
writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
|
||||
}
|
||||
} catch (Exception x) {
|
||||
throw (RuntimeException)x;
|
||||
}
|
||||
try {
|
||||
this.attrs = Files.readAttributes(Paths.get(name), BasicFileAttributes.class);
|
||||
this.lastModified = new File(name).lastModified();
|
||||
} catch (Exception x) {
|
||||
throw (RuntimeException)x;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeEntry(ZipOutputStream zos, CRC32 crc,
|
||||
ZipEntry ze, int method, int szMax)
|
||||
throws IOException
|
||||
{
|
||||
ze.setMethod(method);
|
||||
byte[] data = new byte[random().nextInt(szMax + 1)];
|
||||
random().nextBytes(data);
|
||||
if (method == ZipEntry.STORED) { // must set size/csize/crc
|
||||
ze.setSize(data.length);
|
||||
ze.setCompressedSize(data.length);
|
||||
crc.reset();
|
||||
crc.update(data);
|
||||
ze.setCrc(crc.getValue());
|
||||
}
|
||||
ze.setTime(System.currentTimeMillis());
|
||||
ze.setComment(ze.getName());
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(data);
|
||||
zos.closeEntry();
|
||||
entries.put(ze, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
126
test/jdk/java/util/zip/ZipFile/ZeroDate.java
Normal file
126
test/jdk/java/util/zip/ZipFile/ZeroDate.java
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import static java.util.zip.ZipFile.CENOFF;
|
||||
import static java.util.zip.ZipFile.CENTIM;
|
||||
import static java.util.zip.ZipFile.ENDHDR;
|
||||
import static java.util.zip.ZipFile.ENDOFF;
|
||||
import static java.util.zip.ZipFile.LOCTIM;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
/* @test
|
||||
* @bug 8184940 8188869
|
||||
* @summary JDK 9 rejects zip files where the modified day or month is 0
|
||||
* or otherwise represent an invalid date, such as 1980-02-30 24:60:60
|
||||
* @author Liam Miller-Cushon
|
||||
* @library /test/lib
|
||||
*/
|
||||
public class ZeroDate {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// create a zip file, and read it in as a byte array
|
||||
Path path = Utils.createTempFile("bad", ".zip");
|
||||
try {
|
||||
try (OutputStream os = Files.newOutputStream(path);
|
||||
ZipOutputStream zos = new ZipOutputStream(os)) {
|
||||
ZipEntry e = new ZipEntry("x");
|
||||
zos.putNextEntry(e);
|
||||
zos.write((int) 'x');
|
||||
}
|
||||
int len = (int) Files.size(path);
|
||||
byte[] data = new byte[len];
|
||||
try (InputStream is = Files.newInputStream(path)) {
|
||||
is.read(data);
|
||||
}
|
||||
|
||||
// year, month, day are zero
|
||||
testDate(data.clone(), 0, LocalDate.of(1979, 11, 30).atStartOfDay());
|
||||
// only year is zero
|
||||
testDate(data.clone(), 0 << 25 | 4 << 21 | 5 << 16, LocalDate.of(1980, 4, 5).atStartOfDay());
|
||||
// month is greater than 12
|
||||
testDate(data.clone(), 0 << 25 | 13 << 21 | 1 << 16, LocalDate.of(1981, 1, 1).atStartOfDay());
|
||||
// 30th of February
|
||||
testDate(data.clone(), 0 << 25 | 2 << 21 | 30 << 16, LocalDate.of(1980, 3, 1).atStartOfDay());
|
||||
// 30th of February, 24:60:60
|
||||
testDate(data.clone(), 0 << 25 | 2 << 21 | 30 << 16 | 24 << 11 | 60 << 5 | 60 >> 1,
|
||||
LocalDateTime.of(1980, 3, 2, 1, 1, 0));
|
||||
} finally {
|
||||
Files.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testDate(byte[] data, int date, LocalDateTime expected) throws IOException {
|
||||
// set the datetime
|
||||
int endpos = data.length - ENDHDR;
|
||||
int cenpos = u16(data, endpos + ENDOFF);
|
||||
int locpos = u16(data, cenpos + CENOFF);
|
||||
writeU32(data, cenpos + CENTIM, date);
|
||||
writeU32(data, locpos + LOCTIM, date);
|
||||
|
||||
// ensure that the archive is still readable, and the date is 1979-11-30
|
||||
Path path = Utils.createTempFile("out", ".zip");
|
||||
try (OutputStream os = Files.newOutputStream(path)) {
|
||||
os.write(data);
|
||||
}
|
||||
try (ZipFile zf = new ZipFile(path.toFile())) {
|
||||
ZipEntry ze = zf.entries().nextElement();
|
||||
Instant actualInstant = ze.getLastModifiedTime().toInstant();
|
||||
Instant expectedInstant = expected.atZone(ZoneId.systemDefault()).toInstant();
|
||||
if (!actualInstant.equals(expectedInstant)) {
|
||||
throw new AssertionError(
|
||||
String.format("actual: %s, expected: %s", actualInstant, expectedInstant));
|
||||
}
|
||||
} finally {
|
||||
Files.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
static int u8(byte[] data, int offset) {
|
||||
return data[offset] & 0xff;
|
||||
}
|
||||
|
||||
static int u16(byte[] data, int offset) {
|
||||
return u8(data, offset) + (u8(data, offset + 1) << 8);
|
||||
}
|
||||
|
||||
private static void writeU32(byte[] data, int pos, int value) {
|
||||
data[pos] = (byte) (value & 0xff);
|
||||
data[pos + 1] = (byte) ((value >> 8) & 0xff);
|
||||
data[pos + 2] = (byte) ((value >> 16) & 0xff);
|
||||
data[pos + 3] = (byte) ((value >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
211
test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java
Normal file
211
test/jdk/java/util/zip/ZipFile/Zip64SizeTest.java
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8226530 8303891
|
||||
* @summary Verify that ZipFile reads size fields using the Zip64 extra
|
||||
* field when only the 'uncompressed size' field has the ZIP64 "magic value" 0xFFFFFFFF
|
||||
* @compile Zip64SizeTest.java
|
||||
* @run junit Zip64SizeTest
|
||||
*/
|
||||
public class Zip64SizeTest {
|
||||
// ZIP file to create
|
||||
private static final Path ZIP_FILE = Path.of("Zip64SizeTest.zip");
|
||||
// Contents to write to ZIP entries
|
||||
private static final byte[] CONTENT = "Hello".getBytes(StandardCharsets.UTF_8);
|
||||
// This opaque tag will be ignored by ZipEntry.setExtra0
|
||||
private static final int UNKNOWN_TAG = 0x9902;
|
||||
// Tag used when converting the extra field to a real ZIP64 extra field
|
||||
private static final short ZIP64_TAG = 0x1;
|
||||
// Marker value to indicate that the actual value is stored in the ZIP64 extra field
|
||||
private static final int ZIP64_MAGIC_VALUE = 0xFFFFFFFF;
|
||||
|
||||
/**
|
||||
* Validate that if the 'uncompressed size' of a ZIP CEN header is 0xFFFFFFFF, then the
|
||||
* actual size is retrieved from the corresponding ZIP64 Extended information field.
|
||||
*
|
||||
* @throws IOException if an unexpected IOException occurs
|
||||
*/
|
||||
@Test
|
||||
public void validateZipEntrySizes() throws IOException {
|
||||
createZipFile();
|
||||
System.out.println("Validating Zip Entry Sizes");
|
||||
try (ZipFile zip = new ZipFile(ZIP_FILE.toFile())) {
|
||||
ZipEntry ze = zip.getEntry("first");
|
||||
System.out.printf("Entry: %s, size= %s%n", ze.getName(), ze.getSize());
|
||||
assertEquals(CONTENT.length, ze.getSize());
|
||||
ze = zip.getEntry("second");
|
||||
System.out.printf("Entry: %s, size= %s%n", ze.getName(), ze.getSize());
|
||||
assertEquals(CONTENT.length, ze.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ZIP file with a CEN entry where the 'uncompressed size' is stored in
|
||||
* the ZIP64 field, but the 'compressed size' is in the CEN field. This makes the
|
||||
* ZIP64 data block 8 bytes long, which triggers the regression described in 8226530.
|
||||
*
|
||||
* The CEN entry for the "first" entry will have the following structure:
|
||||
* (Note the CEN 'Uncompressed Length' being 0xFFFFFFFF and the ZIP64
|
||||
* 'Uncompressed Size' being 5)
|
||||
*
|
||||
* 0081 CENTRAL HEADER #1 02014B50
|
||||
* 0085 Created Zip Spec 14 '2.0'
|
||||
* 0086 Created OS 00 'MS-DOS'
|
||||
* [...] Omitted for brevity
|
||||
* 0091 CRC F7D18982
|
||||
* 0095 Compressed Length 00000007
|
||||
* 0099 Uncompressed Length FFFFFFFF
|
||||
* [...] Omitted for brevity
|
||||
* 00AF Filename 'first'
|
||||
* 00B4 Extra ID #0001 0001 'ZIP64'
|
||||
* 00B6 Length 0008
|
||||
* 00B8 Uncompressed Size 0000000000000005
|
||||
*
|
||||
* @throws IOException if an error occurs creating the ZIP File
|
||||
*/
|
||||
private static void createZipFile() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
|
||||
// The 'first' entry will store 'uncompressed size' in the Zip64 format
|
||||
ZipEntry e1 = new ZipEntry("first");
|
||||
|
||||
// Make an extra field with the correct size for an 8-byte 'uncompressed size'
|
||||
// Zip64 field. Temporarily use the 'unknown' tag 0x9902 to make
|
||||
// ZipEntry.setExtra0 skip parsing this as a Zip64.
|
||||
// See APPNOTE.TXT, 4.6.1 Third Party Mappings
|
||||
byte[] opaqueExtra = createBlankExtra((short) UNKNOWN_TAG, (short) Long.BYTES);
|
||||
e1.setExtra(opaqueExtra);
|
||||
|
||||
zos.putNextEntry(e1);
|
||||
zos.write(CONTENT);
|
||||
|
||||
// A second entry, not in Zip64 format
|
||||
ZipEntry e2 = new ZipEntry("second");
|
||||
zos.putNextEntry(e2);
|
||||
zos.write(CONTENT);
|
||||
}
|
||||
|
||||
byte[] zip = baos.toByteArray();
|
||||
|
||||
// Update the CEN of 'first' to use the Zip64 format
|
||||
updateCENHeaderToZip64(zip);
|
||||
Files.write(ZIP_FILE, zip);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the CEN entry of the "first" entry to use ZIP64 format for the
|
||||
* 'uncompressed size' field. The updated extra field will have the following
|
||||
* structure:
|
||||
*
|
||||
* 00B4 Extra ID #0001 0001 'ZIP64'
|
||||
* 00B6 Length 0008
|
||||
* 00B8 Uncompressed Size 0000000000000005
|
||||
*
|
||||
* @param zip the ZIP file to update to ZIP64
|
||||
*/
|
||||
private static void updateCENHeaderToZip64(byte[] zip) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(zip).order(ByteOrder.LITTLE_ENDIAN);
|
||||
// Find the offset of the first CEN header
|
||||
int cenOffset = buffer.getInt(zip.length- ZipFile.ENDHDR + ZipFile.ENDOFF);
|
||||
// Find the offset of the extra field
|
||||
int nlen = buffer.getShort(cenOffset + ZipFile.CENNAM);
|
||||
int extraOffset = cenOffset + ZipFile.CENHDR + nlen;
|
||||
|
||||
// Change the header ID from 'unknown' to ZIP64
|
||||
buffer.putShort(extraOffset, ZIP64_TAG);
|
||||
// Update the 'uncompressed size' ZIP64 value to the actual uncompressed length
|
||||
int fieldOffset = extraOffset
|
||||
+ Short.BYTES // TAG
|
||||
+ Short.BYTES; // data size
|
||||
buffer.putLong(fieldOffset, CONTENT.length);
|
||||
|
||||
// Set the 'uncompressed size' field of the CEN to 0xFFFFFFFF
|
||||
buffer.putInt(cenOffset + ZipFile.CENLEN, ZIP64_MAGIC_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an extra field with the given tag and data block size, and a
|
||||
* blank data block.
|
||||
* @return an extra field with the specified tag and size
|
||||
* @param tag the header id of the extra field
|
||||
* @param blockSize the size of the extra field's data block
|
||||
*/
|
||||
private static byte[] createBlankExtra(short tag, short blockSize) {
|
||||
int size = Short.BYTES // tag
|
||||
+ Short.BYTES // data block size
|
||||
+ blockSize; // data block;
|
||||
|
||||
byte[] extra = new byte[size];
|
||||
ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN)
|
||||
.putShort(0, tag)
|
||||
.putShort(Short.BYTES, blockSize);
|
||||
return extra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the needed test files do not exist prior to executing the test
|
||||
* @throws IOException
|
||||
*/
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
deleteFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the files created for the test
|
||||
* @throws IOException
|
||||
*/
|
||||
@AfterEach
|
||||
public void tearDown() throws IOException {
|
||||
deleteFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the files created for use by the test
|
||||
* @throws IOException if an error occurs deleting the files
|
||||
*/
|
||||
private static void deleteFiles() throws IOException {
|
||||
Files.deleteIfExists(ZIP_FILE);
|
||||
}
|
||||
}
|
||||
131
test/jdk/java/util/zip/ZipFile/ZipEntryFreeTest.java
Normal file
131
test/jdk/java/util/zip/ZipFile/ZipEntryFreeTest.java
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 6907252
|
||||
* @summary ZipFileInputStream Not Thread-Safe
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Platform
|
||||
* jdk.test.lib.util.FileUtils
|
||||
* @run main ZipEntryFreeTest
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.zip.*;
|
||||
import jdk.test.lib.util.FileUtils;
|
||||
|
||||
public class ZipEntryFreeTest extends Thread {
|
||||
|
||||
private static final int NUM_THREADS = 5;
|
||||
private static final int TEST_ITERATIONS = 5;
|
||||
private static final String ZIPFILE_NAME = "large.zip";
|
||||
private static final String ZIPENTRY_NAME = "random.txt";
|
||||
private static InputStream is = null;
|
||||
final Timer timer = new Timer();
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
createZipFile();
|
||||
try {
|
||||
for (int i = 0; i < TEST_ITERATIONS; i++) {
|
||||
runTest();
|
||||
}
|
||||
} finally {
|
||||
FileUtils.deleteFileIfExistsWithRetry(Paths.get(ZIPFILE_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTest() throws Exception {
|
||||
try (ZipFile zf = new ZipFile(new File(ZIPFILE_NAME))) {
|
||||
is = zf.getInputStream(zf.getEntry(ZIPENTRY_NAME + "_0"));
|
||||
Thread[] threadArray = new Thread[NUM_THREADS];
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i] = new ZipEntryFreeTest();
|
||||
}
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i].start();
|
||||
}
|
||||
for (int i = 0; i < threadArray.length; i++) {
|
||||
threadArray[i].join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createZipFile() throws Exception {
|
||||
Random rnd = new Random(1000L);
|
||||
byte[] contents = new byte[2_000_000];
|
||||
ZipEntry ze = null;
|
||||
|
||||
try (ZipOutputStream zos =
|
||||
new ZipOutputStream(new FileOutputStream(ZIPFILE_NAME))) {
|
||||
// uncompressed mode seemed to tickle the crash
|
||||
zos.setMethod(ZipOutputStream.STORED);
|
||||
for (int ze_count = 0; ze_count < 10; ze_count++) {
|
||||
rnd.nextBytes(contents);
|
||||
ze = createZipEntry(contents, ze_count);
|
||||
zos.putNextEntry(ze);
|
||||
zos.write(contents, 0, contents.length);
|
||||
}
|
||||
zos.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private static ZipEntry createZipEntry(byte[] b, int i) {
|
||||
ZipEntry ze = new ZipEntry(ZIPENTRY_NAME + "_" + i);
|
||||
ze.setCompressedSize(b.length);
|
||||
ze.setSize(b.length);
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(b);
|
||||
ze.setCrc(crc.getValue());
|
||||
return ze;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int iteration = 0;
|
||||
TimerTask tt = (new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
});
|
||||
timer.schedule(tt, 50);
|
||||
while (is.read() != -1 && iteration++ < 1_000) { }
|
||||
} catch (ZipException ze) {
|
||||
// ZipException now expected instead of ZIP_Read crash
|
||||
System.out.println(ze);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
timer.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
152
test/jdk/java/util/zip/ZipFile/ZipEntryTimeBounds.java
Normal file
152
test/jdk/java/util/zip/ZipFile/ZipEntryTimeBounds.java
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
/* @test
|
||||
* @bug 8246129
|
||||
* @summary JDK add metadata to zip files with entries timestamped at the
|
||||
* lower bound of the DOS time epoch, i.e., 1980-01-01T00:00:00Z
|
||||
* @run junit/othervm ZipEntryTimeBounds
|
||||
*/
|
||||
public class ZipEntryTimeBounds {
|
||||
|
||||
@Test
|
||||
public void testFilesWithEntryAtLowerTimeBoundAreEqual() throws Exception {
|
||||
|
||||
// Ensure that entries that end up being exactly at the start of the
|
||||
// DOS epoch, java.util.zip.ZipEntry.DOSTIME_BEFORE_1980, or
|
||||
// 1980-01-01 00:00:00 are written without any extra timestamp metadata
|
||||
// being written
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT-01"));
|
||||
File f1 = createTempFile();
|
||||
makeZip(f1, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 0).getTimeInMillis());
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
File f2 = createTempFile();
|
||||
makeZip(f2, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 0).getTimeInMillis());
|
||||
assertEquals(-1L, Files.mismatch(f1.toPath(), f2.toPath()));
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+01"));
|
||||
File f3 = createTempFile();
|
||||
makeZip(f3, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 0).getTimeInMillis());
|
||||
assertEquals(-1L, Files.mismatch(f1.toPath(), f3.toPath()));
|
||||
|
||||
// Check that the milliseconds part of the time is exactly preserved
|
||||
assertEquals(0, new ZipFile(f1).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(0, new ZipFile(f2).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(0, new ZipFile(f3).getEntry("entry.txt").getTime() % 60000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilesWithEntryAfterLowerTimeBoundAreEqual() throws Exception {
|
||||
// Ensure files written using different timezone with entries set
|
||||
// shortly after 1980-01-01 00:00:00 produce exactly identical files
|
||||
// without metadata
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT-01"));
|
||||
File f1 = createTempFile();
|
||||
makeZip(f1, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 1).getTimeInMillis());
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
File f2 = createTempFile();
|
||||
makeZip(f2, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 1).getTimeInMillis());
|
||||
assertEquals(-1L, Files.mismatch(f1.toPath(), f2.toPath()));
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+01"));
|
||||
File f3 = createTempFile();
|
||||
makeZip(f3, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 1).getTimeInMillis() + 999);
|
||||
assertEquals(-1L, Files.mismatch(f1.toPath(), f3.toPath()));
|
||||
|
||||
// Check that the seconds part of the time is lossily preserved,
|
||||
// rounding down to the previous 2s step since epoch
|
||||
assertEquals(0, new ZipFile(f1).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(0, new ZipFile(f2).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(0, new ZipFile(f3).getEntry("entry.txt").getTime() % 60000);
|
||||
|
||||
File f4 = createTempFile();
|
||||
makeZip(f4, new GregorianCalendar(1980, Calendar.JANUARY, 1, 0, 0, 2).getTimeInMillis());
|
||||
assertEquals(2000, new ZipFile(f4).getEntry("entry.txt").getTime() % 60000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilesWithEntryBeforeLowerTimeBoundAreNotEqual() throws Exception {
|
||||
// Files written using different timezone with entries set shortly
|
||||
// before 1980-01-01 00:00:00 will produce files which add timestamp
|
||||
// metadata that make the files turn up not equal
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT-01"));
|
||||
File f1 = createTempFile();
|
||||
makeZip(f1, new GregorianCalendar(1979, Calendar.DECEMBER, 31, 23, 59, 59).getTimeInMillis());
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
File f2 = createTempFile();
|
||||
makeZip(f2, new GregorianCalendar(1979, Calendar.DECEMBER, 31, 23, 59, 59).getTimeInMillis());
|
||||
assertNotEquals(-1L, Files.mismatch(f1.toPath(), f2.toPath()));
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT+01"));
|
||||
File f3 = createTempFile();
|
||||
makeZip(f3, new GregorianCalendar(1979, Calendar.DECEMBER, 31, 23, 59, 59).getTimeInMillis() + 500);
|
||||
assertNotEquals(-1L, Files.mismatch(f1.toPath(), f3.toPath()));
|
||||
|
||||
// Check that the time is preserved at second precision, no rounding
|
||||
// to 2s
|
||||
assertEquals(59000, new ZipFile(f1).getEntry("entry.txt").getTime() % 60000);
|
||||
assertEquals(59000, new ZipFile(f2).getEntry("entry.txt").getTime() % 60000);
|
||||
// Milliseconds are discarded even when storing entries with extended
|
||||
// time metadata
|
||||
assertEquals(59000, new ZipFile(f3).getEntry("entry.txt").getTime() % 60000);
|
||||
}
|
||||
|
||||
private static void makeZip(File f, long time) throws Exception {
|
||||
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f))) {
|
||||
ZipEntry e = new ZipEntry("entry.txt");
|
||||
e.setTime(time);
|
||||
out.putNextEntry(e);
|
||||
out.write(new byte[] { 0, 1, 2, 3 });
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private static File createTempFile() throws IOException {
|
||||
File file = File.createTempFile("out", "zip");
|
||||
file.deleteOnExit();
|
||||
return file;
|
||||
}
|
||||
}
|
||||
125
test/jdk/java/util/zip/ZipFile/ZipFileCharsetTest.java
Normal file
125
test/jdk/java/util/zip/ZipFile/ZipFileCharsetTest.java
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8355975
|
||||
* @summary verify that the internal ZIP structure caching in java.util.zip.ZipFile
|
||||
* uses the correct Charset when parsing the ZIP structure of a ZIP file
|
||||
* @run junit ZipFileCharsetTest
|
||||
*/
|
||||
public class ZipFileCharsetTest {
|
||||
|
||||
private static final String ISO_8859_15_NAME = "ISO-8859-15";
|
||||
|
||||
/**
|
||||
* The internal implementation of java.util.zip.ZipFile maintains a cache
|
||||
* of the ZIP structure of each ZIP file that's currently open. This cache
|
||||
* helps prevent repeat parsing of the ZIP structure of the same underlying
|
||||
* ZIP file, every time a ZipFile instance is created for the same ZIP file.
|
||||
* The cache uses an internal key to map a ZIP file to the corresponding
|
||||
* ZIP structure that's cached.
|
||||
* A ZipFile can be constructed by passing a Charset which will be used to
|
||||
* decode the entry names (and comment) in a ZIP file.
|
||||
* The test verifies that when multiple ZipFile instances are
|
||||
* constructed using different Charsets but the same underlying ZIP file,
|
||||
* then the internal caching implementation of ZipFile doesn't end up using
|
||||
* a wrong Charset for parsing the ZIP structure of the ZIP file.
|
||||
*/
|
||||
@Test
|
||||
void testCachedZipFileSource() throws Exception {
|
||||
// ISO-8859-15 is not a standard charset in Java. We skip this test
|
||||
// when it is unavailable
|
||||
assumeTrue(Charset.availableCharsets().containsKey(ISO_8859_15_NAME),
|
||||
"skipping test since " + ISO_8859_15_NAME + " charset isn't available");
|
||||
|
||||
// We choose the byte 0xA4 for entry name in the ZIP file.
|
||||
// 0xA4 is "Euro sign" in ISO-8859-15 charset and
|
||||
// "Currency sign (generic)" in ISO-8859-1 charset.
|
||||
final byte[] entryNameBytes = new byte[]{(byte) 0xA4}; // intentional cast
|
||||
final Charset euroSignCharset = Charset.forName(ISO_8859_15_NAME);
|
||||
final Charset currencySignCharset = ISO_8859_1;
|
||||
|
||||
final String euroSign = new String(entryNameBytes, euroSignCharset);
|
||||
final String currencySign = new String(entryNameBytes, currencySignCharset);
|
||||
|
||||
// create a ZIP file whose entry name is encoded using ISO-8859-15 charset
|
||||
final Path zip = createZIP("euro", euroSignCharset, entryNameBytes);
|
||||
|
||||
// Construct a ZipFile instance using the (incorrect) charset ISO-8859-1.
|
||||
// While that ZipFile instance is still open (and the ZIP file structure
|
||||
// still cached), construct another instance for the same ZIP file, using
|
||||
// the (correct) charset ISO-8859-15.
|
||||
try (ZipFile incorrect = new ZipFile(zip.toFile(), currencySignCharset);
|
||||
ZipFile correct = new ZipFile(zip.toFile(), euroSignCharset)) {
|
||||
|
||||
// correct encoding should resolve the entry name to euro sign
|
||||
// and the entry should be thus be located
|
||||
assertNotNull(correct.getEntry(euroSign), "euro sign entry missing in " + correct);
|
||||
// correct encoding should not be able to find an entry name
|
||||
// with the currency sign
|
||||
assertNull(correct.getEntry(currencySign), "currency sign entry unexpectedly found in "
|
||||
+ correct);
|
||||
|
||||
// incorrect encoding should resolve the entry name to currency sign
|
||||
// and the entry should be thus be located by the currency sign name
|
||||
assertNotNull(incorrect.getEntry(currencySign), "currency sign entry missing in "
|
||||
+ incorrect);
|
||||
// incorrect encoding should not be able to find an entry name
|
||||
// with the euro sign
|
||||
assertNull(incorrect.getEntry(euroSign), "euro sign entry unexpectedly found in "
|
||||
+ incorrect);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and return ZIP file whose entry names are encoded using the given {@code charset}
|
||||
*/
|
||||
private static Path createZIP(final String fileNamePrefix, final Charset charset,
|
||||
final byte[] entryNameBytes) throws IOException {
|
||||
final Path zip = Files.createTempFile(Path.of("."), fileNamePrefix, ".zip");
|
||||
// create a ZIP file whose entry name(s) use the given charset
|
||||
try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(zip), charset)) {
|
||||
zos.putNextEntry(new ZipEntry(new String(entryNameBytes, charset)));
|
||||
final byte[] entryContent = "doesnotmatter".getBytes(US_ASCII);
|
||||
zos.write(entryContent);
|
||||
zos.closeEntry();
|
||||
}
|
||||
return zip;
|
||||
}
|
||||
}
|
||||
587
test/jdk/java/util/zip/ZipFile/ZipFileDuplicateEntryTest.java
Normal file
587
test/jdk/java/util/zip/ZipFile/ZipFileDuplicateEntryTest.java
Normal file
|
|
@ -0,0 +1,587 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8276123
|
||||
* @summary ZipFile::getEntry will not return a file entry when there is a
|
||||
* directory entry of the same name within a Zip File
|
||||
* @run junit/othervm ZipFileDuplicateEntryTest
|
||||
*/
|
||||
public class ZipFileDuplicateEntryTest {
|
||||
|
||||
/**
|
||||
* Name to use for creating Zip entries
|
||||
*/
|
||||
private static final String ENTRY_NAME = "entry";
|
||||
|
||||
/**
|
||||
* Zip and Jar files to be created
|
||||
*/
|
||||
private static final Path ZIP_FILE = Paths.get("fileDirEntry.zip");
|
||||
private static final Path ZIP_FILE2 = Paths.get("OnlyDirEntry.zip");
|
||||
private static final Path DUPLICATE_FILE_ENTRY_FILE = Paths.get("DupFIleEntry.zip");
|
||||
private static final Path TEST_JAR = Paths.get("fileDirEntry.jar");
|
||||
|
||||
/**
|
||||
* Directory entry added to the Zip File.
|
||||
*/
|
||||
private static final Entry DIR_ENTRY =
|
||||
Entry.of(ENTRY_NAME + "/", ZipEntry.DEFLATED,
|
||||
"I am a Directory");
|
||||
|
||||
/**
|
||||
* File entry added to the Zip File.
|
||||
*/
|
||||
private static final Entry FILE_ENTRY =
|
||||
Entry.of(ENTRY_NAME, ZipEntry.DEFLATED, "I am a File");
|
||||
|
||||
/**
|
||||
* Duplicate File entry added to the Zip file. This is the 2nd entry added
|
||||
* to the Zip file and is expected to be returned.
|
||||
*/
|
||||
private static final Entry DUPLICATE_FILE_ENTRY =
|
||||
Entry.of(ENTRY_NAME, ZipEntry.DEFLATED, "Yet another File");
|
||||
/**
|
||||
* Entries expected to be returned via ZipFile::stream
|
||||
*/
|
||||
private static final List<String> EXPECTED_ENTRIES =
|
||||
Arrays.asList(FILE_ENTRY.name, DIR_ENTRY.name);
|
||||
|
||||
/**
|
||||
* Max buffer size for readAllBytes method which can be used when
|
||||
* InputStream::readAllBytes is not available
|
||||
*/
|
||||
private static final int MAX_BUFFER_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* Flag to enable test output
|
||||
*/
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Array representing a Jar File with the entries:
|
||||
* Name: entry, contents: "I am a File"
|
||||
* Name: entry, contents: "Yet another File"
|
||||
* See createByteArray()
|
||||
*/
|
||||
private static final byte[] DUPLICATE_ENTRY_JAR_BYTES = {
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8,
|
||||
(byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53, (byte) 0x8e, (byte) 0x39,
|
||||
(byte) 0x14, (byte) 0x49, (byte) 0xd, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xb, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xb,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xd,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xf3,
|
||||
(byte) 0x54, (byte) 0x48, (byte) 0xcc, (byte) 0x55, (byte) 0x48, (byte) 0x54, (byte) 0x70, (byte) 0xcb,
|
||||
(byte) 0xcc, (byte) 0x49, (byte) 0x5, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59,
|
||||
(byte) 0x55, (byte) 0x53, (byte) 0xe1, (byte) 0x4c, (byte) 0x29, (byte) 0xa4, (byte) 0x12, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0,
|
||||
(byte) 0x14, (byte) 0x0, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x1,
|
||||
(byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x12, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8b, (byte) 0x4c, (byte) 0x2d, (byte) 0x51, (byte) 0x48,
|
||||
(byte) 0xcc, (byte) 0xcb, (byte) 0x2f, (byte) 0xc9, (byte) 0x48, (byte) 0x2d, (byte) 0x52, (byte) 0x70,
|
||||
(byte) 0xcb, (byte) 0xcc, (byte) 0x49, (byte) 0x5, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1,
|
||||
(byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8,
|
||||
(byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53, (byte) 0x8e, (byte) 0x39, (byte) 0x14,
|
||||
(byte) 0x49, (byte) 0xd, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xb, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79,
|
||||
(byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53,
|
||||
(byte) 0xe1, (byte) 0x4c, (byte) 0x29, (byte) 0xa4, (byte) 0x12, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x44, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x65, (byte) 0x6e,
|
||||
(byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x66,
|
||||
(byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
|
||||
(byte) 0x0,
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Zip files used by the tests.
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
|
||||
/**
|
||||
* Zip contains two entries named "entry" and "entry/"
|
||||
*/
|
||||
Files.deleteIfExists(ZIP_FILE);
|
||||
try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(ZIP_FILE))) {
|
||||
zos.putNextEntry(new ZipEntry(FILE_ENTRY.name));
|
||||
zos.write(FILE_ENTRY.bytes);
|
||||
zos.closeEntry();
|
||||
zos.putNextEntry(new ZipEntry(DIR_ENTRY.name));
|
||||
zos.write(DIR_ENTRY.bytes);
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Jar contains two entries named "entry" and "entry/"
|
||||
*/
|
||||
Files.deleteIfExists(TEST_JAR);
|
||||
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(TEST_JAR))) {
|
||||
jos.putNextEntry(new JarEntry(FILE_ENTRY.name));
|
||||
jos.write(FILE_ENTRY.bytes);
|
||||
jos.closeEntry();
|
||||
jos.putNextEntry(new JarEntry(DIR_ENTRY.name));
|
||||
jos.write(DIR_ENTRY.bytes);
|
||||
jos.closeEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip contains the entry "entry/"
|
||||
*/
|
||||
Files.deleteIfExists(ZIP_FILE2);
|
||||
try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(ZIP_FILE2))) {
|
||||
zos.putNextEntry(new ZipEntry(DIR_ENTRY.name));
|
||||
zos.write(DIR_ENTRY.bytes);
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Jar that contains two entries named "entry"
|
||||
*/
|
||||
Files.deleteIfExists(DUPLICATE_FILE_ENTRY_FILE);
|
||||
Files.write(DUPLICATE_FILE_ENTRY_FILE, DUPLICATE_ENTRY_JAR_BYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up after the test run
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@AfterAll
|
||||
public static void cleanup() throws IOException {
|
||||
Files.deleteIfExists(ZIP_FILE);
|
||||
Files.deleteIfExists(ZIP_FILE2);
|
||||
Files.deleteIfExists(DUPLICATE_FILE_ENTRY_FILE);
|
||||
Files.deleteIfExists(TEST_JAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* MethodSource used to specify the Zip entries to use
|
||||
*
|
||||
* @return Stream that indicates which Entry to use within the test
|
||||
*/
|
||||
public static Stream<Entry> entries() {
|
||||
return Stream.of(FILE_ENTRY, DIR_ENTRY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether ZipFile::getEntry can find a directory entry within a Zip
|
||||
* file specifying "name" vs "name/"
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void readDirWithoutSlash() throws IOException {
|
||||
System.out.printf("%n%n**** readDirWithoutSlash ***%n");
|
||||
try (ZipFile zip = new ZipFile(ZIP_FILE2.toString())) {
|
||||
ZipEntry ze = zip.getEntry(ENTRY_NAME);
|
||||
if (DEBUG) {
|
||||
System.out.printf(" Entry:%s, found:%s%n", ENTRY_NAME, ze != null);
|
||||
}
|
||||
assertNotNull(ze);
|
||||
assertTrue(ze.isDirectory());
|
||||
try (InputStream in = zip.getInputStream(ze)) {
|
||||
byte[] bytes = in.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf("name: %s, isDirectory: %s, payload= %s%n",
|
||||
ze.getName(), ze.isDirectory(), new String(bytes));
|
||||
}
|
||||
assertArrayEquals(DIR_ENTRY.bytes, bytes,
|
||||
String.format("Expected payload: %s",
|
||||
new String(DIR_ENTRY.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that ZipFile::getEntry will return the correct entry when a file
|
||||
* and directory have the same name
|
||||
*
|
||||
* @param entry The entry to search for
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("entries")
|
||||
public void testSameFileDirEntryName(Entry entry) throws IOException {
|
||||
System.out.printf("%n%n**** testSameFileDirEntryName ***%n");
|
||||
|
||||
try (ZipFile zip = new ZipFile(ZIP_FILE.toString())) {
|
||||
ZipEntry ze = zip.getEntry(entry.name);
|
||||
if (DEBUG) {
|
||||
System.out.printf(" Entry:%s, found:%s%n", entry.name, ze != null);
|
||||
}
|
||||
assertNotNull(ze);
|
||||
try (InputStream in = zip.getInputStream(ze)) {
|
||||
byte[] bytes = in.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf("name: %s, isDirectory: %s, payload= %s%n",
|
||||
ze.getName(), ze.isDirectory(), new String(bytes));
|
||||
}
|
||||
assertArrayEquals(entry.bytes, bytes,
|
||||
String.format("Expected payload: %s", new String(entry.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that ZipFile::getEntry will return the correct entry, which
|
||||
* is the second entry, when there are duplicate entries within the Zip file.
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void DupFileEntryTest() throws IOException {
|
||||
System.out.printf("%n%n**** DupFileEntryTest ***%n");
|
||||
try (ZipFile zip =
|
||||
new ZipFile(DUPLICATE_FILE_ENTRY_FILE.toString())) {
|
||||
ZipEntry ze = zip.getEntry(ENTRY_NAME);
|
||||
if (DEBUG) {
|
||||
System.out.printf(" Entry:%s, found:%s%n", ENTRY_NAME, ze != null);
|
||||
}
|
||||
assertNotNull(ze);
|
||||
try (InputStream in = zip.getInputStream(ze)) {
|
||||
byte[] bytes = in.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf("name: %s, isDirectory: %s, payload= %s%n",
|
||||
ze.getName(), ze.isDirectory(), new String(bytes));
|
||||
}
|
||||
assertArrayEquals(DUPLICATE_FILE_ENTRY.bytes, bytes,
|
||||
String.format("Expected payload: %s", new String(DUPLICATE_FILE_ENTRY.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipInputStream can be used to read all Zip entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void ZipInputStreamTest() throws IOException {
|
||||
System.out.printf("%n%n**** ZipInputStreamTest ***%n");
|
||||
try (ZipInputStream zis = new ZipInputStream(
|
||||
new FileInputStream(ZIP_FILE.toFile()))) {
|
||||
ZipEntry zipEntry = zis.getNextEntry();
|
||||
assertNotNull(zipEntry);
|
||||
while (zipEntry != null) {
|
||||
Entry e;
|
||||
if (zipEntry.getName().equals(FILE_ENTRY.name)) {
|
||||
e = FILE_ENTRY;
|
||||
} else if (zipEntry.getName().equals(DIR_ENTRY.name)) {
|
||||
e = DIR_ENTRY;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
String.format("Invalid Zip entry: %s", zipEntry.getName()));
|
||||
}
|
||||
assertEquals(e.method, zipEntry.getMethod());
|
||||
assertArrayEquals(e.bytes, zis.readAllBytes(),
|
||||
String.format("Expected payload: %s", new String(e.bytes)));
|
||||
zipEntry = zis.getNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that ZipFile::stream returns all Zip entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void ZipFileStreamTest() throws IOException {
|
||||
System.out.printf("%n%n**** ZipFileStreamTest ***%n");
|
||||
try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) {
|
||||
List<? extends ZipEntry> entries = zf.stream().collect(Collectors.toList());
|
||||
assertEquals(EXPECTED_ENTRIES.size(), entries.size());
|
||||
for (ZipEntry e : entries) {
|
||||
assertTrue(EXPECTED_ENTRIES.contains(e.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarFile can be used to read all the entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @param entry The entry to validate
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("entries")
|
||||
public void JarFileInputStreamTest(Entry entry) throws IOException {
|
||||
System.out.printf("%n%n**** JarFileInputStreamTest ***%n");
|
||||
try (JarFile jarFile = new JarFile(TEST_JAR.toFile())) {
|
||||
JarEntry je = jarFile.getJarEntry(entry.name);
|
||||
assertNotNull(je);
|
||||
if (DEBUG) {
|
||||
System.out.printf("Entry Name: %s, method: %s, Expected Method: %s%n",
|
||||
entry.name, je.getMethod(), entry.method);
|
||||
}
|
||||
assertEquals(entry.method, je.getMethod());
|
||||
try (InputStream in = jarFile.getInputStream(je)) {
|
||||
byte[] bytes = in.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf("bytes= %s, expected=%s%n",
|
||||
new String(bytes), new String(entry.bytes));
|
||||
}
|
||||
assertArrayEquals(entry.bytes, bytes,
|
||||
String.format("Expected payload: %s", new String(entry.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarInputStream can be used to read all entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void JarInputStreamTest() throws IOException {
|
||||
System.out.printf("%n%n**** JarInputStreamTest ***%n");
|
||||
try (JarInputStream jis = new JarInputStream(
|
||||
new FileInputStream(TEST_JAR.toFile()))) {
|
||||
JarEntry jarEntry = jis.getNextJarEntry();
|
||||
assertNotNull(jarEntry);
|
||||
while (jarEntry != null) {
|
||||
Entry e;
|
||||
if (jarEntry.getName().equals(FILE_ENTRY.name)) {
|
||||
e = FILE_ENTRY;
|
||||
} else if (jarEntry.getName().equals(DIR_ENTRY.name)) {
|
||||
e = DIR_ENTRY;
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
String.format("Invalid Jar entry: %s", jarEntry.getName()));
|
||||
}
|
||||
assertEquals(e.method, jarEntry.getMethod());
|
||||
assertArrayEquals(e.bytes, jis.readAllBytes(),
|
||||
String.format("Expected payload: %s", new String(e.bytes)));
|
||||
jarEntry = jis.getNextJarEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarURLConnection can be used to access all the entries including
|
||||
* a file and directory entry with the same name within a jar file
|
||||
*
|
||||
* @param entry The entry to validate
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("entries")
|
||||
public void JarURLConnectionTest(Entry entry) throws Exception {
|
||||
System.out.printf("%n%n**** JarURLConnectionTest ***%n");
|
||||
URL url = new URL("jar:" + TEST_JAR.toUri().toURL() + "!/" + entry.name);
|
||||
if (DEBUG) {
|
||||
System.out.printf("URL=%s%n", url);
|
||||
}
|
||||
JarURLConnection con = (JarURLConnection) url.openConnection();
|
||||
con.connect();
|
||||
JarEntry je = con.getJarEntry();
|
||||
try (JarFile jarFile = con.getJarFile()) {
|
||||
assertNotNull(je);
|
||||
assertNotNull(jarFile);
|
||||
assertNull(con.getAttributes());
|
||||
assertNull(con.getMainAttributes());
|
||||
assertNull(con.getManifest());
|
||||
assertEquals(entry.name, je.getName());
|
||||
assertEquals(entry.name, con.getEntryName());
|
||||
assertEquals(entry.method, je.getMethod());
|
||||
assertEquals(TEST_JAR.toUri().toURL(), con.getJarFileURL());
|
||||
if (DEBUG) {
|
||||
System.out.printf(" getEntryName: %s, getJarFileURL:%s%n",
|
||||
con.getEntryName(), con.getJarFileURL());
|
||||
System.out.printf(" Jar Entry= %s, size= %s%n", je.getName(), je.getSize());
|
||||
}
|
||||
|
||||
try (InputStream is = jarFile.getInputStream(je)) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
if (DEBUG) {
|
||||
System.out.printf(" Bytes read:%s%n", new String(bytes));
|
||||
}
|
||||
assertArrayEquals(entry.bytes, bytes,
|
||||
String.format("Expected payload: %s", new String(entry.bytes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that JarFile::stream returns all entries including
|
||||
* a file and directory entry with the same name
|
||||
*
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
@Test
|
||||
public void JarFileStreamTest() throws IOException {
|
||||
System.out.printf("%n%n**** JarFileStreamTest ***%n");
|
||||
try (JarFile jf = new JarFile(TEST_JAR.toFile())) {
|
||||
List<? extends JarEntry> entries = jf.stream().collect(Collectors.toList());
|
||||
assertEquals(EXPECTED_ENTRIES.size(), jf.size());
|
||||
for (JarEntry e : entries) {
|
||||
assertTrue(EXPECTED_ENTRIES.contains(e.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to read the bytes from an InputStream. This method is
|
||||
* here so that the test could be backported to JDK 8 if needed as
|
||||
* InputStream::readAllBytes() does not exist
|
||||
*
|
||||
* @param is The InputStream to read from
|
||||
* @return The byte array representing bytes read from the InputStream
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
public static byte[] readAllBytes(InputStream is) throws IOException {
|
||||
byte[] data = new byte[MAX_BUFFER_SIZE];
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int len;
|
||||
while ((len = is.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, len);
|
||||
}
|
||||
buffer.flush();
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to create a byte[] representing a Jar file with
|
||||
* duplicate file entries. This uses ZipArchiveOutputStream as ZipOutputStream
|
||||
* will fail with a "java.util.zip.ZipException: duplicate entry".
|
||||
*/
|
||||
// public static void createJarWithDuplicateFileEntries() throws IOException {
|
||||
// Files.deleteIfExists(DUPFILE_ENTRY_FILE);
|
||||
// try (ZipArchiveOutputStream zos =
|
||||
// new ZipArchiveOutputStream(DUPFILE_ENTRY_FILE.toFile())) {
|
||||
// zos.putArchiveEntry(new ZipArchiveEntry(FILE_ENTRY.name));
|
||||
// zos.write(FILE_ENTRY.bytes);
|
||||
// zos.putArchiveEntry(new ZipArchiveEntry(FILE_ENTRY.name));
|
||||
// zos.write("Yet another File".getBytes(StandardCharsets.UTF_8));
|
||||
// zos.closeArchiveEntry();
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// byte[] jarBytes = Files.readAllBytes(DUPFILE_ENTRY_FILE);
|
||||
// String result = createByteArray(jarBytes, "DUPLICATE_ENTRY_JAR_BYTES");
|
||||
// System.out.println(result);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Utility method which takes a byte array and converts to byte array
|
||||
* declaration. For example:
|
||||
* <pre>
|
||||
* {@code
|
||||
* var fooJar = Files.readAllBytes(Path.of("foo.jar"));
|
||||
* var result = createByteArray(fooJar, "FOOBYTES");
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param bytes A byte array used to create a byte array declaration
|
||||
* @param name Name to be used in the byte array declaration
|
||||
* @return The formatted byte array declaration
|
||||
*/
|
||||
public static String createByteArray(byte[] bytes, String name) {
|
||||
StringBuilder sb = new StringBuilder(bytes.length * 5);
|
||||
Formatter fmt = new Formatter(sb);
|
||||
fmt.format(" public static byte[] %s = {", name);
|
||||
final int linelen = 8;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
if (i % linelen == 0) {
|
||||
fmt.format("%n ");
|
||||
}
|
||||
fmt.format(" (byte) 0x%x,", bytes[i] & 0xff);
|
||||
}
|
||||
fmt.format("%n };%n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entry in a Zip file. An entry encapsulates a name, a
|
||||
* compression method, and its contents/data.
|
||||
*/
|
||||
public static class Entry {
|
||||
public final String name;
|
||||
public final int method;
|
||||
public final byte[] bytes;
|
||||
|
||||
public Entry(String name, int method, String contents) {
|
||||
this.name = name;
|
||||
this.method = method;
|
||||
this.bytes = contents.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static Entry of(String name, int method, String contents) {
|
||||
return new Entry(name, method, contents);
|
||||
}
|
||||
}
|
||||
}
|
||||
294
test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java
Normal file
294
test/jdk/java/util/zip/ZipFile/ZipFileInputStreamSkipTest.java
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8231451
|
||||
* @summary Basic tests for ZipFileInputStream::skip
|
||||
* @modules jdk.zipfs
|
||||
* @run junit/othervm ZipFileInputStreamSkipTest
|
||||
*/
|
||||
public class ZipFileInputStreamSkipTest {
|
||||
|
||||
// Stored and Deflated Zip File paths used by the tests
|
||||
private static final Path STORED_ZIPFILE = Path.of("skipStoredEntries.zip");
|
||||
private static final Path DEFLATED_ZIPFILE = Path.of("skipDeflatedEntries.zip");
|
||||
|
||||
// Saved Entries added to the relevant Zip file
|
||||
private static final HashMap<String, Entry> STORED_ZIP_ENTRIES = new HashMap<>();
|
||||
private static final HashMap<String, Entry> DEFLATED_ZIP_ENTRIES = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create the Zip Files used by the tests
|
||||
*
|
||||
* @throws IOException If an error occurs creating the Zip Files
|
||||
*/
|
||||
@BeforeAll
|
||||
static void createZip() throws IOException {
|
||||
Entry e0 = Entry.of("Entry-0", ZipEntry.STORED, "Tennis Pro");
|
||||
Entry e1 = Entry.of("Entry-1", ZipEntry.STORED,
|
||||
"United States Tennis Association");
|
||||
Entry e2 = Entry.of("Entry-2", ZipEntry.DEFLATED, "Cardio Tennis");
|
||||
Entry e3 = Entry.of("Entry-3", ZipEntry.DEFLATED, "USTA League Championships");
|
||||
|
||||
// Add entries
|
||||
STORED_ZIP_ENTRIES.put(e0.name, e0);
|
||||
STORED_ZIP_ENTRIES.put(e1.name, e1);
|
||||
DEFLATED_ZIP_ENTRIES.put(e2.name, e2);
|
||||
DEFLATED_ZIP_ENTRIES.put(e3.name, e3);
|
||||
|
||||
Files.deleteIfExists(STORED_ZIPFILE);
|
||||
Files.deleteIfExists(DEFLATED_ZIPFILE);
|
||||
|
||||
createZipFile(STORED_ZIPFILE,
|
||||
Map.of("create", "true", "noCompression", "true"),
|
||||
e0, e1);
|
||||
|
||||
createZipFile(DEFLATED_ZIPFILE, Map.of("create", "true"), e2, e3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Zip Files created for the test
|
||||
*
|
||||
* @throws IOException If an error occurs during cleanup
|
||||
*/
|
||||
@AfterAll
|
||||
static void cleanUp() throws IOException {
|
||||
Files.deleteIfExists(STORED_ZIPFILE);
|
||||
Files.deleteIfExists(DEFLATED_ZIPFILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that you can skip forward within a STORED entry
|
||||
* and then read the expected data for the entry
|
||||
*
|
||||
* @throws Exception If an error occurs during the test
|
||||
*/
|
||||
@Test
|
||||
public void testStoredSkip() throws Exception {
|
||||
|
||||
try (ZipFile zf = new ZipFile(STORED_ZIPFILE.toFile())) {
|
||||
var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
var entrySize = entry.getSize();
|
||||
long midpoint = entrySize / 2;
|
||||
Entry expected = STORED_ZIP_ENTRIES.get(entry.getName());
|
||||
assertNotNull(expected);
|
||||
try (InputStream in = zf.getInputStream(entry)) {
|
||||
|
||||
// Check that if we specify 0, that we return the correct
|
||||
// skip value value
|
||||
assertEquals(0, in.skip(0));
|
||||
|
||||
// Try to skip past EOF and should return remaining bytes
|
||||
assertEquals(entrySize, in.skip(entrySize + 100));
|
||||
|
||||
// Return to BOF and then specify a value which would
|
||||
// overflow the projected skip value and return the
|
||||
// number of bytes moved to reach EOF
|
||||
assertEquals(-entrySize, in.skip(-entrySize));
|
||||
assertEquals(entrySize, in.skip(Long.MAX_VALUE));
|
||||
|
||||
// From midpoint, try to skip past EOF and then skip back
|
||||
// to BOF
|
||||
assertEquals(-entrySize, in.skip(-entrySize));
|
||||
assertEquals(midpoint, in.skip(midpoint));
|
||||
assertEquals(entrySize - midpoint, in.skip(1000));
|
||||
assertEquals(-entrySize, in.skip(-entrySize));
|
||||
|
||||
// Read remaining bytes and validate against expected bytes
|
||||
byte[] bytes = in.readAllBytes();
|
||||
assertArrayEquals(expected.bytes, bytes);
|
||||
assertEquals(expected.bytes.length, bytes.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that you can skip backwards within a STORED entry
|
||||
* and then read the expected data for the entry
|
||||
*
|
||||
* @throws Exception If an error occurs during the test
|
||||
*/
|
||||
@Test
|
||||
public void testStoredNegativeSkip() throws Exception {
|
||||
|
||||
try (ZipFile zf = new ZipFile(STORED_ZIPFILE.toFile())) {
|
||||
var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
var entrySize = entry.getSize();
|
||||
var midpoint = entrySize / 2;
|
||||
Entry expected = STORED_ZIP_ENTRIES.get(entry.getName());
|
||||
assertNotNull(expected);
|
||||
try (InputStream in = zf.getInputStream(entry)) {
|
||||
|
||||
// Check that if you try to move past BOF
|
||||
// that we return the correct value
|
||||
assertEquals(0, in.skip(-1));
|
||||
assertEquals(0, in.skip(-100));
|
||||
assertEquals(0, in.skip(Long.MIN_VALUE));
|
||||
|
||||
// Go to midpoint in file; then specify a value before
|
||||
// BOF which should result in the number of
|
||||
// bytes to BOF returned
|
||||
assertEquals(midpoint, in.skip(midpoint));
|
||||
assertEquals(-midpoint, in.skip(-(midpoint + 10)));
|
||||
|
||||
// From midpoint, move back a couple of bytes
|
||||
assertEquals(midpoint, in.skip(midpoint));
|
||||
assertEquals(-2, in.skip(-2));
|
||||
|
||||
// Read the remaining bytes and compare to the expected bytes
|
||||
byte[] bytes = in.readAllBytes();
|
||||
assertArrayEquals(Arrays.copyOfRange(expected.bytes,
|
||||
(int)midpoint - 2, (int) entrySize), bytes);
|
||||
assertEquals(entrySize - midpoint + 2, bytes.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that you can skip forward within a DEFLATED entry
|
||||
* and then read the expected data for the entry
|
||||
*
|
||||
* @throws Exception If an error occurs during the test
|
||||
*/
|
||||
@Test
|
||||
public void testDeflatedSkip() throws Exception {
|
||||
try (ZipFile zf = new ZipFile(DEFLATED_ZIPFILE.toFile())) {
|
||||
var toSkip = 5; // Bytes to Skip
|
||||
var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
Entry expected = DEFLATED_ZIP_ENTRIES.get(entry.getName());
|
||||
assertNotNull(expected);
|
||||
try (InputStream in = zf.getInputStream(entry)) {
|
||||
assertEquals(toSkip, in.skip(toSkip));
|
||||
byte[] bytes = in.readAllBytes();
|
||||
var ebytes = Arrays.copyOfRange(expected.bytes,
|
||||
toSkip, expected.bytes.length);
|
||||
assertArrayEquals(ebytes, bytes);
|
||||
assertEquals(expected.bytes.length - toSkip, bytes.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an IllegalArgumentException is thrown if you specify
|
||||
* a negative skip value for a DEFLATED entry.
|
||||
*
|
||||
* @throws Exception If an unexpected error occurs during the test
|
||||
*/
|
||||
@Test
|
||||
public void testDeflatedIOException() throws Exception {
|
||||
try (ZipFile zf = new ZipFile(DEFLATED_ZIPFILE.toFile())) {
|
||||
var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
var entry = entries.nextElement();
|
||||
assertNotNull(entry);
|
||||
try (InputStream in = zf.getInputStream(entry)) {
|
||||
// Cannot specify a negative value
|
||||
assertThrows(IllegalArgumentException.class, () -> in.skip((-1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Zip File System using the specified properties and a Zip file
|
||||
* with the specified number of entries
|
||||
*
|
||||
* @param zipFile Path to the Zip File to create
|
||||
* @param env Properties used for creating the Zip Filesystem
|
||||
* @param entries The entries to add to the Zip File
|
||||
* @throws IOException If an error occurs while creating the Zip file
|
||||
*/
|
||||
private static void createZipFile(Path zipFile, Map<String, String> env,
|
||||
Entry... entries) throws IOException {
|
||||
try (FileSystem zipfs =
|
||||
FileSystems.newFileSystem(zipFile, env)) {
|
||||
for (Entry e : entries) {
|
||||
Files.writeString(zipfs.getPath(e.name), new String(e.bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an entry in a Zip file. An entry encapsulates a name, a
|
||||
* compression method, and its contents/data.
|
||||
*/
|
||||
static class Entry {
|
||||
private final String name;
|
||||
private final int method;
|
||||
private final byte[] bytes;
|
||||
|
||||
Entry(String name, int method, String contents) {
|
||||
this.name = name;
|
||||
this.method = method;
|
||||
this.bytes = contents.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
static Entry of(String name, int method, String contents) {
|
||||
return new Entry(name, method, contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new Entry with the same name and compression method as this
|
||||
* Entry but with the given content.
|
||||
*/
|
||||
Entry content(String contents) {
|
||||
return new Entry(name, method, contents);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
137
test/jdk/java/util/zip/ZipFile/ZipFileSharedSourceTest.java
Normal file
137
test/jdk/java/util/zip/ZipFile/ZipFileSharedSourceTest.java
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8347712
|
||||
* @summary verify that different instances of java.util.zip.ZipFile do not share
|
||||
* the same instance of (non-thread-safe) java.nio.charset.CharsetEncoder/CharsetDecoder
|
||||
* @run junit ZipFileSharedSourceTest
|
||||
*/
|
||||
public class ZipFileSharedSourceTest {
|
||||
|
||||
static Path createZipFile(final Charset charset) throws Exception {
|
||||
final Path zipFilePath = Files.createTempFile(Path.of("."), "8347712", ".zip");
|
||||
try (OutputStream os = Files.newOutputStream(zipFilePath);
|
||||
ZipOutputStream zos = new ZipOutputStream(os, charset)) {
|
||||
final int numEntries = 10240;
|
||||
for (int i = 1; i <= numEntries; i++) {
|
||||
final ZipEntry entry = new ZipEntry("entry-" + i);
|
||||
zos.putNextEntry(entry);
|
||||
zos.write("foo bar".getBytes(US_ASCII));
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
return zipFilePath;
|
||||
}
|
||||
|
||||
static List<Arguments> charsets() {
|
||||
return List.of(
|
||||
Arguments.of(StandardCharsets.UTF_8),
|
||||
Arguments.of(StandardCharsets.ISO_8859_1),
|
||||
Arguments.of(US_ASCII)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* In this test, multiple concurrent threads each create an instance of java.util.zip.ZipFile
|
||||
* with the given {@code charset} for the same underlying ZIP file. Each of the threads
|
||||
* then iterate over the entries of their ZipFile instance. The test verifies that such access,
|
||||
* where each thread is accessing an independent ZipFile instance corresponding to the same
|
||||
* underlying ZIP file, doesn't lead to unexpected failures contributed by concurrent
|
||||
* threads.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("charsets")
|
||||
void testMultipleZipFileInstances(final Charset charset) throws Exception {
|
||||
final Path zipFilePath = createZipFile(charset);
|
||||
final int numTasks = 200;
|
||||
final CountDownLatch startLatch = new CountDownLatch(numTasks);
|
||||
final List<Future<Void>> results = new ArrayList<>();
|
||||
try (final ExecutorService executor =
|
||||
Executors.newThreadPerTaskExecutor(Thread.ofPlatform().factory())) {
|
||||
for (int i = 0; i < numTasks; i++) {
|
||||
final var task = new ZipEntryIteratingTask(zipFilePath, charset,
|
||||
startLatch);
|
||||
results.add(executor.submit(task));
|
||||
}
|
||||
System.out.println(numTasks + " tasks submitted, waiting for them to complete");
|
||||
for (final Future<Void> f : results) {
|
||||
f.get();
|
||||
}
|
||||
}
|
||||
System.out.println("All " + numTasks + " tasks completed successfully");
|
||||
}
|
||||
|
||||
private static final class ZipEntryIteratingTask implements Callable<Void> {
|
||||
private final Path file;
|
||||
private final Charset charset;
|
||||
private final CountDownLatch startLatch;
|
||||
|
||||
private ZipEntryIteratingTask(final Path file, final Charset charset,
|
||||
final CountDownLatch startLatch) {
|
||||
this.file = file;
|
||||
this.charset = charset;
|
||||
this.startLatch = startLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
// let other tasks know we are ready to run
|
||||
this.startLatch.countDown();
|
||||
// wait for other tasks to be ready to run
|
||||
this.startLatch.await();
|
||||
// create a new instance of ZipFile and iterate over the entries
|
||||
try (final ZipFile zf = new ZipFile(this.file.toFile(), this.charset)) {
|
||||
final var entries = zf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final ZipEntry ze = entries.nextElement();
|
||||
// additionally exercise the ZipFile.getEntry() method
|
||||
zf.getEntry(ze.getName());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
164
test/jdk/java/util/zip/ZipFile/ZipSourceCache.java
Normal file
164
test/jdk/java/util/zip/ZipFile/ZipSourceCache.java
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8317678
|
||||
* @modules java.base/java.util.zip:open
|
||||
* @summary Fix up hashCode() for ZipFile.Source.Key
|
||||
* @library /test/lib
|
||||
* @run junit/othervm ZipSourceCache
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import jdk.test.lib.util.FileUtils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ZipSourceCache {
|
||||
|
||||
private static final String ZIPFILE_NAME =
|
||||
System.currentTimeMillis() + "-bug8317678.zip";
|
||||
private static final String ZIPENTRY_NAME = "random.txt";
|
||||
private static final String INVALID_LOC_EXCEPTION =
|
||||
"ZipFile invalid LOC header (bad signature)";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static File relativeFile = new File(ZIPFILE_NAME);
|
||||
private static File absoluteFile = new File(ZIPFILE_NAME).getAbsoluteFile();
|
||||
private static boolean hasfileKeySupport;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws Exception {
|
||||
createZipFile("test1");
|
||||
var attrs = Files.readAttributes(relativeFile.toPath(), BasicFileAttributes.class);
|
||||
hasfileKeySupport = (attrs.fileKey() != null);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void cleanup() throws IOException {
|
||||
FileUtils.deleteFileIfExistsWithRetry(Path.of(ZIPFILE_NAME));
|
||||
}
|
||||
|
||||
/*
|
||||
* Monitor the internal "files" HashMap to ensure that we only
|
||||
* create one <Key, Source> mapping per unique zip file.
|
||||
*
|
||||
* This test also ensures that a new <Key, Source> mapping is created
|
||||
* if an update to an existing zip file is detected.
|
||||
*/
|
||||
@Test
|
||||
public void testKeySourceMapping() throws Exception {
|
||||
ZipFile absoluteZipFile;
|
||||
HashMap internalMap;
|
||||
int numSources;
|
||||
try (ZipFile zipFile = new ZipFile(relativeFile)) {
|
||||
Class source = Class.forName("java.util.zip.ZipFile$Source");
|
||||
Field filesMap = source.getDeclaredField("files");
|
||||
filesMap.setAccessible(true);
|
||||
internalMap = (HashMap) filesMap.get(zipFile);
|
||||
numSources = internalMap.size();
|
||||
// opening of same zip file shouldn't cause new Source
|
||||
// to be constructed on filesystems which support fileKey()
|
||||
absoluteZipFile = new ZipFile(absoluteFile);
|
||||
if (hasfileKeySupport) {
|
||||
assertEquals(numSources, internalMap.size());
|
||||
} else {
|
||||
assertEquals(++numSources, internalMap.size());
|
||||
}
|
||||
|
||||
// update the zip file, should expect a new Source Object
|
||||
// ignore this part of test if file can't be updated (can't overwrite)
|
||||
if (createZipFile("differentContent")) {
|
||||
ZipFile z = new ZipFile(relativeFile);
|
||||
// update of file should trigger new <Key, Source> mapping
|
||||
assertEquals(++numSources, internalMap.size());
|
||||
// new Source created, CEN structure should map fine
|
||||
readZipFileContents(z);
|
||||
// the old Source in use for old file, should no longer map correctly
|
||||
IOException ioe = assertThrows(IOException.class, () -> readZipFileContents(absoluteZipFile));
|
||||
assertEquals(INVALID_LOC_EXCEPTION, ioe.getMessage());
|
||||
z.close();
|
||||
assertEquals(--numSources, internalMap.size());
|
||||
}
|
||||
}
|
||||
// with fileKey() support, the close() call shouldn't remove the
|
||||
// Source entry just yet since we still have one reference to the file
|
||||
if (hasfileKeySupport) {
|
||||
assertEquals(numSources, internalMap.size());
|
||||
} else {
|
||||
assertEquals(--numSources, internalMap.size());
|
||||
}
|
||||
if (absoluteZipFile != null) {
|
||||
absoluteZipFile.close();
|
||||
}
|
||||
// now, the Source entry key should be removed
|
||||
assertEquals(--numSources, internalMap.size());
|
||||
}
|
||||
|
||||
private static void readZipFileContents(ZipFile zf) throws IOException {
|
||||
var e = zf.entries();
|
||||
while (e.hasMoreElements()) {
|
||||
InputStream is = zf.getInputStream(e.nextElement());
|
||||
String s = new String(is.readAllBytes());
|
||||
if (DEBUG) System.err.println(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean createZipFile(String content) {
|
||||
CRC32 crc32 = new CRC32();
|
||||
long t = System.currentTimeMillis();
|
||||
// let's have at least 2 entries created to ensure
|
||||
// that a bad zip structure is detected if file is updated
|
||||
int numEntries = new Random().nextInt(10) + 2;
|
||||
File zipFile = new File(ZIPFILE_NAME);
|
||||
try (FileOutputStream fos = new FileOutputStream(zipFile);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
ZipOutputStream zos = new ZipOutputStream(bos)) {
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
ZipEntry e = new ZipEntry(ZIPENTRY_NAME + i);
|
||||
e.setMethod(ZipEntry.STORED);
|
||||
byte[] toWrite = content.repeat(i+1).getBytes();
|
||||
e.setTime(t);
|
||||
e.setSize(toWrite.length);
|
||||
crc32.reset();
|
||||
crc32.update(toWrite);
|
||||
e.setCrc(crc32.getValue());
|
||||
zos.putNextEntry(e);
|
||||
zos.write(toWrite);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// some systems mightn't allow file to be updated while open
|
||||
System.err.println("error updating file. " + e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue