/*
* Copyright (c) 2006-2007 Graz University of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The names "Graz University of Technology" and "IAIK of Graz University of
* Technology" must not be used to endorse or promote products derived from
* this software without prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED 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 LICENSOR 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 ejip.jtcpip;
import java.io.InputStream;
import util.Dbg;
/**
* TCPInputStream
*
* @author Ulrich Feichter
* @author Tobias Kellner
* @author Christof Rath
* @version $Rev: 989 $ $Date: 2007/01/24 19:37:07 $
*/
public class TCPInputStream extends InputStream
{
/**
* Size of the circular buffer in 4 bytes
*/
private int BUFSIZE;
/**
* The circular buffer
*/
private byte[] buffer;
/**
* Points at the next element to be written
*/
private int writePtr;
/**
* Points at the next element to be read
*/
private int readPtr;
/**
* Whether the buffer is full (if {@link #readPtr} == {@link #writePtr})
*/
private boolean isBufferFull;
/**
* Whether the stream is closed
*/
private boolean closed;
/**
* Constructor which takes the size of the circular buffer in bytes
*
* @param size
* size of the circular buffer
*/
protected TCPInputStream(int size)
{
closed = false;
BUFSIZE = size;
writePtr = 0;
readPtr = 0;
isBufferFull = false;
buffer = new byte[BUFSIZE];
}
/**
* Returns the number of free bytes in the buffer
*
* @return int containing the number of free bytes in the buffer
*/
protected int getFreeBufferSpace()
{
if (isBufferFull)
return 0;
else if (writePtr == readPtr)
return BUFSIZE;
else if (writePtr > readPtr)
return BUFSIZE - (writePtr - readPtr);
else
return readPtr - writePtr;
}
/**
* Writes the 8 least significant bits of b into the stream. Returns 0 if
* all was ok, -1 if the buffer is full and -2 if the stream is closed.
* IMPORTANT: If some bytes are written they chould not be read out before
* wakeUpRead() was invoked!
*
* @param b
* Byte to be written. (is passed as integer from which the 24
* most significant bits are discarded)
*
* @return 0 if all was ok, -1 if the buffer is full and -2 if the stream is
* closed
*
*/
synchronized protected int write(int b)
{
//System.out.println(b);
if (closed)
return -2;
if (isBufferFull)
return -1;
buffer[writePtr] = (byte) (b & 0xFF);
writePtr = ++writePtr % BUFSIZE;
if (writePtr == readPtr)
isBufferFull = true;
return 0;
}
/**
* Reads a byte from the buffer. If the stream is closed, -1 is returned
* instead.
*
* @return The read byte in the LSByte of the int, or -1 if closed
*/
synchronized public int read()
{
if (isBufferEmpty() || (closed == true))
return -1;
// while (isBufferEmpty()) {
// //wait(); // block
// return -1;
// }
byte out = buffer[readPtr];
readPtr = ++readPtr % BUFSIZE;
isBufferFull = false;
return out & 0xFF;
}
/**
* Checks if the buffer of the stream is empty
*
* @return true if empty, else false
*/
protected boolean isBufferEmpty()
{
return (writePtr == readPtr && !isBufferFull);
}
/**
* Checks if the stream's buffer is full
*
* @return true if full, else false
*/
protected boolean isBufferFull()
{
return isBufferFull;
}
/**
* Closes the stream.
* After closing all data can be read out from the stream, after a that
* -1 will be returned.
*/
synchronized public void close()
{
closed = true;
//notifyAll();
}
/**
* Re-opens the stream.
* ATTENTION: if a user keeps the handle after reopening the stream
* is re activated
*/
synchronized protected void reOpen()
{
if (!closed)
return;
closed = false;
writePtr = 0;
readPtr = 0;
isBufferFull = false;
}
/**
* Clones the instance.
*
* @return the cloned stream
*/
synchronized protected TCPInputStream cloneInstance()
{
TCPInputStream clone = new TCPInputStream(BUFSIZE);
for (int i = 0; i < buffer.length; i++)
clone.buffer[i] = buffer[i];
clone.writePtr = writePtr;
clone.readPtr = readPtr;
clone.isBufferFull = isBufferFull;
clone.closed = closed;
return clone;
}
/**
* wakes <code>read()</code> method up if it is sleeping
*
*/
synchronized protected void wakeUpRead()
{
//Dbg.wr("wake up\n");
//notifyAll();
}
}