Ross Larkin
Ross Larkin

Reputation: 29

CAP converter fails with 'unsupported int type of intermediate value, must cast value to type short or byte'

I am very close to finally creating a CAP file for the JCDK 2.2.2 using command line. I first compile the source file Transfer.java into a class file Transfer.class and then try to generate the CAP file. Everything is fine except that I get the error

error: line 56: smartTransfer.Transfer: unsupported int type of intermediate value, must cast intermediate value to type short or byte.

from the CAP converter tool when trying to build my Java Card applet from the class file. I do not have a clue where this error comes from and as such can not assign the value to a byte or short.

I remember when I had Eclipse Neon installed with JCDK 3.0.5, there was a int error of an unknown location, but the applet still ran. I guess due to the JRE on my system.

Here is my applet code:

package smartTransfer;
import javacard.framework.*;

public class Transfer extends Applet {
final static byte CLASS = (byte) 0x80;
final static byte WRITE_USER_INFO_INS = 0x07;
final static byte WRITEIT_USER_INFO_INS = 0x08;
final static byte READ_USER_INFO_INS = 0x09;
final static byte READIT_USER_INFO_INS = 0x06;
final static byte SIZE_MEMORY = (short) 127;
static byte[] memory;
static byte[] memoryy;

public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException {
    new Transfer().register();
    memory = new byte[SIZE_MEMORY];
    memoryy = new byte[SIZE_MEMORY];
}

public void process(APDU apdu)
throws ISOException {
    if (selectingApplet()) return;
    byte[] buffer = apdu.getBuffer();
    if (buffer[ISO7816.OFFSET_CLA] !=CLASS) {
        ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
    }
    byte ins = buffer[ISO7816.OFFSET_INS];
    switch (ins) {
    case READ_USER_INFO_INS:
        readUserInfo(apdu);
        break;
    case READIT_USER_INFO_INS:
        readitUserInfo(apdu);
        break;
    case WRITE_USER_INFO_INS:
        writeUserInfo(apdu);
        break;
    case WRITEIT_USER_INFO_INS:
        writeitUserInfo(apdu);
    default:
        ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    }
}

private void writeUserInfo(APDU apdu) {
    byte[] cmd_apdu = apdu.getBuffer();
    if (cmd_apdu[ISO7816.OFFSET_P1] != 0x00) 
        ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    short offset = (short) (cmd_apdu[ISO7816.OFFSET_P2] & 0x00FF);
    if (offset >= SIZE_MEMORY) 
        ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    short lc = (short)(cmd_apdu[ISO7816.OFFSET_LC] & 0x00FF);
    if ((offset + lc) > SIZE_MEMORY) 
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    if (lc == 0x00) 
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    getAPDUBody(apdu);    
        Util.arrayCopy(cmd_apdu, (short)((ISO7816.OFFSET_CDATA) & 0x00FF), 
                memory, offset, lc);
        ISOException.throwIt(ISO7816.SW_NO_ERROR); 
     }

public void getAPDUBody(APDU apdu) {
    byte[] buffer = apdu.getBuffer();
    short lc = (short)(buffer[ISO7816.OFFSET_LC] & 0x00FF); 
    if (lc != apdu.setIncomingAndReceive()) 
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}  

private void readUserInfo(APDU apdu) {
    byte[] cmd_apdu = apdu.getBuffer();
    if (cmd_apdu[ISO7816.OFFSET_P1] != 0x00) ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    short offset = (short) (cmd_apdu[ISO7816.OFFSET_P2] & 0x00FF); 
    if (offset >= SIZE_MEMORY) ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    short le = (short)(cmd_apdu[ISO7816.OFFSET_LC] & 0x00FF);
    if (le == 0x00) le = (short)(SIZE_MEMORY - offset);
    if ((offset + le) > SIZE_MEMORY) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    apdu.setOutgoing(); 
    apdu.setOutgoingLength((short)le);  
    apdu.sendBytesLong(memory, (short)offset, (short)le); 

}

private void writeitUserInfo(APDU apdu) {
    byte[] cmd_apdu = apdu.getBuffer();
    if (cmd_apdu[ISO7816.OFFSET_P1] != 0) 
        ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    short offset = (short) (cmd_apdu[ISO7816.OFFSET_P2] & 0x00FF); 
    if (offset >= SIZE_MEMORY) 
        ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    short lc = (short)(cmd_apdu[ISO7816.OFFSET_LC] & 0x00FF);
    if ((offset + lc) > SIZE_MEMORY) 
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    if (lc == 0x00) 
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    getAPDUBody(apdu);    
        Util.arrayCopy(cmd_apdu, (short)((ISO7816.OFFSET_CDATA) & 0x00FF), 
                memoryy, offset, lc); 
        ISOException.throwIt(ISO7816.SW_NO_ERROR); 
     }

private void readitUserInfo(APDU apdu) {
    byte[] cmd_apdu = apdu.getBuffer();
    if (cmd_apdu[ISO7816.OFFSET_P1] != 0x00) ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    short offset = (short) (cmd_apdu[ISO7816.OFFSET_P2] & 0x00FF); 
    if (offset >= SIZE_MEMORY) ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    short le = (short)(cmd_apdu[ISO7816.OFFSET_LC] & 0x00FF); 
    if (le == 0x00) le = (short)(SIZE_MEMORY - offset);
    if ((offset + le) > SIZE_MEMORY) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    apdu.setOutgoing(); 
    apdu.setOutgoingLength((short)le);  
    apdu.sendBytesLong(memoryy, (short)offset, (short)le); 

  }
}

I know the error is at line 56, but I guess that would be from the Transfer.class file (which I can't open to read) and not in the source code. But the only unassigned intermediate value that I can think of would be with the instruction case, when reading the incoming APDU header.

Where could this error come from?

Upvotes: 2

Views: 1241

Answers (1)

Michael Roland
Michael Roland

Reputation: 40831

The error already clearly tells you the line in the source file that contains the problematic code. In your case the error is caused by all the lines with the if statement

if ((offset + lc) > SIZE_MEMORY) 

The intermediate value of type integer in this case is offset + lc. Eventhough both operands of the plus operator are shorts, the result of the plus operator is an int. Hence, you need to explicitly cast this value back into a short:

if ((short)(offset + lc) > SIZE_MEMORY) 

Also note that the constant SIZE_MEMORY should probably have been of type short instead of byte:

final static short SIZE_MEMORY = (short) 127;

Upvotes: 3

Related Questions