    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}