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 * <b>Origin of code: </b>Avalon Excalibur (IO)
033 * </p>
034 *
035 */
036public class SwappedDataInputStream extends ProxyInputStream implements DataInput {
037
038    /**
039     * Constructs a SwappedDataInputStream.
040     *
041     * @param input InputStream to read from
042     */
043    public SwappedDataInputStream(final InputStream input) {
044        super(input);
045    }
046
047    /**
048     * Return <code>{@link #readByte()} != 0</code>
049     *
050     * @return false if the byte read is zero, otherwise true
051     * @throws IOException if an I/O error occurs.
052     * @throws EOFException if an end of file is reached unexpectedly
053     */
054    @Override
055    public boolean readBoolean() throws IOException, EOFException {
056        return 0 != readByte();
057    }
058
059    /**
060     * Invokes the delegate's {@code read()} method.
061     *
062     * @return the byte read or -1 if the end of stream
063     * @throws IOException if an I/O error occurs.
064     * @throws EOFException if an end of file is reached unexpectedly
065     */
066    @Override
067    public byte readByte() throws IOException, EOFException {
068        return (byte) in.read();
069    }
070
071    /**
072     * Reads a character delegating to {@link #readShort()}.
073     *
074     * @return the byte read or -1 if the end of stream
075     * @throws IOException if an I/O error occurs.
076     * @throws EOFException if an end of file is reached unexpectedly
077     */
078    @Override
079    public char readChar() throws IOException, EOFException {
080        return (char) readShort();
081    }
082
083    /**
084     * Delegates to {@link EndianUtils#readSwappedDouble(InputStream)}.
085     *
086     * @return the read long
087     * @throws IOException if an I/O error occurs.
088     * @throws EOFException if an end of file is reached unexpectedly
089     */
090    @Override
091    public double readDouble() throws IOException, EOFException {
092        return EndianUtils.readSwappedDouble(in);
093    }
094
095    /**
096     * Delegates to {@link EndianUtils#readSwappedFloat(InputStream)}.
097     *
098     * @return the read long
099     * @throws IOException if an I/O error occurs.
100     * @throws EOFException if an end of file is reached unexpectedly
101     */
102    @Override
103    public float readFloat() throws IOException, EOFException {
104        return EndianUtils.readSwappedFloat(in);
105    }
106
107    /**
108     * Invokes the delegate's {@code read(byte[] data, int, int)} method.
109     *
110     * @param data the buffer to read the bytes into
111     * @throws EOFException if an end of file is reached unexpectedly
112     * @throws IOException if an I/O error occurs.
113     */
114    @Override
115    public void readFully(final byte[] data) throws IOException, EOFException {
116        readFully(data, 0, data.length);
117    }
118
119    /**
120     * Invokes the delegate's {@code read(byte[] data, int, int)} method.
121     *
122     * @param data the buffer to read the bytes into
123     * @param offset The start offset
124     * @param length The number of bytes to read
125     * @throws EOFException if an end of file is reached unexpectedly
126     * @throws IOException if an I/O error occurs.
127     */
128    @Override
129    public void readFully(final byte[] data, final int offset, final int length) throws IOException, EOFException {
130        int remaining = length;
131
132        while (remaining > 0) {
133            final int location = offset + length - remaining;
134            final int count = read(data, location, remaining);
135
136            if (EOF == count) {
137                throw new EOFException();
138            }
139
140            remaining -= count;
141        }
142    }
143
144    /**
145     * Delegates to {@link EndianUtils#readSwappedInteger(InputStream)}.
146     *
147     * @return the read long
148     * @throws EOFException if an end of file is reached unexpectedly
149     * @throws IOException if an I/O error occurs.
150     */
151    @Override
152    public int readInt() throws IOException, EOFException {
153        return EndianUtils.readSwappedInteger(in);
154    }
155
156    /**
157     * Not currently supported - throws {@link UnsupportedOperationException}.
158     *
159     * @return the line read
160     * @throws EOFException if an end of file is reached unexpectedly
161     * @throws IOException if an I/O error occurs.
162     */
163    @Override
164    public String readLine() throws IOException, EOFException {
165        throw UnsupportedOperationExceptions.method("readLine");
166    }
167
168    /**
169     * Delegates to {@link EndianUtils#readSwappedLong(InputStream)}.
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     * Delegates to {@link EndianUtils#readSwappedShort(InputStream)}.
182     *
183     * @return the read long
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     * Delegates to {@link EndianUtils#readSwappedUnsignedShort(InputStream)}.
206     *
207     * @return the read long
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 UTF String read
220     * @throws EOFException if an end of file is reached unexpectedly
221     * @throws IOException if an I/O error occurs.
222     */
223    @Override
224    public String readUTF() throws IOException, EOFException {
225        throw UnsupportedOperationExceptions.method("readUTF");
226    }
227
228    /**
229     * Invokes the delegate's {@code skip(int)} method.
230     *
231     * @param count the number of bytes to skip
232     * @return the number of bytes to skipped or -1 if the end of stream
233     * @throws EOFException if an end of file is reached unexpectedly
234     * @throws IOException if an I/O error occurs.
235     */
236    @Override
237    public int skipBytes(final int count) throws IOException, EOFException {
238        return (int) in.skip(count);
239    }
240
241}