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.compressors.pack200;
20  
21  import static org.junit.Assert.assertEquals;
22  
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.OutputStream;
29  import java.nio.file.Files;
30  import java.nio.file.StandardCopyOption;
31  import java.util.HashMap;
32  
33  import org.apache.commons.compress.AbstractTest;
34  import org.apache.commons.compress.archivers.ArchiveEntry;
35  import org.apache.commons.compress.archivers.ArchiveInputStream;
36  import org.apache.commons.compress.archivers.ArchiveStreamFactory;
37  import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
38  import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
39  import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
40  import org.apache.commons.io.IOUtils;
41  import org.apache.commons.io.input.CloseShieldInputStream;
42  import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
43  import org.junit.jupiter.api.Test;
44  
45  public final class Pack200UtilsTest extends AbstractTest {
46  
47      private long parseEntry(final InputStream is) throws IOException {
48          try (UnsynchronizedByteArrayOutputStream bos = UnsynchronizedByteArrayOutputStream.builder().get();
49                  Pack200CompressorInputStream p = new Pack200CompressorInputStream(is)) {
50              return IOUtils.copy(p, bos);
51          }
52      }
53  
54      /**
55       * Tests https://issues.apache.org/jira/browse/COMPRESS-675
56       *
57       * Put 2 pack files inside an archive and then try to unpack them.
58       * @throws Exception Test failure.
59       */
60      @Test
61      void testCompress675() throws Exception {
62          // put 2 pack files inside an archive and then try to unpack them.
63          final File pack = getFile("bla.pack");
64          final File archiveFile = createTempFile();
65          final long expectedCount;
66          try (UnsynchronizedByteArrayOutputStream bos = UnsynchronizedByteArrayOutputStream.builder().get();
67                  Pack200CompressorInputStream inputStream = new Pack200CompressorInputStream(new FileInputStream(pack))) {
68              IOUtils.copy(inputStream, bos);
69              expectedCount = bos.size() * 2;
70          }
71          try (OutputStream os = new FileOutputStream(archiveFile);
72                  TarArchiveOutputStream taos = new TarArchiveOutputStream(os)) {
73              final TarArchiveEntry ae = taos.createArchiveEntry(pack, "./bla.pack");
74              taos.putArchiveEntry(ae);
75              try (FileInputStream in = new FileInputStream(pack)) {
76                  IOUtils.copy(in, taos);
77              }
78              taos.closeArchiveEntry();
79              final TarArchiveEntry ae2 = taos.createArchiveEntry(pack, "./bla2.pack");
80              taos.putArchiveEntry(ae2);
81              try (FileInputStream in = new FileInputStream(pack)) {
82                  IOUtils.copy(in, taos);
83              }
84              taos.closeArchiveEntry();
85              taos.finish();
86              taos.flush();
87          }
88          // The underlying ChannelInputStream is what causes the problem
89          // FileInputStream doesn't show the bug
90          //
91          // If you use a zip archive instead of a tar archive you
92          // get a different number of bytes read, but still not the expected
93          try (InputStream is = new FileInputStream(archiveFile);
94                  // Files.newInputStream(archiveFile.toPath());
95                  TarArchiveInputStream in = new TarArchiveInputStream(is)) {
96              ArchiveEntry entry = in.getNextEntry();
97              int entries = 0;
98              long count = 0;
99              while (entry != null) {
100                 if (in.canReadEntryData(entry)) {
101                     @SuppressWarnings("resource")
102                     final CloseShieldInputStream wrap = CloseShieldInputStream.wrap(in);
103                     count += parseEntry(wrap);
104                     entries++;
105                 }
106                 entry = in.getNextEntry();
107             }
108             assertEquals(2, entries);
109             assertEquals(expectedCount, count);
110         }
111     }
112 
113     @Test
114     void testNormalize() throws Throwable {
115         final File input = getFile("bla.jar");
116         final File output = createTempFile();
117         Pack200Utils.normalize(input, output, new HashMap<>());
118         try (InputStream is = Files.newInputStream(output.toPath());
119                 ArchiveInputStream<?> in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("jar", is)) {
120             in.forEach(entry -> {
121                 final File archiveEntry = newTempFile(entry.getName());
122                 archiveEntry.getParentFile().mkdirs();
123                 if (entry.isDirectory()) {
124                     archiveEntry.mkdir();
125                 } else {
126                     Files.copy(in, archiveEntry.toPath());
127                 }
128             });
129         }
130     }
131 
132     @Test
133     void testNormalizeInPlace() throws Throwable {
134         final File input = getFile("bla.jar");
135         final File output = createTempFile();
136         try (InputStream is = Files.newInputStream(input.toPath())) {
137             Files.copy(is, output.toPath(), StandardCopyOption.REPLACE_EXISTING);
138         }
139         Pack200Utils.normalize(output);
140         try (InputStream is = Files.newInputStream(output.toPath());
141                 ArchiveInputStream<?> in = ArchiveStreamFactory.DEFAULT.createArchiveInputStream("jar", is)) {
142             in.forEach(entry -> {
143                 final File archiveEntry = newTempFile(entry.getName());
144                 archiveEntry.getParentFile().mkdirs();
145                 if (entry.isDirectory()) {
146                     archiveEntry.mkdir();
147                 } else {
148                     Files.copy(in, archiveEntry.toPath());
149                 }
150             });
151         }
152     }
153 
154 }