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