Home | History | Annotate | Download | only in io
      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 
     18 package java.io;
     19 
     20 import java.nio.ByteOrder;
     21 import java.nio.charset.ModifiedUtf8;
     22 import libcore.io.Memory;
     23 import libcore.io.Streams;
     24 import 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  */
     35 public 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     /**
     63      * Reads at most {@code length} bytes from this stream and stores them in
     64      * the byte array {@code buffer} starting at {@code offset}. Returns the
     65      * number of bytes that have been read or -1 if no bytes have been read and
     66      * the end of the stream has been reached.
     67      *
     68      * @param buffer
     69      *            the byte array in which to store the bytes read.
     70      * @param offset
     71      *            the initial position in {@code buffer} to store the bytes
     72      *            read from this stream.
     73      * @param length
     74      *            the maximum number of bytes to store in {@code buffer}.
     75      * @return the number of bytes that have been read or -1 if the end of the
     76      *         stream has been reached.
     77      * @throws IOException
     78      *             if a problem occurs while reading from this stream.
     79      * @see DataOutput#write(byte[])
     80      * @see DataOutput#write(byte[], int, int)
     81      */
     82     @Override
     83     public final int read(byte[] buffer, int offset, int length) throws IOException {
     84         return in.read(buffer, offset, length);
     85     }
     86 
     87     public final boolean readBoolean() throws IOException {
     88         int temp = in.read();
     89         if (temp < 0) {
     90             throw new EOFException();
     91         }
     92         return temp != 0;
     93     }
     94 
     95     public final byte readByte() throws IOException {
     96         int temp = in.read();
     97         if (temp < 0) {
     98             throw new EOFException();
     99         }
    100         return (byte) temp;
    101     }
    102 
    103     public final char readChar() throws IOException {
    104         return (char) readShort();
    105     }
    106 
    107     public final double readDouble() throws IOException {
    108         return Double.longBitsToDouble(readLong());
    109     }
    110 
    111     public final float readFloat() throws IOException {
    112         return Float.intBitsToFloat(readInt());
    113     }
    114 
    115     public final void readFully(byte[] dst) throws IOException {
    116         readFully(dst, 0, dst.length);
    117     }
    118 
    119     public final void readFully(byte[] dst, int offset, int byteCount) throws IOException {
    120         Streams.readFully(in, dst, offset, byteCount);
    121     }
    122 
    123     public final int readInt() throws IOException {
    124         Streams.readFully(in, scratch, 0, SizeOf.INT);
    125         return Memory.peekInt(scratch, 0, ByteOrder.BIG_ENDIAN);
    126     }
    127 
    128     @Deprecated
    129     public final String readLine() throws IOException {
    130         StringBuilder line = new StringBuilder(80); // Typical line length
    131         boolean foundTerminator = false;
    132         while (true) {
    133             int nextByte = in.read();
    134             switch (nextByte) {
    135                 case -1:
    136                     if (line.length() == 0 && !foundTerminator) {
    137                         return null;
    138                     }
    139                     return line.toString();
    140                 case (byte) '\r':
    141                     if (foundTerminator) {
    142                         ((PushbackInputStream) in).unread(nextByte);
    143                         return line.toString();
    144                     }
    145                     foundTerminator = true;
    146                     /* Have to be able to peek ahead one byte */
    147                     if (!(in.getClass() == PushbackInputStream.class)) {
    148                         in = new PushbackInputStream(in);
    149                     }
    150                     break;
    151                 case (byte) '\n':
    152                     return line.toString();
    153                 default:
    154                     if (foundTerminator) {
    155                         ((PushbackInputStream) in).unread(nextByte);
    156                         return line.toString();
    157                     }
    158                     line.append((char) nextByte);
    159             }
    160         }
    161     }
    162 
    163     public final long readLong() throws IOException {
    164         Streams.readFully(in, scratch, 0, SizeOf.LONG);
    165         return Memory.peekLong(scratch, 0, ByteOrder.BIG_ENDIAN);
    166     }
    167 
    168     public final short readShort() throws IOException {
    169         Streams.readFully(in, scratch, 0, SizeOf.SHORT);
    170         return Memory.peekShort(scratch, 0, ByteOrder.BIG_ENDIAN);
    171     }
    172 
    173     public final int readUnsignedByte() throws IOException {
    174         int temp = in.read();
    175         if (temp < 0) {
    176             throw new EOFException();
    177         }
    178         return temp;
    179     }
    180 
    181     public final int readUnsignedShort() throws IOException {
    182         return ((int) readShort()) & 0xffff;
    183     }
    184 
    185     public final String readUTF() throws IOException {
    186         return decodeUTF(readUnsignedShort());
    187     }
    188 
    189     String decodeUTF(int utfSize) throws IOException {
    190         return decodeUTF(utfSize, this);
    191     }
    192 
    193     private static String decodeUTF(int utfSize, DataInput in) throws IOException {
    194         byte[] buf = new byte[utfSize];
    195         in.readFully(buf, 0, utfSize);
    196         return ModifiedUtf8.decode(buf, new char[utfSize], 0, utfSize);
    197     }
    198 
    199     public static final String readUTF(DataInput in) throws IOException {
    200         return decodeUTF(in.readUnsignedShort(), in);
    201     }
    202 
    203     /**
    204      * Skips {@code count} number of bytes in this stream. Subsequent {@code
    205      * read()}s will not return these bytes unless {@code reset()} is used.
    206      *
    207      * This method will not throw an {@link EOFException} if the end of the
    208      * input is reached before {@code count} bytes where skipped.
    209      *
    210      * @param count
    211      *            the number of bytes to skip.
    212      * @return the number of bytes actually skipped.
    213      * @throws IOException
    214      *             if a problem occurs during skipping.
    215      * @see #mark(int)
    216      * @see #reset()
    217      */
    218     public final int skipBytes(int count) throws IOException {
    219         int skipped = 0;
    220         long skip;
    221         while (skipped < count && (skip = in.skip(count - skipped)) != 0) {
    222             skipped += skip;
    223         }
    224         return skipped;
    225     }
    226 }
    227