      1 /*
      2  * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25
     26 package javax.smartcardio;
     27
     28 import java.util.Arrays;
     29
     30 /**
     31  * A response APDU as defined in ISO/IEC 7816-4. It consists of a conditional
     32  * body and a two byte trailer.
     33  * This class does not attempt to verify that the APDU encodes a semantically
     34  * valid response.
     35  *
     36  * <p>Instances of this class are immutable. Where data is passed in or out
     37  * via byte arrays, defensive cloning is performed.
     38  *
     39  * @see CommandAPDU
     40  * @see CardChannel#transmit CardChannel.transmit
     41  *
     42  * @since   1.6
     43  * @author  Andreas Sterbenz
     44  * @author  JSR 268 Expert Group
     45  */
     46 public final class ResponseAPDU implements java.io.Serializable {
     47
     48     private static final long serialVersionUID = 6962744978375594225L;
     49
     50     /** @serial */
     51     private byte[] apdu;
     52
     53     /**
     54      * Constructs a ResponseAPDU from a byte array containing the complete
     55      * APDU contents (conditional body and trailed).
     56      *
     57      * <p>Note that the byte array is cloned to protect against subsequent
     58      * modification.
     59      *
     60      * @param apdu the complete response APDU
     61      *
     62      * @throws NullPointerException if apdu is null
     63      * @throws IllegalArgumentException if apdu.length is less than 2
     64      */
     65     public ResponseAPDU(byte[] apdu) {
     66         apdu = apdu.clone();
     67         check(apdu);
     68         this.apdu = apdu;
     69     }
     70
     71     private static void check(byte[] apdu) {
     72         if (apdu.length < 2) {
     73             throw new IllegalArgumentException("apdu must be at least 2 bytes long");
     74         }
     75     }
     76
     77     /**
     78      * Returns the number of data bytes in the response body (Nr) or 0 if this
     79      * APDU has no body. This call is equivalent to
     80      * <code>getData().length</code>.
     81      *
     82      * @return the number of data bytes in the response body or 0 if this APDU
     83      * has no body.
     84      */
     85     public int getNr() {
     86         return apdu.length - 2;
     87     }
     88
     89     /**
     90      * Returns a copy of the data bytes in the response body. If this APDU as
     91      * no body, this method returns a byte array with a length of zero.
     92      *
     93      * @return a copy of the data bytes in the response body or the empty
     94      *    byte array if this APDU has no body.
     95      */
     96     public byte[] getData() {
     97         byte[] data = new byte[apdu.length - 2];
     98         System.arraycopy(apdu, 0, data, 0, data.length);
     99         return data;
    100     }
    101
    102     /**
    103      * Returns the value of the status byte SW1 as a value between 0 and 255.
    104      *
    105      * @return the value of the status byte SW1 as a value between 0 and 255.
    106      */
    107     public int getSW1() {
    108         return apdu[apdu.length - 2] & 0xff;
    109     }
    110
    111     /**
    112      * Returns the value of the status byte SW2 as a value between 0 and 255.
    113      *
    114      * @return the value of the status byte SW2 as a value between 0 and 255.
    115      */
    116     public int getSW2() {
    117         return apdu[apdu.length - 1] & 0xff;
    118     }
    119
    120     /**
    121      * Returns the value of the status bytes SW1 and SW2 as a single
    122      * status word SW.
    123      * It is defined as
    124      * {@code (getSW1() << 8) | getSW2()}
    125      *
    126      * @return the value of the status word SW.
    127      */
    128     public int getSW() {
    129         return (getSW1() << 8) | getSW2();
    130     }
    131
    132     /**
    133      * Returns a copy of the bytes in this APDU.
    134      *
    135      * @return a copy of the bytes in this APDU.
    136      */
    137     public byte[] getBytes() {
    138         return apdu.clone();
    139     }
    140
    141     /**
    142      * Returns a string representation of this response APDU.
    143      *
    144      * @return a String representation of this response APDU.
    145      */
    146     public String toString() {
    147         return "ResponseAPDU: " + apdu.length + " bytes, SW="
    148             + Integer.toHexString(getSW());
    149     }
    150
    151     /**
    152      * Compares the specified object with this response APDU for equality.
    153      * Returns true if the given object is also a ResponseAPDU and its bytes are
    154      * identical to the bytes in this ResponseAPDU.
    155      *
    156      * @param obj the object to be compared for equality with this response APDU
    157      * @return true if the specified object is equal to this response APDU
    158      */
    159     public boolean equals(Object obj) {
    160         if (this == obj) {
    161             return true;
    162         }
    163         if (obj instanceof ResponseAPDU == false) {
    164             return false;
    165         }
    166         ResponseAPDU other = (ResponseAPDU)obj;
    167         return Arrays.equals(this.apdu, other.apdu);
    168     }
    169
    170     /**
    171      * Returns the hash code value for this response APDU.
    172      *
    173      * @return the hash code value for this response APDU.
    174      */
    175     public int hashCode() {
    176         return Arrays.hashCode(apdu);
    177     }
    178
    179     private void readObject(java.io.ObjectInputStream in)
    180             throws java.io.IOException, ClassNotFoundException {
    181         apdu = (byte[])in.readUnshared();
    182         check(apdu);
    183     }
    184
    185 }