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