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 * @author <a href="mailto:peter@apache.org">Peter Donald</a>
037 * @version $Id: EndianUtils.java 539632 2007-05-18 23:37:59Z bayard $
038 * @see org.apache.commons.io.input.SwappedDataInputStream
039 */
040 public 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(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(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(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(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(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 }