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