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