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 *     https://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 */
020
021package org.apache.directory.api.util;
022
023
024import java.io.BufferedReader;
025import java.io.Closeable;
026import java.io.IOException;
027import java.io.InputStream;
028import java.io.InputStreamReader;
029import java.io.OutputStream;
030import java.io.Reader;
031import java.io.Writer;
032import java.nio.charset.Charset;
033import java.util.ArrayList;
034import java.util.List;
035
036import org.apache.directory.api.i18n.I18n;
037
038
039/**
040 * This code comes from Apache commons.io library.
041 * 
042 * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils.
043 *
044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
045 */
046public final class IOUtils
047{
048    /**
049     * The default buffer size ({@value}) to use for
050     * {@link #copyLarge(InputStream, OutputStream)}
051     * and
052     * {@link #copyLarge(Reader, Writer)}
053     */
054    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
055
056    /** The end of file */
057    private static final int EOF = -1;
058
059
060    /**
061     * Creates a new instance of FileUtils.
062     */
063    private IOUtils()
064    {
065        // Nothing to do.
066    }
067
068
069    /**
070    * Closes an <code>InputStream</code> unconditionally.
071    * <p>
072    * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
073    * This is typically used in finally blocks.
074    * <p>
075    * Example code:
076    * <pre>
077    *   byte[] data = new byte[1024];
078    *   InputStream in = null;
079    *   try {
080    *       in = new FileInputStream("foo.txt");
081    *       in.read(data);
082    *       in.close(); //close errors are handled
083    *   } catch (Exception e) {
084    *       // error handling
085    *   } finally {
086    *       IOUtils.closeQuietly(in);
087    *   }
088    * </pre>
089    *
090    * @param input  the InputStream to close, may be null or already closed
091    */
092    public static void closeQuietly( InputStream input )
093    {
094        closeQuietly( ( Closeable ) input );
095    }
096
097
098    /**
099     * Closes a <code>Closeable</code> unconditionally.
100     * <p>
101     * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in
102     * finally blocks.
103     * <p>
104     * Example code:
105     * 
106     * <pre>
107     * Closeable closeable = null;
108     * try {
109     *     closeable = new FileReader(&quot;foo.txt&quot;);
110     *     // process closeable
111     *     closeable.close();
112     * } catch (Exception e) {
113     *     // error handling
114     * } finally {
115     *     IOUtils.closeQuietly(closeable);
116     * }
117     * </pre>
118     * 
119     * Closing all streams:
120     * 
121     * <pre>
122     * try {
123     *     return IOUtils.copy(inputStream, outputStream);
124     * } finally {
125     *     IOUtils.closeQuietly(inputStream);
126     *     IOUtils.closeQuietly(outputStream);
127     * }
128     * </pre>
129     * 
130     * @param closeables the objects to close, may be null or already closed
131     * @since 2.5
132     */
133    public static void closeQuietly( Closeable... closeables )
134    {
135        if ( closeables == null )
136        {
137            return;
138        }
139
140        for ( Closeable closeable : closeables )
141        {
142            closeQuietly( closeable );
143        }
144    }
145
146
147    /**
148     * Closes a <code>Closeable</code> unconditionally.
149     * <p>
150     * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in
151     * finally blocks.
152     * <p>
153     * Example code:
154     * 
155     * <pre>
156     * Closeable closeable = null;
157     * try {
158     *     closeable = new FileReader(&quot;foo.txt&quot;);
159     *     // process closeable
160     *     closeable.close();
161     * } catch (Exception e) {
162     *     // error handling
163     * } finally {
164     *     IOUtils.closeQuietly(closeable);
165     * }
166     * </pre>
167     * 
168     * Closing all streams:
169     * 
170     * <pre>
171     * try {
172     *     return IOUtils.copy(inputStream, outputStream);
173     * } finally {
174     *     IOUtils.closeQuietly(inputStream);
175     *     IOUtils.closeQuietly(outputStream);
176     * }
177     * </pre>
178     * 
179     * @param closeable
180     *            the objects to close, may be null or already closed
181     * @since 2.0
182     */
183    public static void closeQuietly( Closeable closeable )
184    {
185        try
186        {
187            if ( closeable != null )
188            {
189                closeable.close();
190            }
191        }
192        catch ( IOException ioe )
193        {
194            // ignore
195        }
196    }
197
198
199    /**
200    * Gets the contents of an <code>InputStream</code> as a String
201    * using the specified character encoding.
202    * <p>
203    * This method buffers the input internally, so there is no need to use a
204    * <code>BufferedInputStream</code>.
205    * </p>
206    * @param input  the <code>InputStream</code> to read from
207    * @param encoding  the encoding to use, null means platform default
208    * @return the requested String
209    * @throws NullPointerException if the input is null
210    * @throws IOException if an I/O error occurs
211    * @since 2.3
212    */
213    public static String toString( InputStream input, Charset encoding ) throws IOException
214    {
215        StringBuilderWriter sw = new StringBuilderWriter();
216        copy( input, sw, encoding );
217
218        return sw.toString();
219    }
220
221
222    /**
223     * Returns the given Charset or the default Charset if the given Charset is null.
224     * 
225     * @param charset A charset or null.
226     * @return the given Charset or the default Charset if the given Charset is null
227     */
228    public static Charset toCharset( Charset charset )
229    {
230        return charset == null ? Charset.defaultCharset() : charset;
231    }
232
233
234    /**
235     * Returns a Charset for the named charset. If the name is null, return the default Charset.
236     * 
237     * @param charset The name of the requested charset, may be null.
238     * @return a Charset for the named charset
239     */
240    public static Charset toCharset( String charset )
241    {
242        return charset == null ? Charset.defaultCharset() : Charset.forName( charset );
243    }
244
245
246    /**
247     * Copies bytes from an <code>InputStream</code> to chars on a
248     * <code>Writer</code> using the specified character encoding.
249     * <p>
250     * This method buffers the input internally, so there is no need to use a
251     * <code>BufferedInputStream</code>.
252     * <p>
253     * This method uses {@link InputStreamReader}.
254     *
255     * @param input  the <code>InputStream</code> to read from
256     * @param output  the <code>Writer</code> to write to
257     * @param inputEncoding  the encoding to use for the input stream, null means platform default
258     * @throws NullPointerException if the input or output is null
259     * @throws IOException if an I/O error occurs
260     * @since 2.3
261     */
262    public static void copy( InputStream input, Writer output, Charset inputEncoding ) throws IOException
263    {
264        InputStreamReader in = new InputStreamReader( input, toCharset( inputEncoding ) );
265        copy( in, output );
266    }
267
268
269    /**
270     * Copies chars from a <code>Reader</code> to a <code>Writer</code>.
271     * <p>
272     * This method buffers the input internally, so there is no need to use a
273     * <code>BufferedReader</code>.
274     * <p>
275     * Large streams (over 2GB) will return a chars copied value of
276     * <code>-1</code> after the copy has completed since the correct
277     * number of chars cannot be returned as an int. For large streams
278     * use the <code>copyLarge(Reader, Writer)</code> method.
279     *
280     * @param input  the <code>Reader</code> to read from
281     * @param output  the <code>Writer</code> to write to
282     * @return the number of characters copied, or -1 if &gt; Integer.MAX_VALUE
283     * @throws NullPointerException if the input or output is null
284     * @throws IOException if an I/O error occurs
285     * @since 1.1
286     */
287    public static int copy( Reader input, Writer output ) throws IOException
288    {
289        long count = copyLarge( input, output );
290
291        if ( count > Integer.MAX_VALUE )
292        {
293            return -1;
294        }
295
296        return ( int ) count;
297    }
298
299    
300    /**
301     * Copies bytes from an <code>InputStream</code> to an
302     * <code>OutputStream</code>.
303     * <p>
304     * This method buffers the input internally, so there is no need to use a
305     * <code>BufferedInputStream</code>.
306     * <p>
307     * Large streams (over 2GB) will return a bytes copied value of
308     * <code>-1</code> after the copy has completed since the correct
309     * number of bytes cannot be returned as an int. For large streams
310     * use the <code>copyLarge(InputStream, OutputStream)</code> method.
311     *
312     * @param input  the <code>InputStream</code> to read from
313     * @param output  the <code>OutputStream</code> to write to
314     * @return the number of bytes copied, or -1 if &gt; Integer.MAX_VALUE
315     * @throws NullPointerException if the input or output is null
316     * @throws IOException if an I/O error occurs
317     * @since 1.1
318     */
319    public static int copy( InputStream input, OutputStream output ) throws IOException 
320    {
321        long count = copyLarge( input, output );
322        
323        if ( count > Integer.MAX_VALUE ) 
324        {
325            return -1;
326        }
327        
328        return ( int ) count;
329    }
330    
331    
332    /**
333     * Copies bytes from an <code>InputStream</code> to an <code>OutputStream</code> using an internal buffer of the
334     * given size.
335     * <p>
336     * This method buffers the input internally, so there is no need to use a <code>BufferedInputStream</code>.
337     * <p>
338     *
339     * @param input
340     *            the <code>InputStream</code> to read from
341     * @param output
342     *            the <code>OutputStream</code> to write to
343     * @param bufferSize
344     *            the bufferSize used to copy from the input to the output
345     * @return the number of bytes copied
346     * @throws NullPointerException
347     *             if the input or output is null
348     * @throws IOException
349     *             if an I/O error occurs
350     * @since 2.5
351     */
352    public static long copy( InputStream input, OutputStream output, int bufferSize ) throws IOException 
353    {
354        return copyLarge( input, output, new byte[bufferSize] );
355    }
356
357
358    /**
359     * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
360     * <p>
361     * This method buffers the input internally, so there is no need to use a
362     * <code>BufferedReader</code>.
363     * <p>
364     * The buffer size is given by #DEFAULT_BUFFER_SIZE.
365     *
366     * @param input  the <code>Reader</code> to read from
367     * @param output  the <code>Writer</code> to write to
368     * @return the number of characters copied
369     * @throws NullPointerException if the input or output is null
370     * @throws IOException if an I/O error occurs
371     * @since 1.3
372     */
373    public static long copyLarge( Reader input, Writer output ) throws IOException
374    {
375        return copyLarge( input, output, new char[DEFAULT_BUFFER_SIZE] );
376    }
377    
378    
379    /**
380     * Copies bytes from a large (over 2GB) <code>InputStream</code> to an
381     * <code>OutputStream</code>.
382     * <p>
383     * This method buffers the input internally, so there is no need to use a
384     * <code>BufferedInputStream</code>.
385     * <p>
386     * The buffer size is given by #DEFAULT_BUFFER_SIZE.
387     *
388     * @param input  the <code>InputStream</code> to read from
389     * @param output  the <code>OutputStream</code> to write to
390     * @return the number of bytes copied
391     * @throws NullPointerException if the input or output is null
392     * @throws IOException if an I/O error occurs
393     * @since 1.3
394     */
395    public static long copyLarge( InputStream input, OutputStream output ) throws IOException 
396    {
397        return copy( input, output, DEFAULT_BUFFER_SIZE );
398    }
399
400    
401    /**
402     * Copies bytes from a large (over 2GB) <code>InputStream</code> to an
403     * <code>OutputStream</code>.
404     * <p>
405     * This method uses the provided buffer, so there is no need to use a
406     * <code>BufferedInputStream</code>.
407     * <p>
408     *
409     * @param input  the <code>InputStream</code> to read from
410     * @param output  the <code>OutputStream</code> to write to
411     * @param buffer the buffer to use for the copy
412     * @return the number of bytes copied
413     * @throws NullPointerException if the input or output is null
414     * @throws IOException if an I/O error occurs
415     * @since 2.2
416     */
417    public static long copyLarge( InputStream input, OutputStream output, byte[] buffer ) throws IOException 
418    {
419        long count = 0;
420        int n;
421        
422        while ( EOF != ( n = input.read( buffer ) ) ) 
423        {
424            output.write( buffer, 0, n );
425            count += n;
426        }
427        
428        return count;
429    }
430
431
432    /**
433     * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
434     * <p>
435     * This method uses the provided buffer, so there is no need to use a
436     * <code>BufferedReader</code>.
437     * <p>
438     *
439     * @param input  the <code>Reader</code> to read from
440     * @param output  the <code>Writer</code> to write to
441     * @param buffer the buffer to be used for the copy
442     * @return the number of characters copied
443     * @throws NullPointerException if the input or output is null
444     * @throws IOException if an I/O error occurs
445     * @since 2.2
446     */
447    public static long copyLarge( Reader input, Writer output, char[] buffer ) throws IOException
448    {
449        long count = 0;
450        int n;
451
452        while ( EOF != ( n = input.read( buffer ) ) )
453        {
454            output.write( buffer, 0, n );
455            count += n;
456        }
457
458        return count;
459    }
460
461
462    /**
463     * Writes chars from a <code>String</code> to bytes on an
464     * <code>OutputStream</code> using the specified character encoding.
465     * <p>
466     * This method uses {@link String#getBytes(String)}.
467     *
468     * @param data  the <code>String</code> to write, null ignored
469     * @param output  the <code>OutputStream</code> to write to
470     * @param encoding  the encoding to use, null means platform default
471     * @throws NullPointerException if output is null
472     * @throws IOException if an I/O error occurs
473     * @since 2.3
474     */
475    public static void write( String data, OutputStream output, Charset encoding ) throws IOException
476    {
477        if ( data != null )
478        {
479            output.write( data.getBytes( toCharset( encoding ) ) );
480        }
481    }
482
483
484    /**
485     * Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>.
486     * Use this method instead of <code>toByteArray(InputStream)</code>
487     * when <code>InputStream</code> size is known
488     * @param input the <code>InputStream</code> to read from
489     * @param size the size of <code>InputStream</code>
490     * @return the requested byte array
491     * @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size
492     * @throws IllegalArgumentException if size is less than zero
493     * @since 2.1
494     */
495    public static byte[] toByteArray( InputStream input, int size ) throws IOException
496    {
497        if ( size < 0 )
498        {
499            throw new IllegalArgumentException( I18n.err( I18n.ERR_17070_SIZE_POSITIVE, size ) );
500        }
501
502        if ( size == 0 )
503        {
504            return new byte[0];
505        }
506
507        byte[] data = new byte[size];
508        int offset = 0;
509        int readed = input.read( data, offset, size - offset );
510
511        while ( offset < size && ( readed != EOF ) )
512        {
513            offset += readed;
514            readed = input.read( data, offset, size - offset );
515        }
516
517        if ( offset != size )
518        {
519            throw new IOException( I18n.err( I18n.ERR_17071_UNEXPECTED_SIZE, offset, size ) );
520        }
521
522        return data;
523    }
524    
525    
526    /**
527     * Gets contents of an <code>InputStream</code> as a <code>byte[]</code>.
528     * Use this method instead of <code>toByteArray(InputStream)</code>
529     * when <code>InputStream</code> size is known.
530     * <b>NOTE:</b> the method checks that the length can safely be cast to an int without truncation
531     * before using {@link IOUtils#toByteArray(java.io.InputStream, int)} to read into the byte array.
532     * (Arrays can have no more than Integer.MAX_VALUE entries anyway)
533     *
534     * @param input the <code>InputStream</code> to read from
535     * @param size the size of <code>InputStream</code>
536     * @return the requested byte array
537     * @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size
538     * @throws IllegalArgumentException if size is less than zero or size is greater than Integer.MAX_VALUE
539     * @see IOUtils#toByteArray(java.io.InputStream, int)
540     * @since 2.1
541     */
542    public static byte[] toByteArray( InputStream input, long size ) throws IOException 
543    {
544
545      if ( size > Integer.MAX_VALUE ) 
546      {
547          throw new IllegalArgumentException( I18n.err( I18n.ERR_17072_INTEGER_OVERFLOW, size ) );
548      }
549
550      return toByteArray( input, ( int ) size );
551    }
552    
553    
554    /**
555     * Gets the contents of an <code>InputStream</code> as a list of Strings,
556     * one entry per line, using the specified character encoding.
557     * <p>
558     * This method buffers the input internally, so there is no need to use a
559     * <code>BufferedInputStream</code>.
560     *
561     * @param input  the <code>InputStream</code> to read from, not null
562     * @param encoding  the encoding to use, null means platform default
563     * @return the list of Strings, never null
564     * @throws NullPointerException if the input is null
565     * @throws IOException if an I/O error occurs
566     * @since 2.3
567     */
568    public static List<String> readLines( InputStream input, Charset encoding ) throws IOException 
569    {
570        InputStreamReader reader = new InputStreamReader( input, toCharset( encoding ) );
571        
572        return readLines( reader );
573    }
574    
575    
576    /**
577     * Gets the contents of a <code>Reader</code> as a list of Strings,
578     * one entry per line.
579     * <p>
580     * This method buffers the input internally, so there is no need to use a
581     * <code>BufferedReader</code>.
582     *
583     * @param input  the <code>Reader</code> to read from, not null
584     * @return the list of Strings, never null
585     * @throws NullPointerException if the input is null
586     * @throws IOException if an I/O error occurs
587     * @since 1.1
588     */
589    public static List<String> readLines( Reader input ) throws IOException 
590    {
591        BufferedReader reader = toBufferedReader( input );
592        List<String> list = new ArrayList<>();
593        String line = reader.readLine();
594        
595        while ( line != null ) 
596        {
597            list.add( line );
598            line = reader.readLine();
599        }
600        
601        return list;
602    }
603
604    
605    /**
606     * Returns the given reader if it is a {@link BufferedReader}, otherwise creates a BufferedReader from the given
607     * reader.
608     *
609     * @param reader
610     *            the reader to wrap or return (not null)
611     * @return the given reader or a new {@link BufferedReader} for the given reader
612     * @since 2.2
613     * @throws NullPointerException if the input parameter is null
614     */
615    public static BufferedReader toBufferedReader( Reader reader ) 
616    {
617        return reader instanceof BufferedReader ? ( BufferedReader ) reader : new BufferedReader( reader );
618    }
619}