1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
/* * @(#)ResponseAPDU.java 1.3 06/07/20 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.smartcardio; import java.util.Arrays; /** * A response APDU as defined in ISO/IEC 7816-4. It consists of a conditional * body and a two byte trailer. * This class does not attempt to verify that the APDU encodes a semantically * valid response. * * <p>Instances of this class are immutable. Where data is passed in or out * via byte arrays, defensive cloning is performed. * * @see CommandAPDU * @see CardChannel#transmit CardChannel.transmit * * @version 1.3, 07/20/06 * @since 1.6 * @author Andreas Sterbenz * @author JSR 268 Expert Group */ public final class ResponseAPDU implements java.io.Serializable { private static final long serialVersionUID = 6962744978375594225L; /** @serial */ private byte[] apdu; /** * Constructs a ResponseAPDU from a byte array containing the complete * APDU contents (conditional body and trailed). * * <p>Note that the byte array is cloned to protect against subsequent * modification. * * @param apdu the complete response APDU * * @throws NullPointerException if apdu is null * @throws IllegalArgumentException if apdu.length is less than 2 */ public ResponseAPDU(byte[] apdu) { apdu = apdu.clone(); check(apdu); this.apdu = apdu; } private static void check(byte[] apdu) { if (apdu.length < 2) { throw new IllegalArgumentException("apdu must be at least 2 bytes long"); } } /** * Returns the number of data bytes in the response body (Nr) or 0 if this * APDU has no body. This call is equivalent to * <code>getData().length</code>. * * @return the number of data bytes in the response body or 0 if this APDU * has no body. */ public int getNr() { return apdu.length - 2; } /** * Returns a copy of the data bytes in the response body. If this APDU as * no body, this method returns a byte array with a length of zero. * * @return a copy of the data bytes in the response body or the empty * byte array if this APDU has no body. */ public byte[] getData() { byte[] data = new byte[apdu.length - 2]; System.arraycopy(apdu, 0, data, 0, data.length); return data; } /** * Returns the value of the status byte SW1 as a value between 0 and 255. * * @return the value of the status byte SW1 as a value between 0 and 255. */ public int getSW1() { return apdu[apdu.length - 2] & 0xff; } /** * Returns the value of the status byte SW2 as a value between 0 and 255. * * @return the value of the status byte SW2 as a value between 0 and 255. */ public int getSW2() { return apdu[apdu.length - 1] & 0xff; } /** * Returns the value of the status bytes SW1 and SW2 as a single * status word SW. * It is defined as * <code>(getSW1() << 8) | getSW2()</code>. * * @return the value of the status word SW. */ public int getSW() { return (getSW1() << 8) | getSW2(); } /** * Returns a copy of the bytes in this APDU. * * @return a copy of the bytes in this APDU. */ public byte[] getBytes() { return apdu.clone(); } /** * Returns a string representation of this response APDU. * * @return a String representation of this response APDU. */ public String toString() { return "ResponseAPDU: " + apdu.length + " bytes, SW=" + Integer.toHexString(getSW()); } /** * Compares the specified object with this response APDU for equality. * Returns true if the given object is also a ResponseAPDU and its bytes are * identical to the bytes in this ResponseAPDU. * * @param obj the object to be compared for equality with this response APDU * @return true if the specified object is equal to this response APDU */ public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof ResponseAPDU == false) { return false; } ResponseAPDU other = (ResponseAPDU)obj; return Arrays.equals(this.apdu, other.apdu); } /** * Returns the hash code value for this response APDU. * * @return the hash code value for this response APDU. */ public int hashCode() { return Arrays.hashCode(apdu); } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { apdu = (byte[])in.readUnshared(); check(apdu); } }