blob: 8df868a5fd197b5c5a18f68488d4e3220c26ea2e [file] [log] [blame]
Torsten Curdtca165392008-07-10 10:17:44 +00001/*
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 * http://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 */
19package org.apache.commons.compress.archivers.tar;
20
21/**
22 * This class provides static utility methods to work with byte streams.
Torsten Curdt46ad24d2009-01-08 11:09:25 +000023 *
Sebastian Bazley44dbd932009-03-28 00:03:11 +000024 * @Immutable
Torsten Curdtca165392008-07-10 10:17:44 +000025 */
Torsten Curdt46ad24d2009-01-08 11:09:25 +000026// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
27public class TarUtils {
Torsten Curdtca165392008-07-10 10:17:44 +000028
Torsten Curdt46ad24d2009-01-08 11:09:25 +000029 private static final int BYTE_MASK = 255;
Torsten Curdtca165392008-07-10 10:17:44 +000030
31 /**
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000032 * Parse an octal string from a buffer.
33 * Leading spaces are ignored.
34 * Parsing stops when a NUL is found, or a trailing space,
35 * or the buffer length is reached.
Torsten Curdtca165392008-07-10 10:17:44 +000036 *
Sebastian Bazley11349c52009-03-31 23:49:20 +000037 * Behaviour with non-octal input is currently undefined.
38 *
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000039 * @param buffer The buffer from which to parse.
Torsten Curdtca165392008-07-10 10:17:44 +000040 * @param offset The offset into the buffer from which to parse.
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000041 * @param length The maximum number of bytes to parse.
Torsten Curdt46ad24d2009-01-08 11:09:25 +000042 * @return The long value of the octal string.
Torsten Curdtca165392008-07-10 10:17:44 +000043 */
Sebastian Bazley1d556702009-04-02 18:45:02 +000044 public static long parseOctal(byte[] buffer, final int offset, final int length) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +000045 long result = 0;
46 boolean stillPadding = true;
47 int end = offset + length;
Torsten Curdtca165392008-07-10 10:17:44 +000048
Torsten Curdt46ad24d2009-01-08 11:09:25 +000049 for (int i = offset; i < end; ++i) {
Sebastian Bazley1d556702009-04-02 18:45:02 +000050 final byte currentByte = buffer[i];
51 if (currentByte == 0) { // Found trailing null
Torsten Curdt46ad24d2009-01-08 11:09:25 +000052 break;
Torsten Curdtca165392008-07-10 10:17:44 +000053 }
Torsten Curdt46ad24d2009-01-08 11:09:25 +000054
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000055 // Ignore leading spaces ('0' can be ignored anyway)
Sebastian Bazley1d556702009-04-02 18:45:02 +000056 if (currentByte == (byte) ' ' || currentByte == '0') {
Torsten Curdt46ad24d2009-01-08 11:09:25 +000057 if (stillPadding) {
58 continue;
59 }
60
Sebastian Bazley1d556702009-04-02 18:45:02 +000061 if (currentByte == (byte) ' ') { // Found trailing space
Torsten Curdt46ad24d2009-01-08 11:09:25 +000062 break;
63 }
64 }
65
66 stillPadding = false;
67 // CheckStyle:MagicNumber OFF
Sebastian Bazley1d556702009-04-02 18:45:02 +000068 if (currentByte < '0' || currentByte > '7'){
69 throw new IllegalArgumentException(
70 "Invalid octal digit at position "+i+" in '"+new String(buffer, offset, length)+"'");
71 }
72 result = (result << 3) + (currentByte - '0');// TODO needs to reject invalid bytes
Torsten Curdt46ad24d2009-01-08 11:09:25 +000073 // CheckStyle:MagicNumber ON
Torsten Curdtca165392008-07-10 10:17:44 +000074 }
75
Torsten Curdt46ad24d2009-01-08 11:09:25 +000076 return result;
Torsten Curdtca165392008-07-10 10:17:44 +000077 }
78
79 /**
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000080 * Parse an entry name from a buffer.
81 * Parsing stops when a NUL is found
82 * or the buffer length is reached.
Torsten Curdtca165392008-07-10 10:17:44 +000083 *
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000084 * @param buffer The buffer from which to parse.
Torsten Curdtca165392008-07-10 10:17:44 +000085 * @param offset The offset into the buffer from which to parse.
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000086 * @param length The maximum number of bytes to parse.
87 * @return The entry name.
Torsten Curdtca165392008-07-10 10:17:44 +000088 */
Sebastian Bazley1d556702009-04-02 18:45:02 +000089 public static String parseName(byte[] buffer, final int offset, final int length) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +000090 StringBuffer result = new StringBuffer(length);
91 int end = offset + length;
Torsten Curdtca165392008-07-10 10:17:44 +000092
Torsten Curdt46ad24d2009-01-08 11:09:25 +000093 for (int i = offset; i < end; ++i) {
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000094 if (buffer[i] == 0) { // Trailing null
Torsten Curdtca165392008-07-10 10:17:44 +000095 break;
96 }
97
Sebastian Bazleyae3c1582009-03-31 16:24:28 +000098 result.append((char) buffer[i]);
Torsten Curdtca165392008-07-10 10:17:44 +000099 }
100
Sebastian Bazley1d556702009-04-02 18:45:02 +0000101 return result.toString();
Torsten Curdtca165392008-07-10 10:17:44 +0000102 }
103
104 /**
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000105 * Copy a name (StringBuffer) into a buffer.
106 * Copies characters from the name into the buffer
107 * starting at the specified offset.
108 * If the buffer is longer than the name, the buffer
109 * is filled with trailing NULs.
110 * If the name is longer than the buffer,
111 * the output is truncated.
Torsten Curdtca165392008-07-10 10:17:44 +0000112 *
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000113 * @param name The header name from which to copy the characters.
114 * @param buf The buffer where the name is to be stored.
115 * @param offset The starting offset into the buffer
116 * @param length The maximum number of header bytes to copy.
117 * @return The updated offset, i.e. offset + length
Torsten Curdtca165392008-07-10 10:17:44 +0000118 */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000119 public static int formatNameBytes(String name, byte[] buf, final int offset, final int length) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000120 int i;
Torsten Curdtca165392008-07-10 10:17:44 +0000121
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000122 // copy until end of input or output is reached.
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000123 for (i = 0; i < length && i < name.length(); ++i) {
124 buf[offset + i] = (byte) name.charAt(i);
Torsten Curdtca165392008-07-10 10:17:44 +0000125 }
126
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000127 // Pad any remaining output bytes with NUL
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000128 for (; i < length; ++i) {
129 buf[offset + i] = 0;
130 }
131
132 return offset + length;
133 }
134
135 /**
Sebastian Bazley1d556702009-04-02 18:45:02 +0000136 * Fill buffer with unsigned octal number, padded with leading zeroes.
Sebastian Bazley11349c52009-03-31 23:49:20 +0000137 *
Sebastian Bazley1d556702009-04-02 18:45:02 +0000138 * @param value number to convert to octal - treated as unsigned
Sebastian Bazley11349c52009-03-31 23:49:20 +0000139 * @param buffer destination buffer
140 * @param offset starting offset in buffer
141 * @param length length of buffer to fill
Sebastian Bazley1d556702009-04-02 18:45:02 +0000142 * @throws IllegalArgumentException if the value will not fit in the buffer
Sebastian Bazley11349c52009-03-31 23:49:20 +0000143 */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000144 public static void formatUnsignedOctalString(final long value, byte[] buffer,
145 final int offset, final int length) {
146 int remaining = length;
147 remaining--;
Sebastian Bazley11349c52009-03-31 23:49:20 +0000148 if (value == 0) {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000149 buffer[offset + remaining--] = (byte) '0';
Sebastian Bazley11349c52009-03-31 23:49:20 +0000150 } else {
Sebastian Bazley1d556702009-04-02 18:45:02 +0000151 long val = value;
152 for (; remaining >= 0 && val != 0; --remaining) {
Sebastian Bazley11349c52009-03-31 23:49:20 +0000153 // CheckStyle:MagicNumber OFF
Sebastian Bazley1d556702009-04-02 18:45:02 +0000154 buffer[offset + remaining] = (byte) ((byte) '0' + (byte) (val & 7));
155 val = val >>> 3;
Sebastian Bazley11349c52009-03-31 23:49:20 +0000156 // CheckStyle:MagicNumber ON
157 }
Sebastian Bazley1d556702009-04-02 18:45:02 +0000158 if (val != 0){
159 throw new IllegalArgumentException
160 (value+"="+Long.toOctalString(value)+ " will not fit in octal number buffer of length "+length);
161 }
Sebastian Bazley11349c52009-03-31 23:49:20 +0000162 }
163
Sebastian Bazley1d556702009-04-02 18:45:02 +0000164 for (; remaining >= 0; --remaining) { // leading zeros
165 buffer[offset + remaining] = (byte) '0';
Sebastian Bazley11349c52009-03-31 23:49:20 +0000166 }
167 }
168
169 /**
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000170 * Write an octal integer into a buffer.
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000171 *
Sebastian Bazley1d556702009-04-02 18:45:02 +0000172 * Uses {@link #formatUnsignedOctalString} to format
173 * the value as an octal string with leading zeros.
174 * The converted number is followed by space and NUL
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000175 *
176 * @param value The value to write
177 * @param buf The buffer to receive the output
178 * @param offset The starting offset into the buffer
179 * @param length The size of the output buffer
180 * @return The updated offset, i.e offset+length
Sebastian Bazley1d556702009-04-02 18:45:02 +0000181 * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000182 */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000183 public static int formatOctalBytes(final long value, byte[] buf, final int offset, final int length) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000184
Sebastian Bazley11349c52009-03-31 23:49:20 +0000185 int idx=length-2; // For space and trailing null
186 formatUnsignedOctalString(value, buf, offset, idx);
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000187
Sebastian Bazley11349c52009-03-31 23:49:20 +0000188 buf[offset + idx++] = (byte) ' '; // Trailing space
189 buf[offset + idx] = 0; // Trailing null
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000190
191 return offset + length;
192 }
193
194 /**
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000195 * Write an octal long integer into a buffer.
Sebastian Bazley1d556702009-04-02 18:45:02 +0000196 *
197 * Uses {@link #formatUnsignedOctalString} to format
198 * the value as an octal string with leading zeros.
199 * The converted number is followed by a space.
Sebastian Bazley11349c52009-03-31 23:49:20 +0000200 *
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000201 * @param value The value to write as octal
202 * @param buf The destinationbuffer.
203 * @param offset The starting offset into the buffer.
204 * @param length The length of the buffer
205 * @return The updated offset
Sebastian Bazley1d556702009-04-02 18:45:02 +0000206 * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000207 */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000208 public static int formatLongOctalBytes(final long value, byte[] buf, final int offset, final int length) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000209
Sebastian Bazley11349c52009-03-31 23:49:20 +0000210 int idx=length-1; // For space
211
212 formatUnsignedOctalString(value, buf, offset, idx);
213 buf[offset + idx] = (byte) ' '; // Trailing space
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000214
215 return offset + length;
216 }
217
218 /**
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000219 * Writes an octal value into a buffer.
Sebastian Bazley1d556702009-04-02 18:45:02 +0000220 *
221 * Uses {@link #formatUnsignedOctalString} to format
222 * the value as an octal string with leading zeros.
223 * The converted number is followed by NUL and then space.
Sebastian Bazleyae3c1582009-03-31 16:24:28 +0000224 *
225 * @param value The value to convert
226 * @param buf The destination buffer
227 * @param offset The starting offset into the buffer.
228 * @param length The size of the buffer.
229 * @return The updated value of offset, i.e. offset+length
Sebastian Bazley1d556702009-04-02 18:45:02 +0000230 * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000231 */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000232 public static int formatCheckSumOctalBytes(final long value, byte[] buf, final int offset, final int length) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000233
Sebastian Bazley11349c52009-03-31 23:49:20 +0000234 int idx=length-2; // for NUL and space
235 formatUnsignedOctalString(value, buf, offset, idx);
236
237 buf[offset + idx++] = 0; // Trailing null
238 buf[offset + idx] = (byte) ' '; // Trailing space
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000239
240 return offset + length;
241 }
242
243 /**
244 * Compute the checksum of a tar entry header.
245 *
246 * @param buf The tar entry's header buffer.
247 * @return The computed checksum.
248 */
Sebastian Bazley1d556702009-04-02 18:45:02 +0000249 public static long computeCheckSum(final byte[] buf) {
Torsten Curdt46ad24d2009-01-08 11:09:25 +0000250 long sum = 0;
251
252 for (int i = 0; i < buf.length; ++i) {
253 sum += BYTE_MASK & buf[i];
254 }
255
256 return sum;
Torsten Curdtca165392008-07-10 10:17:44 +0000257 }
258}