001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io.input;
018
019import static org.apache.commons.io.IOUtils.EOF;
020
021import java.io.DataInput;
022import java.io.EOFException;
023import java.io.IOException;
024import java.io.InputStream;
025
026import org.apache.commons.io.EndianUtils;
027
028/**
029 * DataInput for systems relying on little-endian data formats. When read, values will be changed from little-endian to
030 * big-endian formats for internal usage.
031 * <p>
032 * Provenance: Avalon Excalibur (IO)
033 * </p>
034 */
035public class SwappedDataInputStream extends ProxyInputStream implements DataInput {
036
037    /**
038     * Constructs a SwappedDataInputStream.
039     *
040     * @param input InputStream to read from
041     */
042    public SwappedDataInputStream(final InputStream input) {
043        super(input);
044    }
045
046    /**
047     * Return <code>{@link #readByte()} != 0</code>
048     *
049     * @return false if the byte read is zero, otherwise true
050     * @throws IOException if an I/O error occurs.
051     * @throws EOFException if an end of file is reached unexpectedly
052     */
053    @Override
054    public boolean readBoolean() throws IOException, EOFException {
055        return 0 != readByte();
056    }
057
058    /**
059     * Invokes the delegate's {@code read()} method.
060     *
061     * @return the byte read or -1 if the end of stream
062     * @throws IOException if an I/O error occurs.
063     * @throws EOFException if an end of file is reached unexpectedly
064     */
065    @Override
066    public byte readByte() throws IOException, EOFException {
067        return (byte) in.read();
068    }
069
070    /**
071     * Reads a 2 byte, unsigned, little endian UTF-16 code point.
072     *
073     * @return the UTF-16 code point read or -1 if the end of stream
074     * @throws IOException if an I/O error occurs.
075     * @throws EOFException if an end of file is reached unexpectedly
076     */
077    @Override
078    public char readChar() throws IOException, EOFException {
079        return (char) readShort();
080    }
081
082    /**
083     * Reads an 8 byte, two's complement, little-endian long.
084     *
085     * @return the read long
086     * @throws IOException if an I/O error occurs.
087     * @throws EOFException if an end of file is reached unexpectedly
088     */
089    @Override
090    public double readDouble() throws IOException, EOFException {
091        return EndianUtils.readSwappedDouble(in);
092    }
093
094    /**
095     * Reads a 4 byte, IEEE 754, little-endian float.
096     *
097     * @return the read float
098     * @throws IOException if an I/O error occurs.
099     * @throws EOFException if an end of file is reached unexpectedly
100     */
101    @Override
102    public float readFloat() throws IOException, EOFException {
103        return EndianUtils.readSwappedFloat(in);
104    }
105
106    /**
107     * Invokes the delegate's {@code read(byte[] data, int, int)} method.
108     *
109     * @param data the buffer to read the bytes into
110     * @throws EOFException if an end of file is reached unexpectedly
111     * @throws IOException if an I/O error occurs.
112     */
113    @Override
114    public void readFully(final byte[] data) throws IOException, EOFException {
115        readFully(data, 0, data.length);
116    }
117
118    /**
119     * Invokes the delegate's {@code read(byte[] data, int, int)} method.
120     *
121     * @param data the buffer to read the bytes into
122     * @param offset The start offset
123     * @param length The number of bytes to read
124     * @throws EOFException if an end of file is reached unexpectedly
125     * @throws IOException if an I/O error occurs.
126     */
127    @Override
128    public void readFully(final byte[] data, final int offset, final int length) throws IOException, EOFException {
129        int remaining = length;
130
131        while (remaining > 0) {
132            final int location = offset + length - remaining;
133            final int count = read(data, location, remaining);
134
135            if (EOF == count) {
136                throw new EOFException();
137            }
138
139            remaining -= count;
140        }
141    }
142
143    /**
144     * Reads a 4 byte, two's complement little-endian integer.
145     *
146     * @return the read int
147     * @throws EOFException if an end of file is reached unexpectedly
148     * @throws IOException if an I/O error occurs.
149     */
150    @Override
151    public int readInt() throws IOException, EOFException {
152        return EndianUtils.readSwappedInteger(in);
153    }
154
155    /**
156     * Not currently supported - throws {@link UnsupportedOperationException}.
157     *
158     * @return the line read
159     * @throws EOFException if an end of file is reached unexpectedly
160     * @throws IOException if an I/O error occurs
161     * @throws UnsupportedOperationException always
162     */
163    @Override
164    public String readLine() throws IOException, EOFException {
165        throw UnsupportedOperationExceptions.method("readLine");
166    }
167
168    /**
169     * Reads an 8 byte, two's complement little-endian integer.
170     *
171     * @return the read long
172     * @throws EOFException if an end of file is reached unexpectedly
173     * @throws IOException if an I/O error occurs.
174     */
175    @Override
176    public long readLong() throws IOException, EOFException {
177        return EndianUtils.readSwappedLong(in);
178    }
179
180    /**
181     * Reads a 2 byte, two's complement, little-endian integer.
182     *
183     * @return the read short
184     * @throws EOFException if an end of file is reached unexpectedly
185     * @throws IOException if an I/O error occurs.
186     */
187    @Override
188    public short readShort() throws IOException, EOFException {
189        return EndianUtils.readSwappedShort(in);
190    }
191
192    /**
193     * Invokes the delegate's {@code read()} method.
194     *
195     * @return the byte read or -1 if the end of stream
196     * @throws EOFException if an end of file is reached unexpectedly
197     * @throws IOException if an I/O error occurs.
198     */
199    @Override
200    public int readUnsignedByte() throws IOException, EOFException {
201        return in.read();
202    }
203
204    /**
205     * Reads a 2 byte, unsigned, little-endian integer.
206     *
207     * @return the read short
208     * @throws EOFException if an end of file is reached unexpectedly
209     * @throws IOException if an I/O error occurs.
210     */
211    @Override
212    public int readUnsignedShort() throws IOException, EOFException {
213        return EndianUtils.readSwappedUnsignedShort(in);
214    }
215
216    /**
217     * Not currently supported - throws {@link UnsupportedOperationException}.
218     *
219     * @return never
220     * @throws EOFException if an end of file is reached unexpectedly
221     * @throws IOException if an I/O error occurs
222     * @throws UnsupportedOperationException always
223     */
224    @Override
225    public String readUTF() throws IOException, EOFException {
226        throw UnsupportedOperationExceptions.method("readUTF");
227    }
228
229    /**
230     * Invokes the delegate's {@code skip(int)} method.
231     *
232     * @param count the number of bytes to skip
233     * @return the number of bytes skipped or -1 if the end of stream
234     * @throws IOException if an I/O error occurs
235     */
236    @Override
237    public int skipBytes(final int count) throws IOException {
238        return (int) in.skip(count);
239    }
240
241}