Weird E. Weird E. - 18 days ago 5
C# Question

C# - Bytes converting doesn't not work as it should

I'm playing around with Source RCON Protocol, but I'm having issues converting a strings to byte array successfully.

Original Code (VB.NET) + Pastebin: http://pastebin.com/4BkbTRfD

Private Function RCON_Command(ByVal Command As String, ByVal ServerData As Integer) As Byte()
Dim Packet As Byte() = New Byte(CByte((13 + Command.Length))) {}
Packet(0) = Command.Length + 9 'Packet Size (Integer)
Packet(4) = 0 'Request Id (Integer)
Packet(8) = ServerData 'SERVERDATA_EXECCOMMAND / SERVERDATA_AUTH (Integer)
For X As Integer = 0 To Command.Length - 1
Packet(12 + X) = System.Text.Encoding.Default.GetBytes(Command(X))(0)
Next
Return Packet
End Function


My current code in C# + Pastebin: http://pastebin.com/eVv0nZCf

byte[] RCONCommand(string cmd, int serverData)
{
int packetSize = cmd.Length + 12;
byte[] byteList = new byte[packetSize];
byteList[0] = (byte)packetSize;
byteList[4] = 0;
byteList[8] = (byte)serverData;

for(int X = 0; X < cmd.Length; X++)
{
byteList[12 + X] = Encoding.ASCII.GetBytes(cmd)[X];
}

return byteList;
}


When I use Encoding.ASCII.GetString(RCONCommand("Word", 3)); the result will be square mark. I tried with Encoding.UTF8.GetString() too, but same result.

Packet structure can be found here: https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Basic_Packet_Structure

I don't just figure it out what I've done wrong, because I'm not even a familiar with bytes and such. PS. The example applications that has been posted in C# for Source RCON Protocol documentation are garbled, because people is using so much OOP and creates millions of class files so I cannot even find the correct stuff.

Answer

A byte is 8 bits. That means that a value such as Size, which according to the spec is a 32-bit little-endian unsigned integer, will require 4 bytes (32 รท 8 = 4).

To fit 32 bits of information into four bytes, you have to split it up. Think of this as dividing a four-digit number into four strings, one for each digit. Except we're working in binary, so it's a little more complicated. We have to do some bit shifting and masking to get just the bits we want into each "string."

The spec calls for little-endian, sothe least significant bytes come first; this takes some getting used to if you haven't done this before.

byte[0] = size && 0xFF;
byte[1] = (size >> 8) && 0xFF;
byte[2] = (size >> 16) && 0xFF;
byte[3] = (size >> 24) && 0xFF;

If you want to rely on the CLR, you can use BitConverter, although it's platform dependent, and not all platforms are little-endian.

var tmp = BitConverter.GetBytes(size);
if (BitConverter.IsLittleEndian)
{
    byte[0] = tmp[0];
    byte[1] = tmp[1];
    byte[2] = tmp[2];
    byte[3] = tmp[3];
}
else  //in case you are running on a bigendian machine like a Mac
{
    byte[0] = tmp[3];
    byte[1] = tmp[2];
    byte[2] = tmp[1];
    byte[3] = tmp[0];
}
Comments