/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mediaframeworktest.unit; import android.util.Log; import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; public class ByteArrayHelpers { private static final String TAG = "ByteArrayHelpers"; private static boolean VERBOSE = false; /** * Convert an array of byte primitives to a {@code byte[]} using native endian order. * *

This function is a pass-through; it's here only to provide overloads for * every single type of primitive arrays. * * @param array array of primitives * @return array */ public static byte[] toByteArray(byte[] array) { return array; } /** * Convert an array of shorts to a {@code byte[]} using native endian order. * * @param array array of shorts * @return array converted into byte array using native endian order */ public static byte[] toByteArray(short[] array) { return toByteArray(array, Short.SIZE); } /** * Convert an array of chars to a {@code byte[]} using native endian order. * * @param array array of chars * @return array converted into byte array using native endian order */ public static byte[] toByteArray(char[] array) { return toByteArray(array, Character.SIZE); } /** * Convert an array of ints to a {@code byte[]} using native endian order. * * @param array array of ints * @return array converted into byte array using native endian order */ public static byte[] toByteArray(int[] array) { return toByteArray(array, Integer.SIZE); } /** * Convert an array of longs to a {@code byte[]} using native endian order. * * @param array array of longs * @return array converted into byte array using native endian order */ public static byte[] toByteArray(long[] array) { return toByteArray(array, Long.SIZE); } /** * Convert an array of floats to a {@code byte[]} using native endian order. * * @param array array of floats * @return array converted into byte array using native endian order */ public static byte[] toByteArray(float[] array) { return toByteArray(array, Float.SIZE); } /** * Convert an array of doubles to a {@code byte[]} using native endian order. * * @param array array of doubles * @return array converted into byte array using native endian order */ public static byte[] toByteArray(double[] array) { return toByteArray(array, Double.SIZE); } /** * Convert an array of primitives to a {@code byte[]} using native endian order. * *

Arguments other than arrays are not supported. The array component must be primitive, * the wrapper class is not allowed (e.g. {@code int[]} is ok, but {@code Integer[]} is not.

* * @param array array of primitives * @return array converted into byte array using native endian order * * @throws IllegalArgumentException if {@code array} was not an array of primitives */ public static byte[] toByteArray(T array) { @SuppressWarnings("unchecked") Class klass = (Class) array.getClass(); if (!klass.isArray()) { throw new IllegalArgumentException("array class must be an array"); } Class componentClass = klass.getComponentType(); if (!componentClass.isPrimitive()) { throw new IllegalArgumentException("array's component must be a primitive"); } int sizeInBits; if (klass == int.class) { sizeInBits = Integer.SIZE; } else if (klass == float.class) { sizeInBits = Float.SIZE; } else if (klass == double.class) { sizeInBits = Double.SIZE; } else if (klass == short.class) { sizeInBits = Short.SIZE; } else if (klass == char.class) { sizeInBits = Character.SIZE; } else if (klass == long.class) { sizeInBits = Long.SIZE; } else if (klass == byte.class) { sizeInBits = Byte.SIZE; } else { throw new AssertionError(); } return toByteArray(array, sizeInBits); } /** * Convert a variadic list of {@code Number}s into a byte array using native endian order. * *

Each {@link Number} must be an instance of a primitive wrapper class * (e.g. {@link Integer} is OK, since it wraps {@code int}, but {@code BigInteger} is not.

* * @param numbers variadic list of numeric values * @return array converted into byte array using native endian order * * @throws IllegalArgumentException * if {@code numbers} contained a class that wasn't a primitive wrapper */ public static byte[] toByteArray(Number... numbers) { if (numbers.length == 0) { throw new IllegalArgumentException("too few numbers"); } if (VERBOSE) Log.v(TAG, "toByteArray - input: " + Arrays.toString(numbers)); // Have a large enough capacity to fit in every number as a double ByteBuffer byteBuffer = ByteBuffer.allocate(numbers.length * (Double.SIZE / Byte.SIZE)) .order(ByteOrder.nativeOrder()); for (int i = 0; i < numbers.length; ++i) { Number value = numbers[i]; Class klass = value.getClass(); if (VERBOSE) Log.v(TAG, "toByteArray - number " + i + ", class " + klass); if (klass == Integer.class) { byteBuffer.putInt((Integer)value); } else if (klass == Float.class) { byteBuffer.putFloat((Float)value); } else if (klass == Double.class) { byteBuffer.putDouble((Double)value); } else if (klass == Short.class) { byteBuffer.putShort((Short)value); } else if (klass == Long.class) { byteBuffer.putLong((Long)value); } else if (klass == Byte.class) { byteBuffer.put((Byte)value); } else { throw new IllegalArgumentException( "number class invalid; must be wrapper around primitive class"); } } if (VERBOSE) Log.v(TAG, "toByteArray - end of loop"); // Each number written is at least 1 byte, so the position should be at least length if (numbers.length != 0 && byteBuffer.position() < numbers.length) { throw new AssertionError(String.format( "Had %d numbers, but byte buffer position was only %d", numbers.length, byteBuffer.position())); } byteBuffer.flip(); byte[] bytes = new byte[byteBuffer.limit()]; byteBuffer.get(bytes); if (VERBOSE) Log.v(TAG, "toByteArray - output: " + Arrays.toString(bytes)); return bytes; } private static byte[] toByteArray(T array, int sizeOfTBits) { @SuppressWarnings("unchecked") Class klass = (Class) array.getClass(); if (!klass.isArray()) { throw new IllegalArgumentException("array class must be an array"); } int sizeOfT = sizeOfTBits / Byte.SIZE; int byteLength = Array.getLength(array) * sizeOfT; if (klass == byte[].class) { // Always return a copy return Arrays.copyOf((byte[])array, byteLength); } ByteBuffer byteBuffer = ByteBuffer.allocate(byteLength).order(ByteOrder.nativeOrder()); if (klass == int[].class) { byteBuffer.asIntBuffer().put((int[])array); } else if (klass == float[].class) { byteBuffer.asFloatBuffer().put((float[])array); } else if (klass == double[].class) { byteBuffer.asDoubleBuffer().put((double[])array); } else if (klass == short[].class) { byteBuffer.asShortBuffer().put((short[])array); } else if (klass == char[].class) { byteBuffer.asCharBuffer().put((char[])array); } else if (klass == long[].class) { byteBuffer.asLongBuffer().put((long[])array); } else { throw new IllegalArgumentException("array class invalid; must be a primitive array"); } return byteBuffer.array(); } private ByteArrayHelpers() { throw new AssertionError(); } }