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