1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.archivers;
20
21 import static java.nio.charset.StandardCharsets.UTF_8;
22 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
24 import static org.junit.jupiter.api.Assertions.assertEquals;
25 import static org.junit.jupiter.api.Assertions.assertFalse;
26 import static org.junit.jupiter.api.Assertions.assertNotNull;
27 import static org.junit.jupiter.api.Assertions.assertNull;
28 import static org.junit.jupiter.api.Assertions.assertThrows;
29 import static org.junit.jupiter.api.Assertions.assertTrue;
30
31 import java.io.ByteArrayInputStream;
32 import java.io.ByteArrayOutputStream;
33 import java.io.File;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.OutputStream;
37 import java.nio.channels.Channels;
38 import java.nio.channels.SeekableByteChannel;
39 import java.nio.file.Files;
40 import java.nio.file.Path;
41 import java.nio.file.Paths;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Enumeration;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.zip.ZipEntry;
49 import java.util.zip.ZipException;
50
51 import org.apache.commons.compress.AbstractTest;
52 import org.apache.commons.compress.archivers.zip.Zip64Mode;
53 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
54 import org.apache.commons.compress.archivers.zip.ZipArchiveEntryPredicate;
55 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
56 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
57 import org.apache.commons.compress.archivers.zip.ZipFile;
58 import org.apache.commons.compress.archivers.zip.ZipMethod;
59 import org.apache.commons.compress.archivers.zip.ZipSplitReadOnlySeekableByteChannel;
60 import org.apache.commons.compress.utils.InputStreamStatistics;
61 import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
62 import org.apache.commons.io.IOUtils;
63 import org.junit.jupiter.api.Test;
64
65 public final class ZipTest extends AbstractTest {
66
67 final String first_payload = "ABBA";
68
69 final String second_payload = "AAAAAAAAAAAA";
70
71 final ZipArchiveEntryPredicate allFilesPredicate = zipArchiveEntry -> true;
72
73 private void addFilesToZip(final ZipArchiveOutputStream zipArchiveOutputStream, final File fileToAdd) throws IOException {
74 if (fileToAdd.isDirectory()) {
75 for (final File file : fileToAdd.listFiles()) {
76 addFilesToZip(zipArchiveOutputStream, file);
77 }
78 } else {
79 final ZipArchiveEntry zipArchiveEntry = new ZipArchiveEntry(fileToAdd.getPath());
80 zipArchiveEntry.setMethod(ZipEntry.DEFLATED);
81
82 zipArchiveOutputStream.putArchiveEntry(zipArchiveEntry);
83 try {
84 Files.copy(fileToAdd.toPath(), zipArchiveOutputStream);
85 } finally {
86 zipArchiveOutputStream.closeArchiveEntry();
87 }
88 }
89 }
90
91 private void assertSameFileContents(final File expectedFile, final File actualFile) throws IOException {
92 final int size = (int) Math.max(expectedFile.length(), actualFile.length());
93 try (ZipFile expected = newZipFile(expectedFile);
94 ZipFile actual = newZipFile(actualFile)) {
95 final byte[] expectedBuf = new byte[size];
96 final byte[] actualBuf = new byte[size];
97
98 final Enumeration<ZipArchiveEntry> actualInOrder = actual.getEntriesInPhysicalOrder();
99 final Enumeration<ZipArchiveEntry> expectedInOrder = expected.getEntriesInPhysicalOrder();
100
101 while (actualInOrder.hasMoreElements()) {
102 final ZipArchiveEntry actualElement = actualInOrder.nextElement();
103 final ZipArchiveEntry expectedElement = expectedInOrder.nextElement();
104 assertEquals(expectedElement.getName(), actualElement.getName());
105
106
107 assertEquals(expectedElement.getMethod(), actualElement.getMethod());
108 assertEquals(expectedElement.getGeneralPurposeBit(), actualElement.getGeneralPurposeBit());
109 assertEquals(expectedElement.getCrc(), actualElement.getCrc());
110 assertEquals(expectedElement.getCompressedSize(), actualElement.getCompressedSize());
111 assertEquals(expectedElement.getSize(), actualElement.getSize());
112 assertEquals(expectedElement.getExternalAttributes(), actualElement.getExternalAttributes());
113 assertEquals(expectedElement.getInternalAttributes(), actualElement.getInternalAttributes());
114
115 try (InputStream actualIs = actual.getInputStream(actualElement);
116 InputStream expectedIs = expected.getInputStream(expectedElement)) {
117 org.apache.commons.compress.utils.IOUtils.readFully(expectedIs, expectedBuf);
118 org.apache.commons.compress.utils.IOUtils.readFully(actualIs, actualBuf);
119 }
120 assertArrayEquals(expectedBuf, actualBuf);
121 }
122
123 }
124 }
125
126 private int countNonDirectories(final File file) {
127 if (!file.isDirectory()) {
128 return 1;
129 }
130
131 int result = 0;
132 for (final File fileInDirectory : file.listFiles()) {
133 result += countNonDirectories(fileInDirectory);
134 }
135
136 return result;
137 }
138
139 private void createArchiveEntry(final String payload, final ZipArchiveOutputStream zos, final String name) throws IOException {
140 final ZipArchiveEntry in = new ZipArchiveEntry(name);
141 zos.putArchiveEntry(in);
142
143 zos.write(payload.getBytes());
144 zos.closeArchiveEntry();
145 }
146
147 private byte[] createArtificialData(final int size) {
148 final ByteArrayOutputStream output = new ByteArrayOutputStream();
149 for (int i = 0; i < size; i += 1) {
150 output.write((byte) ((i & 1) == 0 ? i / 2 % 256 : i / 2 / 256));
151 }
152 return output.toByteArray();
153 }
154
155 private ZipArchiveOutputStream createFirstEntry(final ZipArchiveOutputStream zos) throws IOException {
156 createArchiveEntry(first_payload, zos, "file1.txt");
157 return zos;
158 }
159
160 private File createReferenceFile(final Zip64Mode zipMode, final String prefix) throws IOException {
161 final File reference = createTempFile(prefix, ".zip");
162 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(reference)) {
163 zos.setUseZip64(zipMode);
164 createFirstEntry(zos);
165 createSecondEntry(zos);
166 }
167 return reference;
168 }
169
170 private ZipArchiveOutputStream createSecondEntry(final ZipArchiveOutputStream zos) throws IOException {
171 createArchiveEntry(second_payload, zos, "file2.txt");
172 return zos;
173 }
174
175 private void createTestSplitZipSegments() throws IOException {
176 final File directoryToZip = getFilesToZip();
177 final File outputZipFile = newTempFile("splitZip.zip");
178 final long splitSize = 100 * 1024L;
179 try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(outputZipFile, splitSize)) {
180 addFilesToZip(zipArchiveOutputStream, directoryToZip);
181 }
182 }
183
184 private File getFilesToZip() throws IOException {
185 final File originalZipFile = getFile("COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip.zip");
186 try (ZipFile zipFile = newZipFile(originalZipFile)) {
187 final Enumeration<ZipArchiveEntry> zipEntries = zipFile.getEntries();
188 ZipArchiveEntry zipEntry;
189 File outputFile;
190 byte[] buffer;
191 int readLen;
192
193 while (zipEntries.hasMoreElements()) {
194 zipEntry = zipEntries.nextElement();
195 if (zipEntry.isDirectory()) {
196 continue;
197 }
198
199 outputFile = newTempFile(zipEntry.getName());
200 if (!outputFile.getParentFile().exists()) {
201 outputFile.getParentFile().mkdirs();
202 }
203 outputFile = newTempFile(zipEntry.getName());
204
205 try (InputStream inputStream = zipFile.getInputStream(zipEntry);
206 OutputStream outputStream = Files.newOutputStream(outputFile.toPath())) {
207 buffer = new byte[(int) zipEntry.getSize()];
208 while ((readLen = inputStream.read(buffer)) > 0) {
209 outputStream.write(buffer, 0, readLen);
210 }
211 }
212 }
213 }
214 return getTempDirFile().listFiles()[0];
215 }
216
217 private ZipFile newZipFile(final File file) throws IOException {
218 return ZipFile.builder().setFile(file).get();
219 }
220
221 private void readStream(final InputStream in, final ArchiveEntry entry, final Map<String, List<List<Long>>> map) throws IOException {
222 final byte[] buf = new byte[4096];
223 final InputStreamStatistics stats = (InputStreamStatistics) in;
224 while (in.read(buf) != -1) {
225
226 }
227
228 final String name = entry.getName();
229 final List<List<Long>> list = map.computeIfAbsent(name, k -> new ArrayList<>());
230
231 final long t = stats.getUncompressedCount();
232 final long b = stats.getCompressedCount();
233 list.add(Arrays.asList(t, b));
234 }
235
236
237
238
239 @Test
240 public void testBuildArtificialSplitZip32Test() throws IOException {
241 final File outputZipFile = newTempFile("artificialSplitZip.zip");
242 final long splitSize = 64 * 1024L;
243 try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(outputZipFile, splitSize)) {
244 zipArchiveOutputStream.setUseZip64(Zip64Mode.Never);
245 final ZipArchiveEntry ze1 = new ZipArchiveEntry("file01");
246 ze1.setMethod(ZipEntry.STORED);
247 zipArchiveOutputStream.putArchiveEntry(ze1);
248 zipArchiveOutputStream.write(createArtificialData(65536));
249 zipArchiveOutputStream.closeArchiveEntry();
250 final ZipArchiveEntry ze2 = new ZipArchiveEntry("file02");
251 ze2.setMethod(ZipEntry.DEFLATED);
252 zipArchiveOutputStream.putArchiveEntry(ze2);
253 zipArchiveOutputStream.write(createArtificialData(65536));
254 zipArchiveOutputStream.closeArchiveEntry();
255 }
256
257 try (ZipFile zipFile = ZipFile.builder()
258 .setPath(outputZipFile.toPath())
259 .setMaxNumberOfDisks(Integer.MAX_VALUE)
260 .get()
261 ) {
262 assertArrayEquals(createArtificialData(65536), IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file01"))));
263 assertArrayEquals(createArtificialData(65536), IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file02"))));
264 }
265 }
266
267
268
269
270 @Test
271 public void testBuildArtificialSplitZip64Test() throws IOException {
272 final File outputZipFile = newTempFile("artificialSplitZip.zip");
273 final long splitSize = 64 * 1024L;
274 final byte[] data = createArtificialData(128 * 1024);
275 try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(outputZipFile, splitSize)) {
276 zipArchiveOutputStream.setUseZip64(Zip64Mode.Always);
277 final ZipArchiveEntry ze1 = new ZipArchiveEntry("file01");
278 ze1.setMethod(ZipEntry.STORED);
279 zipArchiveOutputStream.putArchiveEntry(ze1);
280 zipArchiveOutputStream.write(data);
281 zipArchiveOutputStream.closeArchiveEntry();
282 final ZipArchiveEntry ze2 = new ZipArchiveEntry("file02");
283 ze2.setMethod(ZipEntry.DEFLATED);
284 zipArchiveOutputStream.putArchiveEntry(ze2);
285 zipArchiveOutputStream.write(data);
286 zipArchiveOutputStream.closeArchiveEntry();
287 }
288 try (ZipFile zipFile = ZipFile.builder().setPath(outputZipFile.toPath()).setMaxNumberOfDisks(Integer.MAX_VALUE).get()) {
289 assertArrayEquals(data, IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file01"))));
290 assertArrayEquals(data, IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file02"))));
291 }
292 }
293
294
295
296
297 @Test
298 public void testBuildSplitZip32_endOfCentralDirectorySkipBoundary() throws IOException {
299 final File outputZipFile = newTempFile("artificialSplitZip.zip");
300 final long splitSize = 64 * 1024L;
301
302
303
304 final byte[] data1 = createArtificialData(64 * 1024 - 4 - 36 - 52 - 1);
305 try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(outputZipFile, splitSize)) {
306 zipArchiveOutputStream.setUseZip64(Zip64Mode.Never);
307 final ZipArchiveEntry ze1 = new ZipArchiveEntry("file01");
308 ze1.setMethod(ZipEntry.STORED);
309 zipArchiveOutputStream.putArchiveEntry(ze1);
310 zipArchiveOutputStream.write(data1);
311 zipArchiveOutputStream.closeArchiveEntry();
312 }
313 assertEquals(64 * 1024L - 1, Files.size(outputZipFile.toPath().getParent().resolve("artificialSplitZip.z01")));
314 try (ZipFile zipFile = ZipFile.builder().setPath(outputZipFile.toPath()).setMaxNumberOfDisks(Integer.MAX_VALUE).get()) {
315 assertArrayEquals(data1, IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file01"))));
316 }
317 }
318
319
320
321
322 @Test
323 public void testBuildSplitZip32_metaCrossBoundary() throws IOException {
324 final File outputZipFile = newTempFile("artificialSplitZip.zip");
325 final long splitSize = 64 * 1024L;
326
327
328 final byte[] data1 = createArtificialData(64 * 1024 - 4 - 36 - 15);
329
330
331 final byte[] data2 = createArtificialData(64 * 1024 - 21 - 19);
332
333
334 final byte[] data3 = createArtificialData(64 * 1024 - 17 - 23);
335
336
337 final byte[] data4 = createArtificialData(64 * 1024 - 13 + 1);
338 try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(outputZipFile, splitSize)) {
339 zipArchiveOutputStream.setUseZip64(Zip64Mode.Never);
340 final ZipArchiveEntry ze1 = new ZipArchiveEntry("file01");
341 ze1.setMethod(ZipEntry.STORED);
342 zipArchiveOutputStream.putArchiveEntry(ze1);
343 zipArchiveOutputStream.write(data1);
344 zipArchiveOutputStream.closeArchiveEntry();
345 final ZipArchiveEntry ze2 = new ZipArchiveEntry("file02");
346 ze2.setMethod(ZipEntry.STORED);
347 zipArchiveOutputStream.putArchiveEntry(ze2);
348 zipArchiveOutputStream.write(data2);
349 zipArchiveOutputStream.closeArchiveEntry();
350 final ZipArchiveEntry ze3 = new ZipArchiveEntry("file03");
351 ze3.setMethod(ZipEntry.STORED);
352 zipArchiveOutputStream.putArchiveEntry(ze3);
353 zipArchiveOutputStream.write(data3);
354 zipArchiveOutputStream.closeArchiveEntry();
355 final ZipArchiveEntry ze4 = new ZipArchiveEntry("file04");
356 ze4.setMethod(ZipEntry.STORED);
357 zipArchiveOutputStream.putArchiveEntry(ze4);
358 zipArchiveOutputStream.write(data4);
359 zipArchiveOutputStream.closeArchiveEntry();
360 }
361 try (ZipFile zipFile = ZipFile.builder().setPath(outputZipFile.toPath()).setMaxNumberOfDisks(Integer.MAX_VALUE).get()) {
362 assertArrayEquals(data1, IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file01"))));
363 assertArrayEquals(data2, IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file02"))));
364 assertArrayEquals(data3, IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file03"))));
365 assertArrayEquals(data4, IOUtils.toByteArray(zipFile.getInputStream(zipFile.getEntry("file04"))));
366 }
367 }
368
369 @Test
370 public void testBuildSplitZipTest() throws IOException {
371 final File directoryToZip = getFilesToZip();
372 createTestSplitZipSegments();
373 final File lastFile = newTempFile("splitZip.zip");
374 try (SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile);
375 InputStream inputStream = Channels.newInputStream(channel);
376 ZipArchiveInputStream splitInputStream = new ZipArchiveInputStream(inputStream, UTF_8.toString(), true, false, true)) {
377
378 ArchiveEntry entry;
379 final int filesNum = countNonDirectories(directoryToZip);
380 int filesCount = 0;
381 while ((entry = splitInputStream.getNextEntry()) != null) {
382 if (entry.isDirectory()) {
383 continue;
384 }
385
386 assertArrayEquals(IOUtils.toByteArray(splitInputStream), Files.readAllBytes(Paths.get(entry.getName())));
387 filesCount++;
388 }
389
390 assertEquals(filesCount, filesNum);
391 }
392 }
393
394 @Test
395 public void testBuildSplitZipWithSegmentAlreadyExistThrowsException() throws IOException {
396 final File directoryToZip = getFilesToZip();
397 final File outputZipFile = newTempFile("splitZip.zip");
398 final long splitSize = 100 * 1024L;
399 try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(outputZipFile, splitSize)) {
400
401 final File sameNameFile = newTempFile("splitZip.z01");
402 sameNameFile.createNewFile();
403 assertThrows(IOException.class, () -> addFilesToZip(zipArchiveOutputStream, directoryToZip));
404 } catch (final Exception e) {
405
406
407
408
409
410 }
411 }
412
413 @Test
414 public void testBuildSplitZipWithTooLargeSizeThrowsException() throws IOException {
415 final Path file = Files.createTempFile("temp", "zip");
416 try {
417 assertThrows(IllegalArgumentException.class, () -> new ZipArchiveOutputStream(file, 4294967295L + 1));
418 } finally {
419 Files.delete(file);
420 }
421 }
422
423 @Test
424 public void testBuildSplitZipWithTooSmallSizeThrowsException() throws IOException {
425 createTempFile("temp", "zip").toPath();
426 assertThrows(IllegalArgumentException.class, () -> new ZipArchiveOutputStream(createTempFile("temp", "zip"), 64 * 1024 - 1));
427 }
428
429 @Test
430 public void testCopyRawEntriesFromFile() throws IOException {
431 final File reference = createReferenceFile(Zip64Mode.Never, "expected.");
432 final File file1 = createTempFile("src1.", ".zip");
433 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(file1)) {
434 zos.setUseZip64(Zip64Mode.Never);
435 createFirstEntry(zos).close();
436 }
437 final File file2 = createTempFile("src2.", ".zip");
438 try (ZipArchiveOutputStream zos1 = new ZipArchiveOutputStream(file2)) {
439 zos1.setUseZip64(Zip64Mode.Never);
440 createSecondEntry(zos1).close();
441 }
442 try (ZipFile zipFile1 = newZipFile(file1);
443 ZipFile zipFile2 = newZipFile(file2)) {
444 final File fileResult = createTempFile("file-actual.", ".zip");
445 try (ZipArchiveOutputStream zos2 = new ZipArchiveOutputStream(fileResult)) {
446 zipFile1.copyRawEntries(zos2, allFilesPredicate);
447 zipFile2.copyRawEntries(zos2, allFilesPredicate);
448 }
449
450
451
452 assertSameFileContents(reference, fileResult);
453 }
454 }
455
456 @Test
457 public void testCopyRawZip64EntryFromFile() throws IOException {
458 final File reference = createTempFile("z64reference.", ".zip");
459 try (ZipArchiveOutputStream zos1 = new ZipArchiveOutputStream(reference)) {
460 zos1.setUseZip64(Zip64Mode.Always);
461 createFirstEntry(zos1);
462 }
463 final File file1 = createTempFile("zip64src.", ".zip");
464 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(file1)) {
465 zos.setUseZip64(Zip64Mode.Always);
466 createFirstEntry(zos).close();
467 }
468 final File fileResult = createTempFile("file-actual.", ".zip");
469 try (ZipFile zipFile1 = newZipFile(file1)) {
470 try (ZipArchiveOutputStream zos2 = new ZipArchiveOutputStream(fileResult)) {
471 zos2.setUseZip64(Zip64Mode.Always);
472 zipFile1.copyRawEntries(zos2, allFilesPredicate);
473 }
474 assertSameFileContents(reference, fileResult);
475 }
476 }
477
478 @Test
479 public void testDirectoryEntryFromFile() throws Exception {
480 final File tmp = getTempDirFile();
481 final File archive = createTempFile("test.", ".zip");
482 final long beforeArchiveWrite;
483 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(archive)) {
484 beforeArchiveWrite = tmp.lastModified();
485 final ZipArchiveEntry in = new ZipArchiveEntry(tmp, "foo");
486 zos.putArchiveEntry(in);
487 zos.closeArchiveEntry();
488 }
489 try (ZipFile zf = newZipFile(archive)) {
490 final ZipArchiveEntry out = zf.getEntry("foo/");
491 assertNotNull(out);
492 assertEquals("foo/", out.getName());
493 assertEquals(0, out.getSize());
494
495 assertEquals(beforeArchiveWrite / 2000, out.getLastModifiedDate().getTime() / 2000);
496 assertTrue(out.isDirectory());
497 }
498 }
499
500 @Test
501 public void testExplicitDirectoryEntry() throws Exception {
502 final File archive = createTempFile("test.", ".zip");
503 final long beforeArchiveWrite;
504 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(archive)) {
505 beforeArchiveWrite = getTempDirFile().lastModified();
506 final ZipArchiveEntry in = new ZipArchiveEntry("foo/");
507 in.setTime(beforeArchiveWrite);
508 zos.putArchiveEntry(in);
509 zos.closeArchiveEntry();
510 }
511 try (ZipFile zf = newZipFile(archive)) {
512 final ZipArchiveEntry out = zf.getEntry("foo/");
513 assertNotNull(out);
514 assertEquals("foo/", out.getName());
515 assertEquals(0, out.getSize());
516 assertEquals(beforeArchiveWrite / 2000, out.getLastModifiedDate().getTime() / 2000);
517 assertTrue(out.isDirectory());
518 }
519 }
520
521 @Test
522 public void testExplicitFileEntry() throws Exception {
523 final File tmp = createTempFile();
524 final File archive = createTempFile("test.", ".zip");
525 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(archive)) {
526 final ZipArchiveEntry in = new ZipArchiveEntry("foo");
527 in.setTime(tmp.lastModified());
528 in.setSize(tmp.length());
529 zos.putArchiveEntry(in);
530 final byte[] b = new byte[(int) tmp.length()];
531 try (InputStream fis = Files.newInputStream(tmp.toPath())) {
532 while (fis.read(b) > 0) {
533 zos.write(b);
534 }
535 }
536 zos.closeArchiveEntry();
537 }
538 try (ZipFile zf = newZipFile(archive)) {
539 final ZipArchiveEntry out = zf.getEntry("foo");
540 assertNotNull(out);
541 assertEquals("foo", out.getName());
542 assertEquals(tmp.length(), out.getSize());
543 assertEquals(tmp.lastModified() / 2000, out.getLastModifiedDate().getTime() / 2000);
544 assertFalse(out.isDirectory());
545 }
546 }
547
548 @Test
549 public void testFileEntryFromFile() throws Exception {
550 final File tmpFile = createTempFile();
551 final File archive = createTempFile("test.", ".zip");
552 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(archive)) {
553 final ZipArchiveEntry in = new ZipArchiveEntry(tmpFile, "foo");
554 zos.putArchiveEntry(in);
555 final byte[] b = new byte[(int) tmpFile.length()];
556 try (InputStream fis = Files.newInputStream(tmpFile.toPath())) {
557 while (fis.read(b) > 0) {
558 zos.write(b);
559 }
560 }
561 zos.closeArchiveEntry();
562 }
563 try (ZipFile zf = newZipFile(archive)) {
564 final ZipArchiveEntry out = zf.getEntry("foo");
565 assertNotNull(out);
566 assertEquals("foo", out.getName());
567 assertEquals(tmpFile.length(), out.getSize());
568 assertEquals(tmpFile.lastModified() / 2000, out.getLastModifiedDate().getTime() / 2000);
569 assertFalse(out.isDirectory());
570 }
571 }
572
573 private void testInputStreamStatistics(final String fileName, final Map<String, List<Long>> expectedStatistics) throws IOException, ArchiveException {
574 final File input = getFile(fileName);
575 final Map<String, List<List<Long>>> actualStatistics = new HashMap<>();
576
577 try (InputStream fis = Files.newInputStream(input.toPath());
578 ArchiveInputStream<?> in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("zip", fis)) {
579 for (ArchiveEntry entry; (entry = in.getNextEntry()) != null;) {
580 readStream(in, entry, actualStatistics);
581 }
582 }
583
584 try (ZipFile zf = newZipFile(input)) {
585 final Enumeration<ZipArchiveEntry> entries = zf.getEntries();
586 while (entries.hasMoreElements()) {
587 final ZipArchiveEntry zae = entries.nextElement();
588 try (InputStream in = zf.getInputStream(zae)) {
589 readStream(in, zae, actualStatistics);
590 }
591 }
592 }
593
594 for (final Map.Entry<String, List<List<Long>>> me : actualStatistics.entrySet()) {
595 assertEquals(me.getValue().get(0), me.getValue().get(1), "Mismatch of stats for: " + me.getKey());
596 }
597 for (final Map.Entry<String, List<Long>> me : expectedStatistics.entrySet()) {
598 assertEquals(me.getValue(), actualStatistics.get(me.getKey()).get(0), "Mismatch of stats with expected value for: " + me.getKey());
599 }
600 }
601
602 @Test
603 public void testInputStreamStatisticsForBzip2Entry() throws IOException, ArchiveException {
604 final Map<String, List<Long>> expected = new HashMap<>();
605 expected.put("lots-of-as", Arrays.asList(42L, 39L));
606 testInputStreamStatistics("bzip2-zip.zip", expected);
607 }
608
609 @Test
610 public void testInputStreamStatisticsForDeflate64Entry() throws IOException, ArchiveException {
611 final Map<String, List<Long>> expected = new HashMap<>();
612 expected.put("input2", Arrays.asList(3072L, 2111L));
613 testInputStreamStatistics("COMPRESS-380/COMPRESS-380.zip", expected);
614 }
615
616 @Test
617 public void testInputStreamStatisticsForImplodedEntry() throws IOException, ArchiveException {
618 final Map<String, List<Long>> expected = new HashMap<>();
619 expected.put("LICENSE.TXT", Arrays.asList(11560L, 4131L));
620 testInputStreamStatistics("imploding-8Kdict-3trees.zip", expected);
621 }
622
623 @Test
624 public void testInputStreamStatisticsForShrunkEntry() throws IOException, ArchiveException {
625 final Map<String, List<Long>> expected = new HashMap<>();
626 expected.put("TEST1.XML", Arrays.asList(76L, 66L));
627 expected.put("TEST2.XML", Arrays.asList(81L, 76L));
628 testInputStreamStatistics("SHRUNK.ZIP", expected);
629 }
630
631 @Test
632 public void testInputStreamStatisticsForStoredEntry() throws IOException, ArchiveException {
633 final Map<String, List<Long>> expected = new HashMap<>();
634 expected.put("test.txt", Arrays.asList(5L, 5L));
635 testInputStreamStatistics("COMPRESS-264.zip", expected);
636 }
637
638 @Test
639 public void testInputStreamStatisticsOfZipBombExcel() throws IOException, ArchiveException {
640 final Map<String, List<Long>> expected = new HashMap<>();
641 expected.put("[Content_Types].xml", Arrays.asList(8390036L, 8600L));
642 expected.put("xl/worksheets/sheet1.xml", Arrays.asList(1348L, 508L));
643 testInputStreamStatistics("zipbomb.xlsx", expected);
644 }
645
646
647
648
649
650
651
652
653 @Test
654 public void testListAllFilesWithNestedArchive() throws Exception {
655 final File input = getFile("OSX_ArchiveWithNestedArchive.zip");
656 final List<String> results = new ArrayList<>();
657 final List<ZipException> expectedExceptions = new ArrayList<>();
658 try (InputStream fis = Files.newInputStream(input.toPath());
659 ZipArchiveInputStream in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("zip", fis)) {
660 ZipArchiveEntry entry;
661 while ((entry = in.getNextEntry()) != null) {
662 results.add(entry.getName());
663 final ZipArchiveInputStream nestedIn = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("zip", in);
664 try {
665 ZipArchiveEntry nestedEntry;
666 while ((nestedEntry = nestedIn.getNextEntry()) != null) {
667 results.add(nestedEntry.getName());
668 }
669 } catch (final ZipException ex) {
670
671 expectedExceptions.add(ex);
672 }
673
674 }
675 }
676 assertTrue(results.contains("NestedArchiv.zip"));
677 assertTrue(results.contains("test1.xml"));
678 assertTrue(results.contains("test2.xml"));
679 assertTrue(results.contains("test3.xml"));
680 assertEquals(1, expectedExceptions.size());
681 }
682
683
684
685
686
687
688 @Test
689 public void testSkipEntryWithUnsupportedCompressionMethod() throws IOException {
690 try (ZipArchiveInputStream zip = new ZipArchiveInputStream(newInputStream("moby.zip"))) {
691 final ZipArchiveEntry entry = zip.getNextZipEntry();
692 assertEquals(ZipMethod.TOKENIZATION.getCode(), entry.getMethod(), "method");
693 assertEquals("README", entry.getName());
694 assertFalse(zip.canReadEntryData(entry));
695 assertDoesNotThrow(() -> assertNull(zip.getNextZipEntry()), "COMPRESS-93: Unable to skip an unsupported ZIP entry");
696 }
697 }
698
699
700
701
702 @Test
703 public void testSkipsPK00Prefix() throws Exception {
704 final File input = getFile("COMPRESS-208.zip");
705 final ArrayList<String> al = new ArrayList<>();
706 al.add("test1.xml");
707 al.add("test2.xml");
708 try (InputStream fis = Files.newInputStream(input.toPath());
709 ZipArchiveInputStream inputStream = new ZipArchiveInputStream(fis)) {
710 checkArchiveContent(inputStream, al);
711 }
712 }
713
714
715
716
717 @Test
718 public void testTokenizationCompressionMethod() throws IOException {
719 try (ZipFile moby = ZipFile.builder().setFile(getFile("moby.zip")).get()) {
720 final ZipArchiveEntry entry = moby.getEntry("README");
721 assertEquals(ZipMethod.TOKENIZATION.getCode(), entry.getMethod(), "method");
722 assertFalse(moby.canReadEntryData(entry));
723 }
724 }
725
726 @Test
727 public void testUnixModeInAddRaw() throws IOException {
728 final File file1 = createTempFile("unixModeBits.", ".zip");
729 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(file1)) {
730 final ZipArchiveEntry archiveEntry = new ZipArchiveEntry("fred");
731 archiveEntry.setUnixMode(0664);
732 archiveEntry.setMethod(ZipEntry.STORED);
733 archiveEntry.setSize(3);
734 archiveEntry.setCompressedSize(3);
735 zos.addRawArchiveEntry(archiveEntry, new ByteArrayInputStream("fud".getBytes()));
736 }
737 try (ZipFile zf1 = newZipFile(file1)) {
738 final ZipArchiveEntry fred = zf1.getEntry("fred");
739 assertEquals(0664, fred.getUnixMode());
740 }
741 }
742
743
744
745
746
747
748 @Test
749 public void testZipArchiveCreation() throws Exception {
750
751 final File output = newTempFile("bla.zip");
752 final File file1 = getFile("test1.xml");
753 final File file2 = getFile("test2.xml");
754 try (OutputStream out = Files.newOutputStream(output.toPath())) {
755 try (ArchiveOutputStream<ZipArchiveEntry> os = ArchiveStreamFactory.DEFAULT.createArchiveOutputStream("zip", out)) {
756
757 os.putArchiveEntry(new ZipArchiveEntry("testdata/test1.xml"));
758 Files.copy(file1.toPath(), os);
759 os.closeArchiveEntry();
760
761 os.putArchiveEntry(new ZipArchiveEntry("testdata/test2.xml"));
762 Files.copy(file2.toPath(), os);
763 os.closeArchiveEntry();
764 }
765 }
766
767 final List<File> results = new ArrayList<>();
768 try (InputStream fileInputStream = Files.newInputStream(output.toPath())) {
769 try (ArchiveInputStream<ZipArchiveEntry> archiveInputStream = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("zip", fileInputStream)) {
770 ZipArchiveEntry entry;
771 while ((entry = archiveInputStream.getNextEntry()) != null) {
772 final File outfile = new File(tempResultDir.getCanonicalPath() + "/result/" + entry.getName());
773 outfile.getParentFile().mkdirs();
774 Files.copy(archiveInputStream, outfile.toPath());
775 results.add(outfile);
776 }
777 }
778 }
779 assertEquals(results.size(), 2);
780 File result = results.get(0);
781 assertEquals(file1.length(), result.length());
782 result = results.get(1);
783 assertEquals(file2.length(), result.length());
784 }
785
786
787
788
789
790
791 @Test
792 public void testZipArchiveCreationInMemory() throws Exception {
793 final byte[] file1Contents = readAllBytes("test1.xml");
794 final byte[] file2Contents = readAllBytes("test2.xml");
795 final List<byte[]> results = new ArrayList<>();
796 try (SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel()) {
797 try (ZipArchiveOutputStream os = new ZipArchiveOutputStream(channel)) {
798 os.putArchiveEntry(new ZipArchiveEntry("testdata/test1.xml"));
799 os.write(file1Contents);
800 os.closeArchiveEntry();
801
802 os.putArchiveEntry(new ZipArchiveEntry("testdata/test2.xml"));
803 os.write(file2Contents);
804 os.closeArchiveEntry();
805 }
806
807 try (ZipArchiveInputStream inputStream = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("zip", new ByteArrayInputStream(channel.array()))) {
808 ZipArchiveEntry entry;
809 while ((entry = inputStream.getNextEntry()) != null) {
810 final byte[] result = new byte[(int) entry.getSize()];
811 IOUtils.readFully(inputStream, result);
812 results.add(result);
813 }
814 }
815 }
816 assertArrayEquals(results.get(0), file1Contents);
817 assertArrayEquals(results.get(1), file2Contents);
818 }
819
820 @Test
821 public void testZipArchiveEntryNewFromPath() throws Exception {
822 Path archivePath;
823 final File tmpFile = createTempFile();
824 final Path tmpFilePath = tmpFile.toPath();
825 final File archiveFile = createTempFile("test.", ".zip");
826 archivePath = archiveFile.toPath();
827 try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(archivePath)) {
828 final ZipArchiveEntry in = zos.createArchiveEntry(tmpFilePath, "foo");
829 zos.putArchiveEntry(in);
830 final byte[] b = new byte[(int) tmpFile.length()];
831 try (InputStream fis = Files.newInputStream(tmpFile.toPath())) {
832 while (fis.read(b) > 0) {
833 zos.write(b);
834 }
835 }
836 zos.closeArchiveEntry();
837 }
838 try (ZipFile zf = newZipFile(archiveFile)) {
839 final ZipArchiveEntry out = zf.getEntry("foo");
840 assertNotNull(out);
841 assertEquals("foo", out.getName());
842 assertEquals(tmpFile.length(), out.getSize());
843 assertEquals(tmpFile.lastModified() / 2000, out.getLastModifiedDate().getTime() / 2000);
844 assertFalse(out.isDirectory());
845 }
846 }
847
848
849
850
851
852
853 @Test
854 public void testZipUnarchive() throws Exception {
855 final File input = getFile("bla.zip");
856 try (InputStream is = Files.newInputStream(input.toPath());
857 ArchiveInputStream<ZipArchiveEntry> in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("zip", is)) {
858 final ZipArchiveEntry entry = in.getNextEntry();
859 Files.copy(in, newTempFile(entry.getName()).toPath());
860 }
861 }
862 }