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.imaging.common; 018 019import java.nio.ByteOrder; 020import java.util.Arrays; 021 022/** 023 * Convenience methods for converting data types to and from byte arrays. 024 */ 025public final class ByteConversions { 026 public static byte[] toBytes(final double value, final ByteOrder byteOrder) { 027 final byte[] result = new byte[8]; 028 toBytes(value, byteOrder, result, 0); 029 return result; 030 } 031 032 private static void toBytes(final double value, final ByteOrder byteOrder, final byte[] result, final int offset) { 033 final long bits = Double.doubleToRawLongBits(value); 034 if (byteOrder == ByteOrder.LITTLE_ENDIAN) { 035 result[offset + 0] = (byte) (0xff & bits >> 0); 036 result[offset + 1] = (byte) (0xff & bits >> 8); 037 result[offset + 2] = (byte) (0xff & bits >> 16); 038 result[offset + 3] = (byte) (0xff & bits >> 24); 039 result[offset + 4] = (byte) (0xff & bits >> 32); 040 result[offset + 5] = (byte) (0xff & bits >> 40); 041 result[offset + 6] = (byte) (0xff & bits >> 48); 042 result[offset + 7] = (byte) (0xff & bits >> 56); 043 } else { 044 result[offset + 7] = (byte) (0xff & bits >> 0); 045 result[offset + 6] = (byte) (0xff & bits >> 8); 046 result[offset + 5] = (byte) (0xff & bits >> 16); 047 result[offset + 4] = (byte) (0xff & bits >> 24); 048 result[offset + 3] = (byte) (0xff & bits >> 32); 049 result[offset + 2] = (byte) (0xff & bits >> 40); 050 result[offset + 1] = (byte) (0xff & bits >> 48); 051 result[offset + 0] = (byte) (0xff & bits >> 56); 052 } 053 } 054 055 public static byte[] toBytes(final double[] values, final ByteOrder byteOrder) { 056 return toBytes(values, 0, values.length, byteOrder); 057 } 058 059 private static byte[] toBytes(final double[] values, final int offset, final int length, final ByteOrder byteOrder) { 060 final byte[] result = Allocator.byteArray(length * 8); 061 for (int i = 0; i < length; i++) { 062 toBytes(values[offset + i], byteOrder, result, i * 8); 063 } 064 return result; 065 } 066 067 public static byte[] toBytes(final float value, final ByteOrder byteOrder) { 068 final byte[] result = new byte[4]; 069 toBytes(value, byteOrder, result, 0); 070 return result; 071 } 072 073 private static void toBytes(final float value, final ByteOrder byteOrder, final byte[] result, final int offset) { 074 final int bits = Float.floatToRawIntBits(value); 075 if (byteOrder == ByteOrder.LITTLE_ENDIAN) { 076 result[offset + 0] = (byte) (0xff & bits >> 0); 077 result[offset + 1] = (byte) (0xff & bits >> 8); 078 result[offset + 2] = (byte) (0xff & bits >> 16); 079 result[offset + 3] = (byte) (0xff & bits >> 24); 080 } else { 081 result[offset + 3] = (byte) (0xff & bits >> 0); 082 result[offset + 2] = (byte) (0xff & bits >> 8); 083 result[offset + 1] = (byte) (0xff & bits >> 16); 084 result[offset + 0] = (byte) (0xff & bits >> 24); 085 } 086 } 087 088 public static byte[] toBytes(final float[] values, final ByteOrder byteOrder) { 089 return toBytes(values, 0, values.length, byteOrder); 090 } 091 092 private static byte[] toBytes(final float[] values, final int offset, final int length, final ByteOrder byteOrder) { 093 final byte[] result = Allocator.byteArray(length * 4); 094 for (int i = 0; i < length; i++) { 095 toBytes(values[offset + i], byteOrder, result, i * 4); 096 } 097 return result; 098 } 099 100 public static byte[] toBytes(final int value, final ByteOrder byteOrder) { 101 final byte[] result = new byte[4]; 102 toBytes(value, byteOrder, result, 0); 103 return result; 104 } 105 106 private static void toBytes(final int value, final ByteOrder byteOrder, final byte[] result, final int offset) { 107 if (byteOrder == ByteOrder.BIG_ENDIAN) { 108 result[offset + 0] = (byte) (value >> 24); 109 result[offset + 1] = (byte) (value >> 16); 110 result[offset + 2] = (byte) (value >> 8); 111 result[offset + 3] = (byte) (value >> 0); 112 } else { 113 result[offset + 3] = (byte) (value >> 24); 114 result[offset + 2] = (byte) (value >> 16); 115 result[offset + 1] = (byte) (value >> 8); 116 result[offset + 0] = (byte) (value >> 0); 117 } 118 } 119 120 public static byte[] toBytes(final int[] values, final ByteOrder byteOrder) { 121 return toBytes(values, 0, values.length, byteOrder); 122 } 123 124 private static byte[] toBytes(final int[] values, final int offset, final int length, final ByteOrder byteOrder) { 125 final byte[] result = Allocator.byteArray(length * 4); 126 for (int i = 0; i < length; i++) { 127 toBytes(values[offset + i], byteOrder, result, i * 4); 128 } 129 return result; 130 } 131 132 /** 133 * Encodes an eight-byte (long) into an array of bytes based on the specified byte order. 134 * 135 * @param value a standard data primitive of type long 136 * @param byteOrder the byte order to be used for encoding 137 * @return an array of length 8 138 */ 139 public static byte[] toBytes(final long value, final ByteOrder byteOrder) { 140 final byte[] result = new byte[8]; 141 toBytes(value, byteOrder, result, 0); 142 return result; 143 } 144 145 private static void toBytes(final long value, final ByteOrder byteOrder, final byte[] result, final int offset) { 146 if (byteOrder == ByteOrder.BIG_ENDIAN) { 147 result[offset + 0] = (byte) (value >> 56); 148 result[offset + 1] = (byte) (value >> 48); 149 result[offset + 2] = (byte) (value >> 40); 150 result[offset + 3] = (byte) (value >> 32); 151 result[offset + 4] = (byte) (value >> 24); 152 result[offset + 5] = (byte) (value >> 16); 153 result[offset + 6] = (byte) (value >> 8); 154 result[offset + 7] = (byte) value; 155 } else { 156 result[offset + 7] = (byte) (value >> 56); 157 result[offset + 6] = (byte) (value >> 48); 158 result[offset + 5] = (byte) (value >> 40); 159 result[offset + 4] = (byte) (value >> 32); 160 result[offset + 3] = (byte) (value >> 24); 161 result[offset + 2] = (byte) (value >> 16); 162 result[offset + 1] = (byte) (value >> 8); 163 result[offset + 0] = (byte) value; 164 } 165 } 166 167 public static byte[] toBytes(final RationalNumber value, final ByteOrder byteOrder) { 168 final byte[] result = new byte[8]; 169 toBytes(value, byteOrder, result, 0); 170 return result; 171 } 172 173 private static void toBytes(final RationalNumber value, final ByteOrder byteOrder, final byte[] result, final int offset) { 174 if (byteOrder == ByteOrder.BIG_ENDIAN) { 175 result[offset + 0] = (byte) (value.numerator >> 24); 176 result[offset + 1] = (byte) (value.numerator >> 16); 177 result[offset + 2] = (byte) (value.numerator >> 8); 178 result[offset + 3] = (byte) (value.numerator >> 0); 179 result[offset + 4] = (byte) (value.divisor >> 24); 180 result[offset + 5] = (byte) (value.divisor >> 16); 181 result[offset + 6] = (byte) (value.divisor >> 8); 182 result[offset + 7] = (byte) (value.divisor >> 0); 183 } else { 184 result[offset + 3] = (byte) (value.numerator >> 24); 185 result[offset + 2] = (byte) (value.numerator >> 16); 186 result[offset + 1] = (byte) (value.numerator >> 8); 187 result[offset + 0] = (byte) (value.numerator >> 0); 188 result[offset + 7] = (byte) (value.divisor >> 24); 189 result[offset + 6] = (byte) (value.divisor >> 16); 190 result[offset + 5] = (byte) (value.divisor >> 8); 191 result[offset + 4] = (byte) (value.divisor >> 0); 192 } 193 } 194 195 public static byte[] toBytes(final RationalNumber[] values, final ByteOrder byteOrder) { 196 return toBytes(values, 0, values.length, byteOrder); 197 } 198 199 private static byte[] toBytes(final RationalNumber[] values, final int offset, final int length, final ByteOrder byteOrder) { 200 final byte[] result = Allocator.byteArray(length * 8); 201 for (int i = 0; i < length; i++) { 202 toBytes(values[offset + i], byteOrder, result, i * 8); 203 } 204 return result; 205 } 206 207 public static byte[] toBytes(final short value, final ByteOrder byteOrder) { 208 final byte[] result = new byte[2]; 209 toBytes(value, byteOrder, result, 0); 210 return result; 211 } 212 213 private static void toBytes(final short value, final ByteOrder byteOrder, final byte[] result, final int offset) { 214 if (byteOrder == ByteOrder.BIG_ENDIAN) { 215 result[offset + 0] = (byte) (value >> 8); 216 result[offset + 1] = (byte) (value >> 0); 217 } else { 218 result[offset + 1] = (byte) (value >> 8); 219 result[offset + 0] = (byte) (value >> 0); 220 } 221 } 222 223 public static byte[] toBytes(final short[] values, final ByteOrder byteOrder) { 224 return toBytes(values, 0, values.length, byteOrder); 225 } 226 227 private static byte[] toBytes(final short[] values, final int offset, final int length, final ByteOrder byteOrder) { 228 final byte[] result = Allocator.byteArray(length * 2); 229 for (int i = 0; i < length; i++) { 230 toBytes(values[offset + i], byteOrder, result, i * 2); 231 } 232 return result; 233 } 234 235 public static double toDouble(final byte[] bytes, final ByteOrder byteOrder) { 236 return toDouble(bytes, 0, byteOrder); 237 } 238 239 private static double toDouble(final byte[] bytes, final int offset, final ByteOrder byteOrder) { 240 final long byte0 = 0xffL & bytes[offset + 0]; 241 final long byte1 = 0xffL & bytes[offset + 1]; 242 final long byte2 = 0xffL & bytes[offset + 2]; 243 final long byte3 = 0xffL & bytes[offset + 3]; 244 final long byte4 = 0xffL & bytes[offset + 4]; 245 final long byte5 = 0xffL & bytes[offset + 5]; 246 final long byte6 = 0xffL & bytes[offset + 6]; 247 final long byte7 = 0xffL & bytes[offset + 7]; 248 final long bits; 249 if (byteOrder == ByteOrder.BIG_ENDIAN) { 250 bits = byte0 << 56 | byte1 << 48 | byte2 << 40 | byte3 << 32 | byte4 << 24 | byte5 << 16 | byte6 << 8 | byte7 << 0; 251 } else { 252 bits = byte7 << 56 | byte6 << 48 | byte5 << 40 | byte4 << 32 | byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0 << 0; 253 } 254 return Double.longBitsToDouble(bits); 255 } 256 257 public static double[] toDoubles(final byte[] bytes, final ByteOrder byteOrder) { 258 return toDoubles(bytes, 0, bytes.length, byteOrder); 259 } 260 261 private static double[] toDoubles(final byte[] bytes, final int offset, final int length, final ByteOrder byteOrder) { 262 final double[] result = Allocator.doubleArray(length / 8); 263 Arrays.setAll(result, i -> toDouble(bytes, offset + 8 * i, byteOrder)); 264 return result; 265 } 266 267 public static float toFloat(final byte[] bytes, final ByteOrder byteOrder) { 268 return toFloat(bytes, 0, byteOrder); 269 } 270 271 private static float toFloat(final byte[] bytes, final int offset, final ByteOrder byteOrder) { 272 final int byte0 = 0xff & bytes[offset + 0]; 273 final int byte1 = 0xff & bytes[offset + 1]; 274 final int byte2 = 0xff & bytes[offset + 2]; 275 final int byte3 = 0xff & bytes[offset + 3]; 276 final int bits; 277 if (byteOrder == ByteOrder.BIG_ENDIAN) { 278 bits = byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3 << 0; 279 } else { 280 bits = byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0 << 0; 281 } 282 return Float.intBitsToFloat(bits); 283 } 284 285 public static float[] toFloats(final byte[] bytes, final ByteOrder byteOrder) { 286 return toFloats(bytes, 0, bytes.length, byteOrder); 287 } 288 289 private static float[] toFloats(final byte[] bytes, final int offset, final int length, final ByteOrder byteOrder) { 290 final float[] result = Allocator.floatArray(length / 4); 291 for (int i = 0; i < result.length; i++) { 292 result[i] = toFloat(bytes, offset + 4 * i, byteOrder); 293 } 294 return result; 295 } 296 297 public static int toInt(final byte[] bytes, final ByteOrder byteOrder) { 298 return toInt(bytes, 0, byteOrder); 299 } 300 301 public static int toInt(final byte[] bytes, final int offset, final ByteOrder byteOrder) { 302 final int byte0 = 0xff & bytes[offset + 0]; 303 final int byte1 = 0xff & bytes[offset + 1]; 304 final int byte2 = 0xff & bytes[offset + 2]; 305 final int byte3 = 0xff & bytes[offset + 3]; 306 if (byteOrder == ByteOrder.BIG_ENDIAN) { 307 return byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3; 308 } 309 return byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0; 310 } 311 312 public static int[] toInts(final byte[] bytes, final ByteOrder byteOrder) { 313 return toInts(bytes, 0, bytes.length, byteOrder); 314 } 315 316 private static int[] toInts(final byte[] bytes, final int offset, final int length, final ByteOrder byteOrder) { 317 final int[] result = Allocator.intArray(length / 4); 318 Arrays.setAll(result, i -> toInt(bytes, offset + 4 * i, byteOrder)); 319 return result; 320 } 321 322 /** 323 * Extracts an eight-byte long integer from the specified byte array. This method assumes that the byte array is of sufficiently large size to encode a long 324 * integer. 325 * 326 * @param bytes an array of size at least 8 327 * @param byteOrder the byte-order for interpreting the input bytes 328 * @return an eight-byte signed integer 329 */ 330 public static long toLong(final byte[] bytes, final ByteOrder byteOrder) { 331 return toLong(bytes, 0, byteOrder); 332 } 333 334 private static long toLong(final byte[] bytes, final int offset, final ByteOrder byteOrder) { 335 final long byte0 = 0xffL & bytes[offset + 0]; 336 final long byte1 = 0xffL & bytes[offset + 1]; 337 final long byte2 = 0xffL & bytes[offset + 2]; 338 final long byte3 = 0xffL & bytes[offset + 3]; 339 final long byte4 = 0xffL & bytes[offset + 4]; 340 final long byte5 = 0xffL & bytes[offset + 5]; 341 final long byte6 = 0xffL & bytes[offset + 6]; 342 final long byte7 = 0xffL & bytes[offset + 7]; 343 344 if (byteOrder == ByteOrder.BIG_ENDIAN) { 345 return byte0 << 56 | byte1 << 48 | byte2 << 40 | byte3 << 32 | byte4 << 24 | byte5 << 16 | byte6 << 8 | byte7; 346 } 347 return byte7 << 56 | byte6 << 48 | byte5 << 40 | byte4 << 32 | byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0; 348 } 349 350 /** 351 * Extracts an array of eight-byte long integers from the specified array of bytes. The size of the result array is computed based on the size of the input 352 * byte array. 353 * 354 * @param bytes a valid array 355 * @param byteOrder the byte-order for interpreting the input bytes 356 * @return an array of zero or more eight-byte signed integers 357 */ 358 public static long[] toLongs(final byte[] bytes, final ByteOrder byteOrder) { 359 return toLongs(bytes, 0, bytes.length, byteOrder); 360 } 361 362 private static long[] toLongs(final byte[] bytes, final int offset, final int length, final ByteOrder byteOrder) { 363 final long[] result = Allocator.longArray(length / 8); 364 Arrays.setAll(result, i -> toLong(bytes, offset + 8 * i, byteOrder)); 365 return result; 366 } 367 368 /** 369 * Interprets the content of a specified bytes array to create an instance of the RationalNumber class. 370 * 371 * @param bytes a valid array dimensioned to at least 8. 372 * @param byteOrder the byte order for integer conversion 373 * @param unsignedType indicates whether the extracted value is an unsigned type. 374 * @return a valid instance 375 */ 376 public static RationalNumber toRational(final byte[] bytes, final ByteOrder byteOrder, final boolean unsignedType) { 377 return toRational(bytes, 0, byteOrder, unsignedType); 378 } 379 380 private static RationalNumber toRational(final byte[] bytes, final int offset, final ByteOrder byteOrder, final boolean unsignedType) { 381 final int byte0 = 0xff & bytes[offset + 0]; 382 final int byte1 = 0xff & bytes[offset + 1]; 383 final int byte2 = 0xff & bytes[offset + 2]; 384 final int byte3 = 0xff & bytes[offset + 3]; 385 final int byte4 = 0xff & bytes[offset + 4]; 386 final int byte5 = 0xff & bytes[offset + 5]; 387 final int byte6 = 0xff & bytes[offset + 6]; 388 final int byte7 = 0xff & bytes[offset + 7]; 389 final int numerator; 390 final int divisor; 391 if (byteOrder == ByteOrder.BIG_ENDIAN) { 392 numerator = byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3; 393 divisor = byte4 << 24 | byte5 << 16 | byte6 << 8 | byte7; 394 } else { 395 numerator = byte3 << 24 | byte2 << 16 | byte1 << 8 | byte0; 396 divisor = byte7 << 24 | byte6 << 16 | byte5 << 8 | byte4; 397 } 398 return new RationalNumber(numerator, divisor, unsignedType); 399 } 400 401 public static RationalNumber[] toRationals(final byte[] bytes, final ByteOrder byteOrder, final boolean unsignedType) { 402 return toRationals(bytes, 0, bytes.length, byteOrder, unsignedType); 403 } 404 405 private static RationalNumber[] toRationals(final byte[] bytes, final int offset, final int length, final ByteOrder byteOrder, final boolean unsignedType) { 406 final RationalNumber[] result = new RationalNumber[length / 8]; 407 Arrays.setAll(result, i -> toRational(bytes, offset + 8 * i, byteOrder, unsignedType)); 408 return result; 409 } 410 411 public static short toShort(final byte[] bytes, final ByteOrder byteOrder) { 412 return toShort(bytes, 0, byteOrder); 413 } 414 415 private static short toShort(final byte[] bytes, final int offset, final ByteOrder byteOrder) { 416 return (short) toUInt16(bytes, offset, byteOrder); 417 } 418 419 public static short[] toShorts(final byte[] bytes, final ByteOrder byteOrder) { 420 return toShorts(bytes, 0, bytes.length, byteOrder); 421 } 422 423 private static short[] toShorts(final byte[] bytes, final int offset, final int length, final ByteOrder byteOrder) { 424 final short[] result = Allocator.shortArray(length / 2); 425 for (int i = 0; i < result.length; i++) { 426 result[i] = toShort(bytes, offset + 2 * i, byteOrder); 427 } 428 return result; 429 } 430 431 public static int toUInt16(final byte[] bytes, final ByteOrder byteOrder) { 432 return toUInt16(bytes, 0, byteOrder); 433 } 434 435 public static int toUInt16(final byte[] bytes, final int offset, final ByteOrder byteOrder) { 436 final int byte0 = 0xff & bytes[offset + 0]; 437 final int byte1 = 0xff & bytes[offset + 1]; 438 if (byteOrder == ByteOrder.BIG_ENDIAN) { 439 return byte0 << 8 | byte1; 440 } 441 return byte1 << 8 | byte0; 442 } 443 444 public static int[] toUInt16s(final byte[] bytes, final ByteOrder byteOrder) { 445 return toUInt16s(bytes, 0, bytes.length, byteOrder); 446 } 447 448 private static int[] toUInt16s(final byte[] bytes, final int offset, final int length, final ByteOrder byteOrder) { 449 final int[] result = Allocator.intArray(length / 2); 450 Arrays.setAll(result, i -> toUInt16(bytes, offset + 2 * i, byteOrder)); 451 return result; 452 } 453 454 private ByteConversions() { 455 } 456}