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 539632 2007-05-18 23:37:59Z 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 */ EndianUtils()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 */ swapShort(short value)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 */ swapInteger(int value)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 */ swapLong(long value)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 */ swapFloat(float value)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 */ swapDouble(double value)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 */ writeSwappedShort(byte[] data, int offset, short value)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 */ readSwappedShort(byte[] data, int offset)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 */ readSwappedUnsignedShort(byte[] data, int offset)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 */ writeSwappedInteger(byte[] data, int offset, int value)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 */ readSwappedInteger(byte[] data, int offset)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 */ readSwappedUnsignedInteger(byte[] data, int offset)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 */ writeSwappedLong(byte[] data, int offset, long value)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 */ readSwappedLong(byte[] data, int offset)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 */ writeSwappedFloat(byte[] data, int offset, float value)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 */ readSwappedFloat(byte[] data, int offset)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 */ writeSwappedDouble(byte[] data, int offset, double value)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 */ readSwappedDouble(byte[] data, int offset)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 */ writeSwappedShort(OutputStream output, short value)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 */ readSwappedShort(InputStream input)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 */ readSwappedUnsignedShort(InputStream input)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 */ writeSwappedInteger(OutputStream output, int value)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 */ readSwappedInteger(InputStream input)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 */ readSwappedUnsignedInteger(InputStream input)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 */ writeSwappedLong(OutputStream output, long value)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 */ readSwappedLong(InputStream input)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 */ writeSwappedFloat(OutputStream output, float value)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 */ readSwappedFloat(InputStream input)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 */ writeSwappedDouble(OutputStream output, double value)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 */ readSwappedDouble(InputStream input)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 */ read(InputStream input)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 } 490