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      }
68  
69      public void testParseOctalInvalid() throws Exception{
70          byte [] buffer;
71          buffer=new byte[0]; // empty byte array
72          try {
73              TarUtils.parseOctal(buffer,0, buffer.length);
74              fail("Expected IllegalArgumentException - should be at least 2 bytes long");
75          } catch (IllegalArgumentException expected) {
76          }
77          buffer=new byte[]{0}; // 1-byte array
78          try {
79              TarUtils.parseOctal(buffer,0, buffer.length);
80              fail("Expected IllegalArgumentException - should be at least 2 bytes long");
81          } catch (IllegalArgumentException expected) {
82          }
83          buffer=new byte[]{' ',0,0,0}; // not all NULs
84          try {
85              TarUtils.parseOctal(buffer,0, buffer.length);
86              fail("Expected IllegalArgumentException - not all NULs");
87          } catch (IllegalArgumentException expected) {
88          }
89          buffer = "abcdef ".getBytes(CharsetNames.UTF_8); // Invalid input
90          try {
91              TarUtils.parseOctal(buffer,0, buffer.length);
92              fail("Expected IllegalArgumentException");
93          } catch (IllegalArgumentException expected) {
94          }
95          buffer = " 0 07 ".getBytes(CharsetNames.UTF_8); // Invalid - embedded space
96          try {
97              TarUtils.parseOctal(buffer,0, buffer.length);
98              fail("Expected IllegalArgumentException - embedded space");
99          } catch (IllegalArgumentException expected) {
100         }
101         buffer = " 0\00007 ".getBytes(CharsetNames.UTF_8); // Invalid - embedded NUL
102         try {
103             TarUtils.parseOctal(buffer,0, buffer.length);
104             fail("Expected IllegalArgumentException - embedded NUL");
105         } catch (IllegalArgumentException expected) {
106         }
107     }
108 
109     private void checkRoundTripOctal(final long value, final int bufsize) {
110         byte [] buffer = new byte[bufsize];
111         long parseValue;
112         TarUtils.formatLongOctalBytes(value, buffer, 0, buffer.length);
113         parseValue = TarUtils.parseOctal(buffer,0, buffer.length);
114         assertEquals(value,parseValue);
115     }
116 
117     private void checkRoundTripOctal(final long value) {
118         checkRoundTripOctal(value, TarConstants.SIZELEN);
119     }
120 
121     public void testRoundTripOctal() {
122         checkRoundTripOctal(0);
123         checkRoundTripOctal(1);
124 //        checkRoundTripOctal(-1); // TODO What should this do?
125         checkRoundTripOctal(TarConstants.MAXSIZE);
126 //        checkRoundTripOctal(0100000000000L); // TODO What should this do?
127 
128         checkRoundTripOctal(0, TarConstants.UIDLEN);
129         checkRoundTripOctal(1, TarConstants.UIDLEN);
130         checkRoundTripOctal(TarConstants.MAXID, 8);
131     }
132 
133     private void checkRoundTripOctalOrBinary(final long value, final int bufsize) {
134         byte [] buffer = new byte[bufsize];
135         long parseValue;
136         TarUtils.formatLongOctalOrBinaryBytes(value, buffer, 0, buffer.length);
137         parseValue = TarUtils.parseOctalOrBinary(buffer,0, buffer.length);
138         assertEquals(value,parseValue);
139     }
140 
141     public void testRoundTripOctalOrBinary8() {
142         testRoundTripOctalOrBinary(8);
143     }
144 
145     public void testRoundTripOctalOrBinary12() {
146         testRoundTripOctalOrBinary(12);
147         checkRoundTripOctalOrBinary(Long.MAX_VALUE, 12);
148         checkRoundTripOctalOrBinary(Long.MIN_VALUE + 1, 12);
149     }
150 
151     private void testRoundTripOctalOrBinary(int length) {
152         checkRoundTripOctalOrBinary(0, length);
153         checkRoundTripOctalOrBinary(1, length);
154         checkRoundTripOctalOrBinary(TarConstants.MAXSIZE, length); // will need binary format
155         checkRoundTripOctalOrBinary(-1, length); // will need binary format
156         checkRoundTripOctalOrBinary(0xff00000000000001l, length);
157     }
158 
159     // Check correct trailing bytes are generated
160     public void testTrailers() {
161         byte [] buffer = new byte[12];
162         TarUtils.formatLongOctalBytes(123, buffer, 0, buffer.length);
163         assertEquals(' ', buffer[buffer.length-1]);
164         assertEquals('3', buffer[buffer.length-2]); // end of number
165         TarUtils.formatOctalBytes(123, buffer, 0, buffer.length);
166         assertEquals(0  , buffer[buffer.length-1]);
167         assertEquals(' ', buffer[buffer.length-2]);
168         assertEquals('3', buffer[buffer.length-3]); // end of number
169         TarUtils.formatCheckSumOctalBytes(123, buffer, 0, buffer.length);
170         assertEquals(' ', buffer[buffer.length-1]);
171         assertEquals(0  , buffer[buffer.length-2]);
172         assertEquals('3', buffer[buffer.length-3]); // end of number
173     }
174 
175     public void testNegative() throws Exception {
176         byte [] buffer = new byte[22];
177         TarUtils.formatUnsignedOctalString(-1, buffer, 0, buffer.length);
178         assertEquals("1777777777777777777777", new String(buffer, CharsetNames.UTF_8));
179     }
180 
181     public void testOverflow() throws Exception {
182         byte [] buffer = new byte[8-1]; // a lot of the numbers have 8-byte buffers (nul term)
183         TarUtils.formatUnsignedOctalString(07777777L, buffer, 0, buffer.length);
184         assertEquals("7777777", new String(buffer, CharsetNames.UTF_8));
185         try {
186             TarUtils.formatUnsignedOctalString(017777777L, buffer, 0, buffer.length);
187             fail("Should have cause IllegalArgumentException");
188         } catch (IllegalArgumentException expected) {
189         }
190     }
191 
192     public void testRoundTripNames(){
193         checkName("");
194         checkName("The quick brown fox\n");
195         checkName("\177");
196         // checkName("\0"); // does not work, because NUL is ignored
197     }
198 
199     public void testRoundEncoding() throws Exception {
200         // COMPRESS-114
201         ZipEncoding enc = ZipEncodingHelper.getZipEncoding(CharsetNames.ISO_8859_1);
202         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";
203         byte buff[] = new byte[100];
204         int len = TarUtils.formatNameBytes(s, buff, 0, buff.length, enc);
205         assertEquals(s, TarUtils.parseName(buff, 0, len, enc));
206     }
207 
208     private void checkName(String string) {
209         byte buff[] = new byte[100];
210         int len = TarUtils.formatNameBytes(string, buff, 0, buff.length);
211         assertEquals(string, TarUtils.parseName(buff, 0, len));
212     }
213 
214     public void testReadNegativeBinary8Byte() {
215         byte[] b = new byte[] {
216             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
217             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
218         };
219         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 8));
220     }
221 
222     public void testReadNegativeBinary12Byte() {
223         byte[] b = new byte[] {
224             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
225             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
226             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
227         };
228         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 12));
229     }
230 
231 
232     public void testWriteNegativeBinary8Byte() {
233         byte[] b = new byte[] {
234             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
235             (byte) 0xff, (byte) 0xff, (byte) 0xf1, (byte) 0xef,
236         };
237         assertEquals(-3601l, TarUtils.parseOctalOrBinary(b, 0, 8));
238     }
239 
240     // https://issues.apache.org/jira/browse/COMPRESS-191
241     public void testVerifyHeaderCheckSum() {
242         byte[] valid = { // from bla.tar
243                 116, 101, 115, 116, 49, 46, 120, 109, 108, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
246                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
247                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
248                 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53,
249                 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48, 48,
250                 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54,
251                 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
254                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0,
256                 0, 0, 0, 0, 0, 0, 0, 0, 117, 115, 116, 97, 114, 32, 32, 0,
257                 116, 99, 117, 114, 100, 116, 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, 116, 99, 117,
259                 114, 100, 116, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
267                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
268                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269                 0, 0, 0, 0 };
270         assertTrue(TarUtils.verifyCheckSum(valid));
271 
272         byte[] compress117 = { // from COMPRESS-117
273                 116, 101, 115, 116, 49, 46, 120, 109, 108, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
276                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
277                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278                 0, 48, 48, 48, 48, 54, 52, 52, 0, 48, 48, 48, 48, 55, 54, 53,
279                 0, 48, 48, 48, 48, 55, 54, 53, 0, 48, 48, 48, 48, 48, 48, 48,
280                 49, 49, 52, 50, 0, 49, 48, 55, 49, 54, 53, 52, 53, 54, 50, 54,
281                 0, 48, 49, 50, 50, 54, 48, 0, 32, 48, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
297                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
298                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
299         assertTrue(TarUtils.verifyCheckSum(compress117));
300 
301         byte[] invalid = { // from the testAIFF.aif file in Tika
302                 70, 79, 82, 77, 0, 0, 15, 46, 65, 73, 70, 70, 67, 79, 77, 77,
303                 0, 0, 0, 18, 0, 2, 0, 0, 3, -64, 0, 16, 64, 14, -84, 68, 0, 0,
304                 0, 0, 0, 0, 83, 83, 78, 68, 0, 0, 15, 8, 0, 0, 0, 0, 0, 0, 0,
305                 0, 0, 1, -1, -1, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1,
306                 0, 0, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0,
307                 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0,
308                 0, 0, 0, 1, -1, -1, 0, 1, -1, -2, 0, 1, -1, -1, 0, 1, 0, 0, 0,
309                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0,
310                 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 1, -1, -1, 0, 1, -1, -1, 0,
311                 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0,
312                 0, 1, -1, -1, 0, 0, 0, 1, -1, -1, 0, 0, 0, 1, -1, -2, 0, 2,
313                 -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
314                 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2,
315                 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, -1,
316                 -2, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
317                 -1, -1, 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -1, 0, 0,
318                 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 2, -1, -2,
319                 0, 1, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -2, 0, 1, 0, 0, 0,
320                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0,
321                 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, 0, 0,
322                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 2, -1, -1, 0,
323                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 1, 0, 0, 0, 0, 0,
324                 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2,
325                 0, 2, -1, -2, 0, 2, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1,
326                 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0,
327                 -1, -1, 0, 2, -1, -2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
328                 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
329                 0, 0, 0, 0, 0, 1 };
330         assertFalse(TarUtils.verifyCheckSum(invalid));
331     }
332 
333 }