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 * Helps 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 * <p> 037 * Provenance: Excalibur 038 * </p> 039 * 040 * @see org.apache.commons.io.input.SwappedDataInputStream 041 */ 042public class EndianUtils { 043 044 /** 045 * Reads the next byte from the input stream. 046 * @param input the stream 047 * @return the byte 048 * @throws IOException if the end of file is reached 049 */ 050 private static int read(final InputStream input) throws IOException { 051 final int value = input.read(); 052 if (EOF == value) { 053 throw new EOFException("Unexpected EOF reached"); 054 } 055 return value; 056 } 057 058 /** 059 * Reads a "double" value from a byte array at a given offset. The value is 060 * converted to the opposed endian system while reading. 061 * @param data source byte array 062 * @param offset starting offset in the byte array 063 * @return the value read 064 */ 065 public static double readSwappedDouble(final byte[] data, final int offset) { 066 return Double.longBitsToDouble(readSwappedLong(data, offset)); 067 } 068 069 /** 070 * Reads a "double" value from an InputStream. The value is 071 * converted to the opposed endian system while reading. 072 * @param input source InputStream 073 * @return the value just read 074 * @throws IOException in case of an I/O problem 075 */ 076 public static double readSwappedDouble(final InputStream input) throws IOException { 077 return Double.longBitsToDouble(readSwappedLong(input)); 078 } 079 080 /** 081 * Reads a "float" value from a byte array at a given offset. The value is 082 * converted to the opposed endian system while reading. 083 * @param data source byte array 084 * @param offset starting offset in the byte array 085 * @return the value read 086 */ 087 public static float readSwappedFloat(final byte[] data, final int offset) { 088 return Float.intBitsToFloat(readSwappedInteger(data, offset)); 089 } 090 091 /** 092 * Reads a "float" value from an InputStream. The value is 093 * converted to the opposed endian system while reading. 094 * @param input source InputStream 095 * @return the value just read 096 * @throws IOException in case of an I/O problem 097 */ 098 public static float readSwappedFloat(final InputStream input) throws IOException { 099 return Float.intBitsToFloat(readSwappedInteger(input)); 100 } 101 102 /** 103 * Reads an "int" value from a byte array at a given offset. The value is 104 * converted to the opposed endian system while reading. 105 * @param data source byte array 106 * @param offset starting offset in the byte array 107 * @return the value read 108 */ 109 public static int readSwappedInteger(final byte[] data, final int offset) { 110 return ((data[offset + 0] & 0xff) << 0) + 111 ((data[offset + 1] & 0xff) << 8) + 112 ((data[offset + 2] & 0xff) << 16) + 113 ((data[offset + 3] & 0xff) << 24); 114 } 115 116 /** 117 * Reads an "int" value from an InputStream. The value is 118 * converted to the opposed endian system while reading. 119 * @param input source InputStream 120 * @return the value just read 121 * @throws IOException in case of an I/O problem 122 */ 123 public static int readSwappedInteger(final InputStream input) throws IOException { 124 final int value1 = read(input); 125 final int value2 = read(input); 126 final int value3 = read(input); 127 final int value4 = read(input); 128 return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16) + ((value4 & 0xff) << 24); 129 } 130 131 /** 132 * Reads a "long" value from a byte array at a given offset. The value is 133 * converted to the opposed endian system while reading. 134 * @param data source byte array 135 * @param offset starting offset in the byte array 136 * @return the value read 137 */ 138 public static long readSwappedLong(final byte[] data, final int offset) { 139 final long low = readSwappedInteger(data, offset); 140 final long high = readSwappedInteger(data, offset + 4); 141 return (high << 32) + (0xffffffffL & low); 142 } 143 144 /** 145 * Reads a "long" value from an InputStream. The value is 146 * converted to the opposed endian system while reading. 147 * @param input source InputStream 148 * @return the value just read 149 * @throws IOException in case of an I/O problem 150 */ 151 public static long readSwappedLong(final InputStream input) throws IOException { 152 final byte[] bytes = new byte[8]; 153 for (int i = 0; i < 8; i++) { 154 bytes[i] = (byte) read(input); 155 } 156 return readSwappedLong(bytes, 0); 157 } 158 159 /** 160 * Reads a "short" value from a byte array at a given offset. The value is 161 * converted to the opposed endian system while reading. 162 * @param data source byte array 163 * @param offset starting offset in the byte array 164 * @return the value read 165 */ 166 public static short readSwappedShort(final byte[] data, final int offset) { 167 return (short) (((data[offset + 0] & 0xff) << 0) + ((data[offset + 1] & 0xff) << 8)); 168 } 169 170 /** 171 * Reads a "short" value from an InputStream. The value is 172 * converted to the opposed endian system while reading. 173 * @param input source InputStream 174 * @return the value just read 175 * @throws IOException in case of an I/O problem 176 */ 177 public static short readSwappedShort(final InputStream input) throws IOException { 178 return (short) (((read(input) & 0xff) << 0) + ((read(input) & 0xff) << 8)); 179 } 180 181 /** 182 * Reads an unsigned integer (32-bit) value from a byte array at a given 183 * offset. The value is converted to the opposed endian system while 184 * reading. 185 * @param data source byte array 186 * @param offset starting offset in the byte array 187 * @return the value read 188 */ 189 public static long readSwappedUnsignedInteger(final byte[] data, final int offset) { 190 final long low = ((data[offset + 0] & 0xff) << 0) + 191 ((data[offset + 1] & 0xff) << 8) + 192 ((data[offset + 2] & 0xff) << 16); 193 final long high = data[offset + 3] & 0xff; 194 return (high << 24) + (0xffffffffL & low); 195 } 196 197 /** 198 * Reads an unsigned integer (32-bit) from an InputStream. The value is 199 * converted to the opposed endian system while reading. 200 * @param input source InputStream 201 * @return the value just read 202 * @throws IOException in case of an I/O problem 203 */ 204 public static long readSwappedUnsignedInteger(final InputStream input) throws IOException { 205 final int value1 = read(input); 206 final int value2 = read(input); 207 final int value3 = read(input); 208 final int value4 = read(input); 209 final long low = ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16); 210 final long high = value4 & 0xff; 211 return (high << 24) + (0xffffffffL & low); 212 } 213 214 /** 215 * Reads an unsigned short (16-bit) value from a byte array at a given 216 * offset. The value is converted to the opposed endian system while 217 * reading. 218 * @param data source byte array 219 * @param offset starting offset in the byte array 220 * @return the value read 221 */ 222 public static int readSwappedUnsignedShort(final byte[] data, final int offset) { 223 return ((data[offset + 0] & 0xff) << 0) + ((data[offset + 1] & 0xff) << 8); 224 } 225 226 /** 227 * Reads an unsigned short (16-bit) from an InputStream. The value is 228 * converted to the opposed endian system while reading. 229 * @param input source InputStream 230 * @return the value just read 231 * @throws IOException in case of an I/O problem 232 */ 233 public static int readSwappedUnsignedShort(final InputStream input) throws IOException { 234 final int value1 = read(input); 235 final int value2 = read(input); 236 237 return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8); 238 } 239 240 /** 241 * Converts a "double" value between endian systems. 242 * @param value value to convert 243 * @return the converted value 244 */ 245 public static double swapDouble(final double value) { 246 return Double.longBitsToDouble(swapLong(Double.doubleToLongBits(value))); 247 } 248 249 /** 250 * Converts a "float" value between endian systems. 251 * @param value value to convert 252 * @return the converted value 253 */ 254 public static float swapFloat(final float value) { 255 return Float.intBitsToFloat(swapInteger(Float.floatToIntBits(value))); 256 } 257 258 /** 259 * Converts an "int" value between endian systems. 260 * @param value value to convert 261 * @return the converted value 262 */ 263 public static int swapInteger(final int value) { 264 return 265 ((value >> 0 & 0xff) << 24) + 266 ((value >> 8 & 0xff) << 16) + 267 ((value >> 16 & 0xff) << 8) + 268 ((value >> 24 & 0xff) << 0); 269 } 270 271 /** 272 * Converts a "long" value between endian systems. 273 * @param value value to convert 274 * @return the converted value 275 */ 276 public static long swapLong(final long value) { 277 return 278 ((value >> 0 & 0xff) << 56) + 279 ((value >> 8 & 0xff) << 48) + 280 ((value >> 16 & 0xff) << 40) + 281 ((value >> 24 & 0xff) << 32) + 282 ((value >> 32 & 0xff) << 24) + 283 ((value >> 40 & 0xff) << 16) + 284 ((value >> 48 & 0xff) << 8) + 285 ((value >> 56 & 0xff) << 0); 286 } 287 288 /** 289 * Converts a "short" value between endian systems. 290 * @param value value to convert 291 * @return the converted value 292 */ 293 public static short swapShort(final short value) { 294 return (short) (((value >> 0 & 0xff) << 8) + 295 ((value >> 8 & 0xff) << 0)); 296 } 297 298 /** 299 * Writes a "double" value to a byte array at a given offset. The value is 300 * converted to the opposed endian system while writing. 301 * @param data target byte array 302 * @param offset starting offset in the byte array 303 * @param value value to write 304 */ 305 public static void writeSwappedDouble(final byte[] data, final int offset, final double value) { 306 writeSwappedLong(data, offset, Double.doubleToLongBits(value)); 307 } 308 309 /** 310 * Writes a "double" value to an OutputStream. The value is 311 * converted to the opposed endian system while writing. 312 * @param output target OutputStream 313 * @param value value to write 314 * @throws IOException in case of an I/O problem 315 */ 316 public static void writeSwappedDouble(final OutputStream output, final double value) throws IOException { 317 writeSwappedLong(output, Double.doubleToLongBits(value)); 318 } 319 320 /** 321 * Writes a "float" value to a byte array at a given offset. The value is 322 * converted to the opposed endian system while writing. 323 * @param data target byte array 324 * @param offset starting offset in the byte array 325 * @param value value to write 326 */ 327 public static void writeSwappedFloat(final byte[] data, final int offset, final float value) { 328 writeSwappedInteger(data, offset, Float.floatToIntBits(value)); 329 } 330 331 /** 332 * Writes a "float" value to an OutputStream. The value is 333 * converted to the opposed endian system while writing. 334 * @param output target OutputStream 335 * @param value value to write 336 * @throws IOException in case of an I/O problem 337 */ 338 public static void writeSwappedFloat(final OutputStream output, final float value) throws IOException { 339 writeSwappedInteger(output, Float.floatToIntBits(value)); 340 } 341 342 /** 343 * Writes an "int" value to a byte array at a given offset. The value is 344 * converted to the opposed endian system while writing. 345 * @param data target byte array 346 * @param offset starting offset in the byte array 347 * @param value value to write 348 */ 349 public static void writeSwappedInteger(final byte[] data, final int offset, final int value) { 350 data[offset + 0] = (byte) (value >> 0 & 0xff); 351 data[offset + 1] = (byte) (value >> 8 & 0xff); 352 data[offset + 2] = (byte) (value >> 16 & 0xff); 353 data[offset + 3] = (byte) (value >> 24 & 0xff); 354 } 355 356 /** 357 * Writes an "int" value to an OutputStream. The value is converted to the opposed endian system while writing. 358 * 359 * @param output target OutputStream 360 * @param value value to write 361 * @throws IOException in case of an I/O problem 362 */ 363 public static void writeSwappedInteger(final OutputStream output, final int value) throws IOException { 364 output.write((byte) (value >> 0 & 0xff)); 365 output.write((byte) (value >> 8 & 0xff)); 366 output.write((byte) (value >> 16 & 0xff)); 367 output.write((byte) (value >> 24 & 0xff)); 368 } 369 370 /** 371 * Writes a "long" value to a byte array at a given offset. The value is 372 * converted to the opposed endian system while writing. 373 * @param data target byte array 374 * @param offset starting offset in the byte array 375 * @param value value to write 376 */ 377 public static void writeSwappedLong(final byte[] data, final int offset, final long value) { 378 data[offset + 0] = (byte) (value >> 0 & 0xff); 379 data[offset + 1] = (byte) (value >> 8 & 0xff); 380 data[offset + 2] = (byte) (value >> 16 & 0xff); 381 data[offset + 3] = (byte) (value >> 24 & 0xff); 382 data[offset + 4] = (byte) (value >> 32 & 0xff); 383 data[offset + 5] = (byte) (value >> 40 & 0xff); 384 data[offset + 6] = (byte) (value >> 48 & 0xff); 385 data[offset + 7] = (byte) (value >> 56 & 0xff); 386 } 387 388 /** 389 * Writes a "long" 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 writeSwappedLong(final OutputStream output, final long value) throws IOException { 396 output.write((byte) (value >> 0 & 0xff)); 397 output.write((byte) (value >> 8 & 0xff)); 398 output.write((byte) (value >> 16 & 0xff)); 399 output.write((byte) (value >> 24 & 0xff)); 400 output.write((byte) (value >> 32 & 0xff)); 401 output.write((byte) (value >> 40 & 0xff)); 402 output.write((byte) (value >> 48 & 0xff)); 403 output.write((byte) (value >> 56 & 0xff)); 404 } 405 406 /** 407 * Writes a "short" value to a byte array at a given offset. The value is 408 * converted to the opposed endian system while writing. 409 * @param data target byte array 410 * @param offset starting offset in the byte array 411 * @param value value to write 412 */ 413 public static void writeSwappedShort(final byte[] data, final int offset, final short value) { 414 data[offset + 0] = (byte) (value >> 0 & 0xff); 415 data[offset + 1] = (byte) (value >> 8 & 0xff); 416 } 417 418 /** 419 * Writes a "short" value to an OutputStream. The value is 420 * converted to the opposed endian system while writing. 421 * @param output target OutputStream 422 * @param value value to write 423 * @throws IOException in case of an I/O problem 424 */ 425 public static void writeSwappedShort(final OutputStream output, final short value) throws IOException { 426 output.write((byte) (value >> 0 & 0xff)); 427 output.write((byte) (value >> 8 & 0xff)); 428 } 429 430 /** 431 * Instances should NOT be constructed in standard programming. 432 */ 433 public EndianUtils() { 434 } 435}