Home | History | Annotate | Download | only in unit
      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      */
     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      */
     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      */
     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      */
     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      */
     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      */
     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      */
     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      */
    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      */
    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 
    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 
    250     private ByteArrayHelpers() {
    251         throw new AssertionError();
    252     }
    253 }
    254