1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.io; 18 19 import com.google.common.annotations.Beta; 20 import com.google.common.base.Preconditions; 21 import com.google.common.primitives.Ints; 22 import com.google.common.primitives.Longs; 23 24 import java.io.DataInput; 25 import java.io.DataInputStream; 26 import java.io.EOFException; 27 import java.io.FilterInputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 31 /** 32 * An implementation of {@link DataInput} that uses little-endian byte ordering 33 * for reading {@code short}, {@code int}, {@code float}, {@code double}, and 34 * {@code long} values. 35 * <p> 36 * <b>Note:</b> This class intentionally violates the specification of its 37 * supertype {@code DataInput}, which explicitly requires big-endian byte order. 38 * 39 * @author Chris Nokleberg 40 * @author Keith Bottner 41 * @since 8.0 42 */ 43 @Beta 44 public final class LittleEndianDataInputStream extends FilterInputStream 45 implements DataInput { 46 47 /** 48 * Creates a {@code LittleEndianDataInputStream} that wraps the given stream. 49 * 50 * @param in the stream to delegate to 51 */ LittleEndianDataInputStream(InputStream in)52 public LittleEndianDataInputStream(InputStream in) { 53 super(Preconditions.checkNotNull(in)); 54 } 55 56 /** 57 * This method will throw an {@link UnsupportedOperationException}. 58 */ 59 @Override readLine()60 public String readLine() { 61 throw new UnsupportedOperationException("readLine is not supported"); 62 } 63 64 @Override readFully(byte[] b)65 public void readFully(byte[] b) throws IOException { 66 ByteStreams.readFully(this, b); 67 } 68 69 @Override readFully(byte[] b, int off, int len)70 public void readFully(byte[] b, int off, int len) throws IOException { 71 ByteStreams.readFully(this, b, off, len); 72 } 73 74 @Override skipBytes(int n)75 public int skipBytes(int n) throws IOException { 76 return (int) in.skip(n); 77 } 78 79 @Override readUnsignedByte()80 public int readUnsignedByte() throws IOException { 81 int b1 = in.read(); 82 if (0 > b1) { 83 throw new EOFException(); 84 } 85 86 return b1; 87 } 88 89 /** 90 * Reads an unsigned {@code short} as specified by 91 * {@link DataInputStream#readUnsignedShort()}, except using little-endian 92 * byte order. 93 * 94 * @return the next two bytes of the input stream, interpreted as an 95 * unsigned 16-bit integer in little-endian byte order 96 * @throws IOException if an I/O error occurs 97 */ 98 @Override readUnsignedShort()99 public int readUnsignedShort() throws IOException { 100 byte b1 = readAndCheckByte(); 101 byte b2 = readAndCheckByte(); 102 103 return Ints.fromBytes((byte) 0, (byte) 0, b2, b1); 104 } 105 106 /** 107 * Reads an integer as specified by {@link DataInputStream#readInt()}, except 108 * using little-endian byte order. 109 * 110 * @return the next four bytes of the input stream, interpreted as an 111 * {@code int} in little-endian byte order 112 * @throws IOException if an I/O error occurs 113 */ 114 @Override readInt()115 public int readInt() throws IOException { 116 byte b1 = readAndCheckByte(); 117 byte b2 = readAndCheckByte(); 118 byte b3 = readAndCheckByte(); 119 byte b4 = readAndCheckByte(); 120 121 return Ints.fromBytes( b4, b3, b2, b1); 122 } 123 124 /** 125 * Reads a {@code long} as specified by {@link DataInputStream#readLong()}, 126 * except using little-endian byte order. 127 * 128 * @return the next eight bytes of the input stream, interpreted as a 129 * {@code long} in little-endian byte order 130 * @throws IOException if an I/O error occurs 131 */ 132 @Override readLong()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()}, 148 * except using little-endian byte order. 149 * 150 * @return the next four bytes of the input stream, interpreted as a 151 * {@code float} in little-endian byte order 152 * @throws IOException if an I/O error occurs 153 */ 154 @Override readFloat()155 public float readFloat() throws IOException { 156 return Float.intBitsToFloat(readInt()); 157 } 158 159 /** 160 * Reads a {@code double} as specified by 161 * {@link DataInputStream#readDouble()}, except using little-endian byte 162 * order. 163 * 164 * @return the next eight bytes of the input stream, interpreted as a 165 * {@code double} in little-endian byte order 166 * @throws IOException if an I/O error occurs 167 */ 168 @Override readDouble()169 public double readDouble() throws IOException { 170 return Double.longBitsToDouble(readLong()); 171 } 172 173 @Override readUTF()174 public String readUTF() throws IOException { 175 return new DataInputStream(in).readUTF(); 176 } 177 178 /** 179 * Reads a {@code short} as specified by {@link DataInputStream#readShort()}, 180 * except using little-endian byte order. 181 * 182 * @return the next two bytes of the input stream, interpreted as a 183 * {@code short} in little-endian byte order. 184 * @throws IOException if an I/O error occurs. 185 */ 186 @Override readShort()187 public short readShort() throws IOException { 188 return (short) readUnsignedShort(); 189 } 190 191 /** 192 * Reads a char as specified by {@link DataInputStream#readChar()}, except 193 * using little-endian byte order. 194 * 195 * @return the next two bytes of the input stream, interpreted as a 196 * {@code char} in little-endian byte order 197 * @throws IOException if an I/O error occurs 198 */ 199 @Override readChar()200 public char readChar() throws IOException { 201 return (char) readUnsignedShort(); 202 } 203 204 @Override readByte()205 public byte readByte() throws IOException { 206 return (byte) readUnsignedByte(); 207 } 208 209 @Override readBoolean()210 public boolean readBoolean() throws IOException { 211 return readUnsignedByte() != 0; 212 } 213 214 /** 215 * Reads a byte from the input stream checking that the end of file (EOF) 216 * has not been encountered. 217 * 218 * @return byte read from input 219 * @throws IOException if an error is encountered while reading 220 * @throws EOFException if the end of file (EOF) is encountered. 221 */ readAndCheckByte()222 private byte readAndCheckByte() throws IOException, EOFException { 223 int b1 = in.read(); 224 225 if (-1 == b1) { 226 throw new EOFException(); 227 } 228 229 return (byte) b1; 230 } 231 232 } 233