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  
18  package org.apache.commons.compress.archivers.ar;
19  
20  import static org.hamcrest.CoreMatchers.equalTo;
21  import static org.hamcrest.CoreMatchers.not;
22  import static org.hamcrest.CoreMatchers.nullValue;
23  import static org.hamcrest.MatcherAssert.assertThat;
24  import static org.junit.jupiter.api.Assertions.assertEquals;
25  import static org.junit.jupiter.api.Assertions.assertNotNull;
26  import static org.junit.jupiter.api.Assertions.assertNull;
27  import static org.junit.jupiter.api.Assertions.assertThrows;
28  
29  import java.io.BufferedInputStream;
30  import java.io.IOException;
31  import java.io.InputStream;
32  
33  import org.apache.commons.compress.AbstractTest;
34  import org.apache.commons.compress.archivers.ArchiveEntry;
35  import org.apache.commons.compress.utils.ArchiveUtils;
36  import org.apache.commons.io.IOUtils;
37  import org.junit.jupiter.api.Test;
38  import org.junit.jupiter.params.ParameterizedTest;
39  import org.junit.jupiter.params.provider.ValueSource;
40  
41  public class ArArchiveInputStreamTest extends AbstractTest {
42  
43      private void checkLongNameEntry(final String archive) throws Exception {
44          try (InputStream fis = newInputStream(archive);
45                  ArArchiveInputStream s = new ArArchiveInputStream(new BufferedInputStream(fis))) {
46              ArchiveEntry e = s.getNextEntry();
47              assertEquals("this_is_a_long_file_name.txt", e.getName());
48              assertEquals(14, e.getSize());
49              final byte[] hello = new byte[14];
50              s.read(hello);
51              assertEquals("Hello, world!\n", ArchiveUtils.toAsciiString(hello));
52              e = s.getNextEntry();
53              assertEquals("this_is_a_long_file_name_as_well.txt", e.getName());
54              assertEquals(4, e.getSize());
55              final byte[] bye = new byte[4];
56              s.read(bye);
57              assertEquals("Bye\n", ArchiveUtils.toAsciiString(bye));
58              assertNull(s.getNextEntry());
59          }
60      }
61  
62      @Test
63      public void testCantReadAfterClose() throws Exception {
64          try (InputStream in = newInputStream("bla.ar");
65                  ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
66              archive.close();
67              assertThrows(IllegalStateException.class, () -> archive.read());
68          }
69      }
70  
71      @Test
72      public void testCantReadWithoutOpeningAnEntry() throws Exception {
73          try (InputStream in = newInputStream("bla.ar");
74                  ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
75              assertThrows(IllegalStateException.class, () -> archive.read());
76          }
77      }
78  
79      @Test
80      public void testCompress661() throws IOException {
81          testCompress661(false);
82          testCompress661(true);
83      }
84  
85      private void testCompress661(final boolean checkMarkReadReset) throws IOException {
86          try (InputStream in = newInputStream("org/apache/commons/compress/COMPRESS-661/testARofText.ar");
87                  ArArchiveInputStream archive = new ArArchiveInputStream(new BufferedInputStream(in))) {
88              assertNotNull(archive.getNextEntry());
89              if (checkMarkReadReset && archive.markSupported()) {
90                  // mark() shouldn't be supported, but if it would be,
91                  // mark+read+reset should not do any harm.
92                  archive.mark(10);
93                  archive.read(new byte[10]);
94                  archive.reset();
95              }
96              final byte[] ba = IOUtils.toByteArray(archive);
97              assertEquals("Test d'indexation de Txt\nhttp://www.apache.org\n", new String(ba));
98              assertEquals(-1, archive.read());
99              assertEquals(-1, archive.read());
100             assertNull(archive.getNextEntry());
101         }
102     }
103 
104     @Test
105     public void testInvalidBadTableLength() throws Exception {
106         try (InputStream in = newInputStream("org/apache/commons/compress/ar/number_parsing/bad_table_length_gnu-fail.ar");
107                 ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
108             assertThrows(IOException.class, archive::getNextEntry);
109         }
110     }
111 
112     @ParameterizedTest
113     @ValueSource(strings = { "bad_long_namelen_bsd-fail.ar", "bad_long_namelen_gnu1-fail.ar", "bad_long_namelen_gnu2-fail.ar", "bad_long_namelen_gnu3-fail.ar",
114             "bad_table_length_gnu-fail.ar" })
115     public void testInvalidLongNameLength(final String testFileName) throws Exception {
116         try (InputStream in = newInputStream("org/apache/commons/compress/ar/number_parsing/" + testFileName);
117                 ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
118             assertThrows(IOException.class, archive::getNextEntry);
119         }
120     }
121 
122     @ParameterizedTest
123     @ValueSource(strings = { "bad_group-fail.ar", "bad_length-fail.ar", "bad_modified-fail.ar", "bad_user-fail.ar" })
124     public void testInvalidNumericFields(final String testFileName) throws Exception {
125         try (InputStream in = newInputStream("org/apache/commons/compress/ar/number_parsing/" + testFileName);
126                 ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
127             assertThrows(IOException.class, archive::getNextEntry);
128         }
129     }
130 
131     @Test
132     public void testMultiByteReadConsistentlyReturnsMinusOneAtEof() throws Exception {
133         final byte[] buf = new byte[2];
134         try (InputStream in = newInputStream("bla.ar");
135                 ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
136             assertNotNull(archive.getNextEntry());
137             IOUtils.toByteArray(archive);
138             assertEquals(-1, archive.read(buf));
139             assertEquals(-1, archive.read(buf));
140         }
141     }
142 
143     @Test
144     public void testReadLongNamesBSD() throws Exception {
145         checkLongNameEntry("longfile_bsd.ar");
146     }
147 
148     @Test
149     public void testReadLongNamesGNU() throws Exception {
150         checkLongNameEntry("longfile_gnu.ar");
151     }
152 
153     @Test
154     public void testSimpleInputStream() throws IOException {
155         try (InputStream fileInputStream = newInputStream("bla.ar");
156 
157                 // This default implementation of InputStream.available() always returns zero,
158                 // and there are many streams in practice where the total length of the stream is not known.
159 
160                 InputStream simpleInputStream = new InputStream() {
161                     @Override
162                     public int read() throws IOException {
163                         return fileInputStream.read();
164                     }
165                 }) {
166 
167             try (ArArchiveInputStream archiveInputStream = new ArArchiveInputStream(simpleInputStream)) {
168                 final ArArchiveEntry entry1 = archiveInputStream.getNextEntry();
169                 assertThat(entry1, not(nullValue()));
170                 assertThat(entry1.getName(), equalTo("test1.xml"));
171                 assertThat(entry1.getLength(), equalTo(610L));
172 
173                 final ArArchiveEntry entry2 = archiveInputStream.getNextEntry();
174                 assertThat(entry2.getName(), equalTo("test2.xml"));
175                 assertThat(entry2.getLength(), equalTo(82L));
176 
177                 assertThat(archiveInputStream.getNextEntry(), nullValue());
178             }
179         }
180     }
181 
182     @SuppressWarnings("deprecation")
183     @Test
184     public void testSimpleInputStreamDeprecated() throws IOException {
185         try (InputStream fileInputStream = newInputStream("bla.ar");
186 
187                 // This default implementation of InputStream.available() always returns zero,
188                 // and there are many streams in practice where the total length of the stream is not known.
189 
190                 InputStream simpleInputStream = new InputStream() {
191                     @Override
192                     public int read() throws IOException {
193                         return fileInputStream.read();
194                     }
195                 }) {
196 
197             try (ArArchiveInputStream archiveInputStream = new ArArchiveInputStream(simpleInputStream)) {
198                 final ArArchiveEntry entry1 = archiveInputStream.getNextArEntry();
199                 assertThat(entry1, not(nullValue()));
200                 assertThat(entry1.getName(), equalTo("test1.xml"));
201                 assertThat(entry1.getLength(), equalTo(610L));
202 
203                 final ArArchiveEntry entry2 = archiveInputStream.getNextArEntry();
204                 assertThat(entry2.getName(), equalTo("test2.xml"));
205                 assertThat(entry2.getLength(), equalTo(82L));
206 
207                 assertThat(archiveInputStream.getNextArEntry(), nullValue());
208             }
209         }
210     }
211 
212     @Test
213     public void testSingleByteReadConsistentlyReturnsMinusOneAtEof() throws Exception {
214         try (InputStream in = newInputStream("bla.ar");
215                 ArArchiveInputStream archive = new ArArchiveInputStream(in)) {
216             assertNotNull(archive.getNextEntry());
217             IOUtils.toByteArray(archive);
218             assertEquals(-1, archive.read());
219             assertEquals(-1, archive.read());
220         }
221     }
222 
223 }