Home | History | Annotate | Download | only in io
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 package org.apache.commons.io;
     18 
     19 import java.io.EOFException;
     20 import java.io.IOException;
     21 import java.io.InputStream;
     22 import java.io.OutputStream;
     23 
     24 /**
     25  * Utility code for dealing with different endian systems.
     26  * <p>
     27  * Different computer architectures adopt different conventions for
     28  * byte ordering. In so-called "Little Endian" architectures (eg Intel),
     29  * the low-order byte is stored in memory at the lowest address, and
     30  * subsequent bytes at higher addresses. For "Big Endian" architectures
     31  * (eg Motorola), the situation is reversed.
     32  * This class helps you solve this incompatability.
     33  * <p>
     34  * Origin of code: Excalibur
     35  *
     36  * @author <a href="mailto:peter (at) apache.org">Peter Donald</a>
     37  * @version $Id: EndianUtils.java 539632 2007-05-18 23:37:59Z bayard $
     38  * @see org.apache.commons.io.input.SwappedDataInputStream
     39  */
     40 public class EndianUtils {
     41 
     42     /**
     43      * Instances should NOT be constructed in standard programming.
     44      */
     45     public EndianUtils() {
     46         super();
     47     }
     48 
     49     // ========================================== Swapping routines
     50 
     51     /**
     52      * Converts a "short" value between endian systems.
     53      * @param value value to convert
     54      * @return the converted value
     55      */
     56     public static short swapShort(short value) {
     57         return (short) ( ( ( ( value >> 0 ) & 0xff ) << 8 ) +
     58             ( ( ( value >> 8 ) & 0xff ) << 0 ) );
     59     }
     60 
     61     /**
     62      * Converts a "int" value between endian systems.
     63      * @param value value to convert
     64      * @return the converted value
     65      */
     66     public static int swapInteger(int value) {
     67         return
     68             ( ( ( value >> 0 ) & 0xff ) << 24 ) +
     69             ( ( ( value >> 8 ) & 0xff ) << 16 ) +
     70             ( ( ( value >> 16 ) & 0xff ) << 8 ) +
     71             ( ( ( value >> 24 ) & 0xff ) << 0 );
     72     }
     73 
     74     /**
     75      * Converts a "long" value between endian systems.
     76      * @param value value to convert
     77      * @return the converted value
     78      */
     79     public static long swapLong(long value) {
     80         return
     81             ( ( ( value >> 0 ) & 0xff ) << 56 ) +
     82             ( ( ( value >> 8 ) & 0xff ) << 48 ) +
     83             ( ( ( value >> 16 ) & 0xff ) << 40 ) +
     84             ( ( ( value >> 24 ) & 0xff ) << 32 ) +
     85             ( ( ( value >> 32 ) & 0xff ) << 24 ) +
     86             ( ( ( value >> 40 ) & 0xff ) << 16 ) +
     87             ( ( ( value >> 48 ) & 0xff ) << 8 ) +
     88             ( ( ( value >> 56 ) & 0xff ) << 0 );
     89     }
     90 
     91     /**
     92      * Converts a "float" value between endian systems.
     93      * @param value value to convert
     94      * @return the converted value
     95      */
     96     public static float swapFloat(float value) {
     97         return Float.intBitsToFloat( swapInteger( Float.floatToIntBits( value ) ) );
     98     }
     99 
    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 }
    490