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 chrisn@google.com (Chris Nokleberg) 040 * @author kbottner@google.com (Keith Bottner) 041 * @since 8 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 a {@link UnsupportedOperationException}. 058 */ 059 @Override 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 @Override 080 public int readUnsignedByte() throws IOException { 081 int b1 = in.read(); 082 if (0 > b1) { 083 throw new EOFException(); 084 } 085 086 return b1; 087 } 088 089 /** 090 * Reads an unsigned {@code short} as specified by 091 * {@link DataInputStream#readUnsignedShort()}, except using little-endian 092 * byte order. 093 * 094 * @return the next two bytes of the input stream, interpreted as an {@code 095 * int} in little-endian byte order 096 * @throws IOException if an I/O error occurs 097 */ 098 @Override 099 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 {@code 111 * int} in little-endian byte order 112 * @throws IOException if an I/O error occurs 113 */ 114 @Override 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 {@code 129 * long} in little-endian byte order 130 * @throws IOException if an I/O error occurs 131 */ 132 @Override 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 an {@code 151 * float} in little-endian byte order 152 * @throws IOException if an I/O error occurs 153 */ 154 @Override 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 an {@code 165 * int} in little-endian byte order 166 * @throws IOException if an I/O error occurs 167 */ 168 @Override 169 public double readDouble() throws IOException { 170 return Double.longBitsToDouble(readLong()); 171 } 172 173 @Override 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 an {@code 183 * short} in little-endian byte order. 184 * @throws IOException if an I/O error occurs. 185 */ 186 @Override 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 an {@code 196 * char} in little-endian byte order 197 * @throws IOException if an I/O error occurs 198 */ 199 @Override 200 public char readChar() throws IOException { 201 return (char) readUnsignedShort(); 202 } 203 204 @Override 205 public byte readByte() throws IOException { 206 return (byte) readUnsignedByte(); 207 } 208 209 @Override 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 */ 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 }