    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     */
    017    package org.apache.commons.io;
    018
    019    import java.io.EOFException;
    020    import java.io.IOException;
    021    import java.io.InputStream;
    022    import java.io.OutputStream;
    023
    024    /**
    025     * Utility code for dealing with different endian systems.
    026     * <p>
    027     * Different computer architectures adopt different conventions for
    028     * byte ordering. In so-called "Little Endian" architectures (eg Intel),
    029     * the low-order byte is stored in memory at the lowest address, and
    030     * subsequent bytes at higher addresses. For "Big Endian" architectures
    031     * (eg Motorola), the situation is reversed.
    032     * This class helps you solve this incompatability.
    033     * <p>
    034     * Origin of code: Excalibur
    035     *
    036     * @author <a href="mailto:peter@apache.org">Peter Donald</a>
    037     * @version $Id: EndianUtils.java 539632 2007-05-18 23:37:59Z bayard $
    038     * @see org.apache.commons.io.input.SwappedDataInputStream
    039     */
    040    public 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(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(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(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(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(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(byte[] data, int offset, 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(byte[] data, 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(byte[] data, 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(byte[] data, int offset, 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(byte[] data, 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(byte[] data, int offset) {
    185            long low = ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
    186                         ( ( data[ offset + 1 ] & 0xff ) << 8 ) +
    187                         ( ( data[ offset + 2 ] & 0xff ) << 16 ) );
    188
    189            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(byte[] data, int offset, 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(byte[] data, int offset) {
    220            long low =
    221                ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
    222                ( ( data[ offset + 1 ] & 0xff ) << 8 ) +
    223                ( ( data[ offset + 2 ] & 0xff ) << 16 ) +
    224                ( ( data[ offset + 3 ] & 0xff ) << 24 );
    225            long high =
    226                ( ( data[ offset + 4 ] & 0xff ) << 0 ) +
    227                ( ( data[ offset + 5 ] & 0xff ) << 8 ) +
    228                ( ( data[ offset + 6 ] & 0xff ) << 16 ) +
    229                ( ( data[ offset + 7 ] & 0xff ) << 24 );
    230            return (high << 32) + (0xffffffffL & low);
    231        }
    232
    233        /**
    234         * Writes a "float" value to a byte array at a given offset. The value is
    235         * converted to the opposed endian system while writing.
    236         * @param data target byte array
    237         * @param offset starting offset in the byte array
    238         * @param value value to write
    239         */
    240        public static void writeSwappedFloat(byte[] data, int offset, float value) {
    241            writeSwappedInteger( data, offset, Float.floatToIntBits( value ) );
    242        }
    243
    244        /**
    245         * Reads a "float" value from a byte array at a given offset. The value is
    246         * converted to the opposed endian system while reading.
    247         * @param data source byte array
    248         * @param offset starting offset in the byte array
    249         * @return the value read
    250         */
    251        public static float readSwappedFloat(byte[] data, int offset) {
    252            return Float.intBitsToFloat( readSwappedInteger( data, offset ) );
    253        }
    254
    255        /**
    256         * Writes a "double" value to a byte array at a given offset. The value is
    257         * converted to the opposed endian system while writing.
    258         * @param data target byte array
    259         * @param offset starting offset in the byte array
    260         * @param value value to write
    261         */
    262        public static void writeSwappedDouble(byte[] data, int offset, double value) {
    263            writeSwappedLong( data, offset, Double.doubleToLongBits( value ) );
    264        }
    265
    266        /**
    267         * Reads a "double" value from a byte array at a given offset. The value is
    268         * converted to the opposed endian system while reading.
    269         * @param data source byte array
    270         * @param offset starting offset in the byte array
    271         * @return the value read
    272         */
    273        public static double readSwappedDouble(byte[] data, int offset) {
    274            return Double.longBitsToDouble( readSwappedLong( data, offset ) );
    275        }
    276
    277        /**
    278         * Writes a "short" value to an OutputStream. The value is
    279         * converted to the opposed endian system while writing.
    280         * @param output target OutputStream
    281         * @param value value to write
    282         * @throws IOException in case of an I/O problem
    283         */
    284        public static void writeSwappedShort(OutputStream output, short value)
    285            throws IOException
    286        {
    287            output.write( (byte)( ( value >> 0 ) & 0xff ) );
    288            output.write( (byte)( ( value >> 8 ) & 0xff ) );
    289        }
    290
    291        /**
    292         * Reads a "short" value from an InputStream. The value is
    293         * converted to the opposed endian system while reading.
    294         * @param input source InputStream
    295         * @return the value just read
    296         * @throws IOException in case of an I/O problem
    297         */
    298        public static short readSwappedShort(InputStream input)
    299            throws IOException
    300        {
    301            return (short)( ( ( read( input ) & 0xff ) << 0 ) +
    302                ( ( read( input ) & 0xff ) << 8 ) );
    303        }
    304
    305        /**
    306         * Reads a unsigned short (16-bit) from an InputStream. The value is
    307         * converted to the opposed endian system while reading.
    308         * @param input source InputStream
    309         * @return the value just read
    310         * @throws IOException in case of an I/O problem
    311         */
    312        public static int readSwappedUnsignedShort(InputStream input)
    313            throws IOException
    314        {
    315            int value1 = read( input );
    316            int value2 = read( input );
    317
    318            return ( ( ( value1 & 0xff ) << 0 ) +
    319                ( ( value2 & 0xff ) << 8 ) );
    320        }
    321
    322        /**
    323         * Writes a "int" value to an OutputStream. The value is
    324         * converted to the opposed endian system while writing.
    325         * @param output target OutputStream
    326         * @param value value to write
    327         * @throws IOException in case of an I/O problem
    328         */
    329        public static void writeSwappedInteger(OutputStream output, int value)
    330            throws IOException
    331        {
    332            output.write( (byte)( ( value >> 0 ) & 0xff ) );
    333            output.write( (byte)( ( value >> 8 ) & 0xff ) );
    334            output.write( (byte)( ( value >> 16 ) & 0xff ) );
    335            output.write( (byte)( ( value >> 24 ) & 0xff ) );
    336        }
    337
    338        /**
    339         * Reads a "int" value from an InputStream. The value is
    340         * converted to the opposed endian system while reading.
    341         * @param input source InputStream
    342         * @return the value just read
    343         * @throws IOException in case of an I/O problem
    344         */
    345        public static int readSwappedInteger(InputStream input)
    346            throws IOException
    347        {
    348            int value1 = read( input );
    349            int value2 = read( input );
    350            int value3 = read( input );
    351            int value4 = read( input );
    352
    353            return ( ( value1 & 0xff ) << 0 ) +
    354                ( ( value2 & 0xff ) << 8 ) +
    355                ( ( value3 & 0xff ) << 16 ) +
    356                ( ( value4 & 0xff ) << 24 );
    357        }
    358
    359        /**
    360         * Reads a unsigned integer (32-bit) from an InputStream. The value is
    361         * converted to the opposed endian system while reading.
    362         * @param input source InputStream
    363         * @return the value just read
    364         * @throws IOException in case of an I/O problem
    365         */
    366        public static long readSwappedUnsignedInteger(InputStream input)
    367            throws IOException
    368        {
    369            int value1 = read( input );
    370            int value2 = read( input );
    371            int value3 = read( input );
    372            int value4 = read( input );
    373
    374            long low = ( ( ( value1 & 0xff ) << 0 ) +
    375                         ( ( value2 & 0xff ) << 8 ) +
    376                         ( ( value3 & 0xff ) << 16 ) );
    377
    378            long high = value4 & 0xff;
    379
    380            return (high << 24) + (0xffffffffL & low);
    381        }
    382
    383        /**
    384         * Writes a "long" value to an OutputStream. The value is
    385         * converted to the opposed endian system while writing.
    386         * @param output target OutputStream
    387         * @param value value to write
    388         * @throws IOException in case of an I/O problem
    389         */
    390        public static void writeSwappedLong(OutputStream output, long value)
    391            throws IOException
    392        {
    393            output.write( (byte)( ( value >> 0 ) & 0xff ) );
    394            output.write( (byte)( ( value >> 8 ) & 0xff ) );
    395            output.write( (byte)( ( value >> 16 ) & 0xff ) );
    396            output.write( (byte)( ( value >> 24 ) & 0xff ) );
    397            output.write( (byte)( ( value >> 32 ) & 0xff ) );
    398            output.write( (byte)( ( value >> 40 ) & 0xff ) );
    399            output.write( (byte)( ( value >> 48 ) & 0xff ) );
    400            output.write( (byte)( ( value >> 56 ) & 0xff ) );
    401        }
    402
    403        /**
    404         * Reads a "long" value from an InputStream. The value is
    405         * converted to the opposed endian system while reading.
    406         * @param input source InputStream
    407         * @return the value just read
    408         * @throws IOException in case of an I/O problem
    409         */
    410        public static long readSwappedLong(InputStream input)
    411            throws IOException
    412        {
    413            byte[] bytes = new byte[8];
    414            for ( int i=0; i<8; i++ ) {
    415                bytes[i] = (byte) read( input );
    416            }
    417            return readSwappedLong( bytes, 0 );
    418        }
    419
    420        /**
    421         * Writes a "float" 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 writeSwappedFloat(OutputStream output, float value)
    428            throws IOException
    429        {
    430            writeSwappedInteger( output, Float.floatToIntBits( value ) );
    431        }
    432
    433        /**
    434         * Reads a "float" value from an InputStream. The value is
    435         * converted to the opposed endian system while reading.
    436         * @param input source InputStream
    437         * @return the value just read
    438         * @throws IOException in case of an I/O problem
    439         */
    440        public static float readSwappedFloat(InputStream input)
    441            throws IOException
    442        {
    443            return Float.intBitsToFloat( readSwappedInteger( input ) );
    444        }
    445
    446        /**
    447         * Writes a "double" value to an OutputStream. The value is
    448         * converted to the opposed endian system while writing.
    449         * @param output target OutputStream
    450         * @param value value to write
    451         * @throws IOException in case of an I/O problem
    452         */
    453        public static void writeSwappedDouble(OutputStream output, double value)
    454            throws IOException
    455        {
    456            writeSwappedLong( output, Double.doubleToLongBits( value ) );
    457        }
    458
    459        /**
    460         * Reads a "double" value from an InputStream. The value is
    461         * converted to the opposed endian system while reading.
    462         * @param input source InputStream
    463         * @return the value just read
    464         * @throws IOException in case of an I/O problem
    465         */
    466        public static double readSwappedDouble(InputStream input)
    467            throws IOException
    468        {
    469            return Double.longBitsToDouble( readSwappedLong( input ) );
    470        }
    471
    472        /**
    473         * Reads the next byte from the input stream.
    474         * @param input  the stream
    475         * @return the byte
    476         * @throws IOException if the end of file is reached
    477         */
    478        private static int read(InputStream input)
    479            throws IOException
    480        {
    481            int value = input.read();
    482
    483            if( -1 == value ) {
    484                throw new EOFException( "Unexpected EOF reached" );
    485            }
    486
    487            return value;
    488        }
    489    }