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 }