/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package java.io;
/**
* A data input stream lets an application read primitive Java data types from an underlying input stream in a machine-independent way. An application uses a data output stream to write data that can later be read by a data input stream.
* Since: JDK1.0, CLDC 1.0 See Also:DataOutputStream
*/
public class DataInputStream extends FilterInputStream implements java.io.DataInput{
private final byte[] scratch = new byte[8];
/**
* Creates a DataInputStream and saves its argument, the input stream in, for later use.
* in - the input stream.
*/
public DataInputStream(java.io.InputStream in){
super(in);
}
/**
* See the general contract of the readBoolean method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final boolean readBoolean() throws java.io.IOException{
int temp = in.read();
if (temp < 0) {
throw new EOFException();
}
return temp != 0;
}
/**
* See the general contract of the readByte method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final byte readByte() throws java.io.IOException{
int temp = in.read();
if (temp < 0) {
throw new EOFException();
}
return (byte) temp;
}
/**
* See the general contract of the readChar method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final char readChar() throws java.io.IOException{
return (char) readShort();
}
/**
* See the general contract of the readDouble method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final double readDouble() throws java.io.IOException{
return Double.longBitsToDouble(readLong());
}
/**
* See the general contract of the readFloat method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final float readFloat() throws java.io.IOException{
return Float.intBitsToFloat(readInt());
}
/**
* See the general contract of the readFully method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final void readFully(byte[] b) throws java.io.IOException{
readFully(b, 0, b.length);
}
/**
* See the general contract of the readFully method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final void readFully(byte[] b, int off, int len) throws java.io.IOException{
if (len < 0) {
throw new IndexOutOfBoundsException();
}
int n = 0;
while (n < len) {
int count = read(b, off + n, len - n);
if (count < 0) {
throw new EOFException();
}
n += count;
}
}
/**
* See the general contract of the readInt method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final int readInt() throws java.io.IOException{
readFully(scratch, 0, 4);
return (((scratch[0] & 0xff) << 24) |
((scratch[1] & 0xff) << 16) |
((scratch[2] & 0xff) << 8) |
((scratch[3] & 0xff) << 0));
}
/**
* See the general contract of the readLong method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final long readLong() throws java.io.IOException{
readFully(scratch, 0, 8);
int h = ((scratch[0] & 0xff) << 24) |
((scratch[1] & 0xff) << 16) |
((scratch[2] & 0xff) << 8) |
((scratch[3] & 0xff) << 0);
int l = ((scratch[4] & 0xff) << 24) |
((scratch[5] & 0xff) << 16) |
((scratch[6] & 0xff) << 8) |
((scratch[7] & 0xff) << 0);
return (((long) h) << 32L) | ((long) l) & 0xffffffffL;
}
/**
* See the general contract of the readShort method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final short readShort() throws java.io.IOException{
readFully(scratch, 0, 2);
return (short) ((scratch[0] << 8) | (scratch[1] & 0xff));
}
/**
* See the general contract of the readUnsignedByte method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final int readUnsignedByte() throws java.io.IOException{
int temp = in.read();
if (temp < 0) {
throw new EOFException();
}
return temp;
}
/**
* See the general contract of the readUnsignedShort method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final int readUnsignedShort() throws java.io.IOException{
return ((int) readShort()) & 0xffff;
}
/**
* See the general contract of the readUTF method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final String readUTF() throws IOException {
return decodeUTF(readUnsignedShort());
}
String decodeUTF(int utfSize) throws IOException {
return decodeUTF(utfSize, this);
}
private static String decodeUTF(int utfSize, DataInput in) throws IOException {
byte[] buf = new byte[utfSize];
in.readFully(buf, 0, utfSize);
return decode(buf, new char[utfSize], 0, utfSize);
}
/**
* Decodes a byte array containing <i>modified UTF-8</i> bytes into a string.
*
* <p>Note that although this method decodes the (supposedly impossible) zero byte to U+0000,
* that's what the RI does too.
*/
private static String decode(byte[] in, char[] out, int offset, int utfSize) throws UTFDataFormatException {
int count = 0, s = 0, a;
while (count < utfSize) {
if ((out[s] = (char) in[offset + count++]) < '\u0080') {
s++;
} else if (((a = out[s]) & 0xe0) == 0xc0) {
if (count >= utfSize) {
throw new RuntimeException("bad second byte at " + count);
}
int b = in[offset + count++];
if ((b & 0xC0) != 0x80) {
throw new RuntimeException("bad second byte at " + (count - 1));
}
out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));
} else if ((a & 0xf0) == 0xe0) {
if (count + 1 >= utfSize) {
throw new RuntimeException("bad third byte at " + (count + 1));
}
int b = in[offset + count++];
int c = in[offset + count++];
if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
throw new RuntimeException("bad second or third byte at " + (count - 2));
}
out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
} else {
throw new RuntimeException("bad byte at " + (count - 1));
}
}
return new String(out, 0, s);
}
/**
* Reads from the stream in a representation of a Unicode character string encoded in Java modified UTF-8 format; this string of characters is then returned as a String. The details of the modified UTF-8 representation are exactly the same as for the readUTF method of DataInput.
*/
public static final java.lang.String readUTF(java.io.DataInput in) throws java.io.IOException{
return decodeUTF(in.readUnsignedShort(), in);
}
/**
* See the general contract of the skipBytes method of DataInput.
* Bytes for this operation are read from the contained input stream.
*/
public final int skipBytes(int count) throws java.io.IOException{
int skipped = 0;
long skip;
while (skipped < count && (skip = in.skip(count - skipped)) != 0) {
skipped += skip;
}
return skipped;
}
public final String readLine() throws IOException {
StringBuilder line = new StringBuilder(80); // Typical line length
boolean foundTerminator = false;
while (true) {
int nextByte = in.read();
switch (nextByte) {
case -1:
if (line.length() == 0 && !foundTerminator) {
return null;
}
return line.toString();
case (byte) '\r':
if (foundTerminator) {
((PushbackInputStream) in).unread(nextByte);
return line.toString();
}
foundTerminator = true;
/* Have to be able to peek ahead one byte */
if (!(in.getClass() == PushbackInputStream.class)) {
in = new PushbackInputStream(in);
}
break;
case (byte) '\n':
return line.toString();
default:
if (foundTerminator) {
((PushbackInputStream) in).unread(nextByte);
return line.toString();
}
line.append((char) nextByte);
}
}
}
}