/* * Copyright (c) 2016, Metron, Inc. * 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 Metron, Inc. 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 METRON, INC. 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) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.metsci.glimpse.util.io.datapipe; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; /** * An implementation of {@link ReadableDataPipe} that uses nio. * * @author hogye */ public class ReadableDataChannel extends AbstractChannel implements ReadableDataPipe { private final DataInputStream _stream; private long _totalBytesRead; protected final ReadableByteChannel _channel; public ReadableDataChannel( ReadableByteChannel channel ) throws IOException { super( channel ); _channel = channel; _stream = new DataInputStream( new BufferedInputStream( Channels.newInputStream( channel ) ) ); _byteBuffer.flip( ); } /** * @return the total number of bytes read since this channel was created. */ public long getTotalBytesRead( ) { return _totalBytesRead; } /** * Postcondition: byte buffer's position is 0. * * @return the number of bytes read from the channel. * @throws EOFException if end of stream is reached. */ protected int fillBuffer( ) throws IOException { _byteBuffer.compact( ); if ( !_byteBuffer.hasRemaining( ) ) return 0; int nBytesRead = _channel.read( _byteBuffer ); if ( nBytesRead == -1 ) throw new EOFException( ); _totalBytesRead += nBytesRead; _byteBuffer.flip( ); return nBytesRead; } public boolean readBoolean( ) throws IOException { return readByte( ) != 0; } public byte readByte( ) throws IOException { while ( _byteBuffer.remaining( ) < 1 ) fillBuffer( ); return _byteBuffer.get( ); } public short readShort( ) throws IOException { while ( _byteBuffer.remaining( ) < 2 ) fillBuffer( ); return _byteBuffer.getShort( ); } public int readInt( ) throws IOException { while ( _byteBuffer.remaining( ) < 4 ) fillBuffer( ); return _byteBuffer.getInt( ); } public long readLong( ) throws IOException { while ( _byteBuffer.remaining( ) < 8 ) fillBuffer( ); return _byteBuffer.getLong( ); } public float readFloat( ) throws IOException { while ( _byteBuffer.remaining( ) < 4 ) fillBuffer( ); return _byteBuffer.getFloat( ); } public double readDouble( ) throws IOException { while ( _byteBuffer.remaining( ) < 8 ) fillBuffer( ); return _byteBuffer.getDouble( ); } public boolean[] readBooleanArray( boolean[] values ) throws IOException { byte[] values2 = new byte[values.length]; readByteArray( values2 ); for ( int i = 0, ni = values.length; i < ni; i++ ) { values[i] = ( values2[i] != 0 ); } return values; } public byte[] readByteArray( byte[] values ) throws IOException { for ( int i = 0, ni = values.length; i < ni; ) { if ( !_byteBuffer.hasRemaining( ) ) fillBuffer( ); int length = Math.min( ni - i, _byteBuffer.remaining( ) ); _byteBuffer.get( values, i, length ); i += length; } return values; } public short[] readShortArray( short[] values ) throws IOException { readArray( values, values.length, _shortBuffer ); return values; } public int[] readIntArray( int[] values ) throws IOException { readArray( values, values.length, _intBuffer ); return values; } public long[] readLongArray( long[] values ) throws IOException { readArray( values, values.length, _longBuffer ); return values; } public float[] readFloatArray( float[] values ) throws IOException { readArray( values, values.length, _floatBuffer ); return values; } public double[] readDoubleArray( double[] values ) throws IOException { readArray( values, values.length, _doubleBuffer ); return values; } public void readArray( Object array, int arrayLength, BufferWrapper buffer ) throws IOException { int shift = buffer.getShift( ); int mask = ( 1 << shift ) - 1; if ( ( _byteBuffer.position( ) & mask ) != 0 ) { _byteBuffer.compact( ).flip( ); } buffer.positionAndLimit( _byteBuffer.position( ) >> shift, _byteBuffer.limit( ) >> shift ); for ( int i = 0; i < arrayLength; ) { if ( !buffer.hasRemaining( ) ) { _byteBuffer.position( buffer.position( ) << shift ); fillBuffer( ); buffer.positionAndLimit( 0, _byteBuffer.limit( ) >> shift ); } int length = Math.min( arrayLength - i, buffer.remaining( ) ); buffer.get( array, i, length ); i += length; } _byteBuffer.position( buffer.position( ) << shift ); } public String readString( ) throws IOException { byte[] bytes = new byte[readInt( )]; readByteArray( bytes ); return new String( bytes, STRING_ENCODING ); } public DataInputStream getInputStream( ) { return _stream; } }