View Javadoc

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@apache.org">Peter Donald</a>
37   * @version $Id: EndianUtils.java 539638 2007-05-18 23:44:30Z 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 }