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