Convert Hex To Byte Array in Java gives different results from C#.NET [port from C# to Java]

I am trying to convert a small piece of code to Java from C#. [I think don't have to say I'm a noob. :P]

The two codes below returns differently I don't understand why. Thanks for any help.

P.S.: I've checked the question here but the answer doesn't fix my problem.

C#.NET

public class Test
{
    private static sbyte[] HexToByte(string hex)
        {
            if (hex.Length % 2 == 1)
                throw new Exception("The binary key cannot have an odd number of digits");

            sbyte[] arr = new sbyte[hex.Length >> 1];
            int l = hex.Length;

            for (int i = 0; i < (l >> 1); ++i)
            {
                arr[i] = (sbyte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
            }

            return arr;
        }

        private static int GetHexVal(char hex)
        {
            int val = (int)hex;
            return val - (val < 58 ? 48 : 55);
        }
    public static void Main()
    {
        Console.WriteLine(HexToByte("EE")[0]);
    }
}

OUTPUT: -18

JAVA

class Test
{
    private static int GetHexVal(char hex)
    {
        int val = (int)hex;
        return val - (val < 58 ? 48 : 55);
    }

    private static byte[] HexToByte(String hex) throws Exception {
        if (hex.length() % 2 == 1)
            throw new Exception("The binary key cannot have an odd number of digits");

        byte[] arr = new byte[hex.length() >> 1];
        int l = hex.length();

        for (int i = 0; i < (l >> 1); ++i)
        {
            arr[i] = (byte)((GetHexVal((char)(hex.charAt(i << 1) << 4)) + (GetHexVal(hex.charAt((i << 1) + 1)))));
        }

        return arr;
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        System.out.println((HexToByte("EE")[0]));
    }
}

OUTPUT: 39

I don't understand why this happens and what is the way to overcome it?

Jon Skeet
people
quotationmark

The problem is in your bracketing for the first character in the Java code. Here's your code:

GetHexVal((char)(hex.charAt(i << 1) << 4))

That's getting the character, shifting that, then calling GetHexVal. You want to shift the result instead:

// Unnecessary cast removed
GetHexVal(hex.charAt(i << 1)) << 4

This would have been much easier to see if you'd made your code simpler. I would have written it as:

private static byte[] HexToByte(String hex) {
    if (hex.length() % 2 == 1) {
        throw new IllegalArgumentException("...");
    }

    byte[] arr = new byte[hex.length() / 2];

    for (int i = 0; i < hex.length(); i += 2)
    {
        int highNybble = parseHex(hex.charAt(i));
        int lowNybble = parseHex(hex.charAt(i + 1));
        arr[i / 2] = (byte) ((highNybble << 4) + lowNybble);
    }

    return arr;
}

While bitshifting is all very efficient, it's not nearly as readable as simply dividing by two... and splitting code up across multiple statements makes it much easier to read each individual part of it.

(I would probably implement parseHex with a switch statement, throwing an IllegalArgumentException for non-hex digits too...)

people

See more on this question at Stackoverflow