/*
*
*
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
//-----------------------------------------------------------------------------
// PACKAGE DEFINITION
//-----------------------------------------------------------------------------
package sim.toolkit;
//import sat.AccessBuffer;
//-----------------------------------------------------------------------------
// IMPORTS
//-----------------------------------------------------------------------------
import javacard.framework.Util;
import javacard.framework.ISO7816;
/**
*
* The ViewHandler class offers basic services and contains basic
* methods to handle
* a Simple TLV List, such as in a <b>Terminal Response</b> data field
* or in a BER-TLV
* element (<b>Envelope</b> data field or <b>Proactive</b> command).
* The byte at offset 0 of a handler is the tag of the first Simple TLV.
*
* @version 8.3.0
*
* @see ToolkitException
*/
public abstract class ViewHandler {
/** Offset of BER_TLV_TAG. */
protected static final byte BER_TLV_TAG_OFFSET = (byte)5;
/** Offset of Lc in the APDU buffer. */
protected static final byte OFFSET_LC = (byte)4;
/** Offset of TPDUD. */
protected static final byte TPUD_OFFSET = (byte)12;
/** Tag of DEVICE_ID field. */
private static final byte DEVICE_ID_TAG = (byte)0x82;
/** Length of DEVICE_ID field. */
private static final byte DEVICE_ID_LENGTH = (byte)0x02;
/** Tag of ADDRESS field. */
private static final byte ADDRESS_TAG = (byte)0x06;
/** Tag of SMS_TPDU. */
private static final byte SMS_TPDU_TAG = (byte)0x8B;
/** Offset of first occurrence of TLV. */
short currentTLVOffset;
/** Offset of first occurrence of TLV. */
short firstTLVOffset;
/** Reference to SAT Accessor. */
public static AccessSAT SATAccessor;
/** Reference to TI which is now serviced. */
public static ToolkitInterface currentTI;
/**
* Constructor.
*/
ViewHandler() {}
// ------------------------------- Constructor ---------------------------
/**
* Builds a new ViewHandler object.
*
* @param buffer a reference to the TLV buffer
* @param offset the position in the TLV buffer
* @param length the length of the TLV buffer
*
* @exception NullPointerException if <code>buffer</code>
* is <code>null</code>
* @exception ArrayIndexOutOfBoundsException if <code>offset</code>
* or <code>length</code> or both would cause access outside array bounds
*/
ViewHandler(byte[] buffer, short offset, short length)
throws NullPointerException,
ArrayIndexOutOfBoundsException {
}
// ------------------------------- Public methods -------------------------
/**
* Returns the length of the TLV list.
*
* @return length in bytes
*
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is
* busy</ul>
*/
public short getLength() throws ToolkitException {
byte[] buffer = getAPDUBuffer();
short length = (short)(buffer[(short)(currentTLVOffset + 1)] & 0xFF);
return length;
}
/**
* Copies the simple TLV list contained in the handler to the
* destination byte array.
*
* <p>
* Notes:<ul>
* <li><em>If </em><code>dstOffset</code><em> or
* </em><code>dstLength</code><em> parameter is negative
* an </em><code>ArrayIndexOutOfBoundsException</code>
* <em> exception is thrown and no copy is performed.</em>
* <li><em>If </em><code>dstOffset+dstLength</code><em> is greater
* than </em><code>dstBuffer.length</code><em>, the length
* of the </em><code>dstBuffer</code><em> array an
* </em><code>ArrayIndexOutOfBoundsException</code><em>
* exception is thrown and no copy is performed.</em>
* </ul>
*
* @param dstBuffer a reference to the destination buffer
* @param dstOffset the position in the destination buffer
* @param dstLength the data length to be copied
*
* @return <code>dstOffset+dstLength</code>
*
* @exception NullPointerException if <code>dstBuffer</code>
* is <code>null</code>
* @exception ArrayIndexOutOfBoundsException if copy would
* cause access of data outside array bounds.
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>OUT_OF_TLV_BOUNDARIES</code> if <code>dstLength</code>
* is grater than the length of the simple TLV List.</ul>
*/
public short copy(byte[] dstBuffer,
short dstOffset,
short dstLength) throws NullPointerException,
ArrayIndexOutOfBoundsException,
ToolkitException {
byte[] buffer = getAPDUBuffer();
short TLVLength =
(short)(buffer[(short)(currentTLVOffset + 1)] & 0xFF);
if (TLVLength < dstLength) {
// if length is greater than the TLV length itself, then
// throw exception
ToolkitException.throwIt(ToolkitException.OUT_OF_TLV_BOUNDARIES);
}
// copy the current TLV list
Util.arrayCopy(buffer, (short)(currentTLVOffset+2), dstBuffer,
dstOffset, dstLength);
return (short)(dstOffset + dstLength);
}
/**
* Looks for the indicated occurrence of a TLV element from the beginning of
* the TLV list (handler buffer). If the method is successful then the
* corresponding TLV becomes current, else no TLV is selected.
* This search method is Comprehension Required flag independent.
*
* @param tag the tag of the TLV element to search
* @param occurrence the occurrence number of the TLV element (1 for the
* first, 2 for the second...)
*
* @return result of the method: <ul>
* <li><code>TLV_NOT_FOUND</code> if the required occurrence of the
* TLV element does not exist
* <li><code>TLV_FOUND_CR_SET</code> if the required occurrence exists
* and Comprehension Required flag is set
* <li><code>TLV_FOUND_CR_NOT_SET</code> if the required occurrence
* exists and Comprehension Required flag is not set</ul>
*
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>BAD_INPUT_PARAMETER</code> if an input parameter is not
* valid (e.g. occurrence = 0)</ul>
*/
public byte findTLV(byte tag, byte occurrence) throws ToolkitException {
byte count = 0; // count of occurances
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getTLVOffset(buffer, tag, Lc, occurrence);
if (TLVOffset >= Lc)
return ToolkitConstants.TLV_NOT_FOUND; // not found
currentTLVOffset = TLVOffset;
if ((byte)(buffer[TLVOffset] & ToolkitConstants.TAG_SET_CR) ==
ToolkitConstants.TAG_SET_CR)
return ToolkitConstants.TLV_FOUND_CR_SET;
return ToolkitConstants.TLV_FOUND_CR_NOT_SET;
}
/**
* Gets the binary length of the value field for the last TLV element
* which has been found in the handler.
*
* @return length of the value field
*
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>UNAVAILABLE_ELEMENT</code> in case of unavailable
* TLV element</ul>
*/
public short getValueLength() throws ToolkitException {
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getLastTLVOffset(buffer, Lc);
if (TLVOffset >= Lc) {
ToolkitException.throwIt(ToolkitException.UNAVAILABLE_ELEMENT);
}
return (short)(buffer[(short)
(TLVOffset + 1)] & 0xFF); // return the length
}
/**
* Gets a byte from the last TLV element which has been found in the
* handler.
*
* @param valueOffset the offset of the byte to return in the TLV element
*
* @return element value (1 byte)
*
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>UNAVAILABLE_ELEMENT</code> in case of unavailable TLV
* element
* <li><code>OUT_OF_TLV_BOUNDARIES</code> if
* <code>valueOffset</code> is out of the current TLV </ul>
*/
public byte getValueByte(short valueOffset) throws ToolkitException {
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getLastTLVOffset(buffer, Lc);
if (TLVOffset >= Lc) {
ToolkitException.throwIt(ToolkitException.UNAVAILABLE_ELEMENT);
}
short TLVLength = (short)(buffer[(short)(TLVOffset + 1)] & 0xFF);
if (valueOffset > TLVLength) {
ToolkitException.throwIt(ToolkitException.OUT_OF_TLV_BOUNDARIES);
}
// return the byte at offset
return buffer[(short)(TLVOffset + 2 + valueOffset)];
}
/**
* Copies a part of the last TLV element which has been found, into a
* destination buffer.
*
* <p>
* Notes:<ul>
* <li><em>If </em><code>dstOffset</code><em> or
* </em><code>dstLength</code><em> parameter is negative an
* </em><code>ArrayIndexOutOfBoundsException</code>
* <em> exception is thrown and no copy is performed.</em>
* <li><em>If </em><code>dstOffset+dstLength</code><em> is
* greater than </em><code>dstBuffer.length</code><em>, the length
* of the </em><code>dstBuffer</code><em> array an
* </em><code>ArrayIndexOutOfBoundsException</code><em> exception
* is thrown and no copy is performed.</em>
* </ul>
*
* @param valueOffset the offset of the first byte in the source
* TLV element
* @param dstBuffer a reference to the destination buffer
* @param dstOffset the position in the destination buffer
* @param dstLength the data length to be copied
*
* @return <code>dstOffset+dstLength</code>
*
* @exception NullPointerException if <code>dstBuffer</code> is
* <code>null</code>
* @exception ArrayIndexOutOfBoundsException if copyValue would
* cause access of data outside array bounds.
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>UNAVAILABLE_ELEMENT</code> in case of unavailable
* TLV element
* <li><code>OUT_OF_TLV_BOUNDARIES</code> if:
* <ul>
* <li><code>valueOffset</code> parameter is negative or
* <li><code>valueOffset + dstLength</code> is greater than
* the length of the current TLV
* </ul>
* </ul>
*/
public short copyValue(short valueOffset,
byte[] dstBuffer,
short dstOffset,
short dstLength)
throws NullPointerException,
ArrayIndexOutOfBoundsException,
ToolkitException {
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getLastTLVOffset(buffer, Lc);
if (TLVOffset >= Lc) {
ToolkitException.throwIt(ToolkitException.UNAVAILABLE_ELEMENT);
}
short TLVLength = (short)(buffer[(short)(TLVOffset + 1)] & 0xFF);
if (valueOffset > TLVLength || valueOffset < 0) {
ToolkitException.throwIt(ToolkitException.OUT_OF_TLV_BOUNDARIES);
}
Util.arrayCopy(buffer,
(short)(currentTLVOffset + 2 + valueOffset),
dstBuffer, dstOffset, dstLength);
return buffer[(short)(TLVOffset + 2 + valueOffset)];
}
/**
* Compares the last found TLV element with a buffer.
*
* <p>
* Notes:<ul>
* <li><em>If </em><code>compareOffset</code><em> or
* </em><code>compareLength</code><em> parameter is negative
* an </em><code>ArrayIndexOutOfBoundsException</code>
* <em> exception is thrown and no compare is performed.</em>
* <li><em>If </em><code>compareOffset+compareLength</code><em>is
* greater than </em><code>compareBuffer.length</code><em>, the length
* of the </em><code>compareBuffer</code><em> array an
* </em><code>ArrayIndexOutOfBoundsException</code><em> exception
* is thrown and no compare is performed.</em>
* </ul>
*
* @param valueOffset the offset of the first byte to compare in
* the TLV element
* @param compareBuffer a reference to the comparison buffer
* @param compareOffset the position in the comparison buffer
* @param compareLength the length to be compared
*
* @return the result of the comparison as follows: <ul>
* <li><code>0</code> if identical
* <li><code>-1</code> if the first miscomparing byte in simple
* TLV List is less than that in <code>compareBuffer</code>,
* <li><code>1</code> if the first miscomparing byte in simple
* TLV List is greater than that in <code>compareBuffer</code>.</ul>
*
* @exception NullPointerException if <code>compareBuffer</code> is
* <code>null</code>
* @exception ArrayIndexOutOfBoundsException if compareValue would
* cause access of data outside array bounds.
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>UNAVAILABLE_ELEMENT</code> in case of unavailable
* TLV element
* <li><code>OUT_OF_TLV_BOUNDARIES</code> if:
* <ul>
* <li><code>valueOffset</code> parameter is negative or
* <li><code>valueOffset + compareLength</code> is greater
* than the length of the current TLV
* </ul>
* </ul>
*/
public byte compareValue(short valueOffset,
byte[] compareBuffer,
short compareOffset,
short compareLength)
throws NullPointerException,
ArrayIndexOutOfBoundsException,
ToolkitException {
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getLastTLVOffset(buffer, Lc);
if (TLVOffset >= Lc) {
ToolkitException.throwIt(ToolkitException.UNAVAILABLE_ELEMENT);
}
short TLVLength = (short)(buffer[(short)(TLVOffset + 1)] & 0xFF);
if (valueOffset > TLVLength || valueOffset < 0) {
ToolkitException.throwIt(ToolkitException.OUT_OF_TLV_BOUNDARIES);
}
return Util.arrayCompare(buffer,
(short)(currentTLVOffset + 2 + valueOffset),
compareBuffer, compareOffset, compareLength);
}
/**
* Looks for the first occurrence of a TLV element from the beginning
* of a TLV
* list and copy its value into a destination buffer.
* If no TLV element is found, the <code>UNAVAILABLE_ELEMENT</code>
* exception is thrown.
* If the method is successful then the corresponding TLV becomes current,
* else no TLV is selected.
* This search method is Comprehension Required flag independent.
*
* <p>
* Notes:<ul>
* <li><em>If </em><code>dstOffset</code><em> parameter is negative or
* </em><code>dstOffset</code>
* <em> is greater than </em><code>dstBuffer.length</code><em>, the
* length of the </em><code>dstBuffer</code>
* <em> array an </em><code>ArrayIndexOutOfBoundsException</code><em>
* exception is thrown and no find is performed.</em>
* </ul>
*
* @param tag the tag of the TLV element to search
* @param dstBuffer a reference to the destination buffer
* @param dstOffset the position in the destination buffer
*
* @return <code>dstOffset</code> + length of the copied value
*
* @exception NullPointerException if <code>dstBuffer</code>
* is <code>null</code>
* @exception ArrayIndexOutOfBoundsException if findAndCopyValue
* would cause access of data outside array bounds.
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>UNAVAILABLE_ELEMENT</code> in case of unavailable
* TLV element</ul>
*/
public short findAndCopyValue(byte tag,
byte[] dstBuffer,
short dstOffset)
throws NullPointerException,
ArrayIndexOutOfBoundsException,
ToolkitException {
// this method could potentialy use the other
// findAndCopyValue() method. The only problem is the length
// parameter required by that method
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getTLVOffset(buffer, tag, Lc, (short)1);
if (TLVOffset >= Lc) {
// TLV not found
ToolkitException.throwIt(ToolkitException.UNAVAILABLE_ELEMENT);
}
currentTLVOffset = TLVOffset;
short length = buffer[(short)(TLVOffset+1)];
Util.arrayCopy(buffer, (short)(TLVOffset+2), dstBuffer,
dstOffset, length);
return (short)(dstOffset + length);
}
/**
* Looks for the indicated occurrence of a TLV element from the
* beginning of a TLV
* list and copy its value into a destination buffer.
* If no TLV element is found, the <code>UNAVAILABLE_ELEMENT</code>
* exception is thrown.
* If the method is successful then the corresponding TLV becomes current,
* else no TLV is selected.
* This search method is Comprehension Required flag independent.
*
* <p>
* Notes:<ul>
* <li><em>If </em><code>dstOffset</code><em> or
* </em><code>dstLength</code><em> parameter is negative
* an </em><code>ArrayIndexOutOfBoundsException</code>
* <em> exception is thrown and no copy is performed.</em>
* <li><em>If </em><code>dstOffset+dstLength</code><em>is greater
* than </em><code>dstBuffer.length</code><em>, the length
* of the </em><code>dstBuffer</code><em> array an
* </em><code>ArrayIndexOutOfBoundsException</code><em> exception
* is thrown and no copy is performed.</em>
* </ul>
*
* @param tag the tag of the TLV element to search
* @param occurrence the occurrence number of the TLV element
* (1 for the first, 2 for the second...)
* @param valueOffset the offset of the first byte in the source
* TLV element
* @param dstBuffer a reference to the destination buffer
* @param dstOffset the position in the destination buffer
* @param dstLength the data length to be copied
*
* @return <code>dstOffset + dstLength</code>
*
* @exception NullPointerException if <code>dstBuffer</code> is
* <code>null</code>
* @exception ArrayIndexOutOfBoundsException if findAndCopyValue
* would cause access of data outside array bounds.
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>UNAVAILABLE_ELEMENT</code> in case of unavailable
* TLV element
* <li><code>OUT_OF_TLV_BOUNDARIES</code> if:
* <ul>
* <li><code>valueOffset</code> parameter is negative or
* <li><code>valueOffset + dstLength</code> is greater
* than the length of the current TLV
* </ul>
* <li><code>BAD_INPUT_PARAMETER</code> if an input parameter
* is not valid (e.g. occurrence = 0)</ul>
*/
public short findAndCopyValue(byte tag,
byte occurrence,
short valueOffset,
byte[] dstBuffer,
short dstOffset,
short dstLength)
throws NullPointerException,
ArrayIndexOutOfBoundsException,
ToolkitException {
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getTLVOffset(buffer, tag, Lc, occurrence);
if (TLVOffset >= Lc) {
// TLV not found
ToolkitException.throwIt(ToolkitException.UNAVAILABLE_ELEMENT);
}
// this is the current TLV
currentTLVOffset = TLVOffset;
short length = buffer[(short)(TLVOffset+1)];
if ((valueOffset < 0) || (short)(valueOffset + dstLength) > length) {
ToolkitException.throwIt(ToolkitException.OUT_OF_TLV_BOUNDARIES);
}
Util.arrayCopy(buffer, (short)(TLVOffset+2+valueOffset),
dstBuffer, dstOffset, dstLength);
return (short)(dstOffset + length);
}
/**
* Looks for the first occurrence of a TLV element
* from beginning of a TLV
* list and compare its value with a buffer.
* If no TLV element is found, the
* <code>UNAVAILABLE_ELEMENT</code> exception is thrown.
* If the method is successful then the corresponding TLV
* becomes current, else no TLV is selected.
* This search method is Comprehension Required flag independent.
*
* <p>
* Notes:<ul>
* <li><em>If </em><code>compareOffset</code><em> parameter is
* negative or </em><code>compareOffset</code>
* <em> is greater than </em><code>compareBuffer.length</code><em>,
* the length of the </em><code>compareBuffer</code>
* <em> array an </em><code>ArrayIndexOutOfBoundsException</code><em>
* exception is thrown and no find is performed.</em>
* </ul>
*
* @param tag the tag of the TLV element to search
* @param compareBuffer a reference to the comparison buffer
* @param compareOffset the position in the comparison buffer
*
* @return the result of the comparison as follows: <ul>
* <li><code>0</code> if identical
* <li><code>-1</code> if the first miscomparing byte in simple
* TLV is less than that in <code>compareBuffer</code>,
* <li><code>1</code> if the first miscomparing byte in simple
* TLV is greater than that in <code>compareBuffer</code>.</ul>
*
* @exception NullPointerException if <code>compareBuffer</code> is
* <code>null</code>
* @exception ArrayIndexOutOfBoundsException if findAndCompareValue
* would cause access of data outside array bounds.
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>UNAVAILABLE_ELEMENT</code> in case of unavailable
* TLV element</ul>
*/
public byte findAndCompareValue(byte tag,
byte[] compareBuffer,
short compareOffset)
throws NullPointerException,
ArrayIndexOutOfBoundsException,
ToolkitException {
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getTLVOffset(buffer, tag, Lc, (byte)1);
if (TLVOffset >= Lc) {
// TLV not found
ToolkitException.throwIt(ToolkitException.UNAVAILABLE_ELEMENT);
}
// this is the current TLV
currentTLVOffset = TLVOffset;
short length = buffer[(short)(TLVOffset+1)];
return Util.arrayCompare(buffer, (short)(TLVOffset+2), compareBuffer,
compareOffset, length);
}
/**
* Looks for the indicated occurrence of a TLV element from the
* beginning of a TLV list and compare its value with a buffer.
* If no TLV element is found, the <code>UNAVAILABLE_ELEMENT</code>
* exception is thrown.
* If the method is successful then the corresponding TLV becomes
* current, else no TLV is selected.
* This search method is Comprehension Required flag independent.
*
* <p>
* Notes:<ul>
* <li><em>If </em><code>compareOffset</code><em> or
* </em><code>compareLength</code><em> parameter is
* negative an </em><code>ArrayIndexOutOfBoundsException</code>
* <em> exception is thrown and no find and compare is performed.</em>
* <li><em>If </em><code>compareOffset+compareLength</code><em> is
* greater than </em><code>compareBuffer.length</code><em>, the length
* of the </em><code>compareBuffer</code><em> array an
* </em><code>ArrayIndexOutOfBoundsException</code><em> exception
* is thrown and no find and compare is performed.</em>
* </ul>
*
* @param tag the tag of the TLV element to search
* @param occurrence the occurrence number of the TLV element
* (1 for the first, 2 for the second...)
* @param valueOffset the offset of the first byte in the source
* TLV element
* @param compareBuffer a reference to the comparison buffer
* @param compareOffset the position in the comparison buffer
* @param compareLength the length to be compared
*
* @return the result of the comparison as follows: <ul>
* <li><code>0</code> if identical
* <li><code>-1</code> if the first miscomparing byte in
* simple TLV is less than that in <code>compareBuffer</code>,
* <li><code>1</code> if the first miscomparing byte in simple
* TLV is greater than that in <code>compareBuffer</code>.</ul>
*
* @exception NullPointerException if <code>compareBuffer</code>
* is <code>null</code>
* @exception ArrayIndexOutOfBoundsException if findAndCompareValue
* would cause access of data outside array bounds.
* @exception ToolkitException with the following reason codes: <ul>
* <li><code>HANDLER_NOT_AVAILABLE</code> if the handler is busy
* <li><code>UNAVAILABLE_ELEMENT</code> in case of unavailable
* TLV element
* <li><code>OUT_OF_TLV_BOUNDARIES</code> if:
* <ul>
* <li><code>valueOffset</code> parameter is negative or
* <li><code>valueOffset + compareLength</code> is greater
* than the length of the current TLV
* </ul>
* <li><code>BAD_INPUT_PARAMETER</code> if an input parameter is
* not valid (e.g. occurrence = 0)</ul>
*/
public byte findAndCompareValue(byte tag,
byte occurrence,
short valueOffset,
byte[] compareBuffer,
short compareOffset,
short compareLength)
throws NullPointerException,
ArrayIndexOutOfBoundsException,
ToolkitException {
byte[] buffer = getAPDUBuffer();
short Lc = (short)(buffer[OFFSET_LC] & 0xFF);
short TLVOffset = getTLVOffset(buffer, tag, Lc, occurrence);
if (TLVOffset >= Lc) {
// TLV not found
ToolkitException.throwIt(ToolkitException.UNAVAILABLE_ELEMENT);
}
// this is the current TLV
currentTLVOffset = TLVOffset;
short length = buffer[(short)(TLVOffset+1)];
if ((valueOffset < 0) || (short)
(valueOffset + compareLength) > length) {
ToolkitException.throwIt(ToolkitException.OUT_OF_TLV_BOUNDARIES);
}
return Util.arrayCompare(buffer, (short)(TLVOffset+2+valueOffset),
compareBuffer, compareOffset, compareLength);
}
/**
* Helper method for <code>findAndCompareValue</code>.
* @param buffer APDU buffer
* @param tag What tag we are finding
* @param Lc Length of command data
* @param occurrence The occurrence number of the TLV element
* @return Offset of the tag
*/
protected short getTLVOffset(byte[] buffer, byte tag,
short Lc, short occurrence) {
byte count = 0; // count of occurances
short offset = firstTLVOffset;
tag = (byte)(tag & 0x7F);
while (offset < Lc) {
if ((byte)(buffer[offset] & 0x7F) == tag) {
count++;
if (count != occurrence) {
continue;
}
return offset;
} else {
// advance to next TLV
offset++;
short length = buffer[offset];
offset = (short)(offset + length + 1);
}
}
return offset; // not found
}
/**
* Helper method for <code>getValue...</code> and
* <code>copyValue...</code>.
* @param buffer APDU buffer
* @param Lc Length of command data
* @return Offset of the tag
*/
protected short getLastTLVOffset(byte[] buffer, short Lc) {
short offset = firstTLVOffset;
short lastTLVOffset;
do {
lastTLVOffset = offset;
// advance to next TLV
offset++;
short length = buffer[offset];
offset = (short)(offset + length + 1);
} while (offset < Lc);
return lastTLVOffset;
}
/**
* Copies the APDUBuffer content into provided buffer.
* @param buffer The buffer
* @return Provided buffer filled with APDUBuffer content
*/
public static byte[] getAPDUBuffer(byte[] buffer) {
short len = SATAccessor.getAPDUBufferLength();
for (short i = 0; i < len; i++) {
buffer[i] = SATAccessor.getAPDUBufferByte(i);
}
return buffer;
}
/**
* Copies the APDUBuffer content into current buffer.
* @return apdu buffer
*/
public static byte[] getAPDUBuffer() {
return getAPDUBuffer(currentTI.getAPDUBuffer());
}
/**
* Copies content of provided buffer into the APDUBuffer.
* @param buffer The buffer
* @param length Length of the buffer
*/
public static void setAPDUBuffer(byte[] buffer, short length) {
for (short i = 0; i < length; i++) {
SATAccessor.setAPDUBufferByte(i, buffer[i]);
}
}
/**
* Copies content of current buffer into the APDUBuffer.
* @param length Length of the current buffer
*/
public static void setAPDUBuffer(short length) {
setAPDUBuffer(currentTI.getAPDUBuffer(), length);
}
/**
* Sets the data in the out buffer.
* @param length Length of data
*/
public static void setOutBufferData(short length) {
setAPDUBuffer(length);
SATAccessor.setOutBufferData(length);
}
}
|