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 */
019package org.apache.commons.compress.utils;
020
021import java.io.ByteArrayOutputStream;
022import java.io.Closeable;
023import java.io.EOFException;
024import java.io.File;
025import java.io.IOException;
026import java.io.InputStream;
027import java.io.OutputStream;
028import java.nio.ByteBuffer;
029import java.nio.channels.ReadableByteChannel;
030import java.nio.file.Files;
031import java.nio.file.LinkOption;
032
033import org.apache.commons.io.FileUtils;
034
035/**
036 * Utility functions.
037 *
038 * @Immutable (has mutable data but it is write-only).
039 */
040public final class IOUtils {
041
042    private static final int COPY_BUF_SIZE = 8024;
043
044    /**
045     * Empty array of type {@link LinkOption}.
046     *
047     * @since 1.21
048     */
049    public static final LinkOption[] EMPTY_LINK_OPTIONS = {};
050
051    /**
052     * Closes the given Closeable and swallows any IOException that may occur.
053     *
054     * @param c Closeable to close, can be null
055     * @since 1.7
056     * @deprecated Use {@link org.apache.commons.io.IOUtils#closeQuietly(Closeable)}.
057     */
058    @Deprecated
059    public static void closeQuietly(final Closeable c) {
060        org.apache.commons.io.IOUtils.closeQuietly(c);
061    }
062
063    /**
064     * Copies the source file to the given output stream.
065     *
066     * @param sourceFile   The file to read.
067     * @param outputStream The output stream to write.
068     * @throws IOException if an I/O error occurs when reading or writing.
069     * @since 1.21
070     * @deprecated Use {@link FileUtils#copyFile(File, OutputStream)}.
071     */
072    @Deprecated
073    public static void copy(final File sourceFile, final OutputStream outputStream) throws IOException {
074        FileUtils.copyFile(sourceFile, outputStream);
075    }
076
077    /**
078     * Copies the content of a InputStream into an OutputStream. Uses a default buffer size of 8024 bytes.
079     *
080     * @param input  the InputStream to copy
081     * @param output the target, may be null to simulate output to dev/null on Linux and NUL on Windows
082     * @return the number of bytes copied
083     * @throws IOException if an error occurs
084     * @deprecated Use {@link org.apache.commons.io.IOUtils#copy(InputStream, OutputStream)}.
085     */
086    @Deprecated
087    public static long copy(final InputStream input, final OutputStream output) throws IOException {
088        return org.apache.commons.io.IOUtils.copy(input, output);
089    }
090
091    /**
092     * Copies the content of a InputStream into an OutputStream
093     *
094     * @param input      the InputStream to copy
095     * @param output     the target, may be null to simulate output to dev/null on Linux and NUL on Windows
096     * @param bufferSize the buffer size to use, must be bigger than 0
097     * @return the number of bytes copied
098     * @throws IOException              if an error occurs
099     * @throws IllegalArgumentException if bufferSize is smaller than or equal to 0
100     * @deprecated Use {@link org.apache.commons.io.IOUtils#copy(InputStream, OutputStream, int)}.
101     */
102    @Deprecated
103    public static long copy(final InputStream input, final OutputStream output, final int bufferSize) throws IOException {
104        return org.apache.commons.io.IOUtils.copy(input, output, bufferSize);
105    }
106
107    /**
108     * Copies part of the content of a InputStream into an OutputStream. Uses a default buffer size of 8024 bytes.
109     *
110     * @param input  the InputStream to copy
111     * @param output the target Stream
112     * @param len    maximum amount of bytes to copy
113     * @return the number of bytes copied
114     * @throws IOException if an error occurs
115     * @since 1.21
116     * @deprecated Use {@link org.apache.commons.io.IOUtils#copyLarge(InputStream, OutputStream, long, long)}.
117     */
118    @Deprecated
119    public static long copyRange(final InputStream input, final long len, final OutputStream output) throws IOException {
120        return org.apache.commons.io.IOUtils.copyLarge(input, output, 0, len);
121    }
122
123    /**
124     * Copies part of the content of a InputStream into an OutputStream
125     *
126     * @param input      the InputStream to copy
127     * @param length        maximum amount of bytes to copy
128     * @param output     the target, may be null to simulate output to dev/null on Linux and NUL on Windows
129     * @param bufferSize the buffer size to use, must be bigger than 0
130     * @return the number of bytes copied
131     * @throws IOException              if an error occurs
132     * @throws IllegalArgumentException if bufferSize is smaller than or equal to 0
133     * @since 1.21
134     * @deprecated No longer used.
135     */
136    @Deprecated
137    public static long copyRange(final InputStream input, final long length, final OutputStream output, final int bufferSize) throws IOException {
138        if (bufferSize < 1) {
139            throw new IllegalArgumentException("bufferSize must be bigger than 0");
140        }
141        final byte[] buffer = new byte[(int) Math.min(bufferSize, Math.max(0, length))];
142        int n = 0;
143        long count = 0;
144        while (count < length && -1 != (n = input.read(buffer, 0, (int) Math.min(length - count, buffer.length)))) {
145            if (output != null) {
146                output.write(buffer, 0, n);
147            }
148            count += n;
149        }
150        return count;
151    }
152
153    /**
154     * Reads as much from the file as possible to fill the given array.
155     * <p>
156     * This method may invoke read repeatedly to fill the array and only read less bytes than the length of the array if the end of the stream has been reached.
157     * </p>
158     *
159     * @param file  file to read
160     * @param array buffer to fill
161     * @return the number of bytes actually read
162     * @throws IOException on error
163     * @since 1.20
164     * @deprecated Use {@link Files#readAllBytes(java.nio.file.Path)}.
165     */
166    @Deprecated
167    public static int read(final File file, final byte[] array) throws IOException {
168        try (InputStream inputStream = Files.newInputStream(file.toPath())) {
169            return readFully(inputStream, array, 0, array.length);
170        }
171    }
172
173    /**
174     * Reads as much from input as possible to fill the given array.
175     * <p>
176     * This method may invoke read repeatedly to fill the array and only read less bytes than the length of the array if the end of the stream has been reached.
177     * </p>
178     *
179     * @param input stream to read from
180     * @param array buffer to fill
181     * @return the number of bytes actually read
182     * @throws IOException on error
183     */
184    public static int readFully(final InputStream input, final byte[] array) throws IOException {
185        return readFully(input, array, 0, array.length);
186    }
187
188    /**
189     * Reads as much from input as possible to fill the given array with the given amount of bytes.
190     * <p>
191     * This method may invoke read repeatedly to read the bytes and only read less bytes than the requested length if the end of the stream has been reached.
192     * </p>
193     *
194     * @param input  stream to read from
195     * @param array  buffer to fill
196     * @param offset offset into the buffer to start filling at
197     * @param length    of bytes to read
198     * @return the number of bytes actually read
199     * @throws IOException if an I/O error has occurred
200     */
201    public static int readFully(final InputStream input, final byte[] array, final int offset, final int length) throws IOException {
202        if (length < 0 || offset < 0 || length + offset > array.length || length + offset < 0) {
203            throw new IndexOutOfBoundsException();
204        }
205        return org.apache.commons.io.IOUtils.read(input, array, offset, length);
206    }
207
208    /**
209     * Reads {@code b.remaining()} bytes from the given channel starting at the current channel's position.
210     * <p>
211     * This method reads repeatedly from the channel until the requested number of bytes are read. This method blocks until the requested number of bytes are
212     * read, the end of the channel is detected, or an exception is thrown.
213     * </p>
214     *
215     * @param channel    the channel to read from
216     * @param byteBuffer the buffer into which the data is read.
217     * @throws IOException  if an I/O error occurs.
218     * @throws EOFException if the channel reaches the end before reading all the bytes.
219     */
220    public static void readFully(final ReadableByteChannel channel, final ByteBuffer byteBuffer) throws IOException {
221        final int expectedLength = byteBuffer.remaining();
222        final int read = org.apache.commons.io.IOUtils.read(channel, byteBuffer);
223        if (read < expectedLength) {
224            throw new EOFException();
225        }
226    }
227
228    /**
229     * Gets part of the contents of an {@code InputStream} as a {@code byte[]}.
230     *
231     * @param input the {@code InputStream} to read from
232     * @param length   maximum amount of bytes to copy
233     * @return the requested byte array
234     * @throws NullPointerException if the input is null
235     * @throws IOException          if an I/O error occurs
236     * @since 1.21
237     */
238    public static byte[] readRange(final InputStream input, final int length) throws IOException {
239        final ByteArrayOutputStream output = new ByteArrayOutputStream();
240        org.apache.commons.io.IOUtils.copyLarge(input, output, 0, length);
241        return output.toByteArray();
242    }
243
244    /**
245     * Gets part of the contents of an {@code ReadableByteChannel} as a {@code byte[]}.
246     *
247     * @param input the {@code ReadableByteChannel} to read from
248     * @param length   maximum amount of bytes to copy
249     * @return the requested byte array
250     * @throws NullPointerException if the input is null
251     * @throws IOException          if an I/O error occurs
252     * @since 1.21
253     */
254    public static byte[] readRange(final ReadableByteChannel input, final int length) throws IOException {
255        final ByteArrayOutputStream output = new ByteArrayOutputStream();
256        final ByteBuffer b = ByteBuffer.allocate(Math.min(length, COPY_BUF_SIZE));
257        int read = 0;
258        while (read < length) {
259            // Make sure we never read more than len bytes
260            b.limit(Math.min(length - read, b.capacity()));
261            final int readNow = input.read(b);
262            if (readNow <= 0) {
263                break;
264            }
265            output.write(b.array(), 0, readNow);
266            b.rewind();
267            read += readNow;
268        }
269        return output.toByteArray();
270    }
271
272    /**
273     * Skips the given number of bytes by repeatedly invoking skip on the given input stream if necessary.
274     * <p>
275     * In a case where the stream's skip() method returns 0 before the requested number of bytes has been skip this implementation will fall back to using the
276     * read() method.
277     * </p>
278     * <p>
279     * This method will only skip less than the requested number of bytes if the end of the input stream has been reached.
280     * </p>
281     *
282     * @param input     stream to skip bytes in
283     * @param numToSkip the number of bytes to skip
284     * @return the number of bytes actually skipped
285     * @throws IOException on error
286     * @deprecated Use {@link org.apache.commons.io.IOUtils#skip(InputStream, long)}.
287     */
288    @Deprecated
289    public static long skip(final InputStream input, final long numToSkip) throws IOException {
290        return org.apache.commons.io.IOUtils.skip(input, numToSkip);
291    }
292
293    /**
294     * Gets the contents of an {@code InputStream} as a {@code byte[]}.
295     * <p>
296     * This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}.
297     * </p>
298     *
299     * @param input the {@code InputStream} to read from
300     * @return the requested byte array
301     * @throws NullPointerException if the input is null
302     * @throws IOException          if an I/O error occurs
303     * @since 1.5
304     * @deprecated Use {@link org.apache.commons.io.IOUtils#toByteArray(InputStream)}.
305     */
306    @Deprecated
307    public static byte[] toByteArray(final InputStream input) throws IOException {
308        return org.apache.commons.io.IOUtils.toByteArray(input);
309    }
310
311    /** Private constructor to prevent instantiation of this utility class. */
312    private IOUtils() {
313    }
314
315}