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      public String readLine() {
060        throw new UnsupportedOperationException("readLine is not supported");
061      }
062    
063      public void readFully(byte[] b) throws IOException {
064        ByteStreams.readFully(this, b);
065      }
066    
067      public void readFully(byte[] b, int off, int len) throws IOException {
068        ByteStreams.readFully(this, b, off, len);
069      }
070    
071      public int skipBytes(int n) throws IOException {
072        return (int) in.skip(n);
073      }
074    
075      public int readUnsignedByte() throws IOException {
076        int b1 = in.read();
077        if (0 > b1) {
078          throw new EOFException();
079        }
080        
081        return b1;
082      }
083    
084      /**
085       * Reads an unsigned {@code short} as specified by
086       * {@link DataInputStream#readUnsignedShort()}, except using little-endian
087       * byte order.
088       *
089       * @return the next two bytes of the input stream, interpreted as an 
090       *         unsigned 16-bit integer in little-endian byte order
091       * @throws IOException if an I/O error occurs
092       */
093      public int readUnsignedShort() throws IOException {
094        byte b1 = readAndCheckByte();
095        byte b2 = readAndCheckByte();
096    
097        return Ints.fromBytes((byte) 0, (byte) 0, b2, b1);
098      }
099    
100      /**
101       * Reads an integer as specified by {@link DataInputStream#readInt()}, except
102       * using little-endian byte order.
103       *
104       * @return the next four bytes of the input stream, interpreted as an 
105       *         {@code int} in little-endian byte order
106       * @throws IOException if an I/O error occurs
107       */
108      public int readInt() throws IOException {
109        byte b1 = readAndCheckByte();
110        byte b2 = readAndCheckByte();
111        byte b3 = readAndCheckByte();
112        byte b4 = readAndCheckByte();
113    
114        return Ints.fromBytes( b4, b3, b2, b1);
115      }
116    
117      /**
118       * Reads a {@code long} as specified by {@link DataInputStream#readLong()},
119       * except using little-endian byte order.
120       *
121       * @return the next eight bytes of the input stream, interpreted as a 
122       *         {@code long} in little-endian byte order
123       * @throws IOException if an I/O error occurs
124       */
125      public long readLong() throws IOException {
126        byte b1 = readAndCheckByte();
127        byte b2 = readAndCheckByte();
128        byte b3 = readAndCheckByte();
129        byte b4 = readAndCheckByte();
130        byte b5 = readAndCheckByte();
131        byte b6 = readAndCheckByte();
132        byte b7 = readAndCheckByte();
133        byte b8 = readAndCheckByte();
134    
135        return Longs.fromBytes(b8, b7, b6, b5, b4, b3, b2, b1);
136      }
137    
138      /**
139       * Reads a {@code float} as specified by {@link DataInputStream#readFloat()},
140       * except using little-endian byte order.
141       *
142       * @return the next four bytes of the input stream, interpreted as a
143       *         {@code float} in little-endian byte order
144       * @throws IOException if an I/O error occurs
145       */
146      public float readFloat() throws IOException {
147        return Float.intBitsToFloat(readInt());
148      }
149    
150      /**
151       * Reads a {@code double} as specified by
152       * {@link DataInputStream#readDouble()}, except using little-endian byte
153       * order.
154       *
155       * @return the next eight bytes of the input stream, interpreted as a
156       *         {@code double} in little-endian byte order
157       * @throws IOException if an I/O error occurs
158       */
159      public double readDouble() throws IOException {
160        return Double.longBitsToDouble(readLong());
161      }
162    
163      public String readUTF() throws IOException {
164        return new DataInputStream(in).readUTF();
165      }
166    
167      /**
168       * Reads a {@code short} as specified by {@link DataInputStream#readShort()},
169       * except using little-endian byte order.
170       *
171       * @return the next two bytes of the input stream, interpreted as a
172       *         {@code short} in little-endian byte order.
173       * @throws IOException if an I/O error occurs.
174       */
175      public short readShort() throws IOException {
176        return (short) readUnsignedShort();
177      }
178    
179      /**
180       * Reads a char as specified by {@link DataInputStream#readChar()}, except
181       * using little-endian byte order.
182       *
183       * @return the next two bytes of the input stream, interpreted as a 
184       *         {@code char} in little-endian byte order
185       * @throws IOException if an I/O error occurs
186       */
187      public char readChar() throws IOException {
188        return (char) readUnsignedShort();
189      }
190    
191      public byte readByte() throws IOException {
192        return (byte) readUnsignedByte();
193      }
194    
195      public boolean readBoolean() throws IOException {
196        return readUnsignedByte() != 0;
197      }
198    
199      /**
200       * Reads a byte from the input stream checking that the end of file (EOF)
201       * has not been encountered.
202       *  
203       * @return byte read from input
204       * @throws IOException if an error is encountered while reading
205       * @throws EOFException if the end of file (EOF) is encountered.
206       */
207      private byte readAndCheckByte() throws IOException, EOFException {
208        int b1 = in.read();
209    
210        if (-1 == b1) {
211          throw new EOFException();
212        }
213    
214        return (byte) b1;
215      }
216    
217    }