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  
19  package org.apache.commons.compress.archivers.tar;
20  
21  import junit.framework.TestCase;
22  
23  import org.apache.commons.compress.archivers.zip.ZipEncoding;
24  import org.apache.commons.compress.archivers.zip.ZipEncodingHelper;
25  import org.apache.commons.compress.utils.CharsetNames;
26  
27  public class TarUtilsTest extends TestCase {
28  
29  
30      public void testName(){
31          byte [] buff = new byte[20];
32          String sb1 = "abcdefghijklmnopqrstuvwxyz";
33          int off = TarUtils.formatNameBytes(sb1, buff, 1, buff.length-1);
34          assertEquals(off, 20);
35          String sb2 = TarUtils.parseName(buff, 1, 10);
36          assertEquals(sb2,sb1.substring(0,10));
37          sb2 = TarUtils.parseName(buff, 1, 19);
38          assertEquals(sb2,sb1.substring(0,19));
39          buff = new byte[30];
40          off = TarUtils.formatNameBytes(sb1, buff, 1, buff.length-1);
41          assertEquals(off, 30);
42          sb2 = TarUtils.parseName(buff, 1, buff.length-1);
43          assertEquals(sb1, sb2);
44      }
45  
46      public void testParseOctal() throws Exception{
47          long value; 
48          byte [] buffer;
49          final long MAX_OCTAL  = 077777777777L; // Allowed 11 digits
50          final long MAX_OCTAL_OVERFLOW  = 0777777777777L; // in fact 12 for some implementations
51          final String maxOctal = "777777777777"; // Maximum valid octal
52          buffer = maxOctal.getBytes(CharsetNames.UTF_8);
53          value = TarUtils.parseOctal(buffer,0, buffer.length);
54          assertEquals(MAX_OCTAL_OVERFLOW, value);
55          buffer[buffer.length - 1] = ' ';
56          value = TarUtils.parseOctal(buffer,0, buffer.length);
57          assertEquals(MAX_OCTAL, value);
58          buffer[buffer.length-1]=0;
59          value = TarUtils.parseOctal(buffer,0, buffer.length);
60          assertEquals(MAX_OCTAL, value);
61          buffer=new byte[]{0,0};
62          value = TarUtils.parseOctal(buffer,0, buffer.length);
63          assertEquals(0, value);
64          buffer=new byte[]{0,' '};
65          value = TarUtils.parseOctal(buffer,0, buffer.length);
66          assertEquals(0, value);
67          buffer=new byte[]{' ',0};
68          value = TarUtils.parseOctal(buffer,0, buffer.length);
69          assertEquals(0, value);
70      }
71  
72      public void testParseOctalInvalid() throws Exception{
73          byte [] buffer;
74          buffer=new byte[0]; // empty byte array
75          try {
76              TarUtils.parseOctal(buffer,0, buffer.length);
77              fail("Expected IllegalArgumentException - should be at least 2 bytes long");
78          } catch (IllegalArgumentException expected) {
79          }
80          buffer=new byte[]{0}; // 1-byte array
81          try {
82              TarUtils.parseOctal(buffer,0, buffer.length);
83              fail("Expected IllegalArgumentException - should be at least 2 bytes long");
84          } catch (IllegalArgumentException expected) {
85          }
86          buffer = "abcdef ".getBytes(CharsetNames.UTF_8); // Invalid input
87          try {
88              TarUtils.parseOctal(buffer,0, buffer.length);
89              fail("Expected IllegalArgumentException");
90          } catch (IllegalArgumentException expected) {
91          }
92          buffer = " 0 07 ".getBytes(CharsetNames.UTF_8); // Invalid - embedded space
93          try {
94              TarUtils.parseOctal(buffer,0, buffer.length);
95              fail("Expected IllegalArgumentException - embedded space");
96          } catch (IllegalArgumentException expected) {
97          }
98          buffer = " 0\00007 ".getBytes(CharsetNames.UTF_8); // Invalid - embedded NUL
99          try {
100             TarUtils.parseOctal(buffer,0, buffer.length);
101             fail("Expected IllegalArgumentException - embedded NUL");
102         } catch (IllegalArgumentException expected) {
103         }
104     }
105 
106     private void checkRoundTripOctal(final long value, final int bufsize) {
107         byte [] buffer = new byte[bufsize];
108         long parseValue;
109         TarUtils.formatLongOctalBytes(value, buffer, 0, buffer.length);
110         parseValue = TarUtils.parseOctal(buffer,0, buffer.length);
111         assertEquals(value,parseValue);
112     }
113 
114     private void checkRoundTripOctal(final long value) {
115         checkRoundTripOctal(value, TarConstants.SIZELEN);
116     }
117 
118     public void testRoundTripOctal() {
119         checkRoundTripOctal(0);
120         checkRoundTripOctal(1);
121 //        checkRoundTripOctal(-1); // TODO What should this do?
122         checkRoundTripOctal(TarConstants.MAXSIZE);
123 //        checkRoundTripOctal(0100000000000L); // TODO What should this do?
124 
125         checkRoundTripOctal(0, TarConstants.UIDLEN);
126         checkRoundTripOctal(1, TarConstants.UIDLEN);
127         checkRoundTripOctal(TarConstants.MAXID, 8);
128     }
129 
130     private void checkRoundTripOctalOrBinary(final long value, final int bufsize) {
131         byte [] buffer = new byte[bufsize];
132         long parseValue;
133         TarUtils.formatLongOctalOrBinaryBytes(value, buffer, 0, buffer.length);
134         parseValue = TarUtils.parseOctalOrBinary(buffer,0, buffer.length);
135         assertEquals(value,parseValue);
136     }
137 
138     public void testRoundTripOctalOrBinary8() {
139         testRoundTripOctalOrBinary(8);
140     }
141 
142     public void testRoundTripOctalOrBinary12() {
143         testRoundTripOctalOrBinary(12);
144         checkRoundTripOctalOrBinary(Long.MAX_VALUE, 12);
145         checkRoundTripOctalOrBinary(Long.MIN_VALUE + 1, 12);
146     }
147 
148     private void testRoundTripOctalOrBinary(int length) {
149         checkRoundTripOctalOrBinary(0, length);
150         checkRoundTripOctalOrBinary(1, length);
151         checkRoundTripOctalOrBinary(TarConstants.MAXSIZE, length); // will need binary format
152         checkRoundTripOctalOrBinary(-1, length); // will need binary format
153         checkRoundTripOctalOrBinary(0xff00000000000001l, length);
154     }
155 
156     // Check correct trailing bytes are generated
157     public void testTrailers() {
158         byte [] buffer = new byte[12];
159         TarUtils.formatLongOctalBytes(123, buffer, 0, buffer.length);
160         assertEquals(' ', buffer[buffer.length-1]);
161         assertEquals('3', buffer[buffer.length-2]); // end of number
162         TarUtils.formatOctalBytes(123, buffer, 0, buffer.length);
163         assertEquals(0  , buffer[buffer.length-1]);
164         assertEquals(' ', buffer[buffer.length-2]);
165         assertEquals('3', buffer[buffer.length-3]); // end of number
166         TarUtils.formatCheckSumOctalBytes(123, buffer, 0, buffer.length);
167         assertEquals(' ', buffer[buffer.length-1]);
168         assertEquals(0  , buffer[buffer.length-2]);
169         assertEquals('3', buffer[buffer.length-3]); // end of number
170     }
171 
172     public void testNegative() throws Exception {
173         byte [] buffer = new byte[22];
174         TarUtils.formatUnsignedOctalString(-1, buffer, 0, buffer.length);
175         assertEquals("1777777777777777777777", new String(buffer, CharsetNames.UTF_8));
176     }
177 
178     public void testOverflow() throws Exception {
179         byte [] buffer = new byte[8-1]; // a lot of the numbers have 8-byte buffers (nul term)
180         TarUtils.formatUnsignedOctalString(07777777L, buffer, 0, buffer.length);
181         assertEquals("7777777", new String(buffer, CharsetNames.UTF_8));
182         try {
183             TarUtils.formatUnsignedOctalString(017777777L, buffer, 0, buffer.length);
184             fail("Should have cause IllegalArgumentException");
185         } catch (IllegalArgumentException expected) {
186         }
187     }
188 
189     public void testRoundTripNames(){
190         checkName("");
191         checkName("The quick brown fox\n");
192         checkName("\177");
193         // checkName("\0"); // does not work, because NUL is ignored
194     }
195 
196     public void testRoundEncoding() throws Exception {
197         // COMPRESS-114
198         ZipEncoding enc = ZipEncodingHelper.getZipEncoding(CharsetNames.ISO_8859_1);
199         String s = "0302-0601-3\u00b1\u00b1\u00b1F06\u00b1W220\u00b1ZB\u00b1LALALA\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1\u00b1CAN\u00b1\u00b1DC\u00b1\u00b1\u00b104\u00b1060302\u00b1MOE.model";
200         byte buff[] = new byte[100];
201         int len = TarUtils.formatNameBytes(s, buff, 0, buff.length, enc);
202         assertEquals(s, TarUtils.parseName(buff, 0, len, enc));
203     }
204 
205     private void checkName(String string) {
206         byte buff[] = new byte[100];
207         int len = TarUtils.formatNameBytes(string, buff, 0, buff.length);
208         assertEquals(string, TarUtils.parseName(buff, 0, len));
209     }
210 
211     public void testReadNegativeBinary8Byte() {
212         byte[] b = new byte[] {
213             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
214             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
215         };
216         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 8));
217     }
218 
219     public void testReadNegativeBinary12Byte() {
220         byte[] b = new byte[] {
221             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
222             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
223             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
224         };
225         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 12));
226     }
227 
228 
229     public void testWriteNegativeBinary8Byte() {
230         byte[] b = new byte[] {
231             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
232             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
233         };
234         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 8));
235     }
236 
237     // https://issues.apache.org/jira/browse/COMPRESS-191
238     public void testVerifyHeaderCheckSum() {
239         byte[] valid = { // from bla.tar
240                 116, 101, 115, 116, 49, 46, 120, 109, 108, 0, 0, 0, 0, 0, 0,
241                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
242                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
243                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
244                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
245                 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53,
246                 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48, 48,
247                 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54,
248                 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 0, 0, 0, 0, 0, 0, 0, 0,
249                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
250                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
251                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
252                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
253                 0, 0, 0, 0, 0, 0, 0, 0, 117, 115, 116, 97, 114, 32, 32, 0,
254                 116, 99, 117, 114, 100, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
255                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 99, 117,
256                 114, 100, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
257                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
258                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
259                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
260                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
261                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
262                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
263                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
264                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
265                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
266                 0, 0, 0, 0 };
267         assertTrue(TarUtils.verifyCheckSum(valid));
268 
269         byte[] compress117 = { // from COMPRESS-117
270                 116, 101, 115, 116, 49, 46, 120, 109, 108, 0, 0, 0, 0, 0, 0,
271                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
272                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
273                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
275                 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53,
276                 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48, 48,
277                 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54,
278                 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 0, 0, 0, 0, 0, 0, 0, 0,
279                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
280                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
281                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
282                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
283                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
284                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
285                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
286                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
287                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
288                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
289                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
290                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
291                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
292                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
293                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
294                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
295                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
296         assertTrue(TarUtils.verifyCheckSum(compress117));
297 
298         byte[] invalid = { // from the testAIFF.aif file in Tika
299                 70, 79, 82, 77, 0, 0, 15, 46, 65, 73, 70, 70, 67, 79, 77, 77,
300                 0, 0, 0, 18, 0, 2, 0, 0, 3, -64, 0, 16, 64, 14, -84, 68, 0, 0,
301                 0, 0, 0, 0, 83, 83, 78, 68, 0, 0, 15, 8, 0, 0, 0, 0, 0, 0, 0,
302                 0, 0, 1, -1, -1, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1,
303                 0, 0, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0,
304                 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0,
305                 0, 0, 0, 1, -1, -1, 0, 1, -1, -2, 0, 1, -1, -1, 0, 1, 0, 0, 0,
306                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0,
307                 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 1, -1, -1, 0, 1, -1, -1, 0,
308                 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0,
309                 0, 1, -1, -1, 0, 0, 0, 1, -1, -1, 0, 0, 0, 1, -1, -2, 0, 2,
310                 -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
311                 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2,
312                 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, -1,
313                 -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
314                 -1, -1, 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0,
315                 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2,
316                 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0,
317                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0,
318                 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0,
319                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -1, 0,
320                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 1, 0, 0, 0, 0, 0,
321                 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2,
322                 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1,
323                 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0,
324                 -1, -1, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
325                 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
326                 0, 0, 0, 0, 0, 1 };
327         assertFalse(TarUtils.verifyCheckSum(invalid));
328     }
329 
330 }