1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.mediaframeworktest.unit; 18 19 import android.util.Log; 20 21 import java.lang.reflect.Array; 22 import java.nio.ByteBuffer; 23 import java.nio.ByteOrder; 24 import java.util.Arrays; 25 26 public class ByteArrayHelpers { 27 28 private static final String TAG = "ByteArrayHelpers"; 29 private static boolean VERBOSE = false; 30 31 /** 32 * Convert an array of byte primitives to a {@code byte[]} using native endian order. 33 * 34 * <p>This function is a pass-through; it's here only to provide overloads for 35 * every single type of primitive arrays. 36 * 37 * @param array array of primitives 38 * @return array 39 */ toByteArray(byte[] array)40 public static byte[] toByteArray(byte[] array) { 41 return array; 42 } 43 44 /** 45 * Convert an array of shorts to a {@code byte[]} using native endian order. 46 * 47 * @param array array of shorts 48 * @return array converted into byte array using native endian order 49 */ toByteArray(short[] array)50 public static byte[] toByteArray(short[] array) { 51 return toByteArray(array, Short.SIZE); 52 } 53 54 /** 55 * Convert an array of chars to a {@code byte[]} using native endian order. 56 * 57 * @param array array of chars 58 * @return array converted into byte array using native endian order 59 */ toByteArray(char[] array)60 public static byte[] toByteArray(char[] array) { 61 return toByteArray(array, Character.SIZE); 62 } 63 /** 64 * Convert an array of ints to a {@code byte[]} using native endian order. 65 * 66 * @param array array of ints 67 * @return array converted into byte array using native endian order 68 */ toByteArray(int[] array)69 public static byte[] toByteArray(int[] array) { 70 return toByteArray(array, Integer.SIZE); 71 } 72 /** 73 * Convert an array of longs to a {@code byte[]} using native endian order. 74 * 75 * @param array array of longs 76 * @return array converted into byte array using native endian order 77 */ toByteArray(long[] array)78 public static byte[] toByteArray(long[] array) { 79 return toByteArray(array, Long.SIZE); 80 } 81 /** 82 * Convert an array of floats to a {@code byte[]} using native endian order. 83 * 84 * @param array array of floats 85 * @return array converted into byte array using native endian order 86 */ toByteArray(float[] array)87 public static byte[] toByteArray(float[] array) { 88 return toByteArray(array, Float.SIZE); 89 } 90 /** 91 * Convert an array of doubles to a {@code byte[]} using native endian order. 92 * 93 * @param array array of doubles 94 * @return array converted into byte array using native endian order 95 */ toByteArray(double[] array)96 public static byte[] toByteArray(double[] array) { 97 return toByteArray(array, Double.SIZE); 98 } 99 100 /** 101 * Convert an array of primitives to a {@code byte[]} using native endian order. 102 * 103 * <p>Arguments other than arrays are not supported. The array component must be primitive, 104 * the wrapper class is not allowed (e.g. {@code int[]} is ok, but {@code Integer[]} is not.</p> 105 * 106 * @param array array of primitives 107 * @return array converted into byte array using native endian order 108 * 109 * @throws IllegalArgumentException if {@code array} was not an array of primitives 110 */ toByteArray(T array)111 public static <T> byte[] toByteArray(T array) { 112 @SuppressWarnings("unchecked") 113 Class<T> klass = (Class<T>) array.getClass(); 114 115 if (!klass.isArray()) { 116 throw new IllegalArgumentException("array class must be an array"); 117 } 118 119 Class<?> componentClass = klass.getComponentType(); 120 121 if (!componentClass.isPrimitive()) { 122 throw new IllegalArgumentException("array's component must be a primitive"); 123 } 124 125 int sizeInBits; 126 if (klass == int.class) { 127 sizeInBits = Integer.SIZE; 128 } else if (klass == float.class) { 129 sizeInBits = Float.SIZE; 130 } else if (klass == double.class) { 131 sizeInBits = Double.SIZE; 132 } else if (klass == short.class) { 133 sizeInBits = Short.SIZE; 134 } else if (klass == char.class) { 135 sizeInBits = Character.SIZE; 136 } else if (klass == long.class) { 137 sizeInBits = Long.SIZE; 138 } else if (klass == byte.class) { 139 sizeInBits = Byte.SIZE; 140 } else { 141 throw new AssertionError(); 142 } 143 144 return toByteArray(array, sizeInBits); 145 } 146 147 /** 148 * Convert a variadic list of {@code Number}s into a byte array using native endian order. 149 * 150 * <p>Each {@link Number} must be an instance of a primitive wrapper class 151 * (e.g. {@link Integer} is OK, since it wraps {@code int}, but {@code BigInteger} is not.</p> 152 * 153 * @param numbers variadic list of numeric values 154 * @return array converted into byte array using native endian order 155 * 156 * @throws IllegalArgumentException 157 * if {@code numbers} contained a class that wasn't a primitive wrapper 158 */ toByteArray(Number... numbers)159 public static byte[] toByteArray(Number... numbers) { 160 if (numbers.length == 0) { 161 throw new IllegalArgumentException("too few numbers"); 162 } 163 164 if (VERBOSE) Log.v(TAG, "toByteArray - input: " + Arrays.toString(numbers)); 165 166 // Have a large enough capacity to fit in every number as a double 167 ByteBuffer byteBuffer = ByteBuffer.allocate(numbers.length * (Double.SIZE / Byte.SIZE)) 168 .order(ByteOrder.nativeOrder()); 169 170 for (int i = 0; i < numbers.length; ++i) { 171 Number value = numbers[i]; 172 Class<? extends Number> klass = value.getClass(); 173 174 if (VERBOSE) Log.v(TAG, "toByteArray - number " + i + ", class " + klass); 175 176 if (klass == Integer.class) { 177 byteBuffer.putInt((Integer)value); 178 } else if (klass == Float.class) { 179 byteBuffer.putFloat((Float)value); 180 } else if (klass == Double.class) { 181 byteBuffer.putDouble((Double)value); 182 } else if (klass == Short.class) { 183 byteBuffer.putShort((Short)value); 184 } else if (klass == Long.class) { 185 byteBuffer.putLong((Long)value); 186 } else if (klass == Byte.class) { 187 byteBuffer.put((Byte)value); 188 } else { 189 throw new IllegalArgumentException( 190 "number class invalid; must be wrapper around primitive class"); 191 } 192 } 193 194 if (VERBOSE) Log.v(TAG, "toByteArray - end of loop"); 195 196 // Each number written is at least 1 byte, so the position should be at least length 197 if (numbers.length != 0 && byteBuffer.position() < numbers.length) { 198 throw new AssertionError(String.format( 199 "Had %d numbers, but byte buffer position was only %d", 200 numbers.length, byteBuffer.position())); 201 } 202 203 byteBuffer.flip(); 204 205 byte[] bytes = new byte[byteBuffer.limit()]; 206 byteBuffer.get(bytes); 207 208 if (VERBOSE) Log.v(TAG, "toByteArray - output: " + Arrays.toString(bytes)); 209 210 return bytes; 211 } 212 toByteArray(T array, int sizeOfTBits)213 private static <T> byte[] toByteArray(T array, int sizeOfTBits) { 214 @SuppressWarnings("unchecked") 215 Class<T> klass = (Class<T>) array.getClass(); 216 217 if (!klass.isArray()) { 218 throw new IllegalArgumentException("array class must be an array"); 219 } 220 221 int sizeOfT = sizeOfTBits / Byte.SIZE; 222 int byteLength = Array.getLength(array) * sizeOfT; 223 224 if (klass == byte[].class) { 225 // Always return a copy 226 return Arrays.copyOf((byte[])array, byteLength); 227 } 228 229 ByteBuffer byteBuffer = ByteBuffer.allocate(byteLength).order(ByteOrder.nativeOrder()); 230 231 if (klass == int[].class) { 232 byteBuffer.asIntBuffer().put((int[])array); 233 } else if (klass == float[].class) { 234 byteBuffer.asFloatBuffer().put((float[])array); 235 } else if (klass == double[].class) { 236 byteBuffer.asDoubleBuffer().put((double[])array); 237 } else if (klass == short[].class) { 238 byteBuffer.asShortBuffer().put((short[])array); 239 } else if (klass == char[].class) { 240 byteBuffer.asCharBuffer().put((char[])array); 241 } else if (klass == long[].class) { 242 byteBuffer.asLongBuffer().put((long[])array); 243 } else { 244 throw new IllegalArgumentException("array class invalid; must be a primitive array"); 245 } 246 247 return byteBuffer.array(); 248 } 249 ByteArrayHelpers()250 private ByteArrayHelpers() { 251 throw new AssertionError(); 252 } 253 } 254