/**
* Copyright (c) 2007-2011, JAGaToo Project Group all rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.jagatoo.util.streams;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import org.jagatoo.util.arrays.ArrayUtils;
/**
* Contains static utility methods for Stream.
*
* @author Marvin Froehlich (aka Qudus)
*/
public class StreamUtils
{
public static final int TRANSFER_BUFFER_SIZE = 1024;
/**
* Skips and discards the given number of bytes from the given stream.
*
* @param in
* @param toSkip
*
* @throws IOException
*/
public static final void skipBytes( InputStream in, long toSkip ) throws IOException
{
while ( toSkip > 0L )
{
long skipped = in.skip( toSkip );
if ( skipped > 0 )
toSkip -= skipped;
else if ( skipped < 0 )
toSkip = 0;
}
}
/**
* Skips and discards the given number of bytes from the given stream.
*
* @param in
* @param toSkip
*
* @throws IOException
*/
public static final void skipBytes( BufferedInputStream in, long toSkip ) throws IOException
{
while ( toSkip > 0L )
{
long skipped = in.skip( toSkip );
if ( skipped > 0 )
toSkip -= skipped;
else if ( skipped < 0 )
toSkip = 0;
}
}
/**
* Reads one byte from the InputStream.
*
* @param in
*
* @return the read byte.
*
* @throws IOException
*/
public static final byte readByte( InputStream in ) throws IOException
{
return ( (byte)in.read() );
}
/**
* Reads one byte from the InputStream.
*
* @param in
*
* @return the read byte.
*
* @throws IOException
*/
public static final byte readByte( BufferedInputStream in ) throws IOException
{
return ( (byte)in.read() );
}
/**
* Reads one unsigned byte from the InputStream stored in a short-value
* to preserve the sign.
*
* @param in
*
* @return the read unsigned byte as a short.
*
* @throws IOException
*/
public static final short readUnsignedByte( InputStream in ) throws IOException
{
int b = in.read();
return ( (short)( b & 0xFF ) );
}
/**
* Reads one unsigned byte from the InputStream stored in a short-value
* to preserve the sign.
*
* @param in
*
* @return the read unsigned byte as a short.
*
* @throws IOException
*/
public static final short readUnsignedByte( BufferedInputStream in ) throws IOException
{
int b = in.read();
return ( (short)( b & 0xFF ) );
}
/**
* Reads two bytes from the InputStream stored in a short-value.
*
* @param in
*
* @return the read short.
*
* @throws IOException
*/
public static final short readShort( InputStream in ) throws IOException
{
int s1 = ( in.read() & 0xFF ) << 8;
int s2 = ( in.read() & 0xFF );
return ( (short)( s1 | s2 ) );
}
/**
* Reads two bytes from the InputStream stored in a short-value.
*
* @param in
*
* @return the read short.
*
* @throws IOException
*/
public static final short readShort( BufferedInputStream in ) throws IOException
{
int s1 = ( in.read() & 0xFF ) << 8;
int s2 = ( in.read() & 0xFF );
return ( (short)( s1 | s2 ) );
}
/**
* Reads two bytes from the InputStream, convertes them to a short
* and stores them to an int to preserve the sign.
*
* @param in
*
* @return the read unsigned short (as an int).
*
* @throws IOException
*/
public static final int readUnsignedShort( InputStream in ) throws IOException
{
int high = in.read();
int low = in.read();
return ( ( ( high & 0xFF ) << 8 ) | ( low & 0xFF ) );
}
/**
* Reads two bytes from the InputStream, convertes them to a short
* and stores them to an int to preserve the sign.
*
* @param in
*
* @return the read unsigned short (as an int).
*
* @throws IOException
*/
public static final int readUnsignedShort( BufferedInputStream in ) throws IOException
{
int high = in.read();
int low = in.read();
return ( ( ( high & 0xFF ) << 8 ) | ( low & 0xFF ) );
}
/**
* Reads two bytes from the InputStream stored in a short-value.
*
* @param in
*
* @return the read short.
*
* @throws IOException
*/
public static final short readSwappedShort( InputStream in ) throws IOException
{
int s2 = ( in.read() & 0xFF );
int s1 = ( in.read() & 0xFF ) << 8;
return ( (short)( s1 | s2 ) );
}
/**
* Reads two bytes from the InputStream stored in a short-value.
*
* @param in
*
* @return the read short.
*
* @throws IOException
*/
public static final short readSwappedShort( BufferedInputStream in ) throws IOException
{
int s2 = ( in.read() & 0xFF );
int s1 = ( in.read() & 0xFF ) << 8;
return ( (short)( s1 | s2 ) );
}
/**
* Reads two bytes from the InputStream, convertes them to a short
* and stores them to an int to preserve the sign.
*
* @param in
*
* @return the read unsigned short (as an int).
*
* @throws IOException
*/
public static final int readSwappedUnsignedShort( InputStream in ) throws IOException
{
int low = in.read();
int high = in.read();
return ( ( ( high & 0xFF ) << 8 ) | ( low & 0xFF ) );
}
/**
* Reads two bytes from the InputStream, convertes them to a short
* and stores them to an int to preserve the sign.
*
* @param in
*
* @return the read unsigned short (as an int).
*
* @throws IOException
*/
public static final int readSwappedUnsignedShort( BufferedInputStream in ) throws IOException
{
int low = in.read();
int high = in.read();
return ( ( ( high & 0xFF ) << 8 ) | ( low & 0xFF ) );
}
/**
* Reads one (signed) int from the stream.
*
* @param in
*
* @return the read int.
*
* @throws IOException
*/
public static final int readInt( InputStream in ) throws IOException
{
int i4 = ( in.read() & 0xFF ) << 24;
int i3 = ( in.read() & 0xFF ) << 16;
int i2 = ( in.read() & 0xFF ) << 8;
int i1 = ( in.read() & 0xFF );
return ( i4 | i3 | i2 | i1 );
}
/**
* Reads one (signed) int from the stream.
*
* @param in
*
* @return the read int.
*
* @throws IOException
*/
public static final int readInt( BufferedInputStream in ) throws IOException
{
int i4 = ( in.read() & 0xFF ) << 24;
int i3 = ( in.read() & 0xFF ) << 16;
int i2 = ( in.read() & 0xFF ) << 8;
int i1 = ( in.read() & 0xFF );
return ( i4 | i3 | i2 | i1 );
}
/**
* Reads one (signed) int from the stream.
*
* @param in
*
* @return the read int.
*
* @throws IOException
*/
public static final int readSwappedInt( InputStream in ) throws IOException
{
int i4 = ( in.read() & 0xFF );
int i3 = ( in.read() & 0xFF ) << 8;
int i2 = ( in.read() & 0xFF ) << 16;
int i1 = ( in.read() & 0xFF ) << 24;
return ( i4 | i3 | i2 | i1 );
}
/**
* Reads one (signed) int from the stream.
*
* @param in
*
* @return the read int.
*
* @throws IOException
*/
public static final int readSwappedInt( BufferedInputStream in ) throws IOException
{
int i1 = ( in.read() & 0xFF );
int i2 = ( in.read() & 0xFF ) << 8;
int i3 = ( in.read() & 0xFF ) << 16;
int i4 = ( in.read() & 0xFF ) << 24;
return ( i4 | i3 | i2 | i1 );
}
/**
* Reads bytesToRead bytes from the stream.
*
* @param in
* @param bytesToRead
* @param buffer
* @param bufferOffset
*
* @throws IOException
*/
public static final void readBytes( InputStream in, int bytesToRead, byte[] buffer, int bufferOffset ) throws IOException
{
int bytesRead = 0;
int read;
do
{
read = in.read( buffer, bufferOffset + bytesRead, bytesToRead );
bytesRead += read;
bytesToRead -= read;
}
while ( ( bytesToRead > 0 ) && ( read > 0 ) );
}
/**
* Reads bytesToRead bytes from the stream.
*
* @param in
* @param bytesToRead
* @param buffer
* @param bufferOffset
*
* @throws IOException
*/
public static final void readBytes( BufferedInputStream in, int bytesToRead, byte[] buffer, int bufferOffset ) throws IOException
{
int bytesRead = 0;
int read;
do
{
read = in.read( buffer, bufferOffset + bytesRead, bytesToRead );
bytesRead += read;
bytesToRead -= read;
}
while ( ( bytesToRead > 0 ) && ( read > 0 ) );
}
/**
* Reads a String from the InputStream.
* The string is expected to be 0-terminated.
*
* @param in
* @param maxLength
* @param alwaysReadMaxLength
*
* @return the read String.
*
* @throws IOException
*/
public static final String readCString( InputStream in, int maxLength, boolean alwaysReadMaxLength ) throws IOException
{
byte[] bytes = new byte[ maxLength ];
if ( alwaysReadMaxLength )
{
int toRead = maxLength;
while ( toRead > 0 )
{
int read = in.read( bytes, maxLength - toRead, toRead );
toRead -= read;
}
int nullIndex = ArrayUtils.indexOf( bytes, (byte)0 );
if ( nullIndex == -1 )
return ( new String( bytes ) );
return ( new String( bytes, 0, nullIndex ) );
}
for ( int i = 0; i < maxLength; i++ )
{
int ib = in.read();
if ( ib == -1 )
return ( null );
byte b = (byte)ib;
if ( b == (byte)0 )
return ( new String( bytes, 0, i ) );
bytes[i] = b;
}
return ( new String( bytes ) );
}
/**
* Builds a byte-array from the given InputStream.<br>
* The byte-array is created with a size of <code>initialSize</code> and is
* enlarged on demand.<br>
* The InputStream is NOT closed at the end.
*
* @param in the InputStream to get data from
* @param initialSize the initial size of the output byte-array
* @return the filled and correctly sized byte-array
*
* @throws IOException
*/
public static final byte[] buildByteArray( InputStream in, int initialSize ) throws IOException
{
int a = in.available();
byte[] buffer = new byte[ Math.min( a, initialSize ) ];
int offset = 0;
int n;
while ( ( n = in.read( buffer, offset, a ) ) > 0 )
{
if ( n <= 0 )
break;
offset += n;
a = in.available();
if ( offset + a > buffer.length )
{
//byte[] newBuffer = new byte[ (buffer.length * 3) / 2 + 1 ];
byte[] newBuffer = new byte[ Math.max( buffer.length << 1, offset + a ) ];
System.arraycopy( buffer, 0, newBuffer, 0, offset );
buffer = newBuffer;
}
}
if ( buffer.length == offset )
return ( buffer );
byte[] copy = new byte[ offset ];
System.arraycopy( buffer, 0, copy, 0, offset );
return ( copy );
}
/**
* This calls {@link #buildByteArray(InputStream, int)} with an initialSize
* of in.available().
*
* @param in the InputStream to get data from
* @return the filled and correctly sized byte-array
*
* @throws IOException
*/
public static final byte[] buildByteArray( InputStream in ) throws IOException
{
return ( buildByteArray( in, in.available() ) );
}
/**
* Closes the passed stream if non <code>null</code> ignoring theoretically irrelevant IOException.
*
* @param s the stream to be closed. If <code>null</code>, this is noop
*
* @return <code>null</code>, if the stream is <code>null</code>, <code>true</code>, if the closing was successful, false otherwise.
*/
public static Boolean closeStream( InputStream s )
{
if ( s == null )
return ( null );
try
{
s.close();
return ( true );
}
catch ( IOException e )
{
// irrelevant! => ignore
return ( false );
}
}
/**
* Closes the passed stream if non <code>null</code> ignoring theoretically irrelevant IOException.
* Make sure, the stream is flushed before.
*
* @param s the stream to be closed. If <code>null</code>, this is noop
*
* @return <code>null</code>, if the stream is <code>null</code>, <code>true</code>, if the closing was successful, false otherwise.
*/
public static Boolean closeStream( OutputStream s )
{
if ( s == null )
return ( null );
try
{
s.close();
return ( true );
}
catch ( IOException e )
{
// irrelevant (if flushed before)! => ignore
return ( false );
}
}
/**
* Flushes the given stream, if it is non <code>null</code> and ignores a rarely possible {@link IOException}.
*
* @param s the strema to flush
*
* @return <code>null</code>, if the stream is <code>null</code>, <code>true</code>, if the closing was successful, false otherwise.
*/
public static Boolean flushStream( OutputStream s )
{
if ( s == null )
return ( null );
try
{
s.flush();
return ( true );
}
catch ( IOException e )
{
// irrelevant (if flushed before)! => ignore
return ( false );
}
}
/**
* Closes the passed reader if non <code>null</code> ignoring theoretically irrelevant IOException.
*
* @param r the reader to be closed. If <code>null</code>, this is noop
*
* @return <code>null</code>, if the reader is <code>null</code>, <code>true</code>, if the closing was successful, false otherwise.
*/
public static Boolean closeReader( Reader r )
{
if ( r == null )
return ( null );
try
{
r.close();
return ( true );
}
catch ( IOException e )
{
// irrelevant! => ignore
return ( false );
}
}
/**
* Closes the passed writer if non <code>null</code> ignoring theoretically irrelevant IOException.
* Make sure, the stream is flushed before.
*
* @param w the writer to be closed. If <code>null</code>, this is noop
*
* @return <code>null</code>, if the writer is <code>null</code>, <code>true</code>, if the closing was successful, false otherwise.
*/
public static Boolean closeWriter( Writer w )
{
if ( w == null )
return ( null );
try
{
w.close();
return ( true );
}
catch ( IOException e )
{
// irrelevant (if flushed before)! => ignore
return ( false );
}
}
/**
* Flushes the given writer, if it is non <code>null</code> and ignores a rarely possible {@link IOException}.
*
* @param w the writer to flush
*
* @return <code>null</code>, if the writer is <code>null</code>, <code>true</code>, if the closing was successful, false otherwise.
*/
public static Boolean flushWriter( Writer w )
{
if ( w == null )
return ( null );
try
{
w.flush();
return ( true );
}
catch ( IOException e )
{
// irrelevant (if flushed before)! => ignore
return ( false );
}
}
/**
* Reads all bytes from the provided {@link InputStream} and writes them to the provided {@link OutputStream}.
*
* @param in
* @param buffer
* @param out
* @param closeIn if <code>true</code> the provided {@link InputStream} is closed after all.
* @param closeOut if <code>true</code> the provided {@link OutputStream} is closed after all.
*
* @return the number of bytes transfered.
*
* @throws IOException
*/
public static long transferBytes( InputStream in, byte[] buffer, OutputStream out, boolean closeIn, boolean closeOut ) throws IOException
{
if ( in == null )
throw new IllegalArgumentException( "in must not be null." );
if ( out == null )
throw new IllegalArgumentException( "out must not be null." );
try
{
long nn = 0L;
int n;
while ( ( n = in.read( buffer, 0, Math.min( buffer.length, in.available() + 1 ) ) ) >= 0 )
{
if ( n > 0 )
{
nn += n;
out.write( buffer, 0, n );
}
}
return ( nn );
}
finally
{
if ( closeIn )
closeStream( in );
if ( closeOut )
closeStream( out );
}
}
/**
* Reads all bytes from the provided {@link InputStream} and writes them to the provided {@link OutputStream}.
*
* @param in
* @param out
* @param closeIn if <code>true</code> the provided {@link InputStream} is closed after all.
* @param closeOut if <code>true</code> the provided {@link OutputStream} is closed after all.
*
* @return the number of bytes transfered.
*
* @throws IOException
*/
public static long transferBytes( InputStream in, OutputStream out, boolean closeIn, boolean closeOut ) throws IOException
{
if ( in == null )
throw new IllegalArgumentException( "in must not be null." );
if ( out == null )
throw new IllegalArgumentException( "out must not be null." );
return ( transferBytes( in, new byte[ TRANSFER_BUFFER_SIZE ], out, closeIn, closeOut ) );
}
/**
* Reads all bytes from the provided {@link InputStream} and writes them to the provided {@link OutputStream}.
* The provided streams are closed after all.
*
* @param in
* @param out
*
* @return the number of bytes transfered.
*
* @throws IOException
*/
public static long transferBytes( InputStream in, OutputStream out ) throws IOException
{
return ( transferBytes( in, out, true, true ) );
}
/**
* Copies all bytes from the given {@link InputStream} into a new byte array.
*
* @param in
* @param closeIn if <code>true</code> the provided {@link InputStream} is closed after all.
*
* @return a byte array containing all the bytes from the given {@link InputStream}.
*
* @throws IOException
*/
public static byte[] getBytesFromStream( InputStream in, boolean closeIn ) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream( in.available() );
transferBytes( in, baos, closeIn, true );
return ( baos.toByteArray() );
}
/**
* Copies all bytes from the given {@link InputStream} into a new byte array.
* The provided stream is closed after all.
*
* @param in
*
* @return a byte array containing all the bytes from the given {@link InputStream}.
*
* @throws IOException
*/
public static byte[] getBytesFromStream( InputStream in ) throws IOException
{
return ( getBytesFromStream( in, true ) );
}
/**
* Copies all bytes from the given {@link InputStream} into a new String.
*
* @param in
* @param closeIn if <code>true</code> the provided {@link InputStream} is closed after all.
*
* @return a String containing all the bytes from the given {@link InputStream}.
*
* @throws IOException
*/
public static String getStringFromStream( InputStream in, boolean closeIn ) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream( in.available() );
transferBytes( in, baos, closeIn, true );
return ( baos.toString() );
}
/**
* Copies all bytes from the given {@link InputStream} into a new String.
* The provided stream is closed after all.
*
* @param in
*
* @return a String containing all the bytes from the given {@link InputStream}.
*
* @throws IOException
*/
public static String getStringFromStream( InputStream in ) throws IOException
{
return ( getStringFromStream( in, true ) );
}
private StreamUtils()
{
}
}