1/* 2 * Copyright (c) 2013 Google Inc. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/** 25 * @test 26 * @summary Test java.util.zip behavior with ~64k entries 27 * @library /lib/testlibrary 28 * @run main/othervm EntryCount64k 29 * @run main/othervm -Djdk.util.zip.inhibitZip64=true EntryCount64k 30 * @run main/othervm -Djdk.util.zip.inhibitZip64=false EntryCount64k 31 */ 32 33import java.io.BufferedInputStream; 34import java.io.BufferedOutputStream; 35import java.io.File; 36import java.nio.file.Files; 37import java.io.FileInputStream; 38import java.io.FileOutputStream; 39import java.io.RandomAccessFile; 40import java.nio.file.Paths; 41import java.util.Enumeration; 42import java.util.zip.ZipEntry; 43import java.util.zip.ZipFile; 44import java.util.zip.ZipInputStream; 45import java.util.zip.ZipOutputStream; 46 47import jdk.testlibrary.OutputAnalyzer; 48import jdk.testlibrary.ProcessTools; 49 50public class EntryCount64k { 51 public static class Main { 52 public static void main(String[] args) { 53 System.out.print("Main"); 54 } 55 } 56 57 static final String MAIN_CLASS = "EntryCount64k$Main"; 58 static final String THIS_CLASS = "EntryCount64k"; 59 static final String[] SPECIAL_CLASSES = { MAIN_CLASS, THIS_CLASS }; 60 // static final String[] SPECIAL_CLASSES = { MAIN_CLASS }; 61 static final int SPECIAL_COUNT = 1 + SPECIAL_CLASSES.length; 62 63 public static void main(String[] args) throws Throwable { 64 for (int i = (1 << 16) - 3; i < (1 << 16) + 2; i++) 65 test(i); 66 } 67 68 static void test(int entryCount) throws Throwable { 69 File zipFile = new File("EntryCount64k-tmp.zip"); 70 zipFile.delete(); 71 72 try (FileOutputStream fos = new FileOutputStream(zipFile); 73 BufferedOutputStream bos = new BufferedOutputStream(fos); 74 ZipOutputStream zos = new ZipOutputStream(bos)) { 75 76 // Add entries to allow the zip file to be used with "java -jar" 77 zos.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF")); 78 for (String line : new String[] { 79 "Manifest-Version: 1.0", 80 "Main-Class: " + MAIN_CLASS, 81 }) 82 zos.write((line + "\n").getBytes("US-ASCII")); 83 zos.closeEntry(); 84 85 String testClasses = System.getProperty("test.classes"); 86 for (String className : SPECIAL_CLASSES) { 87 String baseName = className + ".class"; 88 ZipEntry ze = new ZipEntry(baseName); 89 File file = new File(testClasses, baseName); 90 zos.putNextEntry(ze); 91 Files.copy(file.toPath(), zos); 92 zos.closeEntry(); 93 } 94 95 for (int i = SPECIAL_COUNT; i < entryCount; i++) { 96 zos.putNextEntry(new ZipEntry(Integer.toString(i))); 97 zos.closeEntry(); 98 } 99 } 100 101 String p = System.getProperty("jdk.util.zip.inhibitZip64"); 102 boolean tooManyEntries = entryCount >= (1 << 16) - 1; 103 boolean shouldUseZip64 = tooManyEntries & !("true".equals(p)); 104 boolean usesZip64 = usesZip64(zipFile); 105 String details = String.format 106 ("entryCount=%d shouldUseZip64=%s usesZip64=%s zipSize=%d%n", 107 entryCount, shouldUseZip64, usesZip64, zipFile.length()); 108 System.err.println(details); 109 checkCanRead(zipFile, entryCount); 110 if (shouldUseZip64 != usesZip64) 111 throw new Error(details); 112 zipFile.delete(); 113 } 114 115 static boolean usesZip64(File zipFile) throws Exception { 116 RandomAccessFile raf = new RandomAccessFile(zipFile, "r"); 117 byte[] buf = new byte[4096]; 118 raf.seek(raf.length() - buf.length); 119 raf.read(buf); 120 for (int i = 0; i < buf.length - 4; i++) { 121 // Look for ZIP64 End Header Signature 122 // Phil Katz: yes, we will always remember you 123 if (buf[i+0] == 'P' && 124 buf[i+1] == 'K' && 125 buf[i+2] == 6 && 126 buf[i+3] == 6) 127 return true; 128 } 129 return false; 130 } 131 132 static void checkCanRead(File zipFile, int entryCount) throws Throwable { 133 // Check ZipInputStream API 134 try (FileInputStream fis = new FileInputStream(zipFile); 135 BufferedInputStream bis = new BufferedInputStream(fis); 136 ZipInputStream zis = new ZipInputStream(bis)) { 137 for (int i = 0; i < entryCount; i++) { 138 ZipEntry e = zis.getNextEntry(); 139 if (i >= SPECIAL_COUNT) // skip special entries 140 if (Integer.parseInt(e.getName()) != i) 141 throw new AssertionError(e.getName()); 142 } 143 if (zis.getNextEntry() != null) 144 throw new AssertionError(); 145 } 146 147 // Check ZipFile API 148 try (ZipFile zf = new ZipFile(zipFile)) { 149 Enumeration<? extends ZipEntry> en = zf.entries(); 150 for (int i = 0; i < entryCount; i++) { 151 ZipEntry e = en.nextElement(); 152 if (i >= SPECIAL_COUNT) // skip special entries 153 if (Integer.parseInt(e.getName()) != i) 154 throw new AssertionError(); 155 } 156 if (en.hasMoreElements() 157 || (zf.size() != entryCount) 158 || (zf.getEntry(Integer.toString(entryCount - 1)) == null) 159 || (zf.getEntry(Integer.toString(entryCount)) != null)) 160 throw new AssertionError(); 161 } 162 163 // Check java -jar 164 String javaHome = System.getProperty("java.home"); 165 String java = Paths.get(javaHome, "bin", "java").toString(); 166 String[] cmd = { java, "-jar", zipFile.getName() }; 167 ProcessBuilder pb = new ProcessBuilder(cmd); 168 OutputAnalyzer a = ProcessTools.executeProcess(pb); 169 a.shouldHaveExitValue(0); 170 a.stdoutShouldMatch("\\AMain\\Z"); 171 a.stderrShouldMatch("\\A\\Z"); 172 } 173} 174