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}