Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# serialization ascii confusion

Here's the code.

[Serializable]
public class HostedGame
{
    public int ID { get; set; }

    public int UID { get; set; }

    public String Name { get; set; }

    public Boolean Available { get; set; }

    public String Description { get; set; }

    public List<int> Users { get; set; }

    public int Port { get; set; }

    public HostedGame(int uid, String name, String description, int port)
    {
        UID = uid;
        Name = name;
        Description = description;
        Available = true;
        Port = port;
        Users = new List<int>();
    }

    public int CompareTo(Object obj)
    {
        int result = 1;
        if(obj != null && obj is HostedGame)
        {
            HostedGame w = obj as HostedGame;
            result = this.ID.CompareTo(w.ID);
        }
        return result;
    }

    static public int Compare(HostedGame x, HostedGame y)
    {
        int result = 1;
        if(x != null && y != null)
        {
            result = x.CompareTo(y);
        }
        return result;
    }

    public static HostedGame DeSerialize(byte[] data)
    {
        MemoryStream ms = new MemoryStream(data);
        BinaryFormatter bff = new BinaryFormatter();
        return (HostedGame)bff.Deserialize(ms);
    }

    public static byte[] Serialize(HostedGame obj)
    {
        BinaryFormatter bff = new BinaryFormatter();
        MemoryStream ms = new MemoryStream();
        bff.Serialize(ms, obj);
        return ms.ToArray();
    }
}

The code bellow doesn't seem to work right:

HostedGame hs = new HostedGame(12,"Name", "Description", 8088);
String s = Encoding.ASCII.GetString(HostedGame.Serialize(hs));
HostedGame HACK = HostedGame.DeSerialize(Encoding.ASCII.GetBytes(s));

HACK.Port for some reason comes out being 7999?

When I just do this...

HostedGame HACK = HostedGame.DeSerialize(HostedGame.Serialize(hs));

It works fine.

So, what I'm asking is

  1. Why am I getting a wrong value?
  2. Is there a better way to convert the bytes to a string and back again?
like image 245
Kelly Elton Avatar asked Dec 16 '22 12:12

Kelly Elton


2 Answers

You cannot use Encoding.ASCII.GetString to convert any byte array to a string. You are losing some data when you do this. Use Convert.ToBase64String instead. This one will make a string from any byte sequence without losing the data.

HostedGame hs = new HostedGame(12,"Name", "Description", 8088);
String s = Convert.ToBase64String(HostedGame.Serialize(hs));
HostedGame HACK= HostedGame.DeSerialize(Convert.FromBase64String(s));

Here is an example, that shows how using Encoding.ASCII loses the data.

var testBytes = new byte[] { 250, 251, 252 };
var text = Encoding.ASCII.GetString(testBytes);
var bytes = Encoding.ASCII.GetBytes(result); // will be 63, 63, 63
like image 125
Alex Aza Avatar answered Jan 02 '23 02:01

Alex Aza


Binary serialization generates a byte array which is not (necessarily) a valid string in any encoding.

When you try to read it as ASCII text, the ASCII decoder will convert any invalid bytes (> 128) into ? characters.
Therefore, when you turn it back into ASCII bytes, you end up with a different set of bytes.

In short, don't treat binary data as ASCII, or as any other text encoding.

If you need to send binary data as plain text, use Base64 to safely convert it to text.

like image 37
SLaks Avatar answered Jan 02 '23 00:01

SLaks