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;
018
019import static org.apache.commons.io.IOUtils.EOF;
020
021import java.io.EOFException;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025
026/**
027 * Helps with different endian systems.
028 * <p>
029 * Different computer architectures adopt different conventions for
030 * byte ordering. In so-called "Little Endian" architectures (eg Intel),
031 * the low-order byte is stored in memory at the lowest address, and
032 * subsequent bytes at higher addresses. For "Big Endian" architectures
033 * (eg Motorola), the situation is reversed.
034 * This class helps you solve this incompatibility.
035 * </p>
036 * <p>
037 * Origin of code: Excalibur
038 * </p>
039 *
040 * @see org.apache.commons.io.input.SwappedDataInputStream
041 */
042public class EndianUtils {
043
044    /**
045     * Reads the next byte from the input stream.
046     * @param input  the stream
047     * @return the byte
048     * @throws IOException if the end of file is reached
049     */
050    private static int read(final InputStream input) throws IOException {
051        final int value = input.read();
052        if (EOF == value) {
053            throw new EOFException("Unexpected EOF reached");
054        }
055        return value;
056    }
057
058    /**
059     * Reads a "double" value from a byte array at a given offset. The value is
060     * converted to the opposed endian system while reading.
061     * @param data source byte array
062     * @param offset starting offset in the byte array
063     * @return the value read
064     */
065    public static double readSwappedDouble(final byte[] data, final int offset) {
066        return Double.longBitsToDouble(readSwappedLong(data, offset));
067    }
068
069    /**
070     * Reads a "double" value from an InputStream. The value is
071     * converted to the opposed endian system while reading.
072     * @param input source InputStream
073     * @return the value just read
074     * @throws IOException in case of an I/O problem
075     */
076    public static double readSwappedDouble(final InputStream input) throws IOException {
077        return Double.longBitsToDouble(readSwappedLong(input));
078    }
079
080    /**
081     * Reads a "float" value from a byte array at a given offset. The value is
082     * converted to the opposed endian system while reading.
083     * @param data source byte array
084     * @param offset starting offset in the byte array
085     * @return the value read
086     */
087    public static float readSwappedFloat(final byte[] data, final int offset) {
088        return Float.intBitsToFloat(readSwappedInteger(data, offset));
089    }
090
091    /**
092     * Reads a "float" value from an InputStream. The value is
093     * converted to the opposed endian system while reading.
094     * @param input source InputStream
095     * @return the value just read
096     * @throws IOException in case of an I/O problem
097     */
098    public static float readSwappedFloat(final InputStream input) throws IOException {
099        return Float.intBitsToFloat(readSwappedInteger(input));
100    }
101
102    /**
103     * Reads an "int" value from a byte array at a given offset. The value is
104     * converted to the opposed endian system while reading.
105     * @param data source byte array
106     * @param offset starting offset in the byte array
107     * @return the value read
108     */
109    public static int readSwappedInteger(final byte[] data, final int offset) {
110        return ((data[offset + 0] & 0xff) << 0) +
111            ((data[offset + 1] & 0xff) << 8) +
112            ((data[offset + 2] & 0xff) << 16) +
113            ((data[offset + 3] & 0xff) << 24);
114    }
115
116    /**
117     * Reads an "int" value from an InputStream. The value is
118     * converted to the opposed endian system while reading.
119     * @param input source InputStream
120     * @return the value just read
121     * @throws IOException in case of an I/O problem
122     */
123    public static int readSwappedInteger(final InputStream input) throws IOException {
124        final int value1 = read(input);
125        final int value2 = read(input);
126        final int value3 = read(input);
127        final int value4 = read(input);
128        return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16) + ((value4 & 0xff) << 24);
129    }
130
131    /**
132     * Reads a "long" value from a byte array at a given offset. The value is
133     * converted to the opposed endian system while reading.
134     * @param data source byte array
135     * @param offset starting offset in the byte array
136     * @return the value read
137     */
138    public static long readSwappedLong(final byte[] data, final int offset) {
139        final long low = readSwappedInteger(data, offset);
140        final long high = readSwappedInteger(data, offset + 4);
141        return (high << 32) + (0xffffffffL & low);
142    }
143
144    /**
145     * Reads a "long" value from an InputStream. The value is
146     * converted to the opposed endian system while reading.
147     * @param input source InputStream
148     * @return the value just read
149     * @throws IOException in case of an I/O problem
150     */
151    public static long readSwappedLong(final InputStream input) throws IOException {
152        final byte[] bytes = new byte[8];
153        for (int i = 0; i < 8; i++) {
154            bytes[i] = (byte) read(input);
155        }
156        return readSwappedLong(bytes, 0);
157    }
158
159    /**
160     * Reads a "short" value from a byte array at a given offset. The value is
161     * converted to the opposed endian system while reading.
162     * @param data source byte array
163     * @param offset starting offset in the byte array
164     * @return the value read
165     */
166    public static short readSwappedShort(final byte[] data, final int offset) {
167        return (short)(((data[offset + 0] & 0xff) << 0) +
168            ((data[offset + 1] & 0xff) << 8));
169    }
170
171    /**
172     * Reads a "short" value from an InputStream. The value is
173     * converted to the opposed endian system while reading.
174     * @param input source InputStream
175     * @return the value just read
176     * @throws IOException in case of an I/O problem
177     */
178    public static short readSwappedShort(final InputStream input) throws IOException {
179        return (short) (((read(input) & 0xff) << 0) + ((read(input) & 0xff) << 8));
180    }
181
182    /**
183     * Reads an unsigned integer (32-bit) value from a byte array at a given
184     * offset. The value is converted to the opposed endian system while
185     * reading.
186     * @param data source byte array
187     * @param offset starting offset in the byte array
188     * @return the value read
189     */
190    public static long readSwappedUnsignedInteger(final byte[] data, final int offset) {
191        final long low = ((data[offset + 0] & 0xff) << 0) +
192                     ((data[offset + 1] & 0xff) << 8) +
193                     ((data[offset + 2] & 0xff) << 16);
194        final long high = data[offset + 3] & 0xff;
195        return (high << 24) + (0xffffffffL & low);
196    }
197
198    /**
199     * Reads an unsigned integer (32-bit) from an InputStream. The value is
200     * converted to the opposed endian system while reading.
201     * @param input source InputStream
202     * @return the value just read
203     * @throws IOException in case of an I/O problem
204     */
205    public static long readSwappedUnsignedInteger(final InputStream input) throws IOException {
206        final int value1 = read(input);
207        final int value2 = read(input);
208        final int value3 = read(input);
209        final int value4 = read(input);
210        final long low = ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16);
211        final long high = value4 & 0xff;
212        return (high << 24) + (0xffffffffL & low);
213    }
214
215    /**
216     * Reads an unsigned short (16-bit) value from a byte array at a given
217     * offset. The value is converted to the opposed endian system while
218     * reading.
219     * @param data source byte array
220     * @param offset starting offset in the byte array
221     * @return the value read
222     */
223    public static int readSwappedUnsignedShort(final byte[] data, final int offset) {
224        return ((data[offset + 0] & 0xff) << 0) +
225            ((data[offset + 1] & 0xff) << 8);
226    }
227
228    /**
229     * Reads an unsigned short (16-bit) from an InputStream. The value is
230     * converted to the opposed endian system while reading.
231     * @param input source InputStream
232     * @return the value just read
233     * @throws IOException in case of an I/O problem
234     */
235    public static int readSwappedUnsignedShort(final InputStream input) throws IOException {
236        final int value1 = read(input);
237        final int value2 = read(input);
238
239        return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8);
240    }
241
242    /**
243     * Converts a "double" value between endian systems.
244     * @param value value to convert
245     * @return the converted value
246     */
247    public static double swapDouble(final double value) {
248        return Double.longBitsToDouble(swapLong(Double.doubleToLongBits(value)));
249    }
250
251    /**
252     * Converts a "float" value between endian systems.
253     * @param value value to convert
254     * @return the converted value
255     */
256    public static float swapFloat(final float value) {
257        return Float.intBitsToFloat(swapInteger(Float.floatToIntBits(value)));
258    }
259
260    /**
261     * Converts an "int" value between endian systems.
262     * @param value value to convert
263     * @return the converted value
264     */
265    public static int swapInteger(final int value) {
266        return
267            ((value >> 0 & 0xff) << 24) +
268            ((value >> 8 & 0xff) << 16) +
269            ((value >> 16 & 0xff) << 8) +
270            ((value >> 24 & 0xff) << 0);
271    }
272
273    /**
274     * Converts a "long" value between endian systems.
275     * @param value value to convert
276     * @return the converted value
277     */
278    public static long swapLong(final long value) {
279        return
280            ((value >> 0 & 0xff) << 56) +
281            ((value >> 8 & 0xff) << 48) +
282            ((value >> 16 & 0xff) << 40) +
283            ((value >> 24 & 0xff) << 32) +
284            ((value >> 32 & 0xff) << 24) +
285            ((value >> 40 & 0xff) << 16) +
286            ((value >> 48 & 0xff) << 8) +
287            ((value >> 56 & 0xff) << 0);
288    }
289
290    /**
291     * Converts a "short" value between endian systems.
292     * @param value value to convert
293     * @return the converted value
294     */
295    public static short swapShort(final short value) {
296        return (short) (((value >> 0 & 0xff) << 8) +
297            ((value >> 8 & 0xff) << 0));
298    }
299
300    /**
301     * Writes a "double" value to a byte array at a given offset. The value is
302     * converted to the opposed endian system while writing.
303     * @param data target byte array
304     * @param offset starting offset in the byte array
305     * @param value value to write
306     */
307    public static void writeSwappedDouble(final byte[] data, final int offset, final double value) {
308        writeSwappedLong(data, offset, Double.doubleToLongBits(value));
309    }
310
311    /**
312     * Writes a "double" value to an OutputStream. The value is
313     * converted to the opposed endian system while writing.
314     * @param output target OutputStream
315     * @param value value to write
316     * @throws IOException in case of an I/O problem
317     */
318    public static void writeSwappedDouble(final OutputStream output, final double value) throws IOException {
319        writeSwappedLong(output, Double.doubleToLongBits(value));
320    }
321
322    /**
323     * Writes a "float" value to a byte array at a given offset. The value is
324     * converted to the opposed endian system while writing.
325     * @param data target byte array
326     * @param offset starting offset in the byte array
327     * @param value value to write
328     */
329    public static void writeSwappedFloat(final byte[] data, final int offset, final float value) {
330        writeSwappedInteger(data, offset, Float.floatToIntBits(value));
331    }
332
333    /**
334     * Writes a "float" value to an OutputStream. The value is
335     * converted to the opposed endian system while writing.
336     * @param output target OutputStream
337     * @param value value to write
338     * @throws IOException in case of an I/O problem
339     */
340    public static void writeSwappedFloat(final OutputStream output, final float value) throws IOException {
341        writeSwappedInteger(output, Float.floatToIntBits(value));
342    }
343
344    /**
345     * Writes an "int" value to a byte array at a given offset. The value is
346     * converted to the opposed endian system while writing.
347     * @param data target byte array
348     * @param offset starting offset in the byte array
349     * @param value value to write
350     */
351    public static void writeSwappedInteger(final byte[] data, final int offset, final int value) {
352        data[offset + 0] = (byte) (value >> 0 & 0xff);
353        data[offset + 1] = (byte) (value >> 8 & 0xff);
354        data[offset + 2] = (byte) (value >> 16 & 0xff);
355        data[offset + 3] = (byte) (value >> 24 & 0xff);
356    }
357
358    /**
359     * Writes an "int" value to an OutputStream. The value is converted to the opposed endian system while writing.
360     *
361     * @param output target OutputStream
362     * @param value value to write
363     * @throws IOException in case of an I/O problem
364     */
365    public static void writeSwappedInteger(final OutputStream output, final int value) throws IOException {
366        output.write((byte) (value >> 0 & 0xff));
367        output.write((byte) (value >> 8 & 0xff));
368        output.write((byte) (value >> 16 & 0xff));
369        output.write((byte) (value >> 24 & 0xff));
370    }
371
372    /**
373     * Writes a "long" value to a byte array at a given offset. The value is
374     * converted to the opposed endian system while writing.
375     * @param data target byte array
376     * @param offset starting offset in the byte array
377     * @param value value to write
378     */
379    public static void writeSwappedLong(final byte[] data, final int offset, final long value) {
380        data[offset + 0] = (byte) (value >> 0 & 0xff);
381        data[offset + 1] = (byte) (value >> 8 & 0xff);
382        data[offset + 2] = (byte) (value >> 16 & 0xff);
383        data[offset + 3] = (byte) (value >> 24 & 0xff);
384        data[offset + 4] = (byte) (value >> 32 & 0xff);
385        data[offset + 5] = (byte) (value >> 40 & 0xff);
386        data[offset + 6] = (byte) (value >> 48 & 0xff);
387        data[offset + 7] = (byte) (value >> 56 & 0xff);
388    }
389
390    /**
391     * Writes a "long" value to an OutputStream. The value is
392     * converted to the opposed endian system while writing.
393     * @param output target OutputStream
394     * @param value value to write
395     * @throws IOException in case of an I/O problem
396     */
397    public static void writeSwappedLong(final OutputStream output, final long value) throws IOException {
398        output.write((byte) (value >> 0 & 0xff));
399        output.write((byte) (value >> 8 & 0xff));
400        output.write((byte) (value >> 16 & 0xff));
401        output.write((byte) (value >> 24 & 0xff));
402        output.write((byte) (value >> 32 & 0xff));
403        output.write((byte) (value >> 40 & 0xff));
404        output.write((byte) (value >> 48 & 0xff));
405        output.write((byte) (value >> 56 & 0xff));
406    }
407
408    /**
409     * Writes a "short" value to a byte array at a given offset. The value is
410     * converted to the opposed endian system while writing.
411     * @param data target byte array
412     * @param offset starting offset in the byte array
413     * @param value value to write
414     */
415    public static void writeSwappedShort(final byte[] data, final int offset, final short value) {
416        data[offset + 0] = (byte)(value >> 0 & 0xff);
417        data[offset + 1] = (byte)(value >> 8 & 0xff);
418    }
419
420    /**
421     * Writes a "short" value to an OutputStream. The value is
422     * converted to the opposed endian system while writing.
423     * @param output target OutputStream
424     * @param value value to write
425     * @throws IOException in case of an I/O problem
426     */
427    public static void writeSwappedShort(final OutputStream output, final short value) throws IOException {
428        output.write((byte) (value >> 0 & 0xff));
429        output.write((byte) (value >> 8 & 0xff));
430    }
431
432    /**
433     * Instances should NOT be constructed in standard programming.
434     */
435    public EndianUtils() {
436    }
437}