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 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@Beta 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}