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