Of course I know this have to do with endianess. I know Java is big-endian while C# is little-endian.
I have a working program in Java which sends a string to an external system. The thing is that they require to use a 2 byte header at the beggining of the string that represents its length.
In this 2 byte header, the first one is just to tell if the string exceeds 255 characters, if not, it is always 0. But the second byte (which is the one that i can't get right in C#) will represent the length of the string, if the first byte is 0 (in almost all cases) it represents the whole lenth of the string, let's say 226.
So in java, I have this segment of code that calculates the header and append the original string so we can have the final string to send, and it works just fine:
Java working segment of code:
String iso_str = iso_buf.toString(); // This contains original string without header
int iso_len = iso_str.length(); // We need to know if it exceeds 255
int i, j;
i = (int)(iso_len / 256); // Always 0. It would be 1 if original string bigger than 255
j = (int)(iso_len % 256); // Length of the string (most times 226)
Integer ii = new Integer(i);
Integer jj = new Integer(j);
byte[] bmsg_0200 = new byte[iso_len + 2]; // We create an array of bytes making room for the 2 bytes header and the original string
bmsg_0200[0] = ii.byteValue(); // Header byte number one
bmsg_0200[1] = jj.byteValue(); // Header byte number two
System.arraycopy(iso_str.getBytes(), 0, bmsg_0200, 2, iso_str.length()); // Then we just copy the original string in the array after the header
String mensaje_str = new String(bmsg_0200); // Make the whole byte array into one string to send
In the part that says: bmsg_0200[1] = jj.byteValue(); is where java actually gets a byte value that works (and I think it puts -30 there when jj is 226). And the final system understands this header, therefore reads all the message.
I tried to replicate the code in .NET (C#) and I have the following code:
C# not working segment of code:
int tramaISOLongitud = iso.Length; // iso contains original string without header, We need to know if it exceeds 255
int i, j;
i = (int)(tramaISOLongitud / 256); // Always 0. It would be 1 if original string bigger than 255
j = (int)(tramaISOLongitud % 256); // Length of the string (most times 226)
byte[] tramaISOBytes = new byte[tramaISOLongitud + 2]; // We create an array of bytes making room for the 2 bytes header and the original string
tramaISOBytes[0] = Convert.ToByte(i); // Header byte number one
tramaISOBytes[1] = Convert.ToByte(j); // Header byte number two
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud); // Then we just copy the original string in the array after the header
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
string tramaISOHeader = enc.GetString(tramaISOBytes); // Make the whole byte array into one string to send
The last code compiles and everything, but gets the wrong byte in tramaISOBytes[1] = Convert.ToByte(j); because is little-endian. So i tried using System.Net.IPAddress.HostToNetworkOrder as follows:
int tramaISOLongitud = iso.Length; // iso contains original string without header, We need to know if it exceeds 255
int i, j;
i = (int)(tramaISOLongitud / 256); // Always 0. It would be 1 if original string bigger than 255
j = (int)(tramaISOLongitud % 256); // Length of the string (most times 226)
int i2 = System.Net.IPAddress.HostToNetworkOrder(i);
int j2 = System.Net.IPAddress.HostToNetworkOrder(j);
byte[] tramaISOBytes = new byte[tramaISOLongitud + 2]; // We create an array of bytes making room for the 2 bytes header and the original string
tramaISOBytes[0] = Convert.ToByte(i2); // Header byte number one
tramaISOBytes[1] = Convert.ToByte(j2); // Header byte number two
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud); // Then we just copy the original string in the array after the header
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
string tramaISOHeader = enc.GetString(tramaISOBytes); // Make the whole byte array into one string to send
But then j2 gets a huge number (like -503316480) that cannot be converted into a single byte because is too large and for sure i need it in one byte because the header as I said, is just 2 byte long. Any ideas?
Thanks in advance.
OK I will put this on a much simpler way:
In C#:
int test = -10471344;
int test2 = -503316480;
int test3 = 57856;
byte b = (byte)test;
byte b2 = (byte)test2;
byte b3 = (byte)test3;
If we run these lines we get: b = 80 b2 = 0 b3 = 0
So, why the number -10471344 casted to a (byte) gives 80; and the other ones just give 0? Actually I'm interested in the variable test2 = -503316480 I would like it to be converted in something else, and i get 0. Why b can be 80 and the other ones cannot be something different than 0?
SOLUTION: As Jim said, my problem didn't have anything to do with endianness (although I thought it was everything related to that), but the key knowledge is that in .NET world converting a String into a byte array is no problem, but getting back from byte array to string is where you have problems because you have to use encoding (ASCIIEncoding or UTF8Enconding) and that's where problems arise because your bytes get mangled.
In java I didn't have this kind of problem.
So this is the block of code that did the job:
static byte[] addHeader2(string iso)
{
int tramaISOLongitud = iso.Length;
byte highByte = (byte)(tramaISOLongitud >> 8);
byte lowByte = (byte)(tramaISOLongitud & 255);
byte[] tramaISOBytes = new byte[tramaISOLongitud + 2];
tramaISOBytes[0] = highByte;
tramaISOBytes[1] = lowByte;
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
System.Array.ConstrainedCopy(encoding.GetBytes(iso), 0, tramaISOBytes, 2, tramaISOLongitud);
return tramaISOBytes;
}
And I just send that byte array through the socket as it is.
THANKS TO ALL FOR YOUR HELP!