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 /** 080 * {@inheritDoc} 081 * 082 * <p>{@link LittleEndianDataInputStream} ignores negative values of {@code n} (returning zero). 083 * Otherwise, it skips the full requested number of bytes unless it reaches end of file or throws 084 * an exception. 085 */ 086 @Override 087 public int skipBytes(int n) throws IOException { 088 return (int) ByteStreams.skipUpTo(in(), n); 089 } 090 091 @CanIgnoreReturnValue // to skip a byte 092 @Override 093 public int readUnsignedByte() throws IOException { 094 int b1 = in().read(); 095 if (b1 < 0) { 096 throw new EOFException(); 097 } 098 099 return b1; 100 } 101 102 /** 103 * Reads an unsigned {@code short} as specified by {@link DataInputStream#readUnsignedShort()}, 104 * except using little-endian byte order. 105 * 106 * @return the next two bytes of the input stream, interpreted as an unsigned 16-bit integer in 107 * little-endian byte order 108 * @throws IOException if an I/O error occurs 109 */ 110 @CanIgnoreReturnValue // to skip some bytes 111 @Override 112 public int readUnsignedShort() throws IOException { 113 byte b1 = readAndCheckByte(); 114 byte b2 = readAndCheckByte(); 115 116 return Ints.fromBytes((byte) 0, (byte) 0, b2, b1); 117 } 118 119 /** 120 * Reads an integer as specified by {@link DataInputStream#readInt()}, except using little-endian 121 * byte order. 122 * 123 * @return the next four bytes of the input stream, interpreted as an {@code int} in little-endian 124 * byte order 125 * @throws IOException if an I/O error occurs 126 */ 127 @CanIgnoreReturnValue // to skip some bytes 128 @Override 129 public int readInt() throws IOException { 130 byte b1 = readAndCheckByte(); 131 byte b2 = readAndCheckByte(); 132 byte b3 = readAndCheckByte(); 133 byte b4 = readAndCheckByte(); 134 135 return Ints.fromBytes(b4, b3, b2, b1); 136 } 137 138 /** 139 * Reads a {@code long} as specified by {@link DataInputStream#readLong()}, except using 140 * little-endian byte order. 141 * 142 * @return the next eight bytes of the input stream, interpreted as a {@code long} in 143 * little-endian byte order 144 * @throws IOException if an I/O error occurs 145 */ 146 @CanIgnoreReturnValue // to skip some bytes 147 @Override 148 public long readLong() throws IOException { 149 byte b1 = readAndCheckByte(); 150 byte b2 = readAndCheckByte(); 151 byte b3 = readAndCheckByte(); 152 byte b4 = readAndCheckByte(); 153 byte b5 = readAndCheckByte(); 154 byte b6 = readAndCheckByte(); 155 byte b7 = readAndCheckByte(); 156 byte b8 = readAndCheckByte(); 157 158 return Longs.fromBytes(b8, b7, b6, b5, b4, b3, b2, b1); 159 } 160 161 /** 162 * Reads a {@code float} as specified by {@link DataInputStream#readFloat()}, except using 163 * little-endian byte order. 164 * 165 * @return the next four bytes of the input stream, interpreted as a {@code float} in 166 * little-endian byte order 167 * @throws IOException if an I/O error occurs 168 */ 169 @CanIgnoreReturnValue // to skip some bytes 170 @Override 171 public float readFloat() throws IOException { 172 return Float.intBitsToFloat(readInt()); 173 } 174 175 /** 176 * Reads a {@code double} as specified by {@link DataInputStream#readDouble()}, except using 177 * little-endian byte order. 178 * 179 * @return the next eight bytes of the input stream, interpreted as a {@code double} in 180 * little-endian byte order 181 * @throws IOException if an I/O error occurs 182 */ 183 @CanIgnoreReturnValue // to skip some bytes 184 @Override 185 public double readDouble() throws IOException { 186 return Double.longBitsToDouble(readLong()); 187 } 188 189 @CanIgnoreReturnValue // to skip a field 190 @Override 191 public String readUTF() throws IOException { 192 return new DataInputStream(in()).readUTF(); 193 } 194 195 /** 196 * Reads a {@code short} as specified by {@link DataInputStream#readShort()}, except using 197 * little-endian byte order. 198 * 199 * @return the next two bytes of the input stream, interpreted as a {@code short} in little-endian 200 * byte order. 201 * @throws IOException if an I/O error occurs. 202 */ 203 @CanIgnoreReturnValue // to skip some bytes 204 @Override 205 public short readShort() throws IOException { 206 return (short) readUnsignedShort(); 207 } 208 209 /** 210 * Reads a char as specified by {@link DataInputStream#readChar()}, except using little-endian 211 * byte order. 212 * 213 * @return the next two bytes of the input stream, interpreted as a {@code char} in little-endian 214 * byte order 215 * @throws IOException if an I/O error occurs 216 */ 217 @CanIgnoreReturnValue // to skip some bytes 218 @Override 219 public char readChar() throws IOException { 220 return (char) readUnsignedShort(); 221 } 222 223 @CanIgnoreReturnValue // to skip a byte 224 @Override 225 public byte readByte() throws IOException { 226 return (byte) readUnsignedByte(); 227 } 228 229 @CanIgnoreReturnValue // to skip a byte 230 @Override 231 public boolean readBoolean() throws IOException { 232 return readUnsignedByte() != 0; 233 } 234 235 /** 236 * Reads a byte from the input stream checking that the end of file (EOF) has not been 237 * encountered. 238 * 239 * @return byte read from input 240 * @throws IOException if an error is encountered while reading 241 * @throws EOFException if the end of file (EOF) is encountered. 242 */ 243 private byte readAndCheckByte() throws IOException { 244 int b1 = in().read(); 245 246 if (b1 == -1) { 247 throw new EOFException(); 248 } 249 250 return (byte) b1; 251 } 252}