1/*
2 * Copyright (C) 2006 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
17package com.android.internal.telephony.gsm.stk;
18
19import java.util.ArrayList;
20import java.util.List;
21
22
23/**
24 * Class for representing COMPREHENSION-TLV objects.
25 *
26 * @see "ETSI TS 101 220 subsection 7.1.1"
27 *
28 * {@hide}
29 */
30class ComprehensionTlv {
31    private int mTag;
32    private boolean mCr;
33    private int mLength;
34    private int mValueIndex;
35    private byte[] mRawValue;
36
37    /**
38     * Constructor. Private on purpose. Use
39     * {@link #decodeMany(byte[], int) decodeMany} or
40     * {@link #decode(byte[], int) decode} method.
41     *
42     * @param tag The tag for this object
43     * @param cr Comprehension Required flag
44     * @param length Length of the value
45     * @param data Byte array containing the value
46     * @param valueIndex Index in data at which the value starts
47     */
48    protected ComprehensionTlv(int tag, boolean cr, int length, byte[] data,
49            int valueIndex) {
50        mTag = tag;
51        mCr = cr;
52        mLength = length;
53        mValueIndex = valueIndex;
54        mRawValue = data;
55    }
56
57    public int getTag() {
58        return mTag;
59    }
60
61    public boolean isComprehensionRequired() {
62        return mCr;
63    }
64
65    public int getLength() {
66        return mLength;
67    }
68
69    public int getValueIndex() {
70        return mValueIndex;
71    }
72
73    public byte[] getRawValue() {
74        return mRawValue;
75    }
76
77    /**
78     * Parses a list of COMPREHENSION-TLV objects from a byte array.
79     *
80     * @param data A byte array containing data to be parsed
81     * @param startIndex Index in data at which to start parsing
82     * @return A list of COMPREHENSION-TLV objects parsed
83     * @throws ResultException
84     */
85    public static List<ComprehensionTlv> decodeMany(byte[] data, int startIndex)
86            throws ResultException {
87        ArrayList<ComprehensionTlv> items = new ArrayList<ComprehensionTlv>();
88        int endIndex = data.length;
89        while (startIndex < endIndex) {
90            ComprehensionTlv ctlv = ComprehensionTlv.decode(data, startIndex);
91            items.add(ctlv);
92            startIndex = ctlv.mValueIndex + ctlv.mLength;
93        }
94
95        return items;
96    }
97
98    /**
99     * Parses an COMPREHENSION-TLV object from a byte array.
100     *
101     * @param data A byte array containing data to be parsed
102     * @param startIndex Index in data at which to start parsing
103     * @return A COMPREHENSION-TLV object parsed
104     * @throws ResultException
105     */
106    public static ComprehensionTlv decode(byte[] data, int startIndex)
107            throws ResultException {
108        try {
109            int curIndex = startIndex;
110            int endIndex = data.length;
111
112            /* tag */
113            int tag;
114            boolean cr; // Comprehension required flag
115            int temp = data[curIndex++] & 0xff;
116            switch (temp) {
117            case 0:
118            case 0xff:
119            case 0x80:
120                throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
121
122            case 0x7f: // tag is in three-byte format
123                tag = ((data[curIndex] & 0xff) << 8)
124                        | (data[curIndex + 1] & 0xff);
125                cr = (tag & 0x8000) != 0;
126                tag &= ~0x8000;
127                curIndex += 2;
128                break;
129
130            default: // tag is in single-byte format
131                tag = temp;
132                cr = (tag & 0x80) != 0;
133                tag &= ~0x80;
134                break;
135            }
136
137            /* length */
138            int length;
139            temp = data[curIndex++] & 0xff;
140            if (temp < 0x80) {
141                length = temp;
142            } else if (temp == 0x81) {
143                length = data[curIndex++] & 0xff;
144                if (length < 0x80) {
145                    throw new ResultException(
146                            ResultCode.CMD_DATA_NOT_UNDERSTOOD);
147                }
148            } else if (temp == 0x82) {
149                length = ((data[curIndex] & 0xff) << 8)
150                        | (data[curIndex + 1] & 0xff);
151                curIndex += 2;
152                if (length < 0x100) {
153                    throw new ResultException(
154                            ResultCode.CMD_DATA_NOT_UNDERSTOOD);
155                }
156            } else if (temp == 0x83) {
157                length = ((data[curIndex] & 0xff) << 16)
158                        | ((data[curIndex + 1] & 0xff) << 8)
159                        | (data[curIndex + 2] & 0xff);
160                curIndex += 3;
161                if (length < 0x10000) {
162                    throw new ResultException(
163                            ResultCode.CMD_DATA_NOT_UNDERSTOOD);
164                }
165            } else {
166                throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
167            }
168
169            return new ComprehensionTlv(tag, cr, length, data, curIndex);
170
171        } catch (IndexOutOfBoundsException e) {
172            throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
173        }
174    }
175}
176