001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 package org.apache.commons.compress.archivers.tar; 020 021 /** 022 * This class provides static utility methods to work with byte streams. 023 * 024 * @Immutable 025 */ 026 // CheckStyle:HideUtilityClassConstructorCheck OFF (bc) 027 public class TarUtils { 028 029 private static final int BYTE_MASK = 255; 030 031 /** Private constructor to prevent instantiation of this utility class. */ 032 private TarUtils(){ 033 } 034 035 /** 036 * Parse an octal string from a buffer. 037 * Leading spaces are ignored. 038 * Parsing stops when a NUL is found, or a trailing space, 039 * or the buffer length is reached. 040 * 041 * Behaviour with non-octal input is currently undefined. 042 * 043 * @param buffer The buffer from which to parse. 044 * @param offset The offset into the buffer from which to parse. 045 * @param length The maximum number of bytes to parse. 046 * @return The long value of the octal string. 047 */ 048 public static long parseOctal(byte[] buffer, final int offset, final int length) { 049 long result = 0; 050 boolean stillPadding = true; 051 int end = offset + length; 052 053 for (int i = offset; i < end; ++i) { 054 final byte currentByte = buffer[i]; 055 if (currentByte == 0) { // Found trailing null 056 break; 057 } 058 059 // Ignore leading spaces ('0' can be ignored anyway) 060 if (currentByte == (byte) ' ' || currentByte == '0') { 061 if (stillPadding) { 062 continue; 063 } 064 065 if (currentByte == (byte) ' ') { // Found trailing space 066 break; 067 } 068 } 069 070 stillPadding = false; 071 // CheckStyle:MagicNumber OFF 072 if (currentByte < '0' || currentByte > '7'){ 073 throw new IllegalArgumentException( 074 "Invalid octal digit at position "+i+" in '"+new String(buffer, offset, length)+"'"); 075 } 076 result = (result << 3) + (currentByte - '0');// TODO needs to reject invalid bytes 077 // CheckStyle:MagicNumber ON 078 } 079 080 return result; 081 } 082 083 /** 084 * Parse an entry name from a buffer. 085 * Parsing stops when a NUL is found 086 * or the buffer length is reached. 087 * 088 * @param buffer The buffer from which to parse. 089 * @param offset The offset into the buffer from which to parse. 090 * @param length The maximum number of bytes to parse. 091 * @return The entry name. 092 */ 093 public static String parseName(byte[] buffer, final int offset, final int length) { 094 StringBuffer result = new StringBuffer(length); 095 int end = offset + length; 096 097 for (int i = offset; i < end; ++i) { 098 if (buffer[i] == 0) { // Trailing null 099 break; 100 } 101 102 result.append((char) buffer[i]); 103 } 104 105 return result.toString(); 106 } 107 108 /** 109 * Copy a name (StringBuffer) into a buffer. 110 * Copies characters from the name into the buffer 111 * starting at the specified offset. 112 * If the buffer is longer than the name, the buffer 113 * is filled with trailing NULs. 114 * If the name is longer than the buffer, 115 * the output is truncated. 116 * 117 * @param name The header name from which to copy the characters. 118 * @param buf The buffer where the name is to be stored. 119 * @param offset The starting offset into the buffer 120 * @param length The maximum number of header bytes to copy. 121 * @return The updated offset, i.e. offset + length 122 */ 123 public static int formatNameBytes(String name, byte[] buf, final int offset, final int length) { 124 int i; 125 126 // copy until end of input or output is reached. 127 for (i = 0; i < length && i < name.length(); ++i) { 128 buf[offset + i] = (byte) name.charAt(i); 129 } 130 131 // Pad any remaining output bytes with NUL 132 for (; i < length; ++i) { 133 buf[offset + i] = 0; 134 } 135 136 return offset + length; 137 } 138 139 /** 140 * Fill buffer with unsigned octal number, padded with leading zeroes. 141 * 142 * @param value number to convert to octal - treated as unsigned 143 * @param buffer destination buffer 144 * @param offset starting offset in buffer 145 * @param length length of buffer to fill 146 * @throws IllegalArgumentException if the value will not fit in the buffer 147 */ 148 public static void formatUnsignedOctalString(final long value, byte[] buffer, 149 final int offset, final int length) { 150 int remaining = length; 151 remaining--; 152 if (value == 0) { 153 buffer[offset + remaining--] = (byte) '0'; 154 } else { 155 long val = value; 156 for (; remaining >= 0 && val != 0; --remaining) { 157 // CheckStyle:MagicNumber OFF 158 buffer[offset + remaining] = (byte) ((byte) '0' + (byte) (val & 7)); 159 val = val >>> 3; 160 // CheckStyle:MagicNumber ON 161 } 162 if (val != 0){ 163 throw new IllegalArgumentException 164 (value+"="+Long.toOctalString(value)+ " will not fit in octal number buffer of length "+length); 165 } 166 } 167 168 for (; remaining >= 0; --remaining) { // leading zeros 169 buffer[offset + remaining] = (byte) '0'; 170 } 171 } 172 173 /** 174 * Write an octal integer into a buffer. 175 * 176 * Uses {@link #formatUnsignedOctalString} to format 177 * the value as an octal string with leading zeros. 178 * The converted number is followed by space and NUL 179 * 180 * @param value The value to write 181 * @param buf The buffer to receive the output 182 * @param offset The starting offset into the buffer 183 * @param length The size of the output buffer 184 * @return The updated offset, i.e offset+length 185 * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer 186 */ 187 public static int formatOctalBytes(final long value, byte[] buf, final int offset, final int length) { 188 189 int idx=length-2; // For space and trailing null 190 formatUnsignedOctalString(value, buf, offset, idx); 191 192 buf[offset + idx++] = (byte) ' '; // Trailing space 193 buf[offset + idx] = 0; // Trailing null 194 195 return offset + length; 196 } 197 198 /** 199 * Write an octal long integer into a buffer. 200 * 201 * Uses {@link #formatUnsignedOctalString} to format 202 * the value as an octal string with leading zeros. 203 * The converted number is followed by a space. 204 * 205 * @param value The value to write as octal 206 * @param buf The destinationbuffer. 207 * @param offset The starting offset into the buffer. 208 * @param length The length of the buffer 209 * @return The updated offset 210 * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer 211 */ 212 public static int formatLongOctalBytes(final long value, byte[] buf, final int offset, final int length) { 213 214 int idx=length-1; // For space 215 216 formatUnsignedOctalString(value, buf, offset, idx); 217 buf[offset + idx] = (byte) ' '; // Trailing space 218 219 return offset + length; 220 } 221 222 /** 223 * Writes an octal value into a buffer. 224 * 225 * Uses {@link #formatUnsignedOctalString} to format 226 * the value as an octal string with leading zeros. 227 * The converted number is followed by NUL and then space. 228 * 229 * @param value The value to convert 230 * @param buf The destination buffer 231 * @param offset The starting offset into the buffer. 232 * @param length The size of the buffer. 233 * @return The updated value of offset, i.e. offset+length 234 * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer 235 */ 236 public static int formatCheckSumOctalBytes(final long value, byte[] buf, final int offset, final int length) { 237 238 int idx=length-2; // for NUL and space 239 formatUnsignedOctalString(value, buf, offset, idx); 240 241 buf[offset + idx++] = 0; // Trailing null 242 buf[offset + idx] = (byte) ' '; // Trailing space 243 244 return offset + length; 245 } 246 247 /** 248 * Compute the checksum of a tar entry header. 249 * 250 * @param buf The tar entry's header buffer. 251 * @return The computed checksum. 252 */ 253 public static long computeCheckSum(final byte[] buf) { 254 long sum = 0; 255 256 for (int i = 0; i < buf.length; ++i) { 257 sum += BYTE_MASK & buf[i]; 258 } 259 260 return sum; 261 } 262 }