Assortment.java revision 9330:8b1f1c2a400f
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 26 * @summary test a variety of zip file entries 27 * @author Martin Buchholz 28 */ 29 30import java.util.*; 31import java.util.zip.*; 32import java.util.jar.*; 33import java.io.*; 34 35public 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) throws Exception { 141 ZipEntry e = f.getEntry(name); 142 byte[] data = (this.data == null) ? new byte[]{} : this.data; 143 byte[] extra = (this.extra != null && this.extra.length == 0) ? 144 null : this.extra; 145 check(name.equals(e.getName())); 146 check(method == e.getMethod()); 147 check((((comment == null) || comment.equals("")) 148 && (e.getComment() == null)) 149 || comment.equals(e.getComment())); 150 check(equalsExtraData(extra, e.getExtra())); 151 check(Arrays.equals(data, getData(f, e))); 152 check(e.getSize() == data.length); 153 check((method == ZipEntry.DEFLATED) || 154 (e.getCompressedSize() == data.length)); 155 } 156 157 void verify(JarInputStream jis) throws Exception { 158 // JarInputStream "automatically" reads the manifest 159 if (name.equals("meta-iNf/ManIfEst.Mf")) 160 return; 161 ZipEntry e = jis.getNextEntry(); 162 163 byte[] data = (this.data == null) ? new byte[]{} : this.data; 164 byte[] otherData = new byte[data.length]; 165 jis.read(otherData); 166 check(Arrays.equals(data, otherData)); 167 168 byte[] extra = (this.extra != null && this.extra.length == 0) ? 169 null : this.extra; 170 check(equalsExtraData(extra, e.getExtra())); 171 check(name.equals(e.getName())); 172 check(method == e.getMethod()); 173 check(e.getSize() == -1 || e.getSize() == data.length); 174 check((method == ZipEntry.DEFLATED) || 175 (e.getCompressedSize() == data.length)); 176 177 } 178 } 179 180 private static int uniquifier = 86; 181 private static String uniquify(String name) { 182 return name + (uniquifier++); 183 } 184 185 private static byte[] toBytes(String s) throws Exception { 186 return s.getBytes("UTF-8"); 187 } 188 189 private static byte[] toExtra(byte[] bytes) throws Exception { 190 if (bytes == null) return null; 191 // Construct a fake extra field with valid header length 192 byte[] v = new byte[bytes.length + 4]; 193 v[0] = (byte) 0x47; 194 v[1] = (byte) 0xff; 195 v[2] = (byte) bytes.length; 196 v[3] = (byte) (bytes.length << 8); 197 System.arraycopy(bytes, 0, v, 4, bytes.length); 198 return v; 199 } 200 201 private static Random random = new Random(); 202 203 private static String makeName(int length) { 204 StringBuilder sb = new StringBuilder(length); 205 for (int i = 0; i < length; i++) 206 sb.append((char)(random.nextInt(10000)+1)); 207 return sb.toString(); 208 } 209 210 public static void main(String[] args) throws Exception { 211 File zipName = new File("x.zip"); 212 int[] methods = {ZipEntry.STORED, ZipEntry.DEFLATED}; 213 String[] names = {makeName(1), makeName(160), makeName(9000)}; 214 byte[][] datas = {null, new byte[]{}, new byte[]{'d'}}; 215 byte[][] extras = {null, new byte[]{}, new byte[]{'e'}}; 216 String[] comments = {null, "", "c"}; 217 218 List<Entry> entries = new ArrayList<Entry>(); 219 220 // Highly unusual manifest 221 entries.add(new Entry("meta-iNf/ManIfEst.Mf", 222 ZipEntry.STORED, 223 toBytes("maNiFest-VeRsIon: 1.0\n"), 224 toExtra(toBytes("Can manifests have extra??")), 225 "Can manifests have comments??")); 226 227 // The emptiest possible entry 228 entries.add(new Entry("", ZipEntry.STORED, null, null, "")); 229 230 for (String name : names) 231 for (int method : methods) 232 for (byte[] data : datas) // datae?? 233 for (byte[] extra : extras) 234 for (String comment : comments) 235 entries.add(new Entry(uniquify(name), method, data, 236 toExtra(extra), comment)); 237 238 //---------------------------------------------------------------- 239 // Write zip file using ZipOutputStream 240 //---------------------------------------------------------------- 241 try (FileOutputStream fos = new FileOutputStream(zipName); 242 ZipOutputStream zos = new ZipOutputStream(fos)) 243 { 244 for (Entry e : entries) 245 e.write(zos); 246 } 247 248 //---------------------------------------------------------------- 249 // Verify zip file contents using JarFile class 250 //---------------------------------------------------------------- 251 JarFile f = new JarFile(zipName); 252 253 check(f.getManifest() != null); 254 255 for (Entry e : entries) 256 e.verify(f); 257 258 f.close(); 259 260 //---------------------------------------------------------------- 261 // Verify zip file contents using JarInputStream class 262 //---------------------------------------------------------------- 263 JarInputStream jis = new JarInputStream( 264 new FileInputStream(zipName)); 265 266 // JarInputStream "automatically" reads the manifest 267 check(jis.getManifest() != null); 268 269 for (Entry e : entries) 270 e.verify(jis); 271 272 jis.close(); 273 274// String cmd = "unzip -t " + zipName.getPath() + " >/dev/tty"; 275// new ProcessBuilder(new String[]{"/bin/sh", "-c", cmd}).start().waitFor(); 276 277 zipName.deleteOnExit(); 278 279 System.out.printf("passed = %d, failed = %d%n", passed, failed); 280 if (failed > 0) throw new Exception("Some tests failed"); 281 } 282} 283