|
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 |
|
26 package javax.smartcardio; |
|
27 |
|
28 import 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 */ |
|
45 public 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 } |