001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *   http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 * 
017 */
018
019package org.apache.commons.compress.utils;
020
021import java.io.UnsupportedEncodingException;
022
023import org.apache.commons.compress.archivers.ArchiveEntry;
024
025/**
026 * Generic Archive utilities
027 */
028public class ArchiveUtils {
029
030    /** Private constructor to prevent instantiation of this utility class. */
031    private ArchiveUtils(){
032    }
033
034    /**
035     * Generates a string containing the name, isDirectory setting and size of an entry.
036     * <p>
037     * For example:
038     * <pre>
039     * -    2000 main.c
040     * d     100 testfiles
041     * </pre>
042     * 
043     * @param entry the entry
044     * @return the representation of the entry
045     */
046    public static String toString(ArchiveEntry entry){
047        StringBuilder sb = new StringBuilder();
048        sb.append(entry.isDirectory()? 'd' : '-');// c.f. "ls -l" output
049        String size = Long.toString(entry.getSize());
050        sb.append(' ');
051        // Pad output to 7 places, leading spaces
052        for(int i=7; i > size.length(); i--){
053            sb.append(' ');
054        }
055        sb.append(size);
056        sb.append(' ').append(entry.getName());
057        return sb.toString();
058    }
059
060    /**
061     * Check if buffer contents matches Ascii String.
062     * 
063     * @param expected expected string
064     * @param buffer the buffer
065     * @param offset offset to read from
066     * @param length length of the buffer
067     * @return {@code true} if buffer is the same as the expected string
068     */
069    public static boolean matchAsciiBuffer(
070            String expected, byte[] buffer, int offset, int length){
071        byte[] buffer1;
072        try {
073            buffer1 = expected.getBytes(CharsetNames.US_ASCII);
074        } catch (UnsupportedEncodingException e) {
075            throw new RuntimeException(e); // Should not happen
076        }
077        return isEqual(buffer1, 0, buffer1.length, buffer, offset, length, false);
078    }
079
080    /**
081     * Check if buffer contents matches Ascii String.
082     * 
083     * @param expected the expected strin
084     * @param buffer the buffer
085     * @return {@code true} if buffer is the same as the expected string
086     */
087    public static boolean matchAsciiBuffer(String expected, byte[] buffer){
088        return matchAsciiBuffer(expected, buffer, 0, buffer.length);
089    }
090
091    /**
092     * Convert a string to Ascii bytes.
093     * Used for comparing "magic" strings which need to be independent of the default Locale.
094     * 
095     * @param inputString string to convert
096     * @return the bytes
097     */
098    public static byte[] toAsciiBytes(String inputString){
099        try {
100            return inputString.getBytes(CharsetNames.US_ASCII);
101        } catch (UnsupportedEncodingException e) {
102           throw new RuntimeException(e); // Should never happen
103        }
104    }
105
106    /**
107     * Convert an input byte array to a String using the ASCII character set.
108     * 
109     * @param inputBytes bytes to convert
110     * @return the bytes, interpreted as an Ascii string
111     */
112    public static String toAsciiString(final byte[] inputBytes){
113        try {
114            return new String(inputBytes, CharsetNames.US_ASCII);
115        } catch (UnsupportedEncodingException e) {
116            throw new RuntimeException(e); // Should never happen
117        }
118    }
119
120    /**
121     * Convert an input byte array to a String using the ASCII character set.
122     * 
123     * @param inputBytes input byte array
124     * @param offset offset within array
125     * @param length length of array
126     * @return the bytes, interpreted as an Ascii string
127     */
128    public static String toAsciiString(final byte[] inputBytes, int offset, int length){
129        try {
130            return new String(inputBytes, offset, length, CharsetNames.US_ASCII);
131        } catch (UnsupportedEncodingException e) {
132            throw new RuntimeException(e); // Should never happen
133        }
134    }
135
136    /**
137     * Compare byte buffers, optionally ignoring trailing nulls
138     * 
139     * @param buffer1 first buffer
140     * @param offset1 first offset
141     * @param length1 first length
142     * @param buffer2 second buffer
143     * @param offset2 second offset
144     * @param length2 second length
145     * @param ignoreTrailingNulls whether to ignore trailing nulls
146     * @return {@code true} if buffer1 and buffer2 have same contents, having regard to trailing nulls
147     */
148    public static boolean isEqual(
149            final byte[] buffer1, final int offset1, final int length1,
150            final byte[] buffer2, final int offset2, final int length2,
151            boolean ignoreTrailingNulls){
152        int minLen=length1 < length2 ? length1 : length2;
153        for (int i=0; i < minLen; i++){
154            if (buffer1[offset1+i] != buffer2[offset2+i]){
155                return false;
156            }
157        }
158        if (length1 == length2){
159            return true;
160        }
161        if (ignoreTrailingNulls){
162            if (length1 > length2){
163                for(int i = length2; i < length1; i++){
164                    if (buffer1[offset1+i] != 0){
165                        return false;
166                    }
167                }
168            } else {
169                for(int i = length1; i < length2; i++){
170                    if (buffer2[offset2+i] != 0){
171                        return false;
172                    }
173                }
174            }
175            return true;
176        }
177        return false;
178    }
179
180    /**
181     * Compare byte buffers
182     * 
183     * @param buffer1 the first buffer
184     * @param offset1 the first offset
185     * @param length1 the first length
186     * @param buffer2 the second buffer
187     * @param offset2 the second offset
188     * @param length2 the second length
189     * @return {@code true} if buffer1 and buffer2 have same contents
190     */
191    public static boolean isEqual(
192            final byte[] buffer1, final int offset1, final int length1,
193            final byte[] buffer2, final int offset2, final int length2){
194        return isEqual(buffer1, offset1, length1, buffer2, offset2, length2, false);
195    }
196
197    /**
198     * Compare byte buffers
199     * 
200     * @param buffer1 the first buffer
201     * @param buffer2 the second buffer
202     * @return {@code true} if buffer1 and buffer2 have same contents
203     */
204    public static boolean isEqual(final byte[] buffer1, final byte[] buffer2 ){
205        return isEqual(buffer1, 0, buffer1.length, buffer2, 0, buffer2.length, false);
206    }
207
208    /**
209     * Compare byte buffers, optionally ignoring trailing nulls
210     * 
211     * @param buffer1 the first buffer
212     * @param buffer2 the second buffer 
213     * @param ignoreTrailingNulls whether to ignore tariling nulls
214     * @return {@code true} if buffer1 and buffer2 have same contents
215     */
216    public static boolean isEqual(final byte[] buffer1, final byte[] buffer2, boolean ignoreTrailingNulls){
217        return isEqual(buffer1, 0, buffer1.length, buffer2, 0, buffer2.length, ignoreTrailingNulls);
218    }
219
220    /**
221     * Compare byte buffers, ignoring trailing nulls
222     * 
223     * @param buffer1 the first buffer
224     * @param offset1 the first offset
225     * @param length1 the first length
226     * @param buffer2 the second buffer
227     * @param offset2 the second offset
228     * @param length2 the second length
229     * @return {@code true} if buffer1 and buffer2 have same contents, having regard to trailing nulls
230     */
231    public static boolean isEqualWithNull(
232            final byte[] buffer1, final int offset1, final int length1,
233            final byte[] buffer2, final int offset2, final int length2){
234        return isEqual(buffer1, offset1, length1, buffer2, offset2, length2, true);
235    }
236    
237    /**
238     * Returns true if the first N bytes of an array are all zero
239     * 
240     * @param a
241     *            The array to check
242     * @param size
243     *            The number of characters to check (not the size of the array)
244     * @return true if the first N bytes are zero
245     */
246    public static boolean isArrayZero(byte[] a, int size) {
247        for (int i = 0; i < size; i++) {
248            if (a[i] != 0) {
249                return false;
250            }
251        }
252        return true;
253    }
254}