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 */ 017package org.apache.commons.io; 018 019import static org.apache.commons.io.IOUtils.EOF; 020 021import java.io.EOFException; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.OutputStream; 025 026/** 027 * Utility code for dealing with different endian systems. 028 * <p> 029 * Different computer architectures adopt different conventions for 030 * byte ordering. In so-called "Little Endian" architectures (eg Intel), 031 * the low-order byte is stored in memory at the lowest address, and 032 * subsequent bytes at higher addresses. For "Big Endian" architectures 033 * (eg Motorola), the situation is reversed. 034 * This class helps you solve this incompatibility. 035 * <p> 036 * Origin of code: Excalibur 037 * 038 * @see org.apache.commons.io.input.SwappedDataInputStream 039 */ 040public class EndianUtils { 041 042 /** 043 * Instances should NOT be constructed in standard programming. 044 */ 045 public EndianUtils() { 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(final 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(final 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(final 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(final 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(final 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(final byte[] data, final int offset, final 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(final byte[] data, final 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(final byte[] data, final 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(final byte[] data, final int offset, final 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(final byte[] data, final 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(final byte[] data, final int offset) { 184 final long low = ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) + 185 ( ( data[ offset + 1 ] & 0xff ) << 8 ) + 186 ( ( data[ offset + 2 ] & 0xff ) << 16 ) ); 187 188 final 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(final byte[] data, final int offset, final 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(final byte[] data, final int offset) { 219 final long low = readSwappedInteger(data, offset); 220 final long high = readSwappedInteger(data, offset + 4); 221 return (high << 32) + (0xffffffffL & low); 222 } 223 224 /** 225 * Writes a "float" value to a byte array at a given offset. The value is 226 * converted to the opposed endian system while writing. 227 * @param data target byte array 228 * @param offset starting offset in the byte array 229 * @param value value to write 230 */ 231 public static void writeSwappedFloat(final byte[] data, final int offset, final float value) { 232 writeSwappedInteger( data, offset, Float.floatToIntBits( value ) ); 233 } 234 235 /** 236 * Reads a "float" value from a byte array at a given offset. The value is 237 * converted to the opposed endian system while reading. 238 * @param data source byte array 239 * @param offset starting offset in the byte array 240 * @return the value read 241 */ 242 public static float readSwappedFloat(final byte[] data, final int offset) { 243 return Float.intBitsToFloat( readSwappedInteger( data, offset ) ); 244 } 245 246 /** 247 * Writes a "double" value to a byte array at a given offset. The value is 248 * converted to the opposed endian system while writing. 249 * @param data target byte array 250 * @param offset starting offset in the byte array 251 * @param value value to write 252 */ 253 public static void writeSwappedDouble(final byte[] data, final int offset, final double value) { 254 writeSwappedLong( data, offset, Double.doubleToLongBits( value ) ); 255 } 256 257 /** 258 * Reads a "double" value from a byte array at a given offset. The value is 259 * converted to the opposed endian system while reading. 260 * @param data source byte array 261 * @param offset starting offset in the byte array 262 * @return the value read 263 */ 264 public static double readSwappedDouble(final byte[] data, final int offset) { 265 return Double.longBitsToDouble( readSwappedLong( data, offset ) ); 266 } 267 268 /** 269 * Writes a "short" value to an OutputStream. The value is 270 * converted to the opposed endian system while writing. 271 * @param output target OutputStream 272 * @param value value to write 273 * @throws IOException in case of an I/O problem 274 */ 275 public static void writeSwappedShort(final OutputStream output, final short value) throws IOException { 276 output.write((byte) ((value >> 0) & 0xff)); 277 output.write((byte) ((value >> 8) & 0xff)); 278 } 279 280 /** 281 * Reads a "short" value from an InputStream. The value is 282 * converted to the opposed endian system while reading. 283 * @param input source InputStream 284 * @return the value just read 285 * @throws IOException in case of an I/O problem 286 */ 287 public static short readSwappedShort(final InputStream input) throws IOException { 288 return (short) (((read(input) & 0xff) << 0) + ((read(input) & 0xff) << 8)); 289 } 290 291 /** 292 * Reads a unsigned short (16-bit) 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 int readSwappedUnsignedShort(final InputStream input) throws IOException { 299 final int value1 = read(input); 300 final int value2 = read(input); 301 302 return (((value1 & 0xff) << 0) + ((value2 & 0xff) << 8)); 303 } 304 305 /** 306 * Writes a "int" value to an OutputStream. The value is converted to the opposed endian system while writing. 307 * 308 * @param output target OutputStream 309 * @param value value to write 310 * @throws IOException in case of an I/O problem 311 */ 312 public static void writeSwappedInteger(final OutputStream output, final int value) throws IOException { 313 output.write((byte) ((value >> 0) & 0xff)); 314 output.write((byte) ((value >> 8) & 0xff)); 315 output.write((byte) ((value >> 16) & 0xff)); 316 output.write((byte) ((value >> 24) & 0xff)); 317 } 318 319 /** 320 * Reads a "int" value from an InputStream. The value is 321 * converted to the opposed endian system while reading. 322 * @param input source InputStream 323 * @return the value just read 324 * @throws IOException in case of an I/O problem 325 */ 326 public static int readSwappedInteger(final InputStream input) throws IOException { 327 final int value1 = read(input); 328 final int value2 = read(input); 329 final int value3 = read(input); 330 final int value4 = read(input); 331 332 return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16) + ((value4 & 0xff) << 24); 333 } 334 335 /** 336 * Reads a unsigned integer (32-bit) from an InputStream. The value is 337 * converted to the opposed endian system while reading. 338 * @param input source InputStream 339 * @return the value just read 340 * @throws IOException in case of an I/O problem 341 */ 342 public static long readSwappedUnsignedInteger(final InputStream input) throws IOException { 343 final int value1 = read(input); 344 final int value2 = read(input); 345 final int value3 = read(input); 346 final int value4 = read(input); 347 348 final long low = (((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16)); 349 350 final long high = value4 & 0xff; 351 352 return (high << 24) + (0xffffffffL & low); 353 } 354 355 /** 356 * Writes a "long" value to an OutputStream. The value is 357 * converted to the opposed endian system while writing. 358 * @param output target OutputStream 359 * @param value value to write 360 * @throws IOException in case of an I/O problem 361 */ 362 public static void writeSwappedLong(final OutputStream output, final long value) throws IOException { 363 output.write((byte) ((value >> 0) & 0xff)); 364 output.write((byte) ((value >> 8) & 0xff)); 365 output.write((byte) ((value >> 16) & 0xff)); 366 output.write((byte) ((value >> 24) & 0xff)); 367 output.write((byte) ((value >> 32) & 0xff)); 368 output.write((byte) ((value >> 40) & 0xff)); 369 output.write((byte) ((value >> 48) & 0xff)); 370 output.write((byte) ((value >> 56) & 0xff)); 371 } 372 373 /** 374 * Reads a "long" value from an InputStream. The value is 375 * converted to the opposed endian system while reading. 376 * @param input source InputStream 377 * @return the value just read 378 * @throws IOException in case of an I/O problem 379 */ 380 public static long readSwappedLong(final InputStream input) throws IOException { 381 final byte[] bytes = new byte[8]; 382 for (int i = 0; i < 8; i++) { 383 bytes[i] = (byte) read(input); 384 } 385 return readSwappedLong(bytes, 0); 386 } 387 388 /** 389 * Writes a "float" 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 writeSwappedFloat(final OutputStream output, final float value) throws IOException { 396 writeSwappedInteger(output, Float.floatToIntBits(value)); 397 } 398 399 /** 400 * Reads a "float" value from an InputStream. The value is 401 * converted to the opposed endian system while reading. 402 * @param input source InputStream 403 * @return the value just read 404 * @throws IOException in case of an I/O problem 405 */ 406 public static float readSwappedFloat(final InputStream input) throws IOException { 407 return Float.intBitsToFloat(readSwappedInteger(input)); 408 } 409 410 /** 411 * Writes a "double" value to an OutputStream. The value is 412 * converted to the opposed endian system while writing. 413 * @param output target OutputStream 414 * @param value value to write 415 * @throws IOException in case of an I/O problem 416 */ 417 public static void writeSwappedDouble(final OutputStream output, final double value) throws IOException { 418 writeSwappedLong(output, Double.doubleToLongBits(value)); 419 } 420 421 /** 422 * Reads a "double" value from an InputStream. The value is 423 * converted to the opposed endian system while reading. 424 * @param input source InputStream 425 * @return the value just read 426 * @throws IOException in case of an I/O problem 427 */ 428 public static double readSwappedDouble(final InputStream input) throws IOException { 429 return Double.longBitsToDouble(readSwappedLong(input)); 430 } 431 432 /** 433 * Reads the next byte from the input stream. 434 * @param input the stream 435 * @return the byte 436 * @throws IOException if the end of file is reached 437 */ 438 private static int read(final InputStream input) throws IOException { 439 final int value = input.read(); 440 441 if (EOF == value) { 442 throw new EOFException("Unexpected EOF reached"); 443 } 444 445 return value; 446 } 447}