120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen/*
220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * Copyright (C) 2016 The Android Open Source Project
320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen *
420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * Licensed under the Apache License, Version 2.0 (the "License");
520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * you may not use this file except in compliance with the License.
620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * You may obtain a copy of the License at
720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen *
820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen *      http://www.apache.org/licenses/LICENSE-2.0
920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen *
1020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * Unless required by applicable law or agreed to in writing, software
1120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * distributed under the License is distributed on an "AS IS" BASIS,
1220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * See the License for the specific language governing permissions and
1420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * limitations under the License.
1520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen */
1620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
1720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohenpackage android.net.wifi.nan;
1820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
1920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohenimport libcore.io.Memory;
2020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
2120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohenimport java.nio.BufferOverflowException;
2220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohenimport java.nio.ByteOrder;
2320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohenimport java.util.Iterator;
2420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
2520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen/**
2620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * Utility class to construct and parse byte arrays using the TLV format -
2720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * Type/Length/Value format. The utilities accept a configuration of the size of
2820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * the Type field and the Length field. A Type field size of 0 is allowed -
2920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * allowing usage for LV (no T) array formats.
3020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen *
3120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen * @hide PROPOSED_NAN_API
3220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen */
3320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohenpublic class TlvBufferUtils {
3420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    private TlvBufferUtils() {
3520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        // no reason to ever create this class
3620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    }
3720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
3820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    /**
3920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * Utility class to construct byte arrays using the TLV format -
4020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * Type/Length/Value.
4120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * <p>
4220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * A constructor is created specifying the size of the Type (T) and Length
4320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * (L) fields. A specification of zero size T field is allowed - resulting
4420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * in LV type format.
4520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * <p>
4620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * The byte array is either provided (using
4720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * {@link TlvConstructor#wrap(byte[])}) or allocated (using
4820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * {@link TlvConstructor#allocate(int)}).
4920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * <p>
5020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * Values are added to the structure using the {@code TlvConstructor.put*()}
5120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * methods.
5220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * <p>
5320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * The final byte array is obtained using {@link TlvConstructor#getArray()}
5420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * and {@link TlvConstructor#getActualLength()} methods.
5520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     */
5620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    public static class TlvConstructor {
5720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private int mTypeSize;
5820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private int mLengthSize;
5920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
6020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private byte[] mArray;
6120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private int mArrayLength;
6220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private int mPosition;
6320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
6420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
6520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Define a TLV constructor with the specified size of the Type (T) and
6620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Length (L) fields.
6720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
6820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param typeSize Number of bytes used for the Type (T) field. Values
6920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            of 0, 1, or 2 bytes are allowed. A specification of 0
7020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            bytes implies that the field being constructed has the LV
7120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            format rather than the TLV format.
7220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param lengthSize Number of bytes used for the Length (L) field.
7320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            Values of 1 or 2 bytes are allowed.
7420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
7520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor(int typeSize, int lengthSize) {
7620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            if (typeSize < 0 || typeSize > 2 || lengthSize <= 0 || lengthSize > 2) {
7720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                throw new IllegalArgumentException(
7820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        "Invalid sizes - typeSize=" + typeSize + ", lengthSize=" + lengthSize);
7920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
8020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mTypeSize = typeSize;
8120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mLengthSize = lengthSize;
8220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
8320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
8420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
8520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Set the byte array to be used to construct the TLV.
8620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
8720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param array Byte array to be formatted.
8820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
8920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
9020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
9120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor wrap(byte[] array) {
9220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mArray = array;
9320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mArrayLength = array.length;
9420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return this;
9520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
9620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
9720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
9820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Allocates a new byte array to be used ot construct a TLV.
9920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
10020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param capacity The size of the byte array to be allocated.
10120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
10220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
10320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
10420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor allocate(int capacity) {
10520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mArray = new byte[capacity];
10620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mArrayLength = capacity;
10720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return this;
10820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
10920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
11020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
11120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Copies a byte into the TLV with the indicated type. For an LV
11220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
11320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * TlvConstructor(int, int)} ) the type field is ignored.
11420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
11520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param type The value to be placed into the Type field.
11620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param b The byte to be inserted into the structure.
11720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
11820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
11920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
12020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor putByte(int type, byte b) {
12120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            checkLength(1);
12220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            addHeader(type, 1);
12320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mArray[mPosition++] = b;
12420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return this;
12520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
12620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
12720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
12820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Copies a byte array into the TLV with the indicated type. For an LV
12920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
13020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * TlvConstructor(int, int)} ) the type field is ignored.
13120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
13220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param type The value to be placed into the Type field.
13320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param array The array to be copied into the TLV structure.
13420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param offset Start copying from the array at the specified offset.
13520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param length Copy the specified number (length) of bytes from the
13620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            array.
13720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
13820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
13920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
14020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor putByteArray(int type, byte[] array, int offset, int length) {
14120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            checkLength(length);
14220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            addHeader(type, length);
14320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            System.arraycopy(array, offset, mArray, mPosition, length);
14420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mPosition += length;
14520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return this;
14620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
14720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
14820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
14920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Copies a byte array into the TLV with the indicated type. For an LV
15020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
15120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * TlvConstructor(int, int)} ) the type field is ignored.
15220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
15320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param type The value to be placed into the Type field.
15420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param array The array to be copied (in full) into the TLV structure.
15520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
15620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
15720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
15820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor putByteArray(int type, byte[] array) {
15920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return putByteArray(type, array, 0, array.length);
16020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
16120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
16220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
16320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Places a zero length element (i.e. Length field = 0) into the TLV.
16420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * For an LV formatted structure (i.e. typeLength=0 in
16520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * {@link TlvConstructor TlvConstructor(int, int)} ) the type field is
16620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * ignored.
16720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
16820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param type The value to be placed into the Type field.
16920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
17020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
17120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
17220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor putZeroLengthElement(int type) {
17320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            checkLength(0);
17420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            addHeader(type, 0);
17520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return this;
17620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
17720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
17820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
17920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Copies short into the TLV with the indicated type. For an LV
18020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
18120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * TlvConstructor(int, int)} ) the type field is ignored.
18220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
18320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param type The value to be placed into the Type field.
18420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param data The short to be inserted into the structure.
18520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
18620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
18720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
18820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor putShort(int type, short data) {
18920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            checkLength(2);
19020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            addHeader(type, 2);
19120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            Memory.pokeShort(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
19220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mPosition += 2;
19320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return this;
19420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
19520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
19620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
19720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Copies integer into the TLV with the indicated type. For an LV
19820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * formatted structure (i.e. typeLength=0 in {@link TlvConstructor
19920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * TlvConstructor(int, int)} ) the type field is ignored.
20020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
20120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param type The value to be placed into the Type field.
20220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param data The integer to be inserted into the structure.
20320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
20420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
20520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
20620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor putInt(int type, int data) {
20720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            checkLength(4);
20820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            addHeader(type, 4);
20920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            Memory.pokeInt(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
21020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mPosition += 4;
21120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return this;
21220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
21320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
21420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
21520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Copies a String's byte representation into the TLV with the indicated
21620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * type. For an LV formatted structure (i.e. typeLength=0 in
21720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * {@link TlvConstructor TlvConstructor(int, int)} ) the type field is
21820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * ignored.
21920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
22020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param type The value to be placed into the Type field.
22120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param data The string whose bytes are to be inserted into the
22220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            structure.
22320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The constructor to facilitate chaining
22420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *         {@code ctr.putXXX(..).putXXX(..)}.
22520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
22620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvConstructor putString(int type, String data) {
22720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return putByteArray(type, data.getBytes(), 0, data.length());
22820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
22920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
23020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
23120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Returns the constructed TLV formatted byte-array. Note that the
23220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * returned array is the fully wrapped (
23320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * {@link TlvConstructor#wrap(byte[])}) or allocated (
23420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * {@link TlvConstructor#allocate(int)}) array - which isn't necessarily
23520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * the actual size of the formatted data. Use
23620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * {@link TlvConstructor#getActualLength()} to obtain the size of the
23720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * formatted data.
23820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
23920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The byte array containing the TLV formatted structure.
24020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
24120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public byte[] getArray() {
24220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return mArray;
24320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
24420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
24520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
24620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Returns the size of the TLV formatted portion of the wrapped or
24720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * allocated byte array. The array itself is returned with
24820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * {@link TlvConstructor#getArray()}.
24920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
25020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return The size of the TLV formatted portion of the byte array.
25120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
25220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public int getActualLength() {
25320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return mPosition;
25420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
25520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
25620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private void checkLength(int dataLength) {
25720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            if (mPosition + mTypeSize + mLengthSize + dataLength > mArrayLength) {
25820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                throw new BufferOverflowException();
25920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
26020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
26120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
26220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private void addHeader(int type, int length) {
26320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            if (mTypeSize == 1) {
26420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                mArray[mPosition] = (byte) type;
26520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            } else if (mTypeSize == 2) {
26620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                Memory.pokeShort(mArray, mPosition, (short) type, ByteOrder.BIG_ENDIAN);
26720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
26820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mPosition += mTypeSize;
26920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
27020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            if (mLengthSize == 1) {
27120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                mArray[mPosition] = (byte) length;
27220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            } else if (mLengthSize == 2) {
27320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                Memory.pokeShort(mArray, mPosition, (short) length, ByteOrder.BIG_ENDIAN);
27420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
27520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mPosition += mLengthSize;
27620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
27720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    }
27820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
27920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    /**
28020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * Utility class used when iterating over a TLV formatted byte-array. Use
28120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * {@link TlvIterable} to iterate over array. A {@link TlvElement}
28220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * represents each entry in a TLV formatted byte-array.
28320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     */
28420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    public static class TlvElement {
28520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
28620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * The Type (T) field of the current TLV element. Note that for LV
28720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * formatted byte-arrays (i.e. TLV whose Type/T size is 0) the value of
28820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * this field is undefined.
28920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
29020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public int mType;
29120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
29220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
29320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * The Length (L) field of the current TLV element.
29420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
29520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public int mLength;
29620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
29720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
29820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * The Value (V) field - a raw byte array representing the current TLV
29920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * element where the entry starts at {@link TlvElement#mOffset}.
30020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
30120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public byte[] mRefArray;
30220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
30320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
30420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * The offset to be used into {@link TlvElement#mRefArray} to access the
30520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * raw data representing the current TLV element.
30620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
30720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public int mOffset;
30820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
30920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private TlvElement(int type, int length, byte[] refArray, int offset) {
31020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mType = type;
31120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mLength = length;
31220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mRefArray = refArray;
31320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mOffset = offset;
31420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
31520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
31620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
31720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Utility function to return a byte representation of a TLV element of
31820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * length 1. Note: an attempt to call this function on a TLV item whose
31920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * {@link TlvElement#mLength} is != 1 will result in an exception.
32020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
32120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return byte representation of current TLV element.
32220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
32320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public byte getByte() {
32420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            if (mLength != 1) {
32520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                throw new IllegalArgumentException(
32620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        "Accesing a byte from a TLV element of length " + mLength);
32720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
32820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return mRefArray[mOffset];
32920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
33020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
33120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
33220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Utility function to return a short representation of a TLV element of
33320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * length 2. Note: an attempt to call this function on a TLV item whose
33420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * {@link TlvElement#mLength} is != 2 will result in an exception.
33520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
33620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return short representation of current TLV element.
33720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
33820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public short getShort() {
33920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            if (mLength != 2) {
34020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                throw new IllegalArgumentException(
34120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        "Accesing a short from a TLV element of length " + mLength);
34220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
34320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return Memory.peekShort(mRefArray, mOffset, ByteOrder.BIG_ENDIAN);
34420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
34520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
34620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
34720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Utility function to return an integer representation of a TLV element
34820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * of length 4. Note: an attempt to call this function on a TLV item
34920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * whose {@link TlvElement#mLength} is != 4 will result in an exception.
35020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
35120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return integer representation of current TLV element.
35220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
35320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public int getInt() {
35420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            if (mLength != 4) {
35520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                throw new IllegalArgumentException(
35620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        "Accesing an int from a TLV element of length " + mLength);
35720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
35820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return Memory.peekInt(mRefArray, mOffset, ByteOrder.BIG_ENDIAN);
35920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
36020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
36120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
36220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Utility function to return a String representation of a TLV element.
36320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
36420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @return String repersentation of the current TLV element.
36520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
36620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public String getString() {
36720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return new String(mRefArray, mOffset, mLength);
36820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
36920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    }
37020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
37120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    /**
37220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     * Utility class to iterate over a TLV formatted byte-array.
37320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen     */
37420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    public static class TlvIterable implements Iterable<TlvElement> {
37520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private int mTypeSize;
37620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private int mLengthSize;
37720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private byte[] mArray;
37820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        private int mArrayLength;
37920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
38020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
38120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Constructs a TlvIterable object - specifying the format of the TLV
38220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * (the sizes of the Type and Length fields), and the byte array whose
38320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * data is to be parsed.
38420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *
38520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param typeSize Number of bytes used for the Type (T) field. Valid
38620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            values are 0 (i.e. indicating the format is LV rather than
38720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            TLV), 1, and 2 bytes.
38820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param lengthSize Number of bytes sued for the Length (L) field.
38920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            Values values are 1 or 2 bytes.
39020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param array The TLV formatted byte-array to parse.
39120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * @param length The number of bytes of the array to be used in the
39220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         *            parsing.
39320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
39420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public TlvIterable(int typeSize, int lengthSize, byte[] array, int length) {
39520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            if (typeSize < 0 || typeSize > 2 || lengthSize <= 0 || lengthSize > 2) {
39620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                throw new IllegalArgumentException(
39720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        "Invalid sizes - typeSize=" + typeSize + ", lengthSize=" + lengthSize);
39820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
39920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mTypeSize = typeSize;
40020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mLengthSize = lengthSize;
40120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mArray = array;
40220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            mArrayLength = length;
40320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
40420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
40520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
40620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Prints out a parsed representation of the TLV-formatted byte array.
40720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Whenever possible bytes, shorts, and integer are printed out (for
40820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * fields whose length is 1, 2, or 4 respectively).
40920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
41020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        @Override
41120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public String toString() {
41220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            StringBuilder builder = new StringBuilder();
41320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
41420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            builder.append("[");
41520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            boolean first = true;
41620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            for (TlvElement tlv : this) {
41720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                if (!first) {
41820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    builder.append(",");
41920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                }
42020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                first = false;
42120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                builder.append(" (");
42220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                if (mTypeSize != 0) {
42320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    builder.append("T=" + tlv.mType + ",");
42420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                }
42520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                builder.append("L=" + tlv.mLength + ") ");
42620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                if (tlv.mLength == 0) {
42720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    builder.append("<null>");
42820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                } else if (tlv.mLength == 1) {
42920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    builder.append(tlv.getByte());
43020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                } else if (tlv.mLength == 2) {
43120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    builder.append(tlv.getShort());
43220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                } else if (tlv.mLength == 4) {
43320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    builder.append(tlv.getInt());
43420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                } else {
43520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    builder.append("<bytes>");
43620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                }
43720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                if (tlv.mLength != 0) {
43820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    builder.append(" (S='" + tlv.getString() + "')");
43920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                }
44020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            }
44120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            builder.append("]");
44220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
44320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return builder.toString();
44420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
44520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
44620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        /**
44720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * Returns an iterator to step through a TLV formatted byte-array. The
44820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         * individual elements returned by the iterator are {@link TlvElement}.
44920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen         */
45020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        @Override
45120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        public Iterator<TlvElement> iterator() {
45220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            return new Iterator<TlvElement>() {
45320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                private int mOffset = 0;
45420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
45520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                @Override
45620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                public boolean hasNext() {
45720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    return mOffset < mArrayLength;
45820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                }
45920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
46020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                @Override
46120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                public TlvElement next() {
46220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    int type = 0;
46320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    if (mTypeSize == 1) {
46420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        type = mArray[mOffset];
46520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    } else if (mTypeSize == 2) {
46620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        type = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
46720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    }
46820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    mOffset += mTypeSize;
46920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
47020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    int length = 0;
47120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    if (mLengthSize == 1) {
47220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        length = mArray[mOffset];
47320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    } else if (mLengthSize == 2) {
47420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                        length = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
47520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    }
47620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    mOffset += mLengthSize;
47720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
47820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    TlvElement tlv = new TlvElement(type, length, mArray, mOffset);
47920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    mOffset += length;
48020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    return tlv;
48120d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                }
48220d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen
48320d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                @Override
48420d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                public void remove() {
48520d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                    throw new UnsupportedOperationException();
48620d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen                }
48720d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen            };
48820d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen        }
48920d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen    }
49020d329b08df7d1a94e6caee781f09e812a79c913Etan Cohen}
491