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