PCSC4Java  0.2
Library PCSC for Java language.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
D:/Affaire/Perso/SmartCardToolBox/pcsc4java-framework-0.2/src/fr/redbilled/pcscforjava/CommandAPDU.java
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
00003  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
00004  *
00005  * This code is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU General Public License version 2 only, as
00007  * published by the Free Software Foundation.  Oracle designates this
00008  * particular file as subject to the "Classpath" exception as provided
00009  * by Oracle in the LICENSE file that accompanied this code.
00010  *
00011  * This code is distributed in the hope that it will be useful, but WITHOUT
00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00014  * version 2 for more details (a copy is included in the LICENSE file that
00015  * accompanied this code).
00016  *
00017  * You should have received a copy of the GNU General Public License version
00018  * 2 along with this work; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
00020  *
00021  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
00022  * or visit www.oracle.com if you need additional information or have any
00023  * questions.
00024  */
00025 
00026 package fr.redbilled.pcscforjava;
00027 
00028 import java.util.Arrays;
00029 
00030 import java.nio.ByteBuffer;
00031 
00065 public final class CommandAPDU implements java.io.Serializable {
00066 
00067     private static final long serialVersionUID = 398698301286670877L;
00068 
00069     private static final int MAX_APDU_SIZE = 65544;
00070 
00072     private byte[] apdu;
00073 
00074     // value of nc
00075     private transient int nc;
00076 
00077     // value of ne
00078     private transient int ne;
00079 
00080     // index of start of data within the apdu array
00081     private transient int dataOffset;
00082 
00096     public CommandAPDU(byte[] apdu) {
00097         this.apdu = apdu.clone();
00098         parse();
00099     }
00100 
00120     public CommandAPDU(byte[] apdu, int apduOffset, int apduLength) {
00121         checkArrayBounds(apdu, apduOffset, apduLength);
00122         this.apdu = new byte[apduLength];
00123         System.arraycopy(apdu, apduOffset, this.apdu, 0, apduLength);
00124         parse();
00125     }
00126 
00127     private void checkArrayBounds(byte[] b, int ofs, int len) {
00128         if ((ofs < 0) || (len < 0)) {
00129             throw new IllegalArgumentException
00130                 ("Offset and length must not be negative");
00131         }
00132         if (b == null) {
00133             if ((ofs != 0) && (len != 0)) {
00134                 throw new IllegalArgumentException
00135                     ("offset and length must be 0 if array is null");
00136             }
00137         } else {
00138             if (ofs > b.length - len) {
00139                 throw new IllegalArgumentException
00140                     ("Offset plus length exceed array size");
00141             }
00142         }
00143     }
00144 
00161     public CommandAPDU(ByteBuffer apdu) {
00162         this.apdu = new byte[apdu.remaining()];
00163         apdu.get(this.apdu);
00164         parse();
00165     }
00166 
00176     public CommandAPDU(int cla, int ins, int p1, int p2) {
00177         this(cla, ins, p1, p2, null, 0, 0, 0);
00178     }
00179 
00195     public CommandAPDU(int cla, int ins, int p1, int p2, int ne) {
00196         this(cla, ins, p1, p2, null, 0, 0, ne);
00197     }
00198 
00216     public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data) {
00217         this(cla, ins, p1, p2, data, 0, arrayLength(data), 0);
00218     }
00219 
00243     public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data,
00244             int dataOffset, int dataLength) {
00245         this(cla, ins, p1, p2, data, dataOffset, dataLength, 0);
00246     }
00247 
00268     public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data, int ne) {
00269         this(cla, ins, p1, p2, data, 0, arrayLength(data), ne);
00270     }
00271 
00272     private static int arrayLength(byte[] b) {
00273         return (b != null) ? b.length : 0;
00274     }
00275 
00290     private void parse() {
00291         if (apdu.length < 4) {
00292             throw new IllegalArgumentException("apdu must be at least 4 bytes long");
00293         }
00294         if (apdu.length == 4) {
00295             // case 1
00296             return;
00297         }
00298         int l1 = apdu[4] & 0xff;
00299         if (apdu.length == 5) {
00300             // case 2s
00301             this.ne = (l1 == 0) ? 256 : l1;
00302             return;
00303         }
00304         if (l1 != 0) {
00305             if (apdu.length == 4 + 1 + l1) {
00306                 // case 3s
00307                 this.nc = l1;
00308                 this.dataOffset = 5;
00309                 return;
00310             } else if (apdu.length == 4 + 2 + l1) {
00311                 // case 4s
00312                 this.nc = l1;
00313                 this.dataOffset = 5;
00314                 int l2 = apdu[apdu.length - 1] & 0xff;
00315                 this.ne = (l2 == 0) ? 256 : l2;
00316                 return;
00317             } else {
00318                 throw new IllegalArgumentException
00319                     ("Invalid APDU: length=" + apdu.length + ", b1=" + l1);
00320             }
00321         }
00322         if (apdu.length < 7) {
00323             throw new IllegalArgumentException
00324                 ("Invalid APDU: length=" + apdu.length + ", b1=" + l1);
00325         }
00326         int l2 = ((apdu[5] & 0xff) << 8) | (apdu[6] & 0xff);
00327         if (apdu.length == 7) {
00328             // case 2e
00329             this.ne = (l2 == 0) ? 65536 : l2;
00330             return;
00331         }
00332         if (l2 == 0) {
00333             throw new IllegalArgumentException("Invalid APDU: length="
00334                     + apdu.length + ", b1=" + l1 + ", b2||b3=" + l2);
00335         }
00336         if (apdu.length == 4 + 3 + l2) {
00337             // case 3e
00338             this.nc = l2;
00339             this.dataOffset = 7;
00340             return;
00341         } else if (apdu.length == 4 + 5 + l2) {
00342             // case 4e
00343             this.nc = l2;
00344             this.dataOffset = 7;
00345             int leOfs = apdu.length - 2;
00346             int l3 = ((apdu[leOfs] & 0xff) << 8) | (apdu[leOfs + 1] & 0xff);
00347             this.ne = (l3 == 0) ? 65536 : l3;
00348         } else {
00349             throw new IllegalArgumentException("Invalid APDU: length="
00350                     + apdu.length + ", b1=" + l1 + ", b2||b3=" + l2);
00351         }
00352     }
00353 
00381     public CommandAPDU(int cla, int ins, int p1, int p2, byte[] data,
00382             int dataOffset, int dataLength, int ne) {
00383         checkArrayBounds(data, dataOffset, dataLength);
00384         if (dataLength > 65535) {
00385             throw new IllegalArgumentException("dataLength is too large");
00386         }
00387         if (ne < 0) {
00388             throw new IllegalArgumentException("ne must not be negative");
00389         }
00390         if (ne > 65536) {
00391             throw new IllegalArgumentException("ne is too large");
00392         }
00393         this.ne = ne;
00394         this.nc = dataLength;
00395         if (dataLength == 0) {
00396             if (ne == 0) {
00397                 // case 1
00398                 this.apdu = new byte[4];
00399                 setHeader(cla, ins, p1, p2);
00400             } else {
00401                 // case 2s or 2e
00402                 if (ne <= 256) {
00403                     // case 2s
00404                     // 256 is encoded as 0x00
00405                     byte len = (ne != 256) ? (byte)ne : 0;
00406                     this.apdu = new byte[5];
00407                     setHeader(cla, ins, p1, p2);
00408                     this.apdu[4] = len;
00409                 } else {
00410                     // case 2e
00411                     byte l1, l2;
00412                     // 65536 is encoded as 0x00 0x00
00413                     if (ne == 65536) {
00414                         l1 = 0;
00415                         l2 = 0;
00416                     } else {
00417                         l1 = (byte)(ne >> 8);
00418                         l2 = (byte)ne;
00419                     }
00420                     this.apdu = new byte[7];
00421                     setHeader(cla, ins, p1, p2);
00422                     this.apdu[5] = l1;
00423                     this.apdu[6] = l2;
00424                 }
00425             }
00426         } else {
00427             if (ne == 0) {
00428                 // case 3s or 3e
00429                 if (dataLength <= 255) {
00430                     // case 3s
00431                     apdu = new byte[4 + 1 + dataLength];
00432                     setHeader(cla, ins, p1, p2);
00433                     apdu[4] = (byte)dataLength;
00434                     this.dataOffset = 5;
00435                     System.arraycopy(data, dataOffset, apdu, 5, dataLength);
00436                 } else {
00437                     // case 3e
00438                     apdu = new byte[4 + 3 + dataLength];
00439                     setHeader(cla, ins, p1, p2);
00440                     apdu[4] = 0;
00441                     apdu[5] = (byte)(dataLength >> 8);
00442                     apdu[6] = (byte)dataLength;
00443                     this.dataOffset = 7;
00444                     System.arraycopy(data, dataOffset, apdu, 7, dataLength);
00445                 }
00446             } else {
00447                 // case 4s or 4e
00448                 if ((dataLength <= 255) && (ne <= 256)) {
00449                     // case 4s
00450                     apdu = new byte[4 + 2 + dataLength];
00451                     setHeader(cla, ins, p1, p2);
00452                     apdu[4] = (byte)dataLength;
00453                     this.dataOffset = 5;
00454                     System.arraycopy(data, dataOffset, apdu, 5, dataLength);
00455                     apdu[apdu.length - 1] = (ne != 256) ? (byte)ne : 0;
00456                 } else {
00457                     // case 4e
00458                     apdu = new byte[4 + 5 + dataLength];
00459                     setHeader(cla, ins, p1, p2);
00460                     apdu[4] = 0;
00461                     apdu[5] = (byte)(dataLength >> 8);
00462                     apdu[6] = (byte)dataLength;
00463                     this.dataOffset = 7;
00464                     System.arraycopy(data, dataOffset, apdu, 7, dataLength);
00465                     if (ne != 65536) {
00466                         int leOfs = apdu.length - 2;
00467                         apdu[leOfs] = (byte)(ne >> 8);
00468                         apdu[leOfs + 1] = (byte)ne;
00469                     } // else le == 65536: no need to fill in, encoded as 0
00470                 }
00471             }
00472         }
00473     }
00474 
00475     private void setHeader(int cla, int ins, int p1, int p2) {
00476         apdu[0] = (byte)cla;
00477         apdu[1] = (byte)ins;
00478         apdu[2] = (byte)p1;
00479         apdu[3] = (byte)p2;
00480     }
00481 
00487     public int getCLA() {
00488         return apdu[0] & 0xff;
00489     }
00490 
00496     public int getINS() {
00497         return apdu[1] & 0xff;
00498     }
00499 
00505     public int getP1() {
00506         return apdu[2] & 0xff;
00507     }
00508 
00514     public int getP2() {
00515         return apdu[3] & 0xff;
00516     }
00517 
00526     public int getNc() {
00527         return nc;
00528     }
00529 
00537     public byte[] getData() {
00538         byte[] data = new byte[nc];
00539         System.arraycopy(apdu, dataOffset, data, 0, nc);
00540         return data;
00541     }
00542 
00549     public int getNe() {
00550         return ne;
00551     }
00552 
00558     public byte[] getBytes() {
00559         return apdu.clone();
00560     }
00561 
00567     public String toString() {
00568         return "CommmandAPDU: " + apdu.length + " bytes, nc=" + nc + ", ne=" + ne;
00569     }
00570 
00579     public boolean equals(Object obj) {
00580         if (this == obj) {
00581             return true;
00582         }
00583         if (obj instanceof CommandAPDU == false) {
00584             return false;
00585         }
00586         CommandAPDU other = (CommandAPDU)obj;
00587         return Arrays.equals(this.apdu, other.apdu);
00588      }
00589 
00595     public int hashCode() {
00596         return Arrays.hashCode(apdu);
00597     }
00598 
00599     private void readObject(java.io.ObjectInputStream in)
00600             throws java.io.IOException, ClassNotFoundException {
00601         apdu = (byte[])in.readUnshared();
00602         // initialize transient fields
00603         parse();
00604     }
00605 
00606 }