/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.cat; import java.util.List; /** * Class for representing BER-TLV objects. * * @see "ETSI TS 102 223 Annex C" for more information. * * {@hide} */ class BerTlv { private int mTag = BER_UNKNOWN_TAG; private List<ComprehensionTlv> mCompTlvs = null; private boolean mLengthValid = true; public static final int BER_UNKNOWN_TAG = 0x00; public static final int BER_PROACTIVE_COMMAND_TAG = 0xd0; public static final int BER_MENU_SELECTION_TAG = 0xd3; public static final int BER_EVENT_DOWNLOAD_TAG = 0xd6; private BerTlv(int tag, List<ComprehensionTlv> ctlvs, boolean lengthValid) { mTag = tag; mCompTlvs = ctlvs; mLengthValid = lengthValid; } /** * Gets a list of ComprehensionTlv objects contained in this BER-TLV object. * * @return A list of COMPREHENSION-TLV object */ public List<ComprehensionTlv> getComprehensionTlvs() { return mCompTlvs; } /** * Gets a tag id of the BER-TLV object. * * @return A tag integer. */ public int getTag() { return mTag; } /** * Gets if the length of the BER-TLV object is valid * * @return if length valid */ public boolean isLengthValid() { return mLengthValid; } /** * Decodes a BER-TLV object from a byte array. * * @param data A byte array to decode from * @return A BER-TLV object decoded * @throws ResultException */ public static BerTlv decode(byte[] data) throws ResultException { int curIndex = 0; int endIndex = data.length; int tag, length = 0; boolean isLengthValid = true; try { /* tag */ tag = data[curIndex++] & 0xff; if (tag == BER_PROACTIVE_COMMAND_TAG) { /* length */ int temp = data[curIndex++] & 0xff; if (temp < 0x80) { length = temp; } else if (temp == 0x81) { temp = data[curIndex++] & 0xff; if (temp < 0x80) { throw new ResultException( ResultCode.CMD_DATA_NOT_UNDERSTOOD, "length < 0x80 length=" + Integer.toHexString(length) + " curIndex=" + curIndex + " endIndex=" + endIndex); } length = temp; } else { throw new ResultException( ResultCode.CMD_DATA_NOT_UNDERSTOOD, "Expected first byte to be length or a length tag and < 0x81" + " byte= " + Integer.toHexString(temp) + " curIndex=" + curIndex + " endIndex=" + endIndex); } } else { if (ComprehensionTlvTag.COMMAND_DETAILS.value() == (tag & ~0x80)) { tag = BER_UNKNOWN_TAG; curIndex = 0; } } } catch (IndexOutOfBoundsException e) { throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING, "IndexOutOfBoundsException " + " curIndex=" + curIndex + " endIndex=" + endIndex); } catch (ResultException e) { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD, e.explanation()); } /* COMPREHENSION-TLVs */ if (endIndex - curIndex < length) { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD, "Command had extra data endIndex=" + endIndex + " curIndex=" + curIndex + " length=" + length); } List<ComprehensionTlv> ctlvs = ComprehensionTlv.decodeMany(data, curIndex); if (tag == BER_PROACTIVE_COMMAND_TAG) { int totalLength = 0; for (ComprehensionTlv item : ctlvs) { int itemLength = item.getLength(); if (itemLength >= 0x80 && itemLength <= 0xFF) { totalLength += itemLength + 3; //3: 'tag'(1 byte) and 'length'(2 bytes). } else if (itemLength >= 0 && itemLength < 0x80) { totalLength += itemLength + 2; //2: 'tag'(1 byte) and 'length'(1 byte). } else { isLengthValid = false; break; } } // According to 3gpp11.14, chapter 6.10.6 "Length errors", // If the total lengths of the SIMPLE-TLV data objects are not // consistent with the length given in the BER-TLV data object, // then the whole BER-TLV data object shall be rejected. The // result field in the TERMINAL RESPONSE shall have the error // condition "Command data not understood by ME". if (length != totalLength) { isLengthValid = false; } } return new BerTlv(tag, ctlvs, isLengthValid); } }