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 */
17package org.apache.commons.io;
18
19import java.io.EOFException;
20import java.io.IOException;
21import java.io.InputStream;
22import 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@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 */
40public 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