      1 /*
      2  * Copyright (c) 2005, 2021, 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.*;
     29 import java.io.IOException;
     30
     31 /**
     32  * A Smart Card's answer-to-reset bytes. A Card's ATR object can be obtained
     33  * by calling {@linkplain Card#getATR}.
     34  * This class does not attempt to verify that the ATR encodes a semantically
     35  * valid structure.
     36  *
     37  * <p>Instances of this class are immutable. Where data is passed in or out
     38  * via byte arrays, defensive cloning is performed.
     39  *
     40  * @see Card#getATR
     41  *
     42  * @since   1.6
     43  * @author  Andreas Sterbenz
     44  * @author  JSR 268 Expert Group
     45  */
     46 public final class ATR implements java.io.Serializable {
     47
     48     private static final long serialVersionUID = 6695383790847736493L;
     49
     50     /**
     51      * The internal answer-to-reset byte array.
     52      */
     53     private byte[] atr;
     54
     55     private transient int startHistorical, nHistorical;
     56
     57     /**
     58      * Constructs an ATR from a byte array.
     59      *
     60      * @param atr the byte array containing the answer-to-reset bytes
     61      * @throws NullPointerException if <code>atr</code> is null
     62      */
     63     public ATR(byte[] atr) {
     64         this.atr = atr.clone();
     65         parse();
     66     }
     67
     68     private void parse() {
     69         if (atr.length < 2) {
     70             return;
     71         }
     72         if ((atr[0] != 0x3b) && (atr[0] != 0x3f)) {
     73             return;
     74         }
     75         int t0 = (atr[1] & 0xf0) >> 4;
     76         int n = atr[1] & 0xf;
     77         int i = 2;
     78         while ((t0 != 0) && (i < atr.length)) {
     79             if ((t0 & 1) != 0) {
     80                 i++;
     81             }
     82             if ((t0 & 2) != 0) {
     83                 i++;
     84             }
     85             if ((t0 & 4) != 0) {
     86                 i++;
     87             }
     88             if ((t0 & 8) != 0) {
     89                 if (i >= atr.length) {
     90                     return;
     91                 }
     92                 t0 = (atr[i++] & 0xf0) >> 4;
     93             } else {
     94                 t0 = 0;
     95             }
     96         }
     97         int k = i + n;
     98         if ((k == atr.length) || (k == atr.length - 1)) {
     99             startHistorical = i;
    100             nHistorical = n;
    101         }
    102     }
    103
    104     /**
    105      * Returns a copy of the bytes in this ATR.
    106      *
    107      * @return a copy of the bytes in this ATR.
    108      */
    109     public byte[] getBytes() {
    110         return atr.clone();
    111     }
    112
    113     /**
    114      * Returns a copy of the historical bytes in this ATR.
    115      * If this ATR does not contain historical bytes, an array of length
    116      * zero is returned.
    117      *
    118      * @return a copy of the historical bytes in this ATR.
    119      */
    120     public byte[] getHistoricalBytes() {
    121         byte[] b = new byte[nHistorical];
    122         System.arraycopy(atr, startHistorical, b, 0, nHistorical);
    123         return b;
    124     }
    125
    126     /**
    127      * Returns a string representation of this ATR.
    128      *
    129      * @return a String representation of this ATR.
    130      */
    131     public String toString() {
    132         return "ATR: " + atr.length + " bytes";
    133     }
    134
    135     /**
    136      * Compares the specified object with this ATR for equality.
    137      * Returns true if the given object is also an ATR and its bytes are
    138      * identical to the bytes in this ATR.
    139      *
    140      * @param obj the object to be compared for equality with this ATR
    141      * @return true if the specified object is equal to this ATR
    142      */
    143     public boolean equals(Object obj) {
    144         if (this == obj) {
    145             return true;
    146         }
    147         if (obj instanceof ATR == false) {
    148             return false;
    149         }
    150         ATR other = (ATR)obj;
    151         return Arrays.equals(this.atr, other.atr);
    152     }
    153
    154     /**
    155      * Returns the hash code value for this ATR.
    156      *
    157      * @return the hash code value for this ATR.
    158      */
    159     public int hashCode() {
    160         return Arrays.hashCode(atr);
    161     }
    162
    163     /**
    164      * Restores the state of this object from the stream.
    165      *
    166      * @param  in the {@code ObjectInputStream} from which data is read
    167      * @throws IOException if an I/O error occurs
    168      * @throws ClassNotFoundException if a serialized class cannot be loaded
    169      */
    170     private void readObject(java.io.ObjectInputStream in)
    171             throws IOException, ClassNotFoundException {
    172         atr = (byte[])in.readUnshared();
    173         parse();
    174     }
    175
    176 }