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 static org.apache.commons.io.IOUtils.EOF;
20  
21  import java.io.EOFException;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  
26  /**
27   * Helps with different endian systems.
28   * <p>
29   * Different computer architectures adopt different conventions for
30   * byte ordering. In so-called "Little Endian" architectures (eg Intel),
31   * the low-order byte is stored in memory at the lowest address, and
32   * subsequent bytes at higher addresses. For "Big Endian" architectures
33   * (eg Motorola), the situation is reversed.
34   * This class helps you solve this incompatibility.
35   * </p>
36   * <p>
37   * Provenance: Excalibur
38   * </p>
39   *
40   * @see org.apache.commons.io.input.SwappedDataInputStream
41   */
42  public class EndianUtils {
43  
44      /**
45       * Reads the next byte from the input stream.
46       * @param input  the stream
47       * @return the byte
48       * @throws IOException if the end of file is reached
49       */
50      private static int read(final InputStream input) throws IOException {
51          final int value = input.read();
52          if (EOF == value) {
53              throw new EOFException("Unexpected EOF reached");
54          }
55          return value;
56      }
57  
58      /**
59       * Reads a "double" value from a byte array at a given offset. The value is
60       * converted to the opposed endian system while reading.
61       * @param data source byte array
62       * @param offset starting offset in the byte array
63       * @return the value read
64       */
65      public static double readSwappedDouble(final byte[] data, final int offset) {
66          return Double.longBitsToDouble(readSwappedLong(data, offset));
67      }
68  
69      /**
70       * Reads a "double" value from an InputStream. The value is
71       * converted to the opposed endian system while reading.
72       * @param input source InputStream
73       * @return the value just read
74       * @throws IOException in case of an I/O problem
75       */
76      public static double readSwappedDouble(final InputStream input) throws IOException {
77          return Double.longBitsToDouble(readSwappedLong(input));
78      }
79  
80      /**
81       * Reads a "float" value from a byte array at a given offset. The value is
82       * converted to the opposed endian system while reading.
83       * @param data source byte array
84       * @param offset starting offset in the byte array
85       * @return the value read
86       */
87      public static float readSwappedFloat(final byte[] data, final int offset) {
88          return Float.intBitsToFloat(readSwappedInteger(data, offset));
89      }
90  
91      /**
92       * Reads a "float" value from an InputStream. The value is
93       * converted to the opposed endian system while reading.
94       * @param input source InputStream
95       * @return the value just read
96       * @throws IOException in case of an I/O problem
97       */
98      public static float readSwappedFloat(final InputStream input) throws IOException {
99          return Float.intBitsToFloat(readSwappedInteger(input));
100     }
101 
102     /**
103      * Reads an "int" value from a byte array at a given offset. The value is
104      * converted to the opposed endian system while reading.
105      * @param data source byte array
106      * @param offset starting offset in the byte array
107      * @return the value read
108      */
109     public static int readSwappedInteger(final byte[] data, final int offset) {
110         return ((data[offset + 0] & 0xff) << 0) +
111             ((data[offset + 1] & 0xff) << 8) +
112             ((data[offset + 2] & 0xff) << 16) +
113             ((data[offset + 3] & 0xff) << 24);
114     }
115 
116     /**
117      * Reads an "int" value from an InputStream. The value is
118      * converted to the opposed endian system while reading.
119      * @param input source InputStream
120      * @return the value just read
121      * @throws IOException in case of an I/O problem
122      */
123     public static int readSwappedInteger(final InputStream input) throws IOException {
124         final int value1 = read(input);
125         final int value2 = read(input);
126         final int value3 = read(input);
127         final int value4 = read(input);
128         return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16) + ((value4 & 0xff) << 24);
129     }
130 
131     /**
132      * Reads a "long" value from a byte array at a given offset. The value is
133      * converted to the opposed endian system while reading.
134      * @param data source byte array
135      * @param offset starting offset in the byte array
136      * @return the value read
137      */
138     public static long readSwappedLong(final byte[] data, final int offset) {
139         final long low = readSwappedInteger(data, offset);
140         final long high = readSwappedInteger(data, offset + 4);
141         return (high << 32) + (0xffffffffL & low);
142     }
143 
144     /**
145      * Reads a "long" value from an InputStream. The value is
146      * converted to the opposed endian system while reading.
147      * @param input source InputStream
148      * @return the value just read
149      * @throws IOException in case of an I/O problem
150      */
151     public static long readSwappedLong(final InputStream input) throws IOException {
152         final byte[] bytes = new byte[8];
153         for (int i = 0; i < 8; i++) {
154             bytes[i] = (byte) read(input);
155         }
156         return readSwappedLong(bytes, 0);
157     }
158 
159     /**
160      * Reads a "short" value from a byte array at a given offset. The value is
161      * converted to the opposed endian system while reading.
162      * @param data source byte array
163      * @param offset starting offset in the byte array
164      * @return the value read
165      */
166     public static short readSwappedShort(final byte[] data, final int offset) {
167         return (short) (((data[offset + 0] & 0xff) << 0) + ((data[offset + 1] & 0xff) << 8));
168     }
169 
170     /**
171      * Reads a "short" value from an InputStream. The value is
172      * converted to the opposed endian system while reading.
173      * @param input source InputStream
174      * @return the value just read
175      * @throws IOException in case of an I/O problem
176      */
177     public static short readSwappedShort(final InputStream input) throws IOException {
178         return (short) (((read(input) & 0xff) << 0) + ((read(input) & 0xff) << 8));
179     }
180 
181     /**
182      * Reads an unsigned integer (32-bit) value from a byte array at a given
183      * offset. The value is converted to the opposed endian system while
184      * reading.
185      * @param data source byte array
186      * @param offset starting offset in the byte array
187      * @return the value read
188      */
189     public static long readSwappedUnsignedInteger(final byte[] data, final int offset) {
190         final long low = ((data[offset + 0] & 0xff) << 0) +
191                      ((data[offset + 1] & 0xff) << 8) +
192                      ((data[offset + 2] & 0xff) << 16);
193         final long high = data[offset + 3] & 0xff;
194         return (high << 24) + (0xffffffffL & low);
195     }
196 
197     /**
198      * Reads an unsigned integer (32-bit) from an InputStream. The value is
199      * converted to the opposed endian system while reading.
200      * @param input source InputStream
201      * @return the value just read
202      * @throws IOException in case of an I/O problem
203      */
204     public static long readSwappedUnsignedInteger(final InputStream input) throws IOException {
205         final int value1 = read(input);
206         final int value2 = read(input);
207         final int value3 = read(input);
208         final int value4 = read(input);
209         final long low = ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16);
210         final long high = value4 & 0xff;
211         return (high << 24) + (0xffffffffL & low);
212     }
213 
214     /**
215      * Reads an unsigned short (16-bit) value from a byte array at a given
216      * offset. The value is converted to the opposed endian system while
217      * reading.
218      * @param data source byte array
219      * @param offset starting offset in the byte array
220      * @return the value read
221      */
222     public static int readSwappedUnsignedShort(final byte[] data, final int offset) {
223         return ((data[offset + 0] & 0xff) << 0) + ((data[offset + 1] & 0xff) << 8);
224     }
225 
226     /**
227      * Reads an unsigned short (16-bit) from an InputStream. The value is
228      * converted to the opposed endian system while reading.
229      * @param input source InputStream
230      * @return the value just read
231      * @throws IOException in case of an I/O problem
232      */
233     public static int readSwappedUnsignedShort(final InputStream input) throws IOException {
234         final int value1 = read(input);
235         final int value2 = read(input);
236 
237         return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8);
238     }
239 
240     /**
241      * Converts a "double" value between endian systems.
242      * @param value value to convert
243      * @return the converted value
244      */
245     public static double swapDouble(final double value) {
246         return Double.longBitsToDouble(swapLong(Double.doubleToLongBits(value)));
247     }
248 
249     /**
250      * Converts a "float" value between endian systems.
251      * @param value value to convert
252      * @return the converted value
253      */
254     public static float swapFloat(final float value) {
255         return Float.intBitsToFloat(swapInteger(Float.floatToIntBits(value)));
256     }
257 
258     /**
259      * Converts an "int" value between endian systems.
260      * @param value value to convert
261      * @return the converted value
262      */
263     public static int swapInteger(final int value) {
264         return
265             ((value >> 0 & 0xff) << 24) +
266             ((value >> 8 & 0xff) << 16) +
267             ((value >> 16 & 0xff) << 8) +
268             ((value >> 24 & 0xff) << 0);
269     }
270 
271     /**
272      * Converts a "long" value between endian systems.
273      * @param value value to convert
274      * @return the converted value
275      */
276     public static long swapLong(final long value) {
277         return
278             ((value >> 0 & 0xff) << 56) +
279             ((value >> 8 & 0xff) << 48) +
280             ((value >> 16 & 0xff) << 40) +
281             ((value >> 24 & 0xff) << 32) +
282             ((value >> 32 & 0xff) << 24) +
283             ((value >> 40 & 0xff) << 16) +
284             ((value >> 48 & 0xff) << 8) +
285             ((value >> 56 & 0xff) << 0);
286     }
287 
288     /**
289      * Converts a "short" value between endian systems.
290      * @param value value to convert
291      * @return the converted value
292      */
293     public static short swapShort(final short value) {
294         return (short) (((value >> 0 & 0xff) << 8) +
295             ((value >> 8 & 0xff) << 0));
296     }
297 
298     /**
299      * Writes a "double" value to a byte array at a given offset. The value is
300      * converted to the opposed endian system while writing.
301      * @param data target byte array
302      * @param offset starting offset in the byte array
303      * @param value value to write
304      */
305     public static void writeSwappedDouble(final byte[] data, final int offset, final double value) {
306         writeSwappedLong(data, offset, Double.doubleToLongBits(value));
307     }
308 
309     /**
310      * Writes a "double" value to an OutputStream. The value is
311      * converted to the opposed endian system while writing.
312      * @param output target OutputStream
313      * @param value value to write
314      * @throws IOException in case of an I/O problem
315      */
316     public static void writeSwappedDouble(final OutputStream output, final double value) throws IOException {
317         writeSwappedLong(output, Double.doubleToLongBits(value));
318     }
319 
320     /**
321      * Writes a "float" value to a byte array at a given offset. The value is
322      * converted to the opposed endian system while writing.
323      * @param data target byte array
324      * @param offset starting offset in the byte array
325      * @param value value to write
326      */
327     public static void writeSwappedFloat(final byte[] data, final int offset, final float value) {
328         writeSwappedInteger(data, offset, Float.floatToIntBits(value));
329     }
330 
331     /**
332      * Writes a "float" value to an OutputStream. The value is
333      * converted to the opposed endian system while writing.
334      * @param output target OutputStream
335      * @param value value to write
336      * @throws IOException in case of an I/O problem
337      */
338     public static void writeSwappedFloat(final OutputStream output, final float value) throws IOException {
339         writeSwappedInteger(output, Float.floatToIntBits(value));
340     }
341 
342     /**
343      * Writes an "int" value to a byte array at a given offset. The value is
344      * converted to the opposed endian system while writing.
345      * @param data target byte array
346      * @param offset starting offset in the byte array
347      * @param value value to write
348      */
349     public static void writeSwappedInteger(final byte[] data, final int offset, final int value) {
350         data[offset + 0] = (byte) (value >> 0 & 0xff);
351         data[offset + 1] = (byte) (value >> 8 & 0xff);
352         data[offset + 2] = (byte) (value >> 16 & 0xff);
353         data[offset + 3] = (byte) (value >> 24 & 0xff);
354     }
355 
356     /**
357      * Writes an "int" value to an OutputStream. The value is converted to the opposed endian system while writing.
358      *
359      * @param output target OutputStream
360      * @param value value to write
361      * @throws IOException in case of an I/O problem
362      */
363     public static void writeSwappedInteger(final OutputStream output, final int value) throws IOException {
364         output.write((byte) (value >> 0 & 0xff));
365         output.write((byte) (value >> 8 & 0xff));
366         output.write((byte) (value >> 16 & 0xff));
367         output.write((byte) (value >> 24 & 0xff));
368     }
369 
370     /**
371      * Writes a "long" value to a byte array at a given offset. The value is
372      * converted to the opposed endian system while writing.
373      * @param data target byte array
374      * @param offset starting offset in the byte array
375      * @param value value to write
376      */
377     public static void writeSwappedLong(final byte[] data, final int offset, final long value) {
378         data[offset + 0] = (byte) (value >> 0 & 0xff);
379         data[offset + 1] = (byte) (value >> 8 & 0xff);
380         data[offset + 2] = (byte) (value >> 16 & 0xff);
381         data[offset + 3] = (byte) (value >> 24 & 0xff);
382         data[offset + 4] = (byte) (value >> 32 & 0xff);
383         data[offset + 5] = (byte) (value >> 40 & 0xff);
384         data[offset + 6] = (byte) (value >> 48 & 0xff);
385         data[offset + 7] = (byte) (value >> 56 & 0xff);
386     }
387 
388     /**
389      * Writes a "long" value to an OutputStream. The value is
390      * converted to the opposed endian system while writing.
391      * @param output target OutputStream
392      * @param value value to write
393      * @throws IOException in case of an I/O problem
394      */
395     public static void writeSwappedLong(final OutputStream output, final long value) throws IOException {
396         output.write((byte) (value >> 0 & 0xff));
397         output.write((byte) (value >> 8 & 0xff));
398         output.write((byte) (value >> 16 & 0xff));
399         output.write((byte) (value >> 24 & 0xff));
400         output.write((byte) (value >> 32 & 0xff));
401         output.write((byte) (value >> 40 & 0xff));
402         output.write((byte) (value >> 48 & 0xff));
403         output.write((byte) (value >> 56 & 0xff));
404     }
405 
406     /**
407      * Writes a "short" value to a byte array at a given offset. The value is
408      * converted to the opposed endian system while writing.
409      * @param data target byte array
410      * @param offset starting offset in the byte array
411      * @param value value to write
412      */
413     public static void writeSwappedShort(final byte[] data, final int offset, final short value) {
414         data[offset + 0] = (byte) (value >> 0 & 0xff);
415         data[offset + 1] = (byte) (value >> 8 & 0xff);
416     }
417 
418     /**
419      * Writes a "short" value to an OutputStream. The value is
420      * converted to the opposed endian system while writing.
421      * @param output target OutputStream
422      * @param value value to write
423      * @throws IOException in case of an I/O problem
424      */
425     public static void writeSwappedShort(final OutputStream output, final short value) throws IOException {
426         output.write((byte) (value >> 0 & 0xff));
427         output.write((byte) (value >> 8 & 0xff));
428     }
429 
430     /**
431      * Instances should NOT be constructed in standard programming.
432      */
433     public EndianUtils() {
434     }
435 }