
/*---------------------------------------------------------------------------
 * Copyright (C) 1999,2000 Dallas Semiconductor Corporation, All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Dallas Semiconductor
 * shall not be used except as stated in the Dallas Semiconductor
 * Branding Policy.
 *---------------------------------------------------------------------------
 */

// ResponseAPDU.java
package com.dalsemi.onewire.container;

/**
 * A ResponseAPDU represents an Application Protocol Data Unit (APDU)
 * received from the smart card in response to a previous CommandAPDU.
 * A ResponseAPDU consists of an optional body and a mandatory
 * Status Word (SW). <BR><BR>
 *
 * According to ISO 7816-4, a ResponseAPDU  has the following
 * format:
 *
 * <pre>
 *          DATA   |  STATUS WORD
 *         [data]  |  SW1     SW2
 *
 * </pre>
 *
 * where
 * <ul>
 * <li>data is a byte array of data received from the smart card.
 * <li>SW1  is a byte containing command processing status.
 * <li>SW2  is a byte containing command processing qualifier.
 * </ul>
 *
 * @version    0.00, 28 Aug 2000
 * @author     YL
 *
 */
public class ResponseAPDU
{

   /** byte array to hold the entire ResponseAPDU. */
   protected byte[] apduBuffer = null;

   /** length of the ResponseAPDU currently in the buffer. */
   protected int apduLength;

   /**
    * Constructs a new ResponseAPDU initialized with
    * the given buffer byte array. The internal buffer length
    * is set to the length of the buffer passed.
    *
    * @param buffer  the byte array with data for the internal apduBuffer.
    *
    * @exception RuntimeException thrown when buffer is invalid.
    *
    * @see #getLength
    */
   public ResponseAPDU (byte[] buffer)
   {
      if (buffer.length < 2)
         throw new RuntimeException("invalid ResponseAPDU, "
                                    + "length must be at least 2 bytes");

      apduLength = buffer.length;
      apduBuffer = new byte [apduLength];

      System.arraycopy(buffer, 0, apduBuffer, 0, apduLength);
   }   // ResponseAPDU

   /**
    * Gets the data field of the ResponseAPDU.
    *
    * @return a byte array containing the ResponseAPDU data field.
    */
   public byte[] getData ()
   {
      if (apduLength > 2)
      {
         byte[] data = new byte [apduLength - 2];

         System.arraycopy(apduBuffer, 0, data, 0, apduLength - 2);

         return data;
      }
      else
         return null;
   }   // data

   /**
    * Gets the value of SW1 and SW2 as an integer.
    * It is computed as: (((SW1<<8) & 0xFF00) | (SW2 & 0xFF)).
    *
    * @return    value (((SW1<<8) & 0xFF00) | (SW2 & 0xFF)) as integer.
    */
   public final int getSW ()
   {
      return (((getSW1() << 8) & 0xFF00) | (getSW2() & 0xFF));
   }   // getSW

   /**
    * Gets the value of SW1.
    *
    * @return    value of SW1 as a byte.
    */
   public final byte getSW1 ()
   {
      return apduBuffer [apduLength - 2];
   }   // getSW1

   /**
    * Gets the value of SW2.
    *
    * @return    value of SW2 as a byte.
    */
   public final byte getSW2 ()
   {
      return apduBuffer [apduLength - 1];
   }   // getSW2

   /**
    * Gets the byte value at the specified position in the internal buffer.
    *
    * @param index   the position in the buffer
    * @return        the value at the given position,
    *                or -1 if the position is invalid
    *
    * @see #getLength
    */
   final public byte getByte (int index)
   {
      if (index >= apduLength)
         return -1;   // read beyond end of ResponseAPDU

      return (apduBuffer [index]);
   }   // getByte

   /**
    * Gets a byte array holding the internal ResponseAPDU buffer.
    *
    * @return  the internal buffer copied into a new array.
    *
    */
   final public byte[] getBytes ()
   {
      byte[] apdu = new byte [apduLength];

      System.arraycopy(apduBuffer, 0, apdu, 0, apduLength);

      return apdu;
   }   // getBytes

   /**
    * Gets the length of the internal buffer.
    *
    * @return  the length of the buffer currently stored
    */
   final public int getLength ()
   {
      return apduLength;
   }   // getLength

   /**
    * Gets a string representation of this ResponseAPDU.
    *
    * @return a string describing this ResponseAPDU.
    */
   public String toString ()
   {
      String apduString = "";

      if (apduLength > 2)
      {
         byte[] dataBuffer = new byte [apduLength - 2];

         dataBuffer = getData();
         apduString += "DATA = ";

         for (int i = 0; i < dataBuffer.length; i++)
         {

            // make hex String representation of byte array             
            if ((dataBuffer [i] & 0xFF) < 0x10)
               apduString += '0';

            apduString += Integer.toHexString(( int ) (dataBuffer [i] & 0xFF))
                          + " ";
         }

         apduString += " | ";
      }

      apduString += "SW1 = ";

      if ((getSW1() & 0xFF) < 0x10)
         apduString += '0';

      apduString += Integer.toHexString(getSW1() & 0xFF);
      apduString += ", SW2 = ";

      if ((getSW2() & 0xFF) < 0x10)
         apduString += '0';

      apduString += Integer.toHexString(getSW2() & 0xFF);

      return (apduString.toUpperCase());
   }   // toString
}
