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