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.Beta;
018import com.google.common.annotations.GwtIncompatible;
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 java.io.DataInput;
024import java.io.DataInputStream;
025import java.io.EOFException;
026import java.io.FilterInputStream;
027import java.io.IOException;
028import java.io.InputStream;
029
030/**
031 * An implementation of {@link DataInput} that uses little-endian byte ordering for reading {@code
032 * short}, {@code int}, {@code float}, {@code double}, and {@code long} values.
033 *
034 * <p><b>Note:</b> This class intentionally violates the specification of its supertype {@code
035 * DataInput}, which explicitly requires big-endian byte order.
036 *
037 * @author Chris Nokleberg
038 * @author Keith Bottner
039 * @since 8.0
040 */
041@Beta
042@GwtIncompatible
043public final class LittleEndianDataInputStream extends FilterInputStream implements DataInput {
044
045  /**
046   * Creates a {@code LittleEndianDataInputStream} that wraps the given stream.
047   *
048   * @param in the stream to delegate to
049   */
050  public LittleEndianDataInputStream(InputStream in) {
051    super(Preconditions.checkNotNull(in));
052  }
053
054  /** This method will throw an {@link UnsupportedOperationException}. */
055  @CanIgnoreReturnValue // to skip a line
056  @Override
057  public String readLine() {
058    throw new UnsupportedOperationException("readLine is not supported");
059  }
060
061  @Override
062  public void readFully(byte[] b) throws IOException {
063    ByteStreams.readFully(this, b);
064  }
065
066  @Override
067  public void readFully(byte[] b, int off, int len) throws IOException {
068    ByteStreams.readFully(this, b, off, len);
069  }
070
071  @Override
072  public int skipBytes(int n) throws IOException {
073    return (int) in.skip(n);
074  }
075
076  @CanIgnoreReturnValue // to skip a byte
077  @Override
078  public int readUnsignedByte() throws IOException {
079    int b1 = in.read();
080    if (0 > b1) {
081      throw new EOFException();
082    }
083
084    return b1;
085  }
086
087  /**
088   * Reads an unsigned {@code short} as specified by {@link DataInputStream#readUnsignedShort()},
089   * except using little-endian byte order.
090   *
091   * @return the next two bytes of the input stream, interpreted as an unsigned 16-bit integer in
092   *     little-endian byte order
093   * @throws IOException if an I/O error occurs
094   */
095  @CanIgnoreReturnValue // to skip some bytes
096  @Override
097  public int readUnsignedShort() throws IOException {
098    byte b1 = readAndCheckByte();
099    byte b2 = readAndCheckByte();
100
101    return Ints.fromBytes((byte) 0, (byte) 0, b2, b1);
102  }
103
104  /**
105   * Reads an integer as specified by {@link DataInputStream#readInt()}, except using little-endian
106   * byte order.
107   *
108   * @return the next four bytes of the input stream, interpreted as an {@code int} in little-endian
109   *     byte order
110   * @throws IOException if an I/O error occurs
111   */
112  @CanIgnoreReturnValue // to skip some bytes
113  @Override
114  public int readInt() throws IOException {
115    byte b1 = readAndCheckByte();
116    byte b2 = readAndCheckByte();
117    byte b3 = readAndCheckByte();
118    byte b4 = readAndCheckByte();
119
120    return Ints.fromBytes(b4, b3, b2, b1);
121  }
122
123  /**
124   * Reads a {@code long} as specified by {@link DataInputStream#readLong()}, except using
125   * little-endian byte order.
126   *
127   * @return the next eight bytes of the input stream, interpreted as a {@code long} in
128   *     little-endian byte order
129   * @throws IOException if an I/O error occurs
130   */
131  @CanIgnoreReturnValue // to skip some bytes
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()}, except using
148   * little-endian byte order.
149   *
150   * @return the next four bytes of the input stream, interpreted as a {@code float} in
151   *     little-endian byte order
152   * @throws IOException if an I/O error occurs
153   */
154  @CanIgnoreReturnValue // to skip some bytes
155  @Override
156  public float readFloat() throws IOException {
157    return Float.intBitsToFloat(readInt());
158  }
159
160  /**
161   * Reads a {@code double} as specified by {@link DataInputStream#readDouble()}, except using
162   * little-endian byte order.
163   *
164   * @return the next eight bytes of the input stream, interpreted as a {@code double} in
165   *     little-endian byte order
166   * @throws IOException if an I/O error occurs
167   */
168  @CanIgnoreReturnValue // to skip some bytes
169  @Override
170  public double readDouble() throws IOException {
171    return Double.longBitsToDouble(readLong());
172  }
173
174  @CanIgnoreReturnValue // to skip a field
175  @Override
176  public String readUTF() throws IOException {
177    return new DataInputStream(in).readUTF();
178  }
179
180  /**
181   * Reads a {@code short} as specified by {@link DataInputStream#readShort()}, except using
182   * little-endian byte order.
183   *
184   * @return the next two bytes of the input stream, interpreted as a {@code short} in little-endian
185   *     byte order.
186   * @throws IOException if an I/O error occurs.
187   */
188  @CanIgnoreReturnValue // to skip some bytes
189  @Override
190  public short readShort() throws IOException {
191    return (short) readUnsignedShort();
192  }
193
194  /**
195   * Reads a char as specified by {@link DataInputStream#readChar()}, except using little-endian
196   * byte order.
197   *
198   * @return the next two bytes of the input stream, interpreted as a {@code char} in little-endian
199   *     byte order
200   * @throws IOException if an I/O error occurs
201   */
202  @CanIgnoreReturnValue // to skip some bytes
203  @Override
204  public char readChar() throws IOException {
205    return (char) readUnsignedShort();
206  }
207
208  @CanIgnoreReturnValue // to skip a byte
209  @Override
210  public byte readByte() throws IOException {
211    return (byte) readUnsignedByte();
212  }
213
214  @CanIgnoreReturnValue // to skip a byte
215  @Override
216  public boolean readBoolean() throws IOException {
217    return readUnsignedByte() != 0;
218  }
219
220  /**
221   * Reads a byte from the input stream checking that the end of file (EOF) has not been
222   * encountered.
223   *
224   * @return byte read from input
225   * @throws IOException if an error is encountered while reading
226   * @throws EOFException if the end of file (EOF) is encountered.
227   */
228  private byte readAndCheckByte() throws IOException, EOFException {
229    int b1 = in.read();
230
231    if (-1 == b1) {
232      throw new EOFException();
233    }
234
235    return (byte) b1;
236  }
237}