C
C#4w ago
BenMcLean

Binary serialization / deserialization where you don't control the format

I wrote this:
public static string ReadPascalString(BinaryReader reader) => System.Text.Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadUInt16()));
public static void WritePascalString(BinaryWriter writer, string s)
{
writer.Write((ushort)s.Length);
writer.Write(System.Text.Encoding.UTF8.GetBytes(s));
}
[Serializable]
public readonly record struct HeaderChunk(
string Name,
string Type,
int ID,
int ReferenceID,
bool Visible,
bool Locked,
uint Color,
float PivotX,
float PivotY,
float PivotZ) : ISerializable
{
public static HeaderChunk Read(Stream stream)
{
BinaryReader reader = new(stream);
return new(
Name: ReadPascalString(reader),
Type: ReadPascalString(reader),
ID: reader.ReadUInt16(),
ReferenceID: reader.ReadUInt16(),
Visible: reader.ReadBoolean(),
Locked: reader.ReadBoolean(),
Color: reader.ReadUInt32(),
PivotX: reader.ReadSingle(),
PivotY: reader.ReadSingle(),
PivotZ: reader.ReadSingle());
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();//Help?
}

public void Write(Stream stream)
{
BinaryWriter writer = new(stream);
WritePascalString(writer, Name);
WritePascalString(writer, Type);
writer.Write(ID);
writer.Write(ReferenceID);
writer.Write(Visible);
writer.Write(Locked);
writer.Write(Color);
writer.Write(PivotX);
writer.Write(PivotY);
writer.Write(PivotZ);
}
}
public static string ReadPascalString(BinaryReader reader) => System.Text.Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadUInt16()));
public static void WritePascalString(BinaryWriter writer, string s)
{
writer.Write((ushort)s.Length);
writer.Write(System.Text.Encoding.UTF8.GetBytes(s));
}
[Serializable]
public readonly record struct HeaderChunk(
string Name,
string Type,
int ID,
int ReferenceID,
bool Visible,
bool Locked,
uint Color,
float PivotX,
float PivotY,
float PivotZ) : ISerializable
{
public static HeaderChunk Read(Stream stream)
{
BinaryReader reader = new(stream);
return new(
Name: ReadPascalString(reader),
Type: ReadPascalString(reader),
ID: reader.ReadUInt16(),
ReferenceID: reader.ReadUInt16(),
Visible: reader.ReadBoolean(),
Locked: reader.ReadBoolean(),
Color: reader.ReadUInt32(),
PivotX: reader.ReadSingle(),
PivotY: reader.ReadSingle(),
PivotZ: reader.ReadSingle());
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();//Help?
}

public void Write(Stream stream)
{
BinaryWriter writer = new(stream);
WritePascalString(writer, Name);
WritePascalString(writer, Type);
writer.Write(ID);
writer.Write(ReferenceID);
writer.Write(Visible);
writer.Write(Locked);
writer.Write(Color);
writer.Write(PivotX);
writer.Write(PivotY);
writer.Write(PivotZ);
}
}
The purpose of this is binary serialization/deserialization to/from a file format I don't control. It has to exactly match that format. The question is, how would I convert my naïve Read and Write methods into something that would properly implement Serializable and ISerializable the idiomatic C# way?
1 Reply
BenMcLean
BenMcLean4w ago
This is just the header to a larger file format .NET Standard 2.0 with PolySharp letting me use more recent language features. What is the right way to do binary serialization/deserialization of a file format I don't control then? Is there no standard interface for reading and writing? A standard interface which marks a type as one that can be binary serialized or deserialized, so that outside code can reference this aspect of the type without knowing more about the type, which is what I thought ISerializable was for. OK, I thought that my Read(Stream stream) and Write(Stream stream) methods were supposed to be implementing some standard C# interface, but you're telling me that in reality, it's just the wild west and everyone does their own thing. Since there are no standards, I'm adding my own:
using System.IO;

namespace Voxel2Pixel.Interfaces
{
public interface IBinaryWritable
{
void Write(Stream stream);
}
}
using System.IO;

namespace Voxel2Pixel.Interfaces
{
public interface IBinaryWritable
{
void Write(Stream stream);
}
}