diff -r 4ebc2e2fb97c -r 71c04702a3d5 test/jdk/java/util/zip/ZipFile/Assortment.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/util/zip/ZipFile/Assortment.java Tue Sep 12 19:03:39 2017 +0200 @@ -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 entries = new ArrayList(); + + // 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 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 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"); + } +}