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