    001    /*
    002     * Copyright (C) 2007 The Guava Authors
    003     *
    004     * Licensed under the Apache License, Version 2.0 (the "License");
    005     * you may not use this file except in compliance with the License.
    006     * You may obtain a copy of the License at
    007     *
    008     * http://www.apache.org/licenses/LICENSE-2.0
    009     *
    010     * Unless required by applicable law or agreed to in writing, software
    011     * distributed under the License is distributed on an "AS IS" BASIS,
    012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    013     * See the License for the specific language governing permissions and
    014     * limitations under the License.
    015     */
    016
    017    package com.google.common.io;
    018
    019    import com.google.common.annotations.Beta;
    020    import com.google.common.base.Preconditions;
    021    import com.google.common.primitives.Ints;
    022    import com.google.common.primitives.Longs;
    023
    024    import java.io.DataInput;
    025    import java.io.DataInputStream;
    026    import java.io.EOFException;
    027    import java.io.FilterInputStream;
    028    import java.io.IOException;
    029    import java.io.InputStream;
    030
    031    /**
    032     * An implementation of {@link DataInput} that uses little-endian byte ordering
    033     * for reading {@code short}, {@code int}, {@code float}, {@code double}, and
    034     * {@code long} values.
    035     * <p>
    036     * <b>Note:</b> This class intentionally violates the specification of its
    037     * supertype {@code DataInput}, which explicitly requires big-endian byte order.
    038     *
    039     * @author Chris Nokleberg
    040     * @author Keith Bottner
    041     * @since 8.0
    042     */
    043    @Beta
    044    public final class LittleEndianDataInputStream extends FilterInputStream
    045        implements DataInput {
    046
    047      /**
    048       * Creates a {@code LittleEndianDataInputStream} that wraps the given stream.
    049       *
    050       * @param in the stream to delegate to
    051       */
    052      public LittleEndianDataInputStream(InputStream in) {
    053        super(Preconditions.checkNotNull(in));
    054      }
    055
    056      /**
    057       * This method will throw an {@link UnsupportedOperationException}.
    058       */
    059      @Override
    060      public String readLine() {
    061        throw new UnsupportedOperationException("readLine is not supported");
    062      }
    063
    064      @Override
    065      public void readFully(byte[] b) throws IOException {
    066        ByteStreams.readFully(this, b);
    067      }
    068
    069      @Override
    070      public void readFully(byte[] b, int off, int len) throws IOException {
    071        ByteStreams.readFully(this, b, off, len);
    072      }
    073
    074      @Override
    075      public int skipBytes(int n) throws IOException {
    076        return (int) in.skip(n);
    077      }
    078
    079      @Override
    080      public int readUnsignedByte() throws IOException {
    081        int b1 = in.read();
    082        if (0 > b1) {
    083          throw new EOFException();
    084        }
    085
    086        return b1;
    087      }
    088
    089      /**
    090       * Reads an unsigned {@code short} as specified by
    091       * {@link DataInputStream#readUnsignedShort()}, except using little-endian
    092       * byte order.
    093       *
    094       * @return the next two bytes of the input stream, interpreted as an
    095       *         unsigned 16-bit integer in little-endian byte order
    096       * @throws IOException if an I/O error occurs
    097       */
    098      @Override
    099      public int readUnsignedShort() throws IOException {
    100        byte b1 = readAndCheckByte();
    101        byte b2 = readAndCheckByte();
    102
    103        return Ints.fromBytes((byte) 0, (byte) 0, b2, b1);
    104      }
    105
    106      /**
    107       * Reads an integer as specified by {@link DataInputStream#readInt()}, except
    108       * using little-endian byte order.
    109       *
    110       * @return the next four bytes of the input stream, interpreted as an
    111       *         {@code int} in little-endian byte order
    112       * @throws IOException if an I/O error occurs
    113       */
    114      @Override
    115      public int readInt() throws IOException {
    116        byte b1 = readAndCheckByte();
    117        byte b2 = readAndCheckByte();
    118        byte b3 = readAndCheckByte();
    119        byte b4 = readAndCheckByte();
    120
    121        return Ints.fromBytes( b4, b3, b2, b1);
    122      }
    123
    124      /**
    125       * Reads a {@code long} as specified by {@link DataInputStream#readLong()},
    126       * except using little-endian byte order.
    127       *
    128       * @return the next eight bytes of the input stream, interpreted as a
    129       *         {@code long} in little-endian byte order
    130       * @throws IOException if an I/O error occurs
    131       */
    132      @Override
    133      public long readLong() throws IOException {
    134        byte b1 = readAndCheckByte();
    135        byte b2 = readAndCheckByte();
    136        byte b3 = readAndCheckByte();
    137        byte b4 = readAndCheckByte();
    138        byte b5 = readAndCheckByte();
    139        byte b6 = readAndCheckByte();
    140        byte b7 = readAndCheckByte();
    141        byte b8 = readAndCheckByte();
    142
    143        return Longs.fromBytes(b8, b7, b6, b5, b4, b3, b2, b1);
    144      }
    145
    146      /**
    147       * Reads a {@code float} as specified by {@link DataInputStream#readFloat()},
    148       * except using little-endian byte order.
    149       *
    150       * @return the next four bytes of the input stream, interpreted as a
    151       *         {@code float} in little-endian byte order
    152       * @throws IOException if an I/O error occurs
    153       */
    154      @Override
    155      public float readFloat() throws IOException {
    156        return Float.intBitsToFloat(readInt());
    157      }
    158
    159      /**
    160       * Reads a {@code double} as specified by
    161       * {@link DataInputStream#readDouble()}, except using little-endian byte
    162       * order.
    163       *
    164       * @return the next eight bytes of the input stream, interpreted as a
    165       *         {@code double} in little-endian byte order
    166       * @throws IOException if an I/O error occurs
    167       */
    168      @Override
    169      public double readDouble() throws IOException {
    170        return Double.longBitsToDouble(readLong());
    171      }
    172
    173      @Override
    174      public String readUTF() throws IOException {
    175        return new DataInputStream(in).readUTF();
    176      }
    177
    178      /**
    179       * Reads a {@code short} as specified by {@link DataInputStream#readShort()},
    180       * except using little-endian byte order.
    181       *
    182       * @return the next two bytes of the input stream, interpreted as a
    183       *         {@code short} in little-endian byte order.
    184       * @throws IOException if an I/O error occurs.
    185       */
    186      @Override
    187      public short readShort() throws IOException {
    188        return (short) readUnsignedShort();
    189      }
    190
    191      /**
    192       * Reads a char as specified by {@link DataInputStream#readChar()}, except
    193       * using little-endian byte order.
    194       *
    195       * @return the next two bytes of the input stream, interpreted as a
    196       *         {@code char} in little-endian byte order
    197       * @throws IOException if an I/O error occurs
    198       */
    199      @Override
    200      public char readChar() throws IOException {
    201        return (char) readUnsignedShort();
    202      }
    203
    204      @Override
    205      public byte readByte() throws IOException {
    206        return (byte) readUnsignedByte();
    207      }
    208
    209      @Override
    210      public boolean readBoolean() throws IOException {
    211        return readUnsignedByte() != 0;
    212      }
    213
    214      /**
    215       * Reads a byte from the input stream checking that the end of file (EOF)
    216       * has not been encountered.
    217       *
    218       * @return byte read from input
    219       * @throws IOException if an error is encountered while reading
    220       * @throws EOFException if the end of file (EOF) is encountered.
    221       */
    222      private byte readAndCheckByte() throws IOException, EOFException {
    223        int b1 = in.read();
    224
    225        if (-1 == b1) {
    226          throw new EOFException();
    227        }
    228
    229        return (byte) b1;
    230      }
    231
    232    }