-3

I am trying to developing a java card application. There will a dynamic input string which will contain a phone number in a byte array like:

 byte[] number =new byte[] {1,2,3,4,5,6,7,8,9,5};

I want this array to be changed into following array:

byte[] changed num = {(byte)0x0C, (byte)0x91, (byte)0x19, (byte)0x21, (byte)0x43, (byte)0x65, (byte)0x87, (byte)0x59}

Where first three bytes will be same always and remaining 5 will be update from the incoming array.

I have tried the following:

public static void main(String args[]){
byte[] number =new byte[] {1,2,3,4,5,6,7,8,9,5};

byte[] changednum = new byte[8];

changednum[0] = (byte)0x0C;
changednum[1] = (byte)0x91;
changednum[2] = (byte)0x19;
changednum[3] = (byte)0x(number[0] + number[1]*10);
changednum[4] = (byte)0x(number[2] + number[3]*10);
changednum[5] = (byte)0x(number[4] + number[5]*10);
changednum[6] = (byte)0x(number[6] + number[7]*10);
changednum[7] = (byte)0x(number[8] + number[9]*10);

System.out.println(Arrays.toString(changednum));

}
} 

But the last 5 values are not being converted to byte value


s.

darkknight
  • 216
  • 5
  • 15
  • 1
    Is `0x(number[0] + number[1]*10);` really valid syntax? – GhostCat Oct 04 '16 at 09:13
  • 1
    Its not. But this is what i want to achieve. – darkknight Oct 04 '16 at 09:21
  • Yuk, you first split the number in pairs and then encode it using BCD while putting your bytes in little endian mode using nibbles as base type? Why??? – Maarten Bodewes Oct 04 '16 at 23:29
  • You want to write java card code, you use `public static void main(String args[])` which is obvoiusly not java card... – Paul Bastian Oct 05 '16 at 11:52
  • @AdityaParsai It's unclear if the code needs to be within Java Card or if it needs to be converted before it is send to the Java Card, i.e. within Java SE. Could you clear this up? – Maarten Bodewes Dec 09 '16 at 13:29
  • @MaartenBodewes I am working on a platform in which i cant see the output on screen. So i first make the logic work in java then implement it in javacard. – darkknight Dec 22 '16 at 08:03

4 Answers4

4

This line

changednum[3] = (byte)0x(number[0] + number[1]*10);

could be done with a complicate set of String manipulation how simple maths will do what you want.

changednum[3] = (byte)(number[0] + number[1]*16);

The *16 is needed because you appear to be assuming the number is in hexadecimal.

You could use a loop

for (int i = 0; i < 4; i++)
    changednum[i+3] = (byte)(number[i*2] + number[i*2+1]*16);

or using += to avoid the cast

for (int i = 0; i < 4; i++)
    changednum[i+3] += number[i*2] + number[i*2+1] * 16;

or you can write

for (int i = 0; i < 4; i++)
    changednum[i+3] += number[i*2] + (number[i*2+1] << 4);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 3
    In this case I would prefer << 4 instead of * 16, as the calculation is performed to put the value in the high 4 bits, not to multiply it with 16. – Maarten Bodewes Oct 04 '16 at 23:31
  • @MaartenBodewes the outcome is the same, however shift has lower precedence than multiply so you need more brackets. – Peter Lawrey Oct 05 '16 at 07:03
  • 4
    Be aware that integer support is optional in JavaCard (at least till 2.2.2 if I recall correctly). Besides byte is signed, so depending on you interests you should try to use shorts in case numbers are bigger that 0x80. – jlanza Oct 06 '16 at 07:53
  • @jlanza whether you consider the value to be signed or unsigned is a matter of how you read the value. `b & 0xFF` is unsigned. – Peter Lawrey Oct 06 '16 at 08:21
  • 1
    @PeterLawrey it is unsigned, but if you do for instance `byte a = (byte) (0x80 & 0xFF)` and then you check `b < 0`, it is true. This is what I meant, that @AdityaParsai should be aware of that. Sorry for the misunderstanding. – jlanza Oct 07 '16 at 07:59
  • @MaartenBodewes it would avoid the cast in the first loop to use a byte. – Peter Lawrey Dec 09 '16 at 14:16
3

Although it is not very important in the standard edition of Java in this case, performance is often crucial in Java Card. This solution is slightly faster than the accepted answer thanks to bitwise operators and it is a valid Java Card code without 32-bit integers:

for (short i = 3, j = 0; i < 7; i++, j += 2) {
    changednum[i] = (byte) ((number[j+1] << 4) | (number[j] & 0x0F));
}
vojta
  • 5,591
  • 2
  • 24
  • 64
1

You can use the method Integer.toHexString, that will do the convertion, you need to carefully note that casting explicity integer to byte will truncate its value in a range between -128 to 127

 final int f = -2211;
 System.out.println(f);
 System.out.println((byte) f);
 System.out.println(Integer.toHexString((byte) f));
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
1

The other answers lack readability, in my opinion.

This solution uses separate methods and a ByteBuffer to make the methods work without passing an offset and other plumbing. It has weird things like constants and well thought out identifiers, exceptions, JavaDoc and other scary concepts from the book of maintainability.

package nl.owlstead.stackoverflow;

import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;

/**
 * Helper class to create telephone numbers with headers for Java card using
 * reverse packed BCD format.
 * 
 * @param buffer
 *            a buffer with enough space for the 3 byte header
 */
public final class OverlyDesignedTelephoneNumberHelper {

    private static final int TELEPHONE_NUMBER_SIZE = 10;
    private static final int NIBBLE_SIZE = 4;
    private static final byte[] HEADER = { (byte) 0x0C, (byte) 0x91,
            (byte) 0x19 };

    /**
     * Adds the header for the telephone number to the given buffer.
     * 
     * @param buffer
     *            a buffer with enough space for the 3 byte header
     * @throws NullPointerException
     *             if the buffer is null
     * @throws BufferOverflowException
     *             if the buffer doesn't have enough space for the header
     */
    private static void addTelephoneNumberHeader(final ByteBuffer buffer) {
        buffer.put(HEADER);
    }

    /**
     * Adds the telephone number to the given buffer.
     * 
     * @param buffer
     *            a buffer with enough space for the 3 byte header
     * @param number
     *            the number in BCD format, should be 10 bytes in size
     * @throws IllegalArgumentException
     *             if the number is null or doesn't contain 10 BCD digits
     * @throws NullPointerException
     *             if the buffer is null
     * @throws BufferOverflowException
     *             if the buffer doesn't have enough space for the telephone
     *             number
     */
    private static void addTelephoneNumber(final ByteBuffer buffer,
            final byte[] number) {
        if (number == null || number.length != TELEPHONE_NUMBER_SIZE) {
            throw new IllegalArgumentException("Expecting 10 digit number");
        }

        for (int i = 0; i < number.length; i += 2) {
            final byte lowDigit = number[i];
            validateUnpackedBCDDigit(lowDigit);
            final byte highDigit = number[i + 1];
            validateUnpackedBCDDigit(highDigit);

            buffer.put((byte) ((highDigit << NIBBLE_SIZE) | lowDigit));
        }
    }

    /**
     * Tests if the given unpacked BCD digit is within range.
     * 
     * @param b
     *            the byte to test
     * @throws IllegalArgumentException
     *             if it isn't
     */
    private static void validateUnpackedBCDDigit(final byte b) {
        if (b < 0 || b > 9) {
            throw new IllegalArgumentException(
                    "Telefonenumber isn't all bytes representing digits in BCD");
        }
    }

    public static void main(final String... args) {
        final byte[] number = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 5 };

        final ByteBuffer buf = ByteBuffer.allocate(HEADER.length
                + TELEPHONE_NUMBER_SIZE);
        addTelephoneNumberHeader(buf);
        addTelephoneNumber(buf, number);
        buf.flip();
        while (buf.hasRemaining()) {
            System.out.printf("%02X", buf.get());
        }
        System.out.println();
    }

    private OverlyDesignedTelephoneNumberHelper() {
        // avoid instantiation
    }
}
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • (Beware,) it is for a java card! – vlp Dec 09 '16 at 11:25
  • @vlp I read this as : "I am trying to developing a java card application. There will a dynamic **input string** which will contain a phone number in a byte array like:". So I assumed that the input needed to be changed *terminal side*, not in the Java Card itself. Note also the question title which indicates Java, not Java Card. This would also explain the main method in the question. – Maarten Bodewes Dec 09 '16 at 13:27
  • Finally note that the accepted andwer also isn't directly compatible with Java Card. – Maarten Bodewes Dec 09 '16 at 14:19
  • You are probably right -- I am sorry for spamming you – vlp Dec 09 '16 at 20:29
  • @vlp Meh, could have fooled me as well. I had to re-read the question a few times to make sure. Spam me again :) – Maarten Bodewes Dec 09 '16 at 20:54