aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/io/DataInputStream.java
blob: d03f8f4da3e17f7856a6de491a070cdea269e9f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/* Copyright (C) 1998, 1999  Cygnus Solutions

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */
 
package java.io;

/**
 * @author Warren Levy <warrenl@cygnus.com>
 * @date October 20, 1998.  
 */

/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
 * "The Java Language Specification", ISBN 0-201-63451-1
 * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
 * Status:  Believed complete and correct.
 */
 
public class DataInputStream extends FilterInputStream implements DataInput
{
  public DataInputStream(InputStream in)
  {
    super(in);
  }

  public final int read(byte[] b) throws IOException
  {
    return super.read(b, 0, b.length);
  }

  public final int read(byte[] b, int off, int len) throws IOException
  {
    if (off < 0 || len < 0 || off + len > b.length)
      throw new ArrayIndexOutOfBoundsException();

    return super.read(b, off, len);
  }

  public final boolean readBoolean() throws IOException
  {
    return (readByte() != 0);
  }

  public final byte readByte() throws IOException
  {
    int i = read();
    if (i < 0)
      throw new EOFException();

    return (byte) i;
  }

  public final char readChar() throws IOException
  {
    return (char) ((readByte() << 8) | readUnsignedByte());
  }

  public final double readDouble() throws IOException
  {
    return Double.longBitsToDouble(readLong());
  }

  public final float readFloat() throws IOException
  {
    return Float.intBitsToFloat(readInt());
  }

  public final void readFully(byte[] b) throws IOException
  {
    readFully(b, 0, b.length);
  }

  public final void readFully(byte[] b, int off, int len) throws IOException
  {
    if (off < 0 || len < 0 || off + len > b.length)
      throw new ArrayIndexOutOfBoundsException();

    while (len > 0)
      {
	// super.read will block until some data is available.
	int numread = super.read(b, off, len);
	if (numread < 0)
	  throw new EOFException();
	len -= numread;
	off += numread;
      }
  }

  public final int readInt() throws IOException
  {
    int retval = 0;
    for (int i = 0; i < 4; i++)
      retval |= readUnsignedByte() << (24 - i * 8);

    return retval;
  }

  // Deprecated as of JDK 1.1
  public final String readLine() throws IOException
  {
    StringBuffer strb = new StringBuffer();

    while (true)
      {
	int c = read();
	if (c < 0)	// got an EOF
	  return strb.length() > 0 ? strb.toString() : null;
	char ch = (char) c;
	if ((ch &= 0xFF) == '\n')
	  break;
	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.
	    if (in instanceof BufferedInputStream && (read() & 0xFF) != '\n')
	      {
	        BufferedInputStream bin = (BufferedInputStream) in;
		if (bin.pos > 0)
                  bin.pos--;
	      }
	    else if (markSupported())
	      {
		mark(1);
		if ((read() & 0xFF) != '\n')
		  reset();
	      }
	    break;
	  }
	strb.append(ch);
      }

    return strb.length() > 0 ? strb.toString() : "";
  }

  public final long readLong() throws IOException
  {
    long retval = 0L;
    for (int i = 0; i < 8; i++)
      retval |= (long) readUnsignedByte() << (56 - i * 8);

    return retval;
  }

  public final short readShort() throws IOException
  {
    return (short) ((readByte() << 8) | readUnsignedByte());
  }

  public final int readUnsignedByte() throws IOException
  {
    int i = read();
    if (i < 0)
      throw new EOFException();

    return (i & 0xFF);
  }

  public final int readUnsignedShort() throws IOException
  {
    return (readUnsignedByte() << 8) | readUnsignedByte();
  }

  public final String readUTF() throws IOException
  {
    return readUTF(this);
  }

  public final static String readUTF(DataInput in) throws IOException
  {
    final int UTFlen = in.readUnsignedShort();
    byte[] buf = new byte[UTFlen];
    StringBuffer strbuf = new StringBuffer();

    // 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);
    for (int i = 0; i < UTFlen; )
      {
	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 >= UTFlen || (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 >= UTFlen ||
		(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();
  }

  public final int skipBytes(int n) throws IOException
  {
    // The contract in the Java Lang. Spec. says that this never
    // throws an EOFException and infers that it doesn't block (since
    // it may skip less than the requested number of bytes).
    // BUT, the JCL book specifically says that this method blocks
    // and can throw an EOFException.  Finally, the Java 1.2 online
    // doc simply refers to the general contract.  As such, we will
    // stick to the contract and assume for now that the JCL book
    // is incorrect.

    // Since we're only skipping at most an int number of bytes, the cast
    // of return value to an int is fine.
    if (n > 0)
      {
	n = Math.min(n, available());
        return (int) super.skip((long) n);
      }

    return 0;
  }
}