1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.io;
19
20import java.nio.ByteOrder;
21import java.nio.charset.ModifiedUtf8;
22import libcore.io.Memory;
23import libcore.io.Streams;
24import libcore.io.SizeOf;
25
26/**
27 * Wraps an existing {@link InputStream} and reads big-endian typed data from it.
28 * Typically, this stream has been written by a DataOutputStream. Types that can
29 * be read include byte, 16-bit short, 32-bit int, 32-bit float, 64-bit long,
30 * 64-bit double, byte strings, and strings encoded in
31 * {@link DataInput modified UTF-8}.
32 *
33 * @see DataOutputStream
34 */
35public class DataInputStream extends FilterInputStream implements DataInput {
36
37    private final byte[] scratch = new byte[8];
38
39    /**
40     * Constructs a new DataInputStream on the InputStream {@code in}. All
41     * reads are then filtered through this stream. Note that data read by this
42     * stream is not in a human readable format and was most likely created by a
43     * DataOutputStream.
44     *
45     * <p><strong>Warning:</strong> passing a null source creates an invalid
46     * {@code DataInputStream}. All operations on such a stream will fail.
47     *
48     * @param in
49     *            the source InputStream the filter reads from.
50     * @see DataOutputStream
51     * @see RandomAccessFile
52     */
53    public DataInputStream(InputStream in) {
54        super(in);
55    }
56
57    // overridden to add 'final'
58    @Override public final int read(byte[] buffer) throws IOException {
59        return super.read(buffer);
60    }
61
62    @Override public final int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
63        return in.read(buffer, byteOffset, byteCount);
64    }
65
66    public final boolean readBoolean() throws IOException {
67        int temp = in.read();
68        if (temp < 0) {
69            throw new EOFException();
70        }
71        return temp != 0;
72    }
73
74    public final byte readByte() throws IOException {
75        int temp = in.read();
76        if (temp < 0) {
77            throw new EOFException();
78        }
79        return (byte) temp;
80    }
81
82    public final char readChar() throws IOException {
83        return (char) readShort();
84    }
85
86    public final double readDouble() throws IOException {
87        return Double.longBitsToDouble(readLong());
88    }
89
90    public final float readFloat() throws IOException {
91        return Float.intBitsToFloat(readInt());
92    }
93
94    public final void readFully(byte[] dst) throws IOException {
95        readFully(dst, 0, dst.length);
96    }
97
98    public final void readFully(byte[] dst, int offset, int byteCount) throws IOException {
99        Streams.readFully(in, dst, offset, byteCount);
100    }
101
102    public final int readInt() throws IOException {
103        Streams.readFully(in, scratch, 0, SizeOf.INT);
104        return Memory.peekInt(scratch, 0, ByteOrder.BIG_ENDIAN);
105    }
106
107    /**
108     * @deprecated This method cannot be trusted to convert bytes to characters correctly.
109     * Wrap this stream with a {@link BufferedReader} instead.
110     */
111    @Deprecated
112    public final String readLine() throws IOException {
113        StringBuilder line = new StringBuilder(80); // Typical line length
114        boolean foundTerminator = false;
115        while (true) {
116            int nextByte = in.read();
117            switch (nextByte) {
118                case -1:
119                    if (line.length() == 0 && !foundTerminator) {
120                        return null;
121                    }
122                    return line.toString();
123                case (byte) '\r':
124                    if (foundTerminator) {
125                        ((PushbackInputStream) in).unread(nextByte);
126                        return line.toString();
127                    }
128                    foundTerminator = true;
129                    /* Have to be able to peek ahead one byte */
130                    if (!(in.getClass() == PushbackInputStream.class)) {
131                        in = new PushbackInputStream(in);
132                    }
133                    break;
134                case (byte) '\n':
135                    return line.toString();
136                default:
137                    if (foundTerminator) {
138                        ((PushbackInputStream) in).unread(nextByte);
139                        return line.toString();
140                    }
141                    line.append((char) nextByte);
142            }
143        }
144    }
145
146    public final long readLong() throws IOException {
147        Streams.readFully(in, scratch, 0, SizeOf.LONG);
148        return Memory.peekLong(scratch, 0, ByteOrder.BIG_ENDIAN);
149    }
150
151    public final short readShort() throws IOException {
152        Streams.readFully(in, scratch, 0, SizeOf.SHORT);
153        return Memory.peekShort(scratch, 0, ByteOrder.BIG_ENDIAN);
154    }
155
156    public final int readUnsignedByte() throws IOException {
157        int temp = in.read();
158        if (temp < 0) {
159            throw new EOFException();
160        }
161        return temp;
162    }
163
164    public final int readUnsignedShort() throws IOException {
165        return ((int) readShort()) & 0xffff;
166    }
167
168    public final String readUTF() throws IOException {
169        return decodeUTF(readUnsignedShort());
170    }
171
172    String decodeUTF(int utfSize) throws IOException {
173        return decodeUTF(utfSize, this);
174    }
175
176    private static String decodeUTF(int utfSize, DataInput in) throws IOException {
177        byte[] buf = new byte[utfSize];
178        in.readFully(buf, 0, utfSize);
179        return ModifiedUtf8.decode(buf, new char[utfSize], 0, utfSize);
180    }
181
182    public static final String readUTF(DataInput in) throws IOException {
183        return decodeUTF(in.readUnsignedShort(), in);
184    }
185
186    /**
187     * Skips {@code count} number of bytes in this stream. Subsequent {@code
188     * read()}s will not return these bytes unless {@code reset()} is used.
189     *
190     * This method will not throw an {@link EOFException} if the end of the
191     * input is reached before {@code count} bytes where skipped.
192     *
193     * @param count
194     *            the number of bytes to skip.
195     * @return the number of bytes actually skipped.
196     * @throws IOException
197     *             if a problem occurs during skipping.
198     * @see #mark(int)
199     * @see #reset()
200     */
201    public final int skipBytes(int count) throws IOException {
202        int skipped = 0;
203        long skip;
204        while (skipped < count && (skip = in.skip(count - skipped)) != 0) {
205            skipped += skip;
206        }
207        return skipped;
208    }
209}
210