Reputation: 10497
First of all, sorry for the long post, I want to include all my thoughts so it's easier for you guys to find what's wrong about my code.
I want to transfer an Hex string from a C# application to a Java application. But, when I convert the same Hex value to a Byte Array on both languages, the output is different.
For instance, the same Hex value gives
[101, 247, 11, 173, 46, 74, 56, 137, 185, 38, 40, 191, 204, 104, 83, 154]
in C# and
[101, -9, 11, -83, 46, 74, 56, -119, -71, 38, 40, -65, -52, 104, 83, -102]
in Java
Here are the methods I use in C#:
public static string ByteArrayToHexString(byte[] byteArray)
{
return BitConverter.ToString(byteArray).Replace("-",""); //To convert the whole array
}
public static byte[] HexStringToByteArray(string hexString)
{
byte[] HexAsBytes = new byte[hexString.Length / 2];
for (int index = 0; index < HexAsBytes.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return HexAsBytes;
}
And the ones in Java:
public static String ByteArrayToHexString(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b: bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString().toUpperCase();
}
public static byte[] HexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
Here's an example in C#:
String hexString = "65F70BAD2E4A3889B92628BFCC68539A";
byte[] byteArray = HexBytes.HexStringToByteArray(hexString);
//Using the debugger, byteArray = [101, 247, 11, 173, 46, 74, 56, 137, 185, 38, 40, 191, 204, 104, 83, 154]
String hexString2 = HexBytes.ByteArrayToHexString(byteArray)
Console.Write("HEX: " + hexString2);
//Outputs 65F70BAD2E4A3889B92628BFCC68539A
And an example in Java:
String hexString = "65F70BAD2E4A3889B92628BFCC68539A";
byte[] byteArray = HexBytes.HexStringToByteArray(hexString);
//Using the debugger, byteArray = [101, -9, 11, -83, 46, 74, 56, -119, -71, 38, 40, -65, -52, 104, 83, -102]
String hexString2 = HexBytes.ByteArrayToHexString(byteArray);
System.out.println("HEX: " + hexString2);
//Outputs 65F70BAD2E4A3889B92628BFCC68539A
As you can see, when I do the opposite operation, the final Hex value is equal to the first one, which means the way I convert is potentially good in both languages individually. But I don't understand why the conversion from Hex to a byte array is different in both languages. I thought Hexadecimal was simply a number on another base.
Thanks for the help
Cydrick
Update
I fixed this issue by replacing the C# code with the following code:
public static string ByteArrayToHexString(sbyte[] byteArray)
{
return BitConverter.ToString(convert(byteArray)).Replace("-", ""); //To convert the whole array
}
public static sbyte[] HexStringToByteArray(string hexString)
{
byte[] HexAsBytes = new byte[hexString.Length / 2];
for (int index = 0; index < HexAsBytes.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return convert(HexAsBytes);
}
private static sbyte[] convert(byte[] byteArray)
{
sbyte[] sbyteArray = new sbyte[byteArray.Length];
for (int i = 0; i < sbyteArray.Length; i++)
{
sbyteArray[i] = unchecked((sbyte) byteArray[i]);
}
return sbyteArray;
}
private static byte[] convert(sbyte[] sbyteArray)
{
byte[] byteArray = new byte[sbyteArray.Length];
for (int i = 0; i < byteArray.Length; i++)
{
byteArray[i] = (byte) sbyteArray[i];
}
return byteArray;
}
Upvotes: 4
Views: 4141
Reputation: 1500385
But, when I convert the same Hex value to a Byte Array on both languages, the output is different.
All you're seeing is that bytes are signed in Java and unsigned in C#. So if you add 256 to any negative value in Java, you'll get the value shown in C#. The actual bits in the values are the same - it's just a matter of whether the top bit is treated as a sign bit or not.
EDIT: As noted in comments, if you're ever using the byte as an integer outside the debugger output, you can always use:
int someInt = someByte & 0xff;
to get the unsigned value.
Upvotes: 10
Reputation: 12811
Looks like this is a debugger issue only. Those negative values you're seeing in the Java debugger are the signed equivalents to the unsigned values you're seeing in the C# debugger. For example, signed byte -9 == unsigned byte 247 (notice that they always differ by 256). The data is fine.
Upvotes: 1