FilteredInputStream
implements the
* DataInput
interface that provides method for reading primitive
* Java data types from a stream.
*
* @see DataInput
*
* @author Warren Levy DataInputStream
* to read from the specified subordinate stream.
*
* @param in The subordinate InputStream
to read from
*/
public DataInputStream (InputStream in)
{
super (in);
}
/**
* This method reads bytes from the underlying stream into the specified
* byte array buffer. It will attempt to fill the buffer completely, but
* may return a short count if there is insufficient data remaining to be
* read to fill the buffer.
*
* @param b The buffer into which bytes will be read.
*
* @return The actual number of bytes read, or -1 if end of stream reached
* before reading any bytes.
*
* @exception IOException If an error occurs.
*/
public final int read (byte[] b) throws IOException
{
return in.read (b, 0, b.length);
}
/**
* This method reads bytes from the underlying stream into the specified
* byte array buffer. It will attempt to read len
bytes and
* will start storing them at position off
into the buffer.
* This method can return a short count if there is insufficient data
* remaining to be read to complete the desired read length.
*
* @param b The buffer into which bytes will be read.
* @param off The offset into the buffer to start storing bytes.
* @param len The requested number of bytes to read.
*
* @return The actual number of bytes read, or -1 if end of stream reached
* before reading any bytes.
*
* @exception IOException If an error occurs.
*/
public final int read (byte[] b, int off, int len) throws IOException
{
return in.read (b, off, len);
}
/**
* This method reads a Java boolean value from an input stream. It does
* so by reading a single byte of data. If that byte is zero, then the
* value returned is false
. If the byte is non-zero, then
* the value returned is true
.
*
* This method can read a boolean
written by an object
* implementing the writeBoolean()
method in the
* DataOutput
interface.
*
* @return The boolean
value read
*
* @exception EOFException If end of file is reached before reading
* the boolean
* @exception IOException If any other error occurs
*
* @see DataOutput#writeBoolean
*/
public final boolean readBoolean () throws IOException
{
return convertToBoolean (in.read ());
}
/**
* This method reads a Java byte value from an input stream. The value
* is in the range of -128 to 127.
*
* This method can read a byte
written by an object
* implementing the writeByte()
method in the
* DataOutput
interface.
*
* @return The byte
value read
*
* @exception EOFException If end of file is reached before reading the byte
* @exception IOException If any other error occurs
*
* @see DataOutput#writeByte
*/
public final byte readByte () throws IOException
{
return convertToByte (in.read ());
}
/**
* This method reads a Java char
value from an input stream.
* It operates by reading two bytes from the stream and converting them to
* a single 16-bit Java char
. The two bytes are stored most
* significant byte first (i.e., "big endian") regardless of the native
* host byte ordering.
*
* As an example, if byte1
and byte2
* represent the first and second byte read from the stream
* respectively, they will be transformed to a char
in
* the following manner:
*
* (char)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF)
*
* This method can read a char
written by an object
* implementing the writeChar()
method in the
* DataOutput
interface.
*
* @return The char
value read
*
* @exception EOFException If end of file is reached before reading the char
* @exception IOException If any other error occurs
*
* @see DataOutput#writeChar
*/
public final char readChar () throws IOException
{
readFully (buf, 0, 2);
return convertToChar (buf);
}
/**
* This method reads a Java double value from an input stream. It operates
* by first reading a long
value from the stream by calling the
* readLong()
method in this interface, then converts
* that long
to a double
using the
* longBitsToDouble
method in the class
* java.lang.Double
*
* This method can read a double
written by an object
* implementing the writeDouble()
method in the
* DataOutput
interface.
*
* @return The double
value read
*
* @exception EOFException If end of file is reached before reading
* the double
* @exception IOException If any other error occurs
*
* @see DataOutput#writeDouble
* @see java.lang.Double#longBitsToDouble
*/
public final double readDouble () throws IOException
{
return Double.longBitsToDouble (readLong ());
}
/**
* This method reads a Java float value from an input stream. It
* operates by first reading an int
value from the
* stream by calling the readInt()
method in this
* interface, then converts that int
to a
* float
using the intBitsToFloat
method
* in the class java.lang.Float
*
* This method can read a float
written by an object
* implementing the writeFloat()
method in the
* DataOutput
interface.
*
* @return The float
value read
*
* @exception EOFException If end of file is reached before reading the float
* @exception IOException If any other error occurs
*
* @see DataOutput#writeFloat
* @see java.lang.Float#intBitsToFloat
*/
public final float readFloat () throws IOException
{
return Float.intBitsToFloat (readInt ());
}
/**
* This method reads raw bytes into the passed array until the array is
* full. Note that this method blocks until the data is available and
* throws an exception if there is not enough data left in the stream to
* fill the buffer. Note also that zero length buffers are permitted.
* In this case, the method will return immediately without reading any
* bytes from the stream.
*
* @param b The buffer into which to read the data
*
* @exception EOFException If end of file is reached before filling the
* buffer
* @exception IOException If any other error occurs
*/
public final void readFully (byte[] b) throws IOException
{
readFully (b, 0, b.length);
}
/**
* This method reads raw bytes into the passed array buf
* starting
* offset
bytes into the buffer. The number of bytes read
* will be
* exactly len
. Note that this method blocks until the data is
* available and throws an exception if there is not enough data left in
* the stream to read len
bytes. Note also that zero length
* buffers are permitted. In this case, the method will return immediately
* without reading any bytes from the stream.
*
* @param buf The buffer into which to read the data
* @param offset The offset into the buffer to start storing data
* @param len The number of bytes to read into the buffer
*
* @exception EOFException If end of file is reached before filling the
* buffer
* @exception IOException If any other error occurs
*/
public final void readFully (byte[] buf, int offset, int len) throws IOException
{
if (len < 0)
throw new IndexOutOfBoundsException("Negative length: " + len);
while (len > 0)
{
// in.read will block until some data is available.
int numread = in.read (buf, offset, len);
if (numread < 0)
throw new EOFException ();
len -= numread;
offset += numread;
}
}
/**
* This method reads a Java int
value from an input stream
* It operates by reading four bytes from the stream and converting them to
* a single Java int
. The bytes are stored most
* significant byte first (i.e., "big endian") regardless of the native
* host byte ordering.
*
* As an example, if byte1
through byte4
represent
* the first four bytes read from the stream, they will be
* transformed to an int
in the following manner:
*
* (int)(((byte1 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) +
* ((byte3 & 0xFF)<< 8) + (byte4 & 0xFF)))
*
* The value returned is in the range of -2147483648 to 2147483647. *
* This method can read an int
written by an object
* implementing the writeInt()
method in the
* DataOutput
interface.
*
* @return The int
value read
*
* @exception EOFException If end of file is reached before reading the int
* @exception IOException If any other error occurs
*
* @see DataOutput#writeInt
*/
public final int readInt () throws IOException
{
readFully (buf, 0, 4);
return convertToInt (buf);
}
/**
* This method reads the next line of text data from an input
* stream. It operates by reading bytes and converting those bytes
* to char
values by treating the byte read as the low
* eight bits of the char
and using 0 as the high eight
* bits. Because of this, it does not support the full 16-bit
* Unicode character set.
*
* The reading of bytes ends when either the end of file or a line
* terminator is encountered. The bytes read are then returned as a
* String
A line terminator is a byte sequence
* consisting of either \r
, \n
or
* \r\n
. These termination charaters are discarded and
* are not returned as part of the string.
*
* This method can read data that was written by an object implementing the
* writeLine()
method in DataOutput
.
*
* @return The line read as a String
*
* @exception IOException If an error occurs
*
* @see DataOutput
*
* @deprecated
*/
public final String readLine () throws IOException
{
StringBuffer strb = new StringBuffer ();
readloop: while (true)
{
int c = 0;
char ch = ' ';
boolean getnext = true;
while (getnext)
{
getnext = false;
c = in.read();
if (c < 0) // got an EOF
return strb.length () > 0 ? strb.toString () : null;
ch = (char) c;
if ((ch &= 0xFF) == '\n')
// hack to correctly handle '\r\n' sequences
if (ignoreInitialNewline)
{
ignoreInitialNewline = false;
getnext = true;
}
else
break readloop;
}
if (ch == '\r')
{
// FIXME: The following code tries to adjust the stream back one
// character if the next char read is '\n'. As a last resort,
// it tries to mark the position before reading but the bottom
// line is that it is possible that this method will not properly
// deal with a '\r' '\n' combination thus not fulfilling the
// DataInput contract for readLine. It's not a particularly
// safe approach threadwise since it is unsynchronized and
// since it might mark an input stream behind the users back.
// Along the same vein it could try the same thing for
// ByteArrayInputStream and PushbackInputStream, but that is
// probably overkill since this is deprecated & BufferedInputStream
// is the most likely type of input stream.
//
// The alternative is to somehow push back the next byte if it
// isn't a '\n' or to have the reading methods of this class
// keep track of whether the last byte read was '\r' by readLine
// and then skip the very next byte if it is '\n'. Either way,
// this would increase the complexity of the non-deprecated methods
// and since it is undesirable to make non-deprecated methods
// less efficient, the following seems like the most reasonable
// approach.
int next_c = 0;
char next_ch = ' ';
if (in instanceof BufferedInputStream)
{
next_c = in.read();
next_ch = (char) (next_c & 0xFF);
if ((next_ch != '\n') && (next_c >= 0))
{
BufferedInputStream bin = (BufferedInputStream) in;
if (bin.pos > 0)
bin.pos--;
}
}
else if (markSupported())
{
next_c = in.read();
next_ch = (char) (next_c & 0xFF);
if ((next_ch != '\n') && (next_c >= 0))
{
mark(1);
if ((in.read() & 0xFF) != '\n')
reset();
}
}
// In order to catch cases where 'in' isn't a BufferedInputStream
// and doesn't support mark() (such as reading from a Socket), set
// a flag that instructs readLine() to ignore the first character
// it sees _if_ that character is a '\n'.
else ignoreInitialNewline = true;
break;
}
strb.append(ch);
}
return strb.length() > 0 ? strb.toString() : "";
}
/**
* This method reads a Java long
value from an input stream
* It operates by reading eight bytes from the stream and converting them to
* a single Java long
. The bytes are stored most
* significant byte first (i.e., "big endian") regardless of the native
* host byte ordering.
*
* As an example, if byte1
through byte8
represent
* the first eight bytes read from the stream, they will be
* transformed to an long
in the following manner:
*
* (long)(((byte1 & 0xFF) << 56) + ((byte2 & 0xFF) << 48) +
* ((byte3 & 0xFF) << 40) + ((byte4 & 0xFF) << 32) +
* ((byte5 & 0xFF) << 24) + ((byte6 & 0xFF) << 16) +
* ((byte7 & 0xFF) << 8) + (byte8 & 0xFF)))
*
*
* The value returned is in the range of -9223372036854775808 to * 9223372036854775807. *
* This method can read an long
written by an object
* implementing the writeLong()
method in the
* DataOutput
interface.
*
* @return The long
value read
*
* @exception EOFException If end of file is reached before reading the long
* @exception IOException If any other error occurs
*
* @see DataOutput#writeLong
*/
public final long readLong () throws IOException
{
readFully (buf, 0, 8);
return convertToLong (buf);
}
/**
* This method reads a signed 16-bit value into a Java in from the
* stream. It operates by reading two bytes from the stream and
* converting them to a single 16-bit Java short
. The
* two bytes are stored most significant byte first (i.e., "big
* endian") regardless of the native host byte ordering.
*
* As an example, if byte1
and byte2
* represent the first and second byte read from the stream
* respectively, they will be transformed to a short
. in
* the following manner:
*
* (short)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF))
*
* The value returned is in the range of -32768 to 32767. *
* This method can read a short
written by an object
* implementing the writeShort()
method in the
* DataOutput
interface.
*
* @return The short
value read
*
* @exception EOFException If end of file is reached before reading the value
* @exception IOException If any other error occurs
*
* @see DataOutput#writeShort
*/
public final short readShort () throws IOException
{
readFully (buf, 0, 2);
return convertToShort (buf);
}
/**
* This method reads 8 unsigned bits into a Java int
* value from the stream. The value returned is in the range of 0 to
* 255.
*
* This method can read an unsigned byte written by an object
* implementing the writeUnsignedByte()
method in the
* DataOutput
interface.
*
* @return The unsigned bytes value read as a Java int
.
*
* @exception EOFException If end of file is reached before reading the value
* @exception IOException If any other error occurs
*
* @see DataOutput#writeByte
*/
public final int readUnsignedByte () throws IOException
{
return convertToUnsignedByte (in.read ());
}
/**
* This method reads 16 unsigned bits into a Java int value from the stream.
* It operates by reading two bytes from the stream and converting them to
* a single Java int
The two bytes are stored most
* significant byte first (i.e., "big endian") regardless of the native
* host byte ordering.
*
* As an example, if byte1
and byte2
* represent the first and second byte read from the stream
* respectively, they will be transformed to an int
in
* the following manner:
*
* (int)(((byte1 & 0xFF) << 8) + (byte2 & 0xFF))
*
* The value returned is in the range of 0 to 65535. *
* This method can read an unsigned short written by an object
* implementing the writeUnsignedShort()
method in the
* DataOutput
interface.
*
* @return The unsigned short value read as a Java int
*
* @exception EOFException If end of file is reached before reading the value
* @exception IOException If any other error occurs
*
* @see DataOutput#writeShort
*/
public final int readUnsignedShort () throws IOException
{
readFully (buf, 0, 2);
return convertToUnsignedShort (buf);
}
/**
* This method reads a String
from an input stream that
* is encoded in a modified UTF-8 format. This format has a leading
* two byte sequence that contains the remaining number of bytes to
* read. This two byte sequence is read using the
* readUnsignedShort()
method of this interface.
*
* After the number of remaining bytes have been determined, these
* bytes are read an transformed into char
values.
* These char
values are encoded in the stream using
* either a one, two, or three byte format. The particular format
* in use can be determined by examining the first byte read.
*
* If the first byte has a high order bit of 0, then that character
* consists on only one byte. This character value consists of
* seven bits that are at positions 0 through 6 of the byte. As an
* example, if byte1
is the byte read from the stream,
* it would be converted to a char
like so:
*
* (char)byte1
*
* If the first byte has 110 as its high order bits, then the * character consists of two bytes. The bits that make up the character * value are in positions 0 through 4 of the first byte and bit positions * 0 through 5 of the second byte. (The second byte should have * 10 as its high order bits). These values are in most significant * byte first (i.e., "big endian") order. *
* As an example, if byte1
and byte2
are
* the first two bytes read respectively, and the high order bits of
* them match the patterns which indicate a two byte character
* encoding, then they would be converted to a Java
* char
like so:
*
* (char)(((byte1 & 0x1F) << 6) | (byte2 & 0x3F))
*
* If the first byte has a 1110 as its high order bits, then the * character consists of three bytes. The bits that make up the character * value are in positions 0 through 3 of the first byte and bit positions * 0 through 5 of the other two bytes. (The second and third bytes should * have 10 as their high order bits). These values are in most * significant byte first (i.e., "big endian") order. *
* As an example, if byte1
byte2
and
* byte3
are the three bytes read, and the high order
* bits of them match the patterns which indicate a three byte
* character encoding, then they would be converted to a Java
* char
like so:
*
* (char)(((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) |
* (byte3 & 0x3F))
*
* Note that all characters are encoded in the method that requires
* the fewest number of bytes with the exception of the character
* with the value of \u0000
which is encoded as two
* bytes. This is a modification of the UTF standard used to
* prevent C language style NUL
values from appearing
* in the byte stream.
*
* This method can read data that was written by an object implementing the
* writeUTF()
method in DataOutput
*
* @return The String
read
*
* @exception EOFException If end of file is reached before reading
* the String
* @exception UTFDataFormatException If the data is not in UTF-8 format
* @exception IOException If any other error occurs
*
* @see DataOutput#writeUTF
*/
public final String readUTF () throws IOException
{
return readUTF (this);
}
/**
* This method reads a String encoded in UTF-8 format from the
* specified DataInput
source.
*
* @param in The DataInput
source to read from
*
* @return The String read from the source
*
* @exception IOException If an error occurs
*
* @see DataInput#readUTF
*/
public static final String readUTF(DataInput in) throws IOException
{
final int UTFlen = in.readUnsignedShort ();
byte[] buf = new byte [UTFlen];
// This blocks until the entire string is available rather than
// doing partial processing on the bytes that are available and then
// blocking. An advantage of the latter is that Exceptions
// could be thrown earlier. The former is a bit cleaner.
in.readFully (buf, 0, UTFlen);
return convertFromUTF (buf);
}
/**
* This method attempts to skip and discard the specified number of bytes
* in the input stream. It may actually skip fewer bytes than requested.
* This method will not skip any bytes if passed a negative number of bytes
* to skip.
*
* @param n The requested number of bytes to skip.
*
* @return The requested number of bytes to skip.
*
* @exception IOException If an error occurs.
* @specnote The JDK docs claim that this returns the number of bytes
* actually skipped. The JCL claims that this method can throw an
* EOFException. Neither of these appear to be true in the JDK 1.3's
* implementation. This tries to implement the actual JDK behaviour.
*/
public final int skipBytes (int n) throws IOException
{
if (n <= 0)
return 0;
try
{
return (int) in.skip (n);
}
catch (EOFException x)
{
// do nothing.
}
return n;
}
static boolean convertToBoolean (int b) throws EOFException
{
if (b < 0)
throw new EOFException ();
return (b != 0);
}
static byte convertToByte (int i) throws EOFException
{
if (i < 0)
throw new EOFException ();
return (byte) i;
}
static int convertToUnsignedByte (int i) throws EOFException
{
if (i < 0)
throw new EOFException ();
return (i & 0xFF);
}
static char convertToChar (byte[] buf)
{
return (char) ((buf [0] << 8)
| (buf [1] & 0xff));
}
static short convertToShort (byte[] buf)
{
return (short) ((buf [0] << 8)
| (buf [1] & 0xff));
}
static int convertToUnsignedShort (byte[] buf)
{
return (((buf [0] & 0xff) << 8)
| (buf [1] & 0xff));
}
static int convertToInt (byte[] buf)
{
return (((buf [0] & 0xff) << 24)
| ((buf [1] & 0xff) << 16)
| ((buf [2] & 0xff) << 8)
| (buf [3] & 0xff));
}
static long convertToLong (byte[] buf)
{
return (((long)(buf [0] & 0xff) << 56) |
((long)(buf [1] & 0xff) << 48) |
((long)(buf [2] & 0xff) << 40) |
((long)(buf [3] & 0xff) << 32) |
((long)(buf [4] & 0xff) << 24) |
((long)(buf [5] & 0xff) << 16) |
((long)(buf [6] & 0xff) << 8) |
((long)(buf [7] & 0xff)));
}
// FIXME: This method should be re-thought. I suspect we have multiple
// UTF-8 decoders floating around. We should use the standard charset
// converters, maybe and adding a direct call into one of the new
// NIO converters for a super-fast UTF8 decode.
static String convertFromUTF (byte[] buf)
throws EOFException, UTFDataFormatException
{
// Give StringBuffer an initial estimated size to avoid
// enlarge buffer frequently
StringBuffer strbuf = new StringBuffer (buf.length / 2 + 2);
for (int i = 0; i < buf.length; )
{
if ((buf [i] & 0x80) == 0) // bit pattern 0xxxxxxx
strbuf.append ((char) (buf [i++] & 0xFF));
else if ((buf [i] & 0xE0) == 0xC0) // bit pattern 110xxxxx
{
if (i + 1 >= buf.length
|| (buf [i + 1] & 0xC0) != 0x80)
throw new UTFDataFormatException ();
strbuf.append((char) (((buf [i++] & 0x1F) << 6)
| (buf [i++] & 0x3F)));
}
else if ((buf [i] & 0xF0) == 0xE0) // bit pattern 1110xxxx
{
if (i + 2 >= buf.length
|| (buf [i + 1] & 0xC0) != 0x80
|| (buf [i + 2] & 0xC0) != 0x80)
throw new UTFDataFormatException ();
strbuf.append ((char) (((buf [i++] & 0x0F) << 12)
| ((buf [i++] & 0x3F) << 6)
| (buf [i++] & 0x3F)));
}
else // must be ((buf [i] & 0xF0) == 0xF0 || (buf [i] & 0xC0) == 0x80)
throw new UTFDataFormatException (); // bit patterns 1111xxxx or
// 10xxxxxx
}
return strbuf.toString ();
}
}