Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c83a07c authored by Etan Cohen's avatar Etan Cohen Committed by Android (Google) Code Review
Browse files

Merge "[AWARE] Enhance TLV utils to support new TLV structs in NAN"

parents 591931fd 912eff09
Loading
Loading
Loading
Loading
+108 −17
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ public class TlvBufferUtils {
    public static class TlvConstructor {
        private int mTypeSize;
        private int mLengthSize;
        private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;

        private byte[] mArray;
        private int mArrayLength;
@@ -84,6 +85,20 @@ public class TlvBufferUtils {
            }
            mTypeSize = typeSize;
            mLengthSize = lengthSize;
            mPosition = 0;
        }

        /**
         * Configure the TLV constructor to use a particular byte order. Should be
         * {@link ByteOrder#BIG_ENDIAN} (the default at construction) or
         * {@link ByteOrder#LITTLE_ENDIAN}.
         *
         * @return The constructor to facilitate chaining
         *         {@code ctr.putXXX(..).putXXX(..)}.
         */
        public TlvConstructor setByteOrder(ByteOrder byteOrder) {
            mByteOrder = byteOrder;
            return this;
        }

        /**
@@ -96,6 +111,7 @@ public class TlvBufferUtils {
        public TlvConstructor wrap(@Nullable byte[] array) {
            mArray = array;
            mArrayLength = (array == null) ? 0 : array.length;
            mPosition = 0;
            return this;
        }

@@ -109,6 +125,7 @@ public class TlvBufferUtils {
        public TlvConstructor allocate(int capacity) {
            mArray = new byte[capacity];
            mArrayLength = capacity;
            mPosition = 0;
            return this;
        }

@@ -154,6 +171,18 @@ public class TlvBufferUtils {
            return this;
        }

        /**
         * Copies a raw byte into the TLV buffer - without a type or a length.
         *
         * @param b The byte to be inserted into the structure.
         * @return The constructor to facilitate chaining {@code cts.putXXX(..).putXXX(..)}.
         */
        public TlvConstructor putRawByte(byte b) {
            checkRawLength(1);
            mArray[mPosition++] = b;
            return this;
        }

        /**
         * Copies a byte array into the TLV with the indicated type. For an LV
         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
@@ -192,6 +221,22 @@ public class TlvBufferUtils {
            return putByteArray(type, array, 0, (array == null) ? 0 : array.length);
        }

        /**
         * Copies a byte array into the TLV - without a type or a length.
         *
         * @param array The array to be copied (in full) into the TLV structure.
         * @return The constructor to facilitate chaining
         *         {@code ctr.putXXX(..).putXXX(..)}.
         */
        public TlvConstructor putRawByteArray(@Nullable byte[] array) {
            if (array == null) return this;

            checkRawLength(array.length);
            System.arraycopy(array, 0, mArray, mPosition, array.length);
            mPosition += array.length;
            return this;
        }

        /**
         * Places a zero length element (i.e. Length field = 0) into the TLV.
         * For an LV formatted structure (i.e. typeLength=0 in
@@ -221,7 +266,7 @@ public class TlvBufferUtils {
        public TlvConstructor putShort(int type, short data) {
            checkLength(2);
            addHeader(type, 2);
            Memory.pokeShort(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
            Memory.pokeShort(mArray, mPosition, data, mByteOrder);
            mPosition += 2;
            return this;
        }
@@ -239,7 +284,7 @@ public class TlvBufferUtils {
        public TlvConstructor putInt(int type, int data) {
            checkLength(4);
            addHeader(type, 4);
            Memory.pokeInt(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
            Memory.pokeInt(mArray, mPosition, data, mByteOrder);
            mPosition += 4;
            return this;
        }
@@ -294,18 +339,24 @@ public class TlvBufferUtils {
            }
        }

        private void checkRawLength(int dataLength) {
            if (mPosition + dataLength > mArrayLength) {
                throw new BufferOverflowException();
            }
        }

        private void addHeader(int type, int length) {
            if (mTypeSize == 1) {
                mArray[mPosition] = (byte) type;
            } else if (mTypeSize == 2) {
                Memory.pokeShort(mArray, mPosition, (short) type, ByteOrder.BIG_ENDIAN);
                Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder);
            }
            mPosition += mTypeSize;

            if (mLengthSize == 1) {
                mArray[mPosition] = (byte) length;
            } else if (mLengthSize == 2) {
                Memory.pokeShort(mArray, mPosition, (short) length, ByteOrder.BIG_ENDIAN);
                Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder);
            }
            mPosition += mLengthSize;
        }
@@ -329,14 +380,20 @@ public class TlvBufferUtils {
         */
        public int length;

        /**
         * Control of the endianess of the TLV element - true for big-endian, false for little-
         * endian.
         */
        public ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;

        /**
         * The Value (V) field - a raw byte array representing the current TLV
         * element where the entry starts at {@link TlvElement#offset}.
         */
        public byte[] refArray;
        private byte[] mRefArray;

        /**
         * The offset to be used into {@link TlvElement#refArray} to access the
         * The offset to be used into {@link TlvElement#mRefArray} to access the
         * raw data representing the current TLV element.
         */
        public int offset;
@@ -344,7 +401,7 @@ public class TlvBufferUtils {
        private TlvElement(int type, int length, @Nullable byte[] refArray, int offset) {
            this.type = type;
            this.length = length;
            this.refArray = refArray;
            mRefArray = refArray;
            this.offset = offset;

            if (offset + length > refArray.length) {
@@ -352,6 +409,15 @@ public class TlvBufferUtils {
            }
        }

        /**
         * Return the raw byte array of the Value (V) field.
         *
         * @return The Value (V) field as a byte array.
         */
        public byte[] getRawData() {
            return Arrays.copyOfRange(mRefArray, offset, offset + length);
        }

        /**
         * Utility function to return a byte representation of a TLV element of
         * length 1. Note: an attempt to call this function on a TLV item whose
@@ -364,7 +430,7 @@ public class TlvBufferUtils {
                throw new IllegalArgumentException(
                        "Accesing a byte from a TLV element of length " + length);
            }
            return refArray[offset];
            return mRefArray[offset];
        }

        /**
@@ -379,7 +445,7 @@ public class TlvBufferUtils {
                throw new IllegalArgumentException(
                        "Accesing a short from a TLV element of length " + length);
            }
            return Memory.peekShort(refArray, offset, ByteOrder.BIG_ENDIAN);
            return Memory.peekShort(mRefArray, offset, byteOrder);
        }

        /**
@@ -394,7 +460,7 @@ public class TlvBufferUtils {
                throw new IllegalArgumentException(
                        "Accesing an int from a TLV element of length " + length);
            }
            return Memory.peekInt(refArray, offset, ByteOrder.BIG_ENDIAN);
            return Memory.peekInt(mRefArray, offset, byteOrder);
        }

        /**
@@ -403,7 +469,7 @@ public class TlvBufferUtils {
         * @return String repersentation of the current TLV element.
         */
        public String getString() {
            return new String(refArray, offset, length);
            return new String(mRefArray, offset, length);
        }
    }

@@ -413,6 +479,7 @@ public class TlvBufferUtils {
    public static class TlvIterable implements Iterable<TlvElement> {
        private int mTypeSize;
        private int mLengthSize;
        private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
        private byte[] mArray;
        private int mArrayLength;

@@ -439,6 +506,13 @@ public class TlvBufferUtils {
            mArrayLength = (array == null) ? 0 : array.length;
        }

        /**
         * Configure the TLV iterator to use little-endian byte ordering.
         */
        public void setByteOrder(ByteOrder byteOrder) {
            mByteOrder = byteOrder;
        }

        /**
         * Prints out a parsed representation of the TLV-formatted byte array.
         * Whenever possible bytes, shorts, and integer are printed out (for
@@ -486,7 +560,7 @@ public class TlvBufferUtils {
        public List<byte[]> toList() {
            List<byte[]> list = new ArrayList<>();
            for (TlvElement tlv : this) {
                list.add(Arrays.copyOfRange(tlv.refArray, tlv.offset, tlv.offset + tlv.length));
                list.add(Arrays.copyOfRange(tlv.mRefArray, tlv.offset, tlv.offset + tlv.length));
            }

            return list;
@@ -516,7 +590,7 @@ public class TlvBufferUtils {
                    if (mTypeSize == 1) {
                        type = mArray[mOffset];
                    } else if (mTypeSize == 2) {
                        type = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
                        type = Memory.peekShort(mArray, mOffset, mByteOrder);
                    }
                    mOffset += mTypeSize;

@@ -524,11 +598,12 @@ public class TlvBufferUtils {
                    if (mLengthSize == 1) {
                        length = mArray[mOffset];
                    } else if (mLengthSize == 2) {
                        length = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
                        length = Memory.peekShort(mArray, mOffset, mByteOrder);
                    }
                    mOffset += mLengthSize;

                    TlvElement tlv = new TlvElement(type, length, mArray, mOffset);
                    tlv.byteOrder = mByteOrder;
                    mOffset += length;
                    return tlv;
                }
@@ -543,7 +618,8 @@ public class TlvBufferUtils {

    /**
     * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length
     * fields correctly fill the specified length (and do not overshoot).
     * fields correctly fill the specified length (and do not overshoot). Uses big-endian
     * byte ordering.
     *
     * @param array The (T)LV array to verify.
     * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2.
@@ -551,6 +627,22 @@ public class TlvBufferUtils {
     * @return A boolean indicating whether the array is valid (true) or invalid (false).
     */
    public static boolean isValid(@Nullable byte[] array, int typeSize, int lengthSize) {
        return isValidEndian(array, typeSize, lengthSize, ByteOrder.BIG_ENDIAN);
    }

    /**
     * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length
     * fields correctly fill the specified length (and do not overshoot).
     *
     * @param array The (T)LV array to verify.
     * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2.
     * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2.
     * @param byteOrder The endianness of the byte array: {@link ByteOrder#BIG_ENDIAN} or
     *                  {@link ByteOrder#LITTLE_ENDIAN}.
     * @return A boolean indicating whether the array is valid (true) or invalid (false).
     */
    public static boolean isValidEndian(@Nullable byte[] array, int typeSize, int lengthSize,
            ByteOrder byteOrder) {
        if (typeSize < 0 || typeSize > 2) {
            throw new IllegalArgumentException(
                    "Invalid arguments - typeSize must be 0, 1, or 2: typeSize=" + typeSize);
@@ -569,8 +661,7 @@ public class TlvBufferUtils {
            if (lengthSize == 1) {
                nextTlvIndex += lengthSize + array[nextTlvIndex];
            } else {
                nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex,
                        ByteOrder.BIG_ENDIAN);
                nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder);
            }
        }

+43 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import java.nio.BufferOverflowException;
import java.util.ArrayList;
import java.util.List;


/**
 * Unit test harness for TlvBufferUtils class.
 */
@@ -68,6 +69,24 @@ public class TlvBufferUtilsTest {
                equalTo(true));
    }

    /**
     * Validate that re-using a TLV by any of the reallocation method resets it completely.
     */
    @Test
    public void testTlvReuse() {
        TlvBufferUtils.TlvConstructor tlv = new TlvBufferUtils.TlvConstructor(1, 1);

        tlv.allocate(10);
        tlv.putByte(0, (byte) 2);
        tlv.putByte(1, (byte) 104);

        collector.checkThat("initial", tlv.getArray(), equalTo(new byte[]{0, 1, 2, 1, 1, 104}));

        tlv.allocate(8);
        tlv.putByte(5, (byte) 7);
        collector.checkThat("re-alloc", tlv.getArray(), equalTo(new byte[]{5, 1, 7}));
    }

    /**
     * Verify that can build a valid TLV from a List of byte[].
     */
@@ -121,6 +140,23 @@ public class TlvBufferUtilsTest {
        List<byte[]> data = new TlvBufferUtils.TlvIterable(0, 1, invalidTlv01).toList();
    }

    /**
     * Validate the API which places raw bytes into the TLV (without a TL structure).
     */
    @Test
    public void testRawPuts() {
        TlvBufferUtils.TlvConstructor tlv = new TlvBufferUtils.TlvConstructor(1, 1);

        tlv.allocate(10);
        tlv.putByte(0, (byte) 2);
        tlv.putRawByte((byte) 55);
        tlv.putByte(1, (byte) 104);
        tlv.putRawByteArray(new byte[]{66, 77});

        collector.checkThat("data", tlv.getArray(),
                equalTo(new byte[]{0, 1, 2, 55, 1, 1, 104, 66, 77}));
    }

    @Test
    public void testTlvIterate() {
        final String ascii = "ABC";
@@ -163,6 +199,7 @@ public class TlvBufferUtilsTest {
        tlv02.putByte(0, (byte) 2);
        tlv02.putString(0, ascii);
        tlv02.putString(0, nonAscii);
        tlv02.putByteArray(0, new byte[]{5, 4, 3, 2, 1});

        TlvBufferUtils.TlvIterable tlv02It = new TlvBufferUtils.TlvIterable(0, 2, tlv02.getArray());
        count = 0;
@@ -181,6 +218,11 @@ public class TlvBufferUtilsTest {
                        equalTo(nonAscii.getBytes().length));
                collector.checkThat("tlv02-correct-iteration-DATA",
                        tlv.getString().equals(nonAscii), equalTo(true));
            } else if (count == 3) {
                collector.checkThat("tlv02-correct-iteration-mLength", tlv.length,
                        equalTo(5));
                collector.checkThat("tlv02-correct-iteration-DATA", tlv.getRawData(),
                        equalTo(new byte[]{5, 4, 3, 2, 1}));
            } else {
                collector.checkThat("Invalid number of iterations in loop - tlv02", true,
                        equalTo(false));
@@ -188,7 +230,7 @@ public class TlvBufferUtilsTest {
            ++count;
        }
        collector.checkThat("Invalid number of iterations outside loop - tlv02", count,
                equalTo(3));
                equalTo(4));

        collector.checkThat("tlv22-valid",
                TlvBufferUtils.isValid(tlv22.getArray(), 2, 2),