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
/* * @(#)ATR.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.*; /** * A Smart Card's answer-to-reset bytes. A Card's ATR object can be obtained * by calling {@linkplain Card#getATR}. * This class does not attempt to verify that the ATR encodes a semantically * valid structure. * * <p>Instances of this class are immutable. Where data is passed in or out * via byte arrays, defensive cloning is performed. * * @see Card#getATR * * @version 1.3, 07/20/06 * @since 1.6 * @author Andreas Sterbenz * @author JSR 268 Expert Group */ public final class ATR implements java.io.Serializable { private static final long serialVersionUID = 6695383790847736493L; private byte[] atr; private transient int startHistorical, nHistorical; /** * Constructs an ATR from a byte array. * * @param atr the byte array containing the answer-to-reset bytes * @throws NullPointerException if <code>atr</code> is null */ public ATR(byte[] atr) { this.atr = atr.clone(); parse(); } private void parse() { if (atr.length < 2) { return; } if ((atr[0] != 0x3b) && (atr[0] != 0x3f)) { return; } int t0 = (atr[1] & 0xf0) >> 4; int n = atr[1] & 0xf; int i = 2; while ((t0 != 0) && (i < atr.length)) { if ((t0 & 1) != 0) { i++; } if ((t0 & 2) != 0) { i++; } if ((t0 & 4) != 0) { i++; } if ((t0 & 8) != 0) { if (i >= atr.length) { return; } t0 = (atr[i++] & 0xf0) >> 4; } else { t0 = 0; } } int k = i + n; if ((k == atr.length) || (k == atr.length - 1)) { startHistorical = i; nHistorical = n; } } /** * Returns a copy of the bytes in this ATR. * * @return a copy of the bytes in this ATR. */ public byte[] getBytes() { return atr.clone(); } /** * Returns a copy of the historical bytes in this ATR. * If this ATR does not contain historical bytes, an array of length * zero is returned. * * @return a copy of the historical bytes in this ATR. */ public byte[] getHistoricalBytes() { byte[] b = new byte[nHistorical]; System.arraycopy(atr, startHistorical, b, 0, nHistorical); return b; } /** * Returns a string representation of this ATR. * * @return a String representation of this ATR. */ public String toString() { return "ATR: " + atr.length + " bytes"; } /** * Compares the specified object with this ATR for equality. * Returns true if the given object is also an ATR and its bytes are * identical to the bytes in this ATR. * * @param obj the object to be compared for equality with this ATR * @return true if the specified object is equal to this ATR */ public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof ATR == false) { return false; } ATR other = (ATR)obj; return Arrays.equals(this.atr, other.atr); } /** * Returns the hash code value for this ATR. * * @return the hash code value for this ATR. */ public int hashCode() { return Arrays.hashCode(atr); } private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { atr = (byte[])in.readUnshared(); parse(); } }