2

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?

Michael Roland
  • 39,663
  • 10
  • 99
  • 206
  • *"I know the error is at line 56.."* I wish we knew which was the 56th line. Missing imports and the package statement, I'm not about to try guessing. For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). An MCVE / SSCCE requires that all code necessary to recreate the problem, is included. – Andrew Thompson Apr 09 '17 at 21:59
  • Hi Andrew, Sorry I did not realise that i hadn't done four space behind them two lines and they ended up in the text above - I have changed it.... As I say, I would have thought that line 56 refers to the .class file which i am converting to the cap file and this I cannot open to read, thats why I did not upload - do you want me to attach it - This is the first time I am doing this so please bare with me. – Ross Larkin Apr 09 '17 at 22:54
  • *"I would have thought that line 56 refers to the .class file "* No, it refers to the Java source code file that produced the class file! See [What is a stack trace, and how can I use it to debug my application errors?](http://stackoverflow.com/q/3988788/418556) – Andrew Thompson Apr 09 '17 at 23:01
  • BTW - that amended source code does not include an import for `java.applet.Applet`.. – Andrew Thompson Apr 09 '17 at 23:04
  • oh okay thanks! line 56 is if ((offset + lc) > SIZE_MEMORY) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);' – Ross Larkin Apr 09 '17 at 23:31
  • under the writeUserInfo Apdu method. I haven't heard of java.applet.Applet, but i am using java.framework.applet class, which worked in javacard CREF simulator (but still had int error, but no more information + the applet ran in there so was fine for testing), but just have an issue with int on this line. I read that i have to explicitly set the intermediate value here as if not set the default is int, which is not supported by java card 2.2.2, I just have no idea how to do this and cannot find any information online on how to actually set it in this circumstance – Ross Larkin Apr 09 '17 at 23:37
  • Is this problem resolved? – JavaCardOS Apr 10 '17 at 06:51

1 Answers1

3

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;
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
  • Thank you so much and sorry that my question wasn't written in an optimal way for you guys to easily read. I am very new to java, so this has been quite a learning experience, but thank you I now have a CAP file! – Ross Larkin Apr 10 '17 at 09:29
  • @RossLarkin By my edit to the question I just wanted to make sure that it's not going to be closed/deleted (since it already had 2 close votes then, though I don't understand why anyone would vote to close that question). Also, you may want to do a bit more reading on how to properly send and receive data in Java Card. – Michael Roland Apr 10 '17 at 12:49
  • 1
    For values of 127 or under you can use a byte for `SIZE_MEMORY`, but I agree: you would avoid the upcast to short and directly compare the left hand short value with a right hand short value. You don't need to cast 127 to short when assigning it to `SIZE_MEMORY` though. I'd make all the constants `private` otherwise they won't be inlined. – Maarten Bodewes Apr 10 '17 at 23:51
  • Thank you @MarteenBodewes, I did not get a notice so i did not notice you had commented. That worked really well for me and everything is working fine.. I managed to download the cap file and download and install it on a J3A041 card using the PyAPDUTool, the only problem I am having now is that other than select the applet, I keep getting a 6E00 (class not found error) and obviously i now I'm using the class i set 0x80 – Ross Larkin Apr 12 '17 at 20:49
  • just to clarify; 00 A4 04 00 07 FF 00 20 00 00 00 10 00 - works fine in the software and with the client application I am creating, but every other command responds with class not supported, I tried changing the class byte to 00, but had the same results – Ross Larkin Apr 12 '17 at 20:57