1 /* 2 * Copyright (c) 2005, Oracle and/or its affiliates. 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 /* @test 25 * @bug 4770745 6234507 26 * @summary test a variety of zip file entries 27 * @author Martin Buchholz 28 */ 29 30 import java.util.*; 31 import java.util.zip.*; 32 import java.util.jar.*; 33 import java.io.*; 34 35 public class Assortment { 36 static int passed = 0, failed = 0; 37 38 static void fail(String msg) { 39 failed++; 40 new Exception(msg).printStackTrace(); 41 } 42 43 static void unexpected(Throwable t) { 44 failed++; 45 t.printStackTrace(); 46 } 47 48 static void check(boolean condition, String msg) { 49 if (! condition) 50 fail(msg); 51 } 52 53 static void check(boolean condition) { 54 check(condition, "Something's wrong"); 55 } 56 57 private static class Entry { 58 private String name; 59 private int method; 60 private byte[] data; 61 private byte[] extra; 62 private String comment; 63 64 Entry(String name, 65 int method, 66 byte[] data, 67 byte[] extra, 68 String comment) { 69 this.name = name; 70 this.method = method; 71 this.data = data; 72 this.extra = extra; 73 this.comment = comment; 74 } 75 76 void write(ZipOutputStream s) throws Exception { 77 ZipEntry e = new ZipEntry(name); 78 CRC32 crc32 = new CRC32(); 79 e.setMethod(method); 80 if (method == ZipEntry.STORED) { 81 e.setSize(data == null ? 0 : data.length); 82 crc32.reset(); 83 if (data != null) crc32.update(data); 84 e.setCrc(crc32.getValue()); 85 } else { 86 e.setSize(0); 87 e.setCrc(0); 88 } 89 if (comment != null) e.setComment(comment); 90 if (extra != null) e.setExtra(extra); 91 s.putNextEntry(e); 92 if (data != null) s.write(data); 93 } 94 95 byte[] getData(ZipFile f, ZipEntry e) throws Exception { 96 byte[] fdata = new byte[(int)e.getSize()]; 97 InputStream is = f.getInputStream(e); 98 is.read(fdata); 99 return fdata; 100 } 101 102 void verify(ZipFile f) throws Exception { 103 ZipEntry e = f.getEntry(name); 104 byte[] data = (this.data == null) ? new byte[]{} : this.data; 105 byte[] extra = (this.extra != null && this.extra.length == 0) ? 106 null : this.extra; 107 check(name.equals(e.getName())); 108 check(method == e.getMethod()); 109 check((((comment == null) || comment.equals("")) 110 && (e.getComment() == null)) 111 || comment.equals(e.getComment())); 112 check(Arrays.equals(extra, e.getExtra())); 113 check(Arrays.equals(data, getData(f, e))); 114 check(e.getSize() == data.length); 115 check((method == ZipEntry.DEFLATED) || 116 (e.getCompressedSize() == data.length)); 117 } 118 119 void verify(JarInputStream jis) throws Exception { 120 // JarInputStream "automatically" reads the manifest 121 if (name.equals("meta-iNf/ManIfEst.Mf")) 122 return; 123 ZipEntry e = jis.getNextEntry(); 124 125 byte[] data = (this.data == null) ? new byte[]{} : this.data; 126 byte[] otherData = new byte[data.length]; 127 jis.read(otherData); 128 check(Arrays.equals(data, otherData)); 129 130 byte[] extra = (this.extra != null && this.extra.length == 0) ? 131 null : this.extra; 132 check(Arrays.equals(extra, e.getExtra())); 133 134 check(name.equals(e.getName())); 135 check(method == e.getMethod()); 136 check(e.getSize() == -1 || e.getSize() == data.length); 137 check((method == ZipEntry.DEFLATED) || 138 (e.getCompressedSize() == data.length)); 139 140 } 141 } 142 143 private static int uniquifier = 86; 144 private static String uniquify(String name) { 145 return name + (uniquifier++); 146 } 147 148 private static byte[] toBytes(String s) throws Exception { 149 return s.getBytes("UTF-8"); 150 } 151 152 private static byte[] toExtra(byte[] bytes) throws Exception { 153 if (bytes == null) return null; 154 // Construct a fake extra field with valid header length 155 byte[] v = new byte[bytes.length + 4]; 156 v[0] = (byte) 0x47; 157 v[1] = (byte) 0xff; 158 v[2] = (byte) bytes.length; 159 v[3] = (byte) (bytes.length << 8); 160 System.arraycopy(bytes, 0, v, 4, bytes.length); 161 return v; 162 } 163 164 private static Random random = new Random(); 165 166 private static String makeName(int length) { 167 StringBuilder sb = new StringBuilder(length); 168 for (int i = 0; i < length; i++) 169 sb.append((char)(random.nextInt(10000)+1)); 170 return sb.toString(); 171 } 172 173 public static void main(String[] args) throws Exception { 174 File zipName = new File("x.zip"); 175 int[] methods = {ZipEntry.STORED, ZipEntry.DEFLATED}; 176 String[] names = {makeName(1), makeName(160), makeName(9000)}; 177 byte[][] datas = {null, new byte[]{}, new byte[]{'d'}}; 178 byte[][] extras = {null, new byte[]{}, new byte[]{'e'}}; 179 String[] comments = {null, "", "c"}; 180 181 List<Entry> entries = new ArrayList<Entry>(); 182 183 // Highly unusual manifest 184 entries.add(new Entry("meta-iNf/ManIfEst.Mf", 185 ZipEntry.STORED, 186 toBytes("maNiFest-VeRsIon: 1.0\n"), 187 toExtra(toBytes("Can manifests have extra??")), 188 "Can manifests have comments??")); 189 190 // The emptiest possible entry 191 entries.add(new Entry("", ZipEntry.STORED, null, null, "")); 192 193 for (String name : names) 194 for (int method : methods) 195 for (byte[] data : datas) // datae?? 196 for (byte[] extra : extras) 197 for (String comment : comments) 198 entries.add(new Entry(uniquify(name), method, data, 199 toExtra(extra), comment)); 200 201 //---------------------------------------------------------------- 202 // Write zip file using ZipOutputStream 203 //---------------------------------------------------------------- 204 ZipOutputStream zos = new ZipOutputStream( 205 new FileOutputStream(zipName)); 206 207 for (Entry e : entries) 208 e.write(zos); 209 210 zos.close(); 211 212 //---------------------------------------------------------------- 213 // Verify zip file contents using JarFile class 214 //---------------------------------------------------------------- 215 JarFile f = new JarFile(zipName); 216 217 check(f.getManifest() != null); 218 219 for (Entry e : entries) 220 e.verify(f); 221 222 f.close(); 223 224 //---------------------------------------------------------------- 225 // Verify zip file contents using JarInputStream class 226 //---------------------------------------------------------------- 227 JarInputStream jis = new JarInputStream( 228 new FileInputStream(zipName)); 229 230 // JarInputStream "automatically" reads the manifest 231 check(jis.getManifest() != null); 232 233 for (Entry e : entries) 234 e.verify(jis); 235 236 jis.close(); 237 238 // String cmd = "unzip -t " + zipName.getPath() + " >/dev/tty"; 239 // new ProcessBuilder(new String[]{"/bin/sh", "-c", cmd}).start().waitFor(); 240 241 zipName.deleteOnExit(); 242 243 System.out.printf("passed = %d, failed = %d%n", passed, failed); 244 if (failed > 0) throw new Exception("Some tests failed"); 245 } 246 }