View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.archivers.zip;
20  
21  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertNotEquals;
24  
25  import java.io.ByteArrayOutputStream;
26  import java.io.File;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.io.OutputStream;
30  import java.nio.file.Files;
31  import java.util.Arrays;
32  
33  import org.junit.jupiter.api.Test;
34  import org.junit.jupiter.api.io.TempDir;
35  
36  class DataDescriptorTest {
37  
38      @TempDir
39      private File dir;
40  
41      private int findCentralDirectory(final byte[] data) {
42          // not a ZIP64 archive, no comment, "End of central directory record" at the end
43          return (int) ZipLong.getValue(data, data.length - 22 + 16);
44      }
45  
46      @Test
47      void testDoesntWriteDataDescriptorForDeflatedEntryOnSeekableOutput() throws IOException {
48          final File file = new File(dir, "test.zip");
49          try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(file)) {
50              zos.putArchiveEntry(new ZipArchiveEntry("test1.txt"));
51              zos.writeUtf8("foo");
52              zos.closeArchiveEntry();
53          }
54  
55          final byte[] data = Files.readAllBytes(file.toPath());
56  
57          final byte[] versionInLFH = Arrays.copyOfRange(data, 4, 6);
58          // still 2.0 because of Deflate
59          assertArrayEquals(new byte[] { 20, 0 }, versionInLFH);
60          final byte[] gpbInLFH = Arrays.copyOfRange(data, 6, 8);
61          // no DD but EFS flag
62          assertArrayEquals(new byte[] { 0, 8 }, gpbInLFH);
63  
64          final int cdhStart = findCentralDirectory(data);
65          final byte[] versionInCDH = Arrays.copyOfRange(data, cdhStart + 6, cdhStart + 8);
66          assertArrayEquals(new byte[] { 20, 0 }, versionInCDH);
67          final byte[] gpbInCDH = Arrays.copyOfRange(data, cdhStart + 8, cdhStart + 10);
68          assertArrayEquals(new byte[] { 0, 8 }, gpbInCDH);
69  
70          final int ddStart = cdhStart - 16;
71          assertNotEquals(ZipLong.DD_SIG, new ZipLong(data, ddStart));
72          final long crcFromLFH = ZipLong.getValue(data, 14);
73          final long cSizeFromLFH = ZipLong.getValue(data, 18);
74          final long sizeFromLFH = ZipLong.getValue(data, 22);
75          assertEquals(3, sizeFromLFH);
76  
77          final long crcFromCDH = ZipLong.getValue(data, cdhStart + 16);
78          assertEquals(crcFromLFH, crcFromCDH);
79          final long cSizeFromCDH = ZipLong.getValue(data, cdhStart + 20);
80          assertEquals(cSizeFromLFH, cSizeFromCDH);
81          final long sizeFromCDH = ZipLong.getValue(data, cdhStart + 24);
82          assertEquals(sizeFromLFH, sizeFromCDH);
83      }
84  
85      @Test
86      void testDoesntWriteDataDescriptorWhenAddingRawEntries() throws IOException {
87          final ByteArrayOutputStream init = new ByteArrayOutputStream();
88          try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(init)) {
89              zos.putArchiveEntry(new ZipArchiveEntry("test1.txt"));
90              zos.writeUtf8("foo");
91              zos.closeArchiveEntry();
92          }
93  
94          final File f = new File(dir, "test.zip");
95          try (OutputStream fos = Files.newOutputStream(f.toPath())) {
96              fos.write(init.toByteArray());
97          }
98  
99          final ByteArrayOutputStream baos = new ByteArrayOutputStream();
100         try (ZipFile zf = ZipFile.builder().setFile(f).get();
101                 ZipArchiveOutputStream zos = new ZipArchiveOutputStream(baos)) {
102             final ZipArchiveEntry zae = zf.getEntry("test1.txt");
103             try (InputStream rawInputStream = zf.getRawInputStream(zae)) {
104                 zos.addRawArchiveEntry(zae, rawInputStream);
105             }
106         }
107 
108         final byte[] data = baos.toByteArray();
109         final byte[] versionInLFH = Arrays.copyOfRange(data, 4, 6);
110         // still 2.0 because of Deflate
111         assertArrayEquals(new byte[] { 20, 0 }, versionInLFH);
112         final byte[] gpbInLFH = Arrays.copyOfRange(data, 6, 8);
113         // no DD but EFS flag
114         assertArrayEquals(new byte[] { 0, 8 }, gpbInLFH);
115 
116         final int cdhStart = findCentralDirectory(data);
117         final byte[] versionInCDH = Arrays.copyOfRange(data, cdhStart + 6, cdhStart + 8);
118         assertArrayEquals(new byte[] { 20, 0 }, versionInCDH);
119         final byte[] gpbInCDH = Arrays.copyOfRange(data, cdhStart + 8, cdhStart + 10);
120         assertArrayEquals(new byte[] { 0, 8 }, gpbInCDH);
121 
122         final int ddStart = cdhStart - 16;
123         assertNotEquals(ZipLong.DD_SIG, new ZipLong(data, ddStart));
124         final long crcFromLFH = ZipLong.getValue(data, 14);
125         final long cSizeFromLFH = ZipLong.getValue(data, 18);
126         final long sizeFromLFH = ZipLong.getValue(data, 22);
127         assertEquals(3, sizeFromLFH);
128 
129         final long crcFromCDH = ZipLong.getValue(data, cdhStart + 16);
130         assertEquals(crcFromLFH, crcFromCDH);
131         final long cSizeFromCDH = ZipLong.getValue(data, cdhStart + 20);
132         assertEquals(cSizeFromLFH, cSizeFromCDH);
133         final long sizeFromCDH = ZipLong.getValue(data, cdhStart + 24);
134         assertEquals(sizeFromLFH, sizeFromCDH);
135     }
136 
137     @Test
138     void testWritesDataDescriptorForDeflatedEntryOnUnseekableOutput() throws IOException {
139         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
140         try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(baos)) {
141             zos.putArchiveEntry(new ZipArchiveEntry("test1.txt"));
142             zos.writeUtf8("foo");
143             zos.closeArchiveEntry();
144         }
145         final byte[] data = baos.toByteArray();
146 
147         final byte[] versionInLFH = Arrays.copyOfRange(data, 4, 6);
148         // 2.0 because of DD
149         assertArrayEquals(new byte[] { 20, 0 }, versionInLFH);
150         final byte[] gpbInLFH = Arrays.copyOfRange(data, 6, 8);
151         // DD and EFS flags
152         assertArrayEquals(new byte[] { 8, 8 }, gpbInLFH);
153         final byte[] crcAndSizedInLFH = Arrays.copyOfRange(data, 14, 26);
154         assertArrayEquals(new byte[12], crcAndSizedInLFH);
155 
156         final int cdhStart = findCentralDirectory(data);
157         final byte[] versionInCDH = Arrays.copyOfRange(data, cdhStart + 6, cdhStart + 8);
158         assertArrayEquals(new byte[] { 20, 0 }, versionInCDH);
159         final byte[] gpbInCDH = Arrays.copyOfRange(data, cdhStart + 8, cdhStart + 10);
160         assertArrayEquals(new byte[] { 8, 8 }, gpbInCDH);
161 
162         final int ddStart = cdhStart - 16;
163         assertEquals(ZipLong.DD_SIG, new ZipLong(data, ddStart));
164         final long crcFromDD = ZipLong.getValue(data, ddStart + 4);
165         final long cSizeFromDD = ZipLong.getValue(data, ddStart + 8);
166         final long sizeFromDD = ZipLong.getValue(data, ddStart + 12);
167         assertEquals(3, sizeFromDD);
168 
169         final long crcFromCDH = ZipLong.getValue(data, cdhStart + 16);
170         assertEquals(crcFromDD, crcFromCDH);
171         final long cSizeFromCDH = ZipLong.getValue(data, cdhStart + 20);
172         assertEquals(cSizeFromDD, cSizeFromCDH);
173         final long sizeFromCDH = ZipLong.getValue(data, cdhStart + 24);
174         assertEquals(sizeFromDD, sizeFromCDH);
175     }
176 }