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