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 }