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