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