| /* |
| * 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.utils; |
| |
| import java.io.UnsupportedEncodingException; |
| import java.util.Arrays; |
| |
| import org.apache.commons.compress.archivers.ArchiveEntry; |
| |
| /** |
| * Generic Archive utilities |
| */ |
| public class ArchiveUtils { |
| |
| private static final int MAX_SANITIZED_NAME_LENGTH = 255; |
| |
| /** Private constructor to prevent instantiation of this utility class. */ |
| private ArchiveUtils(){ |
| } |
| |
| /** |
| * Generates a string containing the name, isDirectory setting and size of an entry. |
| * <p> |
| * For example: |
| * <pre> |
| * - 2000 main.c |
| * d 100 testfiles |
| * </pre> |
| * |
| * @param entry the entry |
| * @return the representation of the entry |
| */ |
| public static String toString(final ArchiveEntry entry){ |
| final StringBuilder sb = new StringBuilder(); |
| sb.append(entry.isDirectory()? 'd' : '-');// c.f. "ls -l" output |
| final String size = Long.toString(entry.getSize()); |
| sb.append(' '); |
| // Pad output to 7 places, leading spaces |
| for(int i=7; i > size.length(); i--){ |
| sb.append(' '); |
| } |
| sb.append(size); |
| sb.append(' ').append(entry.getName()); |
| return sb.toString(); |
| } |
| |
| /** |
| * Check if buffer contents matches Ascii String. |
| * |
| * @param expected expected string |
| * @param buffer the buffer |
| * @param offset offset to read from |
| * @param length length of the buffer |
| * @return {@code true} if buffer is the same as the expected string |
| */ |
| public static boolean matchAsciiBuffer( |
| final String expected, final byte[] buffer, final int offset, final int length){ |
| byte[] buffer1; |
| try { |
| buffer1 = expected.getBytes(CharsetNames.US_ASCII); |
| } catch (final UnsupportedEncodingException e) { |
| throw new RuntimeException(e); // Should not happen |
| } |
| return isEqual(buffer1, 0, buffer1.length, buffer, offset, length, false); |
| } |
| |
| /** |
| * Check if buffer contents matches Ascii String. |
| * |
| * @param expected the expected strin |
| * @param buffer the buffer |
| * @return {@code true} if buffer is the same as the expected string |
| */ |
| public static boolean matchAsciiBuffer(final String expected, final byte[] buffer){ |
| return matchAsciiBuffer(expected, buffer, 0, buffer.length); |
| } |
| |
| /** |
| * Convert a string to Ascii bytes. |
| * Used for comparing "magic" strings which need to be independent of the default Locale. |
| * |
| * @param inputString string to convert |
| * @return the bytes |
| */ |
| public static byte[] toAsciiBytes(final String inputString){ |
| try { |
| return inputString.getBytes(CharsetNames.US_ASCII); |
| } catch (final UnsupportedEncodingException e) { |
| throw new RuntimeException(e); // Should never happen |
| } |
| } |
| |
| /** |
| * Convert an input byte array to a String using the ASCII character set. |
| * |
| * @param inputBytes bytes to convert |
| * @return the bytes, interpreted as an Ascii string |
| */ |
| public static String toAsciiString(final byte[] inputBytes){ |
| try { |
| return new String(inputBytes, CharsetNames.US_ASCII); |
| } catch (final UnsupportedEncodingException e) { |
| throw new RuntimeException(e); // Should never happen |
| } |
| } |
| |
| /** |
| * Convert an input byte array to a String using the ASCII character set. |
| * |
| * @param inputBytes input byte array |
| * @param offset offset within array |
| * @param length length of array |
| * @return the bytes, interpreted as an Ascii string |
| */ |
| public static String toAsciiString(final byte[] inputBytes, final int offset, final int length){ |
| try { |
| return new String(inputBytes, offset, length, CharsetNames.US_ASCII); |
| } catch (final UnsupportedEncodingException e) { |
| throw new RuntimeException(e); // Should never happen |
| } |
| } |
| |
| /** |
| * Compare byte buffers, optionally ignoring trailing nulls |
| * |
| * @param buffer1 first buffer |
| * @param offset1 first offset |
| * @param length1 first length |
| * @param buffer2 second buffer |
| * @param offset2 second offset |
| * @param length2 second length |
| * @param ignoreTrailingNulls whether to ignore trailing nulls |
| * @return {@code true} if buffer1 and buffer2 have same contents, having regard to trailing nulls |
| */ |
| public static boolean isEqual( |
| final byte[] buffer1, final int offset1, final int length1, |
| final byte[] buffer2, final int offset2, final int length2, |
| final boolean ignoreTrailingNulls){ |
| final int minLen=length1 < length2 ? length1 : length2; |
| for (int i=0; i < minLen; i++){ |
| if (buffer1[offset1+i] != buffer2[offset2+i]){ |
| return false; |
| } |
| } |
| if (length1 == length2){ |
| return true; |
| } |
| if (ignoreTrailingNulls){ |
| if (length1 > length2){ |
| for(int i = length2; i < length1; i++){ |
| if (buffer1[offset1+i] != 0){ |
| return false; |
| } |
| } |
| } else { |
| for(int i = length1; i < length2; i++){ |
| if (buffer2[offset2+i] != 0){ |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Compare byte buffers |
| * |
| * @param buffer1 the first buffer |
| * @param offset1 the first offset |
| * @param length1 the first length |
| * @param buffer2 the second buffer |
| * @param offset2 the second offset |
| * @param length2 the second length |
| * @return {@code true} if buffer1 and buffer2 have same contents |
| */ |
| public static boolean isEqual( |
| final byte[] buffer1, final int offset1, final int length1, |
| final byte[] buffer2, final int offset2, final int length2){ |
| return isEqual(buffer1, offset1, length1, buffer2, offset2, length2, false); |
| } |
| |
| /** |
| * Compare byte buffers |
| * |
| * @param buffer1 the first buffer |
| * @param buffer2 the second buffer |
| * @return {@code true} if buffer1 and buffer2 have same contents |
| */ |
| public static boolean isEqual(final byte[] buffer1, final byte[] buffer2 ){ |
| return isEqual(buffer1, 0, buffer1.length, buffer2, 0, buffer2.length, false); |
| } |
| |
| /** |
| * Compare byte buffers, optionally ignoring trailing nulls |
| * |
| * @param buffer1 the first buffer |
| * @param buffer2 the second buffer |
| * @param ignoreTrailingNulls whether to ignore tariling nulls |
| * @return {@code true} if buffer1 and buffer2 have same contents |
| */ |
| public static boolean isEqual(final byte[] buffer1, final byte[] buffer2, final boolean ignoreTrailingNulls){ |
| return isEqual(buffer1, 0, buffer1.length, buffer2, 0, buffer2.length, ignoreTrailingNulls); |
| } |
| |
| /** |
| * Compare byte buffers, ignoring trailing nulls |
| * |
| * @param buffer1 the first buffer |
| * @param offset1 the first offset |
| * @param length1 the first length |
| * @param buffer2 the second buffer |
| * @param offset2 the second offset |
| * @param length2 the second length |
| * @return {@code true} if buffer1 and buffer2 have same contents, having regard to trailing nulls |
| */ |
| public static boolean isEqualWithNull( |
| final byte[] buffer1, final int offset1, final int length1, |
| final byte[] buffer2, final int offset2, final int length2){ |
| return isEqual(buffer1, offset1, length1, buffer2, offset2, length2, true); |
| } |
| |
| /** |
| * Returns true if the first N bytes of an array are all zero |
| * |
| * @param a |
| * The array to check |
| * @param size |
| * The number of characters to check (not the size of the array) |
| * @return true if the first N bytes are zero |
| */ |
| public static boolean isArrayZero(final byte[] a, final int size) { |
| for (int i = 0; i < size; i++) { |
| if (a[i] != 0) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Returns a "sanitized" version of the string given as arguments, |
| * where sanitized means non-printable characters have been |
| * replaced with a question mark and the outcome is not longer |
| * than 255 chars. |
| * |
| * <p>This method is used to clean up file names when they are |
| * used in exception messages as they may end up in log files or |
| * as console output and may have been read from a corrupted |
| * input.</p> |
| * |
| * @param s the string to sanitize |
| * @return a sanitized version of the argument |
| * @since Compress 1.12 |
| */ |
| public static String sanitize(final String s) { |
| final char[] cs = s.toCharArray(); |
| final char[] chars = cs.length <= MAX_SANITIZED_NAME_LENGTH ? cs : Arrays.copyOf(cs, MAX_SANITIZED_NAME_LENGTH); |
| if (cs.length > MAX_SANITIZED_NAME_LENGTH) { |
| for (int i = MAX_SANITIZED_NAME_LENGTH - 3; i < MAX_SANITIZED_NAME_LENGTH; i++) { |
| chars[i] = '.'; |
| } |
| } |
| final int len = chars.length; |
| final StringBuilder sb = new StringBuilder(); |
| for (int i = 0; i < len; i++) { |
| final char c = chars[i]; |
| if (!Character.isISOControl(c)) { |
| Character.UnicodeBlock block = Character.UnicodeBlock.of(c); |
| if (block != null && block != Character.UnicodeBlock.SPECIALS) { |
| sb.append(c); |
| continue; |
| } |
| } |
| sb.append('?'); |
| } |
| return sb.toString(); |
| } |
| |
| } |