10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/*
20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2011 The Android Open Source Project
30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License");
50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License.
60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at
70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *      http://www.apache.org/licenses/LICENSE-2.0
90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software
110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS,
120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and
140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License.
150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony.cat;
180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1999c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Savilleimport android.telephony.Rlog;
200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList;
220825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.List;
230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/**
260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Class for representing COMPREHENSION-TLV objects.
270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @see "ETSI TS 101 220 subsection 7.1.1"
290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville *
300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * {@hide}
310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */
320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleclass ComprehensionTlv {
330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private static final String LOG_TAG = "ComprehensionTlv";
340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mTag;
350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private boolean mCr;
360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mLength;
370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private int mValueIndex;
380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    private byte[] mRawValue;
390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Constructor. Private on purpose. Use
420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * {@link #decodeMany(byte[], int) decodeMany} or
430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * {@link #decode(byte[], int) decode} method.
440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param tag The tag for this object
460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param cr Comprehension Required flag
470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param length Length of the value
480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data Byte array containing the value
490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param valueIndex Index in data at which the value starts
500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    protected ComprehensionTlv(int tag, boolean cr, int length, byte[] data,
520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int valueIndex) {
530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mTag = tag;
540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mCr = cr;
550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mLength = length;
560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mValueIndex = valueIndex;
570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        mRawValue = data;
580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int getTag() {
610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return mTag;
620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public boolean isComprehensionRequired() {
650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return mCr;
660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int getLength() {
690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return mLength;
700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public int getValueIndex() {
730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return mValueIndex;
740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public byte[] getRawValue() {
770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return mRawValue;
780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Parses a list of COMPREHENSION-TLV objects from a byte array.
820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data A byte array containing data to be parsed
840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param startIndex Index in data at which to start parsing
850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return A list of COMPREHENSION-TLV objects parsed
860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @throws ResultException
870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static List<ComprehensionTlv> decodeMany(byte[] data, int startIndex)
890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throws ResultException {
900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        ArrayList<ComprehensionTlv> items = new ArrayList<ComprehensionTlv>();
910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int endIndex = data.length;
920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        while (startIndex < endIndex) {
930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            ComprehensionTlv ctlv = ComprehensionTlv.decode(data, startIndex);
940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (ctlv != null) {
950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                items.add(ctlv);
960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                startIndex = ctlv.mValueIndex + ctlv.mLength;
970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                CatLog.d(LOG_TAG, "decodeMany: ctlv is null, stop decoding");
990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        return items;
1040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    /**
1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * Parses an COMPREHENSION-TLV object from a byte array.
1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     *
1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param data A byte array containing data to be parsed
1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @param startIndex Index in data at which to start parsing
1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @return A COMPREHENSION-TLV object parsed
1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     * @throws ResultException
1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville     */
1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    public static ComprehensionTlv decode(byte[] data, int startIndex)
1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throws ResultException {
1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int curIndex = startIndex;
1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        int endIndex = data.length;
1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        try {
1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            /* tag */
1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int tag;
1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            boolean cr; // Comprehension required flag
1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int temp = data[curIndex++] & 0xff;
1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            switch (temp) {
1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case 0:
1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case 0xff:
1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case 0x80:
12899c2e1d6749cfad2a8ca94a47857d8c3bfc09454Wink Saville                Rlog.d("CAT     ", "decode: unexpected first tag byte=" + Integer.toHexString(temp) +
1290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        ", startIndex=" + startIndex + " curIndex=" + curIndex +
1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        " endIndex=" + endIndex);
1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // Return null which will stop decoding, this has occurred
1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                // with Ghana MTN simcard and JDI simcard.
1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                return null;
1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            case 0x7f: // tag is in three-byte format
1360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tag = ((data[curIndex] & 0xff) << 8)
1370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        | (data[curIndex + 1] & 0xff);
1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                cr = (tag & 0x8000) != 0;
1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tag &= ~0x8000;
1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                curIndex += 2;
1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            default: // tag is in single-byte format
1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tag = temp;
1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                cr = (tag & 0x80) != 0;
1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                tag &= ~0x80;
1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                break;
1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            /* length */
1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            int length;
1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            temp = data[curIndex++] & 0xff;
1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            if (temp < 0x80) {
1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                length = temp;
1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (temp == 0x81) {
1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                length = data[curIndex++] & 0xff;
1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (length < 0x80) {
1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    throw new ResultException(
1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            ResultCode.CMD_DATA_NOT_UNDERSTOOD,
1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            "length < 0x80 length=" + Integer.toHexString(length) +
1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            " startIndex=" + startIndex + " curIndex=" + curIndex +
1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            " endIndex=" + endIndex);
1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (temp == 0x82) {
1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                length = ((data[curIndex] & 0xff) << 8)
1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        | (data[curIndex + 1] & 0xff);
1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                curIndex += 2;
1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (length < 0x100) {
1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    throw new ResultException(
1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            ResultCode.CMD_DATA_NOT_UNDERSTOOD,
1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            "two byte length < 0x100 length=" + Integer.toHexString(length) +
1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            " startIndex=" + startIndex + " curIndex=" + curIndex +
1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            " endIndex=" + endIndex);
1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else if (temp == 0x83) {
1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                length = ((data[curIndex] & 0xff) << 16)
1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        | ((data[curIndex + 1] & 0xff) << 8)
1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        | (data[curIndex + 2] & 0xff);
1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                curIndex += 3;
1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                if (length < 0x10000) {
1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    throw new ResultException(
1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            ResultCode.CMD_DATA_NOT_UNDERSTOOD,
1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            "three byte length < 0x10000 length=0x" + Integer.toHexString(length) +
1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            " startIndex=" + startIndex + " curIndex=" + curIndex +
1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                            " endIndex=" + endIndex);
1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                }
1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            } else {
1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD,
1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        "Bad length modifer=" + temp +
1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        " startIndex=" + startIndex + " curIndex=" + curIndex +
1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                        " endIndex=" + endIndex);
1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            }
1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            return new ComprehensionTlv(tag, cr, length, data, curIndex);
1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville
1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        } catch (IndexOutOfBoundsException e) {
1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville            throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD,
1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    "IndexOutOfBoundsException" + " startIndex=" + startIndex +
2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville                    " curIndex=" + curIndex + " endIndex=" + endIndex);
2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville        }
2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville    }
2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville}
204