1 /* 2 * Copyright (c) 2005, 2013, 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 6303183 8048990 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 static final int get16(byte b[], int off) { 58 return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8); 59 } 60 61 // check if all "expected" extra fields equal to their 62 // corresponding fields in "extra". The "extra" might have 63 // timestamp fields added by ZOS. 64 static boolean equalsExtraData(byte[] expected, byte[] extra) { 65 if (expected == null) 66 return true; 67 int off = 0; 68 int len = expected.length; 69 while (off + 4 < len) { 70 int tag = get16(expected, off); 71 int sz = get16(expected, off + 2); 72 int off0 = 0; 73 int len0 = extra.length; 74 boolean matched = false; 75 while (off0 + 4 < len0) { 76 int tag0 = get16(extra, off0); 77 int sz0 = get16(extra, off0 + 2); 78 if (tag == tag0 && sz == sz0) { 79 matched = true; 80 for (int i = 0; i < sz; i++) { 81 if (expected[off + i] != extra[off0 +i]) 82 matched = false; 83 } 84 break; 85 } 86 off0 += (4 + sz0); 87 } 88 if (!matched) 89 return false; 90 off += (4 + sz); 91 } 92 return true; 93 } 94 95 private static class Entry { 96 private String name; 97 private int method; 98 private byte[] data; 99 private byte[] extra; 100 private String comment; 101 102 Entry(String name, 103 int method, 104 byte[] data, 105 byte[] extra, 106 String comment) { 107 this.name = name; 108 this.method = method; 109 this.data = data; 110 this.extra = extra; 111 this.comment = comment; 112 } 113 114 void write(ZipOutputStream s) throws Exception { 115 ZipEntry e = new ZipEntry(name); 116 CRC32 crc32 = new CRC32(); 117 e.setMethod(method); 118 if (method == ZipEntry.STORED) { 119 e.setSize(data == null ? 0 : data.length); 120 crc32.reset(); 121 if (data != null) crc32.update(data); 122 e.setCrc(crc32.getValue()); 123 } else { 124 e.setSize(0); 125 e.setCrc(0); 126 } 127 if (comment != null) e.setComment(comment); 128 if (extra != null) e.setExtra(extra); 129 s.putNextEntry(e); 130 if (data != null) s.write(data); 131 } 132 133 byte[] getData(ZipFile f, ZipEntry e) throws Exception { 134 byte[] fdata = new byte[(int)e.getSize()]; 135 InputStream is = f.getInputStream(e); 136 is.read(fdata); 137 return fdata; 138 } 139 140 void verify(ZipFile f, ZipEntry e) throws Exception { 141 verify(e, getData(f, e)); 142 } 143 144 void verify(ZipEntry e, byte[] eData) throws Exception { 145 byte[] data = (this.data == null) ? new byte[]{} : this.data; 146 byte[] extra = (this.extra != null && this.extra.length == 0) ? 147 null : this.extra; 148 check(name.equals(e.getName())); 149 check(method == e.getMethod()); 150 check((((comment == null) || comment.equals("")) 151 && (e.getComment() == null)) 152 || comment.equals(e.getComment())); 153 check(equalsExtraData(extra, e.getExtra())); 154 check(Arrays.equals(data, eData)); 155 check(e.getSize() == data.length); 156 check((method == ZipEntry.DEFLATED) || 157 (e.getCompressedSize() == data.length)); 158 } 159 160 void verify(ZipFile f) throws Exception { 161 ZipEntry e = f.getEntry(name); 162 verify(e, getData(f, e)); 163 } 164 165 void verifyZipInputStream(ZipInputStream s) throws Exception { 166 ZipEntry e = s.getNextEntry(); 167 168 byte[] data = (this.data == null) ? new byte[]{} : this.data; 169 byte[] otherData = new byte[data.length]; 170 s.read(otherData); 171 check(Arrays.equals(data, otherData)); 172 173 byte[] extra = (this.extra != null && this.extra.length == 0) ? 174 null : this.extra; 175 check(equalsExtraData(extra, e.getExtra())); 176 check(name.equals(e.getName())); 177 check(method == e.getMethod()); 178 check(e.getSize() == -1 || e.getSize() == data.length); 179 check((method == ZipEntry.DEFLATED) || 180 (e.getCompressedSize() == data.length)); 181 } 182 183 void verifyJarInputStream(JarInputStream s) throws Exception { 184 // JarInputStream "automatically" reads the manifest 185 if (name.equals("meta-iNf/ManIfEst.Mf")) 186 return; 187 188 verifyZipInputStream(s); 189 } 190 } 191 192 private static int uniquifier = 86; 193 private static String uniquify(String name) { 194 return name + (uniquifier++); 195 } 196 197 private static byte[] toBytes(String s) throws Exception { 198 return s.getBytes("UTF-8"); 199 } 200 201 private static byte[] toExtra(byte[] bytes) throws Exception { 202 if (bytes == null) return null; 203 // Construct a fake extra field with valid header length 204 byte[] v = new byte[bytes.length + 4]; 205 v[0] = (byte) 0x47; 206 v[1] = (byte) 0xff; 207 v[2] = (byte) bytes.length; 208 v[3] = (byte) (bytes.length << 8); 209 System.arraycopy(bytes, 0, v, 4, bytes.length); 210 return v; 211 } 212 213 private static Random random = new Random(); 214 215 private static String makeName(int length) { 216 StringBuilder sb = new StringBuilder(length); 217 for (int i = 0; i < length; i++) 218 sb.append((char)(random.nextInt(10000)+1)); 219 return sb.toString(); 220 } 221 222 public static void main(String[] args) throws Exception { 223 File zipName = new File("x.zip"); 224 int[] methods = {ZipEntry.STORED, ZipEntry.DEFLATED}; 225 String[] names = {makeName(1), makeName(160), makeName(9000)}; 226 byte[][] datas = {null, new byte[]{}, new byte[]{'d'}}; 227 byte[][] extras = {null, new byte[]{}, new byte[]{'e'}}; 228 String[] comments = {null, "", "c"}; 229 230 List<Entry> entries = new ArrayList<Entry>(); 231 232 // Highly unusual manifest 233 entries.add(new Entry("meta-iNf/ManIfEst.Mf", 234 ZipEntry.STORED, 235 toBytes("maNiFest-VeRsIon: 1.0\n"), 236 toExtra(toBytes("Can manifests have extra??")), 237 "Can manifests have comments??")); 238 239 // The emptiest possible entry 240 entries.add(new Entry("", ZipEntry.STORED, null, null, "")); 241 242 for (String name : names) 243 for (int method : methods) 244 for (byte[] data : datas) // datae?? 245 for (byte[] extra : extras) 246 for (String comment : comments) 247 entries.add(new Entry(uniquify(name), method, data, 248 toExtra(extra), comment)); 249 250 //---------------------------------------------------------------- 251 // Write zip file using ZipOutputStream 252 //---------------------------------------------------------------- 253 try (FileOutputStream fos = new FileOutputStream(zipName); 254 ZipOutputStream zos = new ZipOutputStream(fos)) 255 { 256 for (Entry e : entries) 257 e.write(zos); 258 } 259 260 //---------------------------------------------------------------- 261 // Verify zip file contents using ZipFile.getEntry() 262 //---------------------------------------------------------------- 263 try (ZipFile f = new ZipFile(zipName)) { 264 for (Entry e : entries) 265 e.verify(f); 266 } 267 268 //---------------------------------------------------------------- 269 // Verify zip file contents using JarFile.getEntry() 270 //---------------------------------------------------------------- 271 try (JarFile f = new JarFile(zipName)) { 272 check(f.getManifest() != null); 273 for (Entry e : entries) 274 e.verify(f); 275 } 276 277 //---------------------------------------------------------------- 278 // Verify zip file contents using ZipFile.entries() 279 //---------------------------------------------------------------- 280 try (ZipFile f = new ZipFile(zipName)) { 281 Enumeration<? extends ZipEntry> en = f.entries(); 282 for (Entry e : entries) 283 e.verify(f, en.nextElement()); 284 285 check(!en.hasMoreElements()); 286 } 287 288 //---------------------------------------------------------------- 289 // Verify zip file contents using JarFile.entries() 290 //---------------------------------------------------------------- 291 try (JarFile f = new JarFile(zipName)) { 292 Enumeration<? extends ZipEntry> en = f.entries(); 293 for (Entry e : entries) 294 e.verify(f, en.nextElement()); 295 296 check(!en.hasMoreElements()); 297 } 298 299 //---------------------------------------------------------------- 300 // Verify zip file contents using ZipInputStream class 301 //---------------------------------------------------------------- 302 try (FileInputStream fis = new FileInputStream(zipName); 303 ZipInputStream s = new ZipInputStream(fis)) { 304 305 for (Entry e : entries) 306 e.verifyZipInputStream(s); 307 } 308 309 //---------------------------------------------------------------- 310 // Verify zip file contents using JarInputStream class 311 //---------------------------------------------------------------- 312 try (FileInputStream fis = new FileInputStream(zipName); 313 JarInputStream s = new JarInputStream(fis)) { 314 315 // JarInputStream "automatically" reads the manifest 316 check(s.getManifest() != null); 317 318 for (Entry e : entries) 319 e.verifyJarInputStream(s); 320 } 321 322 // String cmd = "unzip -t " + zipName.getPath() + " >/dev/tty"; 323 // new ProcessBuilder(new String[]{"/bin/sh", "-c", cmd}).start().waitFor(); 324 325 zipName.deleteOnExit(); 326 327 System.out.printf("passed = %d, failed = %d%n", passed, failed); 328 if (failed > 0) throw new Exception("Some tests failed"); 329 } 330 }