| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.commons.compress.archivers.tar; |
| |
| /** |
| * This class provides static utility methods to work with byte streams. |
| * |
| * @Immutable |
| */ |
| // CheckStyle:HideUtilityClassConstructorCheck OFF (bc) |
| public class TarUtils { |
| |
| private static final int BYTE_MASK = 255; |
| |
| /** Private constructor to prevent instantiation of this utility class. */ |
| private TarUtils(){ |
| } |
| |
| /** |
| * Parse an octal string from a buffer. |
| * Leading spaces are ignored. |
| * Parsing stops when a NUL is found, or a trailing space, |
| * or the buffer length is reached. |
| * |
| * Behaviour with non-octal input is currently undefined. |
| * |
| * @param buffer The buffer from which to parse. |
| * @param offset The offset into the buffer from which to parse. |
| * @param length The maximum number of bytes to parse. |
| * @return The long value of the octal string. |
| */ |
| public static long parseOctal(byte[] buffer, final int offset, final int length) { |
| long result = 0; |
| boolean stillPadding = true; |
| int end = offset + length; |
| |
| for (int i = offset; i < end; ++i) { |
| final byte currentByte = buffer[i]; |
| if (currentByte == 0) { // Found trailing null |
| break; |
| } |
| |
| // Ignore leading spaces ('0' can be ignored anyway) |
| if (currentByte == (byte) ' ' || currentByte == '0') { |
| if (stillPadding) { |
| continue; |
| } |
| |
| if (currentByte == (byte) ' ') { // Found trailing space |
| break; |
| } |
| } |
| |
| stillPadding = false; |
| // CheckStyle:MagicNumber OFF |
| if (currentByte < '0' || currentByte > '7'){ |
| throw new IllegalArgumentException( |
| "Invalid octal digit at position "+i+" in '"+new String(buffer, offset, length)+"'"); |
| } |
| result = (result << 3) + (currentByte - '0');// TODO needs to reject invalid bytes |
| // CheckStyle:MagicNumber ON |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Parse an entry name from a buffer. |
| * Parsing stops when a NUL is found |
| * or the buffer length is reached. |
| * |
| * @param buffer The buffer from which to parse. |
| * @param offset The offset into the buffer from which to parse. |
| * @param length The maximum number of bytes to parse. |
| * @return The entry name. |
| */ |
| public static String parseName(byte[] buffer, final int offset, final int length) { |
| StringBuffer result = new StringBuffer(length); |
| int end = offset + length; |
| |
| for (int i = offset; i < end; ++i) { |
| if (buffer[i] == 0) { // Trailing null |
| break; |
| } |
| |
| result.append((char) buffer[i]); |
| } |
| |
| return result.toString(); |
| } |
| |
| /** |
| * Copy a name (StringBuffer) into a buffer. |
| * Copies characters from the name into the buffer |
| * starting at the specified offset. |
| * If the buffer is longer than the name, the buffer |
| * is filled with trailing NULs. |
| * If the name is longer than the buffer, |
| * the output is truncated. |
| * |
| * @param name The header name from which to copy the characters. |
| * @param buf The buffer where the name is to be stored. |
| * @param offset The starting offset into the buffer |
| * @param length The maximum number of header bytes to copy. |
| * @return The updated offset, i.e. offset + length |
| */ |
| public static int formatNameBytes(String name, byte[] buf, final int offset, final int length) { |
| int i; |
| |
| // copy until end of input or output is reached. |
| for (i = 0; i < length && i < name.length(); ++i) { |
| buf[offset + i] = (byte) name.charAt(i); |
| } |
| |
| // Pad any remaining output bytes with NUL |
| for (; i < length; ++i) { |
| buf[offset + i] = 0; |
| } |
| |
| return offset + length; |
| } |
| |
| /** |
| * Fill buffer with unsigned octal number, padded with leading zeroes. |
| * |
| * @param value number to convert to octal - treated as unsigned |
| * @param buffer destination buffer |
| * @param offset starting offset in buffer |
| * @param length length of buffer to fill |
| * @throws IllegalArgumentException if the value will not fit in the buffer |
| */ |
| public static void formatUnsignedOctalString(final long value, byte[] buffer, |
| final int offset, final int length) { |
| int remaining = length; |
| remaining--; |
| if (value == 0) { |
| buffer[offset + remaining--] = (byte) '0'; |
| } else { |
| long val = value; |
| for (; remaining >= 0 && val != 0; --remaining) { |
| // CheckStyle:MagicNumber OFF |
| buffer[offset + remaining] = (byte) ((byte) '0' + (byte) (val & 7)); |
| val = val >>> 3; |
| // CheckStyle:MagicNumber ON |
| } |
| if (val != 0){ |
| throw new IllegalArgumentException |
| (value+"="+Long.toOctalString(value)+ " will not fit in octal number buffer of length "+length); |
| } |
| } |
| |
| for (; remaining >= 0; --remaining) { // leading zeros |
| buffer[offset + remaining] = (byte) '0'; |
| } |
| } |
| |
| /** |
| * Write an octal integer into a buffer. |
| * |
| * Uses {@link #formatUnsignedOctalString} to format |
| * the value as an octal string with leading zeros. |
| * The converted number is followed by space and NUL |
| * |
| * @param value The value to write |
| * @param buf The buffer to receive the output |
| * @param offset The starting offset into the buffer |
| * @param length The size of the output buffer |
| * @return The updated offset, i.e offset+length |
| * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer |
| */ |
| public static int formatOctalBytes(final long value, byte[] buf, final int offset, final int length) { |
| |
| int idx=length-2; // For space and trailing null |
| formatUnsignedOctalString(value, buf, offset, idx); |
| |
| buf[offset + idx++] = (byte) ' '; // Trailing space |
| buf[offset + idx] = 0; // Trailing null |
| |
| return offset + length; |
| } |
| |
| /** |
| * Write an octal long integer into a buffer. |
| * |
| * Uses {@link #formatUnsignedOctalString} to format |
| * the value as an octal string with leading zeros. |
| * The converted number is followed by a space. |
| * |
| * @param value The value to write as octal |
| * @param buf The destinationbuffer. |
| * @param offset The starting offset into the buffer. |
| * @param length The length of the buffer |
| * @return The updated offset |
| * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer |
| */ |
| public static int formatLongOctalBytes(final long value, byte[] buf, final int offset, final int length) { |
| |
| int idx=length-1; // For space |
| |
| formatUnsignedOctalString(value, buf, offset, idx); |
| buf[offset + idx] = (byte) ' '; // Trailing space |
| |
| return offset + length; |
| } |
| |
| /** |
| * Writes an octal value into a buffer. |
| * |
| * Uses {@link #formatUnsignedOctalString} to format |
| * the value as an octal string with leading zeros. |
| * The converted number is followed by NUL and then space. |
| * |
| * @param value The value to convert |
| * @param buf The destination buffer |
| * @param offset The starting offset into the buffer. |
| * @param length The size of the buffer. |
| * @return The updated value of offset, i.e. offset+length |
| * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer |
| */ |
| public static int formatCheckSumOctalBytes(final long value, byte[] buf, final int offset, final int length) { |
| |
| int idx=length-2; // for NUL and space |
| formatUnsignedOctalString(value, buf, offset, idx); |
| |
| buf[offset + idx++] = 0; // Trailing null |
| buf[offset + idx] = (byte) ' '; // Trailing space |
| |
| return offset + length; |
| } |
| |
| /** |
| * Compute the checksum of a tar entry header. |
| * |
| * @param buf The tar entry's header buffer. |
| * @return The computed checksum. |
| */ |
| public static long computeCheckSum(final byte[] buf) { |
| long sum = 0; |
| |
| for (int i = 0; i < buf.length; ++i) { |
| sum += BYTE_MASK & buf[i]; |
| } |
| |
| return sum; |
| } |
| } |